From 88377de8d6d38b4a8ab68ca59daafaee469d78a9 Mon Sep 17 00:00:00 2001 From: Victor Bojica Date: Wed, 5 Feb 2025 12:04:44 +0200 Subject: [PATCH] updated registerOptions to use the core to get the user email when using a recover token --- .../recipe/webauthn/recipeImplementation.js | 70 ++++++------------- lib/build/recipe/webauthn/types.d.ts | 2 +- .../recipe/webauthn/recipeImplementation.ts | 21 +++--- 3 files changed, 33 insertions(+), 60 deletions(-) diff --git a/lib/build/recipe/webauthn/recipeImplementation.js b/lib/build/recipe/webauthn/recipeImplementation.js index 7f85f6bd8..a5e1868b4 100644 --- a/lib/build/recipe/webauthn/recipeImplementation.js +++ b/lib/build/recipe/webauthn/recipeImplementation.js @@ -1,40 +1,4 @@ "use strict"; -var __createBinding = - (this && this.__createBinding) || - (Object.create - ? function (o, m, k, k2) { - if (k2 === undefined) k2 = k; - Object.defineProperty(o, k2, { - enumerable: true, - get: function () { - return m[k]; - }, - }); - } - : function (o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; - }); -var __setModuleDefault = - (this && this.__setModuleDefault) || - (Object.create - ? function (o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); - } - : function (o, v) { - o["default"] = v; - }); -var __importStar = - (this && this.__importStar) || - function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) - for (var k in mod) - if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; - }; var __rest = (this && this.__rest) || function (s, e) { @@ -59,11 +23,11 @@ const recipeUserId_1 = __importDefault(require("../../recipeUserId")); const constants_1 = require("../multitenancy/constants"); const user_1 = require("../../user"); const authUtils_1 = require("../../authUtils"); -const jose = __importStar(require("jose")); const utils_1 = require("../thirdparty/utils"); function getRecipeInterface(querier, getWebauthnConfig) { return { registerOptions: async function (_a) { + var _b; var { relyingPartyId, relyingPartyName, @@ -94,17 +58,25 @@ function getRecipeInterface(querier, getWebauthnConfig) { if (emailInput !== undefined) { email = emailInput; } else if (recoverAccountTokenInput !== undefined) { - // the actual validation of the token will be done during consumeRecoverAccountToken - let decoded; - try { - decoded = await jose.decodeJwt(recoverAccountTokenInput); - } catch (e) { - console.error(e); + const result = await this.getUserFromRecoverAccountToken({ + token: recoverAccountTokenInput, + tenantId, + userContext, + }); + if (result.status !== "OK") { + return result; + } + const user = result.user; + // todo this might be wrong but will have to figure out - what happens when there are multiple webauthn login methods ? + const email = + (_b = user.loginMethods.find((lm) => lm.recipeId === "webauthn")) === null || _b === void 0 + ? void 0 + : _b.email; + if (!email) { return { status: "RECOVER_ACCOUNT_TOKEN_INVALID_ERROR", }; } - email = decoded === null || decoded === void 0 ? void 0 : decoded.email; } if (!email) { return { @@ -364,19 +336,17 @@ function getRecipeInterface(querier, getWebauthnConfig) { new normalisedURLPath_1.default( `/${ tenantId === undefined ? constants_1.DEFAULT_TENANT_ID : tenantId - }/recipe/webauthn/user/recover/token/${token}` + }/recipe/webauthn/user/recover/token` ), - {}, + { token }, userContext ); }, removeCredential: async function ({ webauthnCredentialId, recipeUserId, userContext }) { return await querier.sendDeleteRequest( - new normalisedURLPath_1.default( - `/recipe/webauthn/user/${recipeUserId}/credential/${webauthnCredentialId}` - ), - {}, + new normalisedURLPath_1.default(`/recipe/webauthn/user/credential/remove`), {}, + { recipeUserId, webauthnCredentialId }, userContext ); }, diff --git a/lib/build/recipe/webauthn/types.d.ts b/lib/build/recipe/webauthn/types.d.ts index 8dcade2ba..5960e6394 100644 --- a/lib/build/recipe/webauthn/types.d.ts +++ b/lib/build/recipe/webauthn/types.d.ts @@ -436,7 +436,7 @@ export declare type RecipeInterface = { }): Promise<{ status: "OK"; credentials: { - id: string; + webauthnCredentialId: string; relyingPartyId: string; createdAt: number; }[]; diff --git a/lib/ts/recipe/webauthn/recipeImplementation.ts b/lib/ts/recipe/webauthn/recipeImplementation.ts index 89389b434..6003b362a 100644 --- a/lib/ts/recipe/webauthn/recipeImplementation.ts +++ b/lib/ts/recipe/webauthn/recipeImplementation.ts @@ -7,7 +7,6 @@ import RecipeUserId from "../../recipeUserId"; import { DEFAULT_TENANT_ID } from "../multitenancy/constants"; import { LoginMethod, User } from "../../user"; import { AuthUtils } from "../../authUtils"; -import * as jose from "jose"; import { isFakeEmail } from "../thirdparty/utils"; export default function getRecipeInterface( @@ -35,19 +34,23 @@ export default function getRecipeInterface( if (emailInput !== undefined) { email = emailInput; } else if (recoverAccountTokenInput !== undefined) { - // the actual validation of the token will be done during consumeRecoverAccountToken - let decoded: jose.JWTPayload | undefined; - try { - decoded = await jose.decodeJwt(recoverAccountTokenInput); - } catch (e) { - console.error(e); + const result = await this.getUserFromRecoverAccountToken({ + token: recoverAccountTokenInput, + tenantId, + userContext, + }); + if (result.status !== "OK") { + return result; + } + const user = result.user as User; + // todo this might be wrong but will have to figure out - what happens when there are multiple webauthn login methods ? + const email = user.loginMethods.find((lm) => lm.recipeId === "webauthn")?.email; + if (!email) { return { status: "RECOVER_ACCOUNT_TOKEN_INVALID_ERROR", }; } - - email = decoded?.email as string | undefined; } if (!email) {