From cde4555adde23df2123c726ab8fc3090b09ea3e4 Mon Sep 17 00:00:00 2001 From: shuaiplus <2327005759@qq.com> Date: Mon, 6 Jul 2026 01:35:12 +0800 Subject: [PATCH] fix: return unsupported for email and kdf flows --- src/handlers/sends-private.ts | 26 +++++++++++++++++++++---- src/handlers/sends-public.ts | 2 +- src/handlers/sends-shared.ts | 6 +++++- src/router-authenticated.ts | 36 ++++++++++++++++++++++++++++++++++- src/router-public.ts | 25 +++++++++++++++++++++++- src/utils/response.ts | 4 ++++ 6 files changed, 91 insertions(+), 8 deletions(-) diff --git a/src/handlers/sends-private.ts b/src/handlers/sends-private.ts index 2433fce..390c2f0 100644 --- a/src/handlers/sends-private.ts +++ b/src/handlers/sends-private.ts @@ -35,6 +35,8 @@ import { } from './sends-shared'; import { auditRequestMetadata, writeAuditEvent } from '../services/audit-events'; +const SEND_EMAIL_AUTH_UNSUPPORTED_MESSAGE = 'Send email verification is not supported by this server.'; + async function writeSendAudit( storage: StorageService, request: Request, @@ -216,11 +218,17 @@ export async function handleCreateSend(request: Request, env: Env, userId: strin if (authTypeRaw.present && requestedAuthType === null) { return errorResponse('Invalid authType', 400); } + if (requestedAuthType === SendAuthType.Email) { + return errorResponse(SEND_EMAIL_AUTH_UNSUPPORTED_MESSAGE, 501); + } const normalizedEmails = normalizeEmails(emailsRaw.value); if (emailsRaw.present && emailsRaw.value !== null && normalizedEmails === null) { return errorResponse('Invalid emails', 400); } + if (normalizedEmails) { + return errorResponse(SEND_EMAIL_AUTH_UNSUPPORTED_MESSAGE, 501); + } const now = new Date().toISOString(); const send: Send = { @@ -340,11 +348,17 @@ export async function handleCreateFileSendV2(request: Request, env: Env, userId: if (authTypeRaw.present && requestedAuthType === null) { return errorResponse('Invalid authType', 400); } + if (requestedAuthType === SendAuthType.Email) { + return errorResponse(SEND_EMAIL_AUTH_UNSUPPORTED_MESSAGE, 501); + } const normalizedEmails = normalizeEmails(emailsRaw.value); if (emailsRaw.present && emailsRaw.value !== null && normalizedEmails === null) { return errorResponse('Invalid emails', 400); } + if (normalizedEmails) { + return errorResponse(SEND_EMAIL_AUTH_UNSUPPORTED_MESSAGE, 501); + } const now = new Date().toISOString(); const send: Send = { @@ -598,10 +612,11 @@ export async function handleUpdateSend(request: Request, env: Env, userId: strin if (parsedAuthType === null) { return errorResponse('Invalid authType', 400); } - send.authType = parsedAuthType; - if (parsedAuthType !== SendAuthType.Email) { - send.emails = null; + if (parsedAuthType === SendAuthType.Email) { + return errorResponse(SEND_EMAIL_AUTH_UNSUPPORTED_MESSAGE, 501); } + send.authType = parsedAuthType; + send.emails = null; } const emailsRaw = getAliasedProp(body, ['emails', 'Emails']); @@ -610,10 +625,13 @@ export async function handleUpdateSend(request: Request, env: Env, userId: strin if (emailsRaw.value !== null && normalizedEmails === null) { return errorResponse('Invalid emails', 400); } + if (normalizedEmails) { + return errorResponse(SEND_EMAIL_AUTH_UNSUPPORTED_MESSAGE, 501); + } send.emails = normalizedEmails; if (send.emails) { send.authType = SendAuthType.Email; - } else if (send.authType === SendAuthType.Email) { + } else if (Number(send.authType) === SendAuthType.Email) { send.authType = SendAuthType.None; } } diff --git a/src/handlers/sends-public.ts b/src/handlers/sends-public.ts index 5e353f7..0355ece 100644 --- a/src/handlers/sends-public.ts +++ b/src/handlers/sends-public.ts @@ -368,7 +368,7 @@ export async function issueSendAccessToken( Object: 'error', }, }, - 400 + 501 ), }; } diff --git a/src/handlers/sends-shared.ts b/src/handlers/sends-shared.ts index 866fd49..82484e7 100644 --- a/src/handlers/sends-shared.ts +++ b/src/handlers/sends-shared.ts @@ -464,7 +464,11 @@ export function sendPasswordLockedOAuthResponse(retryAfterSeconds: number): Resp export async function validatePublicSendAccess(send: Send, body: unknown): Promise { if (hasEmailAuth(send)) { - return { ok: false, response: errorResponse(SEND_INACCESSIBLE_MSG, 404), reason: 'email_auth_unsupported' }; + return { + ok: false, + response: errorResponse('Send email verification is not supported by this server.', 501), + reason: 'email_auth_unsupported', + }; } if (!send.passwordHash) return { ok: true }; diff --git a/src/router-authenticated.ts b/src/router-authenticated.ts index ae35c19..a6336c8 100644 --- a/src/router-authenticated.ts +++ b/src/router-authenticated.ts @@ -1,5 +1,5 @@ import type { Env, User } from './types'; -import { errorResponse, jsonResponse } from './utils/response'; +import { errorResponse, jsonResponse, unsupportedResponse } from './utils/response'; import { handleGetProfile, handleUpdateProfile, @@ -116,6 +116,40 @@ export async function handleAuthenticatedRoute( } } + if ((path === '/api/accounts/kdf' || path === '/accounts/kdf') && (method === 'POST' || method === 'PUT')) { + return unsupportedResponse('KDF changes are not supported by this server.'); + } + + const mailBackedAccountPaths = new Set([ + '/api/accounts/email-token', + '/accounts/email-token', + '/api/accounts/verify-email', + '/accounts/verify-email', + '/api/accounts/verify-email-token', + '/accounts/verify-email-token', + '/api/accounts/request-otp', + '/accounts/request-otp', + '/api/accounts/verify-otp', + '/accounts/verify-otp', + ]); + if (mailBackedAccountPaths.has(path) && (method === 'POST' || method === 'PUT')) { + return unsupportedResponse('Email delivery is not supported by this server.'); + } + + const emailTwoFactorPaths = new Set([ + '/api/two-factor/get-email', + '/two-factor/get-email', + '/api/two-factor/send-email', + '/two-factor/send-email', + '/api/two-factor/send-email-login', + '/two-factor/send-email-login', + '/api/two-factor/email', + '/two-factor/email', + ]); + if (emailTwoFactorPaths.has(path) && (method === 'POST' || method === 'PUT' || method === 'DELETE')) { + return unsupportedResponse('Email two-step login is not supported by this server.'); + } + if (path === '/api/accounts/profile') { if (method === 'GET') return handleGetProfile(request, env, userId); if (method === 'PUT') return handleUpdateProfile(request, env, userId); diff --git a/src/router-public.ts b/src/router-public.ts index 91de2d5..4131e81 100644 --- a/src/router-public.ts +++ b/src/router-public.ts @@ -28,7 +28,7 @@ import { } from './handlers/notifications'; import { handlePublicUploadSendFile } from './handlers/sends'; import { isSafeWebsiteIconContentType } from './utils/content-type'; -import { jsonResponse } from './utils/response'; +import { jsonResponse, unsupportedResponse } from './utils/response'; import { StorageService } from './services/storage'; import type { Env } from './types'; @@ -470,6 +470,29 @@ export async function handlePublicRoute( return handleRecoverTwoFactor(request, env); } + const publicMailBackedPaths = new Set([ + '/api/accounts/resend-new-device-otp', + '/accounts/resend-new-device-otp', + '/api/accounts/register/send-verification-email', + '/accounts/register/send-verification-email', + '/identity/accounts/register/send-verification-email', + '/api/accounts/register/verification-email-clicked', + '/accounts/register/verification-email-clicked', + '/identity/accounts/register/verification-email-clicked', + '/api/accounts/register/finish', + '/accounts/register/finish', + '/identity/accounts/register/finish', + '/api/accounts/verify-email-token', + '/accounts/verify-email-token', + '/api/two-factor/send-email-login', + '/two-factor/send-email-login', + ]); + if (publicMailBackedPaths.has(path) && method === 'POST') { + const blocked = await enforcePublicRateLimit('public-sensitive', LIMITS.rateLimit.sensitivePublicRequestsPerMinute); + if (blocked) return blocked; + return unsupportedResponse('Email delivery is not supported by this server.'); + } + if (path === '/api/accounts/password-hint' && method === 'POST') { const blocked = await enforcePublicRateLimit('public-sensitive', LIMITS.rateLimit.sensitivePublicRequestsPerMinute); if (blocked) return blocked; diff --git a/src/utils/response.ts b/src/utils/response.ts index a068016..6fcf0db 100644 --- a/src/utils/response.ts +++ b/src/utils/response.ts @@ -136,6 +136,10 @@ export function errorResponse(message: string, status: number = 400): Response { ); } +export function unsupportedResponse(message: string = 'This feature is not supported by this server.'): Response { + return errorResponse(message, 501); +} + // Identity endpoint error response (for /identity/connect/token) export function identityErrorResponse(message: string, error: string = 'invalid_grant', status: number = 400): Response { return jsonResponse(