diff --git a/lib/build/authUtils.js b/lib/build/authUtils.js index b03e8cb94..5b9ec7081 100644 --- a/lib/build/authUtils.js +++ b/lib/build/authUtils.js @@ -311,6 +311,7 @@ exports.AuthUtils = { logger_1.logDebugMessage( `getAuthenticatingUserAndAddToCurrentTenantIfRequired got ${existingUsers.length} users from the core resp` ); + console.log("existingUsers", existingUsers, accountInfo); const usersWithMatchingLoginMethods = existingUsers .map((user) => ({ user, @@ -319,7 +320,8 @@ exports.AuthUtils = { lm.recipeId === recipeId && ((accountInfo.email !== undefined && lm.hasSameEmailAs(accountInfo.email)) || lm.hasSamePhoneNumberAs(accountInfo.phoneNumber) || - lm.hasSameThirdPartyInfoAs(accountInfo.thirdParty)) + lm.hasSameThirdPartyInfoAs(accountInfo.thirdParty) || + lm.hasSameWebauthnInfoAs(accountInfo.webauthn)) ), })) .filter(({ loginMethod }) => loginMethod !== undefined); diff --git a/lib/build/recipe/accountlinking/recipeImplementation.js b/lib/build/recipe/accountlinking/recipeImplementation.js index 55774660f..cf6ae1f15 100644 --- a/lib/build/recipe/accountlinking/recipeImplementation.js +++ b/lib/build/recipe/accountlinking/recipeImplementation.js @@ -157,7 +157,7 @@ function getRecipeImplementation(querier, config, recipeInstance) { return undefined; }, listUsersByAccountInfo: async function ({ tenantId, accountInfo, doUnionOfAccountInfo, userContext }) { - var _a, _b; + var _a, _b, _c; let result = await querier.sendGetRequest( new normalisedURLPath_1.default( `${tenantId !== null && tenantId !== void 0 ? tenantId : "public"}/users/by-accountinfo` @@ -167,6 +167,8 @@ function getRecipeImplementation(querier, config, recipeInstance) { phoneNumber: accountInfo.phoneNumber, thirdPartyId: (_a = accountInfo.thirdParty) === null || _a === void 0 ? void 0 : _a.id, thirdPartyUserId: (_b = accountInfo.thirdParty) === null || _b === void 0 ? void 0 : _b.userId, + webauthnCredentialId: + (_c = accountInfo.webauthn) === null || _c === void 0 ? void 0 : _c.credentialId, doUnionOfAccountInfo, }, userContext diff --git a/lib/build/recipe/webauthn/api/implementation.js b/lib/build/recipe/webauthn/api/implementation.js index b38e8f704..a5196e62d 100644 --- a/lib/build/recipe/webauthn/api/implementation.js +++ b/lib/build/recipe/webauthn/api/implementation.js @@ -307,6 +307,7 @@ function getAPIImplementation() { tenantId, userContext, }); + console.log("generatedOptions", generatedOptions); if (generatedOptions.status !== "OK") { return { status: "INVALID_CREDENTIALS_ERROR", @@ -341,6 +342,7 @@ function getAPIImplementation() { // the implementation of that function, this way we can guarantee that either isSignInAllowed or // isSignUpAllowed will be called as expected. if (authenticatingUser === undefined) { + console.log("authenticatingUser is undefined"); return { status: "INVALID_CREDENTIALS_ERROR", }; @@ -390,6 +392,7 @@ function getAPIImplementation() { } if (utils_1.isFakeEmail(email) && preAuthChecks.isFirstFactor) { // Fake emails cannot be used as a first factor + console.log("isFakeEmail(email) && preAuthChecks.isFirstFactor"); return { status: "INVALID_CREDENTIALS_ERROR", }; @@ -402,10 +405,13 @@ function getAPIImplementation() { tenantId, userContext, }); + console.log("signInPOST signInResponse", signInResponse); if (signInResponse.status === "INVALID_CREDENTIALS_ERROR") { + console.log("signInResponse.status === 'INVALID_CREDENTIALS_ERROR'"); return signInResponse; } if (signInResponse.status !== "OK") { + console.log("signInResponse.status !== 'OK'"); return authUtils_1.AuthUtils.getErrorStatusResponseWithReason( signInResponse, errorCodeMap, @@ -424,6 +430,7 @@ function getAPIImplementation() { userContext, }); if (postAuthChecks.status !== "OK") { + console.log("postAuthChecks.status !== 'OK'", postAuthChecks); return authUtils_1.AuthUtils.getErrorStatusResponseWithReason( postAuthChecks, errorCodeMap, diff --git a/lib/build/recipe/webauthn/recipeImplementation.js b/lib/build/recipe/webauthn/recipeImplementation.js index ea5b48dcb..fe08878a3 100644 --- a/lib/build/recipe/webauthn/recipeImplementation.js +++ b/lib/build/recipe/webauthn/recipeImplementation.js @@ -240,11 +240,13 @@ function getRecipeInterface(querier, getWebauthnConfig) { }, userContext ); + console.log("response", response); if (response.status === "OK") { return { status: "OK", user: new user_1.User(response.user), - recipeUserId: new recipeUserId_1.default(response.recipeUserId), + // todo change this to response.recipeUserId when implemented, + recipeUserId: new recipeUserId_1.default(response.user.id), }; } return { diff --git a/lib/build/types.d.ts b/lib/build/types.d.ts index c1abe0c67..c9337d396 100644 --- a/lib/build/types.d.ts +++ b/lib/build/types.d.ts @@ -95,6 +95,7 @@ export declare type User = { hasSameEmailAs: (email: string | undefined) => boolean; hasSamePhoneNumberAs: (phoneNumber: string | undefined) => boolean; hasSameThirdPartyInfoAs: (thirdParty?: { id: string; userId: string }) => boolean; + hasSameWebauthnInfoAs: (webauthn?: { credentialId: string }) => boolean; toJson: () => any; })[]; toJson: () => any; diff --git a/lib/build/user.d.ts b/lib/build/user.d.ts index 9bc4835a5..b50e8f506 100644 --- a/lib/build/user.d.ts +++ b/lib/build/user.d.ts @@ -16,6 +16,7 @@ export declare class LoginMethod implements RecipeLevelUser { hasSameEmailAs(email: string | undefined): boolean; hasSamePhoneNumberAs(phoneNumber: string | undefined): boolean; hasSameThirdPartyInfoAs(thirdParty?: { id: string; userId: string }): boolean; + hasSameWebauthnInfoAs(webauthn?: { credentialId: string }): boolean; toJson(): JSONObject; } export declare class User implements UserType { diff --git a/lib/build/user.js b/lib/build/user.js index fe045dde2..f89bf48bc 100644 --- a/lib/build/user.js +++ b/lib/build/user.js @@ -54,6 +54,12 @@ class LoginMethod { this.thirdParty.userId === thirdParty.userId ); } + hasSameWebauthnInfoAs(webauthn) { + if (webauthn === undefined) { + return false; + } + return this.webauthn !== undefined && this.webauthn.credentialIds.includes(webauthn.credentialId); + } toJson() { return { recipeId: this.recipeId, diff --git a/lib/ts/authUtils.ts b/lib/ts/authUtils.ts index 91a0a33a7..f0e4733d1 100644 --- a/lib/ts/authUtils.ts +++ b/lib/ts/authUtils.ts @@ -359,6 +359,7 @@ export const AuthUtils = { logDebugMessage( `getAuthenticatingUserAndAddToCurrentTenantIfRequired got ${existingUsers.length} users from the core resp` ); + console.log("existingUsers", existingUsers, accountInfo); const usersWithMatchingLoginMethods = existingUsers .map((user) => ({ user, @@ -367,7 +368,8 @@ export const AuthUtils = { lm.recipeId === recipeId && ((accountInfo.email !== undefined && lm.hasSameEmailAs(accountInfo.email)) || lm.hasSamePhoneNumberAs(accountInfo.phoneNumber) || - lm.hasSameThirdPartyInfoAs(accountInfo.thirdParty)) + lm.hasSameThirdPartyInfoAs(accountInfo.thirdParty) || + lm.hasSameWebauthnInfoAs(accountInfo.webauthn)) )!, })) .filter(({ loginMethod }) => loginMethod !== undefined); diff --git a/lib/ts/recipe/accountlinking/recipeImplementation.ts b/lib/ts/recipe/accountlinking/recipeImplementation.ts index 598e4baae..79b4357ce 100644 --- a/lib/ts/recipe/accountlinking/recipeImplementation.ts +++ b/lib/ts/recipe/accountlinking/recipeImplementation.ts @@ -320,6 +320,7 @@ export default function getRecipeImplementation( phoneNumber: accountInfo.phoneNumber, thirdPartyId: accountInfo.thirdParty?.id, thirdPartyUserId: accountInfo.thirdParty?.userId, + webauthnCredentialId: accountInfo.webauthn?.credentialId, doUnionOfAccountInfo, }, userContext diff --git a/lib/ts/recipe/webauthn/api/implementation.ts b/lib/ts/recipe/webauthn/api/implementation.ts index ceb8163cf..18eb108fe 100644 --- a/lib/ts/recipe/webauthn/api/implementation.ts +++ b/lib/ts/recipe/webauthn/api/implementation.ts @@ -424,6 +424,7 @@ export default function getAPIImplementation(): APIInterface { tenantId, userContext, }); + console.log("generatedOptions", generatedOptions); if (generatedOptions.status !== "OK") { return { status: "INVALID_CREDENTIALS_ERROR", @@ -460,6 +461,7 @@ export default function getAPIImplementation(): APIInterface { // the implementation of that function, this way we can guarantee that either isSignInAllowed or // isSignUpAllowed will be called as expected. if (authenticatingUser === undefined) { + console.log("authenticatingUser is undefined"); return { status: "INVALID_CREDENTIALS_ERROR", }; @@ -498,6 +500,7 @@ export default function getAPIImplementation(): APIInterface { if (isFakeEmail(email) && preAuthChecks.isFirstFactor) { // Fake emails cannot be used as a first factor + console.log("isFakeEmail(email) && preAuthChecks.isFirstFactor"); return { status: "INVALID_CREDENTIALS_ERROR", }; @@ -511,11 +514,14 @@ export default function getAPIImplementation(): APIInterface { tenantId, userContext, }); + console.log("signInPOST signInResponse", signInResponse); if (signInResponse.status === "INVALID_CREDENTIALS_ERROR") { + console.log("signInResponse.status === 'INVALID_CREDENTIALS_ERROR'"); return signInResponse; } if (signInResponse.status !== "OK") { + console.log("signInResponse.status !== 'OK'"); return AuthUtils.getErrorStatusResponseWithReason(signInResponse, errorCodeMap, "SIGN_IN_NOT_ALLOWED"); } @@ -532,6 +538,7 @@ export default function getAPIImplementation(): APIInterface { }); if (postAuthChecks.status !== "OK") { + console.log("postAuthChecks.status !== 'OK'", postAuthChecks); return AuthUtils.getErrorStatusResponseWithReason(postAuthChecks, errorCodeMap, "SIGN_IN_NOT_ALLOWED"); } diff --git a/lib/ts/recipe/webauthn/recipeImplementation.ts b/lib/ts/recipe/webauthn/recipeImplementation.ts index f65eac21e..7165926d6 100644 --- a/lib/ts/recipe/webauthn/recipeImplementation.ts +++ b/lib/ts/recipe/webauthn/recipeImplementation.ts @@ -217,11 +217,14 @@ export default function getRecipeInterface( userContext ); + console.log("response", response); + if (response.status === "OK") { return { status: "OK", user: new User(response.user), - recipeUserId: new RecipeUserId(response.recipeUserId), + // todo change this to response.recipeUserId when implemented, + recipeUserId: new RecipeUserId(response.user.id), }; } diff --git a/lib/ts/types.ts b/lib/ts/types.ts index 308fd0436..d68ab47a0 100644 --- a/lib/ts/types.ts +++ b/lib/ts/types.ts @@ -123,6 +123,7 @@ export type User = { hasSameEmailAs: (email: string | undefined) => boolean; hasSamePhoneNumberAs: (phoneNumber: string | undefined) => boolean; hasSameThirdPartyInfoAs: (thirdParty?: { id: string; userId: string }) => boolean; + hasSameWebauthnInfoAs: (webauthn?: { credentialId: string }) => boolean; toJson: () => any; })[]; diff --git a/lib/ts/user.ts b/lib/ts/user.ts index 5a611e340..7fb9cebfa 100644 --- a/lib/ts/user.ts +++ b/lib/ts/user.ts @@ -66,6 +66,13 @@ export class LoginMethod implements RecipeLevelUser { ); } + hasSameWebauthnInfoAs(webauthn?: { credentialId: string }): boolean { + if (webauthn === undefined) { + return false; + } + return this.webauthn !== undefined && this.webauthn.credentialIds.includes(webauthn.credentialId); + } + toJson(): JSONObject { return { recipeId: this.recipeId, diff --git a/test/webauthn/apis.test.js b/test/webauthn/apis.test.js index 0cd364318..b99901e3c 100644 --- a/test/webauthn/apis.test.js +++ b/test/webauthn/apis.test.js @@ -23,7 +23,6 @@ let WebAuthn = require("../../recipe/webauthn"); let { ProcessState } = require("../../lib/build/processState"); let { middleware, errorHandler } = require("../../framework/express"); let { isCDIVersionCompatible } = require("../utils"); -const nock = require("nock"); const getWebauthnLib = require("./lib/getWebAuthnLib"); const getWebAuthnRecipe = require("./lib/getWebAuthnRecipe"); const createUser = require("./lib/createUser"); @@ -451,6 +450,8 @@ describe(`apisFunctions: ${printPath("[test/webauthn/apis.test.js]")}`, function }) ); + console.log("signInResponse", signInResponse); + assert(signInResponse.status === "OK"); assert(signInResponse?.user?.id !== undefined); @@ -529,20 +530,6 @@ describe(`apisFunctions: ${printPath("[test/webauthn/apis.test.js]")}`, function assert(signUpResponse.status === "OK"); - // todo remove this when the core is implemented - // mock the core to return the user - nock("http://localhost:8080/", { allowUnmocked: true }) - .get("/public/users/by-accountinfo") - .query({ email, doUnionOfAccountInfo: true }) - .reply(200, (uri, body) => { - return { status: "OK", users: [signUpResponse.user] }; - }) - .get("/user/id") - .query({ userId: signUpResponse.user.id }) - .reply(200, (uri, body) => { - return { status: "OK", user: signUpResponse.user }; - }); - let signInResponse = await new Promise((resolve, reject) => request(app) .post("/auth/webauthn/signin")