migration to postgres

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-26 17:42:59 +00:00
co-authored by Claude Opus 4.6
parent 7f04ecd644
commit 500a70910e
54 changed files with 4016 additions and 264 deletions
+20 -14
View File
@@ -6,7 +6,7 @@ import { sign } from '../../jwt';
import * as errors from '../../custom-errors';
import {
getUserByEmail,
getPasskeysByEmailAndOrigin,
getPasskeysByUserIdAndOrigin,
getPasskeyByCredentialId,
createPasskey,
updatePasskey,
@@ -41,8 +41,11 @@ const passkeyRouterPostChallenge: Handler = async (ctx) => {
const origin = ctx.get('origin') as string;
const rpId = getRpId(origin);
const dbUser = await getUserByEmail(email!);
if (!dbUser) throw errors.NOT_FOUND('User not found');
// Get existing passkeys to exclude them
const existingPasskeys = getPasskeysByEmailAndOrigin(email!, origin);
const existingPasskeys = await getPasskeysByUserIdAndOrigin(dbUser.id, origin);
const options = await generateRegistrationOptions({
rpName: RP_NAME,
@@ -59,7 +62,7 @@ const passkeyRouterPostChallenge: Handler = async (ctx) => {
},
});
await storeChallenge(email!, origin, options.challenge);
await storeChallenge(dbUser.id, origin, options.challenge, CHALLENGE_TTL_MS);
return ctx.json(options);
};
passkeyRouter.post('/challenge/:email', passkeyRateLimiter, passkeyRouterPostChallenge);
@@ -68,10 +71,10 @@ passkeyRouter.post('/challenge/:email', passkeyRateLimiter, passkeyRouterPostCha
const passkeyRouterPost: Handler = async (ctx) => {
const origin = ctx.get('origin') as string;
const rpId = getRpId(origin);
const { email } = ctx.get('user') as User;
const user = ctx.get('user') as User;
const response = ctx.get('body') as RegistrationResponseJSON;
const storedChallenge = await consumeChallenge(email, origin, CHALLENGE_TTL_MS);
const storedChallenge = await consumeChallenge(user.id, origin);
if (!storedChallenge) throw errors.BAD_CREDENTIALS();
const verification = await verifyRegistrationResponse({
@@ -88,7 +91,7 @@ const passkeyRouterPost: Handler = async (ctx) => {
const { credential, credentialDeviceType, credentialBackedUp } = verification.registrationInfo;
await createPasskey({
email,
userId: user.id,
origin,
credentialId: credential.id,
publicKey: Buffer.from(credential.publicKey).toString('base64'),
@@ -105,7 +108,10 @@ const passkeyRouterGet: Handler = async (ctx) => {
const origin = ctx.get('origin') as string;
const rpId = getRpId(origin);
const passkeys = getPasskeysByEmailAndOrigin(email!, origin);
const dbUser = await getUserByEmail(email!);
if (!dbUser) throw errors.NOT_FOUND('User not found');
const passkeys = await getPasskeysByUserIdAndOrigin(dbUser.id, origin);
const options = await generateAuthenticationOptions({
rpID: rpId,
@@ -115,7 +121,7 @@ const passkeyRouterGet: Handler = async (ctx) => {
userVerification: 'preferred',
});
await storeChallenge(email!, origin, options.challenge);
await storeChallenge(dbUser.id, origin, options.challenge, CHALLENGE_TTL_MS);
return ctx.json(options);
};
passkeyRouter.get('/signin/:email', passkeyRateLimiter, passkeyRouterGet);
@@ -127,11 +133,14 @@ const passkeyRouterPostVerify: Handler = async (ctx) => {
const rpId = getRpId(origin);
const response = ctx.get('body') as AuthenticationResponseJSON;
const storedChallenge = await consumeChallenge(email!, origin, CHALLENGE_TTL_MS);
const dbUser = await getUserByEmail(email!);
if (!dbUser) throw errors.UNAUTHORIZED();
const storedChallenge = await consumeChallenge(dbUser.id, origin);
if (!storedChallenge) throw errors.BAD_CREDENTIALS();
// Find the passkey being used
const dbPasskey = getPasskeyByCredentialId(email!, response.id);
const dbPasskey = await getPasskeyByCredentialId(dbUser.id, response.id);
if (!dbPasskey || !dbPasskey.publicKey) throw errors.BAD_CREDENTIALS();
@@ -152,10 +161,7 @@ const passkeyRouterPostVerify: Handler = async (ctx) => {
// Update counter to prevent replay attacks
await updatePasskey(dbPasskey.id, { counter: verification.authenticationInfo.newCounter });
const dbUser = getUserByEmail(email!);
if (!dbUser) throw errors.UNAUTHORIZED();
const passkeys = getPasskeysByEmailAndOrigin(email!, origin);
const passkeys = await getPasskeysByUserIdAndOrigin(dbUser.id, origin);
const { id, name, username, role } = dbUser;
const token = await sign({