UNPKG

@permitio/permit-prisma

Version:

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

233 lines (232 loc) 9.99 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.PermitClient = void 0; const error_1 = require("../utils/error"); const permitio_1 = require("permitio"); const logger_1 = __importDefault(require("../utils/logger")); class PermitClient { constructor(config) { this.initialized = false; this.initializationPromise = null; this.config = config; this.permitInstance = new permitio_1.Permit({ token: config.token, pdp: config.pdp, apiUrl: config.apiUrl, log: config.debug ? { level: "debug", } : undefined, throwOnError: Boolean(config.throwOnError), }); this.initializationPromise = this.initialize(); } /** * Initialize the Permit SDK connection * This is called automatically when the client is constructed */ initialize() { return __awaiter(this, void 0, void 0, function* () { try { yield this.permitInstance.api.tenants.list(); this.initialized = true; if (this.config.debug) { logger_1.default.info("Permit SDK initialized successfully"); } } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); if (this.config.debug) { logger_1.default.error(`Failed to initialize SDK: ${errorMessage}`); } this.initialized = false; } }); } /** * Ensure the SDK is initialized before performing operations */ ensureInitialized() { return __awaiter(this, void 0, void 0, function* () { if (this.initializationPromise) { yield this.initializationPromise; this.initializationPromise = null; } if (!this.initialized) { const error = new error_1.PermitError("Permit SDK is not properly initialized"); if (this.config.throwOnError) { throw error; } if (this.config.debug) { logger_1.default.error("[Permit] Operation attempted but SDK is not initialized"); } } }); } /** * Check if a user has permission to perform an action on a resource */ check(user, action, resource, context) { return __awaiter(this, void 0, void 0, function* () { try { yield this.ensureInitialized(); if (this.config.debug) { logger_1.default.info(`[Permit] Checking permission for user=${typeof user === "string" ? user : JSON.stringify(user)}, action=${action}, resource=${typeof resource === "string" ? resource : JSON.stringify(resource)}`); } const allowed = yield this.permitInstance.check(user, action, resource, context); if (this.config.debug) { logger_1.default.info(`Permission result: ${allowed ? "ALLOWED" : "DENIED"}`); } return allowed; } catch (error) { const errorCause = error instanceof Error ? error : new Error(String(error)); const errorMessage = `Permission check failed: ${errorCause.message}`; if (this.config.debug) { logger_1.default.error(`[Permit] ${errorMessage}`); } if (this.config.throwOnError) { throw new error_1.PermitError(errorMessage, { cause: errorCause }); } return false; } }); } /** * Enforce permission check - throws if permission is denied */ enforceCheck(user, action, resource, context) { return __awaiter(this, void 0, void 0, function* () { const allowed = yield this.check(user, action, resource, context); if (!allowed) { const userStr = typeof user === "string" ? user : user.key; const resourceStr = typeof resource === "string" ? resource : `${resource.type}${resource.key ? `:${resource.key}` : ""}`; const errorMessage = `Permission denied: User ${userStr} is not allowed to ${action} on ${resourceStr}`; if (this.config.debug) { logger_1.default.error(`[Permit] ${errorMessage}`); } throw new error_1.PermitError(errorMessage); } }); } getUserPermissions(userId) { return __awaiter(this, void 0, void 0, function* () { return this.permitInstance.getUserPermissions(userId); }); } getAllowedResourceIds(userId, resourceType, action) { return __awaiter(this, void 0, void 0, function* () { yield this.ensureInitialized(); const userKey = typeof userId === "string" ? userId : userId.key; const permissions = yield this.getUserPermissions(userKey); if (this.config.debug) { logger_1.default.info(`Fetched permissions for ${userId}: ${JSON.stringify(permissions)}`); } const allowedKeys = []; for (const [key, data] of Object.entries(permissions)) { const [type, id] = key.split(":"); if (type === resourceType && data.permissions.includes(`${resourceType}:${action}`)) { allowedKeys.push(id); } } return allowedKeys; }); } filterObjects(user, action, resources) { return __awaiter(this, void 0, void 0, function* () { yield this.ensureInitialized(); const checkRequests = resources.map(resource => ({ user: user, action: action, resource: `${resource.type}:${resource.id}`, context: { resourceAttributes: resource.attributes } })); const results = yield this.permitInstance.bulkCheck(checkRequests); const allowedResources = resources.filter((resource, index) => results[index]); return allowedResources; }); } syncResourceInstanceCreate(resourceType, resourceKey, tenant = "default", attributes = {}) { return __awaiter(this, void 0, void 0, function* () { yield this.ensureInitialized(); const instanceData = { resource: resourceType, key: resourceKey, tenant, attributes, }; try { const result = yield this.permitInstance.api.resourceInstances.create(instanceData); if (this.config.debug) { logger_1.default.info(`Synced resource instance: ${resourceType}:${resourceKey} to Permit`); } return result; } catch (error) { logger_1.default.error(`Failed to sync resource instance ${resourceType}:${resourceKey}: ${error.message}`); throw error; } }); } syncResourceInstanceUpdate(resourceType, resourceKey, tenant = "default", attributes = {}) { return __awaiter(this, void 0, void 0, function* () { yield this.ensureInitialized(); const instanceData = { attributes, }; const instanceKey = `${resourceType}:${resourceKey}`; try { const result = yield this.permitInstance.api.resourceInstances.update(instanceKey, instanceData); if (this.config.debug) { logger_1.default.info(`Updated resource instance: ${instanceKey} in Permit`); } return result; } catch (error) { logger_1.default.error(`Failed to update resource instance ${instanceKey}: ${error.message}`); throw error; } }); } syncResourceInstanceDelete(resourceType, resourceKey) { return __awaiter(this, void 0, void 0, function* () { yield this.ensureInitialized(); const instanceKey = `${resourceType}:${resourceKey}`; try { yield this.permitInstance.api.resourceInstances.delete(instanceKey); if (this.config.debug) { logger_1.default.info(`Deleted resource instance: ${instanceKey} from Permit`); } } catch (error) { logger_1.default.error(`Failed to delete resource instance ${instanceKey}: ${error.message}`); throw error; } }); } /** * Get the underlying Permit SDK instance for advanced usage */ getPermitInstance() { return this.permitInstance; } } exports.PermitClient = PermitClient;