Skip to content

Commit

Permalink
feat(mfa): initial types (#708)
Browse files Browse the repository at this point in the history
* feat: add (partial) initial types for MFA

* feat: expand the MFA recipe interface

* feat: add export point for mfa

* feat: update based on review discussions

* feat: add extra params to MFARequirements callbacks to help customizations

* feat: implement review feedback

* feat: implement review comments

* feat: implement review comments

* feat: stricter type for first factor/mfa requirement
  • Loading branch information
porcellus authored Oct 13, 2023
1 parent 6d93571 commit 5297aef
Show file tree
Hide file tree
Showing 35 changed files with 1,432 additions and 5 deletions.
3 changes: 3 additions & 0 deletions lib/build/recipe/multifactorauth/api/implementation.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// @ts-nocheck
import { APIInterface } from "../";
export default function getAPIInterface(): APIInterface;
6 changes: 6 additions & 0 deletions lib/build/recipe/multifactorauth/api/implementation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
function getAPIInterface() {
return {};
}
exports.default = getAPIInterface;
7 changes: 7 additions & 0 deletions lib/build/recipe/multifactorauth/api/mfaInfo.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// @ts-nocheck
import { APIInterface, APIOptions } from "..";
export default function mfaInfo(
apiImplementation: APIInterface,
options: APIOptions,
userContext: any
): Promise<boolean>;
51 changes: 51 additions & 0 deletions lib/build/recipe/multifactorauth/api/mfaInfo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
"use strict";
/* Copyright (c) 2021, 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 });
const utils_1 = require("../../../utils");
const session_1 = __importDefault(require("../../session"));
async function mfaInfo(apiImplementation, options, userContext) {
let result;
if (apiImplementation.mfaInfoGET === undefined) {
return false;
}
const session = await session_1.default.getSession(
options.req,
options.res,
{ overrideGlobalClaimValidators: () => [], sessionRequired: true },
userContext
);
let response = await apiImplementation.mfaInfoGET({
options,
session,
userContext,
});
if (response.status === "OK") {
// if there is a new session, it will be
// automatically added to the response by the createNewSession function call
// inside the verifyEmailPOST function.
result = { status: "OK" };
} else {
result = response;
}
utils_1.send200Response(options.res, result);
return true;
}
exports.default = mfaInfo;
2 changes: 2 additions & 0 deletions lib/build/recipe/multifactorauth/constants.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// @ts-nocheck
export declare const GET_MFA_INFO = "/mfa-info";
18 changes: 18 additions & 0 deletions lib/build/recipe/multifactorauth/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"use strict";
/* Copyright (c) 2021, 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.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.GET_MFA_INFO = void 0;
exports.GET_MFA_INFO = "/mfa-info";
5 changes: 5 additions & 0 deletions lib/build/recipe/multifactorauth/error.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// @ts-nocheck
import STError from "../../error";
export default class SessionError extends STError {
constructor(options: { type: "BAD_INPUT_ERROR"; message: string });
}
29 changes: 29 additions & 0 deletions lib/build/recipe/multifactorauth/error.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"use strict";
/* Copyright (c) 2021, 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 });
const error_1 = __importDefault(require("../../error"));
class SessionError extends error_1.default {
constructor(options) {
super(Object.assign({}, options));
this.fromRecipe = "multifactorauth";
}
}
exports.default = SessionError;
24 changes: 24 additions & 0 deletions lib/build/recipe/multifactorauth/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// @ts-nocheck
import Recipe from "./recipe";
import { RecipeInterface, APIOptions, APIInterface } from "./types";
import { MultiFactorAuthClaim } from "./multiFactorAuthClaim";
import { SessionContainerInterface } from "../session/types";
export default class Wrapper {
static init: typeof Recipe.init;
static MultiFactorAuthClaim: import("./multiFactorAuthClaim").MultiFactorAuthClaimClass;
static getFactorsSetUpByUser(tenantId: string, userId: string, userContext?: any): Promise<string[]>;
static isAllowedToSetupFactor(
session: SessionContainerInterface,
factorId: string,
userContext?: any
): Promise<boolean>;
static markFactorAsCompleteInSession(
session: SessionContainerInterface,
factorId: string,
userContext?: any
): Promise<void>;
}
export declare let init: typeof Recipe.init;
export declare let markFactorAsCompleteInSession: typeof Wrapper.markFactorAsCompleteInSession;
export { MultiFactorAuthClaim };
export type { RecipeInterface, APIOptions, APIInterface };
100 changes: 100 additions & 0 deletions lib/build/recipe/multifactorauth/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
"use strict";
/* Copyright (c) 2021, 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.MultiFactorAuthClaim = exports.markFactorAsCompleteInSession = exports.init = void 0;
const recipe_1 = __importDefault(require("./recipe"));
const multiFactorAuthClaim_1 = require("./multiFactorAuthClaim");
Object.defineProperty(exports, "MultiFactorAuthClaim", {
enumerable: true,
get: function () {
return multiFactorAuthClaim_1.MultiFactorAuthClaim;
},
});
const __1 = require("../..");
class Wrapper {
static async getFactorsSetUpByUser(tenantId, userId, userContext) {
const ctx = userContext !== null && userContext !== void 0 ? userContext : {};
const user = await __1.getUser(userId, ctx);
if (!user) {
throw new Error("UKNKNOWN_USER_ID");
}
return recipe_1.default.getInstanceOrThrowError().recipeInterfaceImpl.getFactorsSetupForUser({
user,
tenantId,
userContext: ctx,
});
}
static async isAllowedToSetupFactor(session, factorId, userContext) {
var _a;
let ctx = userContext !== null && userContext !== void 0 ? userContext : {};
const user = await __1.getUser(session.getUserId(), ctx);
if (!user) {
throw new Error("UKNKNOWN_USER_ID");
}
const factorsSetup = await recipe_1.default
.getInstanceOrThrowError()
.recipeInterfaceImpl.getFactorsSetupForUser({
user,
tenantId: session.getTenantId(),
userContext: ctx,
});
const mfaClaimValue = await session.getClaimValue(multiFactorAuthClaim_1.MultiFactorAuthClaim, ctx);
const completedFactors =
(_a = mfaClaimValue === null || mfaClaimValue === void 0 ? void 0 : mfaClaimValue.c) !== null &&
_a !== void 0
? _a
: {};
const defaultMFARequirementsForUser = []; // TODO
const defaultMFARequirementsForTenant = []; // TODO
const requirements = await recipe_1.default
.getInstanceOrThrowError()
.recipeInterfaceImpl.getMFARequirementsForAuth({
session,
factorsSetUpByTheUser: factorsSetup,
defaultRequiredFactorsForUser: defaultMFARequirementsForUser,
defaultRequiredFactorsForTenant: defaultMFARequirementsForTenant,
completedFactors,
userContext: ctx,
});
return recipe_1.default.getInstanceOrThrowError().recipeInterfaceImpl.isAllowedToSetupFactor({
session,
factorId,
completedFactors,
mfaRequirementsForAuth: requirements,
factorsSetUpByTheUser: factorsSetup,
defaultRequiredFactorsForUser: defaultMFARequirementsForUser,
defaultRequiredFactorsForTenant: defaultMFARequirementsForTenant,
userContext,
});
}
static async markFactorAsCompleteInSession(session, factorId, userContext) {
return recipe_1.default.getInstanceOrThrowError().recipeInterfaceImpl.markFactorAsCompleteInSession({
session,
factorId,
userContext: userContext !== null && userContext !== void 0 ? userContext : {},
});
}
}
exports.default = Wrapper;
Wrapper.init = recipe_1.default.init;
Wrapper.MultiFactorAuthClaim = multiFactorAuthClaim_1.MultiFactorAuthClaim;
exports.init = Wrapper.init;
exports.markFactorAsCompleteInSession = Wrapper.markFactorAsCompleteInSession;
54 changes: 54 additions & 0 deletions lib/build/recipe/multifactorauth/multiFactorAuthClaim.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// @ts-nocheck
import RecipeUserId from "../../recipeUserId";
import { SessionClaimValidator } from "../session";
import { SessionClaim } from "../session/claims";
import { JSONObject } from "../usermetadata";
import { MFAClaimValue, MFARequirementList } from "./types";
/**
* We include "Class" in the class name, because it makes it easier to import the right thing (the instance) instead of this.
* */
export declare class MultiFactorAuthClaimClass extends SessionClaim<MFAClaimValue> {
validators: {
passesMFARequirements: (requirements?: MFARequirementList) => SessionClaimValidator;
};
constructor(key?: string);
buildNextArray(_completedClaims: MFAClaimValue["c"], _requirements: MFARequirementList): never[];
fetchValue: (
_userId: string,
_recipeUserId: RecipeUserId,
_tenantId: string | undefined,
_userContext: any
) => {
c: {};
n: never[];
};
addToPayload_internal: (
payload: JSONObject,
value: MFAClaimValue
) => {
[x: string]:
| string
| number
| boolean
| JSONObject
| import("../../types").JSONArray
| {
c: {
[x: string]: number;
};
n: string[];
}
| null
| undefined;
};
removeFromPayload: (
payload: JSONObject
) => {
[x: string]: import("../../types").JSONValue;
};
removeFromPayloadByMerge_internal: () => {
[x: string]: null;
};
getValueFromPayload: (payload: JSONObject) => MFAClaimValue;
}
export declare const MultiFactorAuthClaim: MultiFactorAuthClaimClass;
53 changes: 53 additions & 0 deletions lib/build/recipe/multifactorauth/multiFactorAuthClaim.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MultiFactorAuthClaim = exports.MultiFactorAuthClaimClass = void 0;
const claims_1 = require("../session/claims");
/**
* We include "Class" in the class name, because it makes it easier to import the right thing (the instance) instead of this.
* */
class MultiFactorAuthClaimClass extends claims_1.SessionClaim {
constructor(key) {
super(key !== null && key !== void 0 ? key : "st-mfa");
this.fetchValue = (_userId, _recipeUserId, _tenantId, _userContext) => {
// TODO
return {
c: {},
n: [],
};
};
this.addToPayload_internal = (payload, value) => {
const prevValue = payload[this.key];
return Object.assign(Object.assign({}, payload), {
[this.key]: {
c: Object.assign(
Object.assign({}, prevValue === null || prevValue === void 0 ? void 0 : prevValue.c),
value.c
),
n: value.n,
},
});
};
this.removeFromPayload = (payload) => {
const retVal = Object.assign({}, payload);
delete retVal[this.key];
return retVal;
};
this.removeFromPayloadByMerge_internal = () => {
return {
[this.key]: null,
};
};
this.getValueFromPayload = (payload) => {
return payload[this.key];
};
this.validators = {
passesMFARequirements: (_requirements) => ({}), // TODO
};
}
buildNextArray(_completedClaims, _requirements) {
// TODO
return [];
}
}
exports.MultiFactorAuthClaimClass = MultiFactorAuthClaimClass;
exports.MultiFactorAuthClaim = new MultiFactorAuthClaimClass();
Loading

0 comments on commit 5297aef

Please sign in to comment.