supertokens-node
Version:
NodeJS driver for SuperTokens core
171 lines (170 loc) • 8.11 kB
JavaScript
;
/* Copyright (c) 2022, 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"));
const recipeModule_1 = __importDefault(require("../../recipeModule"));
const recipeImplementation_1 = __importDefault(require("./recipeImplementation"));
const utils_1 = require("./utils");
const supertokens_js_override_1 = __importDefault(require("supertokens-js-override"));
const postSuperTokensInitCallbacks_1 = require("../../postSuperTokensInitCallbacks");
const userRoleClaim_1 = require("./userRoleClaim");
const permissionClaim_1 = require("./permissionClaim");
const session_1 = require("../session");
const utils_2 = require("../../utils");
const plugins_1 = require("../../plugins");
class Recipe extends recipeModule_1.default {
constructor(stInstance, recipeId, appInfo, isInServerlessEnv, config) {
super(stInstance, recipeId, appInfo);
// This stub is required to implement RecipeModule
this.handleAPIRequest = async (_, _tenantId, __, ___, ____, _____) => {
throw new Error("Should never come here");
};
this.config = (0, utils_1.validateAndNormaliseUserInput)(this, appInfo, config);
this.isInServerlessEnv = isInServerlessEnv;
{
let builder = new supertokens_js_override_1.default((0, recipeImplementation_1.default)(this.querier));
this.recipeInterfaceImpl = builder.override(this.config.override.functions).build();
}
postSuperTokensInitCallbacks_1.PostSuperTokensInitCallbacks.addPostInitCallback(() => {
if (!this.config.skipAddingRolesToAccessToken) {
stInstance.getRecipeInstanceOrThrow("session").addClaimFromOtherRecipe(userRoleClaim_1.UserRoleClaim);
}
if (!this.config.skipAddingPermissionsToAccessToken) {
stInstance.getRecipeInstanceOrThrow("session").addClaimFromOtherRecipe(permissionClaim_1.PermissionClaim);
}
const tokenPayloadBuilder = async (user, scopes, sessionHandle, userContext) => {
let payload = {};
const sessionInfo = await (0, session_1.getSessionInformation)(sessionHandle, userContext);
let userRoles = [];
if (scopes.includes("roles") || scopes.includes("permissions")) {
const res = await this.recipeInterfaceImpl.getRolesForUser({
userId: user.id,
tenantId: sessionInfo.tenantId,
userContext,
});
if (res.status !== "OK") {
throw new Error("Failed to fetch roles for the user");
}
userRoles = res.roles;
}
if (scopes.includes("roles")) {
payload.roles = userRoles;
}
if (scopes.includes("permissions")) {
const userPermissions = new Set();
for (const role of userRoles) {
const rolePermissions = await this.recipeInterfaceImpl.getPermissionsForRole({
role,
userContext,
});
if (rolePermissions.status !== "OK") {
throw new Error("Failed to fetch permissions for the role");
}
for (const perm of rolePermissions.permissions) {
userPermissions.add(perm);
}
}
payload.permissions = Array.from(userPermissions);
}
return payload;
};
stInstance
.getRecipeInstanceOrThrow("oauth2provider")
.addAccessTokenBuilderFromOtherRecipe(tokenPayloadBuilder);
stInstance.getRecipeInstanceOrThrow("oauth2provider").addIdTokenBuilderFromOtherRecipe(tokenPayloadBuilder);
stInstance
.getRecipeInstanceOrThrow("oauth2provider")
.addUserInfoBuilderFromOtherRecipe(async (user, _accessTokenPayload, scopes, tenantId, userContext) => {
let userInfo = {};
let userRoles = [];
if (scopes.includes("roles") || scopes.includes("permissions")) {
const res = await this.recipeInterfaceImpl.getRolesForUser({
userId: user.id,
tenantId,
userContext,
});
if (res.status !== "OK") {
throw new Error("Failed to fetch roles for the user");
}
userRoles = res.roles;
}
if (scopes.includes("roles")) {
userInfo.roles = userRoles;
}
if (scopes.includes("permissions")) {
const userPermissions = new Set();
for (const role of userRoles) {
const rolePermissions = await this.recipeInterfaceImpl.getPermissionsForRole({
role,
userContext,
});
if (rolePermissions.status !== "OK") {
throw new Error("Failed to fetch permissions for the role");
}
for (const perm of rolePermissions.permissions) {
userPermissions.add(perm);
}
}
userInfo.permissions = Array.from(userPermissions);
}
return userInfo;
});
});
}
/* Init functions */
static getInstanceOrThrowError() {
if (Recipe.instance !== undefined) {
return Recipe.instance;
}
throw new Error("Initialisation not done. Did you forget to call the UserRoles.init or SuperTokens.init functions?");
}
static init(config) {
return (stInstance, appInfo, isInServerlessEnv, plugins) => {
if (Recipe.instance === undefined) {
Recipe.instance = new Recipe(stInstance, Recipe.RECIPE_ID, appInfo, isInServerlessEnv, (0, plugins_1.applyPlugins)(Recipe.RECIPE_ID, config, plugins !== null && plugins !== void 0 ? plugins : []));
return Recipe.instance;
}
else {
throw new Error("UserRoles recipe has already been initialised. Please check your code for bugs.");
}
};
}
static reset() {
if (!(0, utils_2.isTestEnv)()) {
throw new Error("calling testing function in non testing env");
}
Recipe.instance = undefined;
}
/* RecipeModule functions */
getAPIsHandled() {
return [];
}
handleError(error, _, __) {
throw error;
}
getAllCORSHeaders() {
return [];
}
isErrorFromThisRecipe(err) {
return error_1.default.isErrorFromSuperTokens(err) && err.fromRecipe === Recipe.RECIPE_ID;
}
}
Recipe.RECIPE_ID = "userroles";
Recipe.instance = undefined;
exports.default = Recipe;