Uh oh!
There was an error while loading. Please reload this page.
feat(files): password, email-OTP, and SSO auth for public file shares - #5140
Conversation
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryHigh Risk Overview API & data: Product & policy: Share modal uses an access ButtonGroup (password, allow-list, client-reserved token before save). Refactors: Reviewed by Cursor Bugbot for commit ec5de63. Bugbot is set up for automated code reviews on this repo. Configure here. |
Uh oh!
There was an error while loading. Please reload this page.
Greptile SummaryThis PR adds Password, Email-OTP, and SSO access controls to public file shares, unifying the gate with the existing deploy-as-chat auth machinery by extracting a shared
Confidence Score: 5/5Safe to merge. The auth logic is cleanly shared, the migration is additive, and the file-name-leak issues from earlier review rounds have been addressed. Cookie generation and validation both use the raw encrypted password from PublicShareRow, so the password-slot invalidation mechanism works as intended. All three new auth modes have IP rate limits on their write paths. The remaining comments are minor validation gaps and a UX inconsistency in the email countdown. apps/sim/app/api/files/public/[token]/otp/route.ts — the PUT verify endpoint would benefit from an IP rate limit to match the POST request path. Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant C as Client
participant P as /f/[token] page.tsx
participant M as GET /api/files/public/[token]
participant O as POST/PUT /otp
participant S as POST /sso
participant A as validateDeploymentAuth
C->>P: Visit share URL
P->>P: resolveShare(token)
P->>P: renderAuthGate(share)
alt "authType = public"
P-->>C: PublicFileView
else "authType = password"
P-->>C: PublicFileAuth gate
C->>M: POST password
M->>A: validateDeploymentAuth
A-->>M: authorized true
M-->>C: Set file_auth cookie
C->>P: router.refresh()
P-->>C: PublicFileView
else "authType = email"
P-->>C: PublicFileEmailAuth
C->>O: POST email request OTP
O-->>C: 200 message
C->>O: PUT email otp verify
O-->>C: Set file_auth cookie
C->>P: router.refresh()
P-->>C: PublicFileView
else "authType = sso"
P->>P: getSession + isEmailAllowed
alt not authorized
P-->>C: PublicFileSSOAuth
C->>S: POST email eligibility
S-->>C: eligible true
C->>C: redirect to SSO
C->>P: return from SSO
P-->>C: PublicFileView
else authorized
P-->>C: PublicFileView
end
end
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant C as Client
participant P as /f/[token] page.tsx
participant M as GET /api/files/public/[token]
participant O as POST/PUT /otp
participant S as POST /sso
participant A as validateDeploymentAuth
C->>P: Visit share URL
P->>P: resolveShare(token)
P->>P: renderAuthGate(share)
alt "authType = public"
P-->>C: PublicFileView
else "authType = password"
P-->>C: PublicFileAuth gate
C->>M: POST password
M->>A: validateDeploymentAuth
A-->>M: authorized true
M-->>C: Set file_auth cookie
C->>P: router.refresh()
P-->>C: PublicFileView
else "authType = email"
P-->>C: PublicFileEmailAuth
C->>O: POST email request OTP
O-->>C: 200 message
C->>O: PUT email otp verify
O-->>C: Set file_auth cookie
C->>P: router.refresh()
P-->>C: PublicFileView
else "authType = sso"
P->>P: getSession + isEmailAllowed
alt not authorized
P-->>C: PublicFileSSOAuth
C->>S: POST email eligibility
S-->>C: eligible true
C->>C: redirect to SSO
C->>P: return from SSO
P-->>C: PublicFileView
else authorized
P-->>C: PublicFileView
end
end
Reviews (4): Last reviewed commit: "fix(security): make isEmailAllowed case-..." | Re-trigger Greptile |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
…on renumber 0243→0244)
TheodoreSpeaks
commented
Jun 19, 2026
Addressed the review feedback in 7578702:
Also rebased onto latest staging (resolved the @greptile review |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
…ed SSO denial message
TheodoreSpeaks
commented
Jun 19, 2026
Round 2 of bot feedback addressed:
@greptile review |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
TheodoreSpeaks
commented
Jun 19, 2026
Round 3 (email casing, root-caused):
Net: allow-list matching is now case-insensitive everywhere; OTP storage keys off the normalized email on both store and verify. @greptile review |
TheodoreSpeaks
commented
Jun 19, 2026
Re the two Bugbot comments still showing on the latest commit (SSO session email casing @
Added a direct unit test for |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
…api-validation baseline 859)
…ts non-password shares
TheodoreSpeaks
commented
Jun 19, 2026
[Bugbot High — "Public cookie bypasses email gate"] Fixed — good catch. Two layers:
Added a route test (password POST on a public share → 400, no cookie) and updated the chat auth-token assertion. Also rebased onto latest staging (migration renumbered to |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 3 total unresolved issues (including 2 from previous reviews).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want reviews to match your repository better? Bugbot Learning can learn team-specific rules from PR activity. A team admin can enable Learning in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 2120a46. Configure here.
Uh oh!
There was an error while loading. Please reload this page.
TheodoreSpeaks
commented
Jun 19, 2026
The 'Share upsert validation returns 500' comment is already resolved as of |

Summary
validateChatAuthinto a sharedvalidateDeploymentAuth(resource, …, cookiePrefix); widensetDeploymentAuthCookieand the OTP store to a'file'kind; reuseisEmailAllowed,encryptSecret, the global/ssoflow, and the mailer/verification tableauth_type,password(encrypted),allowed_emailstopublic_share(migrations 0243/0244, additive)file_auth_{shareId}cookie (auth_required_*401 sentinels); addPOST /api/files/public/[token](password),…/otp(request+verify),…/sso(eligibility)AuthSelectorprecedent (ButtonGroup+ conditional password / allowed-emails fields); SSO hidden unlessNEXT_PUBLIC_SSO_ENABLED; link is reserved on open (client token, persisted on save) and shown live for non-private modes; removed the post-save link toastopengraph-image+generateMetadatafor/f/[token](rich for public shares, generic for password/email/SSO so the filename never leaks pre-auth; alwaysnoindex)GeneratedPasswordInput(deploy modal + share modal) andPublicFileAuthShell(the three gates)Type of Change
Testing
bun run lint✓ ·check:api-validation:strict✓ ·check:migrations origin/staging✓ (backward-compatible) ·tsc✓Checklist