UNPKG

@bdelab/roar-firekit

Version:

A library to facilitate Firebase authentication and Cloud Firestore interaction for ROAR apps

110 lines (109 loc) 5.37 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.PermissionsService = void 0; const roles_1 = require("../constants/roles"); const user_roles_1 = require("../constants/user-roles"); const permissions_1 = require("../constants/permissions"); const flattenObjectValues_util_1 = require("../utils/flattenObjectValues.util"); const jwt_decode_1 = require("jwt-decode"); exports.PermissionsService = (() => { /** * This function takes a the JWT token of the user and a permission, and validates if the user is allowed to perform the action associated with the permission. * @param {string} token A JWT token string from Firestore User. * @param {string} permission The permission to check. * @returns {Boolean} True if the user has the permission, false otherwise. */ const canUser = (token, permission) => { var _a; if (!isValidPermission(permission)) { console.error(`[ROAR Permissions Service] Invalid permission "${permission}".`); return false; } try { const userRole = (_a = getRoleFromToken(token)) === null || _a === void 0 ? void 0 : _a.toLowerCase(); // If the user is a super admin, grant permission. if (userRole === user_roles_1.UserRoles.SUPER_ADMIN.toLowerCase()) return true; const config = roles_1.roles[userRole]; // If the user role doesn't exist in our config, flag and deny. if (!config) { console.error(`[ROAR Permissions Service] Invalid user role "${userRole}".`); return false; } return checkPermissionList(config.permissions, permission); } catch (error) { console.error('[ROAR Permissions Service] Error checking permissions:', error); return false; } }; /** * This function returns a boolean indicating whether the provided permission is present * in the Permissions object. * * @param {any} permission A permission string to check. * @returns {Boolean} True if the permission is valid, false otherwise. */ const isValidPermission = (permission) => { if (typeof permission !== 'string') return false; const allPermissions = (0, flattenObjectValues_util_1.flattenObjectValues)(permissions_1.Permissions); return allPermissions.includes(permission); }; /** * This function takes a JWT token and returns the user's role. If the token is invalid or missing the role claim, * return the GUEST role. * * @param {string} token JWT token string from Firestore User. * @returns {string} The user's role based on the provided JWT token. */ const getRoleFromToken = (token) => { var _a; const decodedToken = (0, jwt_decode_1.jwtDecode)(token); const userRole = (_a = decodedToken.role) !== null && _a !== void 0 ? _a : user_roles_1.FallbackRole; // Retrieve the user's role from the token's claims. If the claim is missing or invalid, default to the GUEST role. if (!decodedToken.role) { console.error(`[ROAR Permissions Service] Missing role claim in user's custom claims. Defaulting to the ${userRole} role.`); } return userRole; }; /** * This function checks if a permission is included in a list of permissions. * * @param {string[]} permissionsList List of permissions to check against. * @param {string} permission Permission to check. * @returns {Boolean} True if the permission is in the list, false otherwise. */ const checkPermissionList = (permissionsList, permission) => { // Check if the literal permission is in the list if (permissionsList.includes(permission)) return true; // Check if the permission matches a wildcard permission return permissionsList.some((rolePermission) => matchWildcardPermission(rolePermission, permission)); }; /** * This function checks if a permission matches a wildcard permission within a permission list. * ex. 'app.users.create' matches 'app.user.*' and 'app.*' * * @param {string} permission Permisssion from the * @param {string} userPermission Permission to check. This will be from the user. * @returns {Boolean} True if the permissions match considering wildcards. False otherwise. */ const matchWildcardPermission = (pattern, permission) => { const patternParts = pattern.split('.'); const permissionParts = permission.split('.'); // Check if the pattern has a wildcard const wildcardIndex = patternParts.indexOf('*'); // If there's no wildcard, the parts should match exactly if (wildcardIndex === -1) { return (patternParts.length === permissionParts.length && patternParts.every((part, index) => part === permissionParts[index])); } // If there's a wildcard, it must be the last part if (wildcardIndex !== patternParts.length - 1) return false; // Check if all parts before the wildcard match return patternParts.slice(0, wildcardIndex).every((part, index) => part === permissionParts[index]); }; return { canUser }; })();