improvements

This commit is contained in:
Bernd Storath 2026-06-12 11:49:34 +02:00
parent 648b114a5f
commit db8f3d6a09
5 changed files with 48 additions and 15 deletions

View file

@ -9,7 +9,7 @@ export default defineEventHandler(async (event) => {
event,
validateZod(Verify2faSchema, event)
);
const session = await useWGSession(event, false);
const session = await useWGSession(event);
const pendingLogin = session.data.pendingLogin;
if (!pendingLogin) {
@ -19,13 +19,23 @@ export default defineEventHandler(async (event) => {
});
}
const isValid = await Database.users.validateTotpCode(
const totpStatus = await Database.users.validateTotpCode(
pendingLogin.userId,
totpCode
);
if (!isValid) {
return { status: 'INVALID_TOTP_CODE' as const };
switch (totpStatus) {
case 'INVALID_TOTP_CODE':
return { status: 'INVALID_TOTP_CODE' as const };
case 'USER_DISABLED':
throw createError({
statusCode: 401,
statusMessage: 'User disabled',
});
case 'success':
break;
default:
assertUnreachable(totpStatus);
}
await session.update({

View file

@ -1,7 +1,7 @@
export default defineEventHandler(async (event) => {
const session = await useWGSession(event);
if (!session.data.userId) {
if (!session.data.userId || session.data.pendingLogin) {
// not logged in
throw createError({
statusCode: 401,
@ -16,6 +16,12 @@ export default defineEventHandler(async (event) => {
statusMessage: 'Not found in Database',
});
}
if (!user.enabled) {
throw createError({
statusCode: 403,
statusMessage: 'User is disabled',
});
}
return {
id: user.id,

View file

@ -195,6 +195,10 @@ export class UserService {
return { success: false, error: 'INCORRECT_CREDENTIALS' };
}
if (!txUser.enabled) {
return { success: false, error: 'USER_DISABLED' };
}
if (txUser.totpVerified) {
return {
success: false,
@ -203,10 +207,6 @@ export class UserService {
};
}
if (!txUser.enabled) {
return { success: false, error: 'USER_DISABLED' };
}
return { success: true, user: txUser };
});
}
@ -272,14 +272,24 @@ export class UserService {
.execute();
if (!txUser || !txUser.totpVerified || !txUser.totpKey) {
return false;
return 'INVALID_TOTP_CODE' as const;
}
const totp = this.#createTotp({
username: txUser.username,
totpKey: txUser.totpKey,
});
return totp.validate({ token: code, window: 1 }) !== null;
const isValid = totp.validate({ token: code, window: 1 }) !== null;
if (!isValid) {
return 'INVALID_TOTP_CODE' as const;
}
if (!txUser.enabled) {
return 'USER_DISABLED' as const;
}
return 'success' as const;
}
/**
@ -305,6 +315,9 @@ export class UserService {
.execute();
if (userById) {
if (!userById.enabled) {
return { success: false, error: 'USER_DISABLED' };
}
if (userById.totpVerified) {
return {
success: false,
@ -312,9 +325,6 @@ export class UserService {
userId: userById.id,
};
}
if (!userById.enabled) {
return { success: false, error: 'USER_DISABLED' };
}
return { success: true, user: userById };
}

View file

@ -144,7 +144,10 @@ export function hasPermissionsWithData<Resource extends keyof Permissions>(
const isAllowed = hasPermissions(user, resource, action, data);
if (!isAllowed) {
throw new Error('Permission denied');
throw createError({
statusCode: 403,
statusMessage: 'Permission denied',
});
}
return isAllowed;

View file

@ -17,4 +17,8 @@ describe('password', () => {
expect(isValidPasswordHash(hash.replace('argon2', 'argon3'))).toBe(false);
});
test('missing password hash is never valid', async () => {
await expect(isPasswordValid('password', null)).resolves.toBe(false);
});
});