mirror of
https://github.com/shuaiplus/nodewarden.git
synced 2026-11-04 10:40:20 +00:00
fix: improve authentication reliability and account compatibility
Resolve bugs in internal authentication handling and improve consistency across supported account flows. Maintain compatibility with existing accounts while preserving user data and established client behavior. Validation: TypeScript checks, production build, and Worker packaging checks passed.
This commit is contained in:
1 parent
588dce6a0a
commit
5f71cb388c
6 files changed
+144
-71
No files matched your search
@@ -316,7 +316,7 @@ export async function handleRegister(request: Request, env: Env): Promise<Respon
|
||||
|
||||
const now = new Date().toISOString();
|
||||
const auth = new AuthService(env);
|
||||
const serverHash = await auth.hashPasswordServer(masterPasswordHash, email);
|
||||
const serverHash = await auth.hashPasswordServer(masterPasswordHash);
|
||||
|
||||
const user: User = {
|
||||
id: generateUUID(),
|
||||
@@ -764,7 +764,7 @@ export async function handleChangePassword(request: Request, env: Env, userId: s
|
||||
return errorResponse('masterPasswordHint must be 120 characters or fewer', 400);
|
||||
}
|
||||
|
||||
user.masterPasswordHash = await auth.hashPasswordServer(newMasterPasswordHash, user.email);
|
||||
user.masterPasswordHash = await auth.hashPasswordServer(newMasterPasswordHash);
|
||||
user.key = nextKey;
|
||||
if (nextPrivateKey) user.privateKey = nextPrivateKey;
|
||||
if (nextPublicKey) user.publicKey = nextPublicKey;
|
||||
|
||||
+18
-28
@@ -391,35 +391,18 @@ export async function handleToken(request: Request, env: Env): Promise<Response>
|
||||
}
|
||||
|
||||
const user = await storage.getUser(email);
|
||||
if (!user) {
|
||||
await rateLimit.recordFailedLogin(loginIdentifier);
|
||||
return identityErrorResponse('Username or password is incorrect. Try again', 'invalid_grant', 400);
|
||||
}
|
||||
if (user.status !== 'active') {
|
||||
await rateLimit.recordFailedLogin(loginIdentifier);
|
||||
await safeWriteAuditEvent(env, {
|
||||
actorUserId: user.id,
|
||||
action: 'auth.login.failed.user_inactive',
|
||||
category: 'auth',
|
||||
level: 'warn',
|
||||
targetType: 'user',
|
||||
targetId: user.id,
|
||||
metadata: {
|
||||
grantType,
|
||||
deviceIdentifier: deviceInfo.deviceIdentifier,
|
||||
...auditRequestMetadata(request),
|
||||
},
|
||||
});
|
||||
return identityErrorResponse('Account is disabled', 'invalid_grant', 400);
|
||||
}
|
||||
|
||||
let validatedAuthRequestId: string | null = null;
|
||||
let authRequestLoginKey: string | null = null;
|
||||
let valid = false;
|
||||
const normalizedAuthRequestId = String(authRequestId || '').trim();
|
||||
if (normalizedAuthRequestId) {
|
||||
const authRequest = await storage.getAuthRequestByIdForUser(normalizedAuthRequestId, user.id);
|
||||
// Auth-request grants carry an access code, not a password hash. Pay the
|
||||
// same KDF cost and perform the lookup even when the account is missing.
|
||||
await auth.performDummyPasswordWork(passwordHash);
|
||||
const authRequest = await storage.getAuthRequestByIdForUser(normalizedAuthRequestId, user?.id ?? '');
|
||||
valid = !!(
|
||||
user &&
|
||||
user.status === 'active' &&
|
||||
authRequest &&
|
||||
authRequest.userId === user.id &&
|
||||
authRequest.type === 0 &&
|
||||
@@ -435,16 +418,19 @@ export async function handleToken(request: Request, env: Env): Promise<Response>
|
||||
authRequestLoginKey = authRequest!.key;
|
||||
}
|
||||
} else {
|
||||
valid = await auth.verifyPassword(passwordHash, user.masterPasswordHash, user.email);
|
||||
const passwordValid = await auth.verifyPassword(passwordHash, user?.masterPasswordHash ?? null, user?.email ?? email);
|
||||
valid = !!user && user.status === 'active' && passwordValid;
|
||||
}
|
||||
if (!valid) {
|
||||
if (!valid || !user) {
|
||||
await safeWriteAuditEvent(env, {
|
||||
actorUserId: user.id,
|
||||
action: normalizedAuthRequestId ? 'auth.login.failed.bad_auth_request' : 'auth.login.failed.bad_password',
|
||||
actorUserId: user?.id,
|
||||
action: user && user.status !== 'active'
|
||||
? 'auth.login.failed.user_inactive'
|
||||
: normalizedAuthRequestId ? 'auth.login.failed.bad_auth_request' : 'auth.login.failed.bad_password',
|
||||
category: 'auth',
|
||||
level: 'warn',
|
||||
targetType: 'user',
|
||||
targetId: user.id,
|
||||
targetId: user?.id,
|
||||
metadata: {
|
||||
grantType,
|
||||
deviceIdentifier: deviceInfo.deviceIdentifier,
|
||||
@@ -577,6 +563,10 @@ export async function handleToken(request: Request, env: Env): Promise<Response>
|
||||
}
|
||||
}
|
||||
|
||||
if (!normalizedAuthRequestId) {
|
||||
await auth.upgradePasswordVerifier(user, passwordHash);
|
||||
}
|
||||
|
||||
// Persist device only after successful password + (optional) 2FA verification.
|
||||
const deviceSession = await persistAndResolveDeviceSession(storage, user.id, deviceInfo);
|
||||
if (deviceSession) {
|
||||
|
||||
Reference in new issue
Block a user