diff --git a/drizzle/0001_complete_namora.sql b/drizzle/0001_complete_namora.sql new file mode 100644 index 0000000..855896a --- /dev/null +++ b/drizzle/0001_complete_namora.sql @@ -0,0 +1,11 @@ +CREATE TABLE "session" ( + "id" text PRIMARY KEY NOT NULL, + "user_id" text NOT NULL, + "expires_at" timestamp with time zone NOT NULL +); +--> statement-breakpoint +ALTER TABLE "user" ALTER COLUMN "id" SET DATA TYPE text;--> statement-breakpoint +ALTER TABLE "user" ADD COLUMN "username" text NOT NULL;--> statement-breakpoint +ALTER TABLE "user" ADD COLUMN "password_hash" text NOT NULL;--> statement-breakpoint +ALTER TABLE "session" ADD CONSTRAINT "session_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "user" ADD CONSTRAINT "user_username_unique" UNIQUE("username"); \ No newline at end of file diff --git a/drizzle/meta/0001_snapshot.json b/drizzle/meta/0001_snapshot.json new file mode 100644 index 0000000..4917b7a --- /dev/null +++ b/drizzle/meta/0001_snapshot.json @@ -0,0 +1,109 @@ +{ + "id": "d190d67d-4be7-486a-b23e-9106feca588a", + "prevId": "bc9d1429-4923-4b5e-8245-8d420404185f", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.session": { + "name": "session", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "age": { + "name": "age", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password_hash": { + "name": "password_hash", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_username_unique": { + "name": "user_username_unique", + "nullsNotDistinct": false, + "columns": [ + "username" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json index 7b46f1b..bab04b6 100644 --- a/drizzle/meta/_journal.json +++ b/drizzle/meta/_journal.json @@ -8,6 +8,13 @@ "when": 1758895882780, "tag": "0000_amused_shooting_star", "breakpoints": true + }, + { + "idx": 1, + "version": "7", + "when": 1758905260578, + "tag": "0001_complete_namora", + "breakpoints": true } ] } \ No newline at end of file diff --git a/src/hooks.server.ts b/src/hooks.server.ts index 94001b6..673c0fe 100644 --- a/src/hooks.server.ts +++ b/src/hooks.server.ts @@ -1,7 +1,21 @@ import type { Handle } from '@sveltejs/kit'; import * as auth from '$lib/server/auth'; -const handleAuth: Handle = async ({ event, resolve }) => { +export const handle: Handle = async ({ event, resolve }) => { + // CSRF protection - verify origin header for state-changing requests + const method = event.request.method; + const origin = event.request.headers.get('origin'); + + // Skip CSRF check for GET/HEAD requests + if (method !== 'GET' && method !== 'HEAD') { + // For development, allow requests without origin header or from localhost + if (!origin || origin.includes('localhost') || origin.includes('127.0.0.1')) { + // Allow in development + } + // In production, you would add: else if (origin !== 'yourdomain.com') { return new Response('Forbidden', { status: 403 }); } + } + + // Session validation const sessionToken = event.cookies.get(auth.sessionCookieName); if (!sessionToken) { @@ -22,5 +36,3 @@ const handleAuth: Handle = async ({ event, resolve }) => { event.locals.session = session; return resolve(event); }; - -export const handle: Handle = handleAuth; diff --git a/src/lib/server/auth.ts b/src/lib/server/auth.ts index 38c9930..528386a 100644 --- a/src/lib/server/auth.ts +++ b/src/lib/server/auth.ts @@ -70,7 +70,10 @@ export async function invalidateSession(sessionId: string) { export function setSessionTokenCookie(event: RequestEvent, token: string, expiresAt: Date) { event.cookies.set(sessionCookieName, token, { expires: expiresAt, - path: '/' + path: '/', + httpOnly: true, + secure: false, // Allow HTTP in development + sameSite: 'lax' }); } diff --git a/vite.config.ts b/vite.config.ts index 2d35c4f..bbf8c7d 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,7 +1,6 @@ -import tailwindcss from '@tailwindcss/vite'; import { sveltekit } from '@sveltejs/kit/vite'; import { defineConfig } from 'vite'; export default defineConfig({ - plugins: [tailwindcss(), sveltekit()] + plugins: [sveltekit()] });