UNPKG

@permitio/permit-prisma

Version:

Prisma extension for integrating Permit.io authorization (RBAC, ABAC, ReBAC) into your Prisma application.

172 lines (171 loc) 6.67 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.extractAttributes = exports.getResourceIdForSync = exports.getResourceId = exports.createResourceObject = exports.mapModelToResourceType = exports.mapOperationToAction = void 0; const PermissionModels_1 = require("../models/PermissionModels"); /** * Maps Prisma query operations to Permit.io permission action names. * This function translates Prisma's operation types (like findMany, create, etc.) * into standardized action names used in Permit.io authorization checks. * * @param {string} operation - The Prisma operation name (e.g., "findMany", "create", "update") * @returns {string} The corresponding Permit.io action name (e.g., "read", "create", "update") * * @example * mapOperationToAction("findMany") // Returns "read" * mapOperationToAction("create") // Returns "create" * mapOperationToAction("upsert") // Returns "update" */ function mapOperationToAction(operation) { switch (operation) { case "findUnique": case "findUniqueOrThrow": case "findFirst": case "findFirstOrThrow": case "findMany": return "read"; case "create": case "createMany": return "create"; case "update": case "updateMany": return "update"; case "upsert": return "update"; case "delete": case "deleteMany": return "delete"; default: return operation; } } exports.mapOperationToAction = mapOperationToAction; /** * Maps Prisma model names to Permit.io resource types. * This function converts Prisma model names (typically PascalCase) to Permit.io * resource type identifiers (typically snake_case) unless a custom mapping is provided. * * @param {string} model - The Prisma model name (e.g., "User", "BlogPost") * @param {Record<string, string>} [mapping] - Optional custom mapping from model names to resource types * @returns {string} The corresponding Permit.io resource type identifier * * @example * // Without mapping * mapModelToResourceType("UserProfile") // Returns "user_profile" * * // With custom mapping * const mapping = { "User": "customer" }; * mapModelToResourceType("User", mapping) // Returns "customer" */ function mapModelToResourceType(model, mapping) { if (mapping && mapping[model]) { return mapping[model]; } return model.replace(/([a-z])([A-Z])/g, "$1_$2").toLowerCase(); } exports.mapModelToResourceType = mapModelToResourceType; /** * Creates a properly formatted resource object for Permit.io permission checks * based on the access control model being used. * * @param {string} resourceType - The Permit.io resource type (e.g., "document", "user") * @param {any} args - Prisma query arguments containing data and/or where clauses * @param {string} operation - The Prisma operation being performed (e.g., "create", "update") * @param {AccessControlModel} [modelType] - The access control model (RBAC, ABAC, or ReBAC) * @returns {string|object} A formatted resource object compatible with Permit.io checks * * @example * // No model type or RBAC - simple string * createResourceObject("document", {}, "read") * // Returns: "document" * * // ABAC - object with attributes * createResourceObject("document", { data: { confidential: true }}, "create", AccessControlModel.ABAC) * // Returns: { type: "document", attributes: { confidential: true }} * * // ReBAC - object with resource ID and attributes * createResourceObject("document", { where: { id: "123" }}, "update", AccessControlModel.ReBAC) * // Returns: { type: "document", key: "123", attributes: {...} } */ function createResourceObject(resourceType, args, operation, modelType) { if (modelType === PermissionModels_1.AccessControlModel.RBAC) { return resourceType; } if (modelType === PermissionModels_1.AccessControlModel.ABAC) { return { type: resourceType, attributes: extractAttributes(args), }; } if (modelType === PermissionModels_1.AccessControlModel.ReBAC) { const key = getResourceId(args === null || args === void 0 ? void 0 : args.where); const attributes = extractAttributes(args); return Object.assign(Object.assign({ type: resourceType }, (key !== undefined && { key })), (attributes && Object.keys(attributes).length > 0 && { attributes })); } return resourceType; } exports.createResourceObject = createResourceObject; /** * Extracts the resource ID from the Prisma query args */ function getResourceId(where) { if (!where || typeof where !== "object") return undefined; if (where.id !== undefined) { return where.id; } for (const key in where) { const value = where[key]; if (typeof value !== "object" && value !== undefined) { return value; } } return undefined; } exports.getResourceId = getResourceId; function getResourceIdForSync(result, operation) { if (!result) return null; if (operation === "create" || operation === "update" || operation === "delete") { if (result.id) return String(result.id); if (Array.isArray(result) && result.length > 0 && result[0].id) return String(result[0].id); } return null; } exports.getResourceIdForSync = getResourceIdForSync; /** * Extracts attributes from Prisma query arguments to be used in ABAC/ReBAC permission checks. * This function attempts to extract meaningful data attributes from either the `data` object * (in create/update operations) or the `where` object (in read/delete operations). * * @param {any} args - The Prisma query arguments object * @returns {Record<string, any>} An object containing extracted attributes, or an empty object if no attributes found * * @example * // From create/update operation * extractAttributes({ data: { title: "Document", confidential: true }}) * // Returns: { title: "Document", confidential: true } * * // From read/delete operation * extractAttributes({ where: { id: "123", status: "active" }}) * // Returns: { id: "123", status: "active" } * * // When no relevant data is found * extractAttributes({}) * // Returns: {} */ function extractAttributes(args) { if (!args) return {}; if (args.data && typeof args.data === "object") { return Object.assign({}, args.data); } if (args.where && typeof args.where === "object") { return Object.assign({}, args.where); } return {}; } exports.extractAttributes = extractAttributes;