diff options
| author | Joe Carstairs <jcarstairs@scottlogic.com> | 2024-01-22 14:59:51 +0000 |
|---|---|---|
| committer | Joe Carstairs <jcarstairs@scottlogic.com> | 2024-01-29 10:51:49 +0000 |
| commit | 19b4835bea200099bae15bc02edd5e4cafa2c46c (patch) | |
| tree | f58a0124b361c16b51a55ebe68fcf52845438270 | |
| parent | edcb9577e28dc312f48d5ab3f5ecc8eeffd8db56 (diff) | |
verifyRegistrationResponse is single-responsibility!
| -rw-r--r-- | api/auth/_verifyRegistrationResponse.ts | 15 | ||||
| -rw-r--r-- | api/auth/registration.ts | 14 | ||||
| -rw-r--r-- | api/db/_deleteCurrentChallenge.ts | 15 | ||||
| -rw-r--r-- | api/db/_deleteUser.ts | 18 | ||||
| -rw-r--r-- | api/db/_deleteUserAuthenticators.ts | 16 |
5 files changed, 66 insertions, 12 deletions
diff --git a/api/auth/_verifyRegistrationResponse.ts b/api/auth/_verifyRegistrationResponse.ts index 66af079..350bf0b 100644 --- a/api/auth/_verifyRegistrationResponse.ts +++ b/api/auth/_verifyRegistrationResponse.ts @@ -4,8 +4,6 @@ import { type RegistrationResponseJSON } from '@simplewebauthn/server/script/dep import { verifyRegistrationResponse as innerVerifyRegistrationResponse } from '@simplewebauthn/server'; import RELYING_PARTY from './_relyingParty'; -import addAuthenticator from '../db/_addAuthenticator'; -import addUser from '../db/_addUser'; import env from '../_env'; /** @@ -14,14 +12,14 @@ import env from '../_env'; * matches the expected challenge, which should be the most recent challenge * to be associated with the given user. * - * If verification is successful, saves the new user and their new - * authenticator to the database. + * If verification is successful, returns the authenticator object. Otherwise, + * returns null. */ export default async function verifyRegistrationResponse( newUser: User, expectedChallenge: string, registrationResponse: RegistrationResponseJSON, -): Promise<boolean> { +): Promise<Authenticator | null> { const verification = await innerVerifyRegistrationResponse({ response: registrationResponse, expectedChallenge, @@ -34,7 +32,7 @@ export default async function verifyRegistrationResponse( }); if (!verification.verified || !verification.registrationInfo) { - return false; + return null; } const authenticator: Authenticator = { @@ -55,8 +53,5 @@ export default async function verifyRegistrationResponse( transports: verification.registrationInfo['transports'] ?? [], }; - await addUser(newUser); - await addAuthenticator(authenticator); - - return true; + return authenticator; } diff --git a/api/auth/registration.ts b/api/auth/registration.ts index d318d83..9f1c377 100644 --- a/api/auth/registration.ts +++ b/api/auth/registration.ts @@ -6,6 +6,9 @@ import verifyRegistrationResponse from './_verifyRegistrationResponse'; import getUser from '../db/_getUser'; import getCurrentChallenge from '../db/_getCurrentChallenge'; import setCurrentChallenge from '../db/_setCurrentChallenge'; +import { getFirstQueryParam } from '../_getFirstQueryParam'; +import addUser from 'db/_addUser'; +import addAuthenticator from 'db/_addAuthenticator'; /** * # registration @@ -152,8 +155,15 @@ async function handlePost(request: VercelRequest): Promise<(r: VercelResponse) = ); } - const isValid = await verifyRegistrationResponse(newUser, expectedChallenge, registrationResponse); + const authenticator = await verifyRegistrationResponse(newUser, expectedChallenge, registrationResponse); + const isVerified = !!authenticator; + + if (isVerified) { + await addUser(newUser); + await addAuthenticator(authenticator); + } + return (response) => void ( - response.status(200).send(isValid ? 'true' : 'false') + response.status(200).send(isVerified ? 'true' : 'false') ); } diff --git a/api/db/_deleteCurrentChallenge.ts b/api/db/_deleteCurrentChallenge.ts new file mode 100644 index 0000000..1f597bc --- /dev/null +++ b/api/db/_deleteCurrentChallenge.ts @@ -0,0 +1,15 @@ +import { sql } from '@vercel/postgres'; +import { CURRENT_CHALLENGES } from './_tables'; + +export default async function deleteCurrentChallenge(userId: string) { + const query = ` + DELETE FROM ${CURRENT_CHALLENGES.name} + WHERE ${CURRENT_CHALLENGES.fields.userId} = '${userId}' + `; + + try { + await sql.query(query); + } catch (err) { + throw new Error(`Failed to delete current challenge for user with ID ${userId} in database. Query was ${query.replace(/\s+/g, ' ')}. ${err}`); + } +} diff --git a/api/db/_deleteUser.ts b/api/db/_deleteUser.ts new file mode 100644 index 0000000..c926800 --- /dev/null +++ b/api/db/_deleteUser.ts @@ -0,0 +1,18 @@ +import type User from '../types/User'; + +import { sql } from '@vercel/postgres'; +import { USERS } from './_tables'; + +export default async function deleteUser(id: User['id']) { + const query = ` + DELETE FROM ${USERS.name} + WHERE ${USERS.fields.id} = '${id}', + ; + `; + + try { + await sql.query(query); + } catch (err) { + throw new Error(`Failed to delete user from database with ID: ${id}. Query was ${query.replace(/\s+/g, ' ')}. ${err}`); + } +} diff --git a/api/db/_deleteUserAuthenticators.ts b/api/db/_deleteUserAuthenticators.ts new file mode 100644 index 0000000..32f4ea5 --- /dev/null +++ b/api/db/_deleteUserAuthenticators.ts @@ -0,0 +1,16 @@ +import { sql } from '@vercel/postgres'; +import { AUTHENTICATORS } from './_tables'; +import User from '../types/User'; + +export default async function deleteUserAuthenticators(userId: User['id']) { + const query = ` + DELETE FROM ${AUTHENTICATORS.name} + WHERE ${AUTHENTICATORS.fields.id} = '${id}'; + `; + + try { + await sql.query(query); + } catch (err) { + throw new Error(`Failed to delete authenticators for user with ID ${userId} from database. Query was ${query.replace(/\s+/g, ' ')}. ${err}`); + } +} |
