fix(bounties): non-sequential public ids, 404-on-DB-error, error handling & payment redirect#30
Merged
Merged
Conversation
vu1nz Security Review0 finding(s) in PR #? No security issues found. |
The POST /api/bounties handler had no try/catch around the DB insert,
so any DB failure (e.g. SQLite Cloud free node paused) returned a
non-JSON 500. The browser's res.json() then threw, surfacing the
opaque "Something went wrong. Please try again." with no detail.
- Wrap the insert + CoinPay payment logic in try/catch, returning a
proper JSON 500 { error: 'Failed to create bounty. Please try again.' }.
- Fix the new-bounty page redirect: it checked data.checkout_url, but
the API returns data.pay_url. Users were never sent to CoinPay to
fund the bounty; now they are redirected to pay_url.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bounty URLs exposed the sequential integer primary key (/bounties/1), which is enumerable and leaks the total count. Switch all public bounty URLs to a non-sequential, URL-safe public_id while keeping the integer PK internally for joins/FKs. - lib/id.ts: generatePublicId() (base62 via crypto), mirrored in migrate.mjs for backfill. - Migration: add bounties.public_id, backfill existing rows, add a UNIQUE index. - POST /api/bounties generates a public_id and returns it; CoinPay redirect_url + metadata.bounty_id and the funding webhook now key off public_id. - Detail page, GET route, claim route, listing links, and auth returnTo all resolve by public_id. - Fix the 404 bug: the detail page's getBounty swallowed DB errors and returned null, so a paused/erroring DB made a real bounty render as 404. Let query errors surface instead of masquerading as not-found. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
df56e88 to
5e47b16
Compare
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.
Fixes the bounty 404 and the enumerable numeric-id problem, plus the original create-error handling.
Changes
Non-sequential public IDs (numeric ids were enumerable / leaked count)
lib/id.tsgeneratePublicId()(base62 viacrypto); mirrored inmigrate.mjs.bounties.public_id, backfills existing rows, adds a UNIQUE index.public_id; integer PK kept internally for joins/FKs.POST /api/bountiesgenerates + returnspublic_id; CoinPayredirect_url,metadata.bounty_id, and the funding webhook all key offpublic_id.returnToresolve bypublic_id.404 on a real bounty
getBountyhadcatch { return null }, turning a DB error (e.g. the SQLite Cloud free node pausing) intonotFound(). An existing bounty rendered as 404. Errors now surface instead of masquerading as not-found.Create error handling + payment redirect (original fix)
POST /api/bountieswrapped in try/catch → proper JSON 500 instead of an opaque non-JSON crash.data.pay_url(the field the API returns) instead of the nonexistentcheckout_url.Verification
tscclean;next buildpasses withSESSION_SECRETunset (all bounty routes build).Note: based on top of #29 (lazy
SESSION_SECRET).🤖 Generated with Claude Code