mirror of
https://github.com/fluxerapp/fluxer.git
synced 2026-09-02 21:04:06 +03:00
fix(auth): harden login rate keys and totp reuse (#2347)
This commit is contained in:
@@ -38,6 +38,9 @@ import * as AuthPassword from './AuthPassword';
|
|||||||
import * as AuthSession from './AuthSession';
|
import * as AuthSession from './AuthSession';
|
||||||
import * as AuthUtility from './AuthUtility';
|
import * as AuthUtility from './AuthUtility';
|
||||||
|
|
||||||
|
const DUMMY_ARGON2_HASH =
|
||||||
|
'$argon2id$v=19$m=65536,t=3,p=4$fT6tGpAyxFiz+n1RbkRqWQ$v05UT17QGeqhsgRjcVjIWcGw6gUDYeCcAA8FiZ63MtA';
|
||||||
|
|
||||||
interface LoginParams {
|
interface LoginParams {
|
||||||
data: LoginRequest;
|
data: LoginRequest;
|
||||||
request: Request;
|
request: Request;
|
||||||
@@ -194,7 +197,7 @@ export async function login(
|
|||||||
const {inviteService, kvDeletionQueue} = deps;
|
const {inviteService, kvDeletionQueue} = deps;
|
||||||
const skipRateLimits = config.dev.testModeEnabled || config.dev.disableRateLimits;
|
const skipRateLimits = config.dev.testModeEnabled || config.dev.disableRateLimits;
|
||||||
const emailRateLimit = await rateLimit.checkLimit({
|
const emailRateLimit = await rateLimit.checkLimit({
|
||||||
identifier: `login:email:${data.email}`,
|
identifier: `login:email:${data.email.toLowerCase()}`,
|
||||||
maxAttempts: 5,
|
maxAttempts: 5,
|
||||||
windowMs: ms('15 minutes'),
|
windowMs: ms('15 minutes'),
|
||||||
});
|
});
|
||||||
@@ -221,9 +224,16 @@ export async function login(
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
AuthUtility.assertNonBotUser(ctx, user);
|
AuthUtility.assertNonBotUser(ctx, user);
|
||||||
|
if (!user.passwordHash) {
|
||||||
|
await AuthPassword.verifyPassword(ctx, {password: data.password, passwordHash: DUMMY_ARGON2_HASH});
|
||||||
|
throw InputValidationError.fromCodes([
|
||||||
|
{path: 'email', code: ValidationErrorCodes.INVALID_EMAIL_OR_PASSWORD},
|
||||||
|
{path: 'password', code: ValidationErrorCodes.INVALID_EMAIL_OR_PASSWORD},
|
||||||
|
]);
|
||||||
|
}
|
||||||
const isMatch = await AuthPassword.verifyPassword(ctx, {
|
const isMatch = await AuthPassword.verifyPassword(ctx, {
|
||||||
password: data.password,
|
password: data.password,
|
||||||
passwordHash: user.passwordHash!,
|
passwordHash: user.passwordHash,
|
||||||
});
|
});
|
||||||
if (!isMatch) {
|
if (!isMatch) {
|
||||||
throw InputValidationError.fromCodes([
|
throw InputValidationError.fromCodes([
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ export async function verifyMfaCode(ctx: ApiContext, params: VerifyMfaCodeParams
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const reuseKey = `mfa-totp:${userId}:${code}`;
|
const reuseKey = `mfa-totp:${userId}:${code}`;
|
||||||
const lockToken = await cache.acquireLock(reuseKey, seconds('30 seconds'));
|
const lockToken = await cache.acquireLock(reuseKey, seconds('90 seconds'));
|
||||||
if (lockToken) {
|
if (lockToken) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user