@datalayer/personal-agent-protocol 0.2.0 → 0.3.1
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/LICENSE +29 -0
- package/README.md +141 -14
- package/lib/auth.d.ts +35 -1
- package/lib/auth.d.ts.map +1 -1
- package/lib/auth.js +230 -2
- package/lib/auth.js.map +1 -1
- package/lib/crypto.d.ts +1 -1
- package/lib/crypto.d.ts.map +1 -1
- package/lib/crypto.js +1 -2
- package/lib/crypto.js.map +1 -1
- package/lib/discovery.d.ts +1 -0
- package/lib/discovery.d.ts.map +1 -1
- package/lib/discovery.js +4 -3
- package/lib/discovery.js.map +1 -1
- package/lib/errors.d.ts +7 -0
- package/lib/errors.d.ts.map +1 -1
- package/lib/errors.js +6 -0
- package/lib/errors.js.map +1 -1
- package/lib/identity.d.ts +19 -0
- package/lib/identity.d.ts.map +1 -0
- package/lib/identity.js +111 -0
- package/lib/identity.js.map +1 -0
- package/lib/index.d.ts +8 -6
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +667 -656
- package/lib/index.js.map +4 -4
- package/lib/models.d.ts +15 -0
- package/lib/models.d.ts.map +1 -1
- package/lib/models.js +53 -0
- package/lib/models.js.map +1 -1
- package/lib/reactor.d.ts +16 -1
- package/lib/reactor.d.ts.map +1 -1
- package/lib/reactor.js +5 -1
- package/lib/reactor.js.map +1 -1
- package/lib/secret.d.ts +9 -0
- package/lib/secret.d.ts.map +1 -0
- package/lib/secret.js +21 -0
- package/lib/secret.js.map +1 -0
- package/lib/server.d.ts +15 -0
- package/lib/server.d.ts.map +1 -0
- package/lib/server.js +74 -0
- package/lib/server.js.map +1 -0
- package/lib/sessions.d.ts +6 -7
- package/lib/sessions.d.ts.map +1 -1
- package/lib/sessions.js +6 -19
- package/lib/sessions.js.map +1 -1
- package/package.json +14 -1
package/lib/index.js
CHANGED
|
@@ -26,6 +26,12 @@ var DiscoveryError = class extends PersonalAgentProtocolError {
|
|
|
26
26
|
this.name = "DiscoveryError";
|
|
27
27
|
}
|
|
28
28
|
};
|
|
29
|
+
var IdentityError = class extends PersonalAgentProtocolError {
|
|
30
|
+
constructor(code, message2, options = {}) {
|
|
31
|
+
super(code, message2, options);
|
|
32
|
+
this.name = "IdentityError";
|
|
33
|
+
}
|
|
34
|
+
};
|
|
29
35
|
var AuthorizationError = class extends PersonalAgentProtocolError {
|
|
30
36
|
constructor(code, message2, options = {}) {
|
|
31
37
|
super(code, message2, options);
|
|
@@ -45,7 +51,7 @@ var ProofError = class extends PersonalAgentProtocolError {
|
|
|
45
51
|
}
|
|
46
52
|
};
|
|
47
53
|
|
|
48
|
-
//
|
|
54
|
+
// node_modules/jose/dist/webapi/lib/buffer_utils.js
|
|
49
55
|
var encoder = new TextEncoder();
|
|
50
56
|
var decoder = new TextDecoder();
|
|
51
57
|
var strictDecoder = new TextDecoder("utf-8", { fatal: true });
|
|
@@ -95,12 +101,8 @@ function decodeBase64(encoded, url = false) {
|
|
|
95
101
|
bytes[i] = binary.charCodeAt(i);
|
|
96
102
|
return bytes;
|
|
97
103
|
}
|
|
98
|
-
async function digest(algorithm2, data) {
|
|
99
|
-
const subtleDigest = `SHA-${algorithm2.slice(-3)}`;
|
|
100
|
-
return new Uint8Array(await crypto.subtle.digest(subtleDigest, data));
|
|
101
|
-
}
|
|
102
104
|
|
|
103
|
-
//
|
|
105
|
+
// node_modules/jose/dist/webapi/util/errors.js
|
|
104
106
|
var JOSEError = class extends Error {
|
|
105
107
|
static code = "ERR_JOSE_GENERIC";
|
|
106
108
|
code = "ERR_JOSE_GENERIC";
|
|
@@ -108,30 +110,6 @@ var JOSEError = class extends Error {
|
|
|
108
110
|
super(message2, options), this.name = this.constructor.name, Error.captureStackTrace?.(this, this.constructor);
|
|
109
111
|
}
|
|
110
112
|
};
|
|
111
|
-
var JWTClaimValidationFailed = class extends JOSEError {
|
|
112
|
-
static code = "ERR_JWT_CLAIM_VALIDATION_FAILED";
|
|
113
|
-
code = "ERR_JWT_CLAIM_VALIDATION_FAILED";
|
|
114
|
-
claim;
|
|
115
|
-
reason;
|
|
116
|
-
payload;
|
|
117
|
-
constructor(message2, payload, claim = "unspecified", reason = "unspecified") {
|
|
118
|
-
super(message2, { cause: { claim, reason, payload } }), this.claim = claim, this.reason = reason, this.payload = payload;
|
|
119
|
-
}
|
|
120
|
-
};
|
|
121
|
-
var JWTExpired = class extends JOSEError {
|
|
122
|
-
static code = "ERR_JWT_EXPIRED";
|
|
123
|
-
code = "ERR_JWT_EXPIRED";
|
|
124
|
-
claim;
|
|
125
|
-
reason;
|
|
126
|
-
payload;
|
|
127
|
-
constructor(message2, payload, claim = "unspecified", reason = "unspecified") {
|
|
128
|
-
super(message2, { cause: { claim, reason, payload } }), this.claim = claim, this.reason = reason, this.payload = payload;
|
|
129
|
-
}
|
|
130
|
-
};
|
|
131
|
-
var JOSEAlgNotAllowed = class extends JOSEError {
|
|
132
|
-
static code = "ERR_JOSE_ALG_NOT_ALLOWED";
|
|
133
|
-
code = "ERR_JOSE_ALG_NOT_ALLOWED";
|
|
134
|
-
};
|
|
135
113
|
var JOSENotSupported = class extends JOSEError {
|
|
136
114
|
static code = "ERR_JOSE_NOT_SUPPORTED";
|
|
137
115
|
code = "ERR_JOSE_NOT_SUPPORTED";
|
|
@@ -144,19 +122,8 @@ var JWTInvalid = class extends JOSEError {
|
|
|
144
122
|
static code = "ERR_JWT_INVALID";
|
|
145
123
|
code = "ERR_JWT_INVALID";
|
|
146
124
|
};
|
|
147
|
-
var JWKInvalid = class extends JOSEError {
|
|
148
|
-
static code = "ERR_JWK_INVALID";
|
|
149
|
-
code = "ERR_JWK_INVALID";
|
|
150
|
-
};
|
|
151
|
-
var JWSSignatureVerificationFailed = class extends JOSEError {
|
|
152
|
-
static code = "ERR_JWS_SIGNATURE_VERIFICATION_FAILED";
|
|
153
|
-
code = "ERR_JWS_SIGNATURE_VERIFICATION_FAILED";
|
|
154
|
-
constructor(message2 = "signature verification failed", options) {
|
|
155
|
-
super(message2, options);
|
|
156
|
-
}
|
|
157
|
-
};
|
|
158
125
|
|
|
159
|
-
//
|
|
126
|
+
// node_modules/jose/dist/webapi/util/base64url.js
|
|
160
127
|
var invalid = "The input to be decoded is not correctly encoded.";
|
|
161
128
|
function decode(input) {
|
|
162
129
|
try {
|
|
@@ -169,7 +136,7 @@ function encode2(input) {
|
|
|
169
136
|
return encodeBase64(typeof input == "string" ? encoder.encode(input) : input, true);
|
|
170
137
|
}
|
|
171
138
|
|
|
172
|
-
//
|
|
139
|
+
// node_modules/jose/dist/webapi/lib/validate.js
|
|
173
140
|
function isObject(input) {
|
|
174
141
|
if (typeof input != "object" || input === null || Object.prototype.toString.call(input) !== "[object Object]")
|
|
175
142
|
return false;
|
|
@@ -191,37 +158,7 @@ function assertNotSet(value, name) {
|
|
|
191
158
|
if (value !== void 0)
|
|
192
159
|
throw new TypeError(`${name} can only be called once`);
|
|
193
160
|
}
|
|
194
|
-
function decodeBase64url(value, label, ErrorClass) {
|
|
195
|
-
try {
|
|
196
|
-
return decode(value);
|
|
197
|
-
} catch {
|
|
198
|
-
throw new ErrorClass(`Failed to base64url decode the ${label}`);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
function encodeBase64url(value, label, ErrorClass) {
|
|
202
|
-
try {
|
|
203
|
-
return encode(value);
|
|
204
|
-
} catch {
|
|
205
|
-
throw new ErrorClass(`The ${label} is not a valid base64url string`);
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
function parseJoseHeader(b64, ErrorClass, message2) {
|
|
209
|
-
let parsed;
|
|
210
|
-
try {
|
|
211
|
-
parsed = JSON.parse(strictDecoder.decode(decode(b64)));
|
|
212
|
-
} catch {
|
|
213
|
-
throw new ErrorClass(message2);
|
|
214
|
-
}
|
|
215
|
-
if (!isObject(parsed))
|
|
216
|
-
throw new ErrorClass(message2);
|
|
217
|
-
return parsed;
|
|
218
|
-
}
|
|
219
161
|
var JWS_RECOGNIZED = { __proto__: null, b64: true };
|
|
220
|
-
function validateAlgorithms(option, algorithms) {
|
|
221
|
-
if (algorithms !== void 0 && (!Array.isArray(algorithms) || algorithms.some((s) => typeof s != "string")))
|
|
222
|
-
throw new TypeError(`"${option}" option must be an array of strings`);
|
|
223
|
-
return algorithms === void 0 ? void 0 : new Set(algorithms);
|
|
224
|
-
}
|
|
225
162
|
function validateCritDuplicates(Err, protectedHeader) {
|
|
226
163
|
const { crit } = protectedHeader ?? {};
|
|
227
164
|
if (Array.isArray(crit) && new Set(crit).size !== crit.length)
|
|
@@ -266,7 +203,7 @@ function serializeJoseHeader(Err, header) {
|
|
|
266
203
|
return [parsed, serialized];
|
|
267
204
|
}
|
|
268
205
|
|
|
269
|
-
//
|
|
206
|
+
// node_modules/jose/dist/webapi/lib/key.js
|
|
270
207
|
var tag = (key) => key[Symbol.toStringTag];
|
|
271
208
|
var jwkMatchesOp = (entry, key, usage) => {
|
|
272
209
|
const { alg } = entry;
|
|
@@ -346,7 +283,6 @@ function message(msg, actual, ...types) {
|
|
|
346
283
|
} else types.length === 2 ? msg += `one of type ${types[0]} or ${types[1]}.` : msg += `of type ${types[0]}.`;
|
|
347
284
|
return actual == null ? msg += ` Received ${actual}` : typeof actual == "function" && actual.name ? msg += ` Received function ${actual.name}` : typeof actual == "object" && actual != null && actual.constructor?.name && (msg += ` Received an instance of ${actual.constructor.name}`), msg;
|
|
348
285
|
}
|
|
349
|
-
var invalidKeyInput = (actual, ...types) => message("Key must be ", actual, ...types);
|
|
350
286
|
function invalidKeyType(alg, actual, secret) {
|
|
351
287
|
const types = ["CryptoKey", "KeyObject", "JSON Web Key"];
|
|
352
288
|
return secret && types.push("Uint8Array"), new TypeError(message(`Key for the ${alg} algorithm must be `, actual, ...types));
|
|
@@ -388,11 +324,6 @@ function normalizeJwk(jwk) {
|
|
|
388
324
|
}
|
|
389
325
|
return normalized;
|
|
390
326
|
}
|
|
391
|
-
function validateExtractableOption(extractable) {
|
|
392
|
-
if (extractable !== void 0 && typeof extractable != "boolean")
|
|
393
|
-
throw new TypeError('"extractable" option must be a boolean');
|
|
394
|
-
return extractable;
|
|
395
|
-
}
|
|
396
327
|
async function jwkToKey(entry, jwk, extractable) {
|
|
397
328
|
if (!entry.kty.includes(jwk.kty))
|
|
398
329
|
throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
|
|
@@ -403,7 +334,7 @@ async function rawKey(key, expected, usage, extractable = false) {
|
|
|
403
334
|
return key instanceof Uint8Array && (key = await crypto.subtle.importKey("raw", key, expected, extractable, [usage])), checkCryptoKey(key, expected, usage), key;
|
|
404
335
|
}
|
|
405
336
|
|
|
406
|
-
//
|
|
337
|
+
// node_modules/jose/dist/webapi/lib/key_descriptor.js
|
|
407
338
|
function table(entries) {
|
|
408
339
|
const out = { __proto__: null };
|
|
409
340
|
for (const alg in entries)
|
|
@@ -411,108 +342,7 @@ function table(entries) {
|
|
|
411
342
|
return out;
|
|
412
343
|
}
|
|
413
344
|
|
|
414
|
-
//
|
|
415
|
-
var wrap = [
|
|
416
|
-
["encrypt", "wrapKey"],
|
|
417
|
-
["decrypt", "unwrapKey"]
|
|
418
|
-
];
|
|
419
|
-
var derive = [[], ["deriveBits"]];
|
|
420
|
-
var none = [[], []];
|
|
421
|
-
function rsaes(bits) {
|
|
422
|
-
return {
|
|
423
|
-
kty: ["RSA"],
|
|
424
|
-
mode: "key-encryption",
|
|
425
|
-
subtle: { name: "RSA-OAEP", hash: `SHA-${bits}` },
|
|
426
|
-
usages: wrap,
|
|
427
|
-
ops: ["wrapKey", "unwrapKey"]
|
|
428
|
-
};
|
|
429
|
-
}
|
|
430
|
-
function ecdh(mode) {
|
|
431
|
-
return {
|
|
432
|
-
kty: ["EC", "OKP"],
|
|
433
|
-
mode,
|
|
434
|
-
subtle: { name: "ECDH" },
|
|
435
|
-
resolve: ({ kty, crv, asymmetricKeyType }) => {
|
|
436
|
-
if (crv === "X25519" || asymmetricKeyType === "x25519")
|
|
437
|
-
return { name: "X25519" };
|
|
438
|
-
if (kty === "OKP")
|
|
439
|
-
throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
|
|
440
|
-
return { name: "ECDH", namedCurve: crv };
|
|
441
|
-
},
|
|
442
|
-
usages: derive,
|
|
443
|
-
ops: [void 0, "deriveBits"]
|
|
444
|
-
};
|
|
445
|
-
}
|
|
446
|
-
function aeskw(bits, gcm = false) {
|
|
447
|
-
return {
|
|
448
|
-
kty: ["oct"],
|
|
449
|
-
mode: "key-wrapping",
|
|
450
|
-
secret: true,
|
|
451
|
-
subtle: { name: gcm ? "AES-GCM" : "AES-KW", length: bits },
|
|
452
|
-
usages: none,
|
|
453
|
-
ops: gcm ? ["encrypt", "decrypt"] : ["wrapKey", "unwrapKey"]
|
|
454
|
-
};
|
|
455
|
-
}
|
|
456
|
-
function pbes2() {
|
|
457
|
-
return {
|
|
458
|
-
kty: ["oct"],
|
|
459
|
-
mode: "key-wrapping",
|
|
460
|
-
secret: true,
|
|
461
|
-
subtle: { name: "PBKDF2" },
|
|
462
|
-
usages: none,
|
|
463
|
-
ops: ["deriveBits", "deriveBits"]
|
|
464
|
-
};
|
|
465
|
-
}
|
|
466
|
-
var JWE = table({
|
|
467
|
-
dir: {
|
|
468
|
-
kty: ["oct"],
|
|
469
|
-
mode: "direct-encryption",
|
|
470
|
-
secret: true,
|
|
471
|
-
subtle: { name: "AES-GCM" },
|
|
472
|
-
usages: none,
|
|
473
|
-
ops: ["encrypt", "decrypt"]
|
|
474
|
-
},
|
|
475
|
-
"RSA-OAEP": rsaes(1),
|
|
476
|
-
"RSA-OAEP-256": rsaes(256),
|
|
477
|
-
"RSA-OAEP-384": rsaes(384),
|
|
478
|
-
"RSA-OAEP-512": rsaes(512),
|
|
479
|
-
"ECDH-ES": ecdh("direct-key-agreement"),
|
|
480
|
-
"ECDH-ES+A128KW": ecdh("key-agreement-with-key-wrapping"),
|
|
481
|
-
"ECDH-ES+A192KW": ecdh("key-agreement-with-key-wrapping"),
|
|
482
|
-
"ECDH-ES+A256KW": ecdh("key-agreement-with-key-wrapping"),
|
|
483
|
-
A128KW: aeskw(128),
|
|
484
|
-
A192KW: aeskw(192),
|
|
485
|
-
A256KW: aeskw(256),
|
|
486
|
-
A128GCMKW: aeskw(128, true),
|
|
487
|
-
A192GCMKW: aeskw(192, true),
|
|
488
|
-
A256GCMKW: aeskw(256, true),
|
|
489
|
-
"PBES2-HS256+A128KW": pbes2(),
|
|
490
|
-
"PBES2-HS384+A192KW": pbes2(),
|
|
491
|
-
"PBES2-HS512+A256KW": pbes2()
|
|
492
|
-
});
|
|
493
|
-
var contentOps = ["encrypt", "decrypt"];
|
|
494
|
-
function contentEncryption(bits, cbc = false) {
|
|
495
|
-
return {
|
|
496
|
-
kty: ["oct"],
|
|
497
|
-
secret: true,
|
|
498
|
-
subtle: { name: cbc ? "AES-CBC" : "AES-GCM", length: bits },
|
|
499
|
-
usages: none,
|
|
500
|
-
ops: contentOps,
|
|
501
|
-
cekBits: bits,
|
|
502
|
-
ivBits: cbc ? 128 : 96,
|
|
503
|
-
cbc
|
|
504
|
-
};
|
|
505
|
-
}
|
|
506
|
-
var ENC = table({
|
|
507
|
-
A128GCM: contentEncryption(128),
|
|
508
|
-
A192GCM: contentEncryption(192),
|
|
509
|
-
A256GCM: contentEncryption(256),
|
|
510
|
-
"A128CBC-HS256": contentEncryption(256, true),
|
|
511
|
-
"A192CBC-HS384": contentEncryption(384, true),
|
|
512
|
-
"A256CBC-HS512": contentEncryption(512, true)
|
|
513
|
-
});
|
|
514
|
-
|
|
515
|
-
// ../../node_modules/jose/dist/webapi/lib/jws_algorithms.js
|
|
345
|
+
// node_modules/jose/dist/webapi/lib/jws_algorithms.js
|
|
516
346
|
var sig = [["verify"], ["sign"]];
|
|
517
347
|
function hmac(bits) {
|
|
518
348
|
const subtle = { name: "HMAC", hash: `SHA-${bits}` };
|
|
@@ -582,59 +412,7 @@ function jwsAlgorithm(alg) {
|
|
|
582
412
|
return entry;
|
|
583
413
|
}
|
|
584
414
|
|
|
585
|
-
//
|
|
586
|
-
function prepareVerify(options) {
|
|
587
|
-
return [options && validateAlgorithms("algorithms", options.algorithms), options?.crit];
|
|
588
|
-
}
|
|
589
|
-
function parseProtectedHeader(encodedProtected) {
|
|
590
|
-
return encodedProtected === void 0 ? {} : parseJoseHeader(encodedProtected, JWSInvalid, "JWS Protected Header is invalid");
|
|
591
|
-
}
|
|
592
|
-
function encodeCompactUnencodedPayload(payload) {
|
|
593
|
-
try {
|
|
594
|
-
return encode(payload);
|
|
595
|
-
} catch {
|
|
596
|
-
throw new JWSInvalid("JWS Compact Serialization payload must use only ASCII characters");
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
async function verifySignature(jws, shared, key, encodeUnencodedPayload, parsedProtected) {
|
|
600
|
-
const { protected: encodedProtected, header, payload: inputPayload } = jws, parsedProt = parsedProtected ?? parseProtectedHeader(encodedProtected);
|
|
601
|
-
if (!isDisjoint(parsedProt, header))
|
|
602
|
-
throw new JWSInvalid("JWS Protected and JWS Unprotected Header Parameter names must be disjoint");
|
|
603
|
-
const joseHeader = { ...parsedProt, ...header }, b64 = validateB64(parsedProt, validateCrit(JWSInvalid, JWS_RECOGNIZED, shared[1], parsedProt, joseHeader)), { alg } = joseHeader;
|
|
604
|
-
if (typeof alg != "string" || !alg)
|
|
605
|
-
throw new JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid');
|
|
606
|
-
if (shared[0] && !shared[0].has(alg))
|
|
607
|
-
throw new JOSEAlgNotAllowed('"alg" (Algorithm) Header Parameter value not allowed');
|
|
608
|
-
if (b64) {
|
|
609
|
-
if (typeof inputPayload != "string")
|
|
610
|
-
throw new JWSInvalid("JWS Payload must be a string");
|
|
611
|
-
} else if (typeof inputPayload != "string" && !(inputPayload instanceof Uint8Array))
|
|
612
|
-
throw new JWSInvalid("JWS Payload must be a string or an Uint8Array instance");
|
|
613
|
-
const signingPayload = b64 || typeof inputPayload != "string" ? inputPayload : encodeUnencodedPayload(inputPayload);
|
|
614
|
-
let resolvedKey = false;
|
|
615
|
-
typeof key == "function" && (key = await key(parsedProt, jws), resolvedKey = true);
|
|
616
|
-
const entry = jwsAlgorithm(alg), data = concat(encodedProtected !== void 0 ? encode(encodedProtected) : new Uint8Array(), encode("."), typeof signingPayload == "string" ? shared[2] ??= encodeBase64url(signingPayload, "payload", JWSInvalid) : signingPayload), signature = decodeBase64url(jws.signature, "signature", JWSInvalid), k = await prepareKey(entry, key, "verify"), cryptoKey = await rawKey(k, entry.subtle, "verify");
|
|
617
|
-
entry.minRsaBits && checkModulusLength(entry.alg, cryptoKey);
|
|
618
|
-
let verified = false;
|
|
619
|
-
try {
|
|
620
|
-
verified = await crypto.subtle.verify(entry.signing, cryptoKey, signature, data);
|
|
621
|
-
} catch {
|
|
622
|
-
}
|
|
623
|
-
if (!verified)
|
|
624
|
-
throw new JWSSignatureVerificationFailed();
|
|
625
|
-
const result = { payload: typeof signingPayload == "string" ? decodeBase64url(signingPayload, "payload", JWSInvalid) : signingPayload };
|
|
626
|
-
return encodedProtected !== void 0 && (result.protectedHeader = parsedProt), header !== void 0 && (result.unprotectedHeader = header), resolvedKey ? [{ ...result, key: k }, b64] : [result, b64];
|
|
627
|
-
}
|
|
628
|
-
async function verifyCompact(jws, shared, key) {
|
|
629
|
-
if (jws instanceof Uint8Array && (jws = decoder.decode(jws)), typeof jws != "string")
|
|
630
|
-
throw new JWSInvalid("Compact JWS must be a string or Uint8Array");
|
|
631
|
-
const { 0: protectedHeader, 1: payload, 2: signature, length } = jws.split(".");
|
|
632
|
-
if (length !== 3)
|
|
633
|
-
throw new JWSInvalid("Invalid Compact JWS");
|
|
634
|
-
return verifySignature({ payload, protected: protectedHeader, signature }, shared, key, encodeCompactUnencodedPayload);
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
// ../../node_modules/jose/dist/webapi/lib/jwt_claims_set.js
|
|
415
|
+
// node_modules/jose/dist/webapi/lib/jwt_claims_set.js
|
|
638
416
|
var epoch = (date) => Math.floor(date.getTime() / 1e3);
|
|
639
417
|
var multipliers = {
|
|
640
418
|
s: 1,
|
|
@@ -645,7 +423,6 @@ var multipliers = {
|
|
|
645
423
|
y: 31557600
|
|
646
424
|
};
|
|
647
425
|
var REGEX = /^(\+|\-)? ?(\d+|\d+\.\d+) ?(seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)(?: (ago|from now))?$/i;
|
|
648
|
-
var checkFailed = "check_failed";
|
|
649
426
|
function invalidDuration() {
|
|
650
427
|
throw new TypeError("Invalid time period format");
|
|
651
428
|
}
|
|
@@ -672,64 +449,6 @@ function validateAudienceClaim(value) {
|
|
|
672
449
|
function numericDate(value, label) {
|
|
673
450
|
return typeof value == "number" ? validateInput(label, value) : value instanceof Date ? validateInput(label, epoch(value)) : epoch(/* @__PURE__ */ new Date()) + secs(value);
|
|
674
451
|
}
|
|
675
|
-
var normalizeTyp = (value) => {
|
|
676
|
-
const normalized = value.toLowerCase();
|
|
677
|
-
return value.includes("/") ? normalized : `application/${normalized}`;
|
|
678
|
-
};
|
|
679
|
-
var checkAudiencePresence = (audPayload, audOption) => typeof audPayload == "string" ? audOption.includes(audPayload) : Array.isArray(audPayload) ? audOption.some((aud) => audPayload.includes(aud)) : false;
|
|
680
|
-
function validateNumericDate(payload, claim, required = false) {
|
|
681
|
-
const value = payload[claim];
|
|
682
|
-
if (!(value === void 0 && !required)) {
|
|
683
|
-
if (typeof value != "number")
|
|
684
|
-
throw new JWTClaimValidationFailed(`"${claim}" claim must be a number`, payload, claim, "invalid");
|
|
685
|
-
return value;
|
|
686
|
-
}
|
|
687
|
-
}
|
|
688
|
-
function unexpectedClaim(payload, claim) {
|
|
689
|
-
throw new JWTClaimValidationFailed(`unexpected "${claim}" claim value`, payload, claim, checkFailed);
|
|
690
|
-
}
|
|
691
|
-
function validateClaimsSet(protectedHeader, encodedPayload, options = {}) {
|
|
692
|
-
let payload;
|
|
693
|
-
try {
|
|
694
|
-
payload = JSON.parse(strictDecoder.decode(encodedPayload));
|
|
695
|
-
} catch {
|
|
696
|
-
}
|
|
697
|
-
if (!isObject(payload))
|
|
698
|
-
throw new JWTInvalid("JWT Claims Set must be a top-level JSON object");
|
|
699
|
-
const { typ } = options;
|
|
700
|
-
if (typ !== void 0 && (typeof protectedHeader.typ != "string" || normalizeTyp(protectedHeader.typ) !== normalizeTyp(typ)))
|
|
701
|
-
throw new JWTClaimValidationFailed('unexpected "typ" JWT header value', payload, "typ", checkFailed);
|
|
702
|
-
const { requiredClaims = [], issuer, subject, audience, maxTokenAge } = options, presenceCheck = [...requiredClaims];
|
|
703
|
-
maxTokenAge !== void 0 && presenceCheck.push("iat"), audience !== void 0 && presenceCheck.push("aud"), subject !== void 0 && presenceCheck.push("sub"), issuer !== void 0 && presenceCheck.push("iss");
|
|
704
|
-
for (const claim of new Set(presenceCheck.reverse()))
|
|
705
|
-
if (!Object.hasOwn(payload, claim))
|
|
706
|
-
throw new JWTClaimValidationFailed(`missing required "${claim}" claim`, payload, claim, "missing");
|
|
707
|
-
issuer !== void 0 && !(Array.isArray(issuer) ? issuer : [issuer]).includes(payload.iss) && unexpectedClaim(payload, "iss"), subject !== void 0 && payload.sub !== subject && unexpectedClaim(payload, "sub"), audience !== void 0 && !checkAudiencePresence(payload.aud, typeof audience == "string" ? [audience] : audience) && unexpectedClaim(payload, "aud");
|
|
708
|
-
const { clockTolerance } = options;
|
|
709
|
-
let tolerance = 0;
|
|
710
|
-
if (typeof clockTolerance == "string")
|
|
711
|
-
tolerance = secs(clockTolerance);
|
|
712
|
-
else if (clockTolerance !== void 0) {
|
|
713
|
-
if (typeof clockTolerance != "number")
|
|
714
|
-
throw new TypeError("Invalid clockTolerance option type");
|
|
715
|
-
tolerance = clockTolerance;
|
|
716
|
-
}
|
|
717
|
-
validateInput("clockTolerance option", tolerance);
|
|
718
|
-
const { currentDate } = options, now = validateInput("currentDate option", epoch(currentDate === void 0 ? /* @__PURE__ */ new Date() : currentDate)), iat = validateNumericDate(payload, "iat", maxTokenAge !== void 0), nbf = validateNumericDate(payload, "nbf");
|
|
719
|
-
if (nbf !== void 0 && nbf > now + tolerance)
|
|
720
|
-
throw new JWTClaimValidationFailed('"nbf" claim timestamp check failed', payload, "nbf", checkFailed);
|
|
721
|
-
const exp = validateNumericDate(payload, "exp");
|
|
722
|
-
if (exp !== void 0 && exp <= now - tolerance)
|
|
723
|
-
throw new JWTExpired('"exp" claim timestamp check failed', payload, "exp", checkFailed);
|
|
724
|
-
if (maxTokenAge !== void 0) {
|
|
725
|
-
const age = now - iat, max = validateInput("maxTokenAge option", typeof maxTokenAge == "number" ? maxTokenAge : secs(maxTokenAge));
|
|
726
|
-
if (age - tolerance > max)
|
|
727
|
-
throw new JWTExpired('"iat" claim timestamp check failed (too far in the past)', payload, "iat", checkFailed);
|
|
728
|
-
if (age < -tolerance)
|
|
729
|
-
throw new JWTClaimValidationFailed('"iat" claim timestamp check failed (it should be in the past)', payload, "iat", checkFailed);
|
|
730
|
-
}
|
|
731
|
-
return payload;
|
|
732
|
-
}
|
|
733
452
|
var producerPayloads;
|
|
734
453
|
function producerPayload(producer) {
|
|
735
454
|
return producerPayloads.get(producer);
|
|
@@ -773,16 +492,7 @@ var JWTClaimsBuilder = class {
|
|
|
773
492
|
}
|
|
774
493
|
};
|
|
775
494
|
|
|
776
|
-
//
|
|
777
|
-
async function jwtVerify(jwt, key, options) {
|
|
778
|
-
const [verified, b64] = await verifyCompact(jwt, prepareVerify(options), key);
|
|
779
|
-
if (!b64)
|
|
780
|
-
throw new JWTInvalid("JWTs MUST NOT use unencoded payload");
|
|
781
|
-
const payload = validateClaimsSet(verified.protectedHeader, verified.payload, options);
|
|
782
|
-
return { ...verified, payload };
|
|
783
|
-
}
|
|
784
|
-
|
|
785
|
-
// ../../node_modules/jose/dist/webapi/lib/jws_sign.js
|
|
495
|
+
// node_modules/jose/dist/webapi/lib/jws_sign.js
|
|
786
496
|
async function createSignature(input, key, rejectUnencoded) {
|
|
787
497
|
let [payload, protectedHeader, unprotectedHeader, crit] = input, protectedHeaderString = "";
|
|
788
498
|
if (protectedHeader !== void 0) {
|
|
@@ -820,7 +530,7 @@ async function createCompactSignature(payload, protectedHeader, crit, key, rejec
|
|
|
820
530
|
return `${jws.protected}.${jws.payload}.${jws.signature}`;
|
|
821
531
|
}
|
|
822
532
|
|
|
823
|
-
//
|
|
533
|
+
// node_modules/jose/dist/webapi/jwt/sign.js
|
|
824
534
|
var SignJWT_base = JWTClaimsBuilder;
|
|
825
535
|
var SignJWT = class extends SignJWT_base {
|
|
826
536
|
#protectedHeader;
|
|
@@ -834,123 +544,95 @@ var SignJWT = class extends SignJWT_base {
|
|
|
834
544
|
}
|
|
835
545
|
};
|
|
836
546
|
|
|
837
|
-
//
|
|
838
|
-
|
|
839
|
-
|
|
547
|
+
// src/crypto.ts
|
|
548
|
+
var privateJwkMembers = /* @__PURE__ */ new Set(["d", "p", "q", "dp", "dq", "qi", "oth", "k"]);
|
|
549
|
+
function algorithm(value) {
|
|
550
|
+
if (value !== "ES256" && value !== "RS256") {
|
|
551
|
+
throw new TypeError("PAP JOSE algorithms must be ES256 or RS256");
|
|
552
|
+
}
|
|
553
|
+
return value;
|
|
840
554
|
}
|
|
841
|
-
function
|
|
842
|
-
|
|
555
|
+
function publicJwk(value, alg) {
|
|
556
|
+
for (const member of privateJwkMembers) {
|
|
557
|
+
if (member in value) {
|
|
558
|
+
throw new TypeError("DPoP public JWK must not contain private key material");
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
const expected = alg === "ES256" ? "EC" : "RSA";
|
|
562
|
+
if (value.kty !== expected) throw new TypeError(`${alg} requires a ${expected} public JWK`);
|
|
563
|
+
if (alg === "ES256") {
|
|
564
|
+
if (value.crv !== "P-256" || !value.x || !value.y) {
|
|
565
|
+
throw new TypeError("ES256 requires a complete P-256 public JWK");
|
|
566
|
+
}
|
|
567
|
+
} else if (!value.n || !value.e) {
|
|
568
|
+
throw new TypeError("RS256 requires a complete RSA public JWK");
|
|
569
|
+
}
|
|
570
|
+
return { ...value };
|
|
843
571
|
}
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
if (!isCryptoKey(key))
|
|
858
|
-
throw new TypeError(invalidKeyInput(key, "CryptoKey", "KeyObject", "Uint8Array"));
|
|
859
|
-
if (!key.extractable)
|
|
860
|
-
throw new TypeError("non-extractable CryptoKey cannot be exported as a JWK");
|
|
861
|
-
const jwk = await crypto.subtle.exportKey("jwk", key);
|
|
862
|
-
delete jwk.ext, delete jwk.key_ops, delete jwk.use, jwk.kty !== "AKP" && delete jwk.alg;
|
|
863
|
-
for (const parameter of Object.keys(jwk))
|
|
864
|
-
jwk[parameter] === void 0 && delete jwk[parameter];
|
|
865
|
-
return jwk;
|
|
572
|
+
function normalizedHtu(value) {
|
|
573
|
+
let url;
|
|
574
|
+
try {
|
|
575
|
+
url = new URL(value);
|
|
576
|
+
} catch (cause) {
|
|
577
|
+
throw new ProofError("invalid_htu", "DPoP target must be an HTTPS URL", { cause });
|
|
578
|
+
}
|
|
579
|
+
if (url.protocol !== "https:" || url.username || url.password) {
|
|
580
|
+
throw new ProofError("invalid_htu", "DPoP target must be an HTTPS URL");
|
|
581
|
+
}
|
|
582
|
+
url.search = "";
|
|
583
|
+
url.hash = "";
|
|
584
|
+
return url.href;
|
|
866
585
|
}
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
throw new JWKInvalid(`${description} missing or invalid`);
|
|
872
|
-
};
|
|
873
|
-
async function calculateJwkThumbprint(key, digestAlgorithm) {
|
|
874
|
-
let jwk;
|
|
875
|
-
if (isObject(key)) {
|
|
876
|
-
if (jwk = snapshotJwk(key), typeof jwk.kty != "string")
|
|
877
|
-
throw new TypeError(invalidKeyInput(key, "CryptoKey", "KeyObject", "JSON Web Key"));
|
|
878
|
-
} else if (isKeyLike(key))
|
|
879
|
-
jwk = snapshotJwk(await exportJWK(key));
|
|
880
|
-
else
|
|
881
|
-
throw new TypeError(invalidKeyInput(key, "CryptoKey", "KeyObject", "JSON Web Key"));
|
|
882
|
-
if (digestAlgorithm ??= "sha256", digestAlgorithm !== "sha256" && digestAlgorithm !== "sha384" && digestAlgorithm !== "sha512")
|
|
883
|
-
throw new TypeError('digestAlgorithm must one of "sha256", "sha384", or "sha512"');
|
|
884
|
-
let components;
|
|
885
|
-
switch (jwk.kty) {
|
|
886
|
-
case "AKP":
|
|
887
|
-
check(jwk.alg, '"alg" (Algorithm) Parameter'), check(jwk.pub, '"pub" (Public key) Parameter'), components = { alg: jwk.alg, kty: jwk.kty, pub: jwk.pub };
|
|
888
|
-
break;
|
|
889
|
-
case "EC":
|
|
890
|
-
check(jwk.crv, '"crv" (Curve) Parameter'), check(jwk.x, '"x" (X Coordinate) Parameter'), check(jwk.y, '"y" (Y Coordinate) Parameter'), components = { crv: jwk.crv, kty: jwk.kty, x: jwk.x, y: jwk.y };
|
|
891
|
-
break;
|
|
892
|
-
case "OKP":
|
|
893
|
-
check(jwk.crv, '"crv" (Subtype of Key Pair) Parameter'), check(jwk.x, '"x" (Public Key) Parameter'), components = { crv: jwk.crv, kty: jwk.kty, x: jwk.x };
|
|
894
|
-
break;
|
|
895
|
-
case "RSA":
|
|
896
|
-
check(jwk.e, '"e" (Exponent) Parameter'), check(jwk.n, '"n" (Modulus) Parameter'), components = { e: jwk.e, kty: jwk.kty, n: jwk.n };
|
|
897
|
-
break;
|
|
898
|
-
case "oct":
|
|
899
|
-
if (typeof jwk.k != "string")
|
|
900
|
-
throw new JWKInvalid('"k" (Key Value) Parameter missing or invalid');
|
|
901
|
-
components = { k: jwk.k, kty: jwk.kty };
|
|
902
|
-
break;
|
|
903
|
-
default:
|
|
904
|
-
throw new JOSENotSupported('"kty" (Key Type) Parameter missing or unsupported');
|
|
905
|
-
}
|
|
906
|
-
const data = encode(JSON.stringify(components));
|
|
907
|
-
return encode2(await digest(digestAlgorithm, data));
|
|
586
|
+
function base64Url(bytes) {
|
|
587
|
+
let binary = "";
|
|
588
|
+
for (const value of bytes) binary += String.fromCharCode(value);
|
|
589
|
+
return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/u, "");
|
|
908
590
|
}
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
if (!isObject(jwk))
|
|
913
|
-
throw new TypeError("JWK must be an object");
|
|
914
|
-
const normalized = normalizeJwk(jwk), extractable = validateExtractableOption(options?.extractable), { alg: jwkAlg } = normalized;
|
|
915
|
-
if (alg ??= jwkAlg, normalized.kty !== "oct" && !alg)
|
|
916
|
-
throw new TypeError('"alg" argument is required when "jwk.alg" is not present');
|
|
917
|
-
switch (normalized.kty) {
|
|
918
|
-
case "oct":
|
|
919
|
-
if (typeof normalized.k != "string")
|
|
920
|
-
throw new TypeError('missing "k" (Key Value) Parameter value');
|
|
921
|
-
return decode(normalized.k);
|
|
922
|
-
case "AKP": {
|
|
923
|
-
if (typeof jwkAlg != "string" || !jwkAlg)
|
|
924
|
-
throw new TypeError('missing "alg" (Algorithm) Parameter value');
|
|
925
|
-
if (alg !== jwkAlg)
|
|
926
|
-
throw new TypeError("JWK alg and alg option value mismatch");
|
|
927
|
-
return jwkToKey(keyAlgorithm(alg), normalized, extractable);
|
|
928
|
-
}
|
|
929
|
-
case "RSA":
|
|
930
|
-
case "EC":
|
|
931
|
-
case "OKP":
|
|
932
|
-
return jwkToKey(keyAlgorithm(alg), normalized, extractable);
|
|
933
|
-
default:
|
|
934
|
-
throw new JOSENotSupported('Unsupported "kty" (Key Type) Parameter value');
|
|
935
|
-
}
|
|
591
|
+
function randomBytes(length) {
|
|
592
|
+
if (!globalThis.crypto) throw new ProofError("crypto_unavailable", "Web Crypto is required");
|
|
593
|
+
return globalThis.crypto.getRandomValues(new Uint8Array(length));
|
|
936
594
|
}
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
} else if (typeof token == "object" && token)
|
|
945
|
-
if ("protected" in token)
|
|
946
|
-
protectedB64u = token.protected;
|
|
947
|
-
else
|
|
948
|
-
throw new TypeError("Token does not contain a Protected Header");
|
|
949
|
-
const invalid2 = "Invalid Token or Protected Header formatting";
|
|
950
|
-
if (typeof protectedB64u != "string" || !protectedB64u)
|
|
951
|
-
throw new TypeError(invalid2);
|
|
952
|
-
return parseJoseHeader(protectedB64u, TypeError, invalid2);
|
|
595
|
+
async function accessTokenHash(token) {
|
|
596
|
+
if (!globalThis.crypto) throw new ProofError("crypto_unavailable", "Web Crypto is required");
|
|
597
|
+
const digest = await globalThis.crypto.subtle.digest(
|
|
598
|
+
"SHA-256",
|
|
599
|
+
new TextEncoder().encode(token.reveal())
|
|
600
|
+
);
|
|
601
|
+
return base64Url(new Uint8Array(digest));
|
|
953
602
|
}
|
|
603
|
+
var JoseDpopProofProvider = class {
|
|
604
|
+
#resolveKey;
|
|
605
|
+
#now;
|
|
606
|
+
#randomBytes;
|
|
607
|
+
constructor(options) {
|
|
608
|
+
this.#resolveKey = options.resolveKey;
|
|
609
|
+
this.#now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
610
|
+
this.#randomBytes = options.randomBytes ?? randomBytes;
|
|
611
|
+
}
|
|
612
|
+
async create(request) {
|
|
613
|
+
const material = await this.#resolveKey(request);
|
|
614
|
+
const alg = algorithm(material.algorithm ?? "ES256");
|
|
615
|
+
const jwk = publicJwk(material.publicJwk, alg);
|
|
616
|
+
const entropy2 = this.#randomBytes(16);
|
|
617
|
+
if (entropy2.byteLength < 16) {
|
|
618
|
+
throw new ProofError("weak_randomness", "DPoP proof IDs require 128 random bits");
|
|
619
|
+
}
|
|
620
|
+
const claims = {
|
|
621
|
+
jti: base64Url(entropy2),
|
|
622
|
+
htm: request.method.toUpperCase(),
|
|
623
|
+
htu: normalizedHtu(request.url),
|
|
624
|
+
iat: Math.floor(this.#now().getTime() / 1e3),
|
|
625
|
+
...request.nonce === void 0 ? {} : { nonce: request.nonce },
|
|
626
|
+
...request.accessToken === void 0 ? {} : { ath: await accessTokenHash(request.accessToken) }
|
|
627
|
+
};
|
|
628
|
+
try {
|
|
629
|
+
const token = await new SignJWT(claims).setProtectedHeader({ typ: "dpop+jwt", alg, jwk }).sign(material.privateKey);
|
|
630
|
+
return new SecretValue(token);
|
|
631
|
+
} catch (cause) {
|
|
632
|
+
throw new ProofError("signing_failed", "Could not sign DPoP proof", { cause });
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
};
|
|
954
636
|
|
|
955
637
|
// src/json.ts
|
|
956
638
|
function parseJsonStrict(source) {
|
|
@@ -1088,7 +770,27 @@ var StrictJsonParser = class {
|
|
|
1088
770
|
}
|
|
1089
771
|
};
|
|
1090
772
|
|
|
1091
|
-
//
|
|
773
|
+
// src/secret.ts
|
|
774
|
+
var SecretValue = class {
|
|
775
|
+
#value;
|
|
776
|
+
constructor(value) {
|
|
777
|
+
if (!value) {
|
|
778
|
+
throw new ProtocolValidationError("invalid_secret", "Secret value must not be empty");
|
|
779
|
+
}
|
|
780
|
+
this.#value = value;
|
|
781
|
+
}
|
|
782
|
+
reveal() {
|
|
783
|
+
return this.#value;
|
|
784
|
+
}
|
|
785
|
+
toString() {
|
|
786
|
+
return "[REDACTED]";
|
|
787
|
+
}
|
|
788
|
+
toJSON() {
|
|
789
|
+
return "[REDACTED]";
|
|
790
|
+
}
|
|
791
|
+
};
|
|
792
|
+
|
|
793
|
+
// node_modules/@datalayer/reactor/lib/core/contributions.js
|
|
1092
794
|
function defineContributionPoint(id) {
|
|
1093
795
|
if (!id) {
|
|
1094
796
|
throw new Error("defineContributionPoint: a contribution point needs an id");
|
|
@@ -1188,7 +890,7 @@ var ContributionRegistry = class {
|
|
|
1188
890
|
}
|
|
1189
891
|
};
|
|
1190
892
|
|
|
1191
|
-
//
|
|
893
|
+
// node_modules/@datalayer/reactor/lib/core/commands.js
|
|
1192
894
|
var CommandRegistry = class {
|
|
1193
895
|
byId = /* @__PURE__ */ new Map();
|
|
1194
896
|
byPlugin = /* @__PURE__ */ new Map();
|
|
@@ -1303,7 +1005,7 @@ var CommandRegistry = class {
|
|
|
1303
1005
|
}
|
|
1304
1006
|
};
|
|
1305
1007
|
|
|
1306
|
-
//
|
|
1008
|
+
// node_modules/@datalayer/reactor/lib/core/activation.js
|
|
1307
1009
|
var ON_STARTUP = "onStartup";
|
|
1308
1010
|
var ON_ANY = "*";
|
|
1309
1011
|
function onContributionPoint(point) {
|
|
@@ -1325,12 +1027,12 @@ function activatesAtStartup(declared) {
|
|
|
1325
1027
|
return matchesActivation(declared, ON_STARTUP);
|
|
1326
1028
|
}
|
|
1327
1029
|
|
|
1328
|
-
//
|
|
1030
|
+
// node_modules/@datalayer/reactor/lib/core/extension.js
|
|
1329
1031
|
function isExtension(ref) {
|
|
1330
1032
|
return typeof ref === "object" && ref !== null && typeof ref.name === "string" && Array.isArray(ref.plugins);
|
|
1331
1033
|
}
|
|
1332
1034
|
|
|
1333
|
-
//
|
|
1035
|
+
// node_modules/@datalayer/reactor/lib/core/gates.js
|
|
1334
1036
|
function isRefusal(answer) {
|
|
1335
1037
|
return answer !== true;
|
|
1336
1038
|
}
|
|
@@ -1356,7 +1058,7 @@ function resolveGate(answers, context) {
|
|
|
1356
1058
|
};
|
|
1357
1059
|
}
|
|
1358
1060
|
|
|
1359
|
-
//
|
|
1061
|
+
// node_modules/@datalayer/reactor/lib/core/reactor.js
|
|
1360
1062
|
function placeholderFor(ref) {
|
|
1361
1063
|
return {
|
|
1362
1064
|
name: ref.name,
|
|
@@ -2110,7 +1812,7 @@ function buildReactorFromPlugins(pluginsInput, options = {}) {
|
|
|
2110
1812
|
};
|
|
2111
1813
|
}
|
|
2112
1814
|
|
|
2113
|
-
//
|
|
1815
|
+
// node_modules/@datalayer/reactor/lib/core/plugin.js
|
|
2114
1816
|
function definePlugin(plugin) {
|
|
2115
1817
|
return plugin;
|
|
2116
1818
|
}
|
|
@@ -2131,7 +1833,7 @@ function mergeWithDefaults(plugin, override) {
|
|
|
2131
1833
|
return shallowMergeConfig(defaults, override);
|
|
2132
1834
|
}
|
|
2133
1835
|
|
|
2134
|
-
//
|
|
1836
|
+
// node_modules/@datalayer/reactor/lib/core/origins.js
|
|
2135
1837
|
var ANY_ORIGIN = "*";
|
|
2136
1838
|
var OriginNotAllowedError = class extends Error {
|
|
2137
1839
|
/** The URL that was refused, as it was written. */
|
|
@@ -2228,7 +1930,7 @@ function assertOriginAllowed(url, extra = [], what = "a remote") {
|
|
|
2228
1930
|
throw new OriginNotAllowedError(url, origin, what);
|
|
2229
1931
|
}
|
|
2230
1932
|
|
|
2231
|
-
//
|
|
1933
|
+
// node_modules/@datalayer/reactor/lib/core/federation.js
|
|
2232
1934
|
var runtimeOverride;
|
|
2233
1935
|
var runtimeLoad;
|
|
2234
1936
|
async function federationRuntime() {
|
|
@@ -2308,14 +2010,14 @@ function createFederationLoader() {
|
|
|
2308
2010
|
}
|
|
2309
2011
|
var federationLoader = createFederationLoader();
|
|
2310
2012
|
|
|
2311
|
-
//
|
|
2013
|
+
// node_modules/@datalayer/reactor/lib/core/remote.js
|
|
2312
2014
|
var SHARED_GLOBAL = "__DATALAYER_REACTOR__";
|
|
2313
2015
|
function getReactorSharedModules() {
|
|
2314
2016
|
const target = globalThis;
|
|
2315
2017
|
return target[SHARED_GLOBAL]?.shared ?? {};
|
|
2316
2018
|
}
|
|
2317
2019
|
|
|
2318
|
-
//
|
|
2020
|
+
// node_modules/@datalayer/reactor/lib/core/agentTools.js
|
|
2319
2021
|
var AgentTools = defineContributionPoint("reactor.agentTools");
|
|
2320
2022
|
|
|
2321
2023
|
// src/reactor.ts
|
|
@@ -2336,6 +2038,12 @@ var RandomSources = defineContributionPoint("pap.randomSource");
|
|
|
2336
2038
|
var Signers = defineContributionPoint("pap.signer");
|
|
2337
2039
|
var KeyStores = defineContributionPoint("pap.keyStore");
|
|
2338
2040
|
var TokenStores = defineContributionPoint("pap.tokenStore");
|
|
2041
|
+
var PairwiseUserIdStores = defineContributionPoint(
|
|
2042
|
+
"pap.pairwiseUserIdStore"
|
|
2043
|
+
);
|
|
2044
|
+
var AuthorizationStateStores = defineContributionPoint(
|
|
2045
|
+
"pap.authorizationStateStore"
|
|
2046
|
+
);
|
|
2339
2047
|
var Caches = defineContributionPoint("pap.cache");
|
|
2340
2048
|
var BrowserHandoffs = defineContributionPoint(
|
|
2341
2049
|
"pap.browserHandoff"
|
|
@@ -2371,7 +2079,7 @@ function createPapCorePlugin(options = {}) {
|
|
|
2371
2079
|
}
|
|
2372
2080
|
return definePlugin({
|
|
2373
2081
|
name: "@datalayer/personal-agent-protocol-core",
|
|
2374
|
-
version: "0.
|
|
2082
|
+
version: "0.3.1",
|
|
2375
2083
|
contributionPoints: [
|
|
2376
2084
|
DiscoveryTransports,
|
|
2377
2085
|
UrlSafetyPolicies,
|
|
@@ -2382,6 +2090,8 @@ function createPapCorePlugin(options = {}) {
|
|
|
2382
2090
|
Signers,
|
|
2383
2091
|
KeyStores,
|
|
2384
2092
|
TokenStores,
|
|
2093
|
+
PairwiseUserIdStores,
|
|
2094
|
+
AuthorizationStateStores,
|
|
2385
2095
|
Caches,
|
|
2386
2096
|
BrowserHandoffs,
|
|
2387
2097
|
DpopProofProviders
|
|
@@ -2428,24 +2138,6 @@ function firstContribution(reactor, point, label) {
|
|
|
2428
2138
|
// src/sessions.ts
|
|
2429
2139
|
var JWT_BEARER_GRANT = "urn:ietf:params:oauth:grant-type:jwt-bearer";
|
|
2430
2140
|
var JWT_CLIENT_ASSERTION = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer";
|
|
2431
|
-
var SecretValue = class {
|
|
2432
|
-
#value;
|
|
2433
|
-
constructor(value) {
|
|
2434
|
-
if (!value) {
|
|
2435
|
-
throw new ProtocolValidationError("invalid_secret", "Secret value must not be empty");
|
|
2436
|
-
}
|
|
2437
|
-
this.#value = value;
|
|
2438
|
-
}
|
|
2439
|
-
reveal() {
|
|
2440
|
-
return this.#value;
|
|
2441
|
-
}
|
|
2442
|
-
toString() {
|
|
2443
|
-
return "[REDACTED]";
|
|
2444
|
-
}
|
|
2445
|
-
toJSON() {
|
|
2446
|
-
return "[REDACTED]";
|
|
2447
|
-
}
|
|
2448
|
-
};
|
|
2449
2141
|
function defaultRandomBytes(length) {
|
|
2450
2142
|
const cryptoApi = globalThis.crypto;
|
|
2451
2143
|
if (!cryptoApi) {
|
|
@@ -2453,7 +2145,7 @@ function defaultRandomBytes(length) {
|
|
|
2453
2145
|
}
|
|
2454
2146
|
return cryptoApi.getRandomValues(new Uint8Array(length));
|
|
2455
2147
|
}
|
|
2456
|
-
function
|
|
2148
|
+
function base64Url2(bytes) {
|
|
2457
2149
|
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
|
2458
2150
|
let output = "";
|
|
2459
2151
|
for (let index = 0; index < bytes.length; index += 3) {
|
|
@@ -2476,11 +2168,19 @@ function opaqueId(prefix, randomBytes2) {
|
|
|
2476
2168
|
if (bytes.byteLength < 16) {
|
|
2477
2169
|
throw new Error("Opaque PAP identifiers require at least 128 random bits");
|
|
2478
2170
|
}
|
|
2479
|
-
return `${prefix}_${
|
|
2171
|
+
return `${prefix}_${base64Url2(bytes)}`;
|
|
2480
2172
|
}
|
|
2481
2173
|
function generatePairwiseUserId(randomBytes2 = defaultRandomBytes) {
|
|
2482
2174
|
return opaqueId("usr", randomBytes2);
|
|
2483
2175
|
}
|
|
2176
|
+
async function resolvePairwiseUserId(reactor, options) {
|
|
2177
|
+
const store = firstContribution(
|
|
2178
|
+
reactor,
|
|
2179
|
+
PairwiseUserIdStores,
|
|
2180
|
+
"pairwise user ID store"
|
|
2181
|
+
);
|
|
2182
|
+
return store.getOrCreate(options);
|
|
2183
|
+
}
|
|
2484
2184
|
function httpsUrl(value, label) {
|
|
2485
2185
|
let parsed;
|
|
2486
2186
|
try {
|
|
@@ -2758,209 +2458,37 @@ var SessionClient = class {
|
|
|
2758
2458
|
}
|
|
2759
2459
|
};
|
|
2760
2460
|
|
|
2761
|
-
// src/
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2461
|
+
// src/auth.ts
|
|
2462
|
+
function defaultRandomBytes2(length) {
|
|
2463
|
+
if (!globalThis.crypto) {
|
|
2464
|
+
throw new AuthorizationError("crypto_unavailable", "Web Crypto is required");
|
|
2465
|
+
}
|
|
2466
|
+
return globalThis.crypto.getRandomValues(new Uint8Array(length));
|
|
2467
|
+
}
|
|
2468
|
+
function entropy(length, randomBytes2) {
|
|
2469
|
+
const value = randomBytes2(length);
|
|
2470
|
+
if (value.byteLength < length) {
|
|
2471
|
+
throw new AuthorizationError(
|
|
2472
|
+
"weak_entropy",
|
|
2473
|
+
`Authorization requires ${length * 8} random bits`
|
|
2474
|
+
);
|
|
2766
2475
|
}
|
|
2767
2476
|
return value;
|
|
2768
2477
|
}
|
|
2769
|
-
function
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2478
|
+
function base64Url3(bytes) {
|
|
2479
|
+
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
|
2480
|
+
let output = "";
|
|
2481
|
+
for (let index = 0; index < bytes.length; index += 3) {
|
|
2482
|
+
const first = bytes[index] ?? 0;
|
|
2483
|
+
const second = bytes[index + 1];
|
|
2484
|
+
const third = bytes[index + 2];
|
|
2485
|
+
output += alphabet[first >>> 2];
|
|
2486
|
+
output += alphabet[(first & 3) << 4 | (second ?? 0) >>> 4];
|
|
2487
|
+
if (second !== void 0) {
|
|
2488
|
+
output += alphabet[(second & 15) << 2 | (third ?? 0) >>> 6];
|
|
2773
2489
|
}
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
if (value.kty !== expected) throw new TypeError(`${alg} requires a ${expected} public JWK`);
|
|
2777
|
-
if (alg === "ES256") {
|
|
2778
|
-
if (value.crv !== "P-256" || !value.x || !value.y) {
|
|
2779
|
-
throw new TypeError("ES256 requires a complete P-256 public JWK");
|
|
2780
|
-
}
|
|
2781
|
-
} else if (!value.n || !value.e) {
|
|
2782
|
-
throw new TypeError("RS256 requires a complete RSA public JWK");
|
|
2783
|
-
}
|
|
2784
|
-
return { ...value };
|
|
2785
|
-
}
|
|
2786
|
-
function normalizedHtu(value) {
|
|
2787
|
-
let url;
|
|
2788
|
-
try {
|
|
2789
|
-
url = new URL(value);
|
|
2790
|
-
} catch (cause) {
|
|
2791
|
-
throw new ProofError("invalid_htu", "DPoP target must be an HTTPS URL", { cause });
|
|
2792
|
-
}
|
|
2793
|
-
if (url.protocol !== "https:" || url.username || url.password) {
|
|
2794
|
-
throw new ProofError("invalid_htu", "DPoP target must be an HTTPS URL");
|
|
2795
|
-
}
|
|
2796
|
-
url.search = "";
|
|
2797
|
-
url.hash = "";
|
|
2798
|
-
return url.href;
|
|
2799
|
-
}
|
|
2800
|
-
function base64Url2(bytes) {
|
|
2801
|
-
let binary = "";
|
|
2802
|
-
for (const value of bytes) binary += String.fromCharCode(value);
|
|
2803
|
-
return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/u, "");
|
|
2804
|
-
}
|
|
2805
|
-
function randomBytes(length) {
|
|
2806
|
-
if (!globalThis.crypto) throw new ProofError("crypto_unavailable", "Web Crypto is required");
|
|
2807
|
-
return globalThis.crypto.getRandomValues(new Uint8Array(length));
|
|
2808
|
-
}
|
|
2809
|
-
async function accessTokenHash(token) {
|
|
2810
|
-
if (!globalThis.crypto) throw new ProofError("crypto_unavailable", "Web Crypto is required");
|
|
2811
|
-
const digest2 = await globalThis.crypto.subtle.digest(
|
|
2812
|
-
"SHA-256",
|
|
2813
|
-
new TextEncoder().encode(token.reveal())
|
|
2814
|
-
);
|
|
2815
|
-
return base64Url2(new Uint8Array(digest2));
|
|
2816
|
-
}
|
|
2817
|
-
var JoseSigner = class {
|
|
2818
|
-
#privateKey;
|
|
2819
|
-
#algorithm;
|
|
2820
|
-
#keyId;
|
|
2821
|
-
constructor(options) {
|
|
2822
|
-
this.#privateKey = options.privateKey;
|
|
2823
|
-
this.#algorithm = algorithm(options.algorithm ?? "ES256");
|
|
2824
|
-
this.#keyId = options.keyId;
|
|
2825
|
-
}
|
|
2826
|
-
async sign(claims, _options) {
|
|
2827
|
-
try {
|
|
2828
|
-
const token = await new SignJWT(claims).setProtectedHeader({
|
|
2829
|
-
alg: this.#algorithm,
|
|
2830
|
-
typ: "JWT",
|
|
2831
|
-
...this.#keyId === void 0 ? {} : { kid: this.#keyId }
|
|
2832
|
-
}).sign(this.#privateKey);
|
|
2833
|
-
return new SecretValue(token);
|
|
2834
|
-
} catch (cause) {
|
|
2835
|
-
throw new ProofError("signing_failed", "Could not sign PAP assertion", { cause });
|
|
2836
|
-
}
|
|
2837
|
-
}
|
|
2838
|
-
};
|
|
2839
|
-
var JoseDpopProofProvider = class {
|
|
2840
|
-
#resolveKey;
|
|
2841
|
-
#now;
|
|
2842
|
-
#randomBytes;
|
|
2843
|
-
constructor(options) {
|
|
2844
|
-
this.#resolveKey = options.resolveKey;
|
|
2845
|
-
this.#now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
2846
|
-
this.#randomBytes = options.randomBytes ?? randomBytes;
|
|
2847
|
-
}
|
|
2848
|
-
async create(request) {
|
|
2849
|
-
const material = await this.#resolveKey(request);
|
|
2850
|
-
const alg = algorithm(material.algorithm ?? "ES256");
|
|
2851
|
-
const jwk = publicJwk(material.publicJwk, alg);
|
|
2852
|
-
const entropy2 = this.#randomBytes(16);
|
|
2853
|
-
if (entropy2.byteLength < 16) {
|
|
2854
|
-
throw new ProofError("weak_randomness", "DPoP proof IDs require 128 random bits");
|
|
2855
|
-
}
|
|
2856
|
-
const claims = {
|
|
2857
|
-
jti: base64Url2(entropy2),
|
|
2858
|
-
htm: request.method.toUpperCase(),
|
|
2859
|
-
htu: normalizedHtu(request.url),
|
|
2860
|
-
iat: Math.floor(this.#now().getTime() / 1e3),
|
|
2861
|
-
...request.nonce === void 0 ? {} : { nonce: request.nonce },
|
|
2862
|
-
...request.accessToken === void 0 ? {} : { ath: await accessTokenHash(request.accessToken) }
|
|
2863
|
-
};
|
|
2864
|
-
try {
|
|
2865
|
-
const token = await new SignJWT(claims).setProtectedHeader({ typ: "dpop+jwt", alg, jwk }).sign(material.privateKey);
|
|
2866
|
-
return new SecretValue(token);
|
|
2867
|
-
} catch (cause) {
|
|
2868
|
-
throw new ProofError("signing_failed", "Could not sign DPoP proof", { cause });
|
|
2869
|
-
}
|
|
2870
|
-
}
|
|
2871
|
-
};
|
|
2872
|
-
async function verifyDpopProof(proof, options) {
|
|
2873
|
-
const compact = proof instanceof SecretValue ? proof.reveal() : proof;
|
|
2874
|
-
const now = options.now ?? /* @__PURE__ */ new Date();
|
|
2875
|
-
const windowSeconds = options.acceptanceWindowSeconds ?? 60;
|
|
2876
|
-
if (!Number.isInteger(windowSeconds) || windowSeconds <= 0) {
|
|
2877
|
-
throw new RangeError("acceptanceWindowSeconds must be a positive integer");
|
|
2878
|
-
}
|
|
2879
|
-
let jwk;
|
|
2880
|
-
let payload;
|
|
2881
|
-
try {
|
|
2882
|
-
const header = decodeProtectedHeader(compact);
|
|
2883
|
-
const alg = algorithm(header.alg ?? "");
|
|
2884
|
-
if (header.typ !== "dpop+jwt" || typeof header.jwk !== "object") {
|
|
2885
|
-
throw new ProofError("invalid_dpop_proof", "DPoP protected header is invalid");
|
|
2886
|
-
}
|
|
2887
|
-
jwk = publicJwk(header.jwk, alg);
|
|
2888
|
-
const key = await importJWK(jwk, alg);
|
|
2889
|
-
({ payload } = await jwtVerify(compact, key, {
|
|
2890
|
-
algorithms: [alg],
|
|
2891
|
-
typ: "dpop+jwt",
|
|
2892
|
-
requiredClaims: ["jti", "htm", "htu", "iat"]
|
|
2893
|
-
}));
|
|
2894
|
-
} catch (cause) {
|
|
2895
|
-
if (cause instanceof ProofError) throw cause;
|
|
2896
|
-
throw new ProofError("invalid_dpop_proof", "DPoP signature or claims are invalid", {
|
|
2897
|
-
cause
|
|
2898
|
-
});
|
|
2899
|
-
}
|
|
2900
|
-
if (typeof payload.jti !== "string" || !payload.jti || typeof payload.iat !== "number") {
|
|
2901
|
-
throw new ProofError("invalid_dpop_proof", "DPoP proof identity is invalid");
|
|
2902
|
-
}
|
|
2903
|
-
const issuedAt = new Date(payload.iat * 1e3);
|
|
2904
|
-
const difference = Math.abs(now.getTime() - issuedAt.getTime());
|
|
2905
|
-
if (difference > windowSeconds * 1e3) {
|
|
2906
|
-
throw new ProofError("invalid_dpop_proof", "DPoP proof is outside the acceptance window");
|
|
2907
|
-
}
|
|
2908
|
-
if (payload.htm !== options.method.toUpperCase() || payload.htu !== normalizedHtu(options.url)) {
|
|
2909
|
-
throw new ProofError("invalid_dpop_proof", "DPoP proof does not match the request");
|
|
2910
|
-
}
|
|
2911
|
-
if (options.nonce !== void 0 && payload.nonce !== options.nonce) {
|
|
2912
|
-
throw new ProofError("use_dpop_nonce", "DPoP proof nonce is missing or invalid");
|
|
2913
|
-
}
|
|
2914
|
-
if (options.accessToken !== void 0) {
|
|
2915
|
-
if (payload.ath !== await accessTokenHash(options.accessToken)) {
|
|
2916
|
-
throw new ProofError("invalid_dpop_proof", "DPoP access-token hash is invalid");
|
|
2917
|
-
}
|
|
2918
|
-
} else if (payload.ath !== void 0) {
|
|
2919
|
-
throw new ProofError(
|
|
2920
|
-
"invalid_dpop_proof",
|
|
2921
|
-
"Token-endpoint DPoP proof must not contain ath"
|
|
2922
|
-
);
|
|
2923
|
-
}
|
|
2924
|
-
const keyThumbprint = await calculateJwkThumbprint(jwk);
|
|
2925
|
-
if (!await options.replayCache.markOnce(`${keyThumbprint}:${payload.jti}`, {
|
|
2926
|
-
expiresAt: new Date(now.getTime() + windowSeconds * 1e3)
|
|
2927
|
-
})) {
|
|
2928
|
-
throw new ProofError("invalid_dpop_proof", "DPoP proof has already been used");
|
|
2929
|
-
}
|
|
2930
|
-
return { jti: payload.jti, issuedAt, publicJwk: jwk, keyThumbprint };
|
|
2931
|
-
}
|
|
2932
|
-
|
|
2933
|
-
// src/auth.ts
|
|
2934
|
-
function defaultRandomBytes2(length) {
|
|
2935
|
-
if (!globalThis.crypto) {
|
|
2936
|
-
throw new AuthorizationError("crypto_unavailable", "Web Crypto is required");
|
|
2937
|
-
}
|
|
2938
|
-
return globalThis.crypto.getRandomValues(new Uint8Array(length));
|
|
2939
|
-
}
|
|
2940
|
-
function entropy(length, randomBytes2) {
|
|
2941
|
-
const value = randomBytes2(length);
|
|
2942
|
-
if (value.byteLength < length) {
|
|
2943
|
-
throw new AuthorizationError(
|
|
2944
|
-
"weak_entropy",
|
|
2945
|
-
`Authorization requires ${length * 8} random bits`
|
|
2946
|
-
);
|
|
2947
|
-
}
|
|
2948
|
-
return value;
|
|
2949
|
-
}
|
|
2950
|
-
function base64Url3(bytes) {
|
|
2951
|
-
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
|
2952
|
-
let output = "";
|
|
2953
|
-
for (let index = 0; index < bytes.length; index += 3) {
|
|
2954
|
-
const first = bytes[index] ?? 0;
|
|
2955
|
-
const second = bytes[index + 1];
|
|
2956
|
-
const third = bytes[index + 2];
|
|
2957
|
-
output += alphabet[first >>> 2];
|
|
2958
|
-
output += alphabet[(first & 3) << 4 | (second ?? 0) >>> 4];
|
|
2959
|
-
if (second !== void 0) {
|
|
2960
|
-
output += alphabet[(second & 15) << 2 | (third ?? 0) >>> 6];
|
|
2961
|
-
}
|
|
2962
|
-
if (third !== void 0) {
|
|
2963
|
-
output += alphabet[third & 63];
|
|
2490
|
+
if (third !== void 0) {
|
|
2491
|
+
output += alphabet[third & 63];
|
|
2964
2492
|
}
|
|
2965
2493
|
}
|
|
2966
2494
|
return output;
|
|
@@ -2989,8 +2517,12 @@ async function buildDirectSignInRequest(options) {
|
|
|
2989
2517
|
const randomBytes2 = options.randomBytes ?? defaultRandomBytes2;
|
|
2990
2518
|
const state = base64Url3(entropy(16, randomBytes2));
|
|
2991
2519
|
const verifier = base64Url3(entropy(32, randomBytes2));
|
|
2520
|
+
const cryptoApi = globalThis.crypto;
|
|
2521
|
+
if (!cryptoApi) {
|
|
2522
|
+
throw new AuthorizationError("crypto_unavailable", "Web Crypto is required");
|
|
2523
|
+
}
|
|
2992
2524
|
const challenge = base64Url3(
|
|
2993
|
-
new Uint8Array(await
|
|
2525
|
+
new Uint8Array(await cryptoApi.subtle.digest("SHA-256", new TextEncoder().encode(verifier)))
|
|
2994
2526
|
);
|
|
2995
2527
|
const endpoint = httpsUrl2(options.authorizationEndpoint, "authorizationEndpoint");
|
|
2996
2528
|
const scopes2 = validScopes(options.scopes);
|
|
@@ -3106,6 +2638,276 @@ var AuthorizationCodeGrant = class {
|
|
|
3106
2638
|
};
|
|
3107
2639
|
}
|
|
3108
2640
|
};
|
|
2641
|
+
async function stateReference(state) {
|
|
2642
|
+
const bytes = new TextEncoder().encode(state);
|
|
2643
|
+
if ([...bytes].some((byte) => byte > 127)) {
|
|
2644
|
+
throw new AuthorizationError("invalid_callback", "Authorization state is invalid");
|
|
2645
|
+
}
|
|
2646
|
+
const cryptoApi = globalThis.crypto;
|
|
2647
|
+
if (!cryptoApi) {
|
|
2648
|
+
throw new AuthorizationError("crypto_unavailable", "Web Crypto is required");
|
|
2649
|
+
}
|
|
2650
|
+
const digest = await cryptoApi.subtle.digest("SHA-256", bytes);
|
|
2651
|
+
return `direct:${Array.from(
|
|
2652
|
+
new Uint8Array(digest),
|
|
2653
|
+
(byte) => byte.toString(16).padStart(2, "0")
|
|
2654
|
+
).join("")}`;
|
|
2655
|
+
}
|
|
2656
|
+
function callbackState(callbackUrl) {
|
|
2657
|
+
const callback = httpsUrl2(callbackUrl, "callbackUrl");
|
|
2658
|
+
if (callback.hash) {
|
|
2659
|
+
throw new AuthorizationError("invalid_callback", "Authorization callback has a fragment");
|
|
2660
|
+
}
|
|
2661
|
+
const states = callback.searchParams.getAll("state");
|
|
2662
|
+
if (states.length !== 1 || !states[0]) {
|
|
2663
|
+
throw new AuthorizationError(
|
|
2664
|
+
"invalid_callback",
|
|
2665
|
+
"Authorization callback must contain one state value"
|
|
2666
|
+
);
|
|
2667
|
+
}
|
|
2668
|
+
return states[0];
|
|
2669
|
+
}
|
|
2670
|
+
function isPendingDirectSignIn(value) {
|
|
2671
|
+
if (typeof value !== "object" || value === null) return false;
|
|
2672
|
+
const pending = value;
|
|
2673
|
+
return pending.kind === "pap.direct-sign-in.v1" && typeof pending.tokenEndpoint === "string" && typeof pending.tenantId === "string" && typeof pending.pairwiseUserId === "string" && typeof pending.sessionId === "string" && pending.expiresAt instanceof Date && typeof pending.request === "object" && pending.request !== null;
|
|
2674
|
+
}
|
|
2675
|
+
var DirectSignInClient = class {
|
|
2676
|
+
#reactor;
|
|
2677
|
+
#fetch;
|
|
2678
|
+
#maxResponseBytes;
|
|
2679
|
+
constructor(options) {
|
|
2680
|
+
const fetcher = options.fetch ?? globalThis.fetch;
|
|
2681
|
+
if (!fetcher) {
|
|
2682
|
+
throw new AuthorizationError("fetch_unavailable", "A fetch implementation is required");
|
|
2683
|
+
}
|
|
2684
|
+
const maxResponseBytes = options.maxResponseBytes ?? 100 * 1024;
|
|
2685
|
+
if (!Number.isInteger(maxResponseBytes) || maxResponseBytes <= 0) {
|
|
2686
|
+
throw new RangeError("maxResponseBytes must be a positive integer");
|
|
2687
|
+
}
|
|
2688
|
+
this.#reactor = options.reactor;
|
|
2689
|
+
this.#fetch = fetcher;
|
|
2690
|
+
this.#maxResponseBytes = maxResponseBytes;
|
|
2691
|
+
}
|
|
2692
|
+
async begin(options) {
|
|
2693
|
+
const lifetimeSeconds = options.lifetimeSeconds ?? 600;
|
|
2694
|
+
if (!Number.isInteger(lifetimeSeconds) || lifetimeSeconds < 1 || lifetimeSeconds > 900) {
|
|
2695
|
+
throw new RangeError("Direct Sign-In state lifetime must be between 1 and 900 seconds");
|
|
2696
|
+
}
|
|
2697
|
+
if (!options.tenantId || options.tenantId.length > 256) {
|
|
2698
|
+
throw new RangeError("tenantId must contain between 1 and 256 characters");
|
|
2699
|
+
}
|
|
2700
|
+
if (!/^[A-Za-z0-9_-]{1,256}$/.test(options.pairwiseUserId)) {
|
|
2701
|
+
throw new AuthorizationError(
|
|
2702
|
+
"invalid_user_id",
|
|
2703
|
+
"Pairwise user ID must be an opaque URL-safe identifier"
|
|
2704
|
+
);
|
|
2705
|
+
}
|
|
2706
|
+
if (!/^[A-Za-z0-9_-]{1,256}$/.test(options.sessionId)) {
|
|
2707
|
+
throw new AuthorizationError("invalid_session_id", "Invalid PAP session ID");
|
|
2708
|
+
}
|
|
2709
|
+
const clock = firstContribution(this.#reactor, Clocks, "clock");
|
|
2710
|
+
const random = firstContribution(this.#reactor, RandomSources, "random source");
|
|
2711
|
+
const store = firstContribution(
|
|
2712
|
+
this.#reactor,
|
|
2713
|
+
AuthorizationStateStores,
|
|
2714
|
+
"authorization state store"
|
|
2715
|
+
);
|
|
2716
|
+
const browser = firstContribution(this.#reactor, BrowserHandoffs, "browser handoff");
|
|
2717
|
+
const request = await buildDirectSignInRequest({
|
|
2718
|
+
authorizationEndpoint: options.authorizationEndpoint,
|
|
2719
|
+
issuer: options.issuer,
|
|
2720
|
+
clientId: options.clientId,
|
|
2721
|
+
redirectUri: options.redirectUri,
|
|
2722
|
+
scopes: options.scopes,
|
|
2723
|
+
randomBytes: (length) => random.bytes(length)
|
|
2724
|
+
});
|
|
2725
|
+
const tokenEndpoint = httpsUrl2(options.tokenEndpoint, "tokenEndpoint").toString();
|
|
2726
|
+
const expiresAt = new Date(clock.now().getTime() + lifetimeSeconds * 1e3);
|
|
2727
|
+
const reference = await stateReference(request.state.reveal());
|
|
2728
|
+
const pending = {
|
|
2729
|
+
kind: "pap.direct-sign-in.v1",
|
|
2730
|
+
request,
|
|
2731
|
+
tokenEndpoint,
|
|
2732
|
+
tenantId: options.tenantId,
|
|
2733
|
+
pairwiseUserId: options.pairwiseUserId,
|
|
2734
|
+
sessionId: options.sessionId,
|
|
2735
|
+
expiresAt
|
|
2736
|
+
};
|
|
2737
|
+
await store.put(reference, pending, { expiresAt });
|
|
2738
|
+
try {
|
|
2739
|
+
await browser.open(request.authorizationUrl);
|
|
2740
|
+
} catch (cause) {
|
|
2741
|
+
await store.take(reference);
|
|
2742
|
+
throw new AuthorizationError("browser_handoff_failed", "Browser handoff failed", { cause });
|
|
2743
|
+
}
|
|
2744
|
+
return { expiresAt, requestedScopes: request.scopes };
|
|
2745
|
+
}
|
|
2746
|
+
async complete(options) {
|
|
2747
|
+
const state = callbackState(options.callbackUrl);
|
|
2748
|
+
const store = firstContribution(
|
|
2749
|
+
this.#reactor,
|
|
2750
|
+
AuthorizationStateStores,
|
|
2751
|
+
"authorization state store"
|
|
2752
|
+
);
|
|
2753
|
+
const pending = await store.take(await stateReference(state));
|
|
2754
|
+
if (!isPendingDirectSignIn(pending)) {
|
|
2755
|
+
throw new AuthorizationError(
|
|
2756
|
+
"invalid_or_expired_state",
|
|
2757
|
+
"Authorization state is unknown, expired, or already used"
|
|
2758
|
+
);
|
|
2759
|
+
}
|
|
2760
|
+
const clock = firstContribution(this.#reactor, Clocks, "clock");
|
|
2761
|
+
if (clock.now().getTime() > pending.expiresAt.getTime()) {
|
|
2762
|
+
throw new AuthorizationError("invalid_or_expired_state", "Authorization state has expired");
|
|
2763
|
+
}
|
|
2764
|
+
const callback = validateDirectSignInCallback(pending.request, options.callbackUrl);
|
|
2765
|
+
return this.#exchange(pending, callback, options.signal);
|
|
2766
|
+
}
|
|
2767
|
+
async #exchange(pending, callback, signal) {
|
|
2768
|
+
const clock = firstContribution(this.#reactor, Clocks, "clock");
|
|
2769
|
+
const random = firstContribution(this.#reactor, RandomSources, "random source");
|
|
2770
|
+
const signer = firstContribution(this.#reactor, Signers, "signer");
|
|
2771
|
+
const dpop = firstContribution(
|
|
2772
|
+
this.#reactor,
|
|
2773
|
+
DpopProofProviders,
|
|
2774
|
+
"DPoP proof provider"
|
|
2775
|
+
);
|
|
2776
|
+
let nonce;
|
|
2777
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
2778
|
+
const iat = Math.floor(clock.now().getTime() / 1e3);
|
|
2779
|
+
const clientAssertion = await signer.sign(
|
|
2780
|
+
{
|
|
2781
|
+
iss: pending.request.clientId,
|
|
2782
|
+
sub: pending.request.clientId,
|
|
2783
|
+
aud: pending.tokenEndpoint,
|
|
2784
|
+
iat,
|
|
2785
|
+
exp: iat + 60,
|
|
2786
|
+
jti: `jti_${base64Url3(entropy(16, (length) => random.bytes(length)))}`
|
|
2787
|
+
},
|
|
2788
|
+
{ purpose: "client_assertion" }
|
|
2789
|
+
);
|
|
2790
|
+
const proof = await dpop.create({
|
|
2791
|
+
method: "POST",
|
|
2792
|
+
url: pending.tokenEndpoint,
|
|
2793
|
+
tenantId: pending.tenantId,
|
|
2794
|
+
subject: pending.pairwiseUserId,
|
|
2795
|
+
issuer: pending.request.issuer,
|
|
2796
|
+
...nonce === void 0 ? {} : { nonce }
|
|
2797
|
+
});
|
|
2798
|
+
const grant = new AuthorizationCodeGrant({
|
|
2799
|
+
code: callback.code.reveal(),
|
|
2800
|
+
redirectUri: pending.request.redirectUri,
|
|
2801
|
+
codeVerifier: pending.request.codeVerifier.reveal(),
|
|
2802
|
+
sessionId: pending.sessionId,
|
|
2803
|
+
clientId: pending.request.clientId,
|
|
2804
|
+
clientAssertion: clientAssertion.reveal()
|
|
2805
|
+
});
|
|
2806
|
+
let response;
|
|
2807
|
+
try {
|
|
2808
|
+
response = await this.#fetch(pending.tokenEndpoint, {
|
|
2809
|
+
method: "POST",
|
|
2810
|
+
headers: { Accept: "application/json", DPoP: proof.reveal() },
|
|
2811
|
+
body: grant.toForm(),
|
|
2812
|
+
credentials: "omit",
|
|
2813
|
+
redirect: "error",
|
|
2814
|
+
...signal === void 0 ? {} : { signal }
|
|
2815
|
+
});
|
|
2816
|
+
} catch (cause) {
|
|
2817
|
+
throw new AuthorizationError(
|
|
2818
|
+
"request_failed",
|
|
2819
|
+
"Direct Sign-In token exchange failed",
|
|
2820
|
+
{ cause }
|
|
2821
|
+
);
|
|
2822
|
+
}
|
|
2823
|
+
const payload = await this.#decode(response);
|
|
2824
|
+
if (response.ok) return this.#result(response, payload, pending);
|
|
2825
|
+
const source = typeof payload === "object" && payload !== null ? payload : {};
|
|
2826
|
+
const remoteCode = "error" in source ? source.error : void 0;
|
|
2827
|
+
const code = typeof remoteCode === "string" ? remoteCode : "http_error";
|
|
2828
|
+
if (code === "use_dpop_nonce" && attempt === 0) {
|
|
2829
|
+
nonce = response.headers.get("dpop-nonce") ?? void 0;
|
|
2830
|
+
if (!nonce) {
|
|
2831
|
+
throw new AuthorizationError(
|
|
2832
|
+
"missing_dpop_nonce",
|
|
2833
|
+
"Company requested a DPoP nonce but did not send one",
|
|
2834
|
+
{ statusCode: response.status }
|
|
2835
|
+
);
|
|
2836
|
+
}
|
|
2837
|
+
continue;
|
|
2838
|
+
}
|
|
2839
|
+
throw new AuthorizationError(code, "Company refused the Direct Sign-In token exchange", {
|
|
2840
|
+
statusCode: response.status
|
|
2841
|
+
});
|
|
2842
|
+
}
|
|
2843
|
+
throw new AuthorizationError("use_dpop_nonce", "Company rejected the refreshed DPoP proof");
|
|
2844
|
+
}
|
|
2845
|
+
async #decode(response) {
|
|
2846
|
+
const contentType = response.headers.get("content-type")?.split(";", 1)[0]?.trim();
|
|
2847
|
+
if (contentType !== "application/json") {
|
|
2848
|
+
throw new AuthorizationError(
|
|
2849
|
+
"invalid_content_type",
|
|
2850
|
+
"Direct Sign-In token endpoint must return JSON",
|
|
2851
|
+
{ statusCode: response.status }
|
|
2852
|
+
);
|
|
2853
|
+
}
|
|
2854
|
+
const body = await response.text();
|
|
2855
|
+
if (new TextEncoder().encode(body).byteLength > this.#maxResponseBytes) {
|
|
2856
|
+
throw new AuthorizationError(
|
|
2857
|
+
"response_too_large",
|
|
2858
|
+
"Direct Sign-In response exceeds size limit",
|
|
2859
|
+
{ statusCode: response.status }
|
|
2860
|
+
);
|
|
2861
|
+
}
|
|
2862
|
+
try {
|
|
2863
|
+
return parseJsonStrict(body);
|
|
2864
|
+
} catch (cause) {
|
|
2865
|
+
throw new AuthorizationError(
|
|
2866
|
+
"invalid_json",
|
|
2867
|
+
"Direct Sign-In token endpoint returned invalid JSON",
|
|
2868
|
+
{ statusCode: response.status, cause }
|
|
2869
|
+
);
|
|
2870
|
+
}
|
|
2871
|
+
}
|
|
2872
|
+
#result(response, payload, pending) {
|
|
2873
|
+
let token;
|
|
2874
|
+
try {
|
|
2875
|
+
token = parseSessionToken(payload);
|
|
2876
|
+
} catch (cause) {
|
|
2877
|
+
throw new AuthorizationError(
|
|
2878
|
+
"invalid_token_response",
|
|
2879
|
+
"Direct Sign-In token response is malformed",
|
|
2880
|
+
{ statusCode: response.status, cause }
|
|
2881
|
+
);
|
|
2882
|
+
}
|
|
2883
|
+
if (token.tokenType !== "DPoP" || !token.signedIn) {
|
|
2884
|
+
throw new AuthorizationError(
|
|
2885
|
+
"invalid_token_response",
|
|
2886
|
+
"Direct Sign-In must return a signed-in DPoP Session Token",
|
|
2887
|
+
{ statusCode: response.status }
|
|
2888
|
+
);
|
|
2889
|
+
}
|
|
2890
|
+
if (token.sessionId !== pending.sessionId) {
|
|
2891
|
+
throw new AuthorizationError(
|
|
2892
|
+
"session_mismatch",
|
|
2893
|
+
"Direct Sign-In response changed the existing Session",
|
|
2894
|
+
{ statusCode: response.status }
|
|
2895
|
+
);
|
|
2896
|
+
}
|
|
2897
|
+
if (token.scopes.some((scope) => !pending.request.scopes.includes(scope))) {
|
|
2898
|
+
throw new AuthorizationError(
|
|
2899
|
+
"scope_escalation",
|
|
2900
|
+
"Company returned a scope that was not requested",
|
|
2901
|
+
{ statusCode: response.status }
|
|
2902
|
+
);
|
|
2903
|
+
}
|
|
2904
|
+
return {
|
|
2905
|
+
token,
|
|
2906
|
+
grantedScopes: token.scopes,
|
|
2907
|
+
missingScopes: pending.request.scopes.filter((scope) => !token.scopes.includes(scope))
|
|
2908
|
+
};
|
|
2909
|
+
}
|
|
2910
|
+
};
|
|
3109
2911
|
|
|
3110
2912
|
// src/models.ts
|
|
3111
2913
|
function record(value, label) {
|
|
@@ -3421,6 +3223,66 @@ function parseClientMetadata(value) {
|
|
|
3421
3223
|
extensions: extensions(source.extensions, "extensions")
|
|
3422
3224
|
};
|
|
3423
3225
|
}
|
|
3226
|
+
var privateJwkMembers2 = /* @__PURE__ */ new Set(["d", "p", "q", "dp", "dq", "qi", "oth", "k"]);
|
|
3227
|
+
function parseJsonWebKey(value) {
|
|
3228
|
+
const source = record(value, "JWKS key");
|
|
3229
|
+
if (Object.keys(source).some((key) => privateJwkMembers2.has(key))) {
|
|
3230
|
+
throw new ProtocolValidationError(
|
|
3231
|
+
"private_jwk",
|
|
3232
|
+
"JWKS keys must not contain private or symmetric key material"
|
|
3233
|
+
);
|
|
3234
|
+
}
|
|
3235
|
+
const kty = oneOf(source.kty, ["EC", "RSA"], "JWKS key kty");
|
|
3236
|
+
const kid = source.kid === void 0 ? void 0 : string(source.kid, "JWKS key kid");
|
|
3237
|
+
const use = source.use === void 0 ? void 0 : oneOf(source.use, ["sig"], "use");
|
|
3238
|
+
const alg = source.alg === void 0 ? void 0 : oneOf(source.alg, ["ES256", "RS256"], "alg");
|
|
3239
|
+
if (kty === "EC") {
|
|
3240
|
+
const crv = oneOf(source.crv, ["P-256"], "EC key crv");
|
|
3241
|
+
const x = string(source.x, "EC key x");
|
|
3242
|
+
const y = string(source.y, "EC key y");
|
|
3243
|
+
if (alg !== void 0 && alg !== "ES256") {
|
|
3244
|
+
throw new ProtocolValidationError(
|
|
3245
|
+
"invalid_jwk_algorithm",
|
|
3246
|
+
"P-256 signing keys may advertise only ES256"
|
|
3247
|
+
);
|
|
3248
|
+
}
|
|
3249
|
+
return {
|
|
3250
|
+
...source,
|
|
3251
|
+
kty,
|
|
3252
|
+
...kid === void 0 ? {} : { kid },
|
|
3253
|
+
...use === void 0 ? {} : { use },
|
|
3254
|
+
...alg === void 0 ? {} : { alg },
|
|
3255
|
+
crv,
|
|
3256
|
+
x,
|
|
3257
|
+
y
|
|
3258
|
+
};
|
|
3259
|
+
}
|
|
3260
|
+
const n = string(source.n, "RSA key n");
|
|
3261
|
+
const e = string(source.e, "RSA key e");
|
|
3262
|
+
if (alg !== void 0 && alg !== "RS256") {
|
|
3263
|
+
throw new ProtocolValidationError(
|
|
3264
|
+
"invalid_jwk_algorithm",
|
|
3265
|
+
"RSA signing keys may advertise only RS256"
|
|
3266
|
+
);
|
|
3267
|
+
}
|
|
3268
|
+
return {
|
|
3269
|
+
...source,
|
|
3270
|
+
kty,
|
|
3271
|
+
...kid === void 0 ? {} : { kid },
|
|
3272
|
+
...use === void 0 ? {} : { use },
|
|
3273
|
+
...alg === void 0 ? {} : { alg },
|
|
3274
|
+
n,
|
|
3275
|
+
e
|
|
3276
|
+
};
|
|
3277
|
+
}
|
|
3278
|
+
function parseJsonWebKeySet(value) {
|
|
3279
|
+
const source = record(value, "JWKS");
|
|
3280
|
+
const keys = array(source.keys, "JWKS keys").map(parseJsonWebKey);
|
|
3281
|
+
if (keys.length === 0) {
|
|
3282
|
+
throw new ProtocolValidationError("invalid_jwks", "JWKS keys must not be empty");
|
|
3283
|
+
}
|
|
3284
|
+
return { ...source, keys };
|
|
3285
|
+
}
|
|
3424
3286
|
function parseOperation(value) {
|
|
3425
3287
|
const source = record(value, "operation");
|
|
3426
3288
|
const state = oneOf(
|
|
@@ -3623,7 +3485,7 @@ function metadataUrl(issuer) {
|
|
|
3623
3485
|
parsed.hash = "";
|
|
3624
3486
|
return parsed;
|
|
3625
3487
|
}
|
|
3626
|
-
async function readJson(initialUrl, transport, urlPolicy, maxRedirects, maxResponseBytes) {
|
|
3488
|
+
async function readJson(initialUrl, transport, urlPolicy, maxRedirects, maxResponseBytes, signal) {
|
|
3627
3489
|
let current = initialUrl;
|
|
3628
3490
|
for (let redirects = 0; redirects <= maxRedirects; redirects += 1) {
|
|
3629
3491
|
await urlPolicy.assertSafe(current);
|
|
@@ -3632,7 +3494,8 @@ async function readJson(initialUrl, transport, urlPolicy, maxRedirects, maxRespo
|
|
|
3632
3494
|
response = await transport.fetch(current, {
|
|
3633
3495
|
headers: { Accept: "application/json" },
|
|
3634
3496
|
redirect: "manual",
|
|
3635
|
-
credentials: "omit"
|
|
3497
|
+
credentials: "omit",
|
|
3498
|
+
...signal === void 0 ? {} : { signal }
|
|
3636
3499
|
});
|
|
3637
3500
|
} catch (cause) {
|
|
3638
3501
|
throw new DiscoveryError("request_failed", "Discovery request failed", { cause });
|
|
@@ -3694,7 +3557,8 @@ async function discoverCompany(domain2, options = {}) {
|
|
|
3694
3557
|
transport,
|
|
3695
3558
|
urlPolicy,
|
|
3696
3559
|
maxRedirects,
|
|
3697
|
-
maxBytes
|
|
3560
|
+
maxBytes,
|
|
3561
|
+
options.signal
|
|
3698
3562
|
);
|
|
3699
3563
|
const document = parseDiscoveryDocument(discovery.value);
|
|
3700
3564
|
if (document.organization.domain.replace(/^www\./, "") !== requestedDomain.replace(/^www\./, "")) {
|
|
@@ -3711,7 +3575,8 @@ async function discoverCompany(domain2, options = {}) {
|
|
|
3711
3575
|
transport,
|
|
3712
3576
|
urlPolicy,
|
|
3713
3577
|
maxRedirects,
|
|
3714
|
-
maxBytes
|
|
3578
|
+
maxBytes,
|
|
3579
|
+
options.signal
|
|
3715
3580
|
);
|
|
3716
3581
|
const oauthMetadata = parseOAuthServerMetadata(metadataResponse.value);
|
|
3717
3582
|
if (oauthMetadata.issuer !== document.auth.issuer) {
|
|
@@ -3729,21 +3594,166 @@ async function discoverCompany(domain2, options = {}) {
|
|
|
3729
3594
|
oauthMetadata
|
|
3730
3595
|
};
|
|
3731
3596
|
}
|
|
3597
|
+
|
|
3598
|
+
// src/identity.ts
|
|
3599
|
+
var AgentIdentityClient = class {
|
|
3600
|
+
#reactor;
|
|
3601
|
+
#maxJwksRedirects;
|
|
3602
|
+
#maxResponseBytes;
|
|
3603
|
+
constructor(options = {}) {
|
|
3604
|
+
const maxRedirects = options.maxJwksRedirects ?? 3;
|
|
3605
|
+
const maxBytes = options.maxResponseBytes ?? 100 * 1024;
|
|
3606
|
+
if (!Number.isInteger(maxRedirects) || maxRedirects < 0) {
|
|
3607
|
+
throw new RangeError("maxJwksRedirects must be a non-negative integer");
|
|
3608
|
+
}
|
|
3609
|
+
if (!Number.isInteger(maxBytes) || maxBytes <= 0) {
|
|
3610
|
+
throw new RangeError("maxResponseBytes must be a positive integer");
|
|
3611
|
+
}
|
|
3612
|
+
this.#reactor = options.reactor ?? buildPapReactor(options);
|
|
3613
|
+
this.#maxJwksRedirects = maxRedirects;
|
|
3614
|
+
this.#maxResponseBytes = maxBytes;
|
|
3615
|
+
}
|
|
3616
|
+
async fetchMetadata(clientId, options = {}) {
|
|
3617
|
+
const requested = this.#clientIdUrl(clientId);
|
|
3618
|
+
const value = await this.#readJson(requested, 0, void 0, options.signal);
|
|
3619
|
+
let metadata;
|
|
3620
|
+
try {
|
|
3621
|
+
metadata = parseClientMetadata(value);
|
|
3622
|
+
} catch (cause) {
|
|
3623
|
+
throw new ProtocolValidationError(
|
|
3624
|
+
"invalid_client_metadata",
|
|
3625
|
+
"Client metadata failed protocol validation",
|
|
3626
|
+
{ cause }
|
|
3627
|
+
);
|
|
3628
|
+
}
|
|
3629
|
+
if (metadata.client_id !== requested.toString()) {
|
|
3630
|
+
throw new IdentityError(
|
|
3631
|
+
"client_id_mismatch",
|
|
3632
|
+
"Client metadata client_id does not match the URL that was fetched"
|
|
3633
|
+
);
|
|
3634
|
+
}
|
|
3635
|
+
return metadata;
|
|
3636
|
+
}
|
|
3637
|
+
async fetchJwks(clientId, options = {}) {
|
|
3638
|
+
const metadata = await this.fetchMetadata(clientId, options);
|
|
3639
|
+
const jwksUrl = new URL(metadata.jwks_uri);
|
|
3640
|
+
const value = await this.#readJson(
|
|
3641
|
+
jwksUrl,
|
|
3642
|
+
this.#maxJwksRedirects,
|
|
3643
|
+
new URL(metadata.client_id).hostname,
|
|
3644
|
+
options.signal
|
|
3645
|
+
);
|
|
3646
|
+
try {
|
|
3647
|
+
return parseJsonWebKeySet(value);
|
|
3648
|
+
} catch (cause) {
|
|
3649
|
+
throw new ProtocolValidationError(
|
|
3650
|
+
"invalid_jwks",
|
|
3651
|
+
"Personal-agent JWKS failed protocol validation",
|
|
3652
|
+
{ cause }
|
|
3653
|
+
);
|
|
3654
|
+
}
|
|
3655
|
+
}
|
|
3656
|
+
#clientIdUrl(clientId) {
|
|
3657
|
+
let requested;
|
|
3658
|
+
try {
|
|
3659
|
+
requested = new URL(clientId);
|
|
3660
|
+
} catch (cause) {
|
|
3661
|
+
throw new IdentityError(
|
|
3662
|
+
"invalid_client_id",
|
|
3663
|
+
"client_id must be a valid HTTPS URL",
|
|
3664
|
+
{ cause }
|
|
3665
|
+
);
|
|
3666
|
+
}
|
|
3667
|
+
if (requested.hash) {
|
|
3668
|
+
throw new IdentityError("invalid_client_id", "client_id must not contain a fragment");
|
|
3669
|
+
}
|
|
3670
|
+
return requested;
|
|
3671
|
+
}
|
|
3672
|
+
async #readJson(initialUrl, maxRedirects, requiredHost, signal) {
|
|
3673
|
+
const transport = firstContribution(
|
|
3674
|
+
this.#reactor,
|
|
3675
|
+
DiscoveryTransports,
|
|
3676
|
+
"metadata transport"
|
|
3677
|
+
);
|
|
3678
|
+
const policy2 = firstContribution(
|
|
3679
|
+
this.#reactor,
|
|
3680
|
+
UrlSafetyPolicies,
|
|
3681
|
+
"URL safety policy"
|
|
3682
|
+
);
|
|
3683
|
+
let current = initialUrl;
|
|
3684
|
+
for (let redirects = 0; redirects <= maxRedirects; redirects += 1) {
|
|
3685
|
+
if (requiredHost !== void 0 && current.hostname !== requiredHost) {
|
|
3686
|
+
throw new IdentityError("jwks_domain_mismatch", "JWKS redirect changed agent domain");
|
|
3687
|
+
}
|
|
3688
|
+
await policy2.assertSafe(current);
|
|
3689
|
+
let response;
|
|
3690
|
+
try {
|
|
3691
|
+
response = await transport.fetch(current, {
|
|
3692
|
+
headers: { Accept: "application/json" },
|
|
3693
|
+
redirect: "manual",
|
|
3694
|
+
credentials: "omit",
|
|
3695
|
+
...signal === void 0 ? {} : { signal }
|
|
3696
|
+
});
|
|
3697
|
+
} catch (cause) {
|
|
3698
|
+
throw new IdentityError("request_failed", "Agent identity request failed", { cause });
|
|
3699
|
+
}
|
|
3700
|
+
if (response.status >= 300 && response.status < 400) {
|
|
3701
|
+
if (redirects === maxRedirects) {
|
|
3702
|
+
const code = maxRedirects === 0 ? "metadata_redirect" : "too_many_redirects";
|
|
3703
|
+
throw new IdentityError(code, "Agent identity endpoint exceeded redirect policy");
|
|
3704
|
+
}
|
|
3705
|
+
const location2 = response.headers.get("location");
|
|
3706
|
+
if (!location2) {
|
|
3707
|
+
throw new IdentityError(
|
|
3708
|
+
"invalid_redirect",
|
|
3709
|
+
"Agent identity redirect has no location"
|
|
3710
|
+
);
|
|
3711
|
+
}
|
|
3712
|
+
current = new URL(location2, current);
|
|
3713
|
+
continue;
|
|
3714
|
+
}
|
|
3715
|
+
if (!response.ok) {
|
|
3716
|
+
throw new IdentityError(
|
|
3717
|
+
"http_error",
|
|
3718
|
+
"Agent identity endpoint returned an unsuccessful status",
|
|
3719
|
+
{ statusCode: response.status }
|
|
3720
|
+
);
|
|
3721
|
+
}
|
|
3722
|
+
const contentType = response.headers.get("content-type")?.split(";", 1)[0]?.trim();
|
|
3723
|
+
if (contentType !== "application/json" && contentType !== "application/jwk-set+json") {
|
|
3724
|
+
throw new IdentityError("invalid_content_type", "Agent identity response must be JSON");
|
|
3725
|
+
}
|
|
3726
|
+
const body = await response.text();
|
|
3727
|
+
if (new TextEncoder().encode(body).byteLength > this.#maxResponseBytes) {
|
|
3728
|
+
throw new IdentityError(
|
|
3729
|
+
"response_too_large",
|
|
3730
|
+
"Agent identity response exceeds size limit"
|
|
3731
|
+
);
|
|
3732
|
+
}
|
|
3733
|
+
return parseJsonStrict(body);
|
|
3734
|
+
}
|
|
3735
|
+
throw new IdentityError("too_many_redirects", "Agent identity endpoint exceeded redirect policy");
|
|
3736
|
+
}
|
|
3737
|
+
};
|
|
3732
3738
|
export {
|
|
3739
|
+
AgentIdentityClient,
|
|
3733
3740
|
AuthorizationCodeGrant,
|
|
3734
3741
|
AuthorizationError,
|
|
3742
|
+
AuthorizationStateStores,
|
|
3735
3743
|
BrowserHandoffs,
|
|
3736
3744
|
Caches,
|
|
3737
3745
|
Clocks,
|
|
3746
|
+
DirectSignInClient,
|
|
3738
3747
|
DiscoveryError,
|
|
3739
3748
|
DiscoveryTransports,
|
|
3740
3749
|
DpopProofProviders,
|
|
3741
3750
|
ExtensionHandlers,
|
|
3751
|
+
IdentityError,
|
|
3742
3752
|
JWT_BEARER_GRANT,
|
|
3743
3753
|
JWT_CLIENT_ASSERTION,
|
|
3744
3754
|
JoseDpopProofProvider,
|
|
3745
|
-
JoseSigner,
|
|
3746
3755
|
KeyStores,
|
|
3756
|
+
PairwiseUserIdStores,
|
|
3747
3757
|
PersonalAgentProtocolError,
|
|
3748
3758
|
ProofError,
|
|
3749
3759
|
ProtocolProfiles,
|
|
@@ -3768,11 +3778,12 @@ export {
|
|
|
3768
3778
|
parseConversationEventPage,
|
|
3769
3779
|
parseDiscoveryDocument,
|
|
3770
3780
|
parseJsonStrict,
|
|
3781
|
+
parseJsonWebKeySet,
|
|
3771
3782
|
parseMessage,
|
|
3772
3783
|
parseOAuthServerMetadata,
|
|
3773
3784
|
parseOperation,
|
|
3774
3785
|
parseSessionToken,
|
|
3775
|
-
|
|
3776
|
-
|
|
3786
|
+
resolvePairwiseUserId,
|
|
3787
|
+
validateDirectSignInCallback
|
|
3777
3788
|
};
|
|
3778
3789
|
//# sourceMappingURL=index.js.map
|