UNPKG

@unkey/rbac

Version:
190 lines (186 loc) 5.28 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var src_exports = {}; __export(src_exports, { RBAC: () => RBAC, and: () => and, apiActions: () => apiActions, buildIdSchema: () => buildIdSchema, buildQuery: () => buildQuery, buildUnkeyQuery: () => buildUnkeyQuery, or: () => or, permissionQuerySchema: () => permissionQuerySchema, ratelimitActions: () => ratelimitActions, unkeyPermissionValidation: () => unkeyPermissionValidation }); module.exports = __toCommonJS(src_exports); // src/permissions.ts var import_zod = require("zod"); function buildIdSchema(prefix) { return import_zod.z.string().refine((s) => { if (s === "*") { return true; } const regex = new RegExp( `^${prefix}_[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{8,32}$` ); return regex.test(s); }); } var apiId = buildIdSchema("api"); var ratelimitNamespaceId = buildIdSchema("rl"); var apiActions = import_zod.z.enum([ "read_api", "create_api", "delete_api", "update_api", "create_key", "update_key", "delete_key", "encrypt_key", "decrypt_key", "read_key" ]); var ratelimitActions = import_zod.z.enum([ "limit", "create_namespace", "read_namespace", "update_namespace", "delete_namespace" ]); var unkeyPermissionValidation = import_zod.z.custom().refine((s) => { import_zod.z.string().parse(s); if (s === "*") { return true; } const split = s.split("."); if (split.length !== 3) { return false; } const [resource, id, action] = split; switch (resource) { case "api": { return apiId.safeParse(id).success && apiActions.safeParse(action).success; } case "ratelimit": { return ratelimitNamespaceId.safeParse(id).success && ratelimitActions.safeParse(action).success; } default: { return false; } } }); // src/queries.ts var import_zod2 = require("zod"); var permissionQuerySchema = import_zod2.z.union([ import_zod2.z.string(), import_zod2.z.object({ and: import_zod2.z.array(import_zod2.z.lazy(() => permissionQuerySchema)).min(1, "provide at least one permission") }), import_zod2.z.object({ or: import_zod2.z.array(import_zod2.z.lazy(() => permissionQuerySchema)).min(1, "provide at least one permission") }) ]); function merge(rule, ...args) { return args.filter(Boolean).reduce( (acc, arg) => { if (typeof acc === "string") { throw new Error("Cannot merge into a string"); } if (!acc[rule]) { acc[rule] = []; } acc[rule].push(arg); return acc; }, {} ); } function or(...args) { return merge("or", ...args); } function and(...args) { return merge("and", ...args); } function buildQuery(fn) { return fn({ or, and }); } var buildUnkeyQuery = buildQuery; // src/rbac.ts var import_error = require("@unkey/error"); var RBAC = class { evaluatePermissions(q, roles) { return this.evaluateQueryV1(q, roles); } validateQuery(q) { const validQuery = permissionQuerySchema.safeParse(q); if (!validQuery.success) { return (0, import_error.Err)(import_error.SchemaError.fromZod(validQuery.error, q)); } return (0, import_error.Ok)({ query: validQuery.data }); } evaluateQueryV1(query, roles) { if (typeof query === "string") { if (roles.includes(query)) { return (0, import_error.Ok)({ valid: true }); } return (0, import_error.Ok)({ valid: false, message: `Role ${query} not allowed` }); } if (query.and) { const results = query.and.filter(Boolean).map((q) => this.evaluateQueryV1(q, roles)); for (const r of results) { if (r.err) { return r; } if (!r.val.valid) { return r; } } return (0, import_error.Ok)({ valid: true }); } if (query.or) { for (const q of query.or) { const r = this.evaluateQueryV1(q, roles); if (r.err) { return r; } if (r.val.valid) { return r; } } return (0, import_error.Ok)({ valid: false, message: "No role matched" }); } return (0, import_error.Err)(new import_error.SchemaError({ message: "reached end of evaluate and no match" })); } }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { RBAC, and, apiActions, buildIdSchema, buildQuery, buildUnkeyQuery, or, permissionQuerySchema, ratelimitActions, unkeyPermissionValidation }); //# sourceMappingURL=index.cjs.map