feat: add centralized snippet request validation - #178
Open
Okorie2000-code wants to merge 2 commits into
Open
Conversation
Introduce a single validation module reused by every snippet operation (create, update, import, share): title 3-100 chars, supported-language enum, code size/whitespace limits, Stellar wallet format+checksum via the SDK, and visibility restricted to private/public/shared. All failures return one consistent JSON error payload with HTTP 400 and nothing is persisted for invalid input. Adds a bounded ZIP reader plus an import endpoint that validates JSON/ZIP manifests before persistence and always assigns the authenticated wallet as owner. Includes a visibility column migration and comprehensive unit/route tests. Closes SudiptaPaul-31#157 🤖 Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.com>
|
@Okorie2000-code is attempting to deploy a commit to the Sudipta 's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
@Okorie2000-code Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
Owner
|
@Okorie2000-code resolve conflicts |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a centralized snippet request validation layer shared by every snippet operation — create, update, import, and share. All rules live in one module (
app/api/snippets/snippet.validator.ts) so validation can never diverge between endpoints. No per-route validation duplication remains.Fields / rules validated
titledescriptionlanguagelib/languages.ts), no conflicting registrycodetagsownerWalletAddressStrKey.isValidEd25519PublicKey) — no hand-rolled cryptovisibilityprivate,public,shared; anything else → 400. Defaults toprivate. Persisted via a newvisibilitycolumn (migration:scripts/add-visibility-column.sql)Import validation
New endpoint
POST /api/snippets/import:import/zip.util.ts).Authorization protection
ownerWalletAddressinside an imported file is rejected).ownerWalletAddressin an update body is rejected) and ownership/edit checks are unchanged.publicsnippets become readable without a wallet.Standardized error handling
Every snippet endpoint now returns one consistent JSON error payload on validation failure with HTTP 400:
{ "error": "Validation failed", "message": "<first issue>", "details": [{ "field": "title", "message": "..." }] }No stack traces, secrets, database errors, or internal details are exposed.
Tests added
app/api/snippets/snippet.validator.test.ts— 54 tests: valid inputs, every supported language, every visibility value, invalid inputs (missing/empty/short/long title, whitespace code, oversized code, unsupported language, malformed wallet/checksum, invalid visibility), boundaries (3/100-char title, 1/10 000-char code), and error-format checks (including no internal detail leakage).app/api/snippets/import/zip.util.test.ts— 13 tests: stored/deflate archives, an externally-generated (Pythonzipfile) fixture, corrupt/truncated/unsupported archives, zip bombs, entry-count and size limits.app/api/snippets/import/route.test.ts— 19 tests: 401 without wallet, malformed JSON, invalid ZIP, missing/invalid fields inside imports, oversized content, no partial persistence, valid JSON + ZIP imports.app/api/snippets/route.test.ts(create) — 12 tests, including HTTP 400 error shape and no persistence on invalid input.app/api/snippets/[id]/route.test.ts(update) — 9 tests: 401/403/404, invalid title/visibility/code, owner cannot be changed via update.app/api/snippets/[id]/share/route.test.ts— 5 tests: 401/403, valid share, malformedexpiresAt, invalidisReadOnly.lib/snippet.service.test.ts— updated to use a checksum-valid Stellar address and extended with invalid-input cases (malformed wallet, unsupported language, invalid visibility).Validation commands / results
npx eslint(changed files)npx tsc --noEmit(changed files)@types/jest, stale.nexttypes)npx jest(all snippet suites)npx next buildsubmitCollectionToStellar/ui/switchissues in collections code)Notes:
jest.config.mjs+jest.setup.tsadd aTextDecoder/TextEncoderpolyfill so the jsdom test environment can load server libraries (e.g.@neondatabase/serverless) — required for any test to run.scripts/add-visibility-column.sql(orpsql -f scripts/add-visibility-column.sql) to add thevisibilitycolumn before deploying.Closes #157