Adding ip country and address to the session DB, updating libraries and Lucia beta, updating auth flows for newest lucia changes.

This commit is contained in:
Bradley Shellnut 2024-01-18 16:57:15 -08:00
parent 994d1d462c
commit 9f4aafe658
9 changed files with 882 additions and 575 deletions

View file

@ -26,47 +26,47 @@
"seed": "node --loader ts-node/esm prisma/seed.ts"
},
"devDependencies": {
"@melt-ui/pp": "^0.1.4",
"@melt-ui/svelte": "^0.66.4",
"@playwright/test": "^1.40.1",
"@melt-ui/pp": "^0.3.0",
"@melt-ui/svelte": "^0.70.0",
"@playwright/test": "^1.41.0",
"@resvg/resvg-js": "^2.4.1",
"@sveltejs/adapter-auto": "^3.0.0",
"@sveltejs/adapter-vercel": "^4.0.0",
"@sveltejs/kit": "^2.0.0",
"@sveltejs/adapter-auto": "^3.1.0",
"@sveltejs/adapter-vercel": "^4.0.5",
"@sveltejs/kit": "^2.3.5",
"@sveltejs/vite-plugin-svelte": "^3.0.0",
"@types/cookie": "^0.5.4",
"@types/node": "^18.19.3",
"@typescript-eslint/eslint-plugin": "^6.16.0",
"@typescript-eslint/parser": "^6.16.0",
"autoprefixer": "^10.4.15",
"@types/node": "^18.19.8",
"@typescript-eslint/eslint-plugin": "^6.19.0",
"@typescript-eslint/parser": "^6.19.0",
"autoprefixer": "^10.4.17",
"eslint": "^8.56.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-svelte": "^2.35.1",
"just-clone": "^6.2.0",
"just-debounce-it": "^3.2.0",
"postcss": "^8.4.32",
"postcss": "^8.4.33",
"postcss-import": "^15.1.0",
"postcss-load-config": "^4.0.2",
"postcss-preset-env": "^9.3.0",
"prettier": "^3.1.1",
"prettier": "^3.2.4",
"prettier-plugin-svelte": "^3.1.2",
"prisma": "^5.7.1",
"sass": "^1.65.1",
"prisma": "^5.8.1",
"sass": "^1.70.0",
"satori": "^0.10.11",
"satori-html": "^0.3.2",
"svelte": "^4.2.8",
"svelte-check": "^3.6.2",
"svelte": "^4.2.9",
"svelte-check": "^3.6.3",
"svelte-meta-tags": "^3.1.0",
"svelte-preprocess": "^5.1.3",
"svelte-sequential-preprocessor": "^2.0.1",
"sveltekit-flash-message": "^2.3.0",
"sveltekit-superforms": "^1.13.1",
"tailwindcss": "^3.4.0",
"sveltekit-flash-message": "^2.3.1",
"sveltekit-superforms": "^1.13.3",
"tailwindcss": "^3.4.1",
"ts-node": "^10.9.2",
"tslib": "^2.6.1",
"typescript": "^5.3.3",
"vite": "^5.0.0",
"vitest": "^1.0.0",
"vite": "^5.0.11",
"vitest": "^1.2.1",
"zod": "^3.22.4"
},
"type": "module",
@ -78,10 +78,10 @@
"@fontsource/fira-mono": "^4.5.10",
"@iconify-icons/line-md": "^1.2.26",
"@iconify-icons/mdi": "^1.2.47",
"@lucia-auth/adapter-prisma": "4.0.0-beta.7",
"@lucia-auth/adapter-prisma": "4.0.0-beta.9",
"@lukeed/uuid": "^2.0.1",
"@paralleldrive/cuid2": "^2.2.2",
"@prisma/client": "^5.7.1",
"@prisma/client": "^5.8.1",
"@sentry/sveltekit": "^7.88.0",
"@types/feather-icons": "^4.29.4",
"@vercel/og": "^0.5.13",
@ -96,10 +96,10 @@
"iconify-icon": "^1.0.8",
"just-kebab-case": "^4.2.0",
"loader": "^2.1.1",
"lucia": "3.0.0-beta.12",
"lucia": "3.0.0-beta.14",
"lucide-svelte": "^0.298.0",
"open-props": "^1.6.16",
"oslo": "^0.24.0",
"oslo": "^0.27.1",
"radix-svelte": "^0.9.0",
"svelte-french-toast": "^1.2.0",
"svelte-lazy-loader": "^1.0.0",

File diff suppressed because it is too large Load diff

View file

@ -59,7 +59,8 @@ model User {
model Session {
id String @id @unique
userId String
country String
ip_country String
ip_address String
expiresAt DateTime
user User @relation(references: [id], fields: [userId], onDelete: Cascade)

7
src/app.d.ts vendored
View file

@ -17,15 +17,14 @@ declare global {
user: import('lucia').User | null;
prisma: PrismaClient;
startTimer: number;
ip: string;
country: string;
error: string;
errorId: string;
errorStackTrace: string;
message: unknown;
track: unknown;
session: {
ip: string,
country: string
}
session: import('lucia').Session | null;
}
interface Error {
code?: string;

View file

@ -15,32 +15,39 @@ export const authentication: Handle = async function ({ event, resolve }) {
const startTimer = Date.now();
event.locals.startTimer = startTimer;
let ip = event.request.headers.get('x-forwarded-for') as string;
if (!ip && browser) {
ip = event.getClientAddress();
}
const country = event.request.headers.get('x-vercel-ip-country') as string || 'unknown';
event.locals.session = {
ip,
country
};
const ip = event.request.headers.get('x-forwarded-for') as string;
const country = event.request.headers.get('x-vercel-ip-country') as string;
event.locals.ip = dev ? '127.0.0.1' : ip || event.getClientAddress();
event.locals.country = dev ? 'us' : country;
const sessionId = event.cookies.get(lucia.sessionCookieName);
if (!sessionId) {
event.locals.user = null;
event.locals.session = null;
return resolve(event);
}
const { session, user } = await lucia.validateSession(sessionId);
if (session && session.fresh) {
const sessionCookie = lucia.createSessionCookie(session.id);
event.cookies.set(sessionCookie.name, sessionCookie.value, sessionCookie.attributes);
console.log('sessionCookie', JSON.stringify(sessionCookie, null, 2));
// sveltekit types deviates from the de-facto standard
// you can use 'as any' too
event.cookies.set(sessionCookie.name, sessionCookie.value, {
path: '.',
...sessionCookie.attributes
});
}
if (!session) {
const sessionCookie = lucia.createBlankSessionCookie();
event.cookies.set(sessionCookie.name, sessionCookie.value, sessionCookie.attributes);
console.log('blank sessionCookie', JSON.stringify(sessionCookie, null, 2));
event.cookies.set(sessionCookie.name, sessionCookie.value, {
path: ".",
...sessionCookie.attributes
});
}
event.locals.user = user;
event.locals.session = session;
return resolve(event);
};

View file

@ -9,7 +9,8 @@ const adapter = new PrismaAdapter(prisma_client.session, prisma_client.user);
export const lucia = new Lucia(adapter, {
getSessionAttributes: (attributes) => {
return {
country: attributes.country,
ipCountry: attributes.ip_country,
ipAddress: attributes.ip_address
};
},
getUserAttributes: (attributes) => {
@ -37,9 +38,11 @@ export const lucia = new Lucia(adapter, {
declare module "lucia" {
interface Register {
Lucia: typeof lucia;
DatabaseUserAttributes: DatabaseUserAttributes;
}
interface DatabaseSessionAttributes {
country: string;
ip_country: string;
ip_address: string;
}
interface DatabaseUserAttributes {
username: string;

View file

@ -49,6 +49,8 @@ export const actions: Actions = {
}
});
console.log('user', JSON.stringify(user, null, 2));
if (!user || !user.hashed_password) {
form.data.password = '';
return setError(form, '', 'Your username or password is incorrect.');
@ -56,12 +58,16 @@ export const actions: Actions = {
const validPassword = await new Argon2id().verify(user.hashed_password, password);
if (!validPassword) {
console.log('invalid password');
form.data.password = '';
return setError(form, '', 'Your username or password is incorrect.');
}
console.log('ip', locals.ip);
console.log('country', locals.country);
session = await lucia.createSession(user.id, {
country: locals.session.ip
ip_country: locals.country,
ip_address: locals.ip
});
sessionCookie = lucia.createSessionCookie(session.id);
@ -94,7 +100,11 @@ export const actions: Actions = {
return setError(form, '', 'Your username or password is incorrect.');
}
event.cookies.set(sessionCookie.name, sessionCookie.value, sessionCookie.attributes);
event.cookies.set(sessionCookie.name, sessionCookie.value, {
path: ".",
...sessionCookie.attributes
});
form.data.username = '';
form.data.password = '';
const message = { type: 'success', message: 'Signed In!' };

View file

@ -1,15 +1,19 @@
import { redirect, type Actions } from '@sveltejs/kit';
import { redirect, fail } from '@sveltejs/kit';
import { lucia } from '$lib/server/auth';
import type { Actions } from "./$types";
export const actions: Actions = {
default: async ({ locals, cookies }) => {
console.log('Signing out user');
const sessionId = cookies.get(lucia.sessionCookieName);
if (!locals.user || !sessionId) {
redirect(302, '/login');
if (!locals.session) {
return fail(401);
}
await lucia.invalidateSession(sessionId);
// locals.auth.setSession(null); // remove cookie
redirect(302, '/');
await lucia.invalidateSession(locals.session.id);
const sessionCookie = lucia.createBlankSessionCookie();
cookies.set(sessionCookie.name, sessionCookie.value, {
path: '.',
...sessionCookie.attributes
});
return redirect(302, '/login');
}
};

View file

@ -87,7 +87,8 @@ export const actions: Actions = {
console.log('User', user);
session = await lucia.createSession(user.id, {
country: event.locals.session.country
ipCountry: event.locals.session?.ipCountry,
ipAddress: event.locals.session?.ipAddress
});
sessionCookie = lucia.createSessionCookie(session.id);
} catch (e: any) {
@ -105,7 +106,11 @@ export const actions: Actions = {
error(500, message);
}
event.cookies.set(sessionCookie.name, sessionCookie.value, sessionCookie.attributes);
event.cookies.set(sessionCookie.name, sessionCookie.value, {
path: ".",
...sessionCookie.attributes
});
redirect(302, '/');
// const message = { type: 'success', message: 'Signed Up!' } as const;
// throw flashRedirect(message, event);