@naylence/advanced-security 0.3.14 → 0.3.15
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.
- package/dist/browser/index.cjs +1961 -1952
- package/dist/browser/index.mjs +1962 -1953
- package/dist/cjs/browser.js +11 -0
- package/dist/cjs/browser.js.map +1 -1
- package/dist/cjs/node.js +27 -0
- package/dist/cjs/node.js.map +1 -1
- package/dist/cjs/version.js +2 -2
- package/dist/esm/browser.js +11 -0
- package/dist/esm/browser.js.map +1 -1
- package/dist/esm/node.js +27 -0
- package/dist/esm/node.js.map +1 -1
- package/dist/esm/version.js +2 -2
- package/dist/node/index.cjs +2 -2
- package/dist/node/index.mjs +2 -2
- package/dist/node/node.cjs +2009 -1983
- package/dist/node/node.mjs +2011 -1985
- package/dist/types/browser.d.ts.map +1 -1
- package/dist/types/node.d.ts.map +1 -1
- package/dist/types/version.d.ts +1 -1
- package/package.json +2 -2
package/dist/node/node.mjs
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { ExtensionManager, Registry, AbstractResourceFactory, createResource, createDefaultResource } from '@naylence/factory';
|
|
2
|
+
import { getLogger, ENCRYPTION_MANAGER_FACTORY_BASE_TYPE, 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 as TrustStoreProviderFactory$1, 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, formatTimestamp, AnsiColor, jsonDumps, validateHostLogicals, HTTP_CONNECTION_GRANT_TYPE, WELCOME_SERVICE_FACTORY_BASE_TYPE, WelcomeServiceFactory, NodePlacementStrategyFactory, TransportProvisionerFactory, TokenIssuerFactory, AuthorizerFactory, AuthInjectionStrategyFactory, CERTIFICATE_MANAGER_FACTORY_BASE_TYPE, CertificateManagerFactory, TRUST_STORE_PROVIDER_FACTORY_BASE_TYPE as TRUST_STORE_PROVIDER_FACTORY_BASE_TYPE$1, validateHostLogical } from '@naylence/runtime';
|
|
1
3
|
import { AsnConvert, OctetString } from '@peculiar/asn1-schema';
|
|
2
4
|
import { Certificate, id_ce_subjectAltName, SubjectAlternativeName, id_ce_nameConstraints, NameConstraints, Name, RelativeDistinguishedName, AttributeTypeAndValue, AttributeValue, SubjectPublicKeyInfo, GeneralName, Extensions, Extension, Attribute, AlgorithmIdentifier, TBSCertificate, Validity, Version, BasicConstraints, id_ce_basicConstraints, KeyUsageFlags, KeyUsage, id_ce_keyUsage, SubjectKeyIdentifier, id_ce_subjectKeyIdentifier, AuthorityKeyIdentifier, KeyIdentifier, id_ce_authorityKeyIdentifier, GeneralSubtrees, GeneralSubtree, ExtendedKeyUsage, id_kp_clientAuth, id_kp_serverAuth, id_ce_extKeyUsage } from '@peculiar/asn1-x509';
|
|
3
5
|
import { sha512, sha256 } from '@noble/hashes/sha2.js';
|
|
4
6
|
import { verify, etc } from '@noble/ed25519';
|
|
5
|
-
import { getLogger, EncryptionResult, urlsafeBase64Decode, sealedDecrypt, sealedEncrypt, FIXED_PREFIX_LEN, urlsafeBase64Encode, ENCRYPTION_MANAGER_FACTORY_BASE_TYPE, 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 as TrustStoreProviderFactory$1, 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, formatTimestamp, AnsiColor, jsonDumps, validateHostLogicals, HTTP_CONNECTION_GRANT_TYPE, WELCOME_SERVICE_FACTORY_BASE_TYPE, WelcomeServiceFactory, NodePlacementStrategyFactory, TransportProvisionerFactory, TokenIssuerFactory, AuthorizerFactory, AuthInjectionStrategyFactory, CERTIFICATE_MANAGER_FACTORY_BASE_TYPE, CertificateManagerFactory, TRUST_STORE_PROVIDER_FACTORY_BASE_TYPE as TRUST_STORE_PROVIDER_FACTORY_BASE_TYPE$1, validateHostLogical } from '@naylence/runtime';
|
|
6
7
|
import { Attributes, CertificationRequestInfo, CertificationRequest } from '@peculiar/asn1-csr';
|
|
7
8
|
import { X509Certificate } from '@peculiar/x509';
|
|
8
9
|
import { localDeliveryContext, createFameEnvelope, FameAddress, generateId, formatAddress, SigningMaterial, DeliveryOriginType as DeliveryOriginType$1 } from '@naylence/core';
|
|
@@ -11,603 +12,1130 @@ import { x25519 } from '@noble/curves/ed25519.js';
|
|
|
11
12
|
import { hkdf } from '@noble/hashes/hkdf.js';
|
|
12
13
|
import { utf8ToBytes, randomBytes as randomBytes$1 } from '@noble/hashes/utils.js';
|
|
13
14
|
import { SignJWT, importPKCS8, compactVerify, importJWK, importSPKI } from 'jose';
|
|
14
|
-
import { ExtensionManager, Registry, AbstractResourceFactory, createResource, createDefaultResource } from '@naylence/factory';
|
|
15
15
|
import { sha256 as sha256$1 } from '@noble/hashes/sha256.js';
|
|
16
16
|
|
|
17
|
-
// This file is auto-generated during build - do not edit manually
|
|
18
|
-
// Generated from package.json version: 0.3.14
|
|
19
17
|
/**
|
|
20
|
-
*
|
|
21
|
-
*
|
|
18
|
+
* AUTO-GENERATED FILE. DO NOT EDIT DIRECTLY.
|
|
19
|
+
* Generated by scripts/generate-factory-manifest.mjs
|
|
20
|
+
*
|
|
21
|
+
* Provides the list of advanced security factory modules for registration.
|
|
22
22
|
*/
|
|
23
|
-
const
|
|
23
|
+
const MODULES = [
|
|
24
|
+
"./security/cert/default-ca-service-factory.js",
|
|
25
|
+
"./security/cert/default-certificate-manager-factory.js",
|
|
26
|
+
"./security/cert/trust-store/browser-trust-store-provider-factory.js",
|
|
27
|
+
"./security/cert/trust-store/node-trust-store-provider-factory.js",
|
|
28
|
+
"./security/encryption/channel/channel-encryption-manager-factory.js",
|
|
29
|
+
"./security/encryption/composite-encryption-manager-factory.js",
|
|
30
|
+
"./security/encryption/default-secure-channel-manager-factory.js",
|
|
31
|
+
"./security/encryption/sealed/x25519-encryption-manager-factory.js",
|
|
32
|
+
"./security/keys/x5c-key-manager-factory.js",
|
|
33
|
+
"./security/signing/eddsa-envelope-signer-factory.js",
|
|
34
|
+
"./security/signing/eddsa-envelope-verifier-factory.js",
|
|
35
|
+
"./stickiness/aft-load-balancer-stickiness-manager-factory.js",
|
|
36
|
+
"./stickiness/aft-replica-stickiness-manager-factory.js",
|
|
37
|
+
"./welcome/advanced-welcome-service-factory.js"
|
|
38
|
+
];
|
|
39
|
+
const MODULE_LOADERS = {
|
|
40
|
+
"./security/cert/default-ca-service-factory.js": () => Promise.resolve().then(function () { return defaultCaServiceFactory; }),
|
|
41
|
+
"./security/cert/default-certificate-manager-factory.js": () => Promise.resolve().then(function () { return defaultCertificateManagerFactory; }),
|
|
42
|
+
"./security/cert/trust-store/browser-trust-store-provider-factory.js": () => Promise.resolve().then(function () { return browserTrustStoreProviderFactory; }),
|
|
43
|
+
"./security/cert/trust-store/node-trust-store-provider-factory.js": () => Promise.resolve().then(function () { return nodeTrustStoreProviderFactory; }),
|
|
44
|
+
"./security/encryption/channel/channel-encryption-manager-factory.js": () => Promise.resolve().then(function () { return channelEncryptionManagerFactory; }),
|
|
45
|
+
"./security/encryption/composite-encryption-manager-factory.js": () => Promise.resolve().then(function () { return compositeEncryptionManagerFactory; }),
|
|
46
|
+
"./security/encryption/default-secure-channel-manager-factory.js": () => Promise.resolve().then(function () { return defaultSecureChannelManagerFactory; }),
|
|
47
|
+
"./security/encryption/sealed/x25519-encryption-manager-factory.js": () => Promise.resolve().then(function () { return x25519EncryptionManagerFactory; }),
|
|
48
|
+
"./security/keys/x5c-key-manager-factory.js": () => Promise.resolve().then(function () { return x5cKeyManagerFactory; }),
|
|
49
|
+
"./security/signing/eddsa-envelope-signer-factory.js": () => Promise.resolve().then(function () { return eddsaEnvelopeSignerFactory; }),
|
|
50
|
+
"./security/signing/eddsa-envelope-verifier-factory.js": () => Promise.resolve().then(function () { return eddsaEnvelopeVerifierFactory; }),
|
|
51
|
+
"./stickiness/aft-load-balancer-stickiness-manager-factory.js": () => Promise.resolve().then(function () { return aftLoadBalancerStickinessManagerFactory; }),
|
|
52
|
+
"./stickiness/aft-replica-stickiness-manager-factory.js": () => Promise.resolve().then(function () { return aftReplicaStickinessManagerFactory; }),
|
|
53
|
+
"./welcome/advanced-welcome-service-factory.js": () => Promise.resolve().then(function () { return advancedWelcomeServiceFactory; }),
|
|
54
|
+
};
|
|
24
55
|
|
|
25
|
-
const logger$h = getLogger("naylence.fame.security.
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
56
|
+
const logger$h = getLogger("naylence.fame.security.encryption.encryption_manager_registry");
|
|
57
|
+
class EncryptionManagerFactoryRegistry {
|
|
58
|
+
constructor(autoDiscover = true) {
|
|
59
|
+
this.factories = [];
|
|
60
|
+
this.algorithmToFactory = new Map();
|
|
61
|
+
this.typeToFactories = new Map();
|
|
62
|
+
this.factorySet = new Set();
|
|
63
|
+
this.autoDiscoveredFactories = new Set();
|
|
64
|
+
this.autoDiscovered = false;
|
|
65
|
+
if (autoDiscover) {
|
|
66
|
+
this.autoDiscoverFactories();
|
|
67
|
+
}
|
|
33
68
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
69
|
+
autoDiscoverFactories() {
|
|
70
|
+
if (this.autoDiscovered) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
try {
|
|
74
|
+
const extensionInfos = ExtensionManager.getExtensionsByType(ENCRYPTION_MANAGER_FACTORY_BASE_TYPE);
|
|
75
|
+
let registeredCount = 0;
|
|
76
|
+
for (const [factoryName, info] of extensionInfos) {
|
|
77
|
+
if (factoryName === "CompositeEncryptionManager") {
|
|
78
|
+
logger$h.debug("skipping_composite_factory_to_avoid_circular_dependency", {
|
|
79
|
+
factory_name: factoryName,
|
|
80
|
+
});
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
const factoryInstance = (info.instance ??
|
|
85
|
+
ExtensionManager.getGlobalFactory(ENCRYPTION_MANAGER_FACTORY_BASE_TYPE, factoryName));
|
|
86
|
+
this.registerFactory(factoryInstance, { autoDiscovered: true });
|
|
87
|
+
registeredCount += 1;
|
|
88
|
+
logger$h.debug("auto_discovered_factory", {
|
|
89
|
+
factory_name: factoryName,
|
|
90
|
+
factory_class: factoryInstance.constructor.name,
|
|
91
|
+
algorithms: factoryInstance.getSupportedAlgorithms(),
|
|
92
|
+
encryption_type: factoryInstance.getEncryptionType(),
|
|
93
|
+
priority: factoryInstance.getPriority(),
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
logger$h.warning("failed_to_auto_register_factory", {
|
|
98
|
+
factory_name: factoryName,
|
|
99
|
+
error: error instanceof Error ? error.message : String(error),
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
this.autoDiscovered = true;
|
|
104
|
+
logger$h.debug("completed_auto_discovery", {
|
|
105
|
+
registered_factories: registeredCount,
|
|
106
|
+
total_discovered: extensionInfos.size,
|
|
107
|
+
skipped_composite: true,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
logger$h.warning("failed_auto_discovery_of_factories", {
|
|
112
|
+
error: error instanceof Error ? error.message : String(error),
|
|
54
113
|
});
|
|
55
|
-
return cached;
|
|
56
114
|
}
|
|
57
|
-
logger$h.debug("certificate_cache_miss", {
|
|
58
|
-
call_id: callId,
|
|
59
|
-
cache_key: cacheKey,
|
|
60
|
-
});
|
|
61
115
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
116
|
+
registerFactory(factory, options = {}) {
|
|
117
|
+
if (this.factorySet.has(factory)) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
this.factorySet.add(factory);
|
|
121
|
+
this.factories.push(factory);
|
|
122
|
+
if (options.autoDiscovered) {
|
|
123
|
+
this.autoDiscoveredFactories.add(factory);
|
|
124
|
+
}
|
|
125
|
+
for (const algorithm of factory.getSupportedAlgorithms()) {
|
|
126
|
+
const existing = this.algorithmToFactory.get(algorithm);
|
|
127
|
+
if (!existing || factory.getPriority() > existing.getPriority()) {
|
|
128
|
+
this.algorithmToFactory.set(algorithm, factory);
|
|
129
|
+
logger$h.debug("registered_algorithm_mapping", {
|
|
130
|
+
algorithm,
|
|
131
|
+
factory: factory.constructor.name,
|
|
132
|
+
priority: factory.getPriority(),
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
const encryptionType = factory.getEncryptionType();
|
|
137
|
+
const typeFactories = this.typeToFactories.get(encryptionType) ?? [];
|
|
138
|
+
typeFactories.push(factory);
|
|
139
|
+
typeFactories.sort((a, b) => b.getPriority() - a.getPriority());
|
|
140
|
+
this.typeToFactories.set(encryptionType, typeFactories);
|
|
141
|
+
logger$h.debug("registered_encryption_manager_factory", {
|
|
142
|
+
factory: factory.constructor.name,
|
|
143
|
+
encryption_type: encryptionType,
|
|
144
|
+
algorithms: factory.getSupportedAlgorithms(),
|
|
145
|
+
priority: factory.getPriority(),
|
|
146
|
+
auto_discovered: options.autoDiscovered ?? false,
|
|
147
|
+
});
|
|
65
148
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
certificate: validation.certificate,
|
|
70
|
-
};
|
|
149
|
+
getFactoryForAlgorithm(algorithm) {
|
|
150
|
+
this.ensureAutoDiscovery();
|
|
151
|
+
return this.algorithmToFactory.get(algorithm);
|
|
71
152
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
153
|
+
getFactoryForOptions(opts) {
|
|
154
|
+
this.ensureAutoDiscovery();
|
|
155
|
+
for (const factory of this.factories) {
|
|
156
|
+
if (factory.supportsOptions(opts ?? undefined)) {
|
|
157
|
+
logger$h.debug("found_factory_for_options", {
|
|
158
|
+
factory: factory.constructor.name,
|
|
159
|
+
encryption_type: factory.getEncryptionType(),
|
|
160
|
+
});
|
|
161
|
+
return factory;
|
|
162
|
+
}
|
|
80
163
|
}
|
|
81
|
-
|
|
164
|
+
logger$h.debug("no_factory_found_for_options", { opts });
|
|
165
|
+
return undefined;
|
|
82
166
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
return
|
|
167
|
+
getFactoriesByType(encryptionType) {
|
|
168
|
+
this.ensureAutoDiscovery();
|
|
169
|
+
return this.typeToFactories.get(encryptionType) ?? [];
|
|
86
170
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
const error = "Invalid x5c field in JWK";
|
|
91
|
-
if (strict) {
|
|
92
|
-
throw new Error(error);
|
|
93
|
-
}
|
|
94
|
-
return { isValid: false, error };
|
|
171
|
+
getAllSupportedAlgorithms() {
|
|
172
|
+
this.ensureAutoDiscovery();
|
|
173
|
+
return Array.from(this.algorithmToFactory.keys());
|
|
95
174
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
175
|
+
getRegistryInfo() {
|
|
176
|
+
return {
|
|
177
|
+
totalFactories: this.factories.length,
|
|
178
|
+
autoDiscovered: this.autoDiscovered,
|
|
179
|
+
algorithmMappings: Object.fromEntries(Array.from(this.algorithmToFactory.entries()).map(([algorithm, factory]) => [algorithm, factory.constructor.name])),
|
|
180
|
+
typeMappings: Object.fromEntries(Array.from(this.typeToFactories.entries()).map(([encType, factories]) => [
|
|
181
|
+
encType,
|
|
182
|
+
factories.map((factory) => factory.constructor.name),
|
|
183
|
+
])),
|
|
184
|
+
};
|
|
102
185
|
}
|
|
103
|
-
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
186
|
+
forceRediscovery() {
|
|
187
|
+
const manualFactories = this.factories.filter((factory) => !this.autoDiscoveredFactories.has(factory));
|
|
188
|
+
this.autoDiscovered = false;
|
|
189
|
+
this.algorithmToFactory.clear();
|
|
190
|
+
this.typeToFactories.clear();
|
|
191
|
+
this.factories.length = 0;
|
|
192
|
+
this.factorySet.clear();
|
|
193
|
+
this.autoDiscoveredFactories.clear();
|
|
194
|
+
for (const factory of manualFactories) {
|
|
195
|
+
this.registerFactory(factory);
|
|
108
196
|
}
|
|
109
|
-
|
|
197
|
+
this.autoDiscoverFactories();
|
|
110
198
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
const leaf = parsed[0];
|
|
114
|
-
const nowMs = Date.now();
|
|
115
|
-
const notBefore = leaf.certificate.tbsCertificate.validity.notBefore.getTime();
|
|
116
|
-
const notAfter = leaf.certificate.tbsCertificate.validity.notAfter.getTime();
|
|
117
|
-
const notBeforeMs = notBefore.getTime();
|
|
118
|
-
const notAfterMs = notAfter.getTime();
|
|
119
|
-
if (nowMs < notBeforeMs || nowMs > notAfterMs) {
|
|
120
|
-
throw new Error(`Certificate is not currently valid (notBefore: ${notBefore.toISOString()}, notAfter: ${notAfter.toISOString()}, now: ${new Date(nowMs).toISOString()})`);
|
|
199
|
+
isAutoDiscovered() {
|
|
200
|
+
return this.autoDiscovered;
|
|
121
201
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
const leafUris = extractUrisFromCert(leaf.certificate);
|
|
125
|
-
validateNameConstraints(issuers, leafUris);
|
|
202
|
+
ensureInitialized() {
|
|
203
|
+
this.ensureAutoDiscovery();
|
|
126
204
|
}
|
|
127
|
-
|
|
128
|
-
|
|
205
|
+
ensureAutoDiscovery() {
|
|
206
|
+
if (!this.autoDiscovered) {
|
|
207
|
+
this.autoDiscoverFactories();
|
|
208
|
+
}
|
|
129
209
|
}
|
|
130
|
-
validateChainContinuity(parsed);
|
|
131
|
-
const publicKey = leaf.subjectPublicKey.slice();
|
|
132
|
-
return {
|
|
133
|
-
publicKey,
|
|
134
|
-
certificate: leaf.certificate,
|
|
135
|
-
notAfter,
|
|
136
|
-
};
|
|
137
210
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
211
|
+
const globalRegistry = new EncryptionManagerFactoryRegistry(true);
|
|
212
|
+
function getEncryptionManagerFactoryRegistry() {
|
|
213
|
+
globalRegistry.ensureInitialized();
|
|
214
|
+
return globalRegistry;
|
|
215
|
+
}
|
|
216
|
+
function registerEncryptionManagerFactory(factory) {
|
|
217
|
+
globalRegistry.registerFactory(factory);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const SECURITY_PREFIX = "./security/";
|
|
221
|
+
const SECURITY_MODULES = MODULES.filter((spec) => spec.startsWith(SECURITY_PREFIX));
|
|
222
|
+
const EXTRA_MODULES = MODULES.filter((spec) => !spec.startsWith(SECURITY_PREFIX));
|
|
223
|
+
const NODE_ONLY_MODULES = new Set([
|
|
224
|
+
"./security/cert/default-ca-service-factory.js",
|
|
225
|
+
"./security/cert/trust-store/node-trust-store-provider-factory.js",
|
|
226
|
+
]);
|
|
227
|
+
const FACTORY_MODULE_PREFIX$1 = "@naylence/advanced-security/naylence/fame/";
|
|
228
|
+
const BROWSER_DIST_SEGMENT = "/dist/browser/";
|
|
229
|
+
function detectModuleUrl() {
|
|
230
|
+
if (typeof __filename === "string") {
|
|
155
231
|
try {
|
|
156
|
-
|
|
232
|
+
return __filename.startsWith("file://")
|
|
233
|
+
? __filename
|
|
234
|
+
: `file://${__filename}`;
|
|
157
235
|
}
|
|
158
|
-
catch
|
|
159
|
-
|
|
160
|
-
throw new Error(`Failed to parse certificate at index ${index}: ${reason}`);
|
|
236
|
+
catch {
|
|
237
|
+
// fall through to stack parsing
|
|
161
238
|
}
|
|
162
|
-
parsed.push(createParsedCertificate(certificate, der));
|
|
163
|
-
derChunks.push(der);
|
|
164
|
-
}
|
|
165
|
-
return { parsed, chainBytes: concatBytes(derChunks) };
|
|
166
|
-
}
|
|
167
|
-
function createParsedCertificate(certificate, raw) {
|
|
168
|
-
return {
|
|
169
|
-
raw,
|
|
170
|
-
certificate,
|
|
171
|
-
serialNumber: toHex(new Uint8Array(certificate.tbsCertificate.serialNumber)).toUpperCase(),
|
|
172
|
-
subjectName: serializeName(certificate.tbsCertificate.subject),
|
|
173
|
-
issuerName: serializeName(certificate.tbsCertificate.issuer),
|
|
174
|
-
subjectPublicKey: new Uint8Array(certificate.tbsCertificate.subjectPublicKeyInfo.subjectPublicKey).slice(),
|
|
175
|
-
};
|
|
176
|
-
}
|
|
177
|
-
function extractUrisFromCert(cert) {
|
|
178
|
-
const extension = findExtension(cert, id_ce_subjectAltName);
|
|
179
|
-
if (!extension) {
|
|
180
|
-
return [];
|
|
181
239
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
for (const generalName of subjectAlternativeName) {
|
|
185
|
-
if (generalName.uniformResourceIdentifier) {
|
|
186
|
-
uris.push(generalName.uniformResourceIdentifier);
|
|
187
|
-
}
|
|
240
|
+
try {
|
|
241
|
+
throw new Error();
|
|
188
242
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
const
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
for (const uri of leafUris) {
|
|
206
|
-
const allowed = permittedUris.some((prefix) => uri.startsWith(prefix));
|
|
207
|
-
if (!allowed) {
|
|
208
|
-
throw new Error(`URI '${uri}' violates name constraints - not in permitted subtrees: ${permittedUris.join(", ")}`);
|
|
243
|
+
catch (error) {
|
|
244
|
+
const stack = typeof error === "object" && error && "stack" in error
|
|
245
|
+
? String(error.stack ?? "")
|
|
246
|
+
: "";
|
|
247
|
+
const lines = stack.split("\n");
|
|
248
|
+
for (const line of lines) {
|
|
249
|
+
const match = line.match(/(https?:\/\/[^\s)]+|file:\/\/[^\s)]+\.(?:js|ts)|\/(?:[^\s)]+\.(?:js|ts)))/u);
|
|
250
|
+
const candidate = match?.[1];
|
|
251
|
+
if (!candidate) {
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
if (candidate.startsWith("http://") || candidate.startsWith("https://")) {
|
|
255
|
+
return candidate;
|
|
256
|
+
}
|
|
257
|
+
if (candidate.startsWith("file://")) {
|
|
258
|
+
return candidate;
|
|
209
259
|
}
|
|
260
|
+
return `file://${candidate}`;
|
|
210
261
|
}
|
|
211
262
|
}
|
|
263
|
+
return null;
|
|
212
264
|
}
|
|
213
|
-
function
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
if (subtree.base.uniformResourceIdentifier &&
|
|
217
|
-
subtree.base.uniformResourceIdentifier.length > 0) {
|
|
218
|
-
uris.push(subtree.base.uniformResourceIdentifier);
|
|
219
|
-
}
|
|
265
|
+
function computeBrowserFactoryBase(rawUrl) {
|
|
266
|
+
if (!rawUrl) {
|
|
267
|
+
return null;
|
|
220
268
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
throw new Error("No valid certificates found in trust store");
|
|
269
|
+
const sanitized = rawUrl.split("?")[0]?.split("#")[0] ?? rawUrl;
|
|
270
|
+
const esmMarker = "/dist/esm/naylence/fame/";
|
|
271
|
+
const distMarker = "/dist/";
|
|
272
|
+
if (sanitized.includes(esmMarker)) {
|
|
273
|
+
return sanitized.slice(0, sanitized.indexOf(esmMarker) + esmMarker.length);
|
|
227
274
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
trust_store_cert_count: trustedCerts.length,
|
|
231
|
-
});
|
|
232
|
-
const chainInfo = chain.map((cert, index) => `[${index}] ${cert.subjectName} (Serial: ${cert.serialNumber})`);
|
|
233
|
-
const trustedInfo = trustedCerts.map((cert, index) => `[${index}] ${cert.subjectName} (Serial: ${cert.serialNumber})`);
|
|
234
|
-
logger$h.debug("certificate_chain_validation", {
|
|
235
|
-
chain_certificates: chainInfo,
|
|
236
|
-
trust_store_certificates: trustedInfo,
|
|
237
|
-
});
|
|
238
|
-
// Strategy 1: direct trust (exact certificate match)
|
|
239
|
-
for (let i = 0; i < chain.length; i += 1) {
|
|
240
|
-
const cert = chain[i];
|
|
241
|
-
const match = trustedCerts.find((trusted) => trusted.serialNumber === cert.serialNumber &&
|
|
242
|
-
namesEqual(trusted.certificate.tbsCertificate.subject, cert.certificate.tbsCertificate.subject));
|
|
243
|
-
if (match) {
|
|
244
|
-
logger$h.debug("certificate_chain_trust_validation_passed", {
|
|
245
|
-
matching_serial: match.serialNumber,
|
|
246
|
-
validation_strategy: `direct_trust_cert_${i}`,
|
|
247
|
-
});
|
|
248
|
-
return;
|
|
249
|
-
}
|
|
275
|
+
if (rawUrl.includes(BROWSER_DIST_SEGMENT)) {
|
|
276
|
+
return new URL("../esm/naylence/fame/", rawUrl).href;
|
|
250
277
|
}
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
if (namesEqual(trusted.certificate.tbsCertificate.subject, leaf.certificate.tbsCertificate.issuer) &&
|
|
255
|
-
trusted.serialNumber !== leaf.serialNumber) {
|
|
256
|
-
verifyCertificateSignature(leaf.certificate, trusted.certificate);
|
|
257
|
-
logger$h.debug("certificate_chain_trust_validation_passed", {
|
|
258
|
-
matching_serial: trusted.serialNumber,
|
|
259
|
-
validation_strategy: "leaf_issuer_trust",
|
|
260
|
-
});
|
|
261
|
-
return;
|
|
262
|
-
}
|
|
278
|
+
if (sanitized.includes(BROWSER_DIST_SEGMENT)) {
|
|
279
|
+
const base = sanitized.slice(0, sanitized.indexOf(BROWSER_DIST_SEGMENT) + BROWSER_DIST_SEGMENT.length);
|
|
280
|
+
return `${base.replace(/browser\/?$/u, "")}esm/naylence/fame/`;
|
|
263
281
|
}
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
const
|
|
267
|
-
|
|
268
|
-
if (namesEqual(trusted.certificate.tbsCertificate.subject, intermediate.certificate.tbsCertificate.issuer) &&
|
|
269
|
-
trusted.serialNumber !== intermediate.serialNumber) {
|
|
270
|
-
verifyCertificateSignature(intermediate.certificate, trusted.certificate);
|
|
271
|
-
logger$h.debug("certificate_chain_trust_validation_passed", {
|
|
272
|
-
matching_serial: trusted.serialNumber,
|
|
273
|
-
validation_strategy: `intermediate_issuer_trust_cert_${index}`,
|
|
274
|
-
});
|
|
275
|
-
return;
|
|
276
|
-
}
|
|
277
|
-
}
|
|
282
|
+
if (sanitized.includes(distMarker)) {
|
|
283
|
+
const index = sanitized.indexOf(distMarker);
|
|
284
|
+
const base = sanitized.slice(0, index + distMarker.length);
|
|
285
|
+
return `${base}esm/naylence/fame/`;
|
|
278
286
|
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
});
|
|
287
|
-
throw new Error("Certificate chain is not rooted in a trusted anchor");
|
|
288
|
-
}
|
|
289
|
-
function parseTrustStore(trustStorePem) {
|
|
290
|
-
const normalized = normalizePem$2(trustStorePem);
|
|
291
|
-
const blocks = extractPemBlocks$1(normalized);
|
|
292
|
-
const parsed = [];
|
|
293
|
-
for (const block of blocks) {
|
|
287
|
+
const srcMarker = "/src/naylence/fame/";
|
|
288
|
+
if (sanitized.includes(srcMarker)) {
|
|
289
|
+
const index = sanitized.indexOf(srcMarker);
|
|
290
|
+
const projectRoot = sanitized.slice(0, index);
|
|
291
|
+
return `${projectRoot}/dist/esm/naylence/fame/`;
|
|
292
|
+
}
|
|
293
|
+
if (sanitized.startsWith("http://") || sanitized.startsWith("https://")) {
|
|
294
294
|
try {
|
|
295
|
-
const
|
|
296
|
-
const
|
|
297
|
-
parsed.
|
|
295
|
+
const parsed = new URL(rawUrl);
|
|
296
|
+
const viteDepsSegment = "/node_modules/.vite/deps/";
|
|
297
|
+
if (parsed.pathname.includes(viteDepsSegment)) {
|
|
298
|
+
const baseOrigin = `${parsed.protocol}//${parsed.host}`;
|
|
299
|
+
return `${baseOrigin}/node_modules/@naylence/advanced-security/dist/esm/naylence/fame/`;
|
|
300
|
+
}
|
|
298
301
|
}
|
|
299
|
-
catch
|
|
300
|
-
|
|
301
|
-
logger$h.debug("trust_store_certificate_parse_failed", { reason });
|
|
302
|
+
catch {
|
|
303
|
+
// ignore
|
|
302
304
|
}
|
|
303
305
|
}
|
|
304
|
-
return
|
|
306
|
+
return null;
|
|
305
307
|
}
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
const body = match[1] ?? "";
|
|
313
|
-
blocks.push(body.replace(/\s+/gu, ""));
|
|
308
|
+
const moduleUrl = detectModuleUrl();
|
|
309
|
+
const browserFactoryBase = computeBrowserFactoryBase(moduleUrl);
|
|
310
|
+
const prefersSource = typeof moduleUrl === "string" && moduleUrl.includes("/src/");
|
|
311
|
+
function resolveFactoryModuleSpecifier$1(specifier) {
|
|
312
|
+
if (specifier.startsWith("../")) {
|
|
313
|
+
return `${FACTORY_MODULE_PREFIX$1}${specifier.slice("../".length)}`;
|
|
314
314
|
}
|
|
315
|
-
|
|
316
|
-
}
|
|
317
|
-
function validateChainContinuity(chain) {
|
|
318
|
-
if (chain.length <= 1) {
|
|
319
|
-
return;
|
|
315
|
+
if (specifier.startsWith("./")) {
|
|
316
|
+
return `${FACTORY_MODULE_PREFIX$1}${specifier.slice("./".length)}`;
|
|
320
317
|
}
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
318
|
+
return null;
|
|
319
|
+
}
|
|
320
|
+
function resolveModuleCandidates(spec) {
|
|
321
|
+
const candidates = [];
|
|
322
|
+
const seen = new Set();
|
|
323
|
+
const addCandidate = (candidate) => {
|
|
324
|
+
if (!candidate) {
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
if (!seen.has(candidate)) {
|
|
328
|
+
seen.add(candidate);
|
|
329
|
+
candidates.push(candidate);
|
|
330
|
+
}
|
|
331
|
+
};
|
|
332
|
+
if (prefersSource && spec.startsWith("./")) {
|
|
333
|
+
const sourceCandidate = `../${spec.slice(2)}`;
|
|
334
|
+
addCandidate(sourceCandidate);
|
|
335
|
+
if (sourceCandidate.endsWith(".js")) {
|
|
336
|
+
addCandidate(sourceCandidate.replace(/\.js$/u, ".ts"));
|
|
334
337
|
}
|
|
338
|
+
}
|
|
339
|
+
if (browserFactoryBase && spec.startsWith("./")) {
|
|
335
340
|
try {
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
});
|
|
341
|
+
const browserCandidate = new URL(spec.slice("./".length), browserFactoryBase).href;
|
|
342
|
+
addCandidate(browserCandidate);
|
|
343
|
+
if (browserCandidate.endsWith(".js")) {
|
|
344
|
+
addCandidate(browserCandidate.replace(/\.js$/u, ".ts"));
|
|
345
|
+
}
|
|
342
346
|
}
|
|
343
|
-
catch
|
|
344
|
-
|
|
345
|
-
logger$h.warning("certificate_chain_continuity_failed", {
|
|
346
|
-
cert_index: index,
|
|
347
|
-
cert_subject: cert.subjectName,
|
|
348
|
-
issuer_subject: issuer.subjectName,
|
|
349
|
-
cert_serial: cert.serialNumber,
|
|
350
|
-
issuer_serial: issuer.serialNumber,
|
|
351
|
-
error: reason,
|
|
352
|
-
reason: "signature_verification_failed",
|
|
353
|
-
});
|
|
354
|
-
throw new Error(`Certificate chain continuity broken: certificate at index ${index} was not signed by certificate at index ${index + 1}: ${reason}`);
|
|
347
|
+
catch {
|
|
348
|
+
// ignore resolution failures for browser base
|
|
355
349
|
}
|
|
356
350
|
}
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
function verifyCertificateSignature(certificate, issuer) {
|
|
362
|
-
ensureEd25519Support();
|
|
363
|
-
const signatureAlgorithm = certificate.signatureAlgorithm.algorithm;
|
|
364
|
-
const issuerAlgorithm = issuer.tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm;
|
|
365
|
-
if (signatureAlgorithm !== OID_ED25519 || issuerAlgorithm !== OID_ED25519) {
|
|
366
|
-
throw new Error(`Unsupported signature algorithm (certificate: ${signatureAlgorithm}, issuer: ${issuerAlgorithm})`);
|
|
351
|
+
const packageCandidate = resolveFactoryModuleSpecifier$1(spec);
|
|
352
|
+
addCandidate(packageCandidate);
|
|
353
|
+
if (packageCandidate?.endsWith(".js")) {
|
|
354
|
+
addCandidate(packageCandidate.replace(/\.js$/u, ".ts"));
|
|
367
355
|
}
|
|
368
|
-
const
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
throw new Error("Issuer Ed25519 public key must be 32 bytes");
|
|
356
|
+
const fallback = spec.startsWith("./") ? `../${spec.slice(2)}` : spec;
|
|
357
|
+
addCandidate(fallback);
|
|
358
|
+
if (fallback.endsWith(".js")) {
|
|
359
|
+
addCandidate(fallback.replace(/\.js$/u, ".ts"));
|
|
373
360
|
}
|
|
374
|
-
|
|
375
|
-
if (
|
|
376
|
-
|
|
361
|
+
addCandidate(spec);
|
|
362
|
+
if (spec.endsWith(".js")) {
|
|
363
|
+
addCandidate(spec.replace(/\.js$/u, ".ts"));
|
|
377
364
|
}
|
|
365
|
+
return candidates;
|
|
378
366
|
}
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
367
|
+
const registeredModules = new Set();
|
|
368
|
+
const inflightModules = new Map();
|
|
369
|
+
const browserSkippedModules = new Set();
|
|
370
|
+
function isNodeEnvironment$5() {
|
|
371
|
+
return (typeof process !== "undefined" &&
|
|
372
|
+
typeof process.release !== "undefined" &&
|
|
373
|
+
process.release?.name === "node");
|
|
374
|
+
}
|
|
375
|
+
function shouldSkipModule(spec) {
|
|
376
|
+
if (isNodeEnvironment$5()) {
|
|
377
|
+
return false;
|
|
383
378
|
}
|
|
384
|
-
if (!
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
379
|
+
if (!NODE_ONLY_MODULES.has(spec)) {
|
|
380
|
+
return false;
|
|
381
|
+
}
|
|
382
|
+
if (!browserSkippedModules.has(spec)) {
|
|
383
|
+
// console.warn(
|
|
384
|
+
// "[advanced-security:factory-manifest] skipped browser-incompatible module",
|
|
385
|
+
// spec,
|
|
386
|
+
// );
|
|
387
|
+
browserSkippedModules.add(spec);
|
|
392
388
|
}
|
|
389
|
+
return true;
|
|
393
390
|
}
|
|
394
|
-
function
|
|
395
|
-
|
|
396
|
-
if (!extensions) {
|
|
391
|
+
function getDynamicImporter() {
|
|
392
|
+
if (typeof globalThis === "undefined") {
|
|
397
393
|
return null;
|
|
398
394
|
}
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
}
|
|
395
|
+
const candidate = globalThis.__naylenceFactoryDynamicImporter;
|
|
396
|
+
if (typeof candidate === "function") {
|
|
397
|
+
return candidate;
|
|
403
398
|
}
|
|
404
399
|
return null;
|
|
405
400
|
}
|
|
406
|
-
function
|
|
407
|
-
const
|
|
408
|
-
const
|
|
409
|
-
|
|
410
|
-
|
|
401
|
+
async function registerModule(spec, registrar) {
|
|
402
|
+
const candidates = resolveModuleCandidates(spec);
|
|
403
|
+
const dynamicImporter = getDynamicImporter();
|
|
404
|
+
const loader = dynamicImporter
|
|
405
|
+
? (specifier) => dynamicImporter(specifier)
|
|
406
|
+
: (specifier) => import(/* @vite-ignore */ specifier);
|
|
407
|
+
const attempts = [];
|
|
408
|
+
const staticLoader = MODULE_LOADERS?.[spec];
|
|
409
|
+
if (staticLoader) {
|
|
410
|
+
attempts.push({ load: () => staticLoader(), candidate: spec });
|
|
411
411
|
}
|
|
412
|
-
for (
|
|
413
|
-
|
|
412
|
+
for (const candidate of candidates) {
|
|
413
|
+
attempts.push({ load: () => loader(candidate), candidate });
|
|
414
|
+
}
|
|
415
|
+
const registerFromModule = (mod) => {
|
|
416
|
+
const meta = mod.FACTORY_META;
|
|
417
|
+
const Ctor = mod.default;
|
|
418
|
+
if (!meta?.base || !meta?.key || typeof Ctor !== "function") {
|
|
419
|
+
console.warn("[debug] invalid factory module", spec, {
|
|
420
|
+
meta,
|
|
421
|
+
hasCtor: typeof Ctor === "function",
|
|
422
|
+
});
|
|
423
|
+
console.warn("[advanced-security:factory-manifest] skipped", spec, "— missing FACTORY_META or default export ctor");
|
|
414
424
|
return false;
|
|
415
425
|
}
|
|
426
|
+
const { base, key, ...metadata } = meta;
|
|
427
|
+
const extraMetadata = Object.keys(metadata).length > 0 ? metadata : undefined;
|
|
428
|
+
// console.log("[debug] registering module", { spec, base, key, metadata: extraMetadata });
|
|
429
|
+
registrar.registerFactory(base, key, Ctor, extraMetadata);
|
|
430
|
+
return true;
|
|
431
|
+
};
|
|
432
|
+
for (const [index, { candidate, load }] of attempts.entries()) {
|
|
433
|
+
try {
|
|
434
|
+
const mod = await load();
|
|
435
|
+
return registerFromModule(mod);
|
|
436
|
+
}
|
|
437
|
+
catch (error) {
|
|
438
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
439
|
+
const moduleNotFound = message.includes("Cannot find module") ||
|
|
440
|
+
message.includes("ERR_MODULE_NOT_FOUND") ||
|
|
441
|
+
message.includes("Unknown file extension") ||
|
|
442
|
+
message.includes("Failed to fetch dynamically imported module") ||
|
|
443
|
+
message.includes("Failed to resolve module specifier") ||
|
|
444
|
+
message.includes("Importing a module script failed");
|
|
445
|
+
const isLastAttempt = index === attempts.length - 1;
|
|
446
|
+
if (!moduleNotFound || isLastAttempt) {
|
|
447
|
+
console.warn("[debug] failed to import candidate", {
|
|
448
|
+
spec,
|
|
449
|
+
candidate,
|
|
450
|
+
message,
|
|
451
|
+
});
|
|
452
|
+
console.warn("[advanced-security:factory-manifest] skipped", spec, "-", message);
|
|
453
|
+
return false;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
416
456
|
}
|
|
417
|
-
return
|
|
418
|
-
}
|
|
419
|
-
function serializeName(name) {
|
|
420
|
-
const rdns = Array.from(name);
|
|
421
|
-
return rdns
|
|
422
|
-
.map((rdn) => Array.from(rdn)
|
|
423
|
-
.map((attr) => `${oidToLabel$1(attr.type)}=${attr.value.toString()}`)
|
|
424
|
-
.join("+"))
|
|
425
|
-
.join(",");
|
|
457
|
+
return false;
|
|
426
458
|
}
|
|
427
|
-
function
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
return "CN";
|
|
431
|
-
case "2.5.4.6":
|
|
432
|
-
return "C";
|
|
433
|
-
case "2.5.4.7":
|
|
434
|
-
return "L";
|
|
435
|
-
case "2.5.4.8":
|
|
436
|
-
return "ST";
|
|
437
|
-
case "2.5.4.10":
|
|
438
|
-
return "O";
|
|
439
|
-
case "2.5.4.11":
|
|
440
|
-
return "OU";
|
|
441
|
-
default:
|
|
442
|
-
return oid;
|
|
459
|
+
async function registerModuleOnce(spec, registrar) {
|
|
460
|
+
if (registeredModules.has(spec)) {
|
|
461
|
+
return false;
|
|
443
462
|
}
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
463
|
+
const inflight = inflightModules.get(spec);
|
|
464
|
+
if (inflight) {
|
|
465
|
+
return inflight;
|
|
466
|
+
}
|
|
467
|
+
const registration = (async () => {
|
|
468
|
+
const registered = await registerModule(spec, registrar);
|
|
469
|
+
if (registered) {
|
|
470
|
+
registeredModules.add(spec);
|
|
471
|
+
}
|
|
472
|
+
return registered;
|
|
473
|
+
})();
|
|
474
|
+
inflightModules.set(spec, registration);
|
|
475
|
+
try {
|
|
476
|
+
return await registration;
|
|
477
|
+
}
|
|
478
|
+
finally {
|
|
479
|
+
inflightModules.delete(spec);
|
|
452
480
|
}
|
|
453
|
-
return result;
|
|
454
481
|
}
|
|
455
|
-
function
|
|
456
|
-
if (
|
|
457
|
-
|
|
458
|
-
return new Uint8Array(Buffer.from(normalized, "base64"));
|
|
482
|
+
async function registerModules(modules, registrar) {
|
|
483
|
+
if (modules.length === 0) {
|
|
484
|
+
return 0;
|
|
459
485
|
}
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
const bytes = new Uint8Array(binary.length);
|
|
464
|
-
for (let i = 0; i < binary.length; i += 1) {
|
|
465
|
-
bytes[i] = binary.charCodeAt(i);
|
|
466
|
-
}
|
|
467
|
-
return bytes;
|
|
486
|
+
const eligibleModules = modules.filter((spec) => !shouldSkipModule(spec));
|
|
487
|
+
if (eligibleModules.length === 0) {
|
|
488
|
+
return 0;
|
|
468
489
|
}
|
|
469
|
-
|
|
490
|
+
const results = await Promise.all(eligibleModules.map((spec) => registerModuleOnce(spec, registrar)));
|
|
491
|
+
return results.reduce((count, registered) => (registered ? count + 1 : count), 0);
|
|
470
492
|
}
|
|
471
|
-
function
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
.
|
|
475
|
-
}
|
|
476
|
-
function buildCacheKey(chainBytes, trustStorePem, enforceNameConstraints) {
|
|
477
|
-
const chainHash = toHex(sha256(chainBytes));
|
|
478
|
-
const trustHash = trustStorePem
|
|
479
|
-
? toHex(sha256(textEncoder.encode(trustStorePem)))
|
|
480
|
-
: "no-trust";
|
|
481
|
-
const constraintFlag = enforceNameConstraints ? "nc1" : "nc0";
|
|
482
|
-
return `${chainHash}|${trustHash}|${constraintFlag}`;
|
|
483
|
-
}
|
|
484
|
-
function getCachedPublicKey(cacheKey) {
|
|
485
|
-
const entry = trustCache.get(cacheKey);
|
|
486
|
-
if (!entry) {
|
|
487
|
-
return null;
|
|
493
|
+
async function registerAdvancedSecurityFactories(registrar = Registry, options) {
|
|
494
|
+
const newlyRegisteredSecurity = await registerModules(SECURITY_MODULES, registrar);
|
|
495
|
+
if (newlyRegisteredSecurity > 0) {
|
|
496
|
+
getEncryptionManagerFactoryRegistry().forceRediscovery();
|
|
488
497
|
}
|
|
489
|
-
if (
|
|
490
|
-
|
|
491
|
-
logger$h.debug("certificate_cache_expired", { cache_key: cacheKey });
|
|
492
|
-
return null;
|
|
498
|
+
if (options?.includeExtras === true) {
|
|
499
|
+
await registerModules(EXTRA_MODULES, registrar);
|
|
493
500
|
}
|
|
494
|
-
return entry.value.slice();
|
|
495
501
|
}
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
502
|
+
|
|
503
|
+
// This file is auto-generated during build - do not edit manually
|
|
504
|
+
// Generated from package.json version: 0.3.15
|
|
505
|
+
/**
|
|
506
|
+
* The package version, injected at build time.
|
|
507
|
+
* @internal
|
|
508
|
+
*/
|
|
509
|
+
const VERSION = '0.3.15';
|
|
510
|
+
|
|
511
|
+
async function registerAdvancedSecurityPluginFactories(registrar = Registry) {
|
|
512
|
+
await registerAdvancedSecurityFactories(registrar, { includeExtras: true });
|
|
513
|
+
}
|
|
514
|
+
let initialized = false;
|
|
515
|
+
let initializing = null;
|
|
516
|
+
const advancedSecurityPlugin = {
|
|
517
|
+
name: "naylence:advanced-security",
|
|
518
|
+
version: VERSION,
|
|
519
|
+
async register() {
|
|
520
|
+
// console.log('[naylence:advanced-security] register() called, initialized=', initialized);
|
|
521
|
+
if (initialized) {
|
|
522
|
+
// console.log('[naylence:advanced-security] already initialized, skipping');
|
|
523
|
+
return;
|
|
501
524
|
}
|
|
502
|
-
|
|
503
|
-
|
|
525
|
+
if (initializing) {
|
|
526
|
+
console.log("[naylence:advanced-security] already initializing, awaiting...");
|
|
527
|
+
await initializing;
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
initializing = (async () => {
|
|
531
|
+
try {
|
|
532
|
+
// console.log('[naylence:advanced-security] registering advanced security factories...');
|
|
533
|
+
await registerAdvancedSecurityPluginFactories();
|
|
534
|
+
// console.log('[naylence:advanced-security] advanced security factories registered');
|
|
535
|
+
initialized = true;
|
|
536
|
+
}
|
|
537
|
+
finally {
|
|
538
|
+
initializing = null;
|
|
539
|
+
}
|
|
540
|
+
})();
|
|
541
|
+
await initializing;
|
|
542
|
+
},
|
|
543
|
+
};
|
|
544
|
+
const ADVANCED_SECURITY_PLUGIN_SPECIFIER = advancedSecurityPlugin.name;
|
|
545
|
+
|
|
546
|
+
var plugin = /*#__PURE__*/Object.freeze({
|
|
547
|
+
__proto__: null,
|
|
548
|
+
ADVANCED_SECURITY_PLUGIN_SPECIFIER: ADVANCED_SECURITY_PLUGIN_SPECIFIER,
|
|
549
|
+
default: advancedSecurityPlugin,
|
|
550
|
+
registerAdvancedSecurityPluginFactories: registerAdvancedSecurityPluginFactories
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
const logger$g = getLogger("naylence.fame.security.cert.util");
|
|
554
|
+
const CACHE_LIMIT = 512;
|
|
555
|
+
const OID_ED25519 = "1.3.101.112";
|
|
556
|
+
const textEncoder = new TextEncoder();
|
|
557
|
+
const trustCache = new Map();
|
|
558
|
+
function publicKeyFromX5c(x5c, options = {}) {
|
|
559
|
+
if (!Array.isArray(x5c) || x5c.length === 0) {
|
|
560
|
+
throw new Error("Empty certificate chain");
|
|
504
561
|
}
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
562
|
+
const callId = generateCallId();
|
|
563
|
+
const enforceNameConstraints = options.enforceNameConstraints ?? true;
|
|
564
|
+
const trustStorePem = normalizeTrustStoreOption(options.trustStorePem ?? null);
|
|
565
|
+
const returnCertificate = options.returnCertificate ?? false;
|
|
566
|
+
const { parsed, chainBytes } = parseCertificateChain(x5c);
|
|
567
|
+
logger$g.debug("public_key_from_x5c_called", {
|
|
568
|
+
call_id: callId,
|
|
569
|
+
x5c_count: parsed.length,
|
|
570
|
+
enforce_name_constraints: enforceNameConstraints,
|
|
571
|
+
has_trust_store: Boolean(trustStorePem),
|
|
572
|
+
return_cert: returnCertificate,
|
|
513
573
|
});
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
574
|
+
let cacheKey = null;
|
|
575
|
+
if (!returnCertificate) {
|
|
576
|
+
cacheKey = buildCacheKey(chainBytes, trustStorePem, enforceNameConstraints);
|
|
577
|
+
const cached = getCachedPublicKey(cacheKey);
|
|
578
|
+
if (cached) {
|
|
579
|
+
logger$g.debug("certificate_cache_hit", {
|
|
580
|
+
call_id: callId,
|
|
581
|
+
cache_key: cacheKey,
|
|
582
|
+
});
|
|
583
|
+
return cached;
|
|
584
|
+
}
|
|
585
|
+
logger$g.debug("certificate_cache_miss", {
|
|
586
|
+
call_id: callId,
|
|
587
|
+
cache_key: cacheKey,
|
|
588
|
+
});
|
|
518
589
|
}
|
|
519
|
-
const
|
|
520
|
-
if (
|
|
521
|
-
|
|
590
|
+
const validation = validateCertificateChain(parsed, enforceNameConstraints, trustStorePem);
|
|
591
|
+
if (cacheKey) {
|
|
592
|
+
setCachedPublicKey(cacheKey, validation.publicKey, validation.notAfter);
|
|
522
593
|
}
|
|
523
|
-
if (
|
|
524
|
-
|
|
594
|
+
if (returnCertificate) {
|
|
595
|
+
return {
|
|
596
|
+
publicKey: validation.publicKey.slice(),
|
|
597
|
+
certificate: validation.certificate,
|
|
598
|
+
};
|
|
525
599
|
}
|
|
526
|
-
return
|
|
527
|
-
}
|
|
528
|
-
function normalizePem$2(pem) {
|
|
529
|
-
return pem.replace(/\r/gu, "").trim();
|
|
530
|
-
}
|
|
531
|
-
function generateCallId() {
|
|
532
|
-
return Math.random().toString(36).slice(2, 10);
|
|
600
|
+
return validation.publicKey.slice();
|
|
533
601
|
}
|
|
534
|
-
|
|
535
|
-
const
|
|
536
|
-
|
|
537
|
-
const
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
if (!instance) {
|
|
543
|
-
throw new Error("WebCrypto subtle API is required to create a CSR");
|
|
602
|
+
function validateJwkX5cCertificate(options) {
|
|
603
|
+
const { jwk, trustStorePem = null, enforceNameConstraints = true, strict = true, } = options;
|
|
604
|
+
if (!jwk || typeof jwk !== "object") {
|
|
605
|
+
const error = "Invalid JWK object";
|
|
606
|
+
if (strict) {
|
|
607
|
+
throw new Error(error);
|
|
608
|
+
}
|
|
609
|
+
return { isValid: false, error };
|
|
544
610
|
}
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
if (!commonName || typeof commonName !== "string") {
|
|
549
|
-
throw new Error("commonName must be a non-empty string");
|
|
611
|
+
const x5c = jwk.x5c;
|
|
612
|
+
if (x5c === undefined) {
|
|
613
|
+
return { isValid: true };
|
|
550
614
|
}
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
}
|
|
560
|
-
function arrayBufferToBase64(buffer) {
|
|
561
|
-
const bytes = new Uint8Array(buffer);
|
|
562
|
-
if (typeof globalThis.Buffer?.from === "function") {
|
|
563
|
-
return globalThis.Buffer.from(bytes).toString("base64");
|
|
615
|
+
if (!Array.isArray(x5c) ||
|
|
616
|
+
x5c.length === 0 ||
|
|
617
|
+
x5c.some((entry) => typeof entry !== "string")) {
|
|
618
|
+
const error = "Invalid x5c field in JWK";
|
|
619
|
+
if (strict) {
|
|
620
|
+
throw new Error(error);
|
|
621
|
+
}
|
|
622
|
+
return { isValid: false, error };
|
|
564
623
|
}
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
624
|
+
try {
|
|
625
|
+
publicKeyFromX5c(x5c, {
|
|
626
|
+
trustStorePem,
|
|
627
|
+
enforceNameConstraints,
|
|
628
|
+
});
|
|
629
|
+
return { isValid: true };
|
|
570
630
|
}
|
|
571
|
-
|
|
572
|
-
|
|
631
|
+
catch (error) {
|
|
632
|
+
const message = error instanceof Error ? error.message : String(error ?? "unknown");
|
|
633
|
+
const normalized = `Certificate validation failed: ${message}`;
|
|
634
|
+
if (strict) {
|
|
635
|
+
throw new Error(normalized);
|
|
636
|
+
}
|
|
637
|
+
return { isValid: false, error: normalized };
|
|
573
638
|
}
|
|
574
|
-
return globalThis.btoa(binary);
|
|
575
639
|
}
|
|
576
|
-
function
|
|
577
|
-
const
|
|
578
|
-
const
|
|
579
|
-
|
|
580
|
-
|
|
640
|
+
function validateCertificateChain(parsed, enforceNameConstraints, trustStorePem) {
|
|
641
|
+
const leaf = parsed[0];
|
|
642
|
+
const nowMs = Date.now();
|
|
643
|
+
const notBefore = leaf.certificate.tbsCertificate.validity.notBefore.getTime();
|
|
644
|
+
const notAfter = leaf.certificate.tbsCertificate.validity.notAfter.getTime();
|
|
645
|
+
const notBeforeMs = notBefore.getTime();
|
|
646
|
+
const notAfterMs = notAfter.getTime();
|
|
647
|
+
if (nowMs < notBeforeMs || nowMs > notAfterMs) {
|
|
648
|
+
throw new Error(`Certificate is not currently valid (notBefore: ${notBefore.toISOString()}, notAfter: ${notAfter.toISOString()}, now: ${new Date(nowMs).toISOString()})`);
|
|
581
649
|
}
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
const { privateKey, publicKey, commonName } = options;
|
|
587
|
-
if (!(privateKey instanceof CryptoKey) || privateKey.type !== "private") {
|
|
588
|
-
throw new Error("privateKey must be a CryptoKey of type 'private'");
|
|
650
|
+
const issuers = parsed.slice(1);
|
|
651
|
+
if (enforceNameConstraints && issuers.length > 0) {
|
|
652
|
+
const leafUris = extractUrisFromCert(leaf.certificate);
|
|
653
|
+
validateNameConstraints(issuers, leafUris);
|
|
589
654
|
}
|
|
590
|
-
if (
|
|
591
|
-
|
|
655
|
+
if (trustStorePem) {
|
|
656
|
+
validateTrustAnchor(parsed, trustStorePem);
|
|
592
657
|
}
|
|
593
|
-
|
|
594
|
-
const
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
new
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
658
|
+
validateChainContinuity(parsed);
|
|
659
|
+
const publicKey = leaf.subjectPublicKey.slice();
|
|
660
|
+
return {
|
|
661
|
+
publicKey,
|
|
662
|
+
certificate: leaf.certificate,
|
|
663
|
+
notAfter,
|
|
664
|
+
};
|
|
665
|
+
}
|
|
666
|
+
function parseCertificateChain(x5c) {
|
|
667
|
+
const parsed = [];
|
|
668
|
+
const derChunks = [];
|
|
669
|
+
for (let index = 0; index < x5c.length; index += 1) {
|
|
670
|
+
const entry = x5c[index];
|
|
671
|
+
if (typeof entry !== "string" || entry.trim().length === 0) {
|
|
672
|
+
throw new Error(`Invalid certificate at index ${index}`);
|
|
673
|
+
}
|
|
674
|
+
let der;
|
|
675
|
+
try {
|
|
676
|
+
der = decodeBase64$2(entry);
|
|
677
|
+
}
|
|
678
|
+
catch (error) {
|
|
679
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
680
|
+
throw new Error(`Failed to decode certificate at index ${index}: ${reason}`);
|
|
681
|
+
}
|
|
682
|
+
let certificate;
|
|
683
|
+
try {
|
|
684
|
+
certificate = AsnConvert.parse(der, Certificate);
|
|
685
|
+
}
|
|
686
|
+
catch (error) {
|
|
687
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
688
|
+
throw new Error(`Failed to parse certificate at index ${index}: ${reason}`);
|
|
689
|
+
}
|
|
690
|
+
parsed.push(createParsedCertificate(certificate, der));
|
|
691
|
+
derChunks.push(der);
|
|
692
|
+
}
|
|
693
|
+
return { parsed, chainBytes: concatBytes(derChunks) };
|
|
694
|
+
}
|
|
695
|
+
function createParsedCertificate(certificate, raw) {
|
|
696
|
+
return {
|
|
697
|
+
raw,
|
|
698
|
+
certificate,
|
|
699
|
+
serialNumber: toHex(new Uint8Array(certificate.tbsCertificate.serialNumber)).toUpperCase(),
|
|
700
|
+
subjectName: serializeName(certificate.tbsCertificate.subject),
|
|
701
|
+
issuerName: serializeName(certificate.tbsCertificate.issuer),
|
|
702
|
+
subjectPublicKey: new Uint8Array(certificate.tbsCertificate.subjectPublicKeyInfo.subjectPublicKey).slice(),
|
|
703
|
+
};
|
|
704
|
+
}
|
|
705
|
+
function extractUrisFromCert(cert) {
|
|
706
|
+
const extension = findExtension(cert, id_ce_subjectAltName);
|
|
707
|
+
if (!extension) {
|
|
708
|
+
return [];
|
|
709
|
+
}
|
|
710
|
+
const subjectAlternativeName = AsnConvert.parse(extension.extnValue.buffer, SubjectAlternativeName);
|
|
711
|
+
const uris = [];
|
|
712
|
+
for (const generalName of subjectAlternativeName) {
|
|
713
|
+
if (generalName.uniformResourceIdentifier) {
|
|
714
|
+
uris.push(generalName.uniformResourceIdentifier);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
return uris;
|
|
718
|
+
}
|
|
719
|
+
function validateNameConstraints(issuers, leafUris) {
|
|
720
|
+
for (const issuer of issuers) {
|
|
721
|
+
const extension = findExtension(issuer.certificate, id_ce_nameConstraints);
|
|
722
|
+
if (!extension) {
|
|
723
|
+
continue;
|
|
724
|
+
}
|
|
725
|
+
const constraints = AsnConvert.parse(extension.extnValue.buffer, NameConstraints);
|
|
726
|
+
if (!constraints.permittedSubtrees) {
|
|
727
|
+
continue;
|
|
728
|
+
}
|
|
729
|
+
const permittedUris = collectPermittedUris(Array.from(constraints.permittedSubtrees));
|
|
730
|
+
if (permittedUris.length === 0) {
|
|
731
|
+
continue;
|
|
732
|
+
}
|
|
733
|
+
for (const uri of leafUris) {
|
|
734
|
+
const allowed = permittedUris.some((prefix) => uri.startsWith(prefix));
|
|
735
|
+
if (!allowed) {
|
|
736
|
+
throw new Error(`URI '${uri}' violates name constraints - not in permitted subtrees: ${permittedUris.join(", ")}`);
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
function collectPermittedUris(subtrees) {
|
|
742
|
+
const uris = [];
|
|
743
|
+
for (const subtree of subtrees) {
|
|
744
|
+
if (subtree.base.uniformResourceIdentifier &&
|
|
745
|
+
subtree.base.uniformResourceIdentifier.length > 0) {
|
|
746
|
+
uris.push(subtree.base.uniformResourceIdentifier);
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
return uris;
|
|
750
|
+
}
|
|
751
|
+
function validateTrustAnchor(chain, trustStorePem) {
|
|
752
|
+
const trustedCerts = parseTrustStore(trustStorePem);
|
|
753
|
+
if (trustedCerts.length === 0) {
|
|
754
|
+
throw new Error("No valid certificates found in trust store");
|
|
755
|
+
}
|
|
756
|
+
logger$g.debug("trust_anchor_validation_start", {
|
|
757
|
+
chain_length: chain.length,
|
|
758
|
+
trust_store_cert_count: trustedCerts.length,
|
|
759
|
+
});
|
|
760
|
+
const chainInfo = chain.map((cert, index) => `[${index}] ${cert.subjectName} (Serial: ${cert.serialNumber})`);
|
|
761
|
+
const trustedInfo = trustedCerts.map((cert, index) => `[${index}] ${cert.subjectName} (Serial: ${cert.serialNumber})`);
|
|
762
|
+
logger$g.debug("certificate_chain_validation", {
|
|
763
|
+
chain_certificates: chainInfo,
|
|
764
|
+
trust_store_certificates: trustedInfo,
|
|
765
|
+
});
|
|
766
|
+
// Strategy 1: direct trust (exact certificate match)
|
|
767
|
+
for (let i = 0; i < chain.length; i += 1) {
|
|
768
|
+
const cert = chain[i];
|
|
769
|
+
const match = trustedCerts.find((trusted) => trusted.serialNumber === cert.serialNumber &&
|
|
770
|
+
namesEqual(trusted.certificate.tbsCertificate.subject, cert.certificate.tbsCertificate.subject));
|
|
771
|
+
if (match) {
|
|
772
|
+
logger$g.debug("certificate_chain_trust_validation_passed", {
|
|
773
|
+
matching_serial: match.serialNumber,
|
|
774
|
+
validation_strategy: `direct_trust_cert_${i}`,
|
|
775
|
+
});
|
|
776
|
+
return;
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
const leaf = chain[0];
|
|
780
|
+
// Strategy 2: leaf issuer in trust store
|
|
781
|
+
for (const trusted of trustedCerts) {
|
|
782
|
+
if (namesEqual(trusted.certificate.tbsCertificate.subject, leaf.certificate.tbsCertificate.issuer) &&
|
|
783
|
+
trusted.serialNumber !== leaf.serialNumber) {
|
|
784
|
+
verifyCertificateSignature(leaf.certificate, trusted.certificate);
|
|
785
|
+
logger$g.debug("certificate_chain_trust_validation_passed", {
|
|
786
|
+
matching_serial: trusted.serialNumber,
|
|
787
|
+
validation_strategy: "leaf_issuer_trust",
|
|
788
|
+
});
|
|
789
|
+
return;
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
// Strategy 3: any intermediate issuer in trust store
|
|
793
|
+
for (let index = 1; index < chain.length; index += 1) {
|
|
794
|
+
const intermediate = chain[index];
|
|
795
|
+
for (const trusted of trustedCerts) {
|
|
796
|
+
if (namesEqual(trusted.certificate.tbsCertificate.subject, intermediate.certificate.tbsCertificate.issuer) &&
|
|
797
|
+
trusted.serialNumber !== intermediate.serialNumber) {
|
|
798
|
+
verifyCertificateSignature(intermediate.certificate, trusted.certificate);
|
|
799
|
+
logger$g.debug("certificate_chain_trust_validation_passed", {
|
|
800
|
+
matching_serial: trusted.serialNumber,
|
|
801
|
+
validation_strategy: `intermediate_issuer_trust_cert_${index}`,
|
|
802
|
+
});
|
|
803
|
+
return;
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
logger$g.warning("certificate_chain_trust_validation_failed", {
|
|
808
|
+
leaf_subject: leaf.subjectName,
|
|
809
|
+
leaf_issuer: leaf.issuerName,
|
|
810
|
+
leaf_serial: leaf.serialNumber,
|
|
811
|
+
trusted_certificates: trustedInfo,
|
|
812
|
+
chain_certificates: chainInfo,
|
|
813
|
+
reason: "no_matching_trust_anchor",
|
|
814
|
+
});
|
|
815
|
+
throw new Error("Certificate chain is not rooted in a trusted anchor");
|
|
816
|
+
}
|
|
817
|
+
function parseTrustStore(trustStorePem) {
|
|
818
|
+
const normalized = normalizePem$2(trustStorePem);
|
|
819
|
+
const blocks = extractPemBlocks$1(normalized);
|
|
820
|
+
const parsed = [];
|
|
821
|
+
for (const block of blocks) {
|
|
822
|
+
try {
|
|
823
|
+
const der = decodeBase64$2(block);
|
|
824
|
+
const certificate = AsnConvert.parse(der, Certificate);
|
|
825
|
+
parsed.push(createParsedCertificate(certificate, der));
|
|
826
|
+
}
|
|
827
|
+
catch (error) {
|
|
828
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
829
|
+
logger$g.debug("trust_store_certificate_parse_failed", { reason });
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
return parsed;
|
|
833
|
+
}
|
|
834
|
+
function extractPemBlocks$1(pem) {
|
|
835
|
+
const blocks = [];
|
|
836
|
+
const regex = /-----BEGIN CERTIFICATE-----([\s\S]*?)-----END CERTIFICATE-----/gu;
|
|
837
|
+
let match;
|
|
838
|
+
// eslint-disable-next-line no-cond-assign
|
|
839
|
+
while ((match = regex.exec(pem)) !== null) {
|
|
840
|
+
const body = match[1] ?? "";
|
|
841
|
+
blocks.push(body.replace(/\s+/gu, ""));
|
|
842
|
+
}
|
|
843
|
+
return blocks;
|
|
844
|
+
}
|
|
845
|
+
function validateChainContinuity(chain) {
|
|
846
|
+
if (chain.length <= 1) {
|
|
847
|
+
return;
|
|
848
|
+
}
|
|
849
|
+
logger$g.debug("validating_chain_continuity", { chain_length: chain.length });
|
|
850
|
+
for (let index = 0; index < chain.length - 1; index += 1) {
|
|
851
|
+
const cert = chain[index];
|
|
852
|
+
const issuer = chain[index + 1];
|
|
853
|
+
if (!namesEqual(cert.certificate.tbsCertificate.issuer, issuer.certificate.tbsCertificate.subject)) {
|
|
854
|
+
logger$g.warning("certificate_chain_continuity_failed", {
|
|
855
|
+
cert_index: index,
|
|
856
|
+
cert_subject: cert.subjectName,
|
|
857
|
+
cert_issuer: cert.issuerName,
|
|
858
|
+
expected_issuer_subject: issuer.subjectName,
|
|
859
|
+
reason: "issuer_name_mismatch",
|
|
860
|
+
});
|
|
861
|
+
throw new Error(`Certificate chain continuity broken: certificate at index ${index} issuer does not match next certificate subject`);
|
|
862
|
+
}
|
|
863
|
+
try {
|
|
864
|
+
verifyCertificateSignature(cert.certificate, issuer.certificate);
|
|
865
|
+
logger$g.debug("chain_continuity_verification_success", {
|
|
866
|
+
cert_index: index,
|
|
867
|
+
cert_serial: cert.serialNumber,
|
|
868
|
+
issuer_serial: issuer.serialNumber,
|
|
869
|
+
});
|
|
870
|
+
}
|
|
871
|
+
catch (error) {
|
|
872
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
873
|
+
logger$g.warning("certificate_chain_continuity_failed", {
|
|
874
|
+
cert_index: index,
|
|
875
|
+
cert_subject: cert.subjectName,
|
|
876
|
+
issuer_subject: issuer.subjectName,
|
|
877
|
+
cert_serial: cert.serialNumber,
|
|
878
|
+
issuer_serial: issuer.serialNumber,
|
|
879
|
+
error: reason,
|
|
880
|
+
reason: "signature_verification_failed",
|
|
881
|
+
});
|
|
882
|
+
throw new Error(`Certificate chain continuity broken: certificate at index ${index} was not signed by certificate at index ${index + 1}: ${reason}`);
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
logger$g.debug("chain_continuity_validation_passed", {
|
|
886
|
+
chain_length: chain.length,
|
|
887
|
+
});
|
|
888
|
+
}
|
|
889
|
+
function verifyCertificateSignature(certificate, issuer) {
|
|
890
|
+
ensureEd25519Support();
|
|
891
|
+
const signatureAlgorithm = certificate.signatureAlgorithm.algorithm;
|
|
892
|
+
const issuerAlgorithm = issuer.tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm;
|
|
893
|
+
if (signatureAlgorithm !== OID_ED25519 || issuerAlgorithm !== OID_ED25519) {
|
|
894
|
+
throw new Error(`Unsupported signature algorithm (certificate: ${signatureAlgorithm}, issuer: ${issuerAlgorithm})`);
|
|
895
|
+
}
|
|
896
|
+
const signatureBytes = new Uint8Array(certificate.signatureValue);
|
|
897
|
+
const tbsBytes = new Uint8Array(AsnConvert.serialize(certificate.tbsCertificate));
|
|
898
|
+
const issuerKey = new Uint8Array(issuer.tbsCertificate.subjectPublicKeyInfo.subjectPublicKey);
|
|
899
|
+
if (issuerKey.length !== 32) {
|
|
900
|
+
throw new Error("Issuer Ed25519 public key must be 32 bytes");
|
|
901
|
+
}
|
|
902
|
+
const valid = verify(signatureBytes, tbsBytes, issuerKey);
|
|
903
|
+
if (!valid) {
|
|
904
|
+
throw new Error("Certificate signature verification failed");
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
function ensureEd25519Support() {
|
|
908
|
+
const etcPatch = etc;
|
|
909
|
+
if (!etcPatch.sha512) {
|
|
910
|
+
etcPatch.sha512 = (message) => sha512(message);
|
|
911
|
+
}
|
|
912
|
+
if (!etcPatch.sha512Sync) {
|
|
913
|
+
etcPatch.sha512Sync = (...messages) => {
|
|
914
|
+
if (messages.length === 1) {
|
|
915
|
+
return sha512(messages[0]);
|
|
916
|
+
}
|
|
917
|
+
const combined = etc.concatBytes(...messages);
|
|
918
|
+
return sha512(combined);
|
|
919
|
+
};
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
function findExtension(certificate, oid) {
|
|
923
|
+
const extensions = certificate.tbsCertificate.extensions;
|
|
924
|
+
if (!extensions) {
|
|
925
|
+
return null;
|
|
926
|
+
}
|
|
927
|
+
for (const extension of extensions) {
|
|
928
|
+
if (extension.extnID === oid) {
|
|
929
|
+
return extension;
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
return null;
|
|
933
|
+
}
|
|
934
|
+
function namesEqual(a, b) {
|
|
935
|
+
const left = new Uint8Array(AsnConvert.serialize(a));
|
|
936
|
+
const right = new Uint8Array(AsnConvert.serialize(b));
|
|
937
|
+
if (left.length !== right.length) {
|
|
938
|
+
return false;
|
|
939
|
+
}
|
|
940
|
+
for (let i = 0; i < left.length; i += 1) {
|
|
941
|
+
if (left[i] !== right[i]) {
|
|
942
|
+
return false;
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
return true;
|
|
946
|
+
}
|
|
947
|
+
function serializeName(name) {
|
|
948
|
+
const rdns = Array.from(name);
|
|
949
|
+
return rdns
|
|
950
|
+
.map((rdn) => Array.from(rdn)
|
|
951
|
+
.map((attr) => `${oidToLabel$1(attr.type)}=${attr.value.toString()}`)
|
|
952
|
+
.join("+"))
|
|
953
|
+
.join(",");
|
|
954
|
+
}
|
|
955
|
+
function oidToLabel$1(oid) {
|
|
956
|
+
switch (oid) {
|
|
957
|
+
case "2.5.4.3":
|
|
958
|
+
return "CN";
|
|
959
|
+
case "2.5.4.6":
|
|
960
|
+
return "C";
|
|
961
|
+
case "2.5.4.7":
|
|
962
|
+
return "L";
|
|
963
|
+
case "2.5.4.8":
|
|
964
|
+
return "ST";
|
|
965
|
+
case "2.5.4.10":
|
|
966
|
+
return "O";
|
|
967
|
+
case "2.5.4.11":
|
|
968
|
+
return "OU";
|
|
969
|
+
default:
|
|
970
|
+
return oid;
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
function concatBytes(chunks) {
|
|
974
|
+
const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
|
|
975
|
+
const result = new Uint8Array(totalLength);
|
|
976
|
+
let offset = 0;
|
|
977
|
+
for (const chunk of chunks) {
|
|
978
|
+
result.set(chunk, offset);
|
|
979
|
+
offset += chunk.length;
|
|
980
|
+
}
|
|
981
|
+
return result;
|
|
982
|
+
}
|
|
983
|
+
function decodeBase64$2(input) {
|
|
984
|
+
if (typeof Buffer !== "undefined") {
|
|
985
|
+
const normalized = input.replace(/\s+/gu, "");
|
|
986
|
+
return new Uint8Array(Buffer.from(normalized, "base64"));
|
|
987
|
+
}
|
|
988
|
+
if (typeof atob === "function") {
|
|
989
|
+
const normalized = input.replace(/\s+/gu, "");
|
|
990
|
+
const binary = atob(normalized);
|
|
991
|
+
const bytes = new Uint8Array(binary.length);
|
|
992
|
+
for (let i = 0; i < binary.length; i += 1) {
|
|
993
|
+
bytes[i] = binary.charCodeAt(i);
|
|
994
|
+
}
|
|
995
|
+
return bytes;
|
|
996
|
+
}
|
|
997
|
+
throw new Error("No base64 decoder available in this environment");
|
|
998
|
+
}
|
|
999
|
+
function toHex(data) {
|
|
1000
|
+
return Array.from(data)
|
|
1001
|
+
.map((byte) => byte.toString(16).padStart(2, "0"))
|
|
1002
|
+
.join("");
|
|
1003
|
+
}
|
|
1004
|
+
function buildCacheKey(chainBytes, trustStorePem, enforceNameConstraints) {
|
|
1005
|
+
const chainHash = toHex(sha256(chainBytes));
|
|
1006
|
+
const trustHash = trustStorePem
|
|
1007
|
+
? toHex(sha256(textEncoder.encode(trustStorePem)))
|
|
1008
|
+
: "no-trust";
|
|
1009
|
+
const constraintFlag = enforceNameConstraints ? "nc1" : "nc0";
|
|
1010
|
+
return `${chainHash}|${trustHash}|${constraintFlag}`;
|
|
1011
|
+
}
|
|
1012
|
+
function getCachedPublicKey(cacheKey) {
|
|
1013
|
+
const entry = trustCache.get(cacheKey);
|
|
1014
|
+
if (!entry) {
|
|
1015
|
+
return null;
|
|
1016
|
+
}
|
|
1017
|
+
if (Date.now() > entry.expiresAt) {
|
|
1018
|
+
trustCache.delete(cacheKey);
|
|
1019
|
+
logger$g.debug("certificate_cache_expired", { cache_key: cacheKey });
|
|
1020
|
+
return null;
|
|
1021
|
+
}
|
|
1022
|
+
return entry.value.slice();
|
|
1023
|
+
}
|
|
1024
|
+
function setCachedPublicKey(cacheKey, value, notAfter) {
|
|
1025
|
+
while (trustCache.size >= CACHE_LIMIT) {
|
|
1026
|
+
const firstKey = trustCache.keys().next().value;
|
|
1027
|
+
if (firstKey === undefined) {
|
|
1028
|
+
break;
|
|
1029
|
+
}
|
|
1030
|
+
trustCache.delete(firstKey);
|
|
1031
|
+
logger$g.debug("certificate_cache_evicted", { cache_key: firstKey });
|
|
1032
|
+
}
|
|
1033
|
+
trustCache.set(cacheKey, {
|
|
1034
|
+
value: value.slice(),
|
|
1035
|
+
expiresAt: notAfter.getTime(),
|
|
1036
|
+
});
|
|
1037
|
+
logger$g.debug("certificate_cache_stored", {
|
|
1038
|
+
cache_key: cacheKey,
|
|
1039
|
+
expires_at: notAfter.toISOString(),
|
|
1040
|
+
cache_size: trustCache.size,
|
|
1041
|
+
});
|
|
1042
|
+
}
|
|
1043
|
+
function normalizeTrustStoreOption(value) {
|
|
1044
|
+
if (!value) {
|
|
1045
|
+
return null;
|
|
1046
|
+
}
|
|
1047
|
+
const trimmed = value.trim();
|
|
1048
|
+
if (trimmed.length === 0) {
|
|
1049
|
+
return null;
|
|
1050
|
+
}
|
|
1051
|
+
if (!trimmed.includes("-----BEGIN CERTIFICATE-----")) {
|
|
1052
|
+
throw new Error("trustStorePem must contain PEM-encoded certificates when provided");
|
|
1053
|
+
}
|
|
1054
|
+
return normalizePem$2(trimmed);
|
|
1055
|
+
}
|
|
1056
|
+
function normalizePem$2(pem) {
|
|
1057
|
+
return pem.replace(/\r/gu, "").trim();
|
|
1058
|
+
}
|
|
1059
|
+
function generateCallId() {
|
|
1060
|
+
return Math.random().toString(36).slice(2, 10);
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
const GRANT_PURPOSE_CA_SIGN = "ca_sign";
|
|
1064
|
+
|
|
1065
|
+
const ED25519_OID$2 = "1.3.101.112";
|
|
1066
|
+
const OID_COMMON_NAME$2 = "2.5.4.3";
|
|
1067
|
+
const LOGICAL_URI_PREFIX$1 = "naylence://";
|
|
1068
|
+
function ensureSubtleCrypto() {
|
|
1069
|
+
const instance = globalThis.crypto?.subtle;
|
|
1070
|
+
if (!instance) {
|
|
1071
|
+
throw new Error("WebCrypto subtle API is required to create a CSR");
|
|
1072
|
+
}
|
|
1073
|
+
return instance;
|
|
1074
|
+
}
|
|
1075
|
+
function buildSubject(commonName) {
|
|
1076
|
+
if (!commonName || typeof commonName !== "string") {
|
|
1077
|
+
throw new Error("commonName must be a non-empty string");
|
|
1078
|
+
}
|
|
1079
|
+
return new Name([
|
|
1080
|
+
new RelativeDistinguishedName([
|
|
1081
|
+
new AttributeTypeAndValue({
|
|
1082
|
+
type: OID_COMMON_NAME$2,
|
|
1083
|
+
value: new AttributeValue({ utf8String: commonName }),
|
|
1084
|
+
}),
|
|
1085
|
+
]),
|
|
1086
|
+
]);
|
|
1087
|
+
}
|
|
1088
|
+
function arrayBufferToBase64(buffer) {
|
|
1089
|
+
const bytes = new Uint8Array(buffer);
|
|
1090
|
+
if (typeof globalThis.Buffer?.from === "function") {
|
|
1091
|
+
return globalThis.Buffer.from(bytes).toString("base64");
|
|
1092
|
+
}
|
|
1093
|
+
let binary = "";
|
|
1094
|
+
const chunkSize = 0x8000;
|
|
1095
|
+
for (let offset = 0; offset < bytes.length; offset += chunkSize) {
|
|
1096
|
+
const slice = bytes.subarray(offset, offset + chunkSize);
|
|
1097
|
+
binary += String.fromCharCode(...slice);
|
|
1098
|
+
}
|
|
1099
|
+
if (typeof globalThis.btoa !== "function") {
|
|
1100
|
+
throw new Error("Base64 encoding not available in this environment");
|
|
1101
|
+
}
|
|
1102
|
+
return globalThis.btoa(binary);
|
|
1103
|
+
}
|
|
1104
|
+
function derToPem$1(der, label) {
|
|
1105
|
+
const base64 = arrayBufferToBase64(der);
|
|
1106
|
+
const lines = [];
|
|
1107
|
+
for (let index = 0; index < base64.length; index += 64) {
|
|
1108
|
+
lines.push(base64.slice(index, index + 64));
|
|
1109
|
+
}
|
|
1110
|
+
return `-----BEGIN ${label}-----\n${lines.join("\n")}\n-----END ${label}-----\n`;
|
|
1111
|
+
}
|
|
1112
|
+
async function createEd25519Csr(options) {
|
|
1113
|
+
const subtle = ensureSubtleCrypto();
|
|
1114
|
+
const { privateKey, publicKey, commonName } = options;
|
|
1115
|
+
if (!(privateKey instanceof CryptoKey) || privateKey.type !== "private") {
|
|
1116
|
+
throw new Error("privateKey must be a CryptoKey of type 'private'");
|
|
1117
|
+
}
|
|
1118
|
+
if (!(publicKey instanceof CryptoKey) || publicKey.type !== "public") {
|
|
1119
|
+
throw new Error("publicKey must be a CryptoKey of type 'public'");
|
|
1120
|
+
}
|
|
1121
|
+
const subject = buildSubject(commonName);
|
|
1122
|
+
const spkiDer = await subtle.exportKey("spki", publicKey);
|
|
1123
|
+
const subjectPublicKeyInfo = AsnConvert.parse(spkiDer, SubjectPublicKeyInfo);
|
|
1124
|
+
const attributes = new Attributes();
|
|
1125
|
+
const sanitizedLogicals = Array.isArray(options.logicals)
|
|
1126
|
+
? options.logicals
|
|
1127
|
+
.map((logical) => logical.trim())
|
|
1128
|
+
.filter((logical) => logical.length > 0)
|
|
1129
|
+
: [];
|
|
1130
|
+
if (sanitizedLogicals.length > 0) {
|
|
1131
|
+
const san = new SubjectAlternativeName(sanitizedLogicals.map((logical) => new GeneralName({
|
|
1132
|
+
uniformResourceIdentifier: `${LOGICAL_URI_PREFIX$1}${logical}`,
|
|
1133
|
+
})));
|
|
1134
|
+
const extensions = new Extensions([
|
|
1135
|
+
new Extension({
|
|
1136
|
+
extnID: id_ce_subjectAltName,
|
|
1137
|
+
critical: false,
|
|
1138
|
+
extnValue: new OctetString(AsnConvert.serialize(san)),
|
|
611
1139
|
}),
|
|
612
1140
|
]);
|
|
613
1141
|
attributes.push(new Attribute({
|
|
@@ -686,7 +1214,7 @@ const NODE_ID_OID = "1.3.6.1.4.1.58530.4";
|
|
|
686
1214
|
* Provides async HTTP client to request certificates from the CA signing service.
|
|
687
1215
|
*/
|
|
688
1216
|
// Simple logger for now - TODO: integrate with runtime logging
|
|
689
|
-
const logger$
|
|
1217
|
+
const logger$f = {
|
|
690
1218
|
debug: (_event, _meta) => {
|
|
691
1219
|
// console.log(`[DEBUG] ${event}`, meta);
|
|
692
1220
|
},
|
|
@@ -1135,7 +1663,7 @@ class CAServiceClient {
|
|
|
1135
1663
|
logicals: logicals || [],
|
|
1136
1664
|
};
|
|
1137
1665
|
const url = `${this.connectionGrant.url.replace(/\/$/, "")}/sign`;
|
|
1138
|
-
logger$
|
|
1666
|
+
logger$f.debug("requesting_certificate", {
|
|
1139
1667
|
requester_id: requesterId,
|
|
1140
1668
|
ca_service_url: url,
|
|
1141
1669
|
physical_path: physicalPath,
|
|
@@ -1164,13 +1692,13 @@ class CAServiceClient {
|
|
|
1164
1692
|
const result = await response.json();
|
|
1165
1693
|
const certificatePem = result.certificate_pem;
|
|
1166
1694
|
const certificateChainPem = result.certificate_chain_pem || certificatePem;
|
|
1167
|
-
logger$
|
|
1695
|
+
logger$f.debug("certificate_request_successful", {
|
|
1168
1696
|
requester_id: requesterId,
|
|
1169
1697
|
expires_at: result.expires_at,
|
|
1170
1698
|
});
|
|
1171
1699
|
// Extract and log certificate information with structured logging
|
|
1172
1700
|
const certInfo = extractCertificateInfo(certificatePem);
|
|
1173
|
-
logger$
|
|
1701
|
+
logger$f.debug("certificate_details", {
|
|
1174
1702
|
requester_id: requesterId,
|
|
1175
1703
|
certificate_type: "issued_certificate",
|
|
1176
1704
|
...certInfo,
|
|
@@ -1189,7 +1717,7 @@ class CAServiceClient {
|
|
|
1189
1717
|
// First cert in chain is usually the issued certificate
|
|
1190
1718
|
if (certPemBlock.trim() !== certificatePem.trim()) {
|
|
1191
1719
|
const chainCertInfo = extractCertificateInfo(certPemBlock);
|
|
1192
|
-
logger$
|
|
1720
|
+
logger$f.debug("certificate_chain_details", {
|
|
1193
1721
|
requester_id: requesterId,
|
|
1194
1722
|
certificate_type: "certificate_chain",
|
|
1195
1723
|
chain_index: i,
|
|
@@ -1200,7 +1728,7 @@ class CAServiceClient {
|
|
|
1200
1728
|
else {
|
|
1201
1729
|
// Subsequent certs are intermediate/root CAs
|
|
1202
1730
|
const caCertInfo = extractCertificateInfo(certPemBlock);
|
|
1203
|
-
logger$
|
|
1731
|
+
logger$f.debug("certificate_chain_details", {
|
|
1204
1732
|
requester_id: requesterId,
|
|
1205
1733
|
certificate_type: "ca_certificate",
|
|
1206
1734
|
chain_index: i,
|
|
@@ -1228,7 +1756,7 @@ class CAServiceClient {
|
|
|
1228
1756
|
// Body read failed entirely
|
|
1229
1757
|
errorDetail = `HTTP ${response.status}`;
|
|
1230
1758
|
}
|
|
1231
|
-
logger$
|
|
1759
|
+
logger$f.error("certificate_request_failed", {
|
|
1232
1760
|
requester_id: requesterId,
|
|
1233
1761
|
status_code: response.status,
|
|
1234
1762
|
error: errorDetail,
|
|
@@ -1245,13 +1773,13 @@ class CAServiceClient {
|
|
|
1245
1773
|
throw error;
|
|
1246
1774
|
}
|
|
1247
1775
|
if (error instanceof Error && error.name === "AbortError") {
|
|
1248
|
-
logger$
|
|
1776
|
+
logger$f.error("certificate_request_timeout", {
|
|
1249
1777
|
requester_id: requesterId,
|
|
1250
1778
|
timeout_seconds: this.timeoutSeconds,
|
|
1251
1779
|
});
|
|
1252
1780
|
throw new CertificateRequestError(`Certificate request timed out after ${this.timeoutSeconds} seconds`);
|
|
1253
1781
|
}
|
|
1254
|
-
logger$
|
|
1782
|
+
logger$f.error("certificate_request_network_error", {
|
|
1255
1783
|
requester_id: requesterId,
|
|
1256
1784
|
error: String(error),
|
|
1257
1785
|
});
|
|
@@ -1260,7 +1788,7 @@ class CAServiceClient {
|
|
|
1260
1788
|
}
|
|
1261
1789
|
}
|
|
1262
1790
|
|
|
1263
|
-
const logger$
|
|
1791
|
+
const logger$e = getLogger("naylence.fame.security.encryption.sealed.x25519_encryption_manager");
|
|
1264
1792
|
class X25519EncryptionManager {
|
|
1265
1793
|
constructor({ keyProvider, nodeLike = null, cryptoProvider = null, }) {
|
|
1266
1794
|
this.pendingEnvelopes = new Map();
|
|
@@ -1277,7 +1805,7 @@ class X25519EncryptionManager {
|
|
|
1277
1805
|
// KeyManagementHandler will queue the envelope and send KeyRequest.
|
|
1278
1806
|
// X25519 should NOT queue here to avoid dual queueing.
|
|
1279
1807
|
if (opts?.requestAddress) {
|
|
1280
|
-
logger$
|
|
1808
|
+
logger$e.debug("key_not_found_delegating_to_key_management", {
|
|
1281
1809
|
envelope_id: envelope.id,
|
|
1282
1810
|
request_address: String(opts.requestAddress),
|
|
1283
1811
|
});
|
|
@@ -1293,7 +1821,7 @@ class X25519EncryptionManager {
|
|
|
1293
1821
|
return await this.encryptWithKey(envelope, recipPub, recipKid);
|
|
1294
1822
|
}
|
|
1295
1823
|
catch (error) {
|
|
1296
|
-
logger$
|
|
1824
|
+
logger$e.error("x25519_encryption_failed", {
|
|
1297
1825
|
error: error instanceof Error ? error.message : String(error),
|
|
1298
1826
|
});
|
|
1299
1827
|
return EncryptionResult.skipped(envelope);
|
|
@@ -1331,20 +1859,20 @@ class X25519EncryptionManager {
|
|
|
1331
1859
|
return envelope;
|
|
1332
1860
|
}
|
|
1333
1861
|
catch (error) {
|
|
1334
|
-
logger$
|
|
1862
|
+
logger$e.error("x25519_decryption_failed", {
|
|
1335
1863
|
error: error instanceof Error ? error.message : String(error),
|
|
1336
1864
|
});
|
|
1337
1865
|
return envelope;
|
|
1338
1866
|
}
|
|
1339
1867
|
}
|
|
1340
1868
|
async notifyKeyAvailable(keyId) {
|
|
1341
|
-
logger$
|
|
1869
|
+
logger$e.debug("x25519_notify_key_available_called", {
|
|
1342
1870
|
key_id: keyId,
|
|
1343
1871
|
pending_keys: Array.from(this.pendingEnvelopes.keys()),
|
|
1344
1872
|
});
|
|
1345
1873
|
const queued = this.pendingEnvelopes.get(keyId);
|
|
1346
1874
|
if (!queued || queued.length === 0) {
|
|
1347
|
-
logger$
|
|
1875
|
+
logger$e.debug("no_queued_envelopes_for_key", {
|
|
1348
1876
|
key_id: keyId,
|
|
1349
1877
|
has_queue: this.pendingEnvelopes.has(keyId),
|
|
1350
1878
|
queue_length: queued?.length ?? 0,
|
|
@@ -1356,13 +1884,13 @@ class X25519EncryptionManager {
|
|
|
1356
1884
|
this.keyRequestsInProgress.delete(keyId);
|
|
1357
1885
|
const node = this.nodeLike;
|
|
1358
1886
|
if (!node) {
|
|
1359
|
-
logger$
|
|
1887
|
+
logger$e.debug("discarding_queued_envelopes_no_node", {
|
|
1360
1888
|
key_id: keyId,
|
|
1361
1889
|
count: queued.length,
|
|
1362
1890
|
});
|
|
1363
1891
|
return;
|
|
1364
1892
|
}
|
|
1365
|
-
logger$
|
|
1893
|
+
logger$e.debug("replaying_envelopes_for_key", {
|
|
1366
1894
|
key_id: keyId,
|
|
1367
1895
|
count: queued.length,
|
|
1368
1896
|
});
|
|
@@ -1371,7 +1899,7 @@ class X25519EncryptionManager {
|
|
|
1371
1899
|
await node.deliver(envelope);
|
|
1372
1900
|
}
|
|
1373
1901
|
catch (error) {
|
|
1374
|
-
logger$
|
|
1902
|
+
logger$e.error("failed_to_replay_envelope", {
|
|
1375
1903
|
key_id: keyId,
|
|
1376
1904
|
envelope_id: envelope.id,
|
|
1377
1905
|
error: error instanceof Error ? error.message : String(error),
|
|
@@ -1472,7 +2000,7 @@ class X25519EncryptionManager {
|
|
|
1472
2000
|
? this.extractPrivateKeyFromRecord(providerRecord)
|
|
1473
2001
|
: null;
|
|
1474
2002
|
if (providerRecordKey) {
|
|
1475
|
-
logger$
|
|
2003
|
+
logger$e.debug("using_provider_key_record_private_key", {
|
|
1476
2004
|
kid,
|
|
1477
2005
|
provider_key_id: providerKeyId,
|
|
1478
2006
|
mismatched_kid: kid && providerKeyId !== kid ? kid : null,
|
|
@@ -1482,7 +2010,7 @@ class X25519EncryptionManager {
|
|
|
1482
2010
|
}
|
|
1483
2011
|
if (!providerPem) {
|
|
1484
2012
|
if (kid && providerKeyId && providerKeyId !== kid) {
|
|
1485
|
-
logger$
|
|
2013
|
+
logger$e.debug("crypto_provider_key_id_mismatch_no_private_key", {
|
|
1486
2014
|
kid,
|
|
1487
2015
|
provider_key_id: providerKeyId,
|
|
1488
2016
|
});
|
|
@@ -1494,13 +2022,13 @@ class X25519EncryptionManager {
|
|
|
1494
2022
|
return null;
|
|
1495
2023
|
}
|
|
1496
2024
|
if (!kid || providerKeyId === kid) {
|
|
1497
|
-
logger$
|
|
2025
|
+
logger$e.debug("using_crypto_provider_private_key_fallback", {
|
|
1498
2026
|
kid: kid ?? null,
|
|
1499
2027
|
provider_key_id: providerKeyId,
|
|
1500
2028
|
});
|
|
1501
2029
|
}
|
|
1502
2030
|
else {
|
|
1503
|
-
logger$
|
|
2031
|
+
logger$e.warning("crypto_provider_key_id_mismatch_using_private_key", {
|
|
1504
2032
|
kid,
|
|
1505
2033
|
provider_key_id: providerKeyId,
|
|
1506
2034
|
key_record_present: Boolean(record),
|
|
@@ -1509,7 +2037,7 @@ class X25519EncryptionManager {
|
|
|
1509
2037
|
return fallbackKey;
|
|
1510
2038
|
}
|
|
1511
2039
|
async queueEnvelopeForKey(envelope, opts, recipientKeyId) {
|
|
1512
|
-
logger$
|
|
2040
|
+
logger$e.debug("queueing_envelope_for_sealed_encryption", {
|
|
1513
2041
|
envelope_id: envelope.id,
|
|
1514
2042
|
recipient_key_id: recipientKeyId,
|
|
1515
2043
|
request_address: opts?.requestAddress
|
|
@@ -1557,7 +2085,7 @@ class X25519EncryptionManager {
|
|
|
1557
2085
|
await node.deliver(keyRequestEnvelope, context);
|
|
1558
2086
|
}
|
|
1559
2087
|
catch (error) {
|
|
1560
|
-
logger$
|
|
2088
|
+
logger$e.error("failed_to_request_recipient_key", {
|
|
1561
2089
|
recipient_key_id: recipientKeyId,
|
|
1562
2090
|
error: error instanceof Error ? error.message : String(error),
|
|
1563
2091
|
});
|
|
@@ -1570,7 +2098,7 @@ class X25519EncryptionManager {
|
|
|
1570
2098
|
return this.extractPublicKeyFromRecord(record);
|
|
1571
2099
|
}
|
|
1572
2100
|
catch (error) {
|
|
1573
|
-
logger$
|
|
2101
|
+
logger$e.debug("recipient_key_lookup_failed", {
|
|
1574
2102
|
kid,
|
|
1575
2103
|
error: error instanceof Error ? error.message : String(error),
|
|
1576
2104
|
});
|
|
@@ -1585,7 +2113,7 @@ class X25519EncryptionManager {
|
|
|
1585
2113
|
return await this.keyProvider.getKey(kid);
|
|
1586
2114
|
}
|
|
1587
2115
|
catch (error) {
|
|
1588
|
-
logger$
|
|
2116
|
+
logger$e.debug("private_key_lookup_failed", {
|
|
1589
2117
|
kid,
|
|
1590
2118
|
error: error instanceof Error ? error.message : String(error),
|
|
1591
2119
|
});
|
|
@@ -1656,7 +2184,7 @@ class X25519EncryptionManager {
|
|
|
1656
2184
|
const base64 = base64Lines.join("");
|
|
1657
2185
|
const der = this.decodeBase64Flexible(base64);
|
|
1658
2186
|
if (!der) {
|
|
1659
|
-
logger$
|
|
2187
|
+
logger$e.debug("pem_decode_failed", {
|
|
1660
2188
|
key_type: keyType,
|
|
1661
2189
|
});
|
|
1662
2190
|
return null;
|
|
@@ -1889,7 +2417,7 @@ var index$1 = /*#__PURE__*/Object.freeze({
|
|
|
1889
2417
|
X25519EncryptionManagerFactory: X25519EncryptionManagerFactory
|
|
1890
2418
|
});
|
|
1891
2419
|
|
|
1892
|
-
const logger$
|
|
2420
|
+
const logger$d = getLogger("naylence.fame.security.encryption.channel.channel_encryption_manager");
|
|
1893
2421
|
const SUPPORTED_CHANNEL_ALGORITHMS = ["chacha20-poly1305-channel"];
|
|
1894
2422
|
const CHANNEL_ENCRYPTION_ALGORITHM = "chacha20-poly1305-channel";
|
|
1895
2423
|
const HANDSHAKE_ALGORITHM = "CHACHA20P1305";
|
|
@@ -2040,13 +2568,13 @@ class ChannelEncryptionManager {
|
|
|
2040
2568
|
const destination = opts?.destination ?? envelope.to ?? null;
|
|
2041
2569
|
const destinationStr = toDestinationString(destination);
|
|
2042
2570
|
if (!destinationStr) {
|
|
2043
|
-
logger$
|
|
2571
|
+
logger$d.warning("no_destination_for_channel_encryption", {
|
|
2044
2572
|
envelope_id: envelope.id,
|
|
2045
2573
|
});
|
|
2046
2574
|
return EncryptionResult.skipped(envelope);
|
|
2047
2575
|
}
|
|
2048
2576
|
if (!this.secureChannelManager) {
|
|
2049
|
-
logger$
|
|
2577
|
+
logger$d.warning("no_secure_channel_manager_available", {
|
|
2050
2578
|
envelope_id: envelope.id,
|
|
2051
2579
|
});
|
|
2052
2580
|
return EncryptionResult.skipped(envelope);
|
|
@@ -2057,7 +2585,7 @@ class ChannelEncryptionManager {
|
|
|
2057
2585
|
return this.encryptWithChannel(envelope, existingChannelId);
|
|
2058
2586
|
}
|
|
2059
2587
|
catch (error) {
|
|
2060
|
-
logger$
|
|
2588
|
+
logger$d.error("channel_encryption_failed", {
|
|
2061
2589
|
error: error instanceof Error ? error.message : String(error),
|
|
2062
2590
|
channel_id: existingChannelId,
|
|
2063
2591
|
});
|
|
@@ -2085,35 +2613,35 @@ class ChannelEncryptionManager {
|
|
|
2085
2613
|
}
|
|
2086
2614
|
const channelId = encHeader.kid;
|
|
2087
2615
|
if (!channelId) {
|
|
2088
|
-
logger$
|
|
2616
|
+
logger$d.error("missing_channel_id_in_encryption_header", {
|
|
2089
2617
|
envelope_id: envelope.id,
|
|
2090
2618
|
});
|
|
2091
2619
|
return envelope;
|
|
2092
2620
|
}
|
|
2093
2621
|
const nonce = this.decodeNonceValue(encHeader.val ?? "");
|
|
2094
2622
|
if (!nonce) {
|
|
2095
|
-
logger$
|
|
2623
|
+
logger$d.error("invalid_nonce_in_encryption_header", {
|
|
2096
2624
|
envelope_id: envelope.id,
|
|
2097
2625
|
value_present: Boolean(encHeader.val),
|
|
2098
2626
|
});
|
|
2099
2627
|
return envelope;
|
|
2100
2628
|
}
|
|
2101
2629
|
if (!this.secureChannelManager) {
|
|
2102
|
-
logger$
|
|
2630
|
+
logger$d.warning("no_secure_channel_manager_for_decryption", {
|
|
2103
2631
|
envelope_id: envelope.id,
|
|
2104
2632
|
});
|
|
2105
2633
|
return envelope;
|
|
2106
2634
|
}
|
|
2107
2635
|
const channelState = this.getChannelState(channelId);
|
|
2108
2636
|
if (!channelState) {
|
|
2109
|
-
logger$
|
|
2637
|
+
logger$d.error("channel_not_available_for_decryption", {
|
|
2110
2638
|
channel_id: channelId,
|
|
2111
2639
|
});
|
|
2112
2640
|
return envelope;
|
|
2113
2641
|
}
|
|
2114
2642
|
const ciphertext = this.extractCiphertext(frame.payload);
|
|
2115
2643
|
if (!ciphertext) {
|
|
2116
|
-
logger$
|
|
2644
|
+
logger$d.error("invalid_ciphertext_payload", { envelope_id: envelope.id });
|
|
2117
2645
|
return envelope;
|
|
2118
2646
|
}
|
|
2119
2647
|
try {
|
|
@@ -2138,7 +2666,7 @@ class ChannelEncryptionManager {
|
|
|
2138
2666
|
return envelope;
|
|
2139
2667
|
}
|
|
2140
2668
|
catch (error) {
|
|
2141
|
-
logger$
|
|
2669
|
+
logger$d.error("channel_decryption_failed", {
|
|
2142
2670
|
channel_id: channelId,
|
|
2143
2671
|
error: error instanceof Error ? error.message : String(error),
|
|
2144
2672
|
});
|
|
@@ -2146,24 +2674,24 @@ class ChannelEncryptionManager {
|
|
|
2146
2674
|
}
|
|
2147
2675
|
}
|
|
2148
2676
|
async notifyChannelEstablished(channelId) {
|
|
2149
|
-
logger$
|
|
2677
|
+
logger$d.debug("channel_encryption_manager_notified", {
|
|
2150
2678
|
channel_id: channelId,
|
|
2151
2679
|
manager_type: "channel",
|
|
2152
2680
|
});
|
|
2153
2681
|
if (!channelId.startsWith("auto-")) {
|
|
2154
|
-
logger$
|
|
2682
|
+
logger$d.warning("unexpected_channel_id_format", { channel_id: channelId });
|
|
2155
2683
|
return;
|
|
2156
2684
|
}
|
|
2157
2685
|
const destinationStr = this.extractDestinationFromChannelId(channelId);
|
|
2158
2686
|
if (!destinationStr) {
|
|
2159
|
-
logger$
|
|
2687
|
+
logger$d.warning("cannot_parse_destination_from_channel_id", {
|
|
2160
2688
|
channel_id: channelId,
|
|
2161
2689
|
});
|
|
2162
2690
|
return;
|
|
2163
2691
|
}
|
|
2164
2692
|
this.handshakeInProgress.delete(destinationStr);
|
|
2165
2693
|
if (!this.pendingEnvelopes.has(destinationStr)) {
|
|
2166
|
-
logger$
|
|
2694
|
+
logger$d.debug("no_pending_queue_for_destination", {
|
|
2167
2695
|
destination: destinationStr,
|
|
2168
2696
|
});
|
|
2169
2697
|
return;
|
|
@@ -2171,7 +2699,7 @@ class ChannelEncryptionManager {
|
|
|
2171
2699
|
const queuedEnvelopes = this.pendingEnvelopes.get(destinationStr) ?? [];
|
|
2172
2700
|
this.pendingEnvelopes.delete(destinationStr);
|
|
2173
2701
|
if (!this.secureChannelManager) {
|
|
2174
|
-
logger$
|
|
2702
|
+
logger$d.error("no_secure_channel_manager_for_queue_drain", {
|
|
2175
2703
|
channel_id: channelId,
|
|
2176
2704
|
});
|
|
2177
2705
|
return;
|
|
@@ -2180,7 +2708,7 @@ class ChannelEncryptionManager {
|
|
|
2180
2708
|
try {
|
|
2181
2709
|
const result = this.encryptWithChannel(envelope, channelId);
|
|
2182
2710
|
if (!result.envelope) {
|
|
2183
|
-
logger$
|
|
2711
|
+
logger$d.warning("failed_to_encrypt_queued_envelope", {
|
|
2184
2712
|
envelope_id: envelope.id,
|
|
2185
2713
|
channel_id: channelId,
|
|
2186
2714
|
});
|
|
@@ -2190,7 +2718,7 @@ class ChannelEncryptionManager {
|
|
|
2190
2718
|
this.runAsyncTask(() => this.deliverEnvelope(encryptedEnvelope), `deliver-queued-${envelope.id}`);
|
|
2191
2719
|
}
|
|
2192
2720
|
catch (error) {
|
|
2193
|
-
logger$
|
|
2721
|
+
logger$d.error("failed_to_encrypt_queued_envelope", {
|
|
2194
2722
|
envelope_id: envelope.id,
|
|
2195
2723
|
error: error instanceof Error ? error.message : String(error),
|
|
2196
2724
|
});
|
|
@@ -2198,19 +2726,19 @@ class ChannelEncryptionManager {
|
|
|
2198
2726
|
}
|
|
2199
2727
|
}
|
|
2200
2728
|
async notifyChannelFailed(channelId, reason = "handshake_failed") {
|
|
2201
|
-
logger$
|
|
2729
|
+
logger$d.debug("channel_encryption_manager_notified_failure", {
|
|
2202
2730
|
channel_id: channelId,
|
|
2203
2731
|
reason,
|
|
2204
2732
|
});
|
|
2205
2733
|
if (!channelId.startsWith("auto-")) {
|
|
2206
|
-
logger$
|
|
2734
|
+
logger$d.warning("unexpected_channel_id_format_on_failure", {
|
|
2207
2735
|
channel_id: channelId,
|
|
2208
2736
|
});
|
|
2209
2737
|
return;
|
|
2210
2738
|
}
|
|
2211
2739
|
const destinationStr = this.extractDestinationFromChannelId(channelId);
|
|
2212
2740
|
if (!destinationStr) {
|
|
2213
|
-
logger$
|
|
2741
|
+
logger$d.warning("cannot_parse_destination_from_channel_id_on_failure", {
|
|
2214
2742
|
channel_id: channelId,
|
|
2215
2743
|
});
|
|
2216
2744
|
return;
|
|
@@ -2220,14 +2748,14 @@ class ChannelEncryptionManager {
|
|
|
2220
2748
|
const cachedChannelId = this.addrChannelMap.get(destinationStr);
|
|
2221
2749
|
if (cachedChannelId === channelId) {
|
|
2222
2750
|
this.addrChannelMap.delete(destinationStr);
|
|
2223
|
-
logger$
|
|
2751
|
+
logger$d.debug("cleared_channel_cache_for_failed_channel", {
|
|
2224
2752
|
destination: destinationStr,
|
|
2225
2753
|
channel_id: channelId,
|
|
2226
2754
|
});
|
|
2227
2755
|
}
|
|
2228
2756
|
const queuedEnvelopes = this.pendingEnvelopes.get(destinationStr);
|
|
2229
2757
|
if (!queuedEnvelopes || queuedEnvelopes.length === 0) {
|
|
2230
|
-
logger$
|
|
2758
|
+
logger$d.debug("no_pending_queue_for_failed_destination", {
|
|
2231
2759
|
destination: destinationStr,
|
|
2232
2760
|
});
|
|
2233
2761
|
return;
|
|
@@ -2246,7 +2774,7 @@ class ChannelEncryptionManager {
|
|
|
2246
2774
|
const cached = this.addrChannelMap.get(destination);
|
|
2247
2775
|
if (cached) {
|
|
2248
2776
|
this.addrChannelMap.delete(destination);
|
|
2249
|
-
logger$
|
|
2777
|
+
logger$d.debug("cleared_channel_cache_for_destination", {
|
|
2250
2778
|
destination,
|
|
2251
2779
|
cached_channel_id: cached,
|
|
2252
2780
|
});
|
|
@@ -2264,14 +2792,14 @@ class ChannelEncryptionManager {
|
|
|
2264
2792
|
}
|
|
2265
2793
|
const cached = this.addrChannelMap.get(destination);
|
|
2266
2794
|
if (cached && this.getChannelState(cached)) {
|
|
2267
|
-
logger$
|
|
2795
|
+
logger$d.debug("using_cached_channel", { destination, channel_id: cached });
|
|
2268
2796
|
return cached;
|
|
2269
2797
|
}
|
|
2270
2798
|
const channels = this.secureChannelManager.channels;
|
|
2271
2799
|
for (const channelId of Object.keys(channels)) {
|
|
2272
2800
|
if (channelId.startsWith(`auto-${destination}-`)) {
|
|
2273
2801
|
this.addrChannelMap.set(destination, channelId);
|
|
2274
|
-
logger$
|
|
2802
|
+
logger$d.debug("using_existing_channel", {
|
|
2275
2803
|
destination,
|
|
2276
2804
|
channel_id: channelId,
|
|
2277
2805
|
});
|
|
@@ -2284,12 +2812,12 @@ class ChannelEncryptionManager {
|
|
|
2284
2812
|
const queue = this.pendingEnvelopes.get(destinationStr) ?? [];
|
|
2285
2813
|
queue.push(envelope);
|
|
2286
2814
|
this.pendingEnvelopes.set(destinationStr, queue);
|
|
2287
|
-
logger$
|
|
2815
|
+
logger$d.debug("queued_envelope_for_channel_handshake", {
|
|
2288
2816
|
envelope_id: envelope.id,
|
|
2289
2817
|
destination: destinationStr,
|
|
2290
2818
|
});
|
|
2291
2819
|
if (this.handshakeInProgress.has(destinationStr)) {
|
|
2292
|
-
logger$
|
|
2820
|
+
logger$d.debug("handshake_already_in_progress", {
|
|
2293
2821
|
destination: destinationStr,
|
|
2294
2822
|
});
|
|
2295
2823
|
return;
|
|
@@ -2308,7 +2836,7 @@ class ChannelEncryptionManager {
|
|
|
2308
2836
|
async initiateChannelHandshakeAsync(destination, destinationStr, opts) {
|
|
2309
2837
|
void opts;
|
|
2310
2838
|
if (!this.secureChannelManager) {
|
|
2311
|
-
logger$
|
|
2839
|
+
logger$d.error("no_secure_channel_manager_for_async_handshake_initiation");
|
|
2312
2840
|
return;
|
|
2313
2841
|
}
|
|
2314
2842
|
const channelId = this.generateChannelId(destinationStr);
|
|
@@ -2316,19 +2844,19 @@ class ChannelEncryptionManager {
|
|
|
2316
2844
|
const openFrame = this.secureChannelManager.generateOpenFrame(channelId, HANDSHAKE_ALGORITHM);
|
|
2317
2845
|
const success = await this.sendSecureOpenFrameAsync(openFrame, destination);
|
|
2318
2846
|
if (success) {
|
|
2319
|
-
logger$
|
|
2847
|
+
logger$d.debug("sent_secure_open_frame_async", {
|
|
2320
2848
|
channel_id: channelId,
|
|
2321
2849
|
destination: destinationStr,
|
|
2322
2850
|
});
|
|
2323
2851
|
}
|
|
2324
2852
|
else {
|
|
2325
|
-
logger$
|
|
2853
|
+
logger$d.warning("failed_to_send_secure_open_frame_async", {
|
|
2326
2854
|
channel_id: channelId,
|
|
2327
2855
|
});
|
|
2328
2856
|
}
|
|
2329
2857
|
}
|
|
2330
2858
|
catch (error) {
|
|
2331
|
-
logger$
|
|
2859
|
+
logger$d.error("async_channel_handshake_initiation_failed", {
|
|
2332
2860
|
destination: destinationStr,
|
|
2333
2861
|
error: error instanceof Error ? error.message : String(error),
|
|
2334
2862
|
});
|
|
@@ -2337,22 +2865,22 @@ class ChannelEncryptionManager {
|
|
|
2337
2865
|
async sendSecureOpenFrameAsync(openFrame, destination) {
|
|
2338
2866
|
const node = this.nodeLike;
|
|
2339
2867
|
if (!node) {
|
|
2340
|
-
logger$
|
|
2868
|
+
logger$d.error("no_node_available_for_sending_secure_open_async");
|
|
2341
2869
|
return false;
|
|
2342
2870
|
}
|
|
2343
2871
|
const envelopeFactory = node.envelopeFactory;
|
|
2344
2872
|
if (!envelopeFactory) {
|
|
2345
|
-
logger$
|
|
2873
|
+
logger$d.error("no_envelope_factory_available_for_secure_open_async");
|
|
2346
2874
|
return false;
|
|
2347
2875
|
}
|
|
2348
2876
|
const replyTo = this.buildSystemReplyTo();
|
|
2349
2877
|
if (!replyTo) {
|
|
2350
|
-
logger$
|
|
2878
|
+
logger$d.error("no_physical_path_available_for_reply_to_async");
|
|
2351
2879
|
return false;
|
|
2352
2880
|
}
|
|
2353
2881
|
const toAddress = toFameAddress(destination);
|
|
2354
2882
|
if (!toAddress) {
|
|
2355
|
-
logger$
|
|
2883
|
+
logger$d.error("invalid_destination_for_secure_open", {
|
|
2356
2884
|
destination: String(destination),
|
|
2357
2885
|
});
|
|
2358
2886
|
return false;
|
|
@@ -2364,7 +2892,7 @@ class ChannelEncryptionManager {
|
|
|
2364
2892
|
corrId: generateId(),
|
|
2365
2893
|
});
|
|
2366
2894
|
await this.deliverEnvelope(envelope);
|
|
2367
|
-
logger$
|
|
2895
|
+
logger$d.debug("delivered_secure_open_frame_async", {
|
|
2368
2896
|
channel_id: openFrame.cid,
|
|
2369
2897
|
});
|
|
2370
2898
|
return true;
|
|
@@ -2372,7 +2900,7 @@ class ChannelEncryptionManager {
|
|
|
2372
2900
|
async deliverEnvelope(envelope) {
|
|
2373
2901
|
const node = this.nodeLike;
|
|
2374
2902
|
if (!node) {
|
|
2375
|
-
logger$
|
|
2903
|
+
logger$d.error("no_node_available_for_delivery", {
|
|
2376
2904
|
envelope_id: envelope.id,
|
|
2377
2905
|
});
|
|
2378
2906
|
return;
|
|
@@ -2382,19 +2910,19 @@ class ChannelEncryptionManager {
|
|
|
2382
2910
|
}
|
|
2383
2911
|
encryptWithChannel(envelope, channelId) {
|
|
2384
2912
|
if (!this.secureChannelManager) {
|
|
2385
|
-
logger$
|
|
2913
|
+
logger$d.error("no_secure_channel_manager_for_encryption");
|
|
2386
2914
|
return EncryptionResult.skipped(envelope);
|
|
2387
2915
|
}
|
|
2388
2916
|
const frame = envelope.frame;
|
|
2389
2917
|
if (!this.isDataFrame(frame)) {
|
|
2390
|
-
logger$
|
|
2918
|
+
logger$d.error("attempted_to_encrypt_non_dataframe", {
|
|
2391
2919
|
frame_type: frame.type ?? typeof frame,
|
|
2392
2920
|
});
|
|
2393
2921
|
return EncryptionResult.skipped(envelope);
|
|
2394
2922
|
}
|
|
2395
2923
|
const channelState = this.getChannelState(channelId);
|
|
2396
2924
|
if (!channelState) {
|
|
2397
|
-
logger$
|
|
2925
|
+
logger$d.error("channel_not_in_channels", { channel_id: channelId });
|
|
2398
2926
|
return EncryptionResult.skipped(envelope);
|
|
2399
2927
|
}
|
|
2400
2928
|
const payloadBytes = this.serializePayload(frame.payload);
|
|
@@ -2453,7 +2981,7 @@ class ChannelEncryptionManager {
|
|
|
2453
2981
|
return decodeBase64$1(payload);
|
|
2454
2982
|
}
|
|
2455
2983
|
catch (error) {
|
|
2456
|
-
logger$
|
|
2984
|
+
logger$d.error("failed_to_decode_base64_ciphertext", {
|
|
2457
2985
|
error: error instanceof Error ? error.message : String(error),
|
|
2458
2986
|
});
|
|
2459
2987
|
return null;
|
|
@@ -2483,7 +3011,7 @@ class ChannelEncryptionManager {
|
|
|
2483
3011
|
return parts.slice(1, -1).join("-");
|
|
2484
3012
|
}
|
|
2485
3013
|
async handleFailedEnvelope(envelope, destinationStr, channelId, reason) {
|
|
2486
|
-
logger$
|
|
3014
|
+
logger$d.warning("envelope_failed_due_to_channel_handshake_failure", {
|
|
2487
3015
|
envelope_id: envelope.id,
|
|
2488
3016
|
destination: destinationStr,
|
|
2489
3017
|
channel_id: channelId,
|
|
@@ -2491,14 +3019,14 @@ class ChannelEncryptionManager {
|
|
|
2491
3019
|
});
|
|
2492
3020
|
const frame = envelope.frame;
|
|
2493
3021
|
if (!this.isDataFrame(frame)) {
|
|
2494
|
-
logger$
|
|
3022
|
+
logger$d.debug("skipping_nack_for_non_dataframe", {
|
|
2495
3023
|
envelope_id: envelope.id,
|
|
2496
3024
|
frame_type: frame.type ?? typeof frame,
|
|
2497
3025
|
});
|
|
2498
3026
|
return;
|
|
2499
3027
|
}
|
|
2500
3028
|
if (!envelope.replyTo) {
|
|
2501
|
-
logger$
|
|
3029
|
+
logger$d.debug("skipping_nack_no_reply_to", { envelope_id: envelope.id });
|
|
2502
3030
|
return;
|
|
2503
3031
|
}
|
|
2504
3032
|
await this.sendDeliveryNack(envelope, `channel_handshake_failed: ${reason}`);
|
|
@@ -2506,17 +3034,17 @@ class ChannelEncryptionManager {
|
|
|
2506
3034
|
async sendDeliveryNack(envelope, failureReason) {
|
|
2507
3035
|
const node = this.nodeLike;
|
|
2508
3036
|
if (!node) {
|
|
2509
|
-
logger$
|
|
3037
|
+
logger$d.error("no_node_available_for_sending_delivery_nack");
|
|
2510
3038
|
return;
|
|
2511
3039
|
}
|
|
2512
3040
|
const envelopeFactory = node.envelopeFactory;
|
|
2513
3041
|
if (!envelopeFactory) {
|
|
2514
|
-
logger$
|
|
3042
|
+
logger$d.error("no_envelope_factory_available_for_delivery_nack");
|
|
2515
3043
|
return;
|
|
2516
3044
|
}
|
|
2517
3045
|
const replyTo = toFameAddress(envelope.replyTo ?? null);
|
|
2518
3046
|
if (!replyTo) {
|
|
2519
|
-
logger$
|
|
3047
|
+
logger$d.error("invalid_reply_to_for_delivery_nack", {
|
|
2520
3048
|
reply_to: envelope.replyTo,
|
|
2521
3049
|
});
|
|
2522
3050
|
return;
|
|
@@ -2533,7 +3061,7 @@ class ChannelEncryptionManager {
|
|
|
2533
3061
|
corrId: envelope.corrId ?? generateId(),
|
|
2534
3062
|
});
|
|
2535
3063
|
await this.deliverEnvelope(nackEnvelope);
|
|
2536
|
-
logger$
|
|
3064
|
+
logger$d.debug("delivered_delivery_nack", {
|
|
2537
3065
|
original_envelope_id: envelope.id,
|
|
2538
3066
|
nack_envelope_id: nackEnvelope.id,
|
|
2539
3067
|
});
|
|
@@ -2571,7 +3099,7 @@ class ChannelEncryptionManager {
|
|
|
2571
3099
|
await task();
|
|
2572
3100
|
}
|
|
2573
3101
|
catch (error) {
|
|
2574
|
-
logger$
|
|
3102
|
+
logger$d.error("async_task_failed", {
|
|
2575
3103
|
task_name: name,
|
|
2576
3104
|
error: error instanceof Error ? error.message : String(error),
|
|
2577
3105
|
});
|
|
@@ -2625,7 +3153,7 @@ class ChannelEncryptionManager {
|
|
|
2625
3153
|
}
|
|
2626
3154
|
}
|
|
2627
3155
|
|
|
2628
|
-
const logger$
|
|
3156
|
+
const logger$c = getLogger("naylence.fame.security.encryption.channel.channel_encryption_manager_factory");
|
|
2629
3157
|
const DEFAULT_SUPPORTED_ALGORITHMS = ["chacha20-poly1305-channel"];
|
|
2630
3158
|
const FACTORY_META$d = {
|
|
2631
3159
|
base: ENCRYPTION_MANAGER_FACTORY_BASE_TYPE,
|
|
@@ -2657,7 +3185,7 @@ class ChannelEncryptionManagerFactory extends EncryptionManagerFactory {
|
|
|
2657
3185
|
async create(_config, ...factoryArgs) {
|
|
2658
3186
|
const [dependencies] = factoryArgs;
|
|
2659
3187
|
const resolvedDependencies = this.resolveDependencies(dependencies);
|
|
2660
|
-
logger$
|
|
3188
|
+
logger$c.debug("creating_channel_encryption_manager", {
|
|
2661
3189
|
has_secure_channel_manager: Boolean(resolvedDependencies.secureChannelManager),
|
|
2662
3190
|
has_node_like: Boolean(resolvedDependencies.nodeLike),
|
|
2663
3191
|
has_task_spawner: Boolean(resolvedDependencies.taskSpawner),
|
|
@@ -2719,7 +3247,7 @@ var index = /*#__PURE__*/Object.freeze({
|
|
|
2719
3247
|
ChannelEncryptionManagerFactory: ChannelEncryptionManagerFactory
|
|
2720
3248
|
});
|
|
2721
3249
|
|
|
2722
|
-
const logger$
|
|
3250
|
+
const logger$b = getLogger("naylence.fame.security.encryption.default_secure_channel_manager");
|
|
2723
3251
|
const DEFAULT_ALGORITHM = "CHACHA20P1305";
|
|
2724
3252
|
const CHANNEL_KEY_LENGTH = 32;
|
|
2725
3253
|
const NONCE_PREFIX_LENGTH = 4;
|
|
@@ -2766,7 +3294,7 @@ class DefaultSecureChannelManager {
|
|
|
2766
3294
|
const privateKey = x25519.utils.randomSecretKey();
|
|
2767
3295
|
const publicKey = x25519.scalarMultBase(privateKey);
|
|
2768
3296
|
this.ephemeralKeys.set(channelId, privateKey);
|
|
2769
|
-
logger$
|
|
3297
|
+
logger$b.debug("generated_channel_open", { cid: channelId, algorithm });
|
|
2770
3298
|
return {
|
|
2771
3299
|
type: "SecureOpen",
|
|
2772
3300
|
cid: channelId,
|
|
@@ -2779,7 +3307,7 @@ class DefaultSecureChannelManager {
|
|
|
2779
3307
|
requireCryptoSupport();
|
|
2780
3308
|
const algorithm = frame.alg || DEFAULT_ALGORITHM;
|
|
2781
3309
|
if (!this.isSupportedAlgorithm(algorithm)) {
|
|
2782
|
-
logger$
|
|
3310
|
+
logger$b.warning("unsupported_channel_algorithm", {
|
|
2783
3311
|
cid: frame.cid,
|
|
2784
3312
|
alg: algorithm,
|
|
2785
3313
|
});
|
|
@@ -2797,7 +3325,7 @@ class DefaultSecureChannelManager {
|
|
|
2797
3325
|
peerPublicKey = decodeBase64(frame.ephPub);
|
|
2798
3326
|
}
|
|
2799
3327
|
catch (error) {
|
|
2800
|
-
logger$
|
|
3328
|
+
logger$b.warning("invalid_peer_public_key", {
|
|
2801
3329
|
cid: frame.cid,
|
|
2802
3330
|
error: error instanceof Error ? error.message : String(error),
|
|
2803
3331
|
});
|
|
@@ -2819,7 +3347,7 @@ class DefaultSecureChannelManager {
|
|
|
2819
3347
|
algorithm,
|
|
2820
3348
|
});
|
|
2821
3349
|
this.channelsMap.set(frame.cid, channelState);
|
|
2822
|
-
logger$
|
|
3350
|
+
logger$b.debug("channel_established", { cid: frame.cid, algorithm });
|
|
2823
3351
|
myPrivateKey.fill(0);
|
|
2824
3352
|
sharedSecret.fill(0);
|
|
2825
3353
|
return {
|
|
@@ -2833,7 +3361,7 @@ class DefaultSecureChannelManager {
|
|
|
2833
3361
|
async handleAcceptFrame(frame) {
|
|
2834
3362
|
requireCryptoSupport();
|
|
2835
3363
|
if (frame.ok === false) {
|
|
2836
|
-
logger$
|
|
3364
|
+
logger$b.warning("channel_rejected", {
|
|
2837
3365
|
cid: frame.cid,
|
|
2838
3366
|
error: frame.reason,
|
|
2839
3367
|
});
|
|
@@ -2842,7 +3370,7 @@ class DefaultSecureChannelManager {
|
|
|
2842
3370
|
}
|
|
2843
3371
|
const privateKey = this.ephemeralKeys.get(frame.cid);
|
|
2844
3372
|
if (!privateKey) {
|
|
2845
|
-
logger$
|
|
3373
|
+
logger$b.error("no_ephemeral_key", { cid: frame.cid });
|
|
2846
3374
|
return false;
|
|
2847
3375
|
}
|
|
2848
3376
|
let peerPublicKey;
|
|
@@ -2850,7 +3378,7 @@ class DefaultSecureChannelManager {
|
|
|
2850
3378
|
peerPublicKey = decodeBase64(frame.ephPub);
|
|
2851
3379
|
}
|
|
2852
3380
|
catch (error) {
|
|
2853
|
-
logger$
|
|
3381
|
+
logger$b.warning("invalid_accept_public_key", {
|
|
2854
3382
|
cid: frame.cid,
|
|
2855
3383
|
error: error instanceof Error ? error.message : String(error),
|
|
2856
3384
|
});
|
|
@@ -2865,17 +3393,17 @@ class DefaultSecureChannelManager {
|
|
|
2865
3393
|
algorithm,
|
|
2866
3394
|
});
|
|
2867
3395
|
this.channelsMap.set(frame.cid, channelState);
|
|
2868
|
-
logger$
|
|
3396
|
+
logger$b.debug("channel_completed", { cid: frame.cid, algorithm });
|
|
2869
3397
|
sharedSecret.fill(0);
|
|
2870
3398
|
this.cleanupEphemeralKey(frame.cid);
|
|
2871
3399
|
return true;
|
|
2872
3400
|
}
|
|
2873
3401
|
handleCloseFrame(frame) {
|
|
2874
3402
|
if (this.channelsMap.delete(frame.cid)) {
|
|
2875
|
-
logger$
|
|
3403
|
+
logger$b.debug("channel_closed", { cid: frame.cid, reason: frame.reason });
|
|
2876
3404
|
}
|
|
2877
3405
|
else {
|
|
2878
|
-
logger$
|
|
3406
|
+
logger$b.warning("close_unknown_channel", { cid: frame.cid });
|
|
2879
3407
|
}
|
|
2880
3408
|
this.cleanupEphemeralKey(frame.cid);
|
|
2881
3409
|
}
|
|
@@ -2902,7 +3430,7 @@ class DefaultSecureChannelManager {
|
|
|
2902
3430
|
}
|
|
2903
3431
|
closeChannel(channelId, reason = "User requested") {
|
|
2904
3432
|
if (this.channelsMap.delete(channelId)) {
|
|
2905
|
-
logger$
|
|
3433
|
+
logger$b.debug("channel_closed_by_user", { cid: channelId, reason });
|
|
2906
3434
|
}
|
|
2907
3435
|
this.cleanupEphemeralKey(channelId);
|
|
2908
3436
|
return {
|
|
@@ -2919,7 +3447,7 @@ class DefaultSecureChannelManager {
|
|
|
2919
3447
|
this.channelsMap.delete(channelId);
|
|
2920
3448
|
this.cleanupEphemeralKey(channelId);
|
|
2921
3449
|
removed += 1;
|
|
2922
|
-
logger$
|
|
3450
|
+
logger$b.debug("channel_expired_cleanup", { cid: channelId });
|
|
2923
3451
|
}
|
|
2924
3452
|
}
|
|
2925
3453
|
return removed;
|
|
@@ -2948,7 +3476,7 @@ class DefaultSecureChannelManager {
|
|
|
2948
3476
|
if (channelId.startsWith(prefix)) {
|
|
2949
3477
|
if (this.removeChannel(channelId)) {
|
|
2950
3478
|
removed += 1;
|
|
2951
|
-
logger$
|
|
3479
|
+
logger$b.debug("removed_channel_for_destination", {
|
|
2952
3480
|
channel_id: channelId,
|
|
2953
3481
|
destination,
|
|
2954
3482
|
});
|
|
@@ -2956,7 +3484,7 @@ class DefaultSecureChannelManager {
|
|
|
2956
3484
|
}
|
|
2957
3485
|
}
|
|
2958
3486
|
if (removed > 0) {
|
|
2959
|
-
logger$
|
|
3487
|
+
logger$b.info("cleanup_channels_for_destination", {
|
|
2960
3488
|
destination,
|
|
2961
3489
|
channels_removed: removed,
|
|
2962
3490
|
});
|
|
@@ -2996,222 +3524,58 @@ const FACTORY_META$c = {
|
|
|
2996
3524
|
base: SECURE_CHANNEL_MANAGER_FACTORY_BASE_TYPE,
|
|
2997
3525
|
key: "DefaultSecureChannelManager",
|
|
2998
3526
|
};
|
|
2999
|
-
class DefaultSecureChannelManagerFactory extends SecureChannelManagerFactory {
|
|
3000
|
-
constructor() {
|
|
3001
|
-
super(...arguments);
|
|
3002
|
-
this.type = "DefaultSecureChannelManager";
|
|
3003
|
-
this.isDefault = true;
|
|
3004
|
-
this.priority = 500;
|
|
3005
|
-
}
|
|
3006
|
-
async create(config = null) {
|
|
3007
|
-
const ttl = this.resolveChannelTtl(config);
|
|
3008
|
-
return new DefaultSecureChannelManager(ttl ? { channelTtlSeconds: ttl } : {});
|
|
3009
|
-
}
|
|
3010
|
-
getSupportedAlgorithms() {
|
|
3011
|
-
return ["CHACHA20P1305"];
|
|
3012
|
-
}
|
|
3013
|
-
resolveChannelTtl(config) {
|
|
3014
|
-
if (!config) {
|
|
3015
|
-
return undefined;
|
|
3016
|
-
}
|
|
3017
|
-
const candidates = [
|
|
3018
|
-
config.channelTtlSeconds,
|
|
3019
|
-
config.channelTtl,
|
|
3020
|
-
config.channel_ttl,
|
|
3021
|
-
config.channelTTL,
|
|
3022
|
-
];
|
|
3023
|
-
for (const candidate of candidates) {
|
|
3024
|
-
const normalized = this.toPositiveNumber(candidate);
|
|
3025
|
-
if (typeof normalized === "number") {
|
|
3026
|
-
return normalized;
|
|
3027
|
-
}
|
|
3028
|
-
}
|
|
3029
|
-
return undefined;
|
|
3030
|
-
}
|
|
3031
|
-
toPositiveNumber(value) {
|
|
3032
|
-
if (typeof value === "number" && Number.isFinite(value) && value > 0) {
|
|
3033
|
-
return value;
|
|
3034
|
-
}
|
|
3035
|
-
if (typeof value === "string" && value.trim() !== "") {
|
|
3036
|
-
const parsed = Number(value);
|
|
3037
|
-
if (Number.isFinite(parsed) && parsed > 0) {
|
|
3038
|
-
return parsed;
|
|
3039
|
-
}
|
|
3040
|
-
}
|
|
3041
|
-
return undefined;
|
|
3042
|
-
}
|
|
3043
|
-
}
|
|
3044
|
-
|
|
3045
|
-
var defaultSecureChannelManagerFactory = /*#__PURE__*/Object.freeze({
|
|
3046
|
-
__proto__: null,
|
|
3047
|
-
DefaultSecureChannelManagerFactory: DefaultSecureChannelManagerFactory,
|
|
3048
|
-
FACTORY_META: FACTORY_META$c,
|
|
3049
|
-
default: DefaultSecureChannelManagerFactory
|
|
3050
|
-
});
|
|
3051
|
-
|
|
3052
|
-
const logger$b = getLogger("naylence.fame.security.encryption.encryption_manager_registry");
|
|
3053
|
-
class EncryptionManagerFactoryRegistry {
|
|
3054
|
-
constructor(autoDiscover = true) {
|
|
3055
|
-
this.factories = [];
|
|
3056
|
-
this.algorithmToFactory = new Map();
|
|
3057
|
-
this.typeToFactories = new Map();
|
|
3058
|
-
this.factorySet = new Set();
|
|
3059
|
-
this.autoDiscoveredFactories = new Set();
|
|
3060
|
-
this.autoDiscovered = false;
|
|
3061
|
-
if (autoDiscover) {
|
|
3062
|
-
this.autoDiscoverFactories();
|
|
3063
|
-
}
|
|
3064
|
-
}
|
|
3065
|
-
autoDiscoverFactories() {
|
|
3066
|
-
if (this.autoDiscovered) {
|
|
3067
|
-
return;
|
|
3068
|
-
}
|
|
3069
|
-
try {
|
|
3070
|
-
const extensionInfos = ExtensionManager.getExtensionsByType(ENCRYPTION_MANAGER_FACTORY_BASE_TYPE);
|
|
3071
|
-
let registeredCount = 0;
|
|
3072
|
-
for (const [factoryName, info] of extensionInfos) {
|
|
3073
|
-
if (factoryName === "CompositeEncryptionManager") {
|
|
3074
|
-
logger$b.debug("skipping_composite_factory_to_avoid_circular_dependency", {
|
|
3075
|
-
factory_name: factoryName,
|
|
3076
|
-
});
|
|
3077
|
-
continue;
|
|
3078
|
-
}
|
|
3079
|
-
try {
|
|
3080
|
-
const factoryInstance = (info.instance ??
|
|
3081
|
-
ExtensionManager.getGlobalFactory(ENCRYPTION_MANAGER_FACTORY_BASE_TYPE, factoryName));
|
|
3082
|
-
this.registerFactory(factoryInstance, { autoDiscovered: true });
|
|
3083
|
-
registeredCount += 1;
|
|
3084
|
-
logger$b.debug("auto_discovered_factory", {
|
|
3085
|
-
factory_name: factoryName,
|
|
3086
|
-
factory_class: factoryInstance.constructor.name,
|
|
3087
|
-
algorithms: factoryInstance.getSupportedAlgorithms(),
|
|
3088
|
-
encryption_type: factoryInstance.getEncryptionType(),
|
|
3089
|
-
priority: factoryInstance.getPriority(),
|
|
3090
|
-
});
|
|
3091
|
-
}
|
|
3092
|
-
catch (error) {
|
|
3093
|
-
logger$b.warning("failed_to_auto_register_factory", {
|
|
3094
|
-
factory_name: factoryName,
|
|
3095
|
-
error: error instanceof Error ? error.message : String(error),
|
|
3096
|
-
});
|
|
3097
|
-
}
|
|
3098
|
-
}
|
|
3099
|
-
this.autoDiscovered = true;
|
|
3100
|
-
logger$b.debug("completed_auto_discovery", {
|
|
3101
|
-
registered_factories: registeredCount,
|
|
3102
|
-
total_discovered: extensionInfos.size,
|
|
3103
|
-
skipped_composite: true,
|
|
3104
|
-
});
|
|
3105
|
-
}
|
|
3106
|
-
catch (error) {
|
|
3107
|
-
logger$b.warning("failed_auto_discovery_of_factories", {
|
|
3108
|
-
error: error instanceof Error ? error.message : String(error),
|
|
3109
|
-
});
|
|
3110
|
-
}
|
|
3111
|
-
}
|
|
3112
|
-
registerFactory(factory, options = {}) {
|
|
3113
|
-
if (this.factorySet.has(factory)) {
|
|
3114
|
-
return;
|
|
3115
|
-
}
|
|
3116
|
-
this.factorySet.add(factory);
|
|
3117
|
-
this.factories.push(factory);
|
|
3118
|
-
if (options.autoDiscovered) {
|
|
3119
|
-
this.autoDiscoveredFactories.add(factory);
|
|
3120
|
-
}
|
|
3121
|
-
for (const algorithm of factory.getSupportedAlgorithms()) {
|
|
3122
|
-
const existing = this.algorithmToFactory.get(algorithm);
|
|
3123
|
-
if (!existing || factory.getPriority() > existing.getPriority()) {
|
|
3124
|
-
this.algorithmToFactory.set(algorithm, factory);
|
|
3125
|
-
logger$b.debug("registered_algorithm_mapping", {
|
|
3126
|
-
algorithm,
|
|
3127
|
-
factory: factory.constructor.name,
|
|
3128
|
-
priority: factory.getPriority(),
|
|
3129
|
-
});
|
|
3130
|
-
}
|
|
3131
|
-
}
|
|
3132
|
-
const encryptionType = factory.getEncryptionType();
|
|
3133
|
-
const typeFactories = this.typeToFactories.get(encryptionType) ?? [];
|
|
3134
|
-
typeFactories.push(factory);
|
|
3135
|
-
typeFactories.sort((a, b) => b.getPriority() - a.getPriority());
|
|
3136
|
-
this.typeToFactories.set(encryptionType, typeFactories);
|
|
3137
|
-
logger$b.debug("registered_encryption_manager_factory", {
|
|
3138
|
-
factory: factory.constructor.name,
|
|
3139
|
-
encryption_type: encryptionType,
|
|
3140
|
-
algorithms: factory.getSupportedAlgorithms(),
|
|
3141
|
-
priority: factory.getPriority(),
|
|
3142
|
-
auto_discovered: options.autoDiscovered ?? false,
|
|
3143
|
-
});
|
|
3144
|
-
}
|
|
3145
|
-
getFactoryForAlgorithm(algorithm) {
|
|
3146
|
-
this.ensureAutoDiscovery();
|
|
3147
|
-
return this.algorithmToFactory.get(algorithm);
|
|
3148
|
-
}
|
|
3149
|
-
getFactoryForOptions(opts) {
|
|
3150
|
-
this.ensureAutoDiscovery();
|
|
3151
|
-
for (const factory of this.factories) {
|
|
3152
|
-
if (factory.supportsOptions(opts ?? undefined)) {
|
|
3153
|
-
logger$b.debug("found_factory_for_options", {
|
|
3154
|
-
factory: factory.constructor.name,
|
|
3155
|
-
encryption_type: factory.getEncryptionType(),
|
|
3156
|
-
});
|
|
3157
|
-
return factory;
|
|
3158
|
-
}
|
|
3159
|
-
}
|
|
3160
|
-
logger$b.debug("no_factory_found_for_options", { opts });
|
|
3161
|
-
return undefined;
|
|
3162
|
-
}
|
|
3163
|
-
getFactoriesByType(encryptionType) {
|
|
3164
|
-
this.ensureAutoDiscovery();
|
|
3165
|
-
return this.typeToFactories.get(encryptionType) ?? [];
|
|
3166
|
-
}
|
|
3167
|
-
getAllSupportedAlgorithms() {
|
|
3168
|
-
this.ensureAutoDiscovery();
|
|
3169
|
-
return Array.from(this.algorithmToFactory.keys());
|
|
3170
|
-
}
|
|
3171
|
-
getRegistryInfo() {
|
|
3172
|
-
return {
|
|
3173
|
-
totalFactories: this.factories.length,
|
|
3174
|
-
autoDiscovered: this.autoDiscovered,
|
|
3175
|
-
algorithmMappings: Object.fromEntries(Array.from(this.algorithmToFactory.entries()).map(([algorithm, factory]) => [algorithm, factory.constructor.name])),
|
|
3176
|
-
typeMappings: Object.fromEntries(Array.from(this.typeToFactories.entries()).map(([encType, factories]) => [
|
|
3177
|
-
encType,
|
|
3178
|
-
factories.map((factory) => factory.constructor.name),
|
|
3179
|
-
])),
|
|
3180
|
-
};
|
|
3181
|
-
}
|
|
3182
|
-
forceRediscovery() {
|
|
3183
|
-
const manualFactories = this.factories.filter((factory) => !this.autoDiscoveredFactories.has(factory));
|
|
3184
|
-
this.autoDiscovered = false;
|
|
3185
|
-
this.algorithmToFactory.clear();
|
|
3186
|
-
this.typeToFactories.clear();
|
|
3187
|
-
this.factories.length = 0;
|
|
3188
|
-
this.factorySet.clear();
|
|
3189
|
-
this.autoDiscoveredFactories.clear();
|
|
3190
|
-
for (const factory of manualFactories) {
|
|
3191
|
-
this.registerFactory(factory);
|
|
3192
|
-
}
|
|
3193
|
-
this.autoDiscoverFactories();
|
|
3527
|
+
class DefaultSecureChannelManagerFactory extends SecureChannelManagerFactory {
|
|
3528
|
+
constructor() {
|
|
3529
|
+
super(...arguments);
|
|
3530
|
+
this.type = "DefaultSecureChannelManager";
|
|
3531
|
+
this.isDefault = true;
|
|
3532
|
+
this.priority = 500;
|
|
3194
3533
|
}
|
|
3195
|
-
|
|
3196
|
-
|
|
3534
|
+
async create(config = null) {
|
|
3535
|
+
const ttl = this.resolveChannelTtl(config);
|
|
3536
|
+
return new DefaultSecureChannelManager(ttl ? { channelTtlSeconds: ttl } : {});
|
|
3197
3537
|
}
|
|
3198
|
-
|
|
3199
|
-
|
|
3538
|
+
getSupportedAlgorithms() {
|
|
3539
|
+
return ["CHACHA20P1305"];
|
|
3200
3540
|
}
|
|
3201
|
-
|
|
3202
|
-
if (!
|
|
3203
|
-
|
|
3541
|
+
resolveChannelTtl(config) {
|
|
3542
|
+
if (!config) {
|
|
3543
|
+
return undefined;
|
|
3544
|
+
}
|
|
3545
|
+
const candidates = [
|
|
3546
|
+
config.channelTtlSeconds,
|
|
3547
|
+
config.channelTtl,
|
|
3548
|
+
config.channel_ttl,
|
|
3549
|
+
config.channelTTL,
|
|
3550
|
+
];
|
|
3551
|
+
for (const candidate of candidates) {
|
|
3552
|
+
const normalized = this.toPositiveNumber(candidate);
|
|
3553
|
+
if (typeof normalized === "number") {
|
|
3554
|
+
return normalized;
|
|
3555
|
+
}
|
|
3204
3556
|
}
|
|
3557
|
+
return undefined;
|
|
3558
|
+
}
|
|
3559
|
+
toPositiveNumber(value) {
|
|
3560
|
+
if (typeof value === "number" && Number.isFinite(value) && value > 0) {
|
|
3561
|
+
return value;
|
|
3562
|
+
}
|
|
3563
|
+
if (typeof value === "string" && value.trim() !== "") {
|
|
3564
|
+
const parsed = Number(value);
|
|
3565
|
+
if (Number.isFinite(parsed) && parsed > 0) {
|
|
3566
|
+
return parsed;
|
|
3567
|
+
}
|
|
3568
|
+
}
|
|
3569
|
+
return undefined;
|
|
3205
3570
|
}
|
|
3206
3571
|
}
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
}
|
|
3572
|
+
|
|
3573
|
+
var defaultSecureChannelManagerFactory = /*#__PURE__*/Object.freeze({
|
|
3574
|
+
__proto__: null,
|
|
3575
|
+
DefaultSecureChannelManagerFactory: DefaultSecureChannelManagerFactory,
|
|
3576
|
+
FACTORY_META: FACTORY_META$c,
|
|
3577
|
+
default: DefaultSecureChannelManagerFactory
|
|
3578
|
+
});
|
|
3215
3579
|
|
|
3216
3580
|
const logger$a = getLogger("naylence.fame.security.encryption.composite_encryption_manager");
|
|
3217
3581
|
const DEFAULT_SEALED_ALGORITHMS = [
|
|
@@ -5133,1275 +5497,953 @@ class AFTLoadBalancerStickinessManager extends BaseNodeEventListener {
|
|
|
5133
5497
|
}
|
|
5134
5498
|
const verification = await this.verifier.verify(aftToken, envelope.sid ?? undefined);
|
|
5135
5499
|
if (!verification.valid) {
|
|
5136
|
-
this.metrics.verifyFailures += 1;
|
|
5137
|
-
logger$4.warning("aft_verification_failed", {
|
|
5138
|
-
envelope_id: envelope.id,
|
|
5139
|
-
replica_id: replicaId,
|
|
5140
|
-
error: verification.error,
|
|
5141
|
-
});
|
|
5142
|
-
return null;
|
|
5143
|
-
}
|
|
5144
|
-
this.storeAssociation(aftToken, {
|
|
5145
|
-
replicaId,
|
|
5146
|
-
token: aftToken,
|
|
5147
|
-
sid: verification.sid ?? "",
|
|
5148
|
-
exp: verification.exp ?? Math.floor(Date.now() / 1000) + this.defaultTtlSec,
|
|
5149
|
-
trustLevel: verification.trustLevel,
|
|
5150
|
-
scope: verification.scope ?? null,
|
|
5151
|
-
clientSid: verification.clientSid ?? null,
|
|
5152
|
-
});
|
|
5153
|
-
if (verification.clientSid) {
|
|
5154
|
-
this.sidCache.set(verification.clientSid, replicaId);
|
|
5155
|
-
logger$4.debug("sid_cache_updated", {
|
|
5156
|
-
envelope_id: envelope.id,
|
|
5157
|
-
client_sid: verification.clientSid,
|
|
5158
|
-
replica_id: replicaId,
|
|
5159
|
-
});
|
|
5160
|
-
}
|
|
5161
|
-
this.metrics.associationsCreated += 1;
|
|
5162
|
-
logger$4.debug("aft_association_created", {
|
|
5163
|
-
envelope_id: envelope.id,
|
|
5164
|
-
replica_id: replicaId,
|
|
5165
|
-
sid: verification.sid,
|
|
5166
|
-
exp: verification.exp,
|
|
5167
|
-
trust_level: verification.trustLevel,
|
|
5168
|
-
scope: verification.scope,
|
|
5169
|
-
});
|
|
5170
|
-
return this.config.clientEcho ? aftToken : null;
|
|
5171
|
-
}
|
|
5172
|
-
getStickyReplicaSegment(envelope, segments) {
|
|
5173
|
-
if (!this.config.enabled) {
|
|
5174
|
-
logger$4.debug("stickiness_disabled", { envelope_id: envelope.id });
|
|
5175
|
-
return null;
|
|
5176
|
-
}
|
|
5177
|
-
if (envelope.aft) {
|
|
5178
|
-
const replicaId = this.routeByAft(envelope.aft, envelope);
|
|
5179
|
-
if (replicaId) {
|
|
5180
|
-
this.metrics.cacheHits += 1;
|
|
5181
|
-
logger$4.debug("aft_routed_envelope", {
|
|
5182
|
-
envelope_id: envelope.id,
|
|
5183
|
-
replica_id: replicaId,
|
|
5184
|
-
routing_type: "aft_direct",
|
|
5185
|
-
});
|
|
5186
|
-
return replicaId;
|
|
5187
|
-
}
|
|
5188
|
-
}
|
|
5189
|
-
if (envelope.sid) {
|
|
5190
|
-
const cachedReplica = this.sidCache.get(envelope.sid);
|
|
5191
|
-
if (cachedReplica) {
|
|
5192
|
-
if (this.config.securityLevel === StickinessMode.SID_ONLY) {
|
|
5193
|
-
this.metrics.cacheHits += 1;
|
|
5194
|
-
logger$4.debug("sid_cache_routed_envelope", {
|
|
5195
|
-
envelope_id: envelope.id,
|
|
5196
|
-
replica_id: cachedReplica,
|
|
5197
|
-
sid: envelope.sid,
|
|
5198
|
-
routing_type: "sid_only",
|
|
5199
|
-
});
|
|
5200
|
-
return cachedReplica;
|
|
5201
|
-
}
|
|
5202
|
-
for (const [token, association] of this.aftAssociations.entries()) {
|
|
5203
|
-
if (association.replicaId === cachedReplica &&
|
|
5204
|
-
!association.isExpired()) {
|
|
5205
|
-
envelope.aft = token;
|
|
5206
|
-
this.metrics.cacheHits += 1;
|
|
5207
|
-
logger$4.debug("sid_cache_routed_envelope", {
|
|
5208
|
-
envelope_id: envelope.id,
|
|
5209
|
-
replica_id: cachedReplica,
|
|
5210
|
-
sid: envelope.sid,
|
|
5211
|
-
routing_type: "sid_cache_with_aft",
|
|
5212
|
-
});
|
|
5213
|
-
return cachedReplica;
|
|
5214
|
-
}
|
|
5215
|
-
}
|
|
5216
|
-
this.metrics.cacheHits += 1;
|
|
5217
|
-
logger$4.debug("sid_cache_routed_envelope", {
|
|
5218
|
-
envelope_id: envelope.id,
|
|
5219
|
-
replica_id: cachedReplica,
|
|
5220
|
-
sid: envelope.sid,
|
|
5221
|
-
routing_type: "sid_cache_direct",
|
|
5222
|
-
});
|
|
5223
|
-
return cachedReplica;
|
|
5224
|
-
}
|
|
5225
|
-
logger$4.debug("no_cached_replica_for_sid", {
|
|
5226
|
-
envelope_id: envelope.id,
|
|
5227
|
-
sid: envelope.sid,
|
|
5228
|
-
});
|
|
5229
|
-
}
|
|
5230
|
-
if (envelope.sid && Array.isArray(segments) && segments.length > 0) {
|
|
5231
|
-
const index = computeDeterministicIndex(envelope.sid, segments.length);
|
|
5232
|
-
const chosen = segments[index];
|
|
5233
|
-
this.metrics.cacheHits += 1;
|
|
5234
|
-
logger$4.debug("sid_based_deterministic_choice", {
|
|
5235
|
-
envelope_id: envelope.id,
|
|
5236
|
-
sid: envelope.sid,
|
|
5237
|
-
chosen,
|
|
5238
|
-
routing_type: "sid_deterministic",
|
|
5239
|
-
});
|
|
5240
|
-
return chosen;
|
|
5241
|
-
}
|
|
5242
|
-
this.metrics.cacheMisses += 1;
|
|
5243
|
-
logger$4.debug("no_stickiness_routing", {
|
|
5244
|
-
envelope_id: envelope.id,
|
|
5245
|
-
has_aft: Boolean(envelope.aft),
|
|
5246
|
-
has_sid: Boolean(envelope.sid),
|
|
5247
|
-
});
|
|
5248
|
-
return null;
|
|
5249
|
-
}
|
|
5250
|
-
cleanupExpiredAssociations() {
|
|
5251
|
-
const now = Math.floor(Date.now() / 1000);
|
|
5252
|
-
const expiredTokens = [];
|
|
5253
|
-
for (const [token, association] of this.aftAssociations.entries()) {
|
|
5254
|
-
if (association.isExpired(now)) {
|
|
5255
|
-
expiredTokens.push(token);
|
|
5256
|
-
}
|
|
5257
|
-
}
|
|
5258
|
-
for (const token of expiredTokens) {
|
|
5259
|
-
this.removeAssociation(token);
|
|
5260
|
-
}
|
|
5261
|
-
if (expiredTokens.length > 0) {
|
|
5262
|
-
this.metrics.associationsExpired += expiredTokens.length;
|
|
5263
|
-
logger$4.debug("cleaned_expired_associations", {
|
|
5264
|
-
count: expiredTokens.length,
|
|
5265
|
-
});
|
|
5266
|
-
}
|
|
5267
|
-
}
|
|
5268
|
-
replicaLeft(replicaId) {
|
|
5269
|
-
const tokensToRemove = [];
|
|
5270
|
-
for (const [token, association] of this.aftAssociations.entries()) {
|
|
5271
|
-
if (association.replicaId === replicaId) {
|
|
5272
|
-
tokensToRemove.push(token);
|
|
5273
|
-
}
|
|
5274
|
-
}
|
|
5275
|
-
for (const token of tokensToRemove) {
|
|
5276
|
-
this.removeAssociation(token);
|
|
5277
|
-
}
|
|
5278
|
-
if (tokensToRemove.length > 0) {
|
|
5279
|
-
logger$4.debug("removed_associations_for_departed_replica", {
|
|
5280
|
-
replica_id: replicaId,
|
|
5281
|
-
count: tokensToRemove.length,
|
|
5282
|
-
});
|
|
5283
|
-
}
|
|
5284
|
-
}
|
|
5285
|
-
handleReplicaLeft(replicaId) {
|
|
5286
|
-
this.replicaLeft(replicaId);
|
|
5287
|
-
logger$4.debug("stickiness_replica_cleanup", { replica_id: replicaId });
|
|
5288
|
-
}
|
|
5289
|
-
getMetrics() {
|
|
5290
|
-
return {
|
|
5291
|
-
...this.metrics,
|
|
5292
|
-
cacheSize: this.aftAssociations.size,
|
|
5293
|
-
sidCacheSize: this.sidCache.size,
|
|
5294
|
-
};
|
|
5295
|
-
}
|
|
5296
|
-
getAssociations() {
|
|
5297
|
-
const result = {};
|
|
5298
|
-
for (const [token, association] of this.aftAssociations.entries()) {
|
|
5299
|
-
result[token] = {
|
|
5300
|
-
replica_id: association.replicaId,
|
|
5301
|
-
sid: association.sid,
|
|
5302
|
-
client_sid: association.clientSid,
|
|
5303
|
-
exp: association.exp,
|
|
5304
|
-
trust_level: association.trustLevel,
|
|
5305
|
-
scope: association.scope,
|
|
5306
|
-
created_at: association.createdAt,
|
|
5307
|
-
expired: association.isExpired(),
|
|
5308
|
-
};
|
|
5309
|
-
}
|
|
5310
|
-
return result;
|
|
5311
|
-
}
|
|
5312
|
-
getStickinessMetrics() {
|
|
5313
|
-
return this.getMetrics();
|
|
5314
|
-
}
|
|
5315
|
-
logMetrics() {
|
|
5316
|
-
const hits = this.metrics.cacheHits;
|
|
5317
|
-
const misses = this.metrics.cacheMisses;
|
|
5318
|
-
const total = hits + misses;
|
|
5319
|
-
const hitRate = total > 0 ? Math.round((hits / total) * 10000) / 100 : 0;
|
|
5320
|
-
logger$4.info("stickiness_metrics_report", {
|
|
5321
|
-
enabled: this.config.enabled,
|
|
5322
|
-
security_level: this.config.securityLevel,
|
|
5323
|
-
cache_hits: hits,
|
|
5324
|
-
cache_misses: misses,
|
|
5325
|
-
verify_failures: this.metrics.verifyFailures,
|
|
5326
|
-
associations_created: this.metrics.associationsCreated,
|
|
5327
|
-
associations_expired: this.metrics.associationsExpired,
|
|
5328
|
-
active_associations: this.aftAssociations.size,
|
|
5329
|
-
sid_cache_entries: this.sidCache.size,
|
|
5330
|
-
hit_rate: hitRate,
|
|
5500
|
+
this.metrics.verifyFailures += 1;
|
|
5501
|
+
logger$4.warning("aft_verification_failed", {
|
|
5502
|
+
envelope_id: envelope.id,
|
|
5503
|
+
replica_id: replicaId,
|
|
5504
|
+
error: verification.error,
|
|
5505
|
+
});
|
|
5506
|
+
return null;
|
|
5507
|
+
}
|
|
5508
|
+
this.storeAssociation(aftToken, {
|
|
5509
|
+
replicaId,
|
|
5510
|
+
token: aftToken,
|
|
5511
|
+
sid: verification.sid ?? "",
|
|
5512
|
+
exp: verification.exp ?? Math.floor(Date.now() / 1000) + this.defaultTtlSec,
|
|
5513
|
+
trustLevel: verification.trustLevel,
|
|
5514
|
+
scope: verification.scope ?? null,
|
|
5515
|
+
clientSid: verification.clientSid ?? null,
|
|
5331
5516
|
});
|
|
5332
|
-
|
|
5333
|
-
|
|
5334
|
-
|
|
5517
|
+
if (verification.clientSid) {
|
|
5518
|
+
this.sidCache.set(verification.clientSid, replicaId);
|
|
5519
|
+
logger$4.debug("sid_cache_updated", {
|
|
5520
|
+
envelope_id: envelope.id,
|
|
5521
|
+
client_sid: verification.clientSid,
|
|
5522
|
+
replica_id: replicaId,
|
|
5523
|
+
});
|
|
5524
|
+
}
|
|
5525
|
+
this.metrics.associationsCreated += 1;
|
|
5526
|
+
logger$4.debug("aft_association_created", {
|
|
5335
5527
|
envelope_id: envelope.id,
|
|
5336
|
-
|
|
5337
|
-
|
|
5528
|
+
replica_id: replicaId,
|
|
5529
|
+
sid: verification.sid,
|
|
5530
|
+
exp: verification.exp,
|
|
5531
|
+
trust_level: verification.trustLevel,
|
|
5532
|
+
scope: verification.scope,
|
|
5338
5533
|
});
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
|
|
5534
|
+
return this.config.clientEcho ? aftToken : null;
|
|
5535
|
+
}
|
|
5536
|
+
getStickyReplicaSegment(envelope, segments) {
|
|
5537
|
+
if (!this.config.enabled) {
|
|
5538
|
+
logger$4.debug("stickiness_disabled", { envelope_id: envelope.id });
|
|
5539
|
+
return null;
|
|
5540
|
+
}
|
|
5541
|
+
if (envelope.aft) {
|
|
5542
|
+
const replicaId = this.routeByAft(envelope.aft, envelope);
|
|
5543
|
+
if (replicaId) {
|
|
5544
|
+
this.metrics.cacheHits += 1;
|
|
5545
|
+
logger$4.debug("aft_routed_envelope", {
|
|
5343
5546
|
envelope_id: envelope.id,
|
|
5344
|
-
|
|
5547
|
+
replica_id: replicaId,
|
|
5548
|
+
routing_type: "aft_direct",
|
|
5345
5549
|
});
|
|
5346
|
-
|
|
5347
|
-
|
|
5348
|
-
|
|
5349
|
-
|
|
5350
|
-
|
|
5550
|
+
return replicaId;
|
|
5551
|
+
}
|
|
5552
|
+
}
|
|
5553
|
+
if (envelope.sid) {
|
|
5554
|
+
const cachedReplica = this.sidCache.get(envelope.sid);
|
|
5555
|
+
if (cachedReplica) {
|
|
5556
|
+
if (this.config.securityLevel === StickinessMode.SID_ONLY) {
|
|
5557
|
+
this.metrics.cacheHits += 1;
|
|
5558
|
+
logger$4.debug("sid_cache_routed_envelope", {
|
|
5351
5559
|
envelope_id: envelope.id,
|
|
5560
|
+
replica_id: cachedReplica,
|
|
5352
5561
|
sid: envelope.sid,
|
|
5353
|
-
|
|
5354
|
-
});
|
|
5355
|
-
}
|
|
5356
|
-
const hadInstruction = Boolean(extractAftInstruction(envelope));
|
|
5357
|
-
const token = await this.handleOutboundEnvelope(envelope, sourceRoute);
|
|
5358
|
-
if (hadInstruction) {
|
|
5359
|
-
logger$4.debug("processed_aft_setter_instruction", {
|
|
5360
|
-
envelope_id: envelope.id,
|
|
5361
|
-
source_route: sourceRoute,
|
|
5362
|
-
client_echo: Boolean(token),
|
|
5562
|
+
routing_type: "sid_only",
|
|
5363
5563
|
});
|
|
5564
|
+
return cachedReplica;
|
|
5364
5565
|
}
|
|
5365
|
-
|
|
5366
|
-
|
|
5367
|
-
|
|
5368
|
-
|
|
5369
|
-
|
|
5566
|
+
for (const [token, association] of this.aftAssociations.entries()) {
|
|
5567
|
+
if (association.replicaId === cachedReplica &&
|
|
5568
|
+
!association.isExpired()) {
|
|
5569
|
+
envelope.aft = token;
|
|
5570
|
+
this.metrics.cacheHits += 1;
|
|
5571
|
+
logger$4.debug("sid_cache_routed_envelope", {
|
|
5572
|
+
envelope_id: envelope.id,
|
|
5573
|
+
replica_id: cachedReplica,
|
|
5574
|
+
sid: envelope.sid,
|
|
5575
|
+
routing_type: "sid_cache_with_aft",
|
|
5576
|
+
});
|
|
5577
|
+
return cachedReplica;
|
|
5578
|
+
}
|
|
5370
5579
|
}
|
|
5371
|
-
|
|
5372
|
-
|
|
5373
|
-
logger$4.debug("downstream_envelope_without_source_route", {
|
|
5580
|
+
this.metrics.cacheHits += 1;
|
|
5581
|
+
logger$4.debug("sid_cache_routed_envelope", {
|
|
5374
5582
|
envelope_id: envelope.id,
|
|
5583
|
+
replica_id: cachedReplica,
|
|
5584
|
+
sid: envelope.sid,
|
|
5585
|
+
routing_type: "sid_cache_direct",
|
|
5375
5586
|
});
|
|
5587
|
+
return cachedReplica;
|
|
5376
5588
|
}
|
|
5377
|
-
|
|
5378
|
-
else {
|
|
5379
|
-
logger$4.debug("envelope_not_from_downstream", {
|
|
5589
|
+
logger$4.debug("no_cached_replica_for_sid", {
|
|
5380
5590
|
envelope_id: envelope.id,
|
|
5591
|
+
sid: envelope.sid,
|
|
5381
5592
|
});
|
|
5382
5593
|
}
|
|
5383
|
-
|
|
5384
|
-
|
|
5385
|
-
|
|
5386
|
-
|
|
5387
|
-
|
|
5388
|
-
}
|
|
5389
|
-
const association = new AFTAssociation(data);
|
|
5390
|
-
this.aftAssociations.set(token, association);
|
|
5391
|
-
while (this.aftAssociations.size > this.cacheMax) {
|
|
5392
|
-
const oldest = this.aftAssociations.keys().next();
|
|
5393
|
-
if (oldest.done) {
|
|
5394
|
-
break;
|
|
5395
|
-
}
|
|
5396
|
-
const oldestToken = oldest.value;
|
|
5397
|
-
this.removeAssociation(oldestToken);
|
|
5398
|
-
}
|
|
5399
|
-
}
|
|
5400
|
-
removeAssociation(token) {
|
|
5401
|
-
this.aftAssociations.delete(token);
|
|
5402
|
-
for (const [sid, cachedToken] of this.sidCache.entries()) {
|
|
5403
|
-
if (cachedToken === token) {
|
|
5404
|
-
this.sidCache.delete(sid);
|
|
5405
|
-
}
|
|
5406
|
-
}
|
|
5407
|
-
}
|
|
5408
|
-
routeByAft(token, envelope) {
|
|
5409
|
-
const association = this.aftAssociations.get(token);
|
|
5410
|
-
if (!association) {
|
|
5411
|
-
return null;
|
|
5412
|
-
}
|
|
5413
|
-
if (association.isExpired()) {
|
|
5414
|
-
this.metrics.associationsExpired += 1;
|
|
5415
|
-
this.removeAssociation(token);
|
|
5416
|
-
return null;
|
|
5417
|
-
}
|
|
5418
|
-
if (this.verifier.securityLevel === StickinessMode.STRICT &&
|
|
5419
|
-
association.isLowTrust()) {
|
|
5420
|
-
logger$4.warning("rejecting_low_trust_association", {
|
|
5594
|
+
if (envelope.sid && Array.isArray(segments) && segments.length > 0) {
|
|
5595
|
+
const index = computeDeterministicIndex(envelope.sid, segments.length);
|
|
5596
|
+
const chosen = segments[index];
|
|
5597
|
+
this.metrics.cacheHits += 1;
|
|
5598
|
+
logger$4.debug("sid_based_deterministic_choice", {
|
|
5421
5599
|
envelope_id: envelope.id,
|
|
5422
|
-
|
|
5423
|
-
|
|
5600
|
+
sid: envelope.sid,
|
|
5601
|
+
chosen,
|
|
5602
|
+
routing_type: "sid_deterministic",
|
|
5424
5603
|
});
|
|
5425
|
-
return
|
|
5604
|
+
return chosen;
|
|
5426
5605
|
}
|
|
5427
|
-
this.
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
if (!envelope.meta) {
|
|
5606
|
+
this.metrics.cacheMisses += 1;
|
|
5607
|
+
logger$4.debug("no_stickiness_routing", {
|
|
5608
|
+
envelope_id: envelope.id,
|
|
5609
|
+
has_aft: Boolean(envelope.aft),
|
|
5610
|
+
has_sid: Boolean(envelope.sid),
|
|
5611
|
+
});
|
|
5434
5612
|
return null;
|
|
5435
5613
|
}
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
|
|
5439
|
-
const
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
|
|
5446
|
-
|
|
5447
|
-
|
|
5448
|
-
|
|
5449
|
-
|
|
5450
|
-
|
|
5451
|
-
return 0;
|
|
5452
|
-
}
|
|
5453
|
-
let hash = 0;
|
|
5454
|
-
for (let i = 0; i < key.length; i += 1) {
|
|
5455
|
-
hash = (hash * 31 + key.charCodeAt(i)) >>> 0;
|
|
5456
|
-
}
|
|
5457
|
-
return hash % modulo;
|
|
5458
|
-
}
|
|
5459
|
-
|
|
5460
|
-
const FACTORY_META$7 = {
|
|
5461
|
-
base: LOAD_BALANCER_STICKINESS_MANAGER_FACTORY_BASE_TYPE,
|
|
5462
|
-
key: "AFTLoadBalancerStickinessManager",
|
|
5463
|
-
};
|
|
5464
|
-
const DEFAULT_VALUES$1 = {
|
|
5465
|
-
enabled: true,
|
|
5466
|
-
clientEcho: false,
|
|
5467
|
-
defaultTtlSec: 30,
|
|
5468
|
-
cacheMax: 100000,
|
|
5469
|
-
securityLevel: StickinessMode.SIGNED_OPTIONAL,
|
|
5470
|
-
maxTtlSec: 7200,
|
|
5471
|
-
};
|
|
5472
|
-
function toBoolean(value, fallback) {
|
|
5473
|
-
return typeof value === "boolean" ? value : fallback;
|
|
5474
|
-
}
|
|
5475
|
-
function toNumber(value, fallback) {
|
|
5476
|
-
if (typeof value === "number" && Number.isFinite(value)) {
|
|
5477
|
-
return value;
|
|
5478
|
-
}
|
|
5479
|
-
return fallback;
|
|
5480
|
-
}
|
|
5481
|
-
function normalizeConfig$4(config) {
|
|
5482
|
-
const record = (config ?? {});
|
|
5483
|
-
const normalizedSecurity = record.securityLevel
|
|
5484
|
-
? normalizeStickinessMode(record.securityLevel)
|
|
5485
|
-
: DEFAULT_VALUES$1.securityLevel;
|
|
5486
|
-
return {
|
|
5487
|
-
...record,
|
|
5488
|
-
type: "AFTLoadBalancerStickinessManager",
|
|
5489
|
-
enabled: toBoolean(record.enabled, DEFAULT_VALUES$1.enabled),
|
|
5490
|
-
clientEcho: toBoolean(record.clientEcho, DEFAULT_VALUES$1.clientEcho),
|
|
5491
|
-
defaultTtlSec: toNumber(record.defaultTtlSec, DEFAULT_VALUES$1.defaultTtlSec),
|
|
5492
|
-
cacheMax: toNumber(record.cacheMax, DEFAULT_VALUES$1.cacheMax),
|
|
5493
|
-
securityLevel: normalizedSecurity,
|
|
5494
|
-
maxTtlSec: toNumber(record.maxTtlSec, DEFAULT_VALUES$1.maxTtlSec),
|
|
5495
|
-
};
|
|
5496
|
-
}
|
|
5497
|
-
class AFTLoadBalancerStickinessManagerFactory extends LoadBalancerStickinessManagerFactory {
|
|
5498
|
-
constructor() {
|
|
5499
|
-
super(...arguments);
|
|
5500
|
-
this.type = "AFTLoadBalancerStickinessManager";
|
|
5501
|
-
this.isDefault = false;
|
|
5502
|
-
}
|
|
5503
|
-
async create(config, keyProvider, verifier) {
|
|
5504
|
-
const resolvedConfig = normalizeConfig$4(config);
|
|
5505
|
-
let effectiveVerifier = verifier ?? null;
|
|
5506
|
-
if (!effectiveVerifier && keyProvider) {
|
|
5507
|
-
effectiveVerifier = createAftVerifier({
|
|
5508
|
-
securityLevel: resolvedConfig.securityLevel ?? DEFAULT_VALUES$1.securityLevel,
|
|
5509
|
-
keyProvider,
|
|
5510
|
-
defaultTtlSec: resolvedConfig.defaultTtlSec ?? DEFAULT_VALUES$1.defaultTtlSec,
|
|
5614
|
+
cleanupExpiredAssociations() {
|
|
5615
|
+
const now = Math.floor(Date.now() / 1000);
|
|
5616
|
+
const expiredTokens = [];
|
|
5617
|
+
for (const [token, association] of this.aftAssociations.entries()) {
|
|
5618
|
+
if (association.isExpired(now)) {
|
|
5619
|
+
expiredTokens.push(token);
|
|
5620
|
+
}
|
|
5621
|
+
}
|
|
5622
|
+
for (const token of expiredTokens) {
|
|
5623
|
+
this.removeAssociation(token);
|
|
5624
|
+
}
|
|
5625
|
+
if (expiredTokens.length > 0) {
|
|
5626
|
+
this.metrics.associationsExpired += expiredTokens.length;
|
|
5627
|
+
logger$4.debug("cleaned_expired_associations", {
|
|
5628
|
+
count: expiredTokens.length,
|
|
5511
5629
|
});
|
|
5512
5630
|
}
|
|
5513
|
-
|
|
5514
|
-
|
|
5631
|
+
}
|
|
5632
|
+
replicaLeft(replicaId) {
|
|
5633
|
+
const tokensToRemove = [];
|
|
5634
|
+
for (const [token, association] of this.aftAssociations.entries()) {
|
|
5635
|
+
if (association.replicaId === replicaId) {
|
|
5636
|
+
tokensToRemove.push(token);
|
|
5637
|
+
}
|
|
5638
|
+
}
|
|
5639
|
+
for (const token of tokensToRemove) {
|
|
5640
|
+
this.removeAssociation(token);
|
|
5641
|
+
}
|
|
5642
|
+
if (tokensToRemove.length > 0) {
|
|
5643
|
+
logger$4.debug("removed_associations_for_departed_replica", {
|
|
5644
|
+
replica_id: replicaId,
|
|
5645
|
+
count: tokensToRemove.length,
|
|
5646
|
+
});
|
|
5515
5647
|
}
|
|
5516
|
-
return new AFTLoadBalancerStickinessManager(resolvedConfig, effectiveVerifier);
|
|
5517
5648
|
}
|
|
5518
|
-
|
|
5519
|
-
|
|
5520
|
-
|
|
5521
|
-
__proto__: null,
|
|
5522
|
-
AFTLoadBalancerStickinessManagerFactory: AFTLoadBalancerStickinessManagerFactory,
|
|
5523
|
-
FACTORY_META: FACTORY_META$7,
|
|
5524
|
-
default: AFTLoadBalancerStickinessManagerFactory
|
|
5525
|
-
});
|
|
5526
|
-
|
|
5527
|
-
const logger$3 = getLogger("naylence.fame.stickiness.aft_replica_stickiness_manager");
|
|
5528
|
-
function isStickinessRequired(context) {
|
|
5529
|
-
if (typeof context.stickinessRequired === "boolean") {
|
|
5530
|
-
return context.stickinessRequired;
|
|
5649
|
+
handleReplicaLeft(replicaId) {
|
|
5650
|
+
this.replicaLeft(replicaId);
|
|
5651
|
+
logger$4.debug("stickiness_replica_cleanup", { replica_id: replicaId });
|
|
5531
5652
|
}
|
|
5532
|
-
|
|
5533
|
-
return
|
|
5653
|
+
getMetrics() {
|
|
5654
|
+
return {
|
|
5655
|
+
...this.metrics,
|
|
5656
|
+
cacheSize: this.aftAssociations.size,
|
|
5657
|
+
sidCacheSize: this.sidCache.size,
|
|
5658
|
+
};
|
|
5534
5659
|
}
|
|
5535
|
-
|
|
5536
|
-
}
|
|
5537
|
-
|
|
5538
|
-
|
|
5539
|
-
|
|
5540
|
-
|
|
5541
|
-
|
|
5542
|
-
|
|
5543
|
-
|
|
5544
|
-
|
|
5545
|
-
|
|
5546
|
-
|
|
5547
|
-
|
|
5548
|
-
helper_type: this.aftHelper.signer.constructor.name,
|
|
5549
|
-
security_level: this.aftHelper.signer.securityLevel,
|
|
5550
|
-
max_ttl_sec: this.aftHelper.maxTtlSec,
|
|
5551
|
-
});
|
|
5552
|
-
}
|
|
5553
|
-
else {
|
|
5554
|
-
logger$3.debug("aft_replica_stickiness_manager_created", {
|
|
5555
|
-
security_level: this.securityLevel,
|
|
5556
|
-
max_ttl_sec: this.maxTtlSec,
|
|
5557
|
-
});
|
|
5660
|
+
getAssociations() {
|
|
5661
|
+
const result = {};
|
|
5662
|
+
for (const [token, association] of this.aftAssociations.entries()) {
|
|
5663
|
+
result[token] = {
|
|
5664
|
+
replica_id: association.replicaId,
|
|
5665
|
+
sid: association.sid,
|
|
5666
|
+
client_sid: association.clientSid,
|
|
5667
|
+
exp: association.exp,
|
|
5668
|
+
trust_level: association.trustLevel,
|
|
5669
|
+
scope: association.scope,
|
|
5670
|
+
created_at: association.createdAt,
|
|
5671
|
+
expired: association.isExpired(),
|
|
5672
|
+
};
|
|
5558
5673
|
}
|
|
5674
|
+
return result;
|
|
5559
5675
|
}
|
|
5560
|
-
|
|
5561
|
-
return
|
|
5676
|
+
getStickinessMetrics() {
|
|
5677
|
+
return this.getMetrics();
|
|
5562
5678
|
}
|
|
5563
|
-
|
|
5564
|
-
|
|
5565
|
-
|
|
5566
|
-
|
|
5567
|
-
|
|
5568
|
-
|
|
5679
|
+
logMetrics() {
|
|
5680
|
+
const hits = this.metrics.cacheHits;
|
|
5681
|
+
const misses = this.metrics.cacheMisses;
|
|
5682
|
+
const total = hits + misses;
|
|
5683
|
+
const hitRate = total > 0 ? Math.round((hits / total) * 10000) / 100 : 0;
|
|
5684
|
+
logger$4.info("stickiness_metrics_report", {
|
|
5685
|
+
enabled: this.config.enabled,
|
|
5686
|
+
security_level: this.config.securityLevel,
|
|
5687
|
+
cache_hits: hits,
|
|
5688
|
+
cache_misses: misses,
|
|
5689
|
+
verify_failures: this.metrics.verifyFailures,
|
|
5690
|
+
associations_created: this.metrics.associationsCreated,
|
|
5691
|
+
associations_expired: this.metrics.associationsExpired,
|
|
5692
|
+
active_associations: this.aftAssociations.size,
|
|
5693
|
+
sid_cache_entries: this.sidCache.size,
|
|
5694
|
+
hit_rate: hitRate,
|
|
5569
5695
|
});
|
|
5570
5696
|
}
|
|
5571
|
-
async
|
|
5572
|
-
|
|
5573
|
-
|
|
5574
|
-
|
|
5575
|
-
|
|
5576
|
-
|
|
5577
|
-
|
|
5578
|
-
|
|
5579
|
-
|
|
5580
|
-
|
|
5581
|
-
|
|
5582
|
-
|
|
5583
|
-
|
|
5584
|
-
|
|
5585
|
-
|
|
5586
|
-
|
|
5587
|
-
|
|
5588
|
-
|
|
5589
|
-
if (negotiated.enabled === false ||
|
|
5590
|
-
(negotiated.mode !== null &&
|
|
5591
|
-
negotiated.mode !== undefined &&
|
|
5592
|
-
negotiated.mode !== "aft")) {
|
|
5593
|
-
logger$3.debug("aft_injection_skipped_due_to_policy", {
|
|
5697
|
+
async onDeliver(_node, envelope, context) {
|
|
5698
|
+
logger$4.debug("stickiness_manager_on_deliver", {
|
|
5699
|
+
envelope_id: envelope.id,
|
|
5700
|
+
origin_type: context?.originType ?? "unknown",
|
|
5701
|
+
from_system_id: context?.fromSystemId ?? null,
|
|
5702
|
+
});
|
|
5703
|
+
if (context?.originType === DeliveryOriginType$1.DOWNSTREAM) {
|
|
5704
|
+
const sourceRoute = context.fromSystemId;
|
|
5705
|
+
if (sourceRoute) {
|
|
5706
|
+
logger$4.debug("processing_downstream_envelope", {
|
|
5707
|
+
envelope_id: envelope.id,
|
|
5708
|
+
source_route: sourceRoute,
|
|
5709
|
+
});
|
|
5710
|
+
if (this.config.securityLevel === StickinessMode.SID_ONLY &&
|
|
5711
|
+
envelope.sid &&
|
|
5712
|
+
!this.sidCache.has(envelope.sid)) {
|
|
5713
|
+
this.sidCache.set(envelope.sid, sourceRoute);
|
|
5714
|
+
logger$4.debug("sid_only_association_recorded", {
|
|
5594
5715
|
envelope_id: envelope.id,
|
|
5595
|
-
|
|
5596
|
-
|
|
5716
|
+
sid: envelope.sid,
|
|
5717
|
+
replica_id: sourceRoute,
|
|
5718
|
+
});
|
|
5719
|
+
}
|
|
5720
|
+
const hadInstruction = Boolean(extractAftInstruction(envelope));
|
|
5721
|
+
const token = await this.handleOutboundEnvelope(envelope, sourceRoute);
|
|
5722
|
+
if (hadInstruction) {
|
|
5723
|
+
logger$4.debug("processed_aft_setter_instruction", {
|
|
5724
|
+
envelope_id: envelope.id,
|
|
5725
|
+
source_route: sourceRoute,
|
|
5726
|
+
client_echo: Boolean(token),
|
|
5727
|
+
});
|
|
5728
|
+
}
|
|
5729
|
+
else {
|
|
5730
|
+
logger$4.debug("no_aft_setter_instruction", {
|
|
5731
|
+
envelope_id: envelope.id,
|
|
5732
|
+
source_route: sourceRoute,
|
|
5597
5733
|
});
|
|
5598
|
-
return envelope;
|
|
5599
5734
|
}
|
|
5600
|
-
}
|
|
5601
|
-
logger$3.debug("applying_aft_for_upstream_stickiness_required", {
|
|
5602
|
-
envelope_id: envelope.id,
|
|
5603
|
-
from_system_id: context.fromSystemId ?? null,
|
|
5604
|
-
delivery_origin: context.originType ?? null,
|
|
5605
|
-
});
|
|
5606
|
-
const success = await helper.requestStickiness(envelope, {
|
|
5607
|
-
ttlSec: null,
|
|
5608
|
-
scope: "node",
|
|
5609
|
-
context: stickinessContext,
|
|
5610
|
-
});
|
|
5611
|
-
if (success) {
|
|
5612
|
-
logger$3.debug("aft_token_applied_via_context_flag_upstream", {
|
|
5613
|
-
envelope_id: envelope.id,
|
|
5614
|
-
from_system_id: context.fromSystemId ?? null,
|
|
5615
|
-
delivery_origin: context.originType ?? null,
|
|
5616
|
-
});
|
|
5617
5735
|
}
|
|
5618
5736
|
else {
|
|
5619
|
-
logger$
|
|
5737
|
+
logger$4.debug("downstream_envelope_without_source_route", {
|
|
5620
5738
|
envelope_id: envelope.id,
|
|
5621
|
-
delivery_origin: context.originType ?? null,
|
|
5622
|
-
reason: "helper_returned_false",
|
|
5623
5739
|
});
|
|
5624
5740
|
}
|
|
5625
5741
|
}
|
|
5626
|
-
return envelope;
|
|
5627
|
-
}
|
|
5628
|
-
async onNodeStarted(node) {
|
|
5629
|
-
if (!this.isInitialized) {
|
|
5630
|
-
await this.initializeAftHelper(node);
|
|
5631
|
-
return;
|
|
5632
|
-
}
|
|
5633
|
-
if (this.aftHelper && node.sid) {
|
|
5634
|
-
this.updateNodeSid(node.sid);
|
|
5635
|
-
logger$3.debug("aft_replica_stickiness_manager_sid_updated", {
|
|
5636
|
-
node_id: node.id ?? "unknown",
|
|
5637
|
-
node_sid: node.sid,
|
|
5638
|
-
security_level: this.aftHelper.signer.securityLevel,
|
|
5639
|
-
});
|
|
5640
|
-
}
|
|
5641
|
-
else if (!node.sid) {
|
|
5642
|
-
logger$3.warning("aft_replica_stickiness_manager_no_sid_available", {
|
|
5643
|
-
node_id: node.id ?? "unknown",
|
|
5644
|
-
});
|
|
5645
|
-
}
|
|
5646
5742
|
else {
|
|
5647
|
-
logger$
|
|
5648
|
-
|
|
5743
|
+
logger$4.debug("envelope_not_from_downstream", {
|
|
5744
|
+
envelope_id: envelope.id,
|
|
5649
5745
|
});
|
|
5650
5746
|
}
|
|
5747
|
+
return envelope;
|
|
5651
5748
|
}
|
|
5652
|
-
|
|
5653
|
-
if (this.
|
|
5654
|
-
this.
|
|
5655
|
-
logger$3.debug("aft_replica_stickiness_manager_sid_updated", {
|
|
5656
|
-
new_sid: nodeSid,
|
|
5657
|
-
});
|
|
5749
|
+
storeAssociation(token, data) {
|
|
5750
|
+
if (this.aftAssociations.has(token)) {
|
|
5751
|
+
this.aftAssociations.delete(token);
|
|
5658
5752
|
}
|
|
5659
|
-
|
|
5660
|
-
|
|
5661
|
-
|
|
5662
|
-
|
|
5663
|
-
|
|
5664
|
-
|
|
5665
|
-
}
|
|
5666
|
-
|
|
5753
|
+
const association = new AFTAssociation(data);
|
|
5754
|
+
this.aftAssociations.set(token, association);
|
|
5755
|
+
while (this.aftAssociations.size > this.cacheMax) {
|
|
5756
|
+
const oldest = this.aftAssociations.keys().next();
|
|
5757
|
+
if (oldest.done) {
|
|
5758
|
+
break;
|
|
5759
|
+
}
|
|
5760
|
+
const oldestToken = oldest.value;
|
|
5761
|
+
this.removeAssociation(oldestToken);
|
|
5667
5762
|
}
|
|
5668
|
-
|
|
5669
|
-
|
|
5670
|
-
|
|
5671
|
-
|
|
5672
|
-
|
|
5673
|
-
|
|
5763
|
+
}
|
|
5764
|
+
removeAssociation(token) {
|
|
5765
|
+
this.aftAssociations.delete(token);
|
|
5766
|
+
for (const [sid, cachedToken] of this.sidCache.entries()) {
|
|
5767
|
+
if (cachedToken === token) {
|
|
5768
|
+
this.sidCache.delete(sid);
|
|
5769
|
+
}
|
|
5674
5770
|
}
|
|
5675
|
-
|
|
5676
|
-
|
|
5677
|
-
|
|
5678
|
-
|
|
5679
|
-
|
|
5680
|
-
? cryptoProvider.signingPrivatePem
|
|
5681
|
-
: null;
|
|
5682
|
-
if (this.securityLevel === StickinessMode.STRICT && !privateKeyPem) {
|
|
5683
|
-
logger$3.error("aft_replica_stickiness_manager_initialization_failed", {
|
|
5684
|
-
node_id: node.id ?? "unknown",
|
|
5685
|
-
error: "Missing signing private key for strict security level",
|
|
5686
|
-
});
|
|
5687
|
-
return;
|
|
5771
|
+
}
|
|
5772
|
+
routeByAft(token, envelope) {
|
|
5773
|
+
const association = this.aftAssociations.get(token);
|
|
5774
|
+
if (!association) {
|
|
5775
|
+
return null;
|
|
5688
5776
|
}
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
|
|
5692
|
-
|
|
5693
|
-
kid: keyId,
|
|
5694
|
-
privateKeyPem,
|
|
5695
|
-
maxTtlSec: this.maxTtlSec,
|
|
5696
|
-
});
|
|
5697
|
-
this.aftHelper = helper;
|
|
5698
|
-
this.isInitialized = true;
|
|
5699
|
-
logger$3.debug("aft_replica_stickiness_manager_initialized", {
|
|
5700
|
-
node_id: node.id ?? "unknown",
|
|
5701
|
-
node_sid: nodeSid,
|
|
5702
|
-
key_id: keyId,
|
|
5703
|
-
security_level: helper.signer.securityLevel,
|
|
5704
|
-
});
|
|
5777
|
+
if (association.isExpired()) {
|
|
5778
|
+
this.metrics.associationsExpired += 1;
|
|
5779
|
+
this.removeAssociation(token);
|
|
5780
|
+
return null;
|
|
5705
5781
|
}
|
|
5706
|
-
|
|
5707
|
-
|
|
5708
|
-
|
|
5709
|
-
|
|
5782
|
+
if (this.verifier.securityLevel === StickinessMode.STRICT &&
|
|
5783
|
+
association.isLowTrust()) {
|
|
5784
|
+
logger$4.warning("rejecting_low_trust_association", {
|
|
5785
|
+
envelope_id: envelope.id,
|
|
5786
|
+
replica_id: association.replicaId,
|
|
5787
|
+
reason: "strict mode rejects low-trust associations",
|
|
5710
5788
|
});
|
|
5789
|
+
return null;
|
|
5711
5790
|
}
|
|
5791
|
+
this.aftAssociations.delete(token);
|
|
5792
|
+
this.aftAssociations.set(token, association);
|
|
5793
|
+
return association.replicaId;
|
|
5712
5794
|
}
|
|
5713
|
-
|
|
5714
|
-
|
|
5795
|
+
}
|
|
5796
|
+
function extractAftInstruction(envelope) {
|
|
5797
|
+
if (!envelope.meta) {
|
|
5798
|
+
return null;
|
|
5715
5799
|
}
|
|
5716
|
-
|
|
5717
|
-
|
|
5800
|
+
const meta = envelope.meta;
|
|
5801
|
+
const nested = meta.set;
|
|
5802
|
+
if (nested && typeof nested === "object" && !Array.isArray(nested)) {
|
|
5803
|
+
const aftValue = nested.aft;
|
|
5804
|
+
if (aftValue !== undefined) {
|
|
5805
|
+
return aftValue;
|
|
5806
|
+
}
|
|
5807
|
+
}
|
|
5808
|
+
if (meta["set.aft"] !== undefined) {
|
|
5809
|
+
return meta["set.aft"];
|
|
5718
5810
|
}
|
|
5811
|
+
return null;
|
|
5719
5812
|
}
|
|
5720
|
-
function
|
|
5721
|
-
|
|
5813
|
+
function computeDeterministicIndex(key, modulo) {
|
|
5814
|
+
if (modulo <= 0) {
|
|
5815
|
+
return 0;
|
|
5816
|
+
}
|
|
5817
|
+
let hash = 0;
|
|
5818
|
+
for (let i = 0; i < key.length; i += 1) {
|
|
5819
|
+
hash = (hash * 31 + key.charCodeAt(i)) >>> 0;
|
|
5820
|
+
}
|
|
5821
|
+
return hash % modulo;
|
|
5722
5822
|
}
|
|
5723
5823
|
|
|
5724
|
-
const FACTORY_META$
|
|
5725
|
-
base:
|
|
5726
|
-
key: "
|
|
5824
|
+
const FACTORY_META$7 = {
|
|
5825
|
+
base: LOAD_BALANCER_STICKINESS_MANAGER_FACTORY_BASE_TYPE,
|
|
5826
|
+
key: "AFTLoadBalancerStickinessManager",
|
|
5727
5827
|
};
|
|
5728
|
-
const DEFAULT_VALUES = {
|
|
5828
|
+
const DEFAULT_VALUES$1 = {
|
|
5829
|
+
enabled: true,
|
|
5830
|
+
clientEcho: false,
|
|
5831
|
+
defaultTtlSec: 30,
|
|
5832
|
+
cacheMax: 100000,
|
|
5729
5833
|
securityLevel: StickinessMode.SIGNED_OPTIONAL,
|
|
5730
5834
|
maxTtlSec: 7200,
|
|
5731
5835
|
};
|
|
5732
|
-
function
|
|
5836
|
+
function toBoolean(value, fallback) {
|
|
5837
|
+
return typeof value === "boolean" ? value : fallback;
|
|
5838
|
+
}
|
|
5839
|
+
function toNumber(value, fallback) {
|
|
5840
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
5841
|
+
return value;
|
|
5842
|
+
}
|
|
5843
|
+
return fallback;
|
|
5844
|
+
}
|
|
5845
|
+
function normalizeConfig$4(config) {
|
|
5733
5846
|
const record = (config ?? {});
|
|
5734
5847
|
const normalizedSecurity = record.securityLevel
|
|
5735
5848
|
? normalizeStickinessMode(record.securityLevel)
|
|
5736
|
-
: DEFAULT_VALUES.securityLevel;
|
|
5737
|
-
const securityLevel = normalizedSecurity ?? DEFAULT_VALUES.securityLevel;
|
|
5738
|
-
const maxTtlSecValue = typeof record.maxTtlSec === "number" && Number.isFinite(record.maxTtlSec)
|
|
5739
|
-
? Math.max(0, Math.floor(record.maxTtlSec))
|
|
5740
|
-
: DEFAULT_VALUES.maxTtlSec;
|
|
5849
|
+
: DEFAULT_VALUES$1.securityLevel;
|
|
5741
5850
|
return {
|
|
5742
5851
|
...record,
|
|
5743
|
-
type: "
|
|
5744
|
-
|
|
5745
|
-
|
|
5852
|
+
type: "AFTLoadBalancerStickinessManager",
|
|
5853
|
+
enabled: toBoolean(record.enabled, DEFAULT_VALUES$1.enabled),
|
|
5854
|
+
clientEcho: toBoolean(record.clientEcho, DEFAULT_VALUES$1.clientEcho),
|
|
5855
|
+
defaultTtlSec: toNumber(record.defaultTtlSec, DEFAULT_VALUES$1.defaultTtlSec),
|
|
5856
|
+
cacheMax: toNumber(record.cacheMax, DEFAULT_VALUES$1.cacheMax),
|
|
5857
|
+
securityLevel: normalizedSecurity,
|
|
5858
|
+
maxTtlSec: toNumber(record.maxTtlSec, DEFAULT_VALUES$1.maxTtlSec),
|
|
5746
5859
|
};
|
|
5747
5860
|
}
|
|
5748
|
-
class
|
|
5861
|
+
class AFTLoadBalancerStickinessManagerFactory extends LoadBalancerStickinessManagerFactory {
|
|
5749
5862
|
constructor() {
|
|
5750
5863
|
super(...arguments);
|
|
5751
|
-
this.type =
|
|
5752
|
-
this.isDefault =
|
|
5864
|
+
this.type = "AFTLoadBalancerStickinessManager";
|
|
5865
|
+
this.isDefault = false;
|
|
5753
5866
|
}
|
|
5754
|
-
async create(config,
|
|
5755
|
-
const resolvedConfig = normalizeConfig$
|
|
5756
|
-
|
|
5757
|
-
|
|
5758
|
-
|
|
5759
|
-
|
|
5760
|
-
|
|
5761
|
-
|
|
5762
|
-
|
|
5763
|
-
|
|
5764
|
-
|
|
5765
|
-
|
|
5766
|
-
}
|
|
5867
|
+
async create(config, keyProvider, verifier) {
|
|
5868
|
+
const resolvedConfig = normalizeConfig$4(config);
|
|
5869
|
+
let effectiveVerifier = verifier ?? null;
|
|
5870
|
+
if (!effectiveVerifier && keyProvider) {
|
|
5871
|
+
effectiveVerifier = createAftVerifier({
|
|
5872
|
+
securityLevel: resolvedConfig.securityLevel ?? DEFAULT_VALUES$1.securityLevel,
|
|
5873
|
+
keyProvider,
|
|
5874
|
+
defaultTtlSec: resolvedConfig.defaultTtlSec ?? DEFAULT_VALUES$1.defaultTtlSec,
|
|
5875
|
+
});
|
|
5876
|
+
}
|
|
5877
|
+
if (!effectiveVerifier) {
|
|
5878
|
+
throw new Error("AFTLoadBalancerStickinessManagerFactory requires an AFT verifier or key provider");
|
|
5879
|
+
}
|
|
5880
|
+
return new AFTLoadBalancerStickinessManager(resolvedConfig, effectiveVerifier);
|
|
5767
5881
|
}
|
|
5768
5882
|
}
|
|
5769
5883
|
|
|
5770
|
-
var
|
|
5884
|
+
var aftLoadBalancerStickinessManagerFactory = /*#__PURE__*/Object.freeze({
|
|
5771
5885
|
__proto__: null,
|
|
5772
|
-
|
|
5773
|
-
FACTORY_META: FACTORY_META$
|
|
5774
|
-
default:
|
|
5886
|
+
AFTLoadBalancerStickinessManagerFactory: AFTLoadBalancerStickinessManagerFactory,
|
|
5887
|
+
FACTORY_META: FACTORY_META$7,
|
|
5888
|
+
default: AFTLoadBalancerStickinessManagerFactory
|
|
5775
5889
|
});
|
|
5776
5890
|
|
|
5777
|
-
const logger$
|
|
5778
|
-
|
|
5779
|
-
|
|
5780
|
-
|
|
5781
|
-
process.env?.[ENV_VAR_SHOW_ENVELOPES] === "true";
|
|
5782
|
-
function nowUtc() {
|
|
5783
|
-
return new Date();
|
|
5784
|
-
}
|
|
5785
|
-
function formatTimestampForConsole() {
|
|
5786
|
-
return color(formatTimestamp(), AnsiColor.GRAY);
|
|
5787
|
-
}
|
|
5788
|
-
function prettyModel(value) {
|
|
5789
|
-
try {
|
|
5790
|
-
return jsonDumps(value);
|
|
5791
|
-
}
|
|
5792
|
-
catch (error) {
|
|
5793
|
-
return String(error);
|
|
5794
|
-
}
|
|
5795
|
-
}
|
|
5796
|
-
function coercePlacementMetadataValue(metadata, camelCaseKey, snakeCaseKey) {
|
|
5797
|
-
if (!metadata) {
|
|
5798
|
-
return undefined;
|
|
5799
|
-
}
|
|
5800
|
-
const record = metadata;
|
|
5801
|
-
if (record[camelCaseKey] !== undefined) {
|
|
5802
|
-
return record[camelCaseKey];
|
|
5891
|
+
const logger$3 = getLogger("naylence.fame.stickiness.aft_replica_stickiness_manager");
|
|
5892
|
+
function isStickinessRequired(context) {
|
|
5893
|
+
if (typeof context.stickinessRequired === "boolean") {
|
|
5894
|
+
return context.stickinessRequired;
|
|
5803
5895
|
}
|
|
5804
|
-
if (
|
|
5805
|
-
return
|
|
5896
|
+
if (typeof context.stickiness_required === "boolean") {
|
|
5897
|
+
return context.stickiness_required;
|
|
5806
5898
|
}
|
|
5807
|
-
return
|
|
5899
|
+
return false;
|
|
5808
5900
|
}
|
|
5809
|
-
class
|
|
5810
|
-
constructor(options) {
|
|
5811
|
-
|
|
5812
|
-
this.
|
|
5813
|
-
|
|
5814
|
-
this.
|
|
5815
|
-
this.
|
|
5816
|
-
this.
|
|
5817
|
-
|
|
5818
|
-
|
|
5819
|
-
|
|
5820
|
-
|
|
5821
|
-
|
|
5822
|
-
|
|
5823
|
-
|
|
5824
|
-
|
|
5825
|
-
|
|
5826
|
-
|
|
5827
|
-
|
|
5828
|
-
|
|
5829
|
-
|
|
5830
|
-
const systemId = trimmedSystemId.length > 0 ? trimmedSystemId : generateId();
|
|
5831
|
-
const wasAssigned = trimmedSystemId.length === 0;
|
|
5832
|
-
const normalizedHello = {
|
|
5833
|
-
...hello,
|
|
5834
|
-
systemId,
|
|
5835
|
-
};
|
|
5836
|
-
if (showEnvelopes) {
|
|
5837
|
-
// eslint-disable-next-line no-console
|
|
5838
|
-
console.log(`\n${formatTimestampForConsole()} - ${color("Received envelope 📨", AnsiColor.BLUE)}\n${prettyModel(normalizedHello)}`);
|
|
5901
|
+
class AFTReplicaStickinessManager extends BaseNodeEventListener {
|
|
5902
|
+
constructor(options = {}) {
|
|
5903
|
+
super();
|
|
5904
|
+
this.securityLevel =
|
|
5905
|
+
normalizeStickinessMode(options.securityLevel ?? DEFAULT_STICKINESS_SECURITY_LEVEL) ?? DEFAULT_STICKINESS_SECURITY_LEVEL;
|
|
5906
|
+
this.aftHelper = options.aftHelper ?? null;
|
|
5907
|
+
this.maxTtlSec = options.maxTtlSec ?? 7200;
|
|
5908
|
+
this.isInitialized = this.aftHelper !== null;
|
|
5909
|
+
this.negotiatedStickiness = null;
|
|
5910
|
+
if (this.aftHelper) {
|
|
5911
|
+
logger$3.debug("aft_replica_stickiness_manager_initialized", {
|
|
5912
|
+
helper_type: this.aftHelper.signer.constructor.name,
|
|
5913
|
+
security_level: this.aftHelper.signer.securityLevel,
|
|
5914
|
+
max_ttl_sec: this.aftHelper.maxTtlSec,
|
|
5915
|
+
});
|
|
5916
|
+
}
|
|
5917
|
+
else {
|
|
5918
|
+
logger$3.debug("aft_replica_stickiness_manager_created", {
|
|
5919
|
+
security_level: this.securityLevel,
|
|
5920
|
+
max_ttl_sec: this.maxTtlSec,
|
|
5921
|
+
});
|
|
5839
5922
|
}
|
|
5840
|
-
|
|
5841
|
-
|
|
5842
|
-
|
|
5843
|
-
|
|
5844
|
-
|
|
5845
|
-
|
|
5923
|
+
}
|
|
5924
|
+
offer() {
|
|
5925
|
+
return { mode: "aft", supportedModes: ["aft", "attr"], version: 1 };
|
|
5926
|
+
}
|
|
5927
|
+
accept(stickiness) {
|
|
5928
|
+
this.negotiatedStickiness = stickiness ?? null;
|
|
5929
|
+
logger$3.debug("replica_stickiness_policy_set", {
|
|
5930
|
+
enabled: stickiness?.enabled ?? null,
|
|
5931
|
+
mode: stickiness?.mode ?? null,
|
|
5932
|
+
ttl: stickiness?.ttlSec ?? null,
|
|
5846
5933
|
});
|
|
5847
|
-
|
|
5848
|
-
|
|
5849
|
-
if (
|
|
5850
|
-
|
|
5851
|
-
fullMetadata.instanceId = normalizedHello.instanceId;
|
|
5852
|
-
}
|
|
5853
|
-
if (fullMetadata.instance_id === undefined) {
|
|
5854
|
-
fullMetadata.instance_id = normalizedHello.instanceId;
|
|
5855
|
-
}
|
|
5934
|
+
}
|
|
5935
|
+
async onForwardUpstream(_node, envelope, context) {
|
|
5936
|
+
if (!context) {
|
|
5937
|
+
return envelope;
|
|
5856
5938
|
}
|
|
5857
|
-
|
|
5858
|
-
|
|
5859
|
-
|
|
5860
|
-
|
|
5861
|
-
|
|
5862
|
-
|
|
5863
|
-
logicals: normalizedHello.logicals,
|
|
5939
|
+
const helper = this.aftHelper;
|
|
5940
|
+
if (!helper) {
|
|
5941
|
+
logger$3.debug("aft_helper_not_ready_skip_injection", {
|
|
5942
|
+
envelope_id: envelope.id,
|
|
5943
|
+
delivery_origin: context.originType ?? null,
|
|
5944
|
+
reason: "not_initialized",
|
|
5864
5945
|
});
|
|
5865
|
-
|
|
5866
|
-
|
|
5867
|
-
|
|
5868
|
-
|
|
5869
|
-
|
|
5946
|
+
return envelope;
|
|
5947
|
+
}
|
|
5948
|
+
const stickinessContext = context;
|
|
5949
|
+
if (isStickinessRequired(stickinessContext) &&
|
|
5950
|
+
context.originType === DeliveryOriginType$1.LOCAL) {
|
|
5951
|
+
if (this.negotiatedStickiness) {
|
|
5952
|
+
const negotiated = this.negotiatedStickiness;
|
|
5953
|
+
if (negotiated.enabled === false ||
|
|
5954
|
+
(negotiated.mode !== null &&
|
|
5955
|
+
negotiated.mode !== undefined &&
|
|
5956
|
+
negotiated.mode !== "aft")) {
|
|
5957
|
+
logger$3.debug("aft_injection_skipped_due_to_policy", {
|
|
5958
|
+
envelope_id: envelope.id,
|
|
5959
|
+
policy_mode: negotiated.mode ?? null,
|
|
5960
|
+
policy_enabled: negotiated.enabled ?? null,
|
|
5961
|
+
});
|
|
5962
|
+
return envelope;
|
|
5963
|
+
}
|
|
5964
|
+
}
|
|
5965
|
+
logger$3.debug("applying_aft_for_upstream_stickiness_required", {
|
|
5966
|
+
envelope_id: envelope.id,
|
|
5967
|
+
from_system_id: context.fromSystemId ?? null,
|
|
5968
|
+
delivery_origin: context.originType ?? null,
|
|
5969
|
+
});
|
|
5970
|
+
const success = await helper.requestStickiness(envelope, {
|
|
5971
|
+
ttlSec: null,
|
|
5972
|
+
scope: "node",
|
|
5973
|
+
context: stickinessContext,
|
|
5974
|
+
});
|
|
5975
|
+
if (success) {
|
|
5976
|
+
logger$3.debug("aft_token_applied_via_context_flag_upstream", {
|
|
5977
|
+
envelope_id: envelope.id,
|
|
5978
|
+
from_system_id: context.fromSystemId ?? null,
|
|
5979
|
+
delivery_origin: context.originType ?? null,
|
|
5980
|
+
});
|
|
5981
|
+
}
|
|
5982
|
+
else {
|
|
5983
|
+
logger$3.debug("aft_token_not_applied_upstream", {
|
|
5984
|
+
envelope_id: envelope.id,
|
|
5985
|
+
delivery_origin: context.originType ?? null,
|
|
5986
|
+
reason: "helper_returned_false",
|
|
5870
5987
|
});
|
|
5871
|
-
throw new Error(`Invalid logical format: ${pathError}`);
|
|
5872
5988
|
}
|
|
5873
|
-
logger$2.debug("logicals_validation_successful");
|
|
5874
5989
|
}
|
|
5875
|
-
|
|
5876
|
-
|
|
5877
|
-
|
|
5878
|
-
|
|
5879
|
-
|
|
5880
|
-
|
|
5990
|
+
return envelope;
|
|
5991
|
+
}
|
|
5992
|
+
async onNodeStarted(node) {
|
|
5993
|
+
if (!this.isInitialized) {
|
|
5994
|
+
await this.initializeAftHelper(node);
|
|
5995
|
+
return;
|
|
5996
|
+
}
|
|
5997
|
+
if (this.aftHelper && node.sid) {
|
|
5998
|
+
this.updateNodeSid(node.sid);
|
|
5999
|
+
logger$3.debug("aft_replica_stickiness_manager_sid_updated", {
|
|
6000
|
+
node_id: node.id ?? "unknown",
|
|
6001
|
+
node_sid: node.sid,
|
|
6002
|
+
security_level: this.aftHelper.signer.securityLevel,
|
|
5881
6003
|
});
|
|
5882
|
-
throw new Error(placementResult.reason || "Node not accepted");
|
|
5883
6004
|
}
|
|
5884
|
-
|
|
5885
|
-
|
|
5886
|
-
|
|
5887
|
-
assignedPath,
|
|
5888
|
-
targetPhysicalPath: placementResult.targetPhysicalPath ?? null,
|
|
5889
|
-
targetSystemId: placementResult.targetSystemId ?? null,
|
|
5890
|
-
});
|
|
5891
|
-
const acceptedCapabilities = coercePlacementMetadataValue(placementResult.metadata, "acceptedCapabilities", "accepted_capabilities") ??
|
|
5892
|
-
normalizedHello.capabilities ??
|
|
5893
|
-
null;
|
|
5894
|
-
const acceptedLogicals = coercePlacementMetadataValue(placementResult.metadata, "acceptedLogicals", "accepted_logicals") ??
|
|
5895
|
-
normalizedHello.logicals ??
|
|
5896
|
-
null;
|
|
5897
|
-
logger$2.debug("processing_placement_result_metadata", {
|
|
5898
|
-
acceptedCapabilities,
|
|
5899
|
-
acceptedLogicals,
|
|
5900
|
-
hasPlacementMetadata: placementResult.metadata !== undefined &&
|
|
5901
|
-
placementResult.metadata !== null,
|
|
5902
|
-
});
|
|
5903
|
-
const connectionGrants = [];
|
|
5904
|
-
const metadataInstanceId = (typeof fullMetadata.instanceId === "string" &&
|
|
5905
|
-
fullMetadata.instanceId) ||
|
|
5906
|
-
(typeof fullMetadata.instance_id === "string" &&
|
|
5907
|
-
fullMetadata.instance_id) ||
|
|
5908
|
-
normalizedHello.instanceId ||
|
|
5909
|
-
generateId();
|
|
5910
|
-
if (placementResult.targetSystemId) {
|
|
5911
|
-
logger$2.debug("issuing_node_attach_token", {
|
|
5912
|
-
systemId,
|
|
5913
|
-
assignedPath,
|
|
6005
|
+
else if (!node.sid) {
|
|
6006
|
+
logger$3.warning("aft_replica_stickiness_manager_no_sid_available", {
|
|
6007
|
+
node_id: node.id ?? "unknown",
|
|
5914
6008
|
});
|
|
5915
|
-
|
|
5916
|
-
|
|
5917
|
-
|
|
5918
|
-
|
|
5919
|
-
assigned_path: placementResult.assignedPath,
|
|
5920
|
-
accepted_logicals: acceptedLogicals,
|
|
5921
|
-
instance_id: metadataInstanceId,
|
|
6009
|
+
}
|
|
6010
|
+
else {
|
|
6011
|
+
logger$3.error("aft_replica_stickiness_manager_node_missing_sid", {
|
|
6012
|
+
node_type: node.constructor?.name ?? typeof node,
|
|
5922
6013
|
});
|
|
5923
|
-
|
|
5924
|
-
|
|
5925
|
-
|
|
5926
|
-
|
|
5927
|
-
|
|
5928
|
-
|
|
5929
|
-
|
|
5930
|
-
? (transportInfo.connectionGrant.type ??
|
|
5931
|
-
"Unknown")
|
|
5932
|
-
: "Unknown",
|
|
6014
|
+
}
|
|
6015
|
+
}
|
|
6016
|
+
updateNodeSid(nodeSid) {
|
|
6017
|
+
if (this.aftHelper) {
|
|
6018
|
+
this.aftHelper.nodeSid = nodeSid;
|
|
6019
|
+
logger$3.debug("aft_replica_stickiness_manager_sid_updated", {
|
|
6020
|
+
new_sid: nodeSid,
|
|
5933
6021
|
});
|
|
5934
|
-
connectionGrants.push(transportInfo.connectionGrant);
|
|
5935
6022
|
}
|
|
5936
|
-
|
|
5937
|
-
|
|
5938
|
-
|
|
5939
|
-
|
|
5940
|
-
|
|
5941
|
-
|
|
5942
|
-
|
|
5943
|
-
|
|
5944
|
-
|
|
5945
|
-
|
|
5946
|
-
|
|
5947
|
-
|
|
5948
|
-
|
|
5949
|
-
|
|
5950
|
-
|
|
5951
|
-
|
|
5952
|
-
|
|
5953
|
-
|
|
5954
|
-
|
|
5955
|
-
|
|
5956
|
-
const
|
|
5957
|
-
|
|
5958
|
-
|
|
5959
|
-
|
|
5960
|
-
|
|
5961
|
-
|
|
5962
|
-
|
|
5963
|
-
|
|
5964
|
-
|
|
5965
|
-
|
|
5966
|
-
|
|
5967
|
-
|
|
5968
|
-
|
|
5969
|
-
|
|
5970
|
-
|
|
5971
|
-
|
|
5972
|
-
|
|
5973
|
-
|
|
5974
|
-
|
|
5975
|
-
|
|
5976
|
-
|
|
5977
|
-
|
|
5978
|
-
|
|
5979
|
-
|
|
5980
|
-
|
|
6023
|
+
}
|
|
6024
|
+
async initializeAftHelper(node) {
|
|
6025
|
+
const nodeSid = node.sid;
|
|
6026
|
+
if (!nodeSid) {
|
|
6027
|
+
logger$3.error("aft_replica_stickiness_manager_cannot_initialize_no_sid", {
|
|
6028
|
+
node_id: node.id ?? "unknown",
|
|
6029
|
+
});
|
|
6030
|
+
return;
|
|
6031
|
+
}
|
|
6032
|
+
const cryptoProvider = node.cryptoProvider ?? null;
|
|
6033
|
+
if (!cryptoProvider) {
|
|
6034
|
+
logger$3.error("aft_replica_stickiness_manager_cannot_initialize_no_crypto_provider", {
|
|
6035
|
+
node_id: node.id ?? "unknown",
|
|
6036
|
+
});
|
|
6037
|
+
return;
|
|
6038
|
+
}
|
|
6039
|
+
const keyId = typeof cryptoProvider.signatureKeyId === "string" &&
|
|
6040
|
+
cryptoProvider.signatureKeyId.length > 0
|
|
6041
|
+
? cryptoProvider.signatureKeyId
|
|
6042
|
+
: "default-key-id";
|
|
6043
|
+
const privateKeyPem = typeof cryptoProvider.signingPrivatePem === "string"
|
|
6044
|
+
? cryptoProvider.signingPrivatePem
|
|
6045
|
+
: null;
|
|
6046
|
+
if (this.securityLevel === StickinessMode.STRICT && !privateKeyPem) {
|
|
6047
|
+
logger$3.error("aft_replica_stickiness_manager_initialization_failed", {
|
|
6048
|
+
node_id: node.id ?? "unknown",
|
|
6049
|
+
error: "Missing signing private key for strict security level",
|
|
6050
|
+
});
|
|
6051
|
+
return;
|
|
6052
|
+
}
|
|
6053
|
+
try {
|
|
6054
|
+
const helper = createAftHelper({
|
|
6055
|
+
securityLevel: this.securityLevel,
|
|
6056
|
+
nodeSid,
|
|
6057
|
+
kid: keyId,
|
|
6058
|
+
privateKeyPem,
|
|
6059
|
+
maxTtlSec: this.maxTtlSec,
|
|
6060
|
+
});
|
|
6061
|
+
this.aftHelper = helper;
|
|
6062
|
+
this.isInitialized = true;
|
|
6063
|
+
logger$3.debug("aft_replica_stickiness_manager_initialized", {
|
|
6064
|
+
node_id: node.id ?? "unknown",
|
|
6065
|
+
node_sid: nodeSid,
|
|
6066
|
+
key_id: keyId,
|
|
6067
|
+
security_level: helper.signer.securityLevel,
|
|
6068
|
+
});
|
|
5981
6069
|
}
|
|
5982
|
-
|
|
6070
|
+
catch (error) {
|
|
6071
|
+
logger$3.error("aft_replica_stickiness_manager_initialization_failed", {
|
|
6072
|
+
node_id: node.id ?? "unknown",
|
|
6073
|
+
error: error instanceof Error ? error.message : String(error),
|
|
6074
|
+
});
|
|
6075
|
+
}
|
|
6076
|
+
}
|
|
6077
|
+
get signer() {
|
|
6078
|
+
return this.aftHelper?.signer ?? null;
|
|
6079
|
+
}
|
|
6080
|
+
getHelper() {
|
|
6081
|
+
return this.aftHelper;
|
|
5983
6082
|
}
|
|
5984
6083
|
}
|
|
6084
|
+
function createAftReplicaStickinessManager(aftHelper) {
|
|
6085
|
+
return new AFTReplicaStickinessManager({ aftHelper });
|
|
6086
|
+
}
|
|
5985
6087
|
|
|
5986
|
-
const FACTORY_META$
|
|
5987
|
-
base:
|
|
5988
|
-
key: "
|
|
5989
|
-
priority: 100,
|
|
5990
|
-
isDefault: true,
|
|
6088
|
+
const FACTORY_META$6 = {
|
|
6089
|
+
base: REPLICA_STICKINESS_MANAGER_FACTORY_BASE_TYPE,
|
|
6090
|
+
key: "AFTReplicaStickinessManager",
|
|
5991
6091
|
};
|
|
5992
|
-
|
|
6092
|
+
const DEFAULT_VALUES = {
|
|
6093
|
+
securityLevel: StickinessMode.SIGNED_OPTIONAL,
|
|
6094
|
+
maxTtlSec: 7200,
|
|
6095
|
+
};
|
|
6096
|
+
function normalizeConfig$3(config) {
|
|
6097
|
+
const record = (config ?? {});
|
|
6098
|
+
const normalizedSecurity = record.securityLevel
|
|
6099
|
+
? normalizeStickinessMode(record.securityLevel)
|
|
6100
|
+
: DEFAULT_VALUES.securityLevel;
|
|
6101
|
+
const securityLevel = normalizedSecurity ?? DEFAULT_VALUES.securityLevel;
|
|
6102
|
+
const maxTtlSecValue = typeof record.maxTtlSec === "number" && Number.isFinite(record.maxTtlSec)
|
|
6103
|
+
? Math.max(0, Math.floor(record.maxTtlSec))
|
|
6104
|
+
: DEFAULT_VALUES.maxTtlSec;
|
|
6105
|
+
return {
|
|
6106
|
+
...record,
|
|
6107
|
+
type: "AFTReplicaStickinessManager",
|
|
6108
|
+
securityLevel,
|
|
6109
|
+
maxTtlSec: maxTtlSecValue,
|
|
6110
|
+
};
|
|
6111
|
+
}
|
|
6112
|
+
class AFTReplicaStickinessManagerFactory extends ReplicaStickinessManagerFactory {
|
|
5993
6113
|
constructor() {
|
|
5994
6114
|
super(...arguments);
|
|
5995
|
-
this.type = FACTORY_META$
|
|
5996
|
-
this.isDefault =
|
|
5997
|
-
this.priority = FACTORY_META$5.priority;
|
|
5998
|
-
}
|
|
5999
|
-
async create(config, ...factoryArgs) {
|
|
6000
|
-
const normalized = normalizeConfig$2(config);
|
|
6001
|
-
// Crypto provider should be passed from upstream (node-welcome-server)
|
|
6002
|
-
// Do not create it here - downstream components should use what's passed in factoryArgs
|
|
6003
|
-
const placementStrategy = await NodePlacementStrategyFactory.createNodePlacementStrategy(normalized.placementConfig ?? null, factoryArgs.length > 0 ? { factoryArgs } : undefined);
|
|
6004
|
-
const transportProvisioner = await TransportProvisionerFactory.createTransportProvisioner(normalized.transportConfig ?? null, factoryArgs.length > 0 ? { factoryArgs } : undefined);
|
|
6005
|
-
const tokenIssuer = await TokenIssuerFactory.createTokenIssuer(normalized.tokenIssuerConfig ?? null, factoryArgs.length > 0 ? { factoryArgs } : undefined);
|
|
6006
|
-
let authorizer = null;
|
|
6007
|
-
if (normalized.authorizerConfig) {
|
|
6008
|
-
authorizer =
|
|
6009
|
-
(await AuthorizerFactory.createAuthorizer(normalized.authorizerConfig, {
|
|
6010
|
-
factoryArgs,
|
|
6011
|
-
})) ?? null;
|
|
6012
|
-
}
|
|
6013
|
-
const options = {
|
|
6014
|
-
placementStrategy,
|
|
6015
|
-
transportProvisioner,
|
|
6016
|
-
tokenIssuer,
|
|
6017
|
-
authorizer,
|
|
6018
|
-
caServiceUrl: normalized.caServiceUrl,
|
|
6019
|
-
};
|
|
6020
|
-
if (normalized.ttlSec !== undefined) {
|
|
6021
|
-
options.ttlSec = normalized.ttlSec;
|
|
6022
|
-
}
|
|
6023
|
-
return new AdvancedWelcomeService(options);
|
|
6024
|
-
}
|
|
6025
|
-
}
|
|
6026
|
-
function normalizeConfig$2(config) {
|
|
6027
|
-
if (!config) {
|
|
6028
|
-
throw new Error("AdvancedWelcomeService requires configuration");
|
|
6029
|
-
}
|
|
6030
|
-
const source = config;
|
|
6031
|
-
const ttlCandidate = typeof source.ttlSec === "number"
|
|
6032
|
-
? source.ttlSec
|
|
6033
|
-
: typeof source.ttl_sec === "number"
|
|
6034
|
-
? source.ttl_sec
|
|
6035
|
-
: undefined;
|
|
6036
|
-
const caServiceUrlCandidate = typeof source.caServiceUrl === "string" &&
|
|
6037
|
-
source.caServiceUrl.trim().length > 0
|
|
6038
|
-
? source.caServiceUrl.trim()
|
|
6039
|
-
: typeof source.ca_service_url === "string" &&
|
|
6040
|
-
source.ca_service_url.trim().length > 0
|
|
6041
|
-
? source.ca_service_url.trim()
|
|
6042
|
-
: undefined;
|
|
6043
|
-
if (!caServiceUrlCandidate) {
|
|
6044
|
-
throw new Error("AdvancedWelcomeService configuration requires caServiceUrl");
|
|
6045
|
-
}
|
|
6046
|
-
const normalized = {
|
|
6047
|
-
caServiceUrl: caServiceUrlCandidate,
|
|
6048
|
-
};
|
|
6049
|
-
if (source.placement !== undefined) {
|
|
6050
|
-
normalized.placementConfig =
|
|
6051
|
-
source.placement ?? null;
|
|
6052
|
-
}
|
|
6053
|
-
if (source.transport !== undefined) {
|
|
6054
|
-
normalized.transportConfig =
|
|
6055
|
-
source.transport ?? null;
|
|
6056
|
-
}
|
|
6057
|
-
const tokenIssuerConfig = source.tokenIssuer !== undefined
|
|
6058
|
-
? source.tokenIssuer
|
|
6059
|
-
: source.token_issuer !== undefined
|
|
6060
|
-
? source.token_issuer
|
|
6061
|
-
: undefined;
|
|
6062
|
-
if (tokenIssuerConfig !== undefined) {
|
|
6063
|
-
normalized.tokenIssuerConfig =
|
|
6064
|
-
tokenIssuerConfig ?? null;
|
|
6065
|
-
}
|
|
6066
|
-
if (source.authorizer !== undefined) {
|
|
6067
|
-
normalized.authorizerConfig =
|
|
6068
|
-
source.authorizer ?? null;
|
|
6115
|
+
this.type = FACTORY_META$6.key;
|
|
6116
|
+
this.isDefault = true;
|
|
6069
6117
|
}
|
|
6070
|
-
|
|
6071
|
-
|
|
6118
|
+
async create(config, dependencies) {
|
|
6119
|
+
const resolvedConfig = normalizeConfig$3(config);
|
|
6120
|
+
const helper = dependencies?.aftHelper ?? null;
|
|
6121
|
+
const securityLevel = normalizeStickinessMode(resolvedConfig.securityLevel ?? DEFAULT_VALUES.securityLevel) ?? DEFAULT_VALUES.securityLevel;
|
|
6122
|
+
const maxTtlSec = typeof resolvedConfig.maxTtlSec === "number" &&
|
|
6123
|
+
Number.isFinite(resolvedConfig.maxTtlSec)
|
|
6124
|
+
? Math.max(0, Math.floor(resolvedConfig.maxTtlSec))
|
|
6125
|
+
: DEFAULT_VALUES.maxTtlSec;
|
|
6126
|
+
return new AFTReplicaStickinessManager({
|
|
6127
|
+
securityLevel,
|
|
6128
|
+
maxTtlSec,
|
|
6129
|
+
aftHelper: helper,
|
|
6130
|
+
});
|
|
6072
6131
|
}
|
|
6073
|
-
return normalized;
|
|
6074
6132
|
}
|
|
6075
6133
|
|
|
6076
|
-
var
|
|
6134
|
+
var aftReplicaStickinessManagerFactory = /*#__PURE__*/Object.freeze({
|
|
6077
6135
|
__proto__: null,
|
|
6078
|
-
|
|
6079
|
-
FACTORY_META: FACTORY_META$
|
|
6080
|
-
default:
|
|
6136
|
+
AFTReplicaStickinessManagerFactory: AFTReplicaStickinessManagerFactory,
|
|
6137
|
+
FACTORY_META: FACTORY_META$6,
|
|
6138
|
+
default: AFTReplicaStickinessManagerFactory
|
|
6081
6139
|
});
|
|
6082
6140
|
|
|
6083
|
-
|
|
6084
|
-
|
|
6085
|
-
|
|
6086
|
-
|
|
6087
|
-
|
|
6088
|
-
|
|
6089
|
-
|
|
6090
|
-
|
|
6091
|
-
|
|
6092
|
-
|
|
6093
|
-
|
|
6094
|
-
|
|
6095
|
-
|
|
6096
|
-
|
|
6097
|
-
"./security/encryption/sealed/x25519-encryption-manager-factory.js",
|
|
6098
|
-
"./security/keys/x5c-key-manager-factory.js",
|
|
6099
|
-
"./security/signing/eddsa-envelope-signer-factory.js",
|
|
6100
|
-
"./security/signing/eddsa-envelope-verifier-factory.js",
|
|
6101
|
-
"./stickiness/aft-load-balancer-stickiness-manager-factory.js",
|
|
6102
|
-
"./stickiness/aft-replica-stickiness-manager-factory.js",
|
|
6103
|
-
"./welcome/advanced-welcome-service-factory.js"
|
|
6104
|
-
];
|
|
6105
|
-
const MODULE_LOADERS = {
|
|
6106
|
-
"./security/cert/default-ca-service-factory.js": () => Promise.resolve().then(function () { return defaultCaServiceFactory; }),
|
|
6107
|
-
"./security/cert/default-certificate-manager-factory.js": () => Promise.resolve().then(function () { return defaultCertificateManagerFactory; }),
|
|
6108
|
-
"./security/cert/trust-store/browser-trust-store-provider-factory.js": () => Promise.resolve().then(function () { return browserTrustStoreProviderFactory; }),
|
|
6109
|
-
"./security/cert/trust-store/node-trust-store-provider-factory.js": () => Promise.resolve().then(function () { return nodeTrustStoreProviderFactory; }),
|
|
6110
|
-
"./security/encryption/channel/channel-encryption-manager-factory.js": () => Promise.resolve().then(function () { return channelEncryptionManagerFactory; }),
|
|
6111
|
-
"./security/encryption/composite-encryption-manager-factory.js": () => Promise.resolve().then(function () { return compositeEncryptionManagerFactory; }),
|
|
6112
|
-
"./security/encryption/default-secure-channel-manager-factory.js": () => Promise.resolve().then(function () { return defaultSecureChannelManagerFactory; }),
|
|
6113
|
-
"./security/encryption/sealed/x25519-encryption-manager-factory.js": () => Promise.resolve().then(function () { return x25519EncryptionManagerFactory; }),
|
|
6114
|
-
"./security/keys/x5c-key-manager-factory.js": () => Promise.resolve().then(function () { return x5cKeyManagerFactory; }),
|
|
6115
|
-
"./security/signing/eddsa-envelope-signer-factory.js": () => Promise.resolve().then(function () { return eddsaEnvelopeSignerFactory; }),
|
|
6116
|
-
"./security/signing/eddsa-envelope-verifier-factory.js": () => Promise.resolve().then(function () { return eddsaEnvelopeVerifierFactory; }),
|
|
6117
|
-
"./stickiness/aft-load-balancer-stickiness-manager-factory.js": () => Promise.resolve().then(function () { return aftLoadBalancerStickinessManagerFactory; }),
|
|
6118
|
-
"./stickiness/aft-replica-stickiness-manager-factory.js": () => Promise.resolve().then(function () { return aftReplicaStickinessManagerFactory; }),
|
|
6119
|
-
"./welcome/advanced-welcome-service-factory.js": () => Promise.resolve().then(function () { return advancedWelcomeServiceFactory; }),
|
|
6120
|
-
};
|
|
6121
|
-
|
|
6122
|
-
const SECURITY_PREFIX = "./security/";
|
|
6123
|
-
const SECURITY_MODULES = MODULES.filter((spec) => spec.startsWith(SECURITY_PREFIX));
|
|
6124
|
-
const EXTRA_MODULES = MODULES.filter((spec) => !spec.startsWith(SECURITY_PREFIX));
|
|
6125
|
-
const NODE_ONLY_MODULES = new Set([
|
|
6126
|
-
"./security/cert/default-ca-service-factory.js",
|
|
6127
|
-
"./security/cert/trust-store/node-trust-store-provider-factory.js",
|
|
6128
|
-
]);
|
|
6129
|
-
const FACTORY_MODULE_PREFIX$1 = "@naylence/advanced-security/naylence/fame/";
|
|
6130
|
-
const BROWSER_DIST_SEGMENT = "/dist/browser/";
|
|
6131
|
-
function detectModuleUrl() {
|
|
6132
|
-
if (typeof __filename === "string") {
|
|
6133
|
-
try {
|
|
6134
|
-
return __filename.startsWith("file://")
|
|
6135
|
-
? __filename
|
|
6136
|
-
: `file://${__filename}`;
|
|
6137
|
-
}
|
|
6138
|
-
catch {
|
|
6139
|
-
// fall through to stack parsing
|
|
6140
|
-
}
|
|
6141
|
-
}
|
|
6142
|
-
try {
|
|
6143
|
-
throw new Error();
|
|
6144
|
-
}
|
|
6145
|
-
catch (error) {
|
|
6146
|
-
const stack = typeof error === "object" && error && "stack" in error
|
|
6147
|
-
? String(error.stack ?? "")
|
|
6148
|
-
: "";
|
|
6149
|
-
const lines = stack.split("\n");
|
|
6150
|
-
for (const line of lines) {
|
|
6151
|
-
const match = line.match(/(https?:\/\/[^\s)]+|file:\/\/[^\s)]+\.(?:js|ts)|\/(?:[^\s)]+\.(?:js|ts)))/u);
|
|
6152
|
-
const candidate = match?.[1];
|
|
6153
|
-
if (!candidate) {
|
|
6154
|
-
continue;
|
|
6155
|
-
}
|
|
6156
|
-
if (candidate.startsWith("http://") || candidate.startsWith("https://")) {
|
|
6157
|
-
return candidate;
|
|
6158
|
-
}
|
|
6159
|
-
if (candidate.startsWith("file://")) {
|
|
6160
|
-
return candidate;
|
|
6161
|
-
}
|
|
6162
|
-
return `file://${candidate}`;
|
|
6163
|
-
}
|
|
6164
|
-
}
|
|
6165
|
-
return null;
|
|
6166
|
-
}
|
|
6167
|
-
function computeBrowserFactoryBase(rawUrl) {
|
|
6168
|
-
if (!rawUrl) {
|
|
6169
|
-
return null;
|
|
6170
|
-
}
|
|
6171
|
-
const sanitized = rawUrl.split("?")[0]?.split("#")[0] ?? rawUrl;
|
|
6172
|
-
const esmMarker = "/dist/esm/naylence/fame/";
|
|
6173
|
-
const distMarker = "/dist/";
|
|
6174
|
-
if (sanitized.includes(esmMarker)) {
|
|
6175
|
-
return sanitized.slice(0, sanitized.indexOf(esmMarker) + esmMarker.length);
|
|
6176
|
-
}
|
|
6177
|
-
if (rawUrl.includes(BROWSER_DIST_SEGMENT)) {
|
|
6178
|
-
return new URL("../esm/naylence/fame/", rawUrl).href;
|
|
6141
|
+
const logger$2 = getLogger("naylence.fame.welcome.advanced_welcome_service");
|
|
6142
|
+
const ENV_VAR_SHOW_ENVELOPES = "FAME_SHOW_ENVELOPES";
|
|
6143
|
+
const DEFAULT_TTL_SEC = 3600;
|
|
6144
|
+
const showEnvelopes = typeof process !== "undefined" &&
|
|
6145
|
+
process.env?.[ENV_VAR_SHOW_ENVELOPES] === "true";
|
|
6146
|
+
function nowUtc() {
|
|
6147
|
+
return new Date();
|
|
6148
|
+
}
|
|
6149
|
+
function formatTimestampForConsole() {
|
|
6150
|
+
return color(formatTimestamp(), AnsiColor.GRAY);
|
|
6151
|
+
}
|
|
6152
|
+
function prettyModel(value) {
|
|
6153
|
+
try {
|
|
6154
|
+
return jsonDumps(value);
|
|
6179
6155
|
}
|
|
6180
|
-
|
|
6181
|
-
|
|
6182
|
-
return `${base.replace(/browser\/?$/u, "")}esm/naylence/fame/`;
|
|
6156
|
+
catch (error) {
|
|
6157
|
+
return String(error);
|
|
6183
6158
|
}
|
|
6184
|
-
|
|
6185
|
-
|
|
6186
|
-
|
|
6187
|
-
return
|
|
6159
|
+
}
|
|
6160
|
+
function coercePlacementMetadataValue(metadata, camelCaseKey, snakeCaseKey) {
|
|
6161
|
+
if (!metadata) {
|
|
6162
|
+
return undefined;
|
|
6188
6163
|
}
|
|
6189
|
-
const
|
|
6190
|
-
if (
|
|
6191
|
-
|
|
6192
|
-
const projectRoot = sanitized.slice(0, index);
|
|
6193
|
-
return `${projectRoot}/dist/esm/naylence/fame/`;
|
|
6164
|
+
const record = metadata;
|
|
6165
|
+
if (record[camelCaseKey] !== undefined) {
|
|
6166
|
+
return record[camelCaseKey];
|
|
6194
6167
|
}
|
|
6195
|
-
if (
|
|
6196
|
-
|
|
6197
|
-
const parsed = new URL(rawUrl);
|
|
6198
|
-
const viteDepsSegment = "/node_modules/.vite/deps/";
|
|
6199
|
-
if (parsed.pathname.includes(viteDepsSegment)) {
|
|
6200
|
-
const baseOrigin = `${parsed.protocol}//${parsed.host}`;
|
|
6201
|
-
return `${baseOrigin}/node_modules/@naylence/advanced-security/dist/esm/naylence/fame/`;
|
|
6202
|
-
}
|
|
6203
|
-
}
|
|
6204
|
-
catch {
|
|
6205
|
-
// ignore
|
|
6206
|
-
}
|
|
6168
|
+
if (record[snakeCaseKey] !== undefined) {
|
|
6169
|
+
return record[snakeCaseKey];
|
|
6207
6170
|
}
|
|
6208
|
-
return
|
|
6171
|
+
return undefined;
|
|
6209
6172
|
}
|
|
6210
|
-
|
|
6211
|
-
|
|
6212
|
-
|
|
6213
|
-
|
|
6214
|
-
|
|
6215
|
-
|
|
6216
|
-
|
|
6217
|
-
|
|
6218
|
-
|
|
6173
|
+
class AdvancedWelcomeService {
|
|
6174
|
+
constructor(options) {
|
|
6175
|
+
this.placementStrategy = options.placementStrategy;
|
|
6176
|
+
this.transportProvisioner = options.transportProvisioner;
|
|
6177
|
+
this.tokenIssuer = options.tokenIssuer;
|
|
6178
|
+
this.authorizer = options.authorizer ?? null;
|
|
6179
|
+
this.caServiceUrl = options.caServiceUrl;
|
|
6180
|
+
this.ttlSec =
|
|
6181
|
+
typeof options.ttlSec === "number" && Number.isFinite(options.ttlSec)
|
|
6182
|
+
? Math.max(0, options.ttlSec)
|
|
6183
|
+
: DEFAULT_TTL_SEC;
|
|
6184
|
+
logger$2.debug("initialized_advanced_welcome_service", {
|
|
6185
|
+
ca_service_url: this.caServiceUrl,
|
|
6186
|
+
ttl_sec: this.ttlSec,
|
|
6187
|
+
});
|
|
6219
6188
|
}
|
|
6220
|
-
|
|
6221
|
-
|
|
6222
|
-
|
|
6223
|
-
|
|
6224
|
-
|
|
6225
|
-
|
|
6226
|
-
|
|
6227
|
-
|
|
6228
|
-
|
|
6229
|
-
|
|
6230
|
-
|
|
6231
|
-
|
|
6189
|
+
async handleHello(hello, metadata) {
|
|
6190
|
+
const fullMetadata = metadata
|
|
6191
|
+
? { ...metadata }
|
|
6192
|
+
: {};
|
|
6193
|
+
const trimmedSystemId = typeof hello.systemId === "string" ? hello.systemId.trim() : "";
|
|
6194
|
+
const systemId = trimmedSystemId.length > 0 ? trimmedSystemId : generateId();
|
|
6195
|
+
const wasAssigned = trimmedSystemId.length === 0;
|
|
6196
|
+
const normalizedHello = {
|
|
6197
|
+
...hello,
|
|
6198
|
+
systemId,
|
|
6199
|
+
};
|
|
6200
|
+
if (showEnvelopes) {
|
|
6201
|
+
// eslint-disable-next-line no-console
|
|
6202
|
+
console.log(`\n${formatTimestampForConsole()} - ${color("Received envelope 📨", AnsiColor.BLUE)}\n${prettyModel(normalizedHello)}`);
|
|
6232
6203
|
}
|
|
6233
|
-
|
|
6234
|
-
|
|
6235
|
-
|
|
6236
|
-
|
|
6237
|
-
|
|
6238
|
-
|
|
6204
|
+
logger$2.debug("starting_hello_frame_processing", {
|
|
6205
|
+
instanceId: normalizedHello.instanceId,
|
|
6206
|
+
systemId,
|
|
6207
|
+
logicals: normalizedHello.logicals,
|
|
6208
|
+
capabilities: normalizedHello.capabilities,
|
|
6209
|
+
ttlSec: this.ttlSec,
|
|
6210
|
+
});
|
|
6211
|
+
const now = nowUtc();
|
|
6212
|
+
const expiry = new Date(now.getTime() + this.ttlSec * 1000);
|
|
6213
|
+
if (normalizedHello.instanceId) {
|
|
6214
|
+
if (fullMetadata.instanceId === undefined) {
|
|
6215
|
+
fullMetadata.instanceId = normalizedHello.instanceId;
|
|
6216
|
+
}
|
|
6217
|
+
if (fullMetadata.instance_id === undefined) {
|
|
6218
|
+
fullMetadata.instance_id = normalizedHello.instanceId;
|
|
6219
|
+
}
|
|
6239
6220
|
}
|
|
6240
|
-
|
|
6241
|
-
|
|
6242
|
-
|
|
6243
|
-
|
|
6244
|
-
|
|
6245
|
-
|
|
6246
|
-
|
|
6221
|
+
logger$2.debug("system_id_assignment_completed", {
|
|
6222
|
+
systemId,
|
|
6223
|
+
wasAssigned,
|
|
6224
|
+
});
|
|
6225
|
+
if (normalizedHello.logicals?.length) {
|
|
6226
|
+
logger$2.debug("validating_logicals_for_dns_compatibility", {
|
|
6227
|
+
logicals: normalizedHello.logicals,
|
|
6228
|
+
});
|
|
6229
|
+
const [pathsValid, pathError] = validateHostLogicals(normalizedHello.logicals);
|
|
6230
|
+
if (!pathsValid) {
|
|
6231
|
+
logger$2.error("logical_validation_failed", {
|
|
6232
|
+
error: pathError,
|
|
6233
|
+
logicals: normalizedHello.logicals,
|
|
6234
|
+
});
|
|
6235
|
+
throw new Error(`Invalid logical format: ${pathError}`);
|
|
6247
6236
|
}
|
|
6237
|
+
logger$2.debug("logicals_validation_successful");
|
|
6248
6238
|
}
|
|
6249
|
-
|
|
6250
|
-
|
|
6239
|
+
logger$2.debug("requesting_node_placement", { systemId });
|
|
6240
|
+
const placementResult = await this.placementStrategy.place(normalizedHello);
|
|
6241
|
+
if (!placementResult.accept) {
|
|
6242
|
+
logger$2.error("node_placement_rejected", {
|
|
6243
|
+
systemId,
|
|
6244
|
+
reason: placementResult.reason,
|
|
6245
|
+
});
|
|
6246
|
+
throw new Error(placementResult.reason || "Node not accepted");
|
|
6251
6247
|
}
|
|
6248
|
+
const assignedPath = placementResult.assignedPath;
|
|
6249
|
+
logger$2.debug("node_placement_accepted", {
|
|
6250
|
+
systemId,
|
|
6251
|
+
assignedPath,
|
|
6252
|
+
targetPhysicalPath: placementResult.targetPhysicalPath ?? null,
|
|
6253
|
+
targetSystemId: placementResult.targetSystemId ?? null,
|
|
6254
|
+
});
|
|
6255
|
+
const acceptedCapabilities = coercePlacementMetadataValue(placementResult.metadata, "acceptedCapabilities", "accepted_capabilities") ??
|
|
6256
|
+
normalizedHello.capabilities ??
|
|
6257
|
+
null;
|
|
6258
|
+
const acceptedLogicals = coercePlacementMetadataValue(placementResult.metadata, "acceptedLogicals", "accepted_logicals") ??
|
|
6259
|
+
normalizedHello.logicals ??
|
|
6260
|
+
null;
|
|
6261
|
+
logger$2.debug("processing_placement_result_metadata", {
|
|
6262
|
+
acceptedCapabilities,
|
|
6263
|
+
acceptedLogicals,
|
|
6264
|
+
hasPlacementMetadata: placementResult.metadata !== undefined &&
|
|
6265
|
+
placementResult.metadata !== null,
|
|
6266
|
+
});
|
|
6267
|
+
const connectionGrants = [];
|
|
6268
|
+
const metadataInstanceId = (typeof fullMetadata.instanceId === "string" &&
|
|
6269
|
+
fullMetadata.instanceId) ||
|
|
6270
|
+
(typeof fullMetadata.instance_id === "string" &&
|
|
6271
|
+
fullMetadata.instance_id) ||
|
|
6272
|
+
normalizedHello.instanceId ||
|
|
6273
|
+
generateId();
|
|
6274
|
+
if (placementResult.targetSystemId) {
|
|
6275
|
+
logger$2.debug("issuing_node_attach_token", {
|
|
6276
|
+
systemId,
|
|
6277
|
+
assignedPath,
|
|
6278
|
+
});
|
|
6279
|
+
const nodeAttachToken = await this.tokenIssuer.issue({
|
|
6280
|
+
aud: placementResult.targetPhysicalPath,
|
|
6281
|
+
system_id: systemId,
|
|
6282
|
+
parent_path: placementResult.targetPhysicalPath,
|
|
6283
|
+
assigned_path: placementResult.assignedPath,
|
|
6284
|
+
accepted_logicals: acceptedLogicals,
|
|
6285
|
+
instance_id: metadataInstanceId,
|
|
6286
|
+
});
|
|
6287
|
+
logger$2.debug("token_issued_successfully");
|
|
6288
|
+
logger$2.debug("provisioning_transport", { systemId });
|
|
6289
|
+
const transportInfo = await this.transportProvisioner.provision(placementResult, normalizedHello, fullMetadata, nodeAttachToken);
|
|
6290
|
+
logger$2.debug("transport_provisioned_successfully", {
|
|
6291
|
+
systemId,
|
|
6292
|
+
directiveType: transportInfo.connectionGrant &&
|
|
6293
|
+
typeof transportInfo.connectionGrant === "object"
|
|
6294
|
+
? (transportInfo.connectionGrant.type ??
|
|
6295
|
+
"Unknown")
|
|
6296
|
+
: "Unknown",
|
|
6297
|
+
});
|
|
6298
|
+
connectionGrants.push(transportInfo.connectionGrant);
|
|
6299
|
+
}
|
|
6300
|
+
const caSignToken = await this.tokenIssuer.issue({
|
|
6301
|
+
aud: "ca",
|
|
6302
|
+
system_id: systemId,
|
|
6303
|
+
assigned_path: assignedPath,
|
|
6304
|
+
accepted_logicals: acceptedLogicals,
|
|
6305
|
+
instance_id: metadataInstanceId,
|
|
6306
|
+
});
|
|
6307
|
+
const caGrant = {
|
|
6308
|
+
type: HTTP_CONNECTION_GRANT_TYPE,
|
|
6309
|
+
purpose: GRANT_PURPOSE_CA_SIGN,
|
|
6310
|
+
url: this.caServiceUrl,
|
|
6311
|
+
auth: {
|
|
6312
|
+
type: "BearerTokenHeaderAuth",
|
|
6313
|
+
tokenProvider: {
|
|
6314
|
+
type: "StaticTokenProvider",
|
|
6315
|
+
token: caSignToken,
|
|
6316
|
+
},
|
|
6317
|
+
},
|
|
6318
|
+
};
|
|
6319
|
+
connectionGrants.push(caGrant);
|
|
6320
|
+
const welcomeFrame = {
|
|
6321
|
+
type: "NodeWelcome",
|
|
6322
|
+
systemId,
|
|
6323
|
+
targetSystemId: placementResult.targetSystemId ?? undefined,
|
|
6324
|
+
targetPhysicalPath: placementResult.targetPhysicalPath ?? undefined,
|
|
6325
|
+
instanceId: normalizedHello.instanceId,
|
|
6326
|
+
assignedPath,
|
|
6327
|
+
acceptedCapabilities: acceptedCapabilities ?? undefined,
|
|
6328
|
+
acceptedLogicals: acceptedLogicals ?? undefined,
|
|
6329
|
+
rejectedLogicals: undefined,
|
|
6330
|
+
connectionGrants,
|
|
6331
|
+
metadata: Object.keys(fullMetadata).length > 0 ? fullMetadata : undefined,
|
|
6332
|
+
expiresAt: expiry.toISOString(),
|
|
6333
|
+
};
|
|
6334
|
+
logger$2.debug("hello_frame_processing_completed_successfully", {
|
|
6335
|
+
systemId,
|
|
6336
|
+
assignedPath,
|
|
6337
|
+
acceptedLogicals,
|
|
6338
|
+
acceptedCapabilities,
|
|
6339
|
+
expiresAt: welcomeFrame.expiresAt,
|
|
6340
|
+
instanceId: normalizedHello.instanceId,
|
|
6341
|
+
});
|
|
6342
|
+
if (showEnvelopes) {
|
|
6343
|
+
// eslint-disable-next-line no-console
|
|
6344
|
+
console.log(`\n${formatTimestampForConsole()} - ${color("Sent envelope", AnsiColor.BLUE)} 🚀\n${prettyModel(welcomeFrame)}`);
|
|
6345
|
+
}
|
|
6346
|
+
return welcomeFrame;
|
|
6252
6347
|
}
|
|
6253
|
-
const packageCandidate = resolveFactoryModuleSpecifier$1(spec);
|
|
6254
|
-
addCandidate(packageCandidate);
|
|
6255
|
-
if (packageCandidate?.endsWith(".js")) {
|
|
6256
|
-
addCandidate(packageCandidate.replace(/\.js$/u, ".ts"));
|
|
6257
|
-
}
|
|
6258
|
-
const fallback = spec.startsWith("./") ? `../${spec.slice(2)}` : spec;
|
|
6259
|
-
addCandidate(fallback);
|
|
6260
|
-
if (fallback.endsWith(".js")) {
|
|
6261
|
-
addCandidate(fallback.replace(/\.js$/u, ".ts"));
|
|
6262
|
-
}
|
|
6263
|
-
addCandidate(spec);
|
|
6264
|
-
if (spec.endsWith(".js")) {
|
|
6265
|
-
addCandidate(spec.replace(/\.js$/u, ".ts"));
|
|
6266
|
-
}
|
|
6267
|
-
return candidates;
|
|
6268
|
-
}
|
|
6269
|
-
const registeredModules = new Set();
|
|
6270
|
-
const inflightModules = new Map();
|
|
6271
|
-
const browserSkippedModules = new Set();
|
|
6272
|
-
function isNodeEnvironment$5() {
|
|
6273
|
-
return (typeof process !== "undefined" &&
|
|
6274
|
-
typeof process.release !== "undefined" &&
|
|
6275
|
-
process.release?.name === "node");
|
|
6276
|
-
}
|
|
6277
|
-
function shouldSkipModule(spec) {
|
|
6278
|
-
if (isNodeEnvironment$5()) {
|
|
6279
|
-
return false;
|
|
6280
|
-
}
|
|
6281
|
-
if (!NODE_ONLY_MODULES.has(spec)) {
|
|
6282
|
-
return false;
|
|
6283
|
-
}
|
|
6284
|
-
if (!browserSkippedModules.has(spec)) {
|
|
6285
|
-
// console.warn(
|
|
6286
|
-
// "[advanced-security:factory-manifest] skipped browser-incompatible module",
|
|
6287
|
-
// spec,
|
|
6288
|
-
// );
|
|
6289
|
-
browserSkippedModules.add(spec);
|
|
6290
|
-
}
|
|
6291
|
-
return true;
|
|
6292
|
-
}
|
|
6293
|
-
function getDynamicImporter() {
|
|
6294
|
-
if (typeof globalThis === "undefined") {
|
|
6295
|
-
return null;
|
|
6296
|
-
}
|
|
6297
|
-
const candidate = globalThis.__naylenceFactoryDynamicImporter;
|
|
6298
|
-
if (typeof candidate === "function") {
|
|
6299
|
-
return candidate;
|
|
6300
|
-
}
|
|
6301
|
-
return null;
|
|
6302
6348
|
}
|
|
6303
|
-
|
|
6304
|
-
|
|
6305
|
-
|
|
6306
|
-
|
|
6307
|
-
|
|
6308
|
-
|
|
6309
|
-
|
|
6310
|
-
|
|
6311
|
-
|
|
6312
|
-
|
|
6313
|
-
|
|
6314
|
-
|
|
6315
|
-
|
|
6349
|
+
|
|
6350
|
+
const FACTORY_META$5 = {
|
|
6351
|
+
base: WELCOME_SERVICE_FACTORY_BASE_TYPE,
|
|
6352
|
+
key: "AdvancedWelcomeService",
|
|
6353
|
+
priority: 100,
|
|
6354
|
+
isDefault: true,
|
|
6355
|
+
};
|
|
6356
|
+
class AdvancedWelcomeServiceFactory extends WelcomeServiceFactory {
|
|
6357
|
+
constructor() {
|
|
6358
|
+
super(...arguments);
|
|
6359
|
+
this.type = FACTORY_META$5.key;
|
|
6360
|
+
this.isDefault = FACTORY_META$5.isDefault;
|
|
6361
|
+
this.priority = FACTORY_META$5.priority;
|
|
6316
6362
|
}
|
|
6317
|
-
|
|
6318
|
-
const
|
|
6319
|
-
|
|
6320
|
-
|
|
6321
|
-
|
|
6322
|
-
|
|
6323
|
-
|
|
6324
|
-
|
|
6325
|
-
|
|
6326
|
-
|
|
6327
|
-
|
|
6328
|
-
|
|
6329
|
-
|
|
6330
|
-
// console.log("[debug] registering module", { spec, base, key, metadata: extraMetadata });
|
|
6331
|
-
registrar.registerFactory(base, key, Ctor, extraMetadata);
|
|
6332
|
-
return true;
|
|
6333
|
-
};
|
|
6334
|
-
for (const [index, { candidate, load }] of attempts.entries()) {
|
|
6335
|
-
try {
|
|
6336
|
-
const mod = await load();
|
|
6337
|
-
return registerFromModule(mod);
|
|
6363
|
+
async create(config, ...factoryArgs) {
|
|
6364
|
+
const normalized = normalizeConfig$2(config);
|
|
6365
|
+
// Crypto provider should be passed from upstream (node-welcome-server)
|
|
6366
|
+
// Do not create it here - downstream components should use what's passed in factoryArgs
|
|
6367
|
+
const placementStrategy = await NodePlacementStrategyFactory.createNodePlacementStrategy(normalized.placementConfig ?? null, factoryArgs.length > 0 ? { factoryArgs } : undefined);
|
|
6368
|
+
const transportProvisioner = await TransportProvisionerFactory.createTransportProvisioner(normalized.transportConfig ?? null, factoryArgs.length > 0 ? { factoryArgs } : undefined);
|
|
6369
|
+
const tokenIssuer = await TokenIssuerFactory.createTokenIssuer(normalized.tokenIssuerConfig ?? null, factoryArgs.length > 0 ? { factoryArgs } : undefined);
|
|
6370
|
+
let authorizer = null;
|
|
6371
|
+
if (normalized.authorizerConfig) {
|
|
6372
|
+
authorizer =
|
|
6373
|
+
(await AuthorizerFactory.createAuthorizer(normalized.authorizerConfig, {
|
|
6374
|
+
factoryArgs,
|
|
6375
|
+
})) ?? null;
|
|
6338
6376
|
}
|
|
6339
|
-
|
|
6340
|
-
|
|
6341
|
-
|
|
6342
|
-
|
|
6343
|
-
|
|
6344
|
-
|
|
6345
|
-
|
|
6346
|
-
|
|
6347
|
-
|
|
6348
|
-
if (!moduleNotFound || isLastAttempt) {
|
|
6349
|
-
console.warn("[debug] failed to import candidate", {
|
|
6350
|
-
spec,
|
|
6351
|
-
candidate,
|
|
6352
|
-
message,
|
|
6353
|
-
});
|
|
6354
|
-
console.warn("[advanced-security:factory-manifest] skipped", spec, "-", message);
|
|
6355
|
-
return false;
|
|
6356
|
-
}
|
|
6377
|
+
const options = {
|
|
6378
|
+
placementStrategy,
|
|
6379
|
+
transportProvisioner,
|
|
6380
|
+
tokenIssuer,
|
|
6381
|
+
authorizer,
|
|
6382
|
+
caServiceUrl: normalized.caServiceUrl,
|
|
6383
|
+
};
|
|
6384
|
+
if (normalized.ttlSec !== undefined) {
|
|
6385
|
+
options.ttlSec = normalized.ttlSec;
|
|
6357
6386
|
}
|
|
6387
|
+
return new AdvancedWelcomeService(options);
|
|
6358
6388
|
}
|
|
6359
|
-
return false;
|
|
6360
6389
|
}
|
|
6361
|
-
|
|
6362
|
-
if (
|
|
6363
|
-
|
|
6364
|
-
}
|
|
6365
|
-
const inflight = inflightModules.get(spec);
|
|
6366
|
-
if (inflight) {
|
|
6367
|
-
return inflight;
|
|
6390
|
+
function normalizeConfig$2(config) {
|
|
6391
|
+
if (!config) {
|
|
6392
|
+
throw new Error("AdvancedWelcomeService requires configuration");
|
|
6368
6393
|
}
|
|
6369
|
-
const
|
|
6370
|
-
|
|
6371
|
-
|
|
6372
|
-
|
|
6373
|
-
|
|
6374
|
-
|
|
6375
|
-
|
|
6376
|
-
|
|
6377
|
-
|
|
6378
|
-
|
|
6394
|
+
const source = config;
|
|
6395
|
+
const ttlCandidate = typeof source.ttlSec === "number"
|
|
6396
|
+
? source.ttlSec
|
|
6397
|
+
: typeof source.ttl_sec === "number"
|
|
6398
|
+
? source.ttl_sec
|
|
6399
|
+
: undefined;
|
|
6400
|
+
const caServiceUrlCandidate = typeof source.caServiceUrl === "string" &&
|
|
6401
|
+
source.caServiceUrl.trim().length > 0
|
|
6402
|
+
? source.caServiceUrl.trim()
|
|
6403
|
+
: typeof source.ca_service_url === "string" &&
|
|
6404
|
+
source.ca_service_url.trim().length > 0
|
|
6405
|
+
? source.ca_service_url.trim()
|
|
6406
|
+
: undefined;
|
|
6407
|
+
if (!caServiceUrlCandidate) {
|
|
6408
|
+
throw new Error("AdvancedWelcomeService configuration requires caServiceUrl");
|
|
6379
6409
|
}
|
|
6380
|
-
|
|
6381
|
-
|
|
6410
|
+
const normalized = {
|
|
6411
|
+
caServiceUrl: caServiceUrlCandidate,
|
|
6412
|
+
};
|
|
6413
|
+
if (source.placement !== undefined) {
|
|
6414
|
+
normalized.placementConfig =
|
|
6415
|
+
source.placement ?? null;
|
|
6382
6416
|
}
|
|
6383
|
-
|
|
6384
|
-
|
|
6385
|
-
|
|
6386
|
-
return 0;
|
|
6417
|
+
if (source.transport !== undefined) {
|
|
6418
|
+
normalized.transportConfig =
|
|
6419
|
+
source.transport ?? null;
|
|
6387
6420
|
}
|
|
6388
|
-
const
|
|
6389
|
-
|
|
6390
|
-
|
|
6421
|
+
const tokenIssuerConfig = source.tokenIssuer !== undefined
|
|
6422
|
+
? source.tokenIssuer
|
|
6423
|
+
: source.token_issuer !== undefined
|
|
6424
|
+
? source.token_issuer
|
|
6425
|
+
: undefined;
|
|
6426
|
+
if (tokenIssuerConfig !== undefined) {
|
|
6427
|
+
normalized.tokenIssuerConfig =
|
|
6428
|
+
tokenIssuerConfig ?? null;
|
|
6391
6429
|
}
|
|
6392
|
-
|
|
6393
|
-
|
|
6394
|
-
|
|
6395
|
-
async function registerAdvancedSecurityFactories(registrar = Registry, options) {
|
|
6396
|
-
const newlyRegisteredSecurity = await registerModules(SECURITY_MODULES, registrar);
|
|
6397
|
-
if (newlyRegisteredSecurity > 0) {
|
|
6398
|
-
getEncryptionManagerFactoryRegistry().forceRediscovery();
|
|
6430
|
+
if (source.authorizer !== undefined) {
|
|
6431
|
+
normalized.authorizerConfig =
|
|
6432
|
+
source.authorizer ?? null;
|
|
6399
6433
|
}
|
|
6400
|
-
if (
|
|
6401
|
-
|
|
6434
|
+
if (ttlCandidate !== undefined && Number.isFinite(ttlCandidate)) {
|
|
6435
|
+
normalized.ttlSec = ttlCandidate;
|
|
6402
6436
|
}
|
|
6437
|
+
return normalized;
|
|
6403
6438
|
}
|
|
6404
6439
|
|
|
6440
|
+
var advancedWelcomeServiceFactory = /*#__PURE__*/Object.freeze({
|
|
6441
|
+
__proto__: null,
|
|
6442
|
+
AdvancedWelcomeServiceFactory: AdvancedWelcomeServiceFactory,
|
|
6443
|
+
FACTORY_META: FACTORY_META$5,
|
|
6444
|
+
default: AdvancedWelcomeServiceFactory
|
|
6445
|
+
});
|
|
6446
|
+
|
|
6405
6447
|
/**
|
|
6406
6448
|
* Isomorphic entry point for Naylence Advanced Security.
|
|
6407
6449
|
*
|
|
@@ -10098,47 +10140,31 @@ var defaultCaServiceFactory = /*#__PURE__*/Object.freeze({
|
|
|
10098
10140
|
* Includes the full factory surface area, including certificate authority
|
|
10099
10141
|
* helpers that rely on Node.js built-ins.
|
|
10100
10142
|
*/
|
|
10101
|
-
|
|
10102
|
-
|
|
10103
|
-
|
|
10143
|
+
// Always register the plugin directly. This ensures it is initialized even if
|
|
10144
|
+
// the dynamic import mechanism (used by FAME_PLUGINS) fails.
|
|
10145
|
+
(async () => {
|
|
10146
|
+
try {
|
|
10147
|
+
await advancedSecurityPlugin.register();
|
|
10148
|
+
}
|
|
10149
|
+
catch (err) {
|
|
10150
|
+
console.error('[naylence:advanced-security] Failed to auto-register plugin:', err);
|
|
10151
|
+
}
|
|
10152
|
+
})();
|
|
10153
|
+
const g = (typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof self !== 'undefined' ? self : {});
|
|
10154
|
+
const proc = g.process || (typeof process !== 'undefined' ? process : undefined);
|
|
10155
|
+
const isNode = typeof process !== 'undefined' &&
|
|
10156
|
+
process.versions != null &&
|
|
10157
|
+
process.versions.node != null;
|
|
10158
|
+
// Only in Node.js: populate FAME_PLUGINS so child processes inherit it.
|
|
10159
|
+
if (isNode && proc && proc.env) {
|
|
10160
|
+
const pluginName = '@naylence/advanced-security';
|
|
10161
|
+
const current = proc.env.FAME_PLUGINS || '';
|
|
10162
|
+
const plugins = current.split(',').map((p) => p.trim());
|
|
10163
|
+
if (!plugins.includes(pluginName)) {
|
|
10164
|
+
proc.env.FAME_PLUGINS = current
|
|
10165
|
+
? `${current},${pluginName}`
|
|
10166
|
+
: pluginName;
|
|
10167
|
+
}
|
|
10104
10168
|
}
|
|
10105
|
-
let initialized = false;
|
|
10106
|
-
let initializing = null;
|
|
10107
|
-
const advancedSecurityPlugin = {
|
|
10108
|
-
name: "naylence:advanced-security",
|
|
10109
|
-
version: VERSION,
|
|
10110
|
-
async register() {
|
|
10111
|
-
// console.log('[naylence:advanced-security] register() called, initialized=', initialized);
|
|
10112
|
-
if (initialized) {
|
|
10113
|
-
// console.log('[naylence:advanced-security] already initialized, skipping');
|
|
10114
|
-
return;
|
|
10115
|
-
}
|
|
10116
|
-
if (initializing) {
|
|
10117
|
-
console.log("[naylence:advanced-security] already initializing, awaiting...");
|
|
10118
|
-
await initializing;
|
|
10119
|
-
return;
|
|
10120
|
-
}
|
|
10121
|
-
initializing = (async () => {
|
|
10122
|
-
try {
|
|
10123
|
-
// console.log('[naylence:advanced-security] registering advanced security factories...');
|
|
10124
|
-
await registerAdvancedSecurityPluginFactories();
|
|
10125
|
-
// console.log('[naylence:advanced-security] advanced security factories registered');
|
|
10126
|
-
initialized = true;
|
|
10127
|
-
}
|
|
10128
|
-
finally {
|
|
10129
|
-
initializing = null;
|
|
10130
|
-
}
|
|
10131
|
-
})();
|
|
10132
|
-
await initializing;
|
|
10133
|
-
},
|
|
10134
|
-
};
|
|
10135
|
-
const ADVANCED_SECURITY_PLUGIN_SPECIFIER = advancedSecurityPlugin.name;
|
|
10136
|
-
|
|
10137
|
-
var plugin = /*#__PURE__*/Object.freeze({
|
|
10138
|
-
__proto__: null,
|
|
10139
|
-
ADVANCED_SECURITY_PLUGIN_SPECIFIER: ADVANCED_SECURITY_PLUGIN_SPECIFIER,
|
|
10140
|
-
default: advancedSecurityPlugin,
|
|
10141
|
-
registerAdvancedSecurityPluginFactories: registerAdvancedSecurityPluginFactories
|
|
10142
|
-
});
|
|
10143
10169
|
|
|
10144
10170
|
export { FACTORY_META$a as ADVANCED_EDDSA_ENVELOPE_SIGNER_FACTORY_META, FACTORY_META$9 as ADVANCED_EDDSA_ENVELOPE_VERIFIER_FACTORY_META, FACTORY_META$5 as ADVANCED_WELCOME_FACTORY_META, AFTHelper, AFTLoadBalancerStickinessManager, AFTLoadBalancerStickinessManagerFactory, AFTReplicaStickinessManager, AFTReplicaStickinessManagerFactory, FACTORY_META$7 as AFT_LOAD_BALANCER_FACTORY_META, FACTORY_META$6 as AFT_REPLICA_FACTORY_META, AdvancedEdDSAEnvelopeSignerFactory, AdvancedEdDSAEnvelopeVerifierFactory, AdvancedWelcomeService, AdvancedWelcomeServiceFactory, FACTORY_META$2 as BROWSER_TRUST_STORE_PROVIDER_FACTORY_META, BrowserTrustStoreProviderFactory, CAService, CAServiceClient, CAServiceFactory, CASigningService, CA_SERVICE_FACTORY_BASE_TYPE, CertificateRequestError, CompositeEncryptionManager, CompositeEncryptionManagerFactory, FACTORY_META$4 as DEFAULT_CERTIFICATE_MANAGER_FACTORY_META, FACTORY_META$c as DEFAULT_SECURE_CHANNEL_MANAGER_FACTORY_META, DEFAULT_STICKINESS_SECURITY_LEVEL, DefaultCAService, DefaultCAServiceFactory, DefaultCertificateManager, DefaultCertificateManagerFactory, DefaultSecureChannelManager, DefaultSecureChannelManagerFactory, ENV_FAME_CA_CERT_FILE, ENV_FAME_CA_CERT_PEM, ENV_FAME_CA_KEY_FILE, ENV_FAME_CA_KEY_PEM, ENV_FAME_INTERMEDIATE_CHAIN_FILE, ENV_FAME_INTERMEDIATE_CHAIN_PEM, ENV_FAME_SIGNING_CERT_FILE, ENV_FAME_SIGNING_CERT_PEM, ENV_FAME_SIGNING_KEY_FILE, ENV_FAME_SIGNING_KEY_PEM, FACTORY_META$3 as ENV_TRUST_STORE_PROVIDER_FACTORY_META, ENV_VAR_FAME_CA_SERVICE_URL, EdDSAEnvelopeVerifier, EnvTrustStoreProviderFactory, GRANT_PURPOSE_CA_SIGN, LOGICALS_OID, NODE_ID_OID, NoAFTSigner, NullTrustStoreProvider, SID_OID, SidOnlyAFTVerifier, SignedAFTSigner, SignedOptionalAFTVerifier, StickinessMode, StrictAFTVerifier, TRUST_STORE_PROVIDER_FACTORY_BASE_TYPE, TrustStoreProviderFactory, UnsignedAFTSigner, VERSION, X5CKeyManager, X5CKeyManagerFactory, FACTORY_META$8 as X5C_KEY_MANAGER_FACTORY_META, __advancedSecurityPluginLoader, base64UrlDecode, base64UrlEncode, index as channelEncryption, createAftHelper, createAftPayload, createAftReplicaStickinessManager, createAftSigner, createAftVerifier, createEd25519Csr, createEd25519CsrFromPem, createTestCA, extractCertificateInfo, extractLogicalHostsFromCert, extractNodeIdFromCert, extractSidFromCert, extractSidFromSpiffeId, extractSpiffeIdFromCert, formatCertificateInfo, normalizeStickinessMode, publicKeyFromX5c, registerAdvancedSecurityFactories, index$1 as sealedEncryption, serializeAftClaims, serializeAftHeader, utf8Decode, validateJwkX5cCertificate, verifyCertSidIntegrity };
|