diff --git a/src/webauthn/webauthn.route.ts b/src/webauthn/webauthn.route.ts index 11a8538..f9a6c3b 100644 --- a/src/webauthn/webauthn.route.ts +++ b/src/webauthn/webauthn.route.ts @@ -18,6 +18,7 @@ const rpName = "Quicker Permits"; const origin = `http://${rpID}:3000`; export async function webAuthnRoutes(fastify: FastifyInstance) { + // Registration request fastify.post<{ Body: { email: string } }>( "/register/request", { @@ -79,59 +80,87 @@ export async function webAuthnRoutes(fastify: FastifyInstance) { } ); + // Registration verification fastify.post<{ Body: { email: string; code: string; attestationResponse: RegistrationResponseJSON; }; - }>("/register/verify", async (req, res: FastifyReply) => { - const { email, code, attestationResponse } = req.body; + }>( + "/register/verify", + { + schema: { + body: { + type: "object", + properties: { + email: { type: "string" }, + code: { type: "string" }, + attestationResponse: { type: "object" }, + }, + }, + }, + }, + async (req, res: FastifyReply) => { + const { email, code, attestationResponse } = req.body; - const userInDB = await getUserByEmail(email); - if (!userInDB) return res.code(400).send({ error: "not allowed" }); + const userInDB = await getUserByEmail(email); + if (!userInDB) return res.code(400).send({ error: "not allowed" }); - const challenge = userInDB.challenge; - const requiredOTP = userInDB.otp; + const challenge = userInDB.challenge; + const requiredOTP = userInDB.otp; - if (!challenge || !requiredOTP) - return res.code(400).send({ error: "not allowed" }); + if (!challenge || !requiredOTP) + return res.code(400).send({ error: "not allowed" }); - if (new Date() > challenge.expiry || new Date() > requiredOTP.expiry) - return res.code(400).send({ error: "challenge expired" }); + if (new Date() > challenge.expiry || new Date() > requiredOTP.expiry) + return res.code(400).send({ error: "challenge expired" }); - if (code != requiredOTP.value) - return res.code(400).send({ error: "invalid code" }); + if (code != requiredOTP.value) + return res.code(400).send({ error: "invalid code" }); - try { - const verification = await verifyRegistrationResponse({ - response: attestationResponse, - expectedChallenge: challenge.value as string, - expectedRPID: rpID, - expectedOrigin: origin, - }); + try { + const verification = await verifyRegistrationResponse({ + response: attestationResponse, + expectedChallenge: challenge.value as string, + expectedRPID: rpID, + expectedOrigin: origin, + }); - if (!verification.verified) { - return res.code(400).send({ error: "registration failed" }); + if (!verification.verified) { + return res.code(400).send({ error: "registration failed" }); + } + + userInDB.passKeys.push({ + credentialID: verification.registrationInfo.credential.id, + credentialPublicKey: + verification.registrationInfo.credential.publicKey, + counter: verification.registrationInfo.credential.counter, + transports: attestationResponse.response.transports, + }); + + await userInDB.save(); + + return res.code(200).send({ success: "registration complete" }); + } catch (error) { + return res.code(400).send({ error: error.message }); } - - userInDB.passKeys.push({ - credentialID: verification.registrationInfo.credential.id, - credentialPublicKey: verification.registrationInfo.credential.publicKey, - counter: verification.registrationInfo.credential.counter, - transports: attestationResponse.response.transports, - }); - - await userInDB.save(); - - return res.code(200).send({ success: "registration complete" }); - } catch (error) { - return res.code(400).send({ error: error.message }); } - }); + ); + // Authentication request fastify.post<{ Body: { email: string } }>( "/login/request", + { + schema: { + body: { + type: "string", + properties: { + email: { type: "string" }, + }, + }, + }, + }, async (req, res) => { const { email } = req.body; @@ -161,9 +190,20 @@ export async function webAuthnRoutes(fastify: FastifyInstance) { } ); - // Authentication Verification (Step 4) + // Authentication Verification fastify.post<{ Body: { email: string; assertionResponse: any } }>( "/login/verify", + { + schema: { + body: { + type: "object", + properties: { + email: { type: "string" }, + assertionResponse: { type: "object" }, + }, + }, + }, + }, async (req, res) => { const { email, assertionResponse } = req.body;