Skip to content

Commit 99f3e04

Browse files
fix: update lucia adder (#254)
Co-authored-by: AdrianGonz97 <[email protected]>
1 parent ce4d11c commit 99f3e04

File tree

2 files changed

+77
-63
lines changed

2 files changed

+77
-63
lines changed

.changeset/nice-lemons-attend.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'sv': patch
3+
---
4+
5+
fix: update lucia add-on

packages/adders/lucia/index.ts

Lines changed: 72 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -212,11 +212,14 @@ export default defineAdder({
212212
imports.addNamespace(ast, '$lib/server/db/schema', 'table');
213213
imports.addNamed(ast, '$lib/server/db', { db: 'db' });
214214
imports.addNamed(ast, '@oslojs/encoding', {
215-
encodeBase32LowerCaseNoPadding: 'encodeBase32LowerCaseNoPadding',
215+
encodeBase64url: 'encodeBase64url',
216216
encodeHexLowerCase: 'encodeHexLowerCase'
217217
});
218218
imports.addNamed(ast, '@oslojs/crypto/sha2', { sha256: 'sha256' });
219219
imports.addNamed(ast, 'drizzle-orm', { eq: 'eq' });
220+
if (typescript) {
221+
imports.addNamed(ast, '@sveltejs/kit', { RequestEvent: 'RequestEvent' }, true);
222+
}
220223

221224
const ms = new MagicString(generateCode().trim());
222225
const [ts] = utils.createPrinter(typescript);
@@ -227,21 +230,22 @@ export default defineAdder({
227230
if (!ms.original.includes('export const sessionCookieName')) {
228231
ms.append("\n\nexport const sessionCookieName = 'auth-session';");
229232
}
230-
if (!ms.original.includes('function generateSessionToken')) {
233+
if (!ms.original.includes('export function generateSessionToken')) {
231234
const generateSessionToken = dedent`
232-
${ts('', '/** @returns {string} */')}
233-
function generateSessionToken()${ts(': string')} {
234-
const bytes = crypto.getRandomValues(new Uint8Array(20));
235-
const token = encodeBase32LowerCaseNoPadding(bytes);
235+
export function generateSessionToken() {
236+
const bytes = crypto.getRandomValues(new Uint8Array(18));
237+
const token = encodeBase64url(bytes);
236238
return token;
237239
}`;
238240
ms.append(`\n\n${generateSessionToken}`);
239241
}
240242
if (!ms.original.includes('async function createSession')) {
241-
const createSession = dedent`
242-
${ts('', '/** @param {string} userId */')}
243-
export async function createSession(userId${ts(': string')})${ts(': Promise<table.Session>')} {
244-
const token = generateSessionToken();
243+
const createSession = dedent`
244+
${ts('', '/**')}
245+
${ts('', ' * @param {string} token')}
246+
${ts('', ' * @param {string} userId')}
247+
${ts('', ' */')}
248+
export async function createSession(token${ts(': string')}, userId${ts(': string')}) {
245249
const sessionId = encodeHexLowerCase(sha256(new TextEncoder().encode(token)));
246250
const session${ts(': table.Session')} = {
247251
id: sessionId,
@@ -253,21 +257,11 @@ export default defineAdder({
253257
}`;
254258
ms.append(`\n\n${createSession}`);
255259
}
256-
if (!ms.original.includes('async function invalidateSession')) {
257-
const invalidateSession = dedent`
258-
${ts('', '/**')}
259-
${ts('', ' * @param {string} sessionId')}
260-
${ts('', ' * @returns {Promise<void>}')}
261-
${ts('', ' */')}
262-
export async function invalidateSession(sessionId${ts(': string')})${ts(': Promise<void>')} {
263-
await db.delete(table.session).where(eq(table.session.id, sessionId));
264-
}`;
265-
ms.append(`\n\n${invalidateSession}`);
266-
}
267-
if (!ms.original.includes('async function validateSession')) {
268-
const validateSession = dedent`
269-
${ts('', '/** @param {string} sessionId */')}
270-
export async function validateSession(sessionId${ts(': string')}) {
260+
if (!ms.original.includes('async function validateSessionToken')) {
261+
const validateSessionToken = dedent`
262+
${ts('', '/** @param {string} token */')}
263+
export async function validateSessionToken(token${ts(': string')}) {
264+
const sessionId = encodeHexLowerCase(sha256(new TextEncoder().encode(token)));
271265
const [result] = await db
272266
.select({
273267
// Adjust user table here to tweak returned data
@@ -300,14 +294,46 @@ export default defineAdder({
300294
301295
return { session, user };
302296
}`;
303-
ms.append(`\n\n${validateSession}`);
297+
ms.append(`\n\n${validateSessionToken}`);
304298
}
305299
if (typescript && !ms.original.includes('export type SessionValidationResult')) {
306300
const sessionType =
307-
'export type SessionValidationResult = Awaited<ReturnType<typeof validateSession>>;';
301+
'export type SessionValidationResult = Awaited<ReturnType<typeof validateSessionToken>>;';
308302
ms.append(`\n\n${sessionType}`);
309303
}
310-
304+
if (!ms.original.includes('async function invalidateSession')) {
305+
const invalidateSession = dedent`
306+
${ts('', '/** @param {string} sessionId */')}
307+
export async function invalidateSession(sessionId${ts(': string')}) {
308+
await db.delete(table.session).where(eq(table.session.id, sessionId));
309+
}`;
310+
ms.append(`\n\n${invalidateSession}`);
311+
}
312+
if (!ms.original.includes('export function setSessionTokenCookie')) {
313+
const setSessionTokenCookie = dedent`
314+
${ts('', '/**')}
315+
${ts('', ' * @param {import("@sveltejs/kit").RequestEvent} event')}
316+
${ts('', ' * @param {string} token')}
317+
${ts('', ' * @param {Date} expiresAt')}
318+
${ts('', ' */')}
319+
export function setSessionTokenCookie(event${ts(': RequestEvent')}, token${ts(': string')}, expiresAt${ts(': Date')}) {
320+
event.cookies.set(sessionCookieName, token, {
321+
expires: expiresAt,
322+
path: '/'
323+
});
324+
}`;
325+
ms.append(`\n\n${setSessionTokenCookie}`);
326+
}
327+
if (!ms.original.includes('export function deleteSessionTokenCookie')) {
328+
const deleteSessionTokenCookie = dedent`
329+
${ts('', '/** @param {import("@sveltejs/kit").RequestEvent} event */')}
330+
export function deleteSessionTokenCookie(event${ts(': RequestEvent')}) {
331+
event.cookies.delete(sessionCookieName, {
332+
path: '/'
333+
});
334+
}`;
335+
ms.append(`\n\n${deleteSessionTokenCookie}`);
336+
}
311337
return ms.toString();
312338
}
313339
},
@@ -339,7 +365,6 @@ export default defineAdder({
339365
content: ({ content, typescript }) => {
340366
const { ast, generateCode } = parseScript(content);
341367
imports.addNamespace(ast, '$lib/server/auth.js', 'auth');
342-
imports.addNamed(ast, '$app/environment', { dev: 'dev' });
343368
kit.addHooksHandle(ast, typescript, 'handleAuth', getAuthHandleContent());
344369
return generateCode();
345370
}
@@ -365,10 +390,9 @@ export default defineAdder({
365390
const [ts] = utils.createPrinter(typescript);
366391
return dedent`
367392
import { hash, verify } from '@node-rs/argon2';
368-
import { generateRandomString } from '@oslojs/crypto/random';
393+
import { encodeBase64url } from '@oslojs/encoding';
369394
import { fail, redirect } from '@sveltejs/kit';
370395
import { eq } from 'drizzle-orm';
371-
import { dev } from '$app/environment';
372396
import * as auth from '$lib/server/auth';
373397
import { db } from '$lib/server/db';
374398
import * as table from '$lib/server/db/schema';
@@ -413,14 +437,9 @@ export default defineAdder({
413437
return fail(400, { message: 'Incorrect username or password' });
414438
}
415439
416-
const session = await auth.createSession(existingUser.id);
417-
event.cookies.set(auth.sessionCookieName, session.id, {
418-
path: '/',
419-
sameSite: 'lax',
420-
httpOnly: true,
421-
expires: session.expiresAt,
422-
secure: !dev
423-
});
440+
const sessionToken = auth.generateSessionToken();
441+
const session = await auth.createSession(sessionToken, existingUser.id);
442+
auth.setSessionTokenCookie(event, sessionToken, session.expiresAt);
424443
425444
return redirect(302, '/demo/lucia');
426445
},
@@ -448,25 +467,21 @@ export default defineAdder({
448467
try {
449468
await db.insert(table.user).values({ id: userId, username, passwordHash });
450469
451-
const session = await auth.createSession(userId);
452-
event.cookies.set(auth.sessionCookieName, session.id, {
453-
path: '/',
454-
sameSite: 'lax',
455-
httpOnly: true,
456-
expires: session.expiresAt,
457-
secure: !dev
458-
});
470+
const sessionToken = auth.generateSessionToken();
471+
const session = await auth.createSession(sessionToken, userId);
472+
auth.setSessionTokenCookie(event, sessionToken, session.expiresAt);
459473
} catch (e) {
460474
return fail(500, { message: 'An error has occurred' });
461475
}
462476
return redirect(302, '/demo/lucia');
463477
},
464478
};
465479
466-
const alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_';
467-
468-
function generateUserId(length = 21)${ts(': string')} {
469-
return generateRandomString({ read: (bytes) => crypto.getRandomValues(bytes) }, alphabet, length);
480+
function generateUserId() {
481+
// ID with 120 bits of entropy, or about the same as UUID v4.
482+
const bytes = crypto.getRandomValues(new Uint8Array(15));
483+
const id = encodeBase64url(bytes);
484+
return id;
470485
}
471486
472487
function validateUsername(username${ts(': unknown')})${ts(': username is string')} {
@@ -554,7 +569,7 @@ export default defineAdder({
554569
return fail(401);
555570
}
556571
await auth.invalidateSession(event.locals.session.id);
557-
event.cookies.delete(auth.sessionCookieName, { path: '/' });
572+
auth.deleteSessionTokenCookie(event);
558573
559574
return redirect(302, '/demo/lucia/login');
560575
},
@@ -636,24 +651,18 @@ function createLuciaType(name: string): AstTypes.TSInterfaceBody['body'][number]
636651
function getAuthHandleContent() {
637652
return `
638653
async ({ event, resolve }) => {
639-
const sessionId = event.cookies.get(auth.sessionCookieName);
640-
if (!sessionId) {
654+
const sessionToken = event.cookies.get(auth.sessionCookieName);
655+
if (!sessionToken) {
641656
event.locals.user = null;
642657
event.locals.session = null;
643658
return resolve(event);
644659
}
645660
646-
const { session, user } = await auth.validateSession(sessionId);
661+
const { session, user } = await auth.validateSessionToken(sessionToken);
647662
if (session) {
648-
event.cookies.set(auth.sessionCookieName, session.id, {
649-
path: '/',
650-
sameSite: 'lax',
651-
httpOnly: true,
652-
expires: session.expiresAt,
653-
secure: !dev
654-
});
663+
auth.setSessionTokenCookie(event, sessionToken, session.expiresAt);
655664
} else {
656-
event.cookies.delete(auth.sessionCookieName, { path: '/' });
665+
auth.deleteSessionTokenCookie(event);
657666
}
658667
659668
event.locals.user = user;

0 commit comments

Comments
 (0)