@naylence/runtime 0.3.5-test.910 → 0.3.5-test.913
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 +1915 -1214
- package/dist/browser/index.mjs +1910 -1209
- package/dist/cjs/naylence/fame/config/extended-fame-config.js +52 -0
- package/dist/cjs/naylence/fame/factory-manifest.js +2 -0
- package/dist/cjs/naylence/fame/http/jwks-api-router.js +16 -18
- package/dist/cjs/naylence/fame/http/oauth2-server.js +28 -31
- package/dist/cjs/naylence/fame/http/oauth2-token-router.js +901 -93
- package/dist/cjs/naylence/fame/http/openid-configuration-router.js +30 -32
- package/dist/cjs/naylence/fame/node/admission/admission-profile-factory.js +79 -0
- package/dist/cjs/naylence/fame/security/auth/oauth2-pkce-token-provider-factory.js +171 -0
- package/dist/cjs/naylence/fame/security/auth/oauth2-pkce-token-provider.js +560 -0
- package/dist/cjs/naylence/fame/security/crypto/providers/default-crypto-provider.js +0 -162
- package/dist/cjs/naylence/fame/telemetry/open-telemetry-trace-emitter-factory.js +19 -2
- package/dist/cjs/naylence/fame/telemetry/open-telemetry-trace-emitter.js +19 -9
- package/dist/cjs/naylence/fame/util/register-runtime-factories.js +6 -0
- package/dist/cjs/version.js +2 -2
- package/dist/esm/naylence/fame/config/extended-fame-config.js +52 -0
- package/dist/esm/naylence/fame/factory-manifest.js +2 -0
- package/dist/esm/naylence/fame/http/jwks-api-router.js +16 -17
- package/dist/esm/naylence/fame/http/oauth2-server.js +28 -31
- package/dist/esm/naylence/fame/http/oauth2-token-router.js +901 -93
- package/dist/esm/naylence/fame/http/openid-configuration-router.js +30 -31
- package/dist/esm/naylence/fame/node/admission/admission-profile-factory.js +79 -0
- package/dist/esm/naylence/fame/security/auth/oauth2-pkce-token-provider-factory.js +134 -0
- package/dist/esm/naylence/fame/security/auth/oauth2-pkce-token-provider.js +555 -0
- package/dist/esm/naylence/fame/security/crypto/providers/default-crypto-provider.js +0 -162
- package/dist/esm/naylence/fame/telemetry/open-telemetry-trace-emitter-factory.js +19 -2
- package/dist/esm/naylence/fame/telemetry/open-telemetry-trace-emitter.js +19 -9
- package/dist/esm/naylence/fame/util/register-runtime-factories.js +6 -0
- package/dist/esm/version.js +2 -2
- package/dist/node/index.cjs +1911 -1210
- package/dist/node/index.mjs +1910 -1209
- package/dist/node/node.cjs +2945 -1439
- package/dist/node/node.mjs +2944 -1438
- package/dist/types/naylence/fame/factory-manifest.d.ts +1 -1
- package/dist/types/naylence/fame/http/jwks-api-router.d.ts +8 -8
- package/dist/types/naylence/fame/http/oauth2-server.d.ts +3 -3
- package/dist/types/naylence/fame/http/oauth2-token-router.d.ts +75 -19
- package/dist/types/naylence/fame/http/openid-configuration-router.d.ts +8 -8
- package/dist/types/naylence/fame/security/auth/oauth2-pkce-token-provider-factory.d.ts +27 -0
- package/dist/types/naylence/fame/security/auth/oauth2-pkce-token-provider.d.ts +42 -0
- package/dist/types/naylence/fame/security/crypto/providers/default-crypto-provider.d.ts +0 -1
- package/dist/types/naylence/fame/telemetry/open-telemetry-trace-emitter.d.ts +4 -0
- package/dist/types/version.d.ts +1 -1
- package/package.json +4 -4
- package/dist/esm/naylence/fame/fastapi/oauth2-server.js +0 -205
- package/dist/types/naylence/fame/fastapi/oauth2-server.d.ts +0 -22
|
@@ -34,9 +34,6 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.DefaultCryptoProvider = void 0;
|
|
37
|
-
const asn1_schema_1 = require("@peculiar/asn1-schema");
|
|
38
|
-
const asn1_x509_1 = require("@peculiar/asn1-x509");
|
|
39
|
-
const asn1_csr_1 = require("@peculiar/asn1-csr");
|
|
40
37
|
const core_1 = require("@naylence/core");
|
|
41
38
|
const logging_js_1 = require("../../../util/logging.js");
|
|
42
39
|
const util_js_1 = require("../../../util/util.js");
|
|
@@ -52,11 +49,6 @@ const DEFAULT_AUDIENCE = 'router-dev';
|
|
|
52
49
|
const DEFAULT_TTL_SEC = 3600;
|
|
53
50
|
const DEFAULT_HMAC_SECRET_BYTES = 32;
|
|
54
51
|
const ENCRYPTION_ALG = 'ECDH-ES';
|
|
55
|
-
const EXTENSION_REQUEST_OID = '1.2.840.113549.1.9.14';
|
|
56
|
-
const COMMON_NAME_OID = '2.5.4.3';
|
|
57
|
-
const ED25519_OID = '1.3.101.112';
|
|
58
|
-
const CSR_PEM_TAG = 'CERTIFICATE REQUEST';
|
|
59
|
-
const LOGICAL_URI_PREFIX = 'naylence://';
|
|
60
52
|
function normalizeDefaultCryptoProviderOptions(options) {
|
|
61
53
|
if (!options) {
|
|
62
54
|
return {};
|
|
@@ -322,76 +314,6 @@ class DefaultCryptoProvider {
|
|
|
322
314
|
has_chain: Boolean(certificateChainPem),
|
|
323
315
|
});
|
|
324
316
|
}
|
|
325
|
-
async createCsr(nodeId, physicalPath, logicals, subjectName) {
|
|
326
|
-
const trimmedNodeId = assertNonEmptyString(nodeId, 'nodeId');
|
|
327
|
-
const trimmedPhysicalPath = assertNonEmptyString(physicalPath, 'physicalPath');
|
|
328
|
-
try {
|
|
329
|
-
if (this.artifacts.signing.algorithm !== 'EdDSA') {
|
|
330
|
-
throw new Error('CSR creation only supported for Ed25519 signing keys in the default crypto provider');
|
|
331
|
-
}
|
|
332
|
-
const cryptoImpl = await ensureWebCrypto();
|
|
333
|
-
const privateKey = await cryptoImpl.subtle.importKey('pkcs8', pemToArrayBuffer(this.signingPrivatePem), {
|
|
334
|
-
name: 'Ed25519',
|
|
335
|
-
}, false, ['sign']);
|
|
336
|
-
const publicKeyDer = pemToArrayBuffer(this.signingPublicPem);
|
|
337
|
-
const subjectPkInfo = asn1_schema_1.AsnConvert.parse(publicKeyDer, asn1_x509_1.SubjectPublicKeyInfo);
|
|
338
|
-
const sanitizedLogicals = Array.isArray(logicals)
|
|
339
|
-
? logicals.filter((value) => typeof value === 'string' && value.trim().length > 0)
|
|
340
|
-
: [];
|
|
341
|
-
const commonName = typeof subjectName === 'string' && subjectName.trim().length > 0
|
|
342
|
-
? subjectName.trim()
|
|
343
|
-
: trimmedNodeId;
|
|
344
|
-
const subject = buildSubjectName(commonName);
|
|
345
|
-
const attributes = new asn1_csr_1.Attributes();
|
|
346
|
-
if (sanitizedLogicals.length > 0) {
|
|
347
|
-
const san = new asn1_x509_1.SubjectAlternativeName(sanitizedLogicals.map((logical) => new asn1_x509_1.GeneralName({
|
|
348
|
-
uniformResourceIdentifier: `${LOGICAL_URI_PREFIX}${logical}`,
|
|
349
|
-
})));
|
|
350
|
-
const extensions = new asn1_x509_1.Extensions([
|
|
351
|
-
new asn1_x509_1.Extension({
|
|
352
|
-
extnID: asn1_x509_1.id_ce_subjectAltName,
|
|
353
|
-
critical: false,
|
|
354
|
-
extnValue: new asn1_schema_1.OctetString(asn1_schema_1.AsnConvert.serialize(san)),
|
|
355
|
-
}),
|
|
356
|
-
]);
|
|
357
|
-
attributes.push(new asn1_x509_1.Attribute({
|
|
358
|
-
type: EXTENSION_REQUEST_OID,
|
|
359
|
-
values: [asn1_schema_1.AsnConvert.serialize(extensions)],
|
|
360
|
-
}));
|
|
361
|
-
}
|
|
362
|
-
const requestInfo = new asn1_csr_1.CertificationRequestInfo({
|
|
363
|
-
subject,
|
|
364
|
-
subjectPKInfo: subjectPkInfo,
|
|
365
|
-
attributes,
|
|
366
|
-
});
|
|
367
|
-
const requestInfoDer = asn1_schema_1.AsnConvert.serialize(requestInfo);
|
|
368
|
-
const signature = await cryptoImpl.subtle.sign('Ed25519', privateKey, requestInfoDer);
|
|
369
|
-
const certificationRequest = new asn1_csr_1.CertificationRequest({
|
|
370
|
-
certificationRequestInfo: requestInfo,
|
|
371
|
-
signatureAlgorithm: new asn1_x509_1.AlgorithmIdentifier({
|
|
372
|
-
algorithm: ED25519_OID,
|
|
373
|
-
}),
|
|
374
|
-
signature: encodeBitString(signature),
|
|
375
|
-
});
|
|
376
|
-
certificationRequest.certificationRequestInfoRaw = requestInfoDer;
|
|
377
|
-
const csrDer = asn1_schema_1.AsnConvert.serialize(certificationRequest);
|
|
378
|
-
const csrPem = arrayBufferToPem(csrDer, CSR_PEM_TAG);
|
|
379
|
-
logger.debug('csr_created', {
|
|
380
|
-
node_id: trimmedNodeId,
|
|
381
|
-
physical_path: trimmedPhysicalPath,
|
|
382
|
-
logical_count: sanitizedLogicals.length,
|
|
383
|
-
});
|
|
384
|
-
return csrPem;
|
|
385
|
-
}
|
|
386
|
-
catch (error) {
|
|
387
|
-
logger.error('csr_creation_failed', {
|
|
388
|
-
node_id: trimmedNodeId,
|
|
389
|
-
physical_path: trimmedPhysicalPath,
|
|
390
|
-
error: error instanceof Error ? error.message : String(error),
|
|
391
|
-
});
|
|
392
|
-
throw error;
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
317
|
}
|
|
396
318
|
exports.DefaultCryptoProvider = DefaultCryptoProvider;
|
|
397
319
|
async function buildProviderArtifacts(options) {
|
|
@@ -628,90 +550,6 @@ function pemToDerBase64(pem) {
|
|
|
628
550
|
// Ensure the output is valid base64 without whitespace
|
|
629
551
|
return base64.replace(/\s+/g, '');
|
|
630
552
|
}
|
|
631
|
-
let cryptoPromise = null;
|
|
632
|
-
async function ensureWebCrypto() {
|
|
633
|
-
if (typeof globalThis.crypto !== 'undefined' && globalThis.crypto?.subtle) {
|
|
634
|
-
return globalThis.crypto;
|
|
635
|
-
}
|
|
636
|
-
if (!cryptoPromise) {
|
|
637
|
-
if (typeof process !== 'undefined' &&
|
|
638
|
-
typeof process.versions?.node === 'string') {
|
|
639
|
-
cryptoPromise = Promise.resolve().then(() => __importStar(require('node:crypto'))).then((module) => {
|
|
640
|
-
const webcrypto = module.webcrypto;
|
|
641
|
-
if (!webcrypto || !webcrypto.subtle) {
|
|
642
|
-
throw new Error('WebCrypto API is not available in this Node.js runtime');
|
|
643
|
-
}
|
|
644
|
-
globalThis.crypto = webcrypto;
|
|
645
|
-
return webcrypto;
|
|
646
|
-
});
|
|
647
|
-
}
|
|
648
|
-
else {
|
|
649
|
-
cryptoPromise = Promise.reject(new Error('WebCrypto API is not available in this environment'));
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
return cryptoPromise;
|
|
653
|
-
}
|
|
654
|
-
function pemToArrayBuffer(pem) {
|
|
655
|
-
const normalized = pem
|
|
656
|
-
.replace(/-----BEGIN[^-]+-----/g, '')
|
|
657
|
-
.replace(/-----END[^-]+-----/g, '')
|
|
658
|
-
.replace(/\s+/g, '');
|
|
659
|
-
const bytes = base64ToBytes(normalized);
|
|
660
|
-
return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
|
|
661
|
-
}
|
|
662
|
-
function base64ToBytes(base64) {
|
|
663
|
-
if (typeof Buffer !== 'undefined') {
|
|
664
|
-
const buffer = Buffer.from(base64, 'base64');
|
|
665
|
-
const bytes = new Uint8Array(buffer.length);
|
|
666
|
-
for (let i = 0; i < buffer.length; i += 1) {
|
|
667
|
-
bytes[i] = buffer[i];
|
|
668
|
-
}
|
|
669
|
-
return bytes;
|
|
670
|
-
}
|
|
671
|
-
if (typeof atob === 'function') {
|
|
672
|
-
const binary = atob(base64);
|
|
673
|
-
const bytes = new Uint8Array(binary.length);
|
|
674
|
-
for (let i = 0; i < binary.length; i += 1) {
|
|
675
|
-
bytes[i] = binary.charCodeAt(i);
|
|
676
|
-
}
|
|
677
|
-
return bytes;
|
|
678
|
-
}
|
|
679
|
-
throw new Error('No base64 decoder available in this environment');
|
|
680
|
-
}
|
|
681
|
-
function arrayBufferToPem(buffer, tag) {
|
|
682
|
-
const base64 = bytesToBase64(new Uint8Array(buffer));
|
|
683
|
-
return `-----BEGIN ${tag}-----\n${formatPem(base64)}\n-----END ${tag}-----\n`;
|
|
684
|
-
}
|
|
685
|
-
function formatPem(base64) {
|
|
686
|
-
const lines = [];
|
|
687
|
-
for (let i = 0; i < base64.length; i += 64) {
|
|
688
|
-
lines.push(base64.slice(i, i + 64));
|
|
689
|
-
}
|
|
690
|
-
return lines.join('\n');
|
|
691
|
-
}
|
|
692
|
-
function encodeBitString(signature) {
|
|
693
|
-
const bytes = new Uint8Array(signature);
|
|
694
|
-
const bitString = new Uint8Array(bytes.length + 1);
|
|
695
|
-
bitString.set(bytes, 1);
|
|
696
|
-
return bitString.buffer;
|
|
697
|
-
}
|
|
698
|
-
function buildSubjectName(commonName) {
|
|
699
|
-
const attribute = new asn1_x509_1.AttributeTypeAndValue({
|
|
700
|
-
type: COMMON_NAME_OID,
|
|
701
|
-
value: new asn1_x509_1.AttributeValue({ utf8String: commonName }),
|
|
702
|
-
});
|
|
703
|
-
return new asn1_x509_1.Name([new asn1_x509_1.RelativeDistinguishedName([attribute])]);
|
|
704
|
-
}
|
|
705
|
-
function assertNonEmptyString(value, name) {
|
|
706
|
-
if (typeof value !== 'string') {
|
|
707
|
-
throw new TypeError(`${name} must be a string`);
|
|
708
|
-
}
|
|
709
|
-
const trimmed = value.trim();
|
|
710
|
-
if (trimmed.length === 0) {
|
|
711
|
-
throw new TypeError(`${name} must be a non-empty string`);
|
|
712
|
-
}
|
|
713
|
-
return trimmed;
|
|
714
|
-
}
|
|
715
553
|
function cloneJson(value) {
|
|
716
554
|
return JSON.parse(JSON.stringify(value));
|
|
717
555
|
}
|
|
@@ -40,15 +40,25 @@ const lazy_import_js_1 = require("../util/lazy-import.js");
|
|
|
40
40
|
const trace_emitter_factory_js_1 = require("./trace-emitter-factory.js");
|
|
41
41
|
const logging_js_1 = require("../util/logging.js");
|
|
42
42
|
let openTelemetryTraceEmitterModulePromise = null;
|
|
43
|
+
let otelApiModulePromise = null;
|
|
43
44
|
const logger = (0, logging_js_1.getLogger)('naylence.fame.telemetry.open_telemetry_trace_emitter_factory');
|
|
45
|
+
const MISSING_OTEL_HELP_MESSAGE = 'Missing optional OpenTelemetry dependency. Install @opentelemetry/api (and related packages) to enable trace emission.';
|
|
44
46
|
function getOpenTelemetryTraceEmitterModule() {
|
|
45
47
|
if (!openTelemetryTraceEmitterModulePromise) {
|
|
46
48
|
openTelemetryTraceEmitterModulePromise = (0, lazy_import_js_1.safeImport)(() => Promise.resolve().then(() => __importStar(require('./open-telemetry-trace-emitter.js'))), '@opentelemetry/api', {
|
|
47
|
-
helpMessage:
|
|
49
|
+
helpMessage: MISSING_OTEL_HELP_MESSAGE,
|
|
48
50
|
});
|
|
49
51
|
}
|
|
50
52
|
return openTelemetryTraceEmitterModulePromise;
|
|
51
53
|
}
|
|
54
|
+
function getOtelApiModule() {
|
|
55
|
+
if (!otelApiModulePromise) {
|
|
56
|
+
otelApiModulePromise = (0, lazy_import_js_1.safeImport)(() => Promise.resolve().then(() => __importStar(require('@opentelemetry/api'))), '@opentelemetry/api', {
|
|
57
|
+
helpMessage: MISSING_OTEL_HELP_MESSAGE,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
return otelApiModulePromise;
|
|
61
|
+
}
|
|
52
62
|
exports.FACTORY_META = {
|
|
53
63
|
base: trace_emitter_factory_js_1.TRACE_EMITTER_FACTORY_BASE_TYPE,
|
|
54
64
|
key: 'OpenTelemetryTraceEmitter',
|
|
@@ -111,9 +121,16 @@ class OpenTelemetryTraceEmitterFactory extends trace_emitter_factory_js_1.TraceE
|
|
|
111
121
|
}
|
|
112
122
|
throw error;
|
|
113
123
|
}
|
|
114
|
-
const { OpenTelemetryTraceEmitter } = await
|
|
124
|
+
const [{ OpenTelemetryTraceEmitter }, otelModule] = await Promise.all([
|
|
125
|
+
getOpenTelemetryTraceEmitterModule(),
|
|
126
|
+
getOtelApiModule(),
|
|
127
|
+
]);
|
|
115
128
|
const emitterOptions = {
|
|
116
129
|
serviceName: normalized.serviceName,
|
|
130
|
+
otelApi: {
|
|
131
|
+
trace: otelModule.trace,
|
|
132
|
+
SpanStatusCode: otelModule.SpanStatusCode,
|
|
133
|
+
},
|
|
117
134
|
};
|
|
118
135
|
if (options.tracer) {
|
|
119
136
|
emitterOptions.tracer = options.tracer;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.OpenTelemetryTraceEmitter = void 0;
|
|
4
|
-
const api_1 = require("@opentelemetry/api");
|
|
5
4
|
const base_trace_emitter_js_1 = require("./base-trace-emitter.js");
|
|
6
5
|
const otel_context_js_1 = require("./otel-context.js");
|
|
7
6
|
class OpenTelemetryTraceSpan {
|
|
8
|
-
constructor(span) {
|
|
7
|
+
constructor(span, api) {
|
|
9
8
|
this.span = span;
|
|
9
|
+
this.api = api;
|
|
10
10
|
}
|
|
11
11
|
setAttribute(key, value) {
|
|
12
12
|
try {
|
|
@@ -32,7 +32,7 @@ class OpenTelemetryTraceSpan {
|
|
|
32
32
|
setStatusError(description) {
|
|
33
33
|
try {
|
|
34
34
|
const status = {
|
|
35
|
-
code:
|
|
35
|
+
code: this.api.SpanStatusCode.ERROR,
|
|
36
36
|
};
|
|
37
37
|
if (description !== undefined) {
|
|
38
38
|
status.message = description;
|
|
@@ -45,10 +45,10 @@ class OpenTelemetryTraceSpan {
|
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
class OpenTelemetrySpanScope {
|
|
48
|
-
constructor(span) {
|
|
48
|
+
constructor(span, api) {
|
|
49
49
|
this.span = span;
|
|
50
50
|
this.entered = false;
|
|
51
|
-
this.wrapper = new OpenTelemetryTraceSpan(span);
|
|
51
|
+
this.wrapper = new OpenTelemetryTraceSpan(span, api);
|
|
52
52
|
}
|
|
53
53
|
enter() {
|
|
54
54
|
if (!this.entered) {
|
|
@@ -83,7 +83,9 @@ class OpenTelemetryTraceEmitter extends base_trace_emitter_js_1.BaseTraceEmitter
|
|
|
83
83
|
super();
|
|
84
84
|
this.shutdownInvoked = false;
|
|
85
85
|
const normalized = normalizeOpenTelemetryTraceEmitterOptions(options);
|
|
86
|
-
this.
|
|
86
|
+
this.otelApi = normalized.otelApi;
|
|
87
|
+
this.tracer =
|
|
88
|
+
normalized.tracer ?? this.otelApi.trace.getTracer(normalized.serviceName);
|
|
87
89
|
this.lifecycle = normalized.lifecycle ?? null;
|
|
88
90
|
this.authStrategy = normalized.authStrategy ?? null;
|
|
89
91
|
}
|
|
@@ -101,7 +103,7 @@ class OpenTelemetryTraceEmitter extends base_trace_emitter_js_1.BaseTraceEmitter
|
|
|
101
103
|
if (typeof envelopeTraceId === 'string') {
|
|
102
104
|
this.applyEnvelopeTraceId(span, envelopeTraceId);
|
|
103
105
|
}
|
|
104
|
-
return new OpenTelemetrySpanScope(span);
|
|
106
|
+
return new OpenTelemetrySpanScope(span, this.otelApi);
|
|
105
107
|
}
|
|
106
108
|
async flush() {
|
|
107
109
|
if (this.lifecycle?.forceFlush) {
|
|
@@ -114,7 +116,7 @@ class OpenTelemetryTraceEmitter extends base_trace_emitter_js_1.BaseTraceEmitter
|
|
|
114
116
|
}
|
|
115
117
|
}
|
|
116
118
|
try {
|
|
117
|
-
const provider =
|
|
119
|
+
const provider = this.otelApi.trace.getTracerProvider();
|
|
118
120
|
if (provider && typeof provider.forceFlush === 'function') {
|
|
119
121
|
await provider.forceFlush();
|
|
120
122
|
}
|
|
@@ -149,7 +151,7 @@ class OpenTelemetryTraceEmitter extends base_trace_emitter_js_1.BaseTraceEmitter
|
|
|
149
151
|
}
|
|
150
152
|
}
|
|
151
153
|
try {
|
|
152
|
-
const provider =
|
|
154
|
+
const provider = this.otelApi.trace.getTracerProvider();
|
|
153
155
|
if (provider && typeof provider.shutdown === 'function') {
|
|
154
156
|
await provider.shutdown();
|
|
155
157
|
}
|
|
@@ -191,6 +193,13 @@ function normalizeOpenTelemetryTraceEmitterOptions(input) {
|
|
|
191
193
|
const source = (input ?? {});
|
|
192
194
|
const serviceName = extractNonEmptyString(pickFirst(source, ['serviceName', 'service_name'])) ?? 'naylence-service';
|
|
193
195
|
const tracer = pickFirst(source, ['tracer']);
|
|
196
|
+
const otelApi = pickFirst(source, [
|
|
197
|
+
'otelApi',
|
|
198
|
+
'otel_api',
|
|
199
|
+
]);
|
|
200
|
+
if (!otelApi) {
|
|
201
|
+
throw new Error('OpenTelemetryTraceEmitter requires OpenTelemetry API bindings. Provide otelApi via options.');
|
|
202
|
+
}
|
|
194
203
|
const lifecycle = pickFirst(source, [
|
|
195
204
|
'lifecycle',
|
|
196
205
|
'lifeCycle',
|
|
@@ -203,6 +212,7 @@ function normalizeOpenTelemetryTraceEmitterOptions(input) {
|
|
|
203
212
|
return {
|
|
204
213
|
serviceName,
|
|
205
214
|
tracer,
|
|
215
|
+
otelApi,
|
|
206
216
|
lifecycle,
|
|
207
217
|
authStrategy,
|
|
208
218
|
};
|
|
@@ -46,6 +46,9 @@ const NODE_ONLY_FACTORY_MODULES = new Set([
|
|
|
46
46
|
'./telemetry/open-telemetry-trace-emitter-factory.js',
|
|
47
47
|
'./security/credential/prompt-credential-provider-factory.js',
|
|
48
48
|
]);
|
|
49
|
+
const BROWSER_ONLY_FACTORY_MODULES = new Set([
|
|
50
|
+
'./security/auth/oauth2-pkce-token-provider-factory.js',
|
|
51
|
+
]);
|
|
49
52
|
const isNodeEnvironment = typeof process !== 'undefined' && Boolean(process?.versions?.node);
|
|
50
53
|
function detectModuleUrl() {
|
|
51
54
|
// Prefer Node-friendly __filename when available.
|
|
@@ -188,6 +191,9 @@ async function performRegistration(registry) {
|
|
|
188
191
|
if (!isNodeEnvironment && NODE_ONLY_FACTORY_MODULES.has(spec)) {
|
|
189
192
|
return;
|
|
190
193
|
}
|
|
194
|
+
if (isNodeEnvironment && BROWSER_ONLY_FACTORY_MODULES.has(spec)) {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
191
197
|
try {
|
|
192
198
|
let mod;
|
|
193
199
|
let lastError;
|
package/dist/cjs/version.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
// This file is auto-generated during build - do not edit manually
|
|
3
|
-
// Generated from package.json version: 0.3.5-test.
|
|
3
|
+
// Generated from package.json version: 0.3.5-test.913
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
5
|
exports.VERSION = void 0;
|
|
6
6
|
/**
|
|
7
7
|
* The package version, injected at build time.
|
|
8
8
|
* @internal
|
|
9
9
|
*/
|
|
10
|
-
exports.VERSION = '0.3.5-test.
|
|
10
|
+
exports.VERSION = '0.3.5-test.913';
|
|
@@ -14,6 +14,57 @@ const CONFIG_SEARCH_PATHS = [
|
|
|
14
14
|
];
|
|
15
15
|
const fsModuleSpecifier = String.fromCharCode(102) + String.fromCharCode(115);
|
|
16
16
|
let cachedFsModule = null;
|
|
17
|
+
// Capture this module's URL without triggering TypeScript's import.meta restriction on CJS builds
|
|
18
|
+
const currentModuleUrl = (() => {
|
|
19
|
+
try {
|
|
20
|
+
return (0, eval)('import.meta.url');
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
})();
|
|
26
|
+
// Shared flag that allows synchronous waiting for the Node-specific require shim
|
|
27
|
+
const requireReadyFlag = isNode && typeof SharedArrayBuffer !== 'undefined'
|
|
28
|
+
? new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT))
|
|
29
|
+
: null;
|
|
30
|
+
if (requireReadyFlag) {
|
|
31
|
+
// 0 means initializing, 1 means ready (success or failure)
|
|
32
|
+
Atomics.store(requireReadyFlag, 0, 0);
|
|
33
|
+
// Prepare a CommonJS-style require when running in pure ESM contexts
|
|
34
|
+
void (async () => {
|
|
35
|
+
try {
|
|
36
|
+
if (typeof require !== 'function') {
|
|
37
|
+
const moduleNamespace = (await import('node:module'));
|
|
38
|
+
const createRequire = moduleNamespace.createRequire;
|
|
39
|
+
if (typeof createRequire === 'function') {
|
|
40
|
+
const fallbackPath = `${process.cwd()}/.__naylence_require_shim__.mjs`;
|
|
41
|
+
const nodeRequire = createRequire(currentModuleUrl ?? fallbackPath);
|
|
42
|
+
globalThis.require = nodeRequire;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// Ignore failures – getFsModule will surface a helpful error when needed
|
|
48
|
+
}
|
|
49
|
+
})()
|
|
50
|
+
.catch(() => {
|
|
51
|
+
// Ignore async errors – the ready flag will still unblock consumers
|
|
52
|
+
})
|
|
53
|
+
.finally(() => {
|
|
54
|
+
Atomics.store(requireReadyFlag, 0, 1);
|
|
55
|
+
Atomics.notify(requireReadyFlag, 0);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
function ensureRequireReady() {
|
|
59
|
+
if (!requireReadyFlag) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (Atomics.load(requireReadyFlag, 0) === 1) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
// Block until the asynchronous loader finishes initialising
|
|
66
|
+
Atomics.wait(requireReadyFlag, 0, 0);
|
|
67
|
+
}
|
|
17
68
|
function getFsModule() {
|
|
18
69
|
if (cachedFsModule) {
|
|
19
70
|
return cachedFsModule;
|
|
@@ -21,6 +72,7 @@ function getFsModule() {
|
|
|
21
72
|
if (!isNode) {
|
|
22
73
|
throw new Error('File system access is not available in this environment');
|
|
23
74
|
}
|
|
75
|
+
ensureRequireReady();
|
|
24
76
|
if (typeof require === 'function') {
|
|
25
77
|
try {
|
|
26
78
|
cachedFsModule = require(fsModuleSpecifier);
|
|
@@ -35,6 +35,7 @@ export const MODULES = [
|
|
|
35
35
|
"./security/auth/noop-token-verifier-factory.js",
|
|
36
36
|
"./security/auth/oauth2-authorizer-factory.js",
|
|
37
37
|
"./security/auth/oauth2-client-credentials-token-provider-factory.js",
|
|
38
|
+
"./security/auth/oauth2-pkce-token-provider-factory.js",
|
|
38
39
|
"./security/auth/query-param-auth-injection-strategy-factory.js",
|
|
39
40
|
"./security/auth/shared-secret-authorizer-factory.js",
|
|
40
41
|
"./security/auth/shared-secret-token-provider-factory.js",
|
|
@@ -108,6 +109,7 @@ export const MODULE_LOADERS = {
|
|
|
108
109
|
"./security/auth/noop-token-verifier-factory.js": () => import("./security/auth/noop-token-verifier-factory.js"),
|
|
109
110
|
"./security/auth/oauth2-authorizer-factory.js": () => import("./security/auth/oauth2-authorizer-factory.js"),
|
|
110
111
|
"./security/auth/oauth2-client-credentials-token-provider-factory.js": () => import("./security/auth/oauth2-client-credentials-token-provider-factory.js"),
|
|
112
|
+
"./security/auth/oauth2-pkce-token-provider-factory.js": () => import("./security/auth/oauth2-pkce-token-provider-factory.js"),
|
|
111
113
|
"./security/auth/query-param-auth-injection-strategy-factory.js": () => import("./security/auth/query-param-auth-injection-strategy-factory.js"),
|
|
112
114
|
"./security/auth/shared-secret-authorizer-factory.js": () => import("./security/auth/shared-secret-authorizer-factory.js"),
|
|
113
115
|
"./security/auth/shared-secret-token-provider-factory.js": () => import("./security/auth/shared-secret-token-provider-factory.js"),
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* JWKS (JSON Web Key Set) API
|
|
2
|
+
* JWKS (JSON Web Key Set) API plugin for Fastify
|
|
3
3
|
*
|
|
4
4
|
* Provides /.well-known/jwks.json endpoint for public key discovery
|
|
5
5
|
* Used by OAuth2/JWT token verification
|
|
6
6
|
*/
|
|
7
|
-
import express from 'express';
|
|
8
7
|
import { getLogger } from '../util/logging.js';
|
|
9
8
|
const logger = getLogger('naylence.fame.http.jwks_api_router');
|
|
10
9
|
const DEFAULT_PREFIX = '';
|
|
@@ -84,23 +83,22 @@ function filterKeysByType(jwksData, allowedTypes) {
|
|
|
84
83
|
return { ...jwksData, keys: filteredKeys };
|
|
85
84
|
}
|
|
86
85
|
/**
|
|
87
|
-
* Create
|
|
86
|
+
* Create a Fastify plugin that exposes JWKS at /.well-known/jwks.json
|
|
88
87
|
*
|
|
89
88
|
* @param options - Router configuration options
|
|
90
|
-
* @returns
|
|
89
|
+
* @returns Fastify plugin with JWKS endpoint
|
|
91
90
|
*
|
|
92
91
|
* @example
|
|
93
92
|
* ```typescript
|
|
94
|
-
* import
|
|
93
|
+
* import Fastify from 'fastify';
|
|
95
94
|
* import { createJwksRouter } from '@naylence/runtime';
|
|
96
95
|
*
|
|
97
|
-
* const app =
|
|
96
|
+
* const app = Fastify();
|
|
98
97
|
* const cryptoProvider = new MyCryptoProvider();
|
|
99
|
-
* app.
|
|
98
|
+
* app.register(createJwksRouter({ cryptoProvider }));
|
|
100
99
|
* ```
|
|
101
100
|
*/
|
|
102
101
|
export function createJwksRouter(options = {}) {
|
|
103
|
-
const router = express.Router();
|
|
104
102
|
const { getJwksJson, cryptoProvider, prefix = DEFAULT_PREFIX, keyTypes, } = normalizeCreateJwksRouterOptions(options);
|
|
105
103
|
// Get JWKS data
|
|
106
104
|
let jwks;
|
|
@@ -123,14 +121,15 @@ export function createJwksRouter(options = {}) {
|
|
|
123
121
|
key_types: allowedKeyTypes,
|
|
124
122
|
total_keys: jwks.keys.length,
|
|
125
123
|
});
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
124
|
+
const plugin = async (instance) => {
|
|
125
|
+
instance.get(`${prefix}/.well-known/jwks.json`, async (_request, reply) => {
|
|
126
|
+
const filteredJwks = filterKeysByType(jwks, allowedKeyTypes);
|
|
127
|
+
logger.debug('jwks_served', {
|
|
128
|
+
total_keys: jwks.keys.length,
|
|
129
|
+
filtered_keys: filteredJwks.keys.length,
|
|
130
|
+
});
|
|
131
|
+
reply.send(filteredJwks);
|
|
132
132
|
});
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
return router;
|
|
133
|
+
};
|
|
134
|
+
return plugin;
|
|
136
135
|
}
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* FAME_JWT_ISSUER: JWT issuer (default: https://auth.fame.fabric)
|
|
22
22
|
* FAME_JWT_ALGORITHM: JWT algorithm (default: EdDSA)
|
|
23
23
|
*/
|
|
24
|
-
import
|
|
24
|
+
import Fastify from 'fastify';
|
|
25
25
|
import { createOAuth2TokenRouter } from './oauth2-token-router.js';
|
|
26
26
|
import { createJwksRouter } from './jwks-api-router.js';
|
|
27
27
|
import { createOpenIDConfigurationRouter } from './openid-configuration-router.js';
|
|
@@ -53,23 +53,18 @@ async function getCryptoProvider() {
|
|
|
53
53
|
return DefaultCryptoProvider.create();
|
|
54
54
|
}
|
|
55
55
|
/**
|
|
56
|
-
* Create and configure the OAuth2
|
|
56
|
+
* Create and configure the OAuth2 Fastify application
|
|
57
57
|
*/
|
|
58
58
|
export async function createApp() {
|
|
59
|
-
const app =
|
|
60
|
-
// Middleware
|
|
61
|
-
app.use(express.json());
|
|
62
|
-
app.use(express.urlencoded({ extended: true }));
|
|
59
|
+
const app = Fastify({ logger: false });
|
|
63
60
|
// Get crypto provider
|
|
64
61
|
const cryptoProvider = await getCryptoProvider();
|
|
65
62
|
// Add routers
|
|
66
|
-
app.
|
|
67
|
-
app.
|
|
68
|
-
app.
|
|
63
|
+
app.register(createOAuth2TokenRouter({ cryptoProvider }));
|
|
64
|
+
app.register(createJwksRouter({ cryptoProvider }));
|
|
65
|
+
app.register(createOpenIDConfigurationRouter());
|
|
69
66
|
// Health check endpoint
|
|
70
|
-
app.get('/health', (
|
|
71
|
-
res.json({ status: 'ok' });
|
|
72
|
-
});
|
|
67
|
+
app.get('/health', async () => ({ status: 'ok' }));
|
|
73
68
|
return app;
|
|
74
69
|
}
|
|
75
70
|
/**
|
|
@@ -97,27 +92,29 @@ async function main() {
|
|
|
97
92
|
});
|
|
98
93
|
const app = await createApp();
|
|
99
94
|
// Start server
|
|
100
|
-
app.listen(port, host
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
});
|
|
95
|
+
await app.listen({ port, host });
|
|
96
|
+
logger.info('oauth2_server_started', {
|
|
97
|
+
host,
|
|
98
|
+
port,
|
|
99
|
+
endpoints: {
|
|
100
|
+
token: '/oauth/token',
|
|
101
|
+
jwks: '/.well-known/jwks.json',
|
|
102
|
+
openid_config: '/.well-known/openid-configuration',
|
|
103
|
+
health: '/health',
|
|
104
|
+
},
|
|
111
105
|
});
|
|
106
|
+
const shutdown = (signal) => {
|
|
107
|
+
logger.info('oauth2_server_shutting_down', { signal });
|
|
108
|
+
app
|
|
109
|
+
.close()
|
|
110
|
+
.catch((error) => logger.error('oauth2_server_shutdown_error', {
|
|
111
|
+
error: error instanceof Error ? error.message : String(error),
|
|
112
|
+
}))
|
|
113
|
+
.finally(() => process.exit(0));
|
|
114
|
+
};
|
|
112
115
|
// Graceful shutdown
|
|
113
|
-
process.on('SIGINT', () =>
|
|
114
|
-
|
|
115
|
-
process.exit(0);
|
|
116
|
-
});
|
|
117
|
-
process.on('SIGTERM', () => {
|
|
118
|
-
logger.info('oauth2_server_shutting_down', { signal: 'SIGTERM' });
|
|
119
|
-
process.exit(0);
|
|
120
|
-
});
|
|
116
|
+
process.on('SIGINT', () => shutdown('SIGINT'));
|
|
117
|
+
process.on('SIGTERM', () => shutdown('SIGTERM'));
|
|
121
118
|
}
|
|
122
119
|
// Export main for CLI usage
|
|
123
120
|
export { main };
|