Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: TOTP recipe #705

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions lib/build/framework/fastify/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
// @ts-nocheck
/// <reference types="node" />
export type { SessionRequest } from "./framework";
export declare const plugin: import("fastify").FastifyPluginCallback<Record<never, never>, import("http").Server>;
export declare const plugin: import("fastify").FastifyPluginCallback<
Record<never, never>,
import("fastify").RawServerDefault
>;
export declare const errorHandler: () => (
err: any,
req: import("fastify").FastifyRequest<
import("fastify/types/route").RouteGenericInterface,
import("http").Server,
import("fastify").RawServerDefault,
import("http").IncomingMessage
>,
res: import("fastify").FastifyReply<
import("http").Server,
import("fastify").RawServerDefault,
import("http").IncomingMessage,
import("http").ServerResponse,
import("http").ServerResponse<import("http").IncomingMessage>,
import("fastify/types/route").RouteGenericInterface,
unknown
>
Expand Down
2 changes: 1 addition & 1 deletion lib/build/framework/utils.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export declare function setCookieForServerResponse(
expires: number,
path: string,
sameSite: "strict" | "lax" | "none"
): ServerResponse;
): ServerResponse<IncomingMessage>;
export declare function getCookieValueToSetInHeader(
prev: string | string[] | undefined,
val: string | string[],
Expand Down
7 changes: 7 additions & 0 deletions lib/build/recipe/totp/api/createDevice.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// @ts-nocheck
import { APIInterface, APIOptions } from "../types";
export default function createDevice(
apiImplementation: APIInterface,
options: APIOptions,
userContext: any
): Promise<boolean>;
46 changes: 46 additions & 0 deletions lib/build/recipe/totp/api/createDevice.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
"use strict";
/* Copyright (c) 2023, 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 createDevice(apiImplementation, options, userContext) {
if (apiImplementation.createDevicePOST === undefined) {
return false;
}
// Device creation is only be allowed if you've completed all factors OR have no devices yet.
// We have to remove claim validators here because we want to allow the user to create a device
// if they don't have any. But later in createDevicePOST, before actually calling the create
// device core API, we use assertClaims to ensure that if they have any devices, they must
// have completed all factors.
let session = await session_1.default.getSession(options.req, options.res, {
overrideGlobalClaimValidators: (_) => [],
});
let { deviceName } = await options.req.getJSONBody();
let result = await apiImplementation.createDevicePOST({
session,
deviceName,
options,
userContext,
});
utils_1.send200Response(options.res, result);
return true;
}
exports.default = createDevice;
3 changes: 3 additions & 0 deletions lib/build/recipe/totp/api/implementation.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// @ts-nocheck
import { APIInterface } from "../types";
export default function getAPIImplementation(): APIInterface;
67 changes: 67 additions & 0 deletions lib/build/recipe/totp/api/implementation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
"use strict";
/* Copyright (c) 2023, 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 recipe_1 = __importDefault(require("../recipe"));
// import { MfaClaim, completeFactorInSession } from '../../mfa';
function getAPIImplementation() {
return {
createDevicePOST: async function ({ session, options, deviceName, userContext }) {
// TODO: validate claims to check if createDevice can be allowed
let userIdentifierInfo = undefined;
const emailOrPhoneInfo = await recipe_1.default
.getInstanceOrThrowError()
.getUserIdentifierInfoForUserId(session.getUserId(), userContext);
if (emailOrPhoneInfo.status === "OK") {
userIdentifierInfo = emailOrPhoneInfo.info;
}
const args = { deviceName, userId: session.getUserId(), userIdentifierInfo, userContext };
let response = await options.recipeImplementation.createDevice(args);
return Object.assign({}, response);
},
verifyCodePOST: async function ({ session, options, totp, userContext }) {
const args = { userId: session.getUserId(), totp, tenantId: session.getTenantId(), userContext };
let response = await options.recipeImplementation.verifyCode(args);
// TODO: Uncomment when MFA is implemented
// userContext.flow = 'signin';
// await completeFactorInSession(session, 'totp', userContext);
return response;
},
verifyDevicePOST: async function ({ session, options, deviceName, totp, userContext }) {
const args = { userId: session.getUserId(), deviceName, totp, userContext };
let response = await options.recipeImplementation.verifyDevice(args);
// TODO: Uncomment when MFA is implemented
// userContext.flow = 'signup';
// await completeFactorInSession(session, 'totp', userContext);
return response;
},
removeDevicePOST: async function ({ session, options, deviceName, userContext }) {
const args = { userId: session.getUserId(), deviceName, userContext };
let response = await options.recipeImplementation.removeDevice(args);
return response;
},
listDevicesGET: async function ({ session, options, userContext }) {
const args = { userId: session.getUserId(), userContext };
let response = await options.recipeImplementation.listDevices(args);
return response;
},
};
}
exports.default = getAPIImplementation;
7 changes: 7 additions & 0 deletions lib/build/recipe/totp/api/listDevices.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// @ts-nocheck
import { APIInterface, APIOptions } from "../types";
export default function listDevices(
apiImplementation: APIInterface,
options: APIOptions,
userContext: any
): Promise<boolean>;
37 changes: 37 additions & 0 deletions lib/build/recipe/totp/api/listDevices.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"use strict";
/* Copyright (c) 2023, 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 listDevices(apiImplementation, options, userContext) {
if (apiImplementation.listDevicesGET === undefined) {
return false;
}
let session = await session_1.default.getSession(options.req, options.res);
let result = await apiImplementation.listDevicesGET({
session,
options,
userContext,
});
utils_1.send200Response(options.res, result);
return true;
}
exports.default = listDevices;
7 changes: 7 additions & 0 deletions lib/build/recipe/totp/api/removeDevice.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// @ts-nocheck
import { APIInterface, APIOptions } from "../types";
export default function removeDevice(
apiImplementation: APIInterface,
options: APIOptions,
userContext: any
): Promise<boolean>;
46 changes: 46 additions & 0 deletions lib/build/recipe/totp/api/removeDevice.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
"use strict";
/* Copyright (c) 2023, 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 error_1 = __importDefault(require("../error"));
const session_1 = __importDefault(require("../../session"));
async function removeDevice(apiImplementation, options, userContext) {
if (apiImplementation.removeDevicePOST === undefined) {
return false;
}
let session = await session_1.default.getSession(options.req, options.res);
const { deviceName } = await options.req.getJSONBody();
if (deviceName === undefined) {
throw new error_1.default({
type: error_1.default.BAD_INPUT_ERROR,
message: "Please provide deviceName",
});
}
let result = await apiImplementation.removeDevicePOST({
session,
deviceName,
options,
userContext,
});
utils_1.send200Response(options.res, result);
return true;
}
exports.default = removeDevice;
7 changes: 7 additions & 0 deletions lib/build/recipe/totp/api/verifyCode.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// @ts-nocheck
import { APIInterface, APIOptions } from "../types";
export default function verifyCode(
apiImplementation: APIInterface,
options: APIOptions,
userContext: any
): Promise<boolean>;
48 changes: 48 additions & 0 deletions lib/build/recipe/totp/api/verifyCode.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
"use strict";
/* Copyright (c) 2023, 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 error_1 = __importDefault(require("../error"));
const session_1 = __importDefault(require("../../session"));
async function verifyCode(apiImplementation, options, userContext) {
if (apiImplementation.verifyCodePOST === undefined) {
return false;
}
let session = await session_1.default.getSession(options.req, options.res, {
overrideGlobalClaimValidators: (_) => [],
});
const { totp } = await options.req.getJSONBody();
if (totp === undefined) {
throw new error_1.default({
type: error_1.default.BAD_INPUT_ERROR,
message: "Please provide totp",
});
}
let result = await apiImplementation.verifyCodePOST({
session,
totp,
options,
userContext,
});
utils_1.send200Response(options.res, result);
return true;
}
exports.default = verifyCode;
7 changes: 7 additions & 0 deletions lib/build/recipe/totp/api/verifyDevice.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// @ts-nocheck
import { APIInterface, APIOptions } from "../types";
export default function verifyDevice(
apiImplementation: APIInterface,
options: APIOptions,
userContext: any
): Promise<boolean>;
55 changes: 55 additions & 0 deletions lib/build/recipe/totp/api/verifyDevice.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
"use strict";
/* Copyright (c) 2023, 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 error_1 = __importDefault(require("../error"));
const session_1 = __importDefault(require("../../session"));
async function verifyDevice(apiImplementation, options, userContext) {
if (apiImplementation.verifyDevicePOST === undefined) {
return false;
}
let session = await session_1.default.getSession(options.req, options.res, {
overrideGlobalClaimValidators: (_) => [],
});
const { deviceName, totp } = await options.req.getJSONBody();
if (deviceName === undefined) {
throw new error_1.default({
type: error_1.default.BAD_INPUT_ERROR,
message: "Please provide deviceName",
});
}
if (totp === undefined) {
throw new error_1.default({
type: error_1.default.BAD_INPUT_ERROR,
message: "Please provide totp",
});
}
let result = await apiImplementation.verifyDevicePOST({
session,
deviceName,
totp,
options,
userContext,
});
utils_1.send200Response(options.res, result);
return true;
}
exports.default = verifyDevice;
6 changes: 6 additions & 0 deletions lib/build/recipe/totp/constants.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// @ts-nocheck
export declare const CREATE_DEVICE_API = "/totp/device";
export declare const VERIFY_CODE_API = "/totp/verify";
export declare const VERIFY_DEVICE_API = "/totp/device/verify";
export declare const REMOVE_DEVICE_API = "/totp/device/remove";
export declare const LIST_DEVICE_API = "/totp/device/list";
Loading
Loading