mirror of
https://github.com/saltbo/zpan.git
synced 2026-09-24 23:22:31 +08:00
fix(share): return 403 instead of 401 on wrong share password
Dev (vite + miniflare + undici) returns 500 "fetch failed" when the Worker responds 401 to a POST with a body. undici follows the Fetch spec's HTTP-auth retry branch, which needs to re-extract the request body from its source — but the body comes from Node's IncomingMessage stream, so `body.source` is null and undici throws `expected non-null body source`. Production (direct CF edge) is unaffected, this only breaks local dev. 403 is also semantically more accurate: the client isn't performing HTTP authentication, just supplying a shared secret. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
f215439a89
commit
6bf8ecc8d5
@@ -85,7 +85,7 @@ const app = new Hono<Env>()
|
||||
const { share } = resolved
|
||||
if (share.kind !== 'landing') return c.json({ error: 'Share not found or revoked' }, 404)
|
||||
|
||||
if (!verifyPassword(share, password)) return c.json({ error: 'Invalid password' }, 401)
|
||||
if (!verifyPassword(share, password)) return c.json({ error: 'Invalid password' }, 403)
|
||||
|
||||
const now = new Date()
|
||||
const oneDayMs = 24 * 60 * 60 * 1000
|
||||
|
||||
@@ -214,7 +214,7 @@ describe('POST /s/:token/verify', () => {
|
||||
expect(cookieHeader).toContain('HttpOnly')
|
||||
})
|
||||
|
||||
it('returns 401 on wrong password', async () => {
|
||||
it('returns 403 on wrong password', async () => {
|
||||
const { app, db } = await createTestApp()
|
||||
await authedHeaders(app)
|
||||
await insertStorage(db)
|
||||
@@ -234,7 +234,7 @@ describe('POST /s/:token/verify', () => {
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ password: 'wrongpassword' }),
|
||||
})
|
||||
expect(res.status).toBe(401)
|
||||
expect(res.status).toBe(403)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ export function PasswordPrompt({ token, fileName, onUnlocked }: PasswordPromptPr
|
||||
await verifySharePassword(token, password)
|
||||
onUnlocked()
|
||||
} catch (err) {
|
||||
if (err instanceof ApiError && err.status === 401) {
|
||||
if (err instanceof ApiError && err.status === 403) {
|
||||
setError(t('share.passwordWrong'))
|
||||
} else {
|
||||
setError(t('share.loadError'))
|
||||
|
||||
+2
-2
@@ -1152,8 +1152,8 @@ describe('api', () => {
|
||||
expect(JSON.parse(init.body as string)).toEqual({ password: 'secret' })
|
||||
})
|
||||
|
||||
it('throws ApiError on 401 (wrong password)', async () => {
|
||||
vi.mocked(fetch).mockResolvedValueOnce(makeResponse({ error: 'Invalid password' }, false, 401))
|
||||
it('throws ApiError on 403 (wrong password)', async () => {
|
||||
vi.mocked(fetch).mockResolvedValueOnce(makeResponse({ error: 'Invalid password' }, false, 403))
|
||||
|
||||
await expect(verifySharePassword('tok123', 'wrong')).rejects.toThrow('Invalid password')
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user