Repository navigation
feat(vercel): Blob token verification and client uploads - #317
Draft
scotttrinh wants to merge 1 commit into
Draft
scotttrinh wants to merge 1 commit into
scotttrinh wants to merge 1 commit into
Conversation
Co-Authored-By: Scott Trinh <1682194+scotttrinh@users.noreply.github.com>
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
Author
|
note: discussed the security review details, and they are moot for the use case that emulate has (local development, end-to-end testing, etc). |
This branch was successfully deployed
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.
Every Blob endpoint (put, copy, head, list, delete and multipart create, upload and complete) now goes through one
authenticate(c, operation)helper instead of trusting the store id it could parse out of a token. Read-write and client tokens take their store id from the token and ignorex-vercel-blob-store-id; any other bearer token is treated as OIDC and uses that header. Read-write tokens must exactly match the store's registered token, client tokens are limited to put and multipart operations, and a valid client token is decoded, checked for expiry, then re-signed with the store's read-write token and compared timing-safely. Public content under/blob/...is still unauthenticated. Stores live in a newblobStorescollection (storeId,rwToken,access,createdAt) that later store lifecycle work can build on.With verified client tokens in place, browser uploads through
handleUpload()work end to end. The signed values foraddRandomSuffix,cacheControlMaxAge,allowOverwriteandifMatchreplace the request headers, and the signed pathname (compared before the random suffix, using the same leading-slash normalization as the request), allowed content types (includingtype/*) and maximum size (measured on the actual body) are enforced before anything is written. The requested pathname and the stored key are now separate values. After a successful client-token PUT the emulator postsblob.upload-completedwith the same blob object the PUT returned plus the token'stokenPayload, signed as hex HMAC-SHA256 over the exact body with the store's read-write token,x-vercel-signature-type: rw_token, and a JSON content type for API versions above 4. Delivery runs in the background and a failing callback never fails the upload.This flips the two
Vercel Blob credential verificationtests and all ofVercel Blob browser client tokens(the signed-token upload, the four server-side constraint cases for expiry, pathname, MIME type and size, the forged store secret, signed options overriding headers, and the callback). The new client-token gate also made thelistanddeletecases of the browser permissions parameterization pass, so thatit.fails.eachis split: those two are now plainit.eachandsigned-tokenstays failing until the signed-token endpoint exists. The sharedbeforeAllnow makes onelist()call with the test token so client-token tests also pass when run on their own.Two behaviors here are deliberately emulator-only, and the docs say so. To keep the zero-config setup working, an unknown store is auto-registered by the first well-formed
vercel_blob_rw_<storeId>_<secret>token that names it, and after that only that exact token is accepted for it. OIDC tokens cannot be verified offline, so the literallocal-oidc-tokenand any JWT-shaped token (three base64url segments) are accepted without verification and anything else gets 403Invalid token. OIDC requests still needx-vercel-blob-store-id, but their stores do not have to be registered.Left out on purpose: multipart part upload and completion (still 400 after authenticating), signed tokens and presigned URLs, TTL, private access, and any HTTPS upgrade, SSRF filtering or deployment-protection handling for the upload-completed callback, which is sent to the URL exactly as given so local
http://callbacks work.Generated with Claude Code