@unkey/rbac
Version:
190 lines (186 loc) • 5.28 kB
JavaScript
;
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