@naylence/advanced-security 0.4.4 → 0.4.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/dist/browser/index.cjs +702 -32
  2. package/dist/browser/index.mjs +702 -32
  3. package/dist/cjs/advanced-security-isomorphic.js +1 -1
  4. package/dist/cjs/advanced-security-isomorphic.js.map +1 -1
  5. package/dist/cjs/naylence/fame/expr/builtins.js +1 -1
  6. package/dist/cjs/naylence/fame/expr/builtins.js.map +1 -1
  7. package/dist/cjs/naylence/fame/factory-manifest.js +2 -0
  8. package/dist/cjs/naylence/fame/factory-manifest.js.map +1 -1
  9. package/dist/cjs/naylence/fame/security/auth/index.js +2 -0
  10. package/dist/cjs/naylence/fame/security/auth/index.js.map +1 -1
  11. package/dist/cjs/naylence/fame/security/auth/policy/advanced-authorization-policy.js +32 -13
  12. package/dist/cjs/naylence/fame/security/auth/policy/advanced-authorization-policy.js.map +1 -1
  13. package/dist/cjs/naylence/fame/security/auth/policy/auth-policy-server-cli.js +47 -0
  14. package/dist/cjs/naylence/fame/security/auth/policy/auth-policy-server-cli.js.map +1 -0
  15. package/dist/cjs/naylence/fame/security/auth/policy/auth-policy-server.js +553 -0
  16. package/dist/cjs/naylence/fame/security/auth/policy/auth-policy-server.js.map +1 -0
  17. package/dist/cjs/naylence/fame/security/auth/policy/expr-builtins.js +166 -2
  18. package/dist/cjs/naylence/fame/security/auth/policy/expr-builtins.js.map +1 -1
  19. package/dist/cjs/naylence/fame/security/auth/policy/http-authorization-policy-source-factory.js +108 -0
  20. package/dist/cjs/naylence/fame/security/auth/policy/http-authorization-policy-source-factory.js.map +1 -0
  21. package/dist/cjs/naylence/fame/security/auth/policy/http-authorization-policy-source.js +367 -0
  22. package/dist/cjs/naylence/fame/security/auth/policy/http-authorization-policy-source.js.map +1 -0
  23. package/dist/cjs/naylence/fame/security/auth/policy/index.js +4 -2
  24. package/dist/cjs/naylence/fame/security/auth/policy/index.js.map +1 -1
  25. package/dist/cjs/naylence/fame/security/auth/policy-http-authorization-profile.js +78 -0
  26. package/dist/cjs/naylence/fame/security/auth/policy-http-authorization-profile.js.map +1 -0
  27. package/dist/cjs/naylence/fame/security/register-advanced-security-factories.js +2 -0
  28. package/dist/cjs/naylence/fame/security/register-advanced-security-factories.js.map +1 -1
  29. package/dist/cjs/version.js +2 -2
  30. package/dist/esm/advanced-security-isomorphic.js +1 -1
  31. package/dist/esm/advanced-security-isomorphic.js.map +1 -1
  32. package/dist/esm/naylence/fame/expr/builtins.js +1 -1
  33. package/dist/esm/naylence/fame/expr/builtins.js.map +1 -1
  34. package/dist/esm/naylence/fame/factory-manifest.js +2 -0
  35. package/dist/esm/naylence/fame/factory-manifest.js.map +1 -1
  36. package/dist/esm/naylence/fame/security/auth/index.js +2 -0
  37. package/dist/esm/naylence/fame/security/auth/index.js.map +1 -1
  38. package/dist/esm/naylence/fame/security/auth/policy/advanced-authorization-policy.js +32 -13
  39. package/dist/esm/naylence/fame/security/auth/policy/advanced-authorization-policy.js.map +1 -1
  40. package/dist/esm/naylence/fame/security/auth/policy/auth-policy-server-cli.js +47 -0
  41. package/dist/esm/naylence/fame/security/auth/policy/auth-policy-server-cli.js.map +1 -0
  42. package/dist/esm/naylence/fame/security/auth/policy/auth-policy-server.js +553 -0
  43. package/dist/esm/naylence/fame/security/auth/policy/auth-policy-server.js.map +1 -0
  44. package/dist/esm/naylence/fame/security/auth/policy/expr-builtins.js +166 -2
  45. package/dist/esm/naylence/fame/security/auth/policy/expr-builtins.js.map +1 -1
  46. package/dist/esm/naylence/fame/security/auth/policy/http-authorization-policy-source-factory.js +108 -0
  47. package/dist/esm/naylence/fame/security/auth/policy/http-authorization-policy-source-factory.js.map +1 -0
  48. package/dist/esm/naylence/fame/security/auth/policy/http-authorization-policy-source.js +367 -0
  49. package/dist/esm/naylence/fame/security/auth/policy/http-authorization-policy-source.js.map +1 -0
  50. package/dist/esm/naylence/fame/security/auth/policy/index.js +4 -2
  51. package/dist/esm/naylence/fame/security/auth/policy/index.js.map +1 -1
  52. package/dist/esm/naylence/fame/security/auth/policy-http-authorization-profile.js +78 -0
  53. package/dist/esm/naylence/fame/security/auth/policy-http-authorization-profile.js.map +1 -0
  54. package/dist/esm/naylence/fame/security/register-advanced-security-factories.js +2 -0
  55. package/dist/esm/naylence/fame/security/register-advanced-security-factories.js.map +1 -1
  56. package/dist/esm/version.js +2 -2
  57. package/dist/node/index.cjs +777 -139
  58. package/dist/node/index.mjs +770 -109
  59. package/dist/node/node.cjs +788 -65
  60. package/dist/node/node.mjs +780 -34
  61. package/dist/types/advanced-security-isomorphic.d.ts +0 -1
  62. package/dist/types/advanced-security-isomorphic.d.ts.map +1 -1
  63. package/dist/types/naylence/fame/factory-manifest.d.ts +1 -1
  64. package/dist/types/naylence/fame/factory-manifest.d.ts.map +1 -1
  65. package/dist/types/naylence/fame/security/auth/index.d.ts +1 -0
  66. package/dist/types/naylence/fame/security/auth/index.d.ts.map +1 -1
  67. package/dist/types/naylence/fame/security/auth/policy/advanced-authorization-policy.d.ts.map +1 -1
  68. package/dist/types/naylence/fame/security/auth/policy/auth-policy-server-cli.d.ts +20 -0
  69. package/dist/types/naylence/fame/security/auth/policy/auth-policy-server-cli.d.ts.map +1 -0
  70. package/dist/types/naylence/fame/security/auth/policy/auth-policy-server.d.ts +74 -0
  71. package/dist/types/naylence/fame/security/auth/policy/auth-policy-server.d.ts.map +1 -0
  72. package/dist/types/naylence/fame/security/auth/policy/expr-builtins.d.ts +71 -1
  73. package/dist/types/naylence/fame/security/auth/policy/expr-builtins.d.ts.map +1 -1
  74. package/dist/types/naylence/fame/security/auth/policy/http-authorization-policy-source-factory.d.ts +81 -0
  75. package/dist/types/naylence/fame/security/auth/policy/http-authorization-policy-source-factory.d.ts.map +1 -0
  76. package/dist/types/naylence/fame/security/auth/policy/http-authorization-policy-source.d.ts +150 -0
  77. package/dist/types/naylence/fame/security/auth/policy/http-authorization-policy-source.d.ts.map +1 -0
  78. package/dist/types/naylence/fame/security/auth/policy/index.d.ts +2 -1
  79. package/dist/types/naylence/fame/security/auth/policy/index.d.ts.map +1 -1
  80. package/dist/types/naylence/fame/security/auth/policy-http-authorization-profile.d.ts +17 -0
  81. package/dist/types/naylence/fame/security/auth/policy-http-authorization-profile.d.ts.map +1 -0
  82. package/dist/types/naylence/fame/security/register-advanced-security-factories.d.ts +1 -0
  83. package/dist/types/naylence/fame/security/register-advanced-security-factories.d.ts.map +1 -1
  84. package/dist/types/version.d.ts +1 -1
  85. package/package.json +3 -2
@@ -1,7 +1,8 @@
1
1
  import { ExtensionManager, Expressions, Registry, AbstractResourceFactory } from '@naylence/factory';
2
- import { ENCRYPTION_MANAGER_FACTORY_BASE_TYPE, getLogger, registerProfile, SECURITY_MANAGER_FACTORY_BASE_TYPE, KNOWN_POLICY_FIELDS, VALID_EFFECTS, compileGlobOnlyScopeRequirement, KNOWN_RULE_FIELDS, VALID_ACTIONS, compileGlobPattern, VALID_ORIGIN_TYPES, AUTHORIZATION_POLICY_FACTORY_BASE_TYPE, AuthorizationPolicyFactory, EncryptionResult, urlsafeBase64Decode, sealedDecrypt, sealedEncrypt, FIXED_PREFIX_LEN, urlsafeBase64Encode, EncryptionManagerFactory, requireCryptoSupport, SECURE_CHANNEL_MANAGER_FACTORY_BASE_TYPE, SecureChannelManagerFactory, ENVELOPE_SIGNER_FACTORY_BASE_TYPE, EnvelopeSignerFactory, SigningConfigClass, validateSigningKey, JWKValidationError, decodeBase64Url, canonicalJson, secureDigest, frameDigest, immutableHeaders, encodeUtf8, ENVELOPE_VERIFIER_FACTORY_BASE_TYPE, EnvelopeVerifierFactory, TrustStoreProviderFactory, TaskSpawner, getKeyStore, DefaultKeyManager, validateJwkComplete, currentTraceId, DeliveryOriginType, KEY_MANAGER_FACTORY_BASE_TYPE, KeyManagerFactory, KeyStoreFactory, BaseNodeEventListener, LOAD_BALANCER_STICKINESS_MANAGER_FACTORY_BASE_TYPE, LoadBalancerStickinessManagerFactory, REPLICA_STICKINESS_MANAGER_FACTORY_BASE_TYPE, ReplicaStickinessManagerFactory, color, AnsiColor, validateHostLogicals, HTTP_CONNECTION_GRANT_TYPE, formatTimestamp, jsonDumps, WELCOME_SERVICE_FACTORY_BASE_TYPE, WelcomeServiceFactory, NodePlacementStrategyFactory, TransportProvisionerFactory, TokenIssuerFactory, AuthorizerFactory, validateHostLogical, AuthInjectionStrategyFactory, CERTIFICATE_MANAGER_FACTORY_BASE_TYPE, CertificateManagerFactory, TRUST_STORE_PROVIDER_FACTORY_BASE_TYPE } from '@naylence/runtime';
3
- import { sha256 } from '@noble/hashes/sha256';
2
+ import { ENCRYPTION_MANAGER_FACTORY_BASE_TYPE, getLogger, registerProfile, SECURITY_MANAGER_FACTORY_BASE_TYPE, KNOWN_POLICY_FIELDS, VALID_EFFECTS, compileGlobOnlyScopeRequirement, KNOWN_RULE_FIELDS, VALID_ACTIONS, compileGlobPattern, VALID_ORIGIN_TYPES, AUTHORIZATION_POLICY_FACTORY_BASE_TYPE, AuthorizationPolicyFactory, AUTHORIZATION_POLICY_SOURCE_FACTORY_BASE_TYPE, AuthorizationPolicySourceFactory, TokenProviderFactory, EncryptionResult, urlsafeBase64Decode, sealedDecrypt, sealedEncrypt, FIXED_PREFIX_LEN, urlsafeBase64Encode, EncryptionManagerFactory, requireCryptoSupport, SECURE_CHANNEL_MANAGER_FACTORY_BASE_TYPE, SecureChannelManagerFactory, ENVELOPE_SIGNER_FACTORY_BASE_TYPE, EnvelopeSignerFactory, SigningConfigClass, validateSigningKey, JWKValidationError, decodeBase64Url, canonicalJson, secureDigest, frameDigest, immutableHeaders, encodeUtf8, ENVELOPE_VERIFIER_FACTORY_BASE_TYPE, EnvelopeVerifierFactory, TrustStoreProviderFactory, TaskSpawner, getKeyStore, DefaultKeyManager, validateJwkComplete, currentTraceId, DeliveryOriginType, KEY_MANAGER_FACTORY_BASE_TYPE, KeyManagerFactory, KeyStoreFactory, BaseNodeEventListener, LOAD_BALANCER_STICKINESS_MANAGER_FACTORY_BASE_TYPE, LoadBalancerStickinessManagerFactory, REPLICA_STICKINESS_MANAGER_FACTORY_BASE_TYPE, ReplicaStickinessManagerFactory, color, AnsiColor, validateHostLogicals, HTTP_CONNECTION_GRANT_TYPE, formatTimestamp, jsonDumps, WELCOME_SERVICE_FACTORY_BASE_TYPE, WelcomeServiceFactory, NodePlacementStrategyFactory, TransportProvisionerFactory, TokenIssuerFactory, AuthorizerFactory, validateHostLogical, AuthInjectionStrategyFactory, CERTIFICATE_MANAGER_FACTORY_BASE_TYPE, CertificateManagerFactory, TRUST_STORE_PROVIDER_FACTORY_BASE_TYPE } from '@naylence/runtime';
3
+ import { sha256 } from '@noble/hashes/sha2';
4
4
  import { generateFingerprintSync, localDeliveryContext, createFameEnvelope, generateId, formatAddress, FameAddress, SigningMaterial, DeliveryOriginType as DeliveryOriginType$1 } from '@naylence/core';
5
+ import { parse as parse$1 } from 'yaml';
5
6
  import { AsnConvert, OctetString } from '@peculiar/asn1-schema';
6
7
  import { Attributes, CertificationRequestInfo, CertificationRequest } from '@peculiar/asn1-csr';
7
8
  import { Certificate, SubjectAlternativeName, NameConstraints, id_ce_subjectAltName, id_ce_nameConstraints, SubjectPublicKeyInfo, GeneralName, Extensions, Extension, Attribute, AlgorithmIdentifier, Name, RelativeDistinguishedName, AttributeTypeAndValue, AttributeValue, BasicConstraints, id_ce_basicConstraints, KeyUsageFlags, id_ce_keyUsage, KeyUsage, id_ce_subjectKeyIdentifier, SubjectKeyIdentifier, id_ce_authorityKeyIdentifier, AuthorityKeyIdentifier, KeyIdentifier, GeneralSubtrees, GeneralSubtree, TBSCertificate, Validity, Version, id_ce_extKeyUsage, ExtendedKeyUsage, id_kp_clientAuth, id_kp_serverAuth } from '@peculiar/asn1-x509';
@@ -23,6 +24,7 @@ import { X509Certificate } from '@peculiar/x509';
23
24
  */
24
25
  const MODULES = [
25
26
  "./security/auth/policy/advanced-authorization-policy-factory.js",
27
+ "./security/auth/policy/http-authorization-policy-source-factory.js",
26
28
  "./security/cert/default-ca-service-factory.js",
27
29
  "./security/cert/default-certificate-manager-factory.js",
28
30
  "./security/cert/trust-store/browser-trust-store-provider-factory.js",
@@ -40,6 +42,7 @@ const MODULES = [
40
42
  ];
41
43
  const MODULE_LOADERS = {
42
44
  "./security/auth/policy/advanced-authorization-policy-factory.js": () => Promise.resolve().then(function () { return advancedAuthorizationPolicyFactory; }),
45
+ "./security/auth/policy/http-authorization-policy-source-factory.js": () => Promise.resolve().then(function () { return httpAuthorizationPolicySourceFactory; }),
43
46
  "./security/cert/default-ca-service-factory.js": () => Promise.resolve().then(function () { return defaultCaServiceFactory; }),
44
47
  "./security/cert/default-certificate-manager-factory.js": () => Promise.resolve().then(function () { return defaultCertificateManagerFactory; }),
45
48
  "./security/cert/trust-store/browser-trust-store-provider-factory.js": () => Promise.resolve().then(function () { return browserTrustStoreProviderFactory; }),
@@ -56,7 +59,7 @@ const MODULE_LOADERS = {
56
59
  "./welcome/advanced-welcome-service-factory.js": () => Promise.resolve().then(function () { return advancedWelcomeServiceFactory; }),
57
60
  };
58
61
 
59
- const logger$h = getLogger("naylence.fame.security.encryption.encryption_manager_registry");
62
+ const logger$i = getLogger("naylence.fame.security.encryption.encryption_manager_registry");
60
63
  class EncryptionManagerFactoryRegistry {
61
64
  constructor(autoDiscover = true) {
62
65
  this.factories = [];
@@ -78,7 +81,7 @@ class EncryptionManagerFactoryRegistry {
78
81
  let registeredCount = 0;
79
82
  for (const [factoryName, info] of extensionInfos) {
80
83
  if (factoryName === "CompositeEncryptionManager") {
81
- logger$h.debug("skipping_composite_factory_to_avoid_circular_dependency", {
84
+ logger$i.debug("skipping_composite_factory_to_avoid_circular_dependency", {
82
85
  factory_name: factoryName,
83
86
  });
84
87
  continue;
@@ -88,7 +91,7 @@ class EncryptionManagerFactoryRegistry {
88
91
  ExtensionManager.getGlobalFactory(ENCRYPTION_MANAGER_FACTORY_BASE_TYPE, factoryName));
89
92
  this.registerFactory(factoryInstance, { autoDiscovered: true });
90
93
  registeredCount += 1;
91
- logger$h.debug("auto_discovered_factory", {
94
+ logger$i.debug("auto_discovered_factory", {
92
95
  factory_name: factoryName,
93
96
  factory_class: factoryInstance.constructor.name,
94
97
  algorithms: factoryInstance.getSupportedAlgorithms(),
@@ -97,21 +100,21 @@ class EncryptionManagerFactoryRegistry {
97
100
  });
98
101
  }
99
102
  catch (error) {
100
- logger$h.warning("failed_to_auto_register_factory", {
103
+ logger$i.warning("failed_to_auto_register_factory", {
101
104
  factory_name: factoryName,
102
105
  error: error instanceof Error ? error.message : String(error),
103
106
  });
104
107
  }
105
108
  }
106
109
  this.autoDiscovered = true;
107
- logger$h.debug("completed_auto_discovery", {
110
+ logger$i.debug("completed_auto_discovery", {
108
111
  registered_factories: registeredCount,
109
112
  total_discovered: extensionInfos.size,
110
113
  skipped_composite: true,
111
114
  });
112
115
  }
113
116
  catch (error) {
114
- logger$h.warning("failed_auto_discovery_of_factories", {
117
+ logger$i.warning("failed_auto_discovery_of_factories", {
115
118
  error: error instanceof Error ? error.message : String(error),
116
119
  });
117
120
  }
@@ -129,7 +132,7 @@ class EncryptionManagerFactoryRegistry {
129
132
  const existing = this.algorithmToFactory.get(algorithm);
130
133
  if (!existing || factory.getPriority() > existing.getPriority()) {
131
134
  this.algorithmToFactory.set(algorithm, factory);
132
- logger$h.debug("registered_algorithm_mapping", {
135
+ logger$i.debug("registered_algorithm_mapping", {
133
136
  algorithm,
134
137
  factory: factory.constructor.name,
135
138
  priority: factory.getPriority(),
@@ -141,7 +144,7 @@ class EncryptionManagerFactoryRegistry {
141
144
  typeFactories.push(factory);
142
145
  typeFactories.sort((a, b) => b.getPriority() - a.getPriority());
143
146
  this.typeToFactories.set(encryptionType, typeFactories);
144
- logger$h.debug("registered_encryption_manager_factory", {
147
+ logger$i.debug("registered_encryption_manager_factory", {
145
148
  factory: factory.constructor.name,
146
149
  encryption_type: encryptionType,
147
150
  algorithms: factory.getSupportedAlgorithms(),
@@ -157,14 +160,14 @@ class EncryptionManagerFactoryRegistry {
157
160
  this.ensureAutoDiscovery();
158
161
  for (const factory of this.factories) {
159
162
  if (factory.supportsOptions(opts ?? undefined)) {
160
- logger$h.debug("found_factory_for_options", {
163
+ logger$i.debug("found_factory_for_options", {
161
164
  factory: factory.constructor.name,
162
165
  encryption_type: factory.getEncryptionType(),
163
166
  });
164
167
  return factory;
165
168
  }
166
169
  }
167
- logger$h.debug("no_factory_found_for_options", { opts });
170
+ logger$i.debug("no_factory_found_for_options", { opts });
168
171
  return undefined;
169
172
  }
170
173
  getFactoriesByType(encryptionType) {
@@ -290,6 +293,7 @@ const SECURITY_PREFIX = "./security/";
290
293
  const SECURITY_MODULES = MODULES.filter((spec) => spec.startsWith(SECURITY_PREFIX));
291
294
  const EXTRA_MODULES = MODULES.filter((spec) => !spec.startsWith(SECURITY_PREFIX));
292
295
  const NODE_ONLY_MODULES = new Set([
296
+ "./security/auth/policy/http-authorization-policy-source-factory.js",
293
297
  "./security/cert/default-ca-service-factory.js",
294
298
  "./security/cert/trust-store/node-trust-store-provider-factory.js",
295
299
  ]);
@@ -570,12 +574,12 @@ async function registerAdvancedSecurityFactories(registrar = Registry, options)
570
574
  }
571
575
 
572
576
  // This file is auto-generated during build - do not edit manually
573
- // Generated from package.json version: 0.4.4
577
+ // Generated from package.json version: 0.4.6
574
578
  /**
575
579
  * The package version, injected at build time.
576
580
  * @internal
577
581
  */
578
- const VERSION = '0.4.4';
582
+ const VERSION = '0.4.6';
579
583
 
580
584
  async function registerAdvancedSecurityPluginFactories(registrar = Registry) {
581
585
  await registerAdvancedSecurityFactories(registrar);
@@ -2459,8 +2463,86 @@ function evaluateAsBoolean(ast, context) {
2459
2463
  * Null handling semantics:
2460
2464
  * - Scope predicate builtins (has_scope, has_any_scope, has_all_scopes)
2461
2465
  * return `false` when passed `null` for required args.
2466
+ * - Security predicate builtins (is_signed, is_encrypted, is_encrypted_at_least)
2467
+ * return `false` when the envelope lacks the required security posture.
2462
2468
  * - Wrong non-null types still raise BuiltinError to surface real bugs.
2463
2469
  */
2470
+ /**
2471
+ * Valid encryption levels for is_encrypted_at_least comparisons.
2472
+ */
2473
+ const VALID_ENCRYPTION_LEVELS = [
2474
+ "plaintext",
2475
+ "channel",
2476
+ "sealed",
2477
+ ];
2478
+ /**
2479
+ * Encryption level ordering for comparison.
2480
+ * Higher number = stronger encryption.
2481
+ */
2482
+ const ENCRYPTION_LEVEL_ORDER = {
2483
+ plaintext: 0,
2484
+ channel: 1,
2485
+ sealed: 2,
2486
+ };
2487
+ /**
2488
+ * Normalizes an encryption algorithm string to an EncryptionLevel.
2489
+ *
2490
+ * Mapping rules:
2491
+ * - null/undefined => "plaintext" (no encryption present)
2492
+ * - alg contains "-channel" => "channel" (e.g., "chacha20-poly1305-channel")
2493
+ * - alg contains "-sealed" => "sealed" (explicit sealed marker)
2494
+ * - alg matches ECDH-ES pattern with AEAD cipher => "sealed" (e.g., "ECDH-ES+A256GCM")
2495
+ * - otherwise => "unknown"
2496
+ *
2497
+ * Currently supported algorithms:
2498
+ * - Channel: "chacha20-poly1305-channel"
2499
+ * - Sealed: "ECDH-ES+A256GCM"
2500
+ *
2501
+ * This helper is centralized to ensure consistent mapping across TS and Python.
2502
+ */
2503
+ function normalizeEncryptionLevelFromAlg(alg) {
2504
+ if (alg === null || alg === undefined) {
2505
+ return "plaintext";
2506
+ }
2507
+ const algLower = alg.toLowerCase();
2508
+ // Check for channel encryption (e.g., "chacha20-poly1305-channel")
2509
+ // Must check before other patterns since channel suffix is explicit
2510
+ if (algLower.includes("-channel")) {
2511
+ return "channel";
2512
+ }
2513
+ // Check for explicit sealed marker
2514
+ if (algLower.includes("-sealed")) {
2515
+ return "sealed";
2516
+ }
2517
+ // ECDH-ES key agreement with AEAD cipher => sealed encryption
2518
+ // Pattern: "ECDH-ES+A256GCM", "ECDH-ES+A128GCM", etc.
2519
+ if (algLower.startsWith("ecdh-es") && algLower.includes("+a")) {
2520
+ return "sealed";
2521
+ }
2522
+ return "unknown";
2523
+ }
2524
+ /**
2525
+ * Creates security bindings from an envelope's sec header.
2526
+ * Exposes only metadata, never raw values like sig.val or enc.val.
2527
+ */
2528
+ function createSecurityBindings(sec) {
2529
+ const sigPresent = sec?.sig !== undefined;
2530
+ const encPresent = sec?.enc !== undefined;
2531
+ return {
2532
+ sig: {
2533
+ present: sigPresent,
2534
+ kid: sec?.sig?.kid ?? null,
2535
+ },
2536
+ enc: {
2537
+ present: encPresent,
2538
+ alg: sec?.enc?.alg ?? null,
2539
+ kid: sec?.enc?.kid ?? null,
2540
+ level: encPresent
2541
+ ? normalizeEncryptionLevelFromAlg(sec?.enc?.alg ?? null)
2542
+ : "plaintext",
2543
+ },
2544
+ };
2545
+ }
2464
2546
  /**
2465
2547
  * Checks if a value is null.
2466
2548
  */
@@ -2469,9 +2551,21 @@ function isNull(value) {
2469
2551
  }
2470
2552
  /**
2471
2553
  * Creates a function registry with auth helpers installed.
2554
+ *
2555
+ * This registry extends the base builtins with:
2556
+ * - Scope builtins: has_scope, has_any_scope, has_all_scopes
2557
+ * - Security builtins: is_signed, encryption_level, is_encrypted, is_encrypted_at_least
2472
2558
  */
2473
- function createAuthFunctionRegistry(grantedScopes = []) {
2474
- const scopes = grantedScopes ?? [];
2559
+ function createAuthFunctionRegistry(grantedScopesOrOptions = []) {
2560
+ // Handle both old signature (array) and new signature (options object)
2561
+ const options = Array.isArray(grantedScopesOrOptions)
2562
+ ? { grantedScopes: grantedScopesOrOptions }
2563
+ : grantedScopesOrOptions;
2564
+ const scopes = options.grantedScopes ?? [];
2565
+ const secBindings = options.securityBindings ?? {
2566
+ sig: { present: false},
2567
+ enc: { level: "plaintext" },
2568
+ };
2475
2569
  /**
2476
2570
  * Checks if any granted scope matches a pattern (using glob syntax).
2477
2571
  */
@@ -2527,11 +2621,85 @@ function createAuthFunctionRegistry(grantedScopes = []) {
2527
2621
  }
2528
2622
  return values.every((scope) => matchesScope(scope));
2529
2623
  };
2624
+ // ============================================================
2625
+ // Security posture builtins
2626
+ // ============================================================
2627
+ /**
2628
+ * is_signed() -> bool
2629
+ *
2630
+ * Returns true if the envelope has a signature present.
2631
+ * No arguments required.
2632
+ */
2633
+ const is_signed = (args) => {
2634
+ assertArgCount(args, 0, "is_signed");
2635
+ return secBindings.sig.present;
2636
+ };
2637
+ /**
2638
+ * encryption_level() -> string
2639
+ *
2640
+ * Returns the normalized encryption level: "plaintext" | "channel" | "sealed" | "unknown"
2641
+ * No arguments required.
2642
+ */
2643
+ const encryption_level = (args) => {
2644
+ assertArgCount(args, 0, "encryption_level");
2645
+ return secBindings.enc.level;
2646
+ };
2647
+ /**
2648
+ * is_encrypted() -> bool
2649
+ *
2650
+ * Returns true if the encryption level is not "plaintext".
2651
+ * This means the envelope has some form of encryption (channel, sealed, or unknown).
2652
+ * No arguments required.
2653
+ */
2654
+ const is_encrypted = (args) => {
2655
+ assertArgCount(args, 0, "is_encrypted");
2656
+ return secBindings.enc.level !== "plaintext";
2657
+ };
2658
+ /**
2659
+ * is_encrypted_at_least(level: string) -> bool
2660
+ *
2661
+ * Returns true if the envelope's encryption level meets or exceeds the required level.
2662
+ *
2663
+ * Level ordering: plaintext < channel < sealed
2664
+ *
2665
+ * Special handling:
2666
+ * - "unknown" encryption level does NOT satisfy "channel" or "sealed" (conservative)
2667
+ * - "plaintext" is always satisfied (any envelope meets at least plaintext)
2668
+ * - null argument => false (predicate-style)
2669
+ * - invalid level string => BuiltinError
2670
+ */
2671
+ const is_encrypted_at_least = (args) => {
2672
+ assertArgCount(args, 1, "is_encrypted_at_least");
2673
+ const requiredLevel = getArg(args, 0, "is_encrypted_at_least");
2674
+ // Null-tolerant: return false if level is null
2675
+ if (!assertStringOrNull(requiredLevel, "level", "is_encrypted_at_least")) {
2676
+ return false;
2677
+ }
2678
+ // Validate required level
2679
+ if (!VALID_ENCRYPTION_LEVELS.includes(requiredLevel)) {
2680
+ throw new BuiltinError("is_encrypted_at_least", `level must be one of: ${VALID_ENCRYPTION_LEVELS.join(", ")}; got "${requiredLevel}"`);
2681
+ }
2682
+ const currentLevel = secBindings.enc.level;
2683
+ const requiredOrder = ENCRYPTION_LEVEL_ORDER[requiredLevel] ?? 0;
2684
+ const currentOrder = ENCRYPTION_LEVEL_ORDER[currentLevel];
2685
+ // If current level is "unknown", it only satisfies "plaintext"
2686
+ if (currentOrder === undefined) {
2687
+ // "unknown" is treated as NOT meeting channel/sealed requirements
2688
+ return requiredOrder === 0; // Only plaintext is satisfied by unknown
2689
+ }
2690
+ return currentOrder >= requiredOrder;
2691
+ };
2530
2692
  return new Map([
2531
2693
  ...BUILTIN_FUNCTIONS,
2694
+ // Scope builtins
2532
2695
  ["has_scope", has_scope],
2533
2696
  ["has_any_scope", has_any_scope],
2534
2697
  ["has_all_scopes", has_all_scopes],
2698
+ // Security posture builtins
2699
+ ["is_signed", is_signed],
2700
+ ["encryption_level", encryption_level],
2701
+ ["is_encrypted", is_encrypted],
2702
+ ["is_encrypted_at_least", is_encrypted_at_least],
2535
2703
  ]);
2536
2704
  }
2537
2705
  /**
@@ -2674,19 +2842,33 @@ function extractClaims(context) {
2674
2842
  }
2675
2843
  /**
2676
2844
  * Creates a safe envelope subset for expression bindings.
2845
+ *
2846
+ * Exposes:
2847
+ * - id, sid, traceId, corrId, flowId, to
2848
+ * - frame: { type }
2849
+ * - sec: { sig: { present, kid }, enc: { present, alg, kid, level } }
2850
+ *
2851
+ * IMPORTANT: Does NOT expose raw security values (sig.val, enc.val).
2677
2852
  */
2678
2853
  function createEnvelopeBindings(envelope) {
2679
2854
  const frame = envelope.frame;
2680
2855
  const envelopeRecord = envelope;
2856
+ const sec = envelopeRecord.sec;
2857
+ const securityBindings = createSecurityBindings(sec);
2681
2858
  return {
2682
- id: envelope.id ?? null,
2683
- traceId: envelopeRecord.traceId ?? null,
2684
- corrId: envelopeRecord.corrId ?? null,
2685
- flowId: envelopeRecord.flowId ?? null,
2686
- to: extractAddress(envelope) ?? null,
2687
- frame: frame
2688
- ? { type: frame.type ?? null }
2689
- : { type: null },
2859
+ bindings: {
2860
+ id: envelope.id ?? null,
2861
+ sid: envelopeRecord.sid ?? null,
2862
+ traceId: envelopeRecord.traceId ?? null,
2863
+ corrId: envelopeRecord.corrId ?? null,
2864
+ flowId: envelopeRecord.flowId ?? null,
2865
+ to: extractAddress(envelope) ?? null,
2866
+ frame: frame
2867
+ ? { type: frame.type ?? null }
2868
+ : { type: null },
2869
+ sec: securityBindings,
2870
+ },
2871
+ securityBindings,
2690
2872
  };
2691
2873
  }
2692
2874
  /**
@@ -2840,11 +3022,12 @@ class AdvancedAuthorizationPolicy {
2840
3022
  continue;
2841
3023
  }
2842
3024
  if (rule.whenAst) {
2843
- // Lazy initialization of expression bindings
3025
+ // Lazy initialization of expression bindings and security context
2844
3026
  if (!expressionBindings) {
3027
+ const envelopeResult = createEnvelopeBindings(envelope);
2845
3028
  expressionBindings = {
2846
3029
  claims: extractClaims(context),
2847
- envelope: createEnvelopeBindings(envelope),
3030
+ envelope: envelopeResult.bindings,
2848
3031
  delivery: createDeliveryBindings(context, resolvedAction),
2849
3032
  node: createNodeBindings(node),
2850
3033
  time: {
@@ -2852,9 +3035,13 @@ class AdvancedAuthorizationPolicy {
2852
3035
  now_iso: new Date().toISOString(),
2853
3036
  },
2854
3037
  };
3038
+ // Create function registry with security bindings for security builtins
3039
+ functionRegistry = createAuthFunctionRegistry({
3040
+ grantedScopes,
3041
+ securityBindings: envelopeResult.securityBindings,
3042
+ });
2855
3043
  }
2856
- const functions = functionRegistry ?? createAuthFunctionRegistry(grantedScopes);
2857
- functionRegistry = functions;
3044
+ const functions = functionRegistry;
2858
3045
  const evalContext = {
2859
3046
  bindings: expressionBindings,
2860
3047
  limits: this.expressionLimits,
@@ -3203,7 +3390,7 @@ function getModule() {
3203
3390
  }
3204
3391
  return modulePromise;
3205
3392
  }
3206
- function normalizeConfig$5(config) {
3393
+ function normalizeConfig$6(config) {
3207
3394
  if (!config) {
3208
3395
  throw new Error("AdvancedAuthorizationPolicyFactory requires a configuration with a policyDefinition");
3209
3396
  }
@@ -3232,7 +3419,7 @@ function normalizeConfig$5(config) {
3232
3419
  /**
3233
3420
  * Factory metadata for registration.
3234
3421
  */
3235
- const FACTORY_META$e = {
3422
+ const FACTORY_META$f = {
3236
3423
  base: AUTHORIZATION_POLICY_FACTORY_BASE_TYPE,
3237
3424
  key: "AdvancedAuthorizationPolicy",
3238
3425
  };
@@ -3251,7 +3438,7 @@ class AdvancedAuthorizationPolicyFactory extends AuthorizationPolicyFactory {
3251
3438
  * @returns The created authorization policy
3252
3439
  */
3253
3440
  async create(config) {
3254
- const normalized = normalizeConfig$5(config);
3441
+ const normalized = normalizeConfig$6(config);
3255
3442
  const { AdvancedAuthorizationPolicy } = await getModule();
3256
3443
  return new AdvancedAuthorizationPolicy({
3257
3444
  policyDefinition: normalized.policyDefinition,
@@ -3264,10 +3451,493 @@ class AdvancedAuthorizationPolicyFactory extends AuthorizationPolicyFactory {
3264
3451
  var advancedAuthorizationPolicyFactory = /*#__PURE__*/Object.freeze({
3265
3452
  __proto__: null,
3266
3453
  AdvancedAuthorizationPolicyFactory: AdvancedAuthorizationPolicyFactory,
3267
- FACTORY_META: FACTORY_META$e,
3454
+ FACTORY_META: FACTORY_META$f,
3268
3455
  default: AdvancedAuthorizationPolicyFactory
3269
3456
  });
3270
3457
 
3458
+ /**
3459
+ * HTTP-based authorization policy source.
3460
+ *
3461
+ * Loads authorization policies from an HTTP endpoint supporting JSON or YAML.
3462
+ * Supports bearer authentication via TokenProvider and HTTP caching via ETag.
3463
+ *
3464
+ * This is a Node.js-only implementation.
3465
+ *
3466
+ * @packageDocumentation
3467
+ */
3468
+ const logger$h = getLogger("naylence.fame.security.auth.policy.http_authorization_policy_source");
3469
+ function isPlainObject(value) {
3470
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
3471
+ }
3472
+ function parseJson(content) {
3473
+ const parsed = JSON.parse(content);
3474
+ if (!isPlainObject(parsed)) {
3475
+ throw new Error("Parsed JSON policy must be an object");
3476
+ }
3477
+ return parsed;
3478
+ }
3479
+ function parseYamlContent(content) {
3480
+ const parsed = parse$1(content ?? "");
3481
+ if (parsed == null) {
3482
+ return {};
3483
+ }
3484
+ if (!isPlainObject(parsed)) {
3485
+ throw new Error("Parsed YAML policy must be an object");
3486
+ }
3487
+ return parsed;
3488
+ }
3489
+ /**
3490
+ * Detect whether content is JSON or YAML based on Content-Type header.
3491
+ * Falls back to sniffing the content if Content-Type is not definitive.
3492
+ */
3493
+ function detectFormat(contentType, content) {
3494
+ if (contentType) {
3495
+ const lower = contentType.toLowerCase();
3496
+ if (lower.includes("application/json") ||
3497
+ lower.includes("text/json")) {
3498
+ return "json";
3499
+ }
3500
+ if (lower.includes("application/yaml") ||
3501
+ lower.includes("application/x-yaml") ||
3502
+ lower.includes("text/yaml") ||
3503
+ lower.includes("text/x-yaml")) {
3504
+ return "yaml";
3505
+ }
3506
+ }
3507
+ // Sniff by first non-whitespace character
3508
+ const trimmed = content.trimStart();
3509
+ if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
3510
+ return "json";
3511
+ }
3512
+ // Default to YAML
3513
+ return "yaml";
3514
+ }
3515
+ /**
3516
+ * Parse Cache-Control header to extract max-age value.
3517
+ */
3518
+ function parseMaxAge(cacheControl) {
3519
+ if (!cacheControl) {
3520
+ return undefined;
3521
+ }
3522
+ const match = cacheControl.match(/max-age\s*=\s*(\d+)/i);
3523
+ if (match && match[1]) {
3524
+ const seconds = parseInt(match[1], 10);
3525
+ if (Number.isFinite(seconds) && seconds >= 0) {
3526
+ return seconds;
3527
+ }
3528
+ }
3529
+ return undefined;
3530
+ }
3531
+ /**
3532
+ * An authorization policy source that loads policy definitions from an HTTP endpoint.
3533
+ *
3534
+ * Supports JSON and YAML formats, bearer authentication via TokenProvider,
3535
+ * and HTTP caching via ETag and Cache-Control headers.
3536
+ *
3537
+ * This is a Node.js-only implementation that uses fetch.
3538
+ */
3539
+ class HttpAuthorizationPolicySource {
3540
+ constructor(options) {
3541
+ this.cachedState = null;
3542
+ this.inflightFetch = null;
3543
+ if (!options.url || typeof options.url !== "string") {
3544
+ throw new Error("HttpAuthorizationPolicySource requires a valid URL");
3545
+ }
3546
+ this.url = options.url;
3547
+ this.method = options.method ?? "GET";
3548
+ this.timeoutMs = options.timeoutMs ?? 30000;
3549
+ this.headers = { ...options.headers };
3550
+ this.tokenProvider = options.tokenProvider;
3551
+ this.bearerPrefix = options.bearerPrefix ?? "Bearer ";
3552
+ this.policyFactoryConfig = options.policyFactory;
3553
+ this.cacheTtlMs = options.cacheTtlMs ?? 300000; // 5 minutes default
3554
+ }
3555
+ /**
3556
+ * Loads the authorization policy from the configured HTTP endpoint.
3557
+ *
3558
+ * Returns a cached policy if still fresh (based on TTL or cache headers).
3559
+ * Multiple concurrent calls are de-duplicated (single-flight pattern).
3560
+ *
3561
+ * @returns The loaded authorization policy
3562
+ */
3563
+ async loadPolicy() {
3564
+ // Return cached policy if still fresh
3565
+ if (this.cachedState && this.isCacheFresh()) {
3566
+ logger$h.debug("returning_cached_policy", {
3567
+ url: this.url,
3568
+ fetchedAt: this.cachedState.metadata.fetchedAt,
3569
+ expiresAt: this.cachedState.metadata.expiresAt,
3570
+ });
3571
+ return this.cachedState.policy;
3572
+ }
3573
+ // De-duplicate concurrent requests
3574
+ if (this.inflightFetch) {
3575
+ return this.inflightFetch;
3576
+ }
3577
+ this.inflightFetch = this.fetchPolicy(false);
3578
+ try {
3579
+ return await this.inflightFetch;
3580
+ }
3581
+ finally {
3582
+ this.inflightFetch = null;
3583
+ }
3584
+ }
3585
+ /**
3586
+ * Forces a reload of the policy from the HTTP endpoint.
3587
+ *
3588
+ * Bypasses cache freshness checks and always fetches from the server.
3589
+ * If the fetch fails, the existing cached policy is preserved and the error is thrown.
3590
+ *
3591
+ * @returns The reloaded authorization policy
3592
+ */
3593
+ async reloadPolicy() {
3594
+ // Clear inflight to force a new request
3595
+ this.inflightFetch = null;
3596
+ return this.fetchPolicy(true);
3597
+ }
3598
+ /**
3599
+ * Clears the cached policy, forcing a fresh fetch on the next loadPolicy() call.
3600
+ */
3601
+ clearCache() {
3602
+ this.cachedState = null;
3603
+ this.inflightFetch = null;
3604
+ }
3605
+ /**
3606
+ * Returns metadata about the last successful fetch.
3607
+ *
3608
+ * Useful for verification, monitoring, or debugging.
3609
+ */
3610
+ getMetadata() {
3611
+ return this.cachedState?.metadata;
3612
+ }
3613
+ /**
3614
+ * Returns the raw policy definition from the last successful fetch.
3615
+ *
3616
+ * Useful for verification or reprocessing.
3617
+ */
3618
+ getRawDefinition() {
3619
+ return this.cachedState?.rawDefinition;
3620
+ }
3621
+ isCacheFresh() {
3622
+ if (!this.cachedState) {
3623
+ return false;
3624
+ }
3625
+ const now = Date.now();
3626
+ const { expiresAt } = this.cachedState.metadata;
3627
+ if (expiresAt !== undefined) {
3628
+ return now < expiresAt;
3629
+ }
3630
+ // No expiration info, check against default TTL
3631
+ const fetchedAt = this.cachedState.metadata.fetchedAt;
3632
+ return now < fetchedAt + this.cacheTtlMs;
3633
+ }
3634
+ async fetchPolicy(forceRefresh) {
3635
+ logger$h.debug("fetching_policy", {
3636
+ url: this.url,
3637
+ method: this.method,
3638
+ forceRefresh,
3639
+ });
3640
+ const requestHeaders = {
3641
+ Accept: "application/json, application/yaml, text/yaml, */*",
3642
+ ...this.headers,
3643
+ };
3644
+ // Add bearer token if token provider is configured
3645
+ if (this.tokenProvider) {
3646
+ try {
3647
+ const token = await this.tokenProvider.getToken();
3648
+ if (token && token.value) {
3649
+ requestHeaders["Authorization"] = `${this.bearerPrefix}${token.value}`;
3650
+ logger$h.debug("added_bearer_token", { url: this.url });
3651
+ }
3652
+ }
3653
+ catch (error) {
3654
+ logger$h.warning("token_provider_failed", {
3655
+ url: this.url,
3656
+ error: error instanceof Error ? error.message : String(error),
3657
+ });
3658
+ // Continue without token - let the server decide if auth is required
3659
+ }
3660
+ }
3661
+ // Add If-None-Match header for conditional request if we have a cached ETag
3662
+ // and this is not a forced refresh
3663
+ if (!forceRefresh && this.cachedState?.metadata.etag) {
3664
+ requestHeaders["If-None-Match"] = this.cachedState.metadata.etag;
3665
+ }
3666
+ const controller = new AbortController();
3667
+ const timeoutId = setTimeout(() => controller.abort(), this.timeoutMs);
3668
+ try {
3669
+ const response = await fetch(this.url, {
3670
+ method: this.method,
3671
+ headers: requestHeaders,
3672
+ signal: controller.signal,
3673
+ });
3674
+ clearTimeout(timeoutId);
3675
+ // Handle 304 Not Modified - return cached policy
3676
+ if (response.status === 304 && this.cachedState) {
3677
+ logger$h.debug("policy_not_modified", {
3678
+ url: this.url,
3679
+ etag: this.cachedState.metadata.etag,
3680
+ });
3681
+ // Update freshness timestamps
3682
+ const now = Date.now();
3683
+ const cacheControl = response.headers.get("Cache-Control");
3684
+ const maxAgeSeconds = parseMaxAge(cacheControl);
3685
+ const expiresAt = maxAgeSeconds !== undefined
3686
+ ? now + maxAgeSeconds * 1000
3687
+ : now + this.cacheTtlMs;
3688
+ this.cachedState = {
3689
+ ...this.cachedState,
3690
+ metadata: {
3691
+ ...this.cachedState.metadata,
3692
+ fetchedAt: now,
3693
+ maxAgeSeconds,
3694
+ expiresAt,
3695
+ },
3696
+ };
3697
+ return this.cachedState.policy;
3698
+ }
3699
+ if (!response.ok) {
3700
+ const errorMessage = `HTTP ${response.status}: ${response.statusText}`;
3701
+ logger$h.error("policy_fetch_failed", {
3702
+ url: this.url,
3703
+ status: response.status,
3704
+ statusText: response.statusText,
3705
+ });
3706
+ // If we have a cached policy, preserve it and throw
3707
+ if (this.cachedState) {
3708
+ throw new Error(`Failed to fetch policy from ${this.url}: ${errorMessage}. ` +
3709
+ "Using last known good policy.");
3710
+ }
3711
+ throw new Error(`Failed to fetch policy from ${this.url}: ${errorMessage}`);
3712
+ }
3713
+ // Parse the response
3714
+ const contentType = response.headers.get("Content-Type");
3715
+ const content = await response.text();
3716
+ const format = detectFormat(contentType, content);
3717
+ let policyDefinition;
3718
+ try {
3719
+ if (format === "json") {
3720
+ policyDefinition = parseJson(content);
3721
+ }
3722
+ else {
3723
+ policyDefinition = parseYamlContent(content);
3724
+ }
3725
+ }
3726
+ catch (parseError) {
3727
+ const message = parseError instanceof Error
3728
+ ? parseError.message
3729
+ : String(parseError);
3730
+ logger$h.error("policy_parse_failed", {
3731
+ url: this.url,
3732
+ format,
3733
+ error: message,
3734
+ });
3735
+ // Preserve cached policy on parse failure
3736
+ if (this.cachedState) {
3737
+ throw new Error(`Failed to parse policy from ${this.url}: ${message}. ` +
3738
+ "Using last known good policy.");
3739
+ }
3740
+ throw new Error(`Failed to parse policy from ${this.url}: ${message}`);
3741
+ }
3742
+ logger$h.debug("parsed_policy_definition", {
3743
+ url: this.url,
3744
+ format,
3745
+ hasType: "type" in policyDefinition,
3746
+ });
3747
+ // Build the policy using the factory
3748
+ const policy = await this.buildPolicy(policyDefinition);
3749
+ // Update cache
3750
+ const now = Date.now();
3751
+ const etag = response.headers.get("ETag") ?? undefined;
3752
+ const cacheControl = response.headers.get("Cache-Control");
3753
+ const maxAgeSeconds = parseMaxAge(cacheControl);
3754
+ const expiresAt = maxAgeSeconds !== undefined
3755
+ ? now + maxAgeSeconds * 1000
3756
+ : now + this.cacheTtlMs;
3757
+ this.cachedState = {
3758
+ policy,
3759
+ rawDefinition: policyDefinition,
3760
+ metadata: {
3761
+ url: this.url,
3762
+ status: response.status,
3763
+ etag,
3764
+ fetchedAt: now,
3765
+ maxAgeSeconds,
3766
+ expiresAt,
3767
+ },
3768
+ };
3769
+ logger$h.info("loaded_policy_from_http", {
3770
+ url: this.url,
3771
+ status: response.status,
3772
+ format,
3773
+ etag,
3774
+ maxAgeSeconds,
3775
+ });
3776
+ return policy;
3777
+ }
3778
+ catch (error) {
3779
+ clearTimeout(timeoutId);
3780
+ if (error instanceof Error && error.name === "AbortError") {
3781
+ const timeoutError = new Error(`Request to ${this.url} timed out after ${this.timeoutMs}ms`);
3782
+ logger$h.error("policy_fetch_timeout", {
3783
+ url: this.url,
3784
+ timeoutMs: this.timeoutMs,
3785
+ });
3786
+ // Preserve cached policy on timeout
3787
+ if (this.cachedState) {
3788
+ throw timeoutError;
3789
+ }
3790
+ throw timeoutError;
3791
+ }
3792
+ throw error;
3793
+ }
3794
+ }
3795
+ async buildPolicy(policyDefinition) {
3796
+ // Determine the factory configuration to use
3797
+ const factoryConfig = this.policyFactoryConfig ?? policyDefinition;
3798
+ // Ensure we have a type field for the factory
3799
+ if (!("type" in factoryConfig) || typeof factoryConfig.type !== "string") {
3800
+ logger$h.warning("policy_type_missing_defaulting_to_basic", {
3801
+ url: this.url,
3802
+ });
3803
+ factoryConfig.type = "BasicAuthorizationPolicy";
3804
+ }
3805
+ // Build the factory config with the policy definition
3806
+ // The response content IS the policy definition, so we extract the type
3807
+ // and wrap the remaining content as the policyDefinition
3808
+ const { type: definitionType, ...restOfDefinition } = policyDefinition;
3809
+ const resolvedType = typeof definitionType === "string" && definitionType.trim().length > 0
3810
+ ? definitionType
3811
+ : factoryConfig.type;
3812
+ const mergedConfig = this.policyFactoryConfig != null
3813
+ ? { ...this.policyFactoryConfig, policyDefinition }
3814
+ : { type: resolvedType, policyDefinition: restOfDefinition };
3815
+ const policy = await AuthorizationPolicyFactory.createAuthorizationPolicy(mergedConfig);
3816
+ if (!policy) {
3817
+ throw new Error(`Failed to create authorization policy from ${this.url}`);
3818
+ }
3819
+ return policy;
3820
+ }
3821
+ }
3822
+
3823
+ var httpAuthorizationPolicySource = /*#__PURE__*/Object.freeze({
3824
+ __proto__: null,
3825
+ HttpAuthorizationPolicySource: HttpAuthorizationPolicySource
3826
+ });
3827
+
3828
+ /**
3829
+ * Factory for creating HttpAuthorizationPolicySource instances.
3830
+ *
3831
+ * @packageDocumentation
3832
+ */
3833
+ let httpModulePromise = null;
3834
+ async function getHttpModule() {
3835
+ if (!httpModulePromise) {
3836
+ httpModulePromise = Promise.resolve().then(function () { return httpAuthorizationPolicySource; });
3837
+ }
3838
+ return httpModulePromise;
3839
+ }
3840
+ function normalizeConfig$5(config) {
3841
+ if (!config) {
3842
+ throw new Error("HttpAuthorizationPolicySourceFactory requires a configuration with a url");
3843
+ }
3844
+ const candidate = config;
3845
+ const url = candidate.url;
3846
+ if (typeof url !== "string" || url.trim().length === 0) {
3847
+ throw new Error("HttpAuthorizationPolicySourceConfig requires a non-empty url");
3848
+ }
3849
+ // Support both camelCase and snake_case
3850
+ const method = candidate.method ?? "GET";
3851
+ if (!["GET", "POST", "PUT"].includes(method)) {
3852
+ throw new Error(`Invalid method "${String(method)}". Must be "GET", "POST", or "PUT"`);
3853
+ }
3854
+ const timeoutMs = candidate.timeout_ms ??
3855
+ candidate.timeoutMs ??
3856
+ 30000;
3857
+ if (typeof timeoutMs !== "number" || !Number.isFinite(timeoutMs) || timeoutMs <= 0) {
3858
+ throw new Error("timeout_ms must be a positive number");
3859
+ }
3860
+ const headers = candidate.headers;
3861
+ if (headers !== undefined && typeof headers !== "object") {
3862
+ throw new Error("headers must be an object");
3863
+ }
3864
+ const tokenProviderConfig = candidate.token_provider ??
3865
+ candidate.tokenProvider;
3866
+ const bearerPrefix = candidate.bearer_prefix ??
3867
+ candidate.bearerPrefix ??
3868
+ "Bearer ";
3869
+ const policyFactory = candidate.policy_factory ??
3870
+ candidate.policyFactory;
3871
+ const cacheTtlMs = candidate.cache_ttl_ms ??
3872
+ candidate.cacheTtlMs ??
3873
+ 300000;
3874
+ if (typeof cacheTtlMs !== "number" || !Number.isFinite(cacheTtlMs) || cacheTtlMs < 0) {
3875
+ throw new Error("cache_ttl_ms must be a non-negative number");
3876
+ }
3877
+ return {
3878
+ url: url.trim(),
3879
+ method,
3880
+ timeoutMs,
3881
+ headers,
3882
+ tokenProviderConfig,
3883
+ bearerPrefix,
3884
+ policyFactory,
3885
+ cacheTtlMs,
3886
+ };
3887
+ }
3888
+ /**
3889
+ * Factory metadata for registration.
3890
+ */
3891
+ const FACTORY_META$e = {
3892
+ base: AUTHORIZATION_POLICY_SOURCE_FACTORY_BASE_TYPE,
3893
+ key: "HttpAuthorizationPolicySource",
3894
+ };
3895
+ /**
3896
+ * Factory for creating HttpAuthorizationPolicySource instances.
3897
+ *
3898
+ * This factory uses lazy loading to avoid pulling in Node.js-specific
3899
+ * code (fetch operations) in browser environments where it may not work.
3900
+ */
3901
+ class HttpAuthorizationPolicySourceFactory extends AuthorizationPolicySourceFactory {
3902
+ constructor() {
3903
+ super(...arguments);
3904
+ this.type = "HttpAuthorizationPolicySource";
3905
+ }
3906
+ /**
3907
+ * Creates an HttpAuthorizationPolicySource from the given configuration.
3908
+ *
3909
+ * @param config - Configuration specifying the policy URL and options
3910
+ * @returns The created policy source
3911
+ */
3912
+ async create(config) {
3913
+ const normalized = normalizeConfig$5(config);
3914
+ // Create token provider if configured
3915
+ let tokenProvider;
3916
+ if (normalized.tokenProviderConfig) {
3917
+ tokenProvider = await TokenProviderFactory.createTokenProvider(normalized.tokenProviderConfig);
3918
+ }
3919
+ const { HttpAuthorizationPolicySource } = await getHttpModule();
3920
+ const options = {
3921
+ url: normalized.url,
3922
+ method: normalized.method,
3923
+ timeoutMs: normalized.timeoutMs,
3924
+ headers: normalized.headers,
3925
+ tokenProvider,
3926
+ bearerPrefix: normalized.bearerPrefix,
3927
+ policyFactory: normalized.policyFactory,
3928
+ cacheTtlMs: normalized.cacheTtlMs,
3929
+ };
3930
+ return new HttpAuthorizationPolicySource(options);
3931
+ }
3932
+ }
3933
+
3934
+ var httpAuthorizationPolicySourceFactory = /*#__PURE__*/Object.freeze({
3935
+ __proto__: null,
3936
+ FACTORY_META: FACTORY_META$e,
3937
+ HttpAuthorizationPolicySourceFactory: HttpAuthorizationPolicySourceFactory,
3938
+ default: HttpAuthorizationPolicySourceFactory
3939
+ });
3940
+
3271
3941
  const logger$g = getLogger("naylence.fame.security.cert.util");
3272
3942
  const CACHE_LIMIT = 512;
3273
3943
  const OID_ED25519 = "1.3.101.112";