4162bfc2f75f9e1b5b661fcb048ec28572133d9d4d2fc96878eaaba887481f87.json raw
1 {"ast":null,"code":"import { IdentityId, PermissionId } from '../value-objects';\n/**\n * Permission entity - represents an authorization decision for\n * a specific identity, host, and method combination.\n *\n * Permissions are immutable once created - to change a permission,\n * delete it and create a new one.\n */\nexport class Permission {\n _id;\n _identityId;\n _host;\n _method;\n _policy;\n _kind;\n constructor(id, identityId, host, method, policy, kind) {\n this._id = id;\n this._identityId = identityId;\n this._host = host;\n this._method = method;\n this._policy = policy;\n this._kind = kind;\n }\n // ─────────────────────────────────────────────────────────────────────────\n // Factory Methods\n // ─────────────────────────────────────────────────────────────────────────\n /**\n * Create an \"allow\" permission.\n */\n static allow(identityId, host, method, kind) {\n return new Permission(PermissionId.generate(), identityId, Permission.normalizeHost(host), method, 'allow', kind);\n }\n /**\n * Create a \"deny\" permission.\n */\n static deny(identityId, host, method, kind) {\n return new Permission(PermissionId.generate(), identityId, Permission.normalizeHost(host), method, 'deny', kind);\n }\n /**\n * Create a permission with explicit policy.\n */\n static create(identityId, host, method, policy, kind) {\n return new Permission(PermissionId.generate(), identityId, Permission.normalizeHost(host), method, policy, kind);\n }\n /**\n * Reconstitute a permission from storage.\n */\n static fromSnapshot(snapshot) {\n return new Permission(PermissionId.from(snapshot.id), IdentityId.from(snapshot.identityId), snapshot.host, snapshot.method, snapshot.methodPolicy, snapshot.kind);\n }\n // ─────────────────────────────────────────────────────────────────────────\n // Getters\n // ─────────────────────────────────────────────────────────────────────────\n get id() {\n return this._id;\n }\n get identityId() {\n return this._identityId;\n }\n get host() {\n return this._host;\n }\n get method() {\n return this._method;\n }\n get policy() {\n return this._policy;\n }\n get kind() {\n return this._kind;\n }\n // ─────────────────────────────────────────────────────────────────────────\n // Behavior\n // ─────────────────────────────────────────────────────────────────────────\n /**\n * Check if this permission allows the action.\n */\n isAllowed() {\n return this._policy === 'allow';\n }\n /**\n * Check if this permission denies the action.\n */\n isDenied() {\n return this._policy === 'deny';\n }\n /**\n * Check if this permission matches the given criteria.\n * For signEvent with kind specified, also checks the kind.\n */\n matches(identityId, host, method, kind) {\n if (!this._identityId.equals(identityId)) {\n return false;\n }\n if (this._host !== Permission.normalizeHost(host)) {\n return false;\n }\n if (this._method !== method) {\n return false;\n }\n // For signEvent, handle kind matching\n if (method === 'signEvent') {\n // If this permission has no kind, it matches all kinds\n if (this._kind === undefined) {\n return true;\n }\n // If checking a specific kind, must match exactly\n return this._kind === kind;\n }\n return true;\n }\n /**\n * Check if this permission applies to a specific event kind.\n * Only relevant for signEvent method.\n */\n appliesToKind(kind) {\n if (this._method !== 'signEvent') {\n return false;\n }\n // No kind restriction means applies to all\n if (this._kind === undefined) {\n return true;\n }\n return this._kind === kind;\n }\n /**\n * Check if this is a blanket permission (no kind restriction).\n */\n isBlanketPermission() {\n return this._method === 'signEvent' && this._kind === undefined;\n }\n // ─────────────────────────────────────────────────────────────────────────\n // Persistence\n // ─────────────────────────────────────────────────────────────────────────\n /**\n * Convert to a snapshot for persistence.\n */\n toSnapshot() {\n const snapshot = {\n id: this._id.value,\n identityId: this._identityId.value,\n host: this._host,\n method: this._method,\n methodPolicy: this._policy\n };\n if (this._kind !== undefined) {\n snapshot.kind = this._kind;\n }\n return snapshot;\n }\n // ─────────────────────────────────────────────────────────────────────────\n // Equality\n // ─────────────────────────────────────────────────────────────────────────\n /**\n * Check equality based on permission ID.\n */\n equals(other) {\n return this._id.equals(other._id);\n }\n // ─────────────────────────────────────────────────────────────────────────\n // Helpers\n // ─────────────────────────────────────────────────────────────────────────\n static normalizeHost(host) {\n return host.toLowerCase().trim();\n }\n}\n/**\n * Permission checker - evaluates permissions for a request.\n * This encapsulates the permission checking logic.\n */\nexport class PermissionChecker {\n permissions;\n constructor(permissions) {\n this.permissions = permissions;\n }\n /**\n * Check if an action is allowed.\n *\n * @returns true if allowed, false if denied, undefined if no matching permission\n */\n check(identityId, host, method, kind) {\n const matching = this.permissions.filter(p => p.matches(identityId, host, method, kind));\n if (matching.length === 0) {\n return undefined;\n }\n // For signEvent with kind, check specific rules\n // Kind-specific rules take priority over blanket rules\n if (method === 'signEvent' && kind !== undefined) {\n // Check for specific kind deny first (takes priority)\n if (matching.some(p => p.kind === kind && p.isDenied())) {\n return false;\n }\n // Check for specific kind allow\n if (matching.some(p => p.kind === kind && p.isAllowed())) {\n return true;\n }\n // Fall back to blanket allow (no kind restriction)\n if (matching.some(p => p.isBlanketPermission() && p.isAllowed())) {\n return true;\n }\n // Fall back to blanket deny\n if (matching.some(p => p.isBlanketPermission() && p.isDenied())) {\n return false;\n }\n // No specific rule found\n return undefined;\n }\n // For other methods, all matching permissions must allow\n return matching.every(p => p.isAllowed());\n }\n /**\n * Get all permissions for a specific identity.\n */\n forIdentity(identityId) {\n return this.permissions.filter(p => p.identityId.equals(identityId));\n }\n /**\n * Get all permissions for a specific host.\n */\n forHost(host) {\n const normalizedHost = host.toLowerCase().trim();\n return this.permissions.filter(p => p.host === normalizedHost);\n }\n}","map":null,"metadata":{},"sourceType":"module","externalDependencies":[]}