UNPKG

supertokens-node

Version:
128 lines (127 loc) 6.3 kB
"use strict"; /* Copyright (c) 2024, VRAI Labs and/or its affiliates. All rights reserved. * * This software is licensed under the Apache License, Version 2.0 (the * "License") as published by the Apache Software Foundation. * * You may not use this file except in compliance with the License. You may * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ var __importDefault = (this && this.__importDefault) || function (mod) { return mod && mod.__esModule ? mod : { default: mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = getAPIInterface; const error_1 = __importDefault(require("../../session/error")); const utils_1 = require("../utils"); function getAPIInterface(stInstance, multiFactorAuthClaim) { return { resyncSessionAndFetchMFAInfoPUT: async ({ options, session, userContext }) => { const sessionUser = await stInstance .getRecipeInstanceOrThrow("accountlinking") .recipeInterfaceImpl.getUser({ userId: session.getUserId(), userContext }); if (sessionUser === undefined) { throw new error_1.default({ type: error_1.default.UNAUTHORISED, message: "Session user not found", }); } const mfaInfo = await (0, utils_1.updateAndGetMFARelatedInfoInSession)({ session, stInstance, userContext, }); const factorsSetUpForUser = await options.recipeImplementation.getFactorsSetupForUser({ user: sessionUser, userContext, }); const tenantInfo = await stInstance .getRecipeInstanceOrThrow("multitenancy") .recipeInterfaceImpl.getTenant({ tenantId: session.getTenantId(userContext), userContext }); if (tenantInfo === undefined) { throw new error_1.default({ type: error_1.default.UNAUTHORISED, message: "Tenant not found", }); } const allAvailableSecondaryFactors = options.recipeInstance.getAllAvailableSecondaryFactorIds(tenantInfo); const factorsAllowedToSetup = []; for (const id of allAvailableSecondaryFactors) { try { await options.recipeImplementation.assertAllowedToSetupFactorElseThrowInvalidClaimError({ session, factorId: id, get factorsSetUpForUser() { return Promise.resolve(factorsSetUpForUser); }, get mfaRequirementsForAuth() { return Promise.resolve(mfaInfo.mfaRequirementsForAuth); }, userContext, }); factorsAllowedToSetup.push(id); } catch (err) { if (!(error_1.default.isErrorFromSuperTokens(err) && err.type === error_1.default.INVALID_CLAIMS)) { throw err; } // ignore claims error and not add to the list of factors allowed to be set up } } const nextSetOfUnsatisfiedFactors = multiFactorAuthClaim.getNextSetOfUnsatisfiedFactors( mfaInfo.completedFactors, mfaInfo.mfaRequirementsForAuth ); let getEmailsForFactorsResult = options.recipeInstance.getEmailsForFactors( sessionUser, session.getRecipeUserId(userContext) ); let getPhoneNumbersForFactorsResult = options.recipeInstance.getPhoneNumbersForFactors( sessionUser, session.getRecipeUserId(userContext) ); if ( getEmailsForFactorsResult.status === "UNKNOWN_SESSION_RECIPE_USER_ID" || getPhoneNumbersForFactorsResult.status === "UNKNOWN_SESSION_RECIPE_USER_ID" ) { throw new error_1.default({ type: "UNAUTHORISED", message: "User no longer associated with the session", }); } // next array is filtered to only include factors that are allowed to be setup or are already setup // we do this because the factor chooser in the frontend will be based on the next array only // we do not simply filter out the factors that are not allowed to be setup because in the case // where user has already setup a factor and not completed it, none of the factors will be allowed to // be setup, and that that will result in an empty next array. However, we want to show the factor // that the user has already setup in that case. const next = nextSetOfUnsatisfiedFactors.factorIds.filter( (factorId) => factorsAllowedToSetup.includes(factorId) || factorsSetUpForUser.includes(factorId) ); if (next.length === 0 && nextSetOfUnsatisfiedFactors.factorIds.length !== 0) { throw new Error( `The user is required to complete secondary factors they are not allowed to (${nextSetOfUnsatisfiedFactors.factorIds.join( ", " )}), likely because of configuration issues.` ); } return { status: "OK", factors: { next, alreadySetup: factorsSetUpForUser, allowedToSetup: factorsAllowedToSetup, }, emails: getEmailsForFactorsResult.factorIdToEmailsMap, phoneNumbers: getPhoneNumbersForFactorsResult.factorIdToPhoneNumberMap, }; }, }; }