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":[]}