diff --git a/cookies.txt b/cookies.txt new file mode 100644 index 0000000..c31d989 --- /dev/null +++ b/cookies.txt @@ -0,0 +1,4 @@ +# Netscape HTTP Cookie File +# https://curl.se/docs/http-cookies.html +# This file was generated by libcurl! Edit at your own risk. + diff --git a/env.example b/env.example index 9e0ce9f..4fb944a 100644 --- a/env.example +++ b/env.example @@ -8,5 +8,8 @@ ORIGIN=https://your-domain.com # Authentication token (required - generate a secure random token) MAGIC_LINK_TOKEN=your-secure-token-here +# Access PIN code (required - set a PIN for site access) +ACCESS_PIN=1234 + # Cloudinary URL for photo uploads (optional) CLOUDINARY_URL=cloudinary://api_key:api_secret@cloud_name diff --git a/src/app.d.ts b/src/app.d.ts index 4e61bff..0ce4e60 100644 --- a/src/app.d.ts +++ b/src/app.d.ts @@ -8,6 +8,7 @@ declare global { // interface Platform {} interface Locals { authenticated: boolean; + hasAccess: boolean; } } } diff --git a/src/hooks.server.ts b/src/hooks.server.ts index c7479ac..6cb842d 100644 --- a/src/hooks.server.ts +++ b/src/hooks.server.ts @@ -1,12 +1,24 @@ import type { Handle } from '@sveltejs/kit'; +import { redirect } from '@sveltejs/kit'; +import { dev } from '$app/environment'; export const handle: Handle = async ({ event, resolve }) => { + // Check if user has access (PIN code authentication) + const accessCookie = event.cookies.get('access_granted'); + const hasAccess = !!accessCookie; + + // If user doesn't have access and is not on the access page, redirect to /access + if (!hasAccess && event.url.pathname !== '/access') { + throw redirect(302, '/access'); + } + // Check if user is authenticated using the chef token cookie const chefToken = event.cookies.get('chef_token'); const authenticated = !!chefToken; // Add authentication status to locals for use in load functions event.locals.authenticated = authenticated; + event.locals.hasAccess = hasAccess; // Continue with the request const response = await resolve(event); diff --git a/src/routes/access/+page.server.ts b/src/routes/access/+page.server.ts new file mode 100644 index 0000000..7e78daf --- /dev/null +++ b/src/routes/access/+page.server.ts @@ -0,0 +1,38 @@ +import type { PageServerLoad, Actions } from './$types'; +import { fail, redirect } from '@sveltejs/kit'; +import { dev } from '$app/environment'; + +export const load: PageServerLoad = async ({ locals }) => { + // If user already has access, redirect to home + if (locals.hasAccess) { + throw redirect(302, '/'); + } + + return {}; +}; + +export const actions: Actions = { + default: async ({ request, cookies }) => { + const data = await request.formData(); + const pin = data.get('pin') as string; + + if (!pin) { + return fail(400, { error: 'PIN is required' }); + } + + if (pin !== process.env.ACCESS_PIN) { + return fail(400, { error: 'Invalid PIN' }); + } + + // Set access cookie + cookies.set('access_granted', 'true', { + path: '/', + httpOnly: true, + sameSite: 'lax', + secure: !dev, + maxAge: 60 * 60 * 24 * 30 // 30 days + }); + + throw redirect(302, '/'); + } +}; diff --git a/src/routes/access/+page.svelte b/src/routes/access/+page.svelte new file mode 100644 index 0000000..acd1949 --- /dev/null +++ b/src/routes/access/+page.svelte @@ -0,0 +1,47 @@ + + + + Access Bible + + +
+
+
+
+

Access

+

Enter your access code to continue

+
+ +
+
+ + + {#if form?.error} +
+ {form.error} +
+ {/if} +
+ +
+ +
+
+
+
+
diff --git a/src/routes/logout/+server.ts b/src/routes/logout/+server.ts index cbfed57..0da51a0 100644 --- a/src/routes/logout/+server.ts +++ b/src/routes/logout/+server.ts @@ -20,6 +20,15 @@ export const POST: RequestHandler = async ({ cookies }) => { maxAge: 0 // Expire immediately }); + // Clear the access cookie + cookies.set('access_granted', '', { + path: '/', + httpOnly: true, + sameSite: 'lax', + secure: !dev, + maxAge: 0 // Expire immediately + }); + // Redirect to home page throw redirect(302, '/'); }; @@ -42,6 +51,15 @@ export const GET: RequestHandler = async ({ cookies }) => { maxAge: 0 // Expire immediately }); + // Clear the access cookie + cookies.set('access_granted', '', { + path: '/', + httpOnly: true, + sameSite: 'lax', + secure: !dev, + maxAge: 0 // Expire immediately + }); + // Redirect to home page throw redirect(302, '/'); };