mirror of
https://github.com/BradNut/boredgame
synced 2025-09-08 17:40:22 +00:00
Adding show 2FA on login if it is enabled on the user.
This commit is contained in:
parent
826d06113d
commit
8b48466c7e
3 changed files with 47 additions and 16 deletions
|
|
@ -1,5 +1,6 @@
|
|||
import { refinePasswords } from "./account";
|
||||
import { userSchema } from "./zod-schemas";
|
||||
import {z} from "zod";
|
||||
|
||||
export const signUpSchema = userSchema
|
||||
.pick({
|
||||
|
|
@ -15,7 +16,14 @@ export const signUpSchema = userSchema
|
|||
refinePasswords(confirm_password, password, ctx);
|
||||
});
|
||||
|
||||
export const signInSchema = userSchema.pick({
|
||||
username: true,
|
||||
password: true
|
||||
});
|
||||
export const signInSchema = z.object({
|
||||
username: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(3, { message: 'Username must be at least 3 characters' })
|
||||
.max(50, { message: 'Username must be less than 50 characters' }),
|
||||
password: z
|
||||
.string({ required_error: 'Password is required' })
|
||||
.trim(),
|
||||
totpToken: z.string().trim().min(6).max(6).optional()
|
||||
})
|
||||
|
|
@ -1,15 +1,17 @@
|
|||
import { fail, error, type Actions } from '@sveltejs/kit';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import { Argon2id } from 'oslo/password';
|
||||
import { decodeHex } from 'oslo/encoding';
|
||||
import { TOTPController } from 'oslo/otp';
|
||||
import { zod } from 'sveltekit-superforms/adapters';
|
||||
import { setError, superValidate } from 'sveltekit-superforms/server';
|
||||
import { redirect } from 'sveltekit-flash-message/server';
|
||||
import { Argon2id } from 'oslo/password';
|
||||
import { RateLimiter } from 'sveltekit-rate-limiter/server';
|
||||
import db from '$lib/drizzle';
|
||||
import { lucia } from '$lib/server/auth';
|
||||
import { signInSchema } from '$lib/validations/auth';
|
||||
import { collections, users, wishlists } from '../../../schema';
|
||||
import type { PageServerLoad } from './$types';
|
||||
import { RateLimiter } from 'sveltekit-rate-limiter/server';
|
||||
|
||||
export const load: PageServerLoad = async (event) => {
|
||||
if (event.locals.user) {
|
||||
|
|
@ -20,13 +22,13 @@ export const load: PageServerLoad = async (event) => {
|
|||
const form = await superValidate(event, zod(signInSchema));
|
||||
|
||||
return {
|
||||
form
|
||||
form,
|
||||
};
|
||||
};
|
||||
|
||||
const limiter = new RateLimiter({
|
||||
// A rate is defined by [number, unit]
|
||||
IPUA: [5, 'm']
|
||||
IPUA: [5, 'm'],
|
||||
});
|
||||
|
||||
export const actions: Actions = {
|
||||
|
|
@ -41,7 +43,7 @@ export const actions: Actions = {
|
|||
if (!form.valid) {
|
||||
form.data.password = '';
|
||||
return fail(400, {
|
||||
form
|
||||
form,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -51,12 +53,12 @@ export const actions: Actions = {
|
|||
const password = form.data.password;
|
||||
|
||||
const user = await db.query.users.findFirst({
|
||||
where: eq(users.username, form.data.username)
|
||||
where: eq(users.username, form.data.username),
|
||||
});
|
||||
|
||||
console.log('user', JSON.stringify(user, null, 2));
|
||||
|
||||
if (!user || !user.hashed_password) {
|
||||
if (!user?.hashed_password) {
|
||||
form.data.password = '';
|
||||
return setError(form, '', 'Your username or password is incorrect.');
|
||||
}
|
||||
|
|
@ -71,21 +73,38 @@ export const actions: Actions = {
|
|||
await db
|
||||
.insert(collections)
|
||||
.values({
|
||||
user_id: user.id
|
||||
user_id: user.id,
|
||||
})
|
||||
.onConflictDoNothing();
|
||||
await db
|
||||
.insert(wishlists)
|
||||
.values({
|
||||
user_id: user.id
|
||||
user_id: user.id,
|
||||
})
|
||||
.onConflictDoNothing();
|
||||
|
||||
if (user?.two_factor_enabled && user?.two_factor_secret && !form?.data?.totpToken) {
|
||||
return setError(
|
||||
form,
|
||||
'totpToken',
|
||||
'Two factor authentication is enabled. Please enter your 2FA code.',
|
||||
);
|
||||
} else if (user?.two_factor_enabled && user?.two_factor_secret && form?.data?.totpToken) {
|
||||
console.log('totpToken', form.data.totpToken);
|
||||
const validOTP = await new TOTPController().verify(
|
||||
form.data.totpToken,
|
||||
decodeHex(user.two_factor_secret)
|
||||
);
|
||||
console.log('validOTP', validOTP);
|
||||
if (!validOTP) {
|
||||
return setError(form, 'totpToken', 'Invalid 2FA code');
|
||||
}
|
||||
}
|
||||
console.log('ip', locals.ip);
|
||||
console.log('country', locals.country);
|
||||
session = await lucia.createSession(user.id, {
|
||||
ip_country: locals.country,
|
||||
ip_address: locals.ip
|
||||
ip_address: locals.ip,
|
||||
});
|
||||
console.log('logging in session', session);
|
||||
sessionCookie = lucia.createSessionCookie(session.id);
|
||||
|
|
@ -100,12 +119,12 @@ export const actions: Actions = {
|
|||
console.log('setting session cookie', sessionCookie);
|
||||
event.cookies.set(sessionCookie.name, sessionCookie.value, {
|
||||
path: '.',
|
||||
...sessionCookie.attributes
|
||||
...sessionCookie.attributes,
|
||||
});
|
||||
|
||||
form.data.username = '';
|
||||
form.data.password = '';
|
||||
const message = { type: 'success', message: 'Signed In!' } as const;
|
||||
redirect(302, '/', message, event);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -47,6 +47,10 @@
|
|||
<Input type="text" id="username" name="username" placeholder="Username" autocomplete="username" data-invalid={$errors.username} bind:value={$form.username} required />
|
||||
<Label for="password">Password</Label>
|
||||
<Input type="password" id="password" name="password" placeholder="Password" autocomplete="password" data-invalid={$errors.password} bind:value={$form.password} required />
|
||||
{#if $errors.totpToken}
|
||||
<Label for="totpToken">2FA Code</Label>
|
||||
<Input type="text" id="totpToken" name="totpToken" placeholder="2FA Code" autocomplete="one-time-code" data-invalid={$errors.totpToken} bind:value={$form.totpToken} />
|
||||
{/if}
|
||||
<Button type="submit">Login</Button>
|
||||
{#if $errors._errors}
|
||||
<Alert.Root variant="destructive">
|
||||
|
|
|
|||
Loading…
Reference in a new issue