fix: address security issue

This commit is contained in:
shuaiplus
2026-06-24 01:44:50 +08:00
committed by Shuai
parent 5048cc0720
commit 7279668955
24 changed files with 613 additions and 114 deletions
+26 -8
View File
@@ -353,9 +353,15 @@ export async function handleRegister(request: Request, env: Env): Promise<Respon
return errorResponse('Invite code is required', 403);
}
const inviteMarked = await storage.markInviteUsed(inviteCode, user.id);
if (!inviteMarked) {
return errorResponse('Invite code is invalid or expired', 403);
}
try {
await storage.createUser(user);
} catch (error) {
await storage.revertInviteUsed(inviteCode, user.id);
const msg = error instanceof Error ? error.message.toLowerCase() : String(error).toLowerCase();
if (msg.includes('unique') || msg.includes('constraint')) {
return errorResponse('Email already registered', 409);
@@ -363,12 +369,6 @@ export async function handleRegister(request: Request, env: Env): Promise<Respon
throw error;
}
const inviteMarked = await storage.markInviteUsed(inviteCode, user.id);
if (!inviteMarked) {
await storage.deleteUserById(user.id);
return errorResponse('Invite code is invalid or expired', 403);
}
await writeAuditEvent(storage, {
actorUserId: user.id,
action: 'user.register.invite',
@@ -891,7 +891,7 @@ export async function handleDisableTwoFactorProvider(request: Request, env: Env,
}
// PUT /api/accounts/totp
// enable: { enabled: true, secret: "...", token: "123456" }
// enable: { enabled: true, secret: "...", token: "123456", masterPasswordHash?: "...", userVerificationToken?: "..." }
// disable: { enabled: false, masterPasswordHash: "..." }
export async function handleSetTotpStatus(request: Request, env: Env, userId: string): Promise<Response> {
const storage = new StorageService(env.DB);
@@ -899,7 +899,13 @@ export async function handleSetTotpStatus(request: Request, env: Env, userId: st
const user = await storage.getUserById(userId);
if (!user) return errorResponse('User not found', 404);
let body: { enabled?: boolean; secret?: string; token?: string; masterPasswordHash?: string };
let body: {
enabled?: boolean;
secret?: string;
token?: string;
masterPasswordHash?: string;
userVerificationToken?: string;
};
try {
body = await request.json();
} catch {
@@ -908,12 +914,24 @@ export async function handleSetTotpStatus(request: Request, env: Env, userId: st
if (body.enabled === true) {
const normalizedSecret = normalizeTotpSecret(body.secret || '');
const masterPasswordHash = readBodyString(body, ['masterPasswordHash', 'MasterPasswordHash']);
const userVerificationToken = readBodyString(body, ['userVerificationToken', 'UserVerificationToken']);
if (!isTotpEnabled(normalizedSecret)) {
return errorResponse('Invalid TOTP secret', 400);
}
if (!body.token) {
return errorResponse('TOTP token is required', 400);
}
let verifiedUser = false;
if (userVerificationToken) {
verifiedUser = await verifyTotpUserVerificationToken(env, user, normalizedSecret, userVerificationToken);
}
if (!verifiedUser && masterPasswordHash) {
verifiedUser = await auth.verifyPassword(masterPasswordHash, user.masterPasswordHash, user.email);
}
if (!verifiedUser) {
return errorResponse('User verification failed.', 400);
}
const verified = await verifyTotpToken(normalizedSecret, body.token);
if (!verified) {
return errorResponse('Invalid TOTP token', 400);