@atproto/jwk 0.6.0 → 0.7.0
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/CHANGELOG.md +12 -0
- package/LICENSE.txt +1 -1
- package/dist/alg.js +8 -11
- package/dist/alg.js.map +1 -1
- package/dist/errors.js +15 -36
- package/dist/errors.js.map +1 -1
- package/dist/index.js +10 -28
- package/dist/index.js.map +1 -1
- package/dist/jwk.js +77 -89
- package/dist/jwk.js.map +1 -1
- package/dist/jwks.js +8 -11
- package/dist/jwks.js.map +1 -1
- package/dist/jwt-decode.js +8 -11
- package/dist/jwt-decode.js.map +1 -1
- package/dist/jwt-verify.js +1 -2
- package/dist/jwt.js +97 -102
- package/dist/jwt.js.map +1 -1
- package/dist/key.js +142 -152
- package/dist/key.js.map +1 -1
- package/dist/keyset.js +153 -169
- package/dist/keyset.js.map +1 -1
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +19 -28
- package/dist/util.js.map +1 -1
- package/package.json +7 -6
- package/src/jwk.ts +1 -1
- package/src/util.ts +2 -1
- package/tsconfig.build.tsbuildinfo +1 -1
package/dist/keyset.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
|
|
3
2
|
var useValue = arguments.length > 2;
|
|
4
3
|
for (var i = 0; i < initializers.length; i++) {
|
|
@@ -33,200 +32,185 @@ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn,
|
|
|
33
32
|
if (target) Object.defineProperty(target, contextIn.name, descriptor);
|
|
34
33
|
done = true;
|
|
35
34
|
};
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const jwt_decode_js_1 = require("./jwt-decode.js");
|
|
40
|
-
const util_js_1 = require("./util.js");
|
|
35
|
+
import { ERR_JWKS_NO_MATCHING_KEY, ERR_JWK_NOT_FOUND, ERR_JWT_INVALID, JwkError, JwtCreateError, JwtVerifyError, } from './errors.js';
|
|
36
|
+
import { unsafeDecodeJwt } from './jwt-decode.js';
|
|
37
|
+
import { cachedGetter, isDefined, matchesAny, preferredOrderCmp, } from './util.js';
|
|
41
38
|
const extractPrivateJwk = (key) => key.privateJwk;
|
|
42
39
|
const extractPublicJwk = (key) => key.publicJwk;
|
|
43
40
|
let Keyset = (() => {
|
|
44
|
-
var _a;
|
|
45
41
|
let _instanceExtraInitializers = [];
|
|
46
42
|
let _get_signAlgorithms_decorators;
|
|
47
43
|
let _get_publicJwks_decorators;
|
|
48
44
|
let _get_privateJwks_decorators;
|
|
49
|
-
return
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
if (
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
if (keyIds.has(key.kid))
|
|
92
|
-
throw new errors_js_1.JwkError(`Duplicate key: ${key.kid}`);
|
|
93
|
-
else
|
|
94
|
-
keyIds.add(key.kid);
|
|
95
|
-
}
|
|
45
|
+
return class Keyset {
|
|
46
|
+
static {
|
|
47
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
|
|
48
|
+
__esDecorate(this, null, _get_signAlgorithms_decorators, { kind: "getter", name: "signAlgorithms", static: false, private: false, access: { has: obj => "signAlgorithms" in obj, get: obj => obj.signAlgorithms }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
49
|
+
__esDecorate(this, null, _get_publicJwks_decorators, { kind: "getter", name: "publicJwks", static: false, private: false, access: { has: obj => "publicJwks" in obj, get: obj => obj.publicJwks }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
50
|
+
__esDecorate(this, null, _get_privateJwks_decorators, { kind: "getter", name: "privateJwks", static: false, private: false, access: { has: obj => "privateJwks" in obj, get: obj => obj.privateJwks }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
51
|
+
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
52
|
+
}
|
|
53
|
+
constructor(iterable,
|
|
54
|
+
/**
|
|
55
|
+
* The preferred algorithms to use when signing a JWT using this keyset.
|
|
56
|
+
*
|
|
57
|
+
* @see {@link https://datatracker.ietf.org/doc/html/rfc7518#section-3.1}
|
|
58
|
+
*/
|
|
59
|
+
preferredSigningAlgorithms = iterable instanceof
|
|
60
|
+
Keyset
|
|
61
|
+
? [...iterable.preferredSigningAlgorithms]
|
|
62
|
+
: [
|
|
63
|
+
// Prefer elliptic curve algorithms
|
|
64
|
+
'EdDSA',
|
|
65
|
+
'ES256K',
|
|
66
|
+
'ES256',
|
|
67
|
+
// https://datatracker.ietf.org/doc/html/rfc7518#section-3.5
|
|
68
|
+
'PS256',
|
|
69
|
+
'PS384',
|
|
70
|
+
'PS512',
|
|
71
|
+
'HS256',
|
|
72
|
+
'HS384',
|
|
73
|
+
'HS512',
|
|
74
|
+
]) {
|
|
75
|
+
this.preferredSigningAlgorithms = (__runInitializers(this, _instanceExtraInitializers), preferredSigningAlgorithms);
|
|
76
|
+
const keys = [];
|
|
77
|
+
const keyIds = new Set();
|
|
78
|
+
for (const key of iterable) {
|
|
79
|
+
if (!key)
|
|
80
|
+
continue;
|
|
81
|
+
keys.push(key);
|
|
82
|
+
if (key.kid) {
|
|
83
|
+
if (keyIds.has(key.kid))
|
|
84
|
+
throw new JwkError(`Duplicate key: ${key.kid}`);
|
|
85
|
+
else
|
|
86
|
+
keyIds.add(key.kid);
|
|
96
87
|
}
|
|
97
|
-
this.keys = Object.freeze(keys);
|
|
98
|
-
}
|
|
99
|
-
get size() {
|
|
100
|
-
return this.keys.length;
|
|
101
88
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
89
|
+
this.keys = Object.freeze(keys);
|
|
90
|
+
}
|
|
91
|
+
get size() {
|
|
92
|
+
return this.keys.length;
|
|
93
|
+
}
|
|
94
|
+
get signAlgorithms() {
|
|
95
|
+
const algorithms = new Set();
|
|
96
|
+
for (const key of this) {
|
|
97
|
+
if (key.use !== 'sig')
|
|
98
|
+
continue;
|
|
99
|
+
for (const alg of key.algorithms) {
|
|
100
|
+
algorithms.add(alg);
|
|
110
101
|
}
|
|
111
|
-
return Object.freeze([...algorithms].sort((0, util_js_1.preferredOrderCmp)(this.preferredSigningAlgorithms)));
|
|
112
|
-
}
|
|
113
|
-
get publicJwks() {
|
|
114
|
-
return Object.freeze({
|
|
115
|
-
keys: Object.freeze(Array.from(this, extractPublicJwk).filter(util_js_1.isDefined)),
|
|
116
|
-
});
|
|
117
102
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
103
|
+
return Object.freeze([...algorithms].sort(preferredOrderCmp(this.preferredSigningAlgorithms)));
|
|
104
|
+
}
|
|
105
|
+
get publicJwks() {
|
|
106
|
+
return Object.freeze({
|
|
107
|
+
keys: Object.freeze(Array.from(this, extractPublicJwk).filter(isDefined)),
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
get privateJwks() {
|
|
111
|
+
return Object.freeze({
|
|
112
|
+
keys: Object.freeze(Array.from(this, extractPrivateJwk).filter(isDefined)),
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
has(kid) {
|
|
116
|
+
return this.keys.some((key) => key.kid === kid);
|
|
117
|
+
}
|
|
118
|
+
get(options) {
|
|
119
|
+
const key = this.find(options);
|
|
120
|
+
if (key)
|
|
121
|
+
return key;
|
|
122
|
+
throw new JwkError(`Key not found ${options.kid ?? options.alg ?? options.usage ?? '<unknown>'}`, ERR_JWK_NOT_FOUND);
|
|
123
|
+
}
|
|
124
|
+
find(options) {
|
|
125
|
+
for (const key of this.list(options)) {
|
|
126
|
+
return key;
|
|
131
127
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
128
|
+
return undefined;
|
|
129
|
+
}
|
|
130
|
+
*list(options) {
|
|
131
|
+
for (const key of this) {
|
|
132
|
+
if (key.isActive(options) && key.matches(options)) {
|
|
133
|
+
yield key;
|
|
135
134
|
}
|
|
136
|
-
return undefined;
|
|
137
135
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
136
|
+
}
|
|
137
|
+
findPrivateKey({ kid, alg, usage, ...options }) {
|
|
138
|
+
const matchingKeys = [];
|
|
139
|
+
// Allow the loop bellow to return early when a single "alg" is provided
|
|
140
|
+
if (Array.isArray(alg) && alg.length === 1)
|
|
141
|
+
alg = alg[0];
|
|
142
|
+
for (const key of this.list({ ...options, kid, alg, usage })) {
|
|
143
|
+
// Skip negotiation if a single "alg" was provided
|
|
144
|
+
if (typeof alg === 'string')
|
|
145
|
+
return { key, alg };
|
|
146
|
+
matchingKeys.push(key);
|
|
147
|
+
}
|
|
148
|
+
const isAllowedAlg = matchesAny(alg);
|
|
149
|
+
const candidates = matchingKeys.map((key) => [key, key.algorithms.filter(isAllowedAlg)]);
|
|
150
|
+
// Return the first candidates that matches the preferred algorithms
|
|
151
|
+
for (const prefAlg of this.preferredSigningAlgorithms) {
|
|
152
|
+
for (const [matchingKey, matchingAlgs] of candidates) {
|
|
153
|
+
if (matchingAlgs.includes(prefAlg)) {
|
|
154
|
+
return { key: matchingKey, alg: prefAlg };
|
|
142
155
|
}
|
|
143
156
|
}
|
|
144
157
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
alg = alg[0];
|
|
150
|
-
for (const key of this.list({ ...options, kid, alg, usage })) {
|
|
151
|
-
// Skip negotiation if a single "alg" was provided
|
|
152
|
-
if (typeof alg === 'string')
|
|
153
|
-
return { key, alg };
|
|
154
|
-
matchingKeys.push(key);
|
|
158
|
+
// Return any candidate
|
|
159
|
+
for (const [matchingKey, matchingAlgs] of candidates) {
|
|
160
|
+
for (const alg of matchingAlgs) {
|
|
161
|
+
return { key: matchingKey, alg };
|
|
155
162
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
163
|
+
}
|
|
164
|
+
throw new JwkError(`No private key found for ${kid || alg || usage}`, ERR_JWK_NOT_FOUND);
|
|
165
|
+
}
|
|
166
|
+
[(_get_signAlgorithms_decorators = [cachedGetter], _get_publicJwks_decorators = [cachedGetter], _get_privateJwks_decorators = [cachedGetter], Symbol.iterator)]() {
|
|
167
|
+
return this.keys.values();
|
|
168
|
+
}
|
|
169
|
+
async createJwt({ alg: sAlg, kid: sKid, ...header }, payload) {
|
|
170
|
+
try {
|
|
171
|
+
const { key, alg } = this.findPrivateKey({
|
|
172
|
+
alg: sAlg,
|
|
173
|
+
kid: sKid,
|
|
174
|
+
usage: 'sign',
|
|
175
|
+
allowRevoked: false, // For explicitness (default value is false)
|
|
176
|
+
});
|
|
177
|
+
const protectedHeader = { ...header, alg, kid: key.kid };
|
|
178
|
+
if (typeof payload === 'function') {
|
|
179
|
+
payload = await payload(protectedHeader, key);
|
|
171
180
|
}
|
|
172
|
-
|
|
181
|
+
return await key.createJwt(protectedHeader, payload);
|
|
173
182
|
}
|
|
174
|
-
|
|
175
|
-
|
|
183
|
+
catch (err) {
|
|
184
|
+
throw JwtCreateError.from(err);
|
|
176
185
|
}
|
|
177
|
-
|
|
186
|
+
}
|
|
187
|
+
async verifyJwt(token, options) {
|
|
188
|
+
const { header } = unsafeDecodeJwt(token);
|
|
189
|
+
const { kid, alg } = header;
|
|
190
|
+
const errors = [];
|
|
191
|
+
for (const key of this.list({ ...options, kid, alg, usage: 'verify' })) {
|
|
178
192
|
try {
|
|
179
|
-
const
|
|
180
|
-
|
|
181
|
-
kid: sKid,
|
|
182
|
-
usage: 'sign',
|
|
183
|
-
allowRevoked: false, // For explicitness (default value is false)
|
|
184
|
-
});
|
|
185
|
-
const protectedHeader = { ...header, alg, kid: key.kid };
|
|
186
|
-
if (typeof payload === 'function') {
|
|
187
|
-
payload = await payload(protectedHeader, key);
|
|
188
|
-
}
|
|
189
|
-
return await key.createJwt(protectedHeader, payload);
|
|
193
|
+
const result = await key.verifyJwt(token, options);
|
|
194
|
+
return { ...result, key };
|
|
190
195
|
}
|
|
191
196
|
catch (err) {
|
|
192
|
-
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
async verifyJwt(token, options) {
|
|
196
|
-
const { header } = (0, jwt_decode_js_1.unsafeDecodeJwt)(token);
|
|
197
|
-
const { kid, alg } = header;
|
|
198
|
-
const errors = [];
|
|
199
|
-
for (const key of this.list({ ...options, kid, alg, usage: 'verify' })) {
|
|
200
|
-
try {
|
|
201
|
-
const result = await key.verifyJwt(token, options);
|
|
202
|
-
return { ...result, key };
|
|
203
|
-
}
|
|
204
|
-
catch (err) {
|
|
205
|
-
errors.push(err);
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
switch (errors.length) {
|
|
209
|
-
case 0:
|
|
210
|
-
throw new errors_js_1.JwtVerifyError('No key matched', errors_js_1.ERR_JWKS_NO_MATCHING_KEY);
|
|
211
|
-
case 1:
|
|
212
|
-
throw errors_js_1.JwtVerifyError.from(errors[0], errors_js_1.ERR_JWT_INVALID);
|
|
213
|
-
default:
|
|
214
|
-
throw errors_js_1.JwtVerifyError.from(errors, errors_js_1.ERR_JWT_INVALID);
|
|
197
|
+
errors.push(err);
|
|
215
198
|
}
|
|
216
199
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
200
|
+
switch (errors.length) {
|
|
201
|
+
case 0:
|
|
202
|
+
throw new JwtVerifyError('No key matched', ERR_JWKS_NO_MATCHING_KEY);
|
|
203
|
+
case 1:
|
|
204
|
+
throw JwtVerifyError.from(errors[0], ERR_JWT_INVALID);
|
|
205
|
+
default:
|
|
206
|
+
throw JwtVerifyError.from(errors, ERR_JWT_INVALID);
|
|
220
207
|
}
|
|
221
|
-
}
|
|
222
|
-
(
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
228
|
-
})(),
|
|
229
|
-
_a;
|
|
208
|
+
}
|
|
209
|
+
toJSON() {
|
|
210
|
+
// Make a copy to allow mutation of the result
|
|
211
|
+
return structuredClone(this.publicJwks);
|
|
212
|
+
}
|
|
213
|
+
};
|
|
230
214
|
})();
|
|
231
|
-
|
|
215
|
+
export { Keyset };
|
|
232
216
|
//# sourceMappingURL=keyset.js.map
|
package/dist/keyset.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keyset.js","sourceRoot":"","sources":["../src/keyset.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n ERR_JWKS_NO_MATCHING_KEY,\n ERR_JWK_NOT_FOUND,\n ERR_JWT_INVALID,\n JwkError,\n JwtCreateError,\n JwtVerifyError,\n} from './errors.js'\nimport { PrivateKeyUsage } from './jwk.js'\nimport { JwksPub } from './jwks.js'\nimport { unsafeDecodeJwt } from './jwt-decode.js'\nimport { VerifyOptions, VerifyResult } from './jwt-verify.js'\nimport { JwtHeader, JwtPayload, SignedJwt } from './jwt.js'\nimport { ActivityCheckOptions, Key, KeyMatchOptions } from './key.js'\nimport {\n Override,\n cachedGetter,\n isDefined,\n matchesAny,\n preferredOrderCmp,\n} from './util.js'\n\nexport type { ActivityCheckOptions, KeyMatchOptions }\nexport type FindKeyOptions = KeyMatchOptions & ActivityCheckOptions\n\nexport type JwtSignHeader = Override<\n JwtHeader,\n Pick<FindKeyOptions, 'alg' | 'kid'>\n>\n\nexport type JwtPayloadGetter<P = JwtPayload> = (\n header: JwtHeader,\n key: Key,\n) => P | PromiseLike<P>\n\nconst extractPrivateJwk = (key: Key) => key.privateJwk\nconst extractPublicJwk = (key: Key) => key.publicJwk\n\nexport class Keyset<K extends Key = Key> implements Iterable<K> {\n private readonly keys: readonly K[]\n\n constructor(\n iterable: Iterable<K | null | undefined | false>,\n /**\n * The preferred algorithms to use when signing a JWT using this keyset.\n *\n * @see {@link https://datatracker.ietf.org/doc/html/rfc7518#section-3.1}\n */\n public readonly preferredSigningAlgorithms: readonly string[] = iterable instanceof\n Keyset\n ? [...iterable.preferredSigningAlgorithms]\n : [\n // Prefer elliptic curve algorithms\n 'EdDSA',\n 'ES256K',\n 'ES256',\n // https://datatracker.ietf.org/doc/html/rfc7518#section-3.5\n 'PS256',\n 'PS384',\n 'PS512',\n 'HS256',\n 'HS384',\n 'HS512',\n ],\n ) {\n const keys: K[] = []\n\n const keyIds = new Set<string>()\n for (const key of iterable) {\n if (!key) continue\n\n keys.push(key)\n\n if (key.kid) {\n if (keyIds.has(key.kid)) throw new JwkError(`Duplicate key: ${key.kid}`)\n else keyIds.add(key.kid)\n }\n }\n\n this.keys = Object.freeze(keys)\n }\n\n get size(): number {\n return this.keys.length\n }\n\n @cachedGetter\n get signAlgorithms(): readonly string[] {\n const algorithms = new Set<string>()\n for (const key of this) {\n if (key.use !== 'sig') continue\n for (const alg of key.algorithms) {\n algorithms.add(alg)\n }\n }\n return Object.freeze(\n [...algorithms].sort(preferredOrderCmp(this.preferredSigningAlgorithms)),\n )\n }\n\n @cachedGetter\n get publicJwks() {\n return Object.freeze({\n keys: Object.freeze(Array.from(this, extractPublicJwk).filter(isDefined)),\n })\n }\n\n @cachedGetter\n get privateJwks() {\n return Object.freeze({\n keys: Object.freeze(\n Array.from(this, extractPrivateJwk).filter(isDefined),\n ),\n })\n }\n\n has(kid: string): boolean {\n return this.keys.some((key) => key.kid === kid)\n }\n\n get(options: FindKeyOptions): K {\n const key = this.find(options)\n if (key) return key\n\n throw new JwkError(\n `Key not found ${options.kid ?? options.alg ?? options.usage ?? '<unknown>'}`,\n ERR_JWK_NOT_FOUND,\n )\n }\n\n find(options: FindKeyOptions): K | undefined {\n for (const key of this.list(options)) {\n return key\n }\n\n return undefined\n }\n\n *list<O extends FindKeyOptions>(options: O) {\n for (const key of this) {\n if (key.isActive(options) && key.matches(options)) {\n yield key\n }\n }\n }\n\n findPrivateKey({\n kid,\n alg,\n usage,\n ...options\n }: FindKeyOptions & { usage: PrivateKeyUsage }): {\n key: Key\n alg: string\n } {\n const matchingKeys: Key[] = []\n\n // Allow the loop bellow to return early when a single \"alg\" is provided\n if (Array.isArray(alg) && alg.length === 1) alg = alg[0]\n\n for (const key of this.list({ ...options, kid, alg, usage })) {\n // Skip negotiation if a single \"alg\" was provided\n if (typeof alg === 'string') return { key, alg }\n\n matchingKeys.push(key)\n }\n\n const isAllowedAlg = matchesAny(alg)\n const candidates = matchingKeys.map(\n (key) => [key, key.algorithms.filter(isAllowedAlg)] as const,\n )\n\n // Return the first candidates that matches the preferred algorithms\n for (const prefAlg of this.preferredSigningAlgorithms) {\n for (const [matchingKey, matchingAlgs] of candidates) {\n if (matchingAlgs.includes(prefAlg)) {\n return { key: matchingKey, alg: prefAlg }\n }\n }\n }\n\n // Return any candidate\n for (const [matchingKey, matchingAlgs] of candidates) {\n for (const alg of matchingAlgs) {\n return { key: matchingKey, alg }\n }\n }\n\n throw new JwkError(\n `No private key found for ${kid || alg || usage}`,\n ERR_JWK_NOT_FOUND,\n )\n }\n\n [Symbol.iterator](): IterableIterator<K> {\n return this.keys.values()\n }\n\n async createJwt(\n { alg: sAlg, kid: sKid, ...header }: JwtSignHeader,\n payload: JwtPayload | JwtPayloadGetter,\n ): Promise<SignedJwt> {\n try {\n const { key, alg } = this.findPrivateKey({\n alg: sAlg,\n kid: sKid,\n usage: 'sign',\n allowRevoked: false, // For explicitness (default value is false)\n })\n const protectedHeader = { ...header, alg, kid: key.kid }\n\n if (typeof payload === 'function') {\n payload = await payload(protectedHeader, key)\n }\n\n return await key.createJwt(protectedHeader, payload)\n } catch (err) {\n throw JwtCreateError.from(err)\n }\n }\n\n async verifyJwt<C extends string = never>(\n token: SignedJwt,\n options?: ActivityCheckOptions & VerifyOptions<C>,\n ): Promise<VerifyResult<C> & { key: K }> {\n const { header } = unsafeDecodeJwt(token)\n const { kid, alg } = header\n\n const errors: unknown[] = []\n\n for (const key of this.list({ ...options, kid, alg, usage: 'verify' })) {\n try {\n const result = await key.verifyJwt<C>(token, options)\n return { ...result, key }\n } catch (err) {\n errors.push(err)\n }\n }\n\n switch (errors.length) {\n case 0:\n throw new JwtVerifyError('No key matched', ERR_JWKS_NO_MATCHING_KEY)\n case 1:\n throw JwtVerifyError.from(errors[0], ERR_JWT_INVALID)\n default:\n throw JwtVerifyError.from(errors, ERR_JWT_INVALID)\n }\n }\n\n toJSON() {\n // Make a copy to allow mutation of the result\n return structuredClone(this.publicJwks) as JwksPub\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"keyset.js","sourceRoot":"","sources":["../src/keyset.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n ERR_JWKS_NO_MATCHING_KEY,\n ERR_JWK_NOT_FOUND,\n ERR_JWT_INVALID,\n JwkError,\n JwtCreateError,\n JwtVerifyError,\n} from './errors.js'\nimport { PrivateKeyUsage } from './jwk.js'\nimport { JwksPub } from './jwks.js'\nimport { unsafeDecodeJwt } from './jwt-decode.js'\nimport { VerifyOptions, VerifyResult } from './jwt-verify.js'\nimport { JwtHeader, JwtPayload, SignedJwt } from './jwt.js'\nimport { ActivityCheckOptions, Key, KeyMatchOptions } from './key.js'\nimport {\n Override,\n cachedGetter,\n isDefined,\n matchesAny,\n preferredOrderCmp,\n} from './util.js'\n\nexport type { ActivityCheckOptions, KeyMatchOptions }\nexport type FindKeyOptions = KeyMatchOptions & ActivityCheckOptions\n\nexport type JwtSignHeader = Override<\n JwtHeader,\n Pick<FindKeyOptions, 'alg' | 'kid'>\n>\n\nexport type JwtPayloadGetter<P = JwtPayload> = (\n header: JwtHeader,\n key: Key,\n) => P | PromiseLike<P>\n\nconst extractPrivateJwk = (key: Key) => key.privateJwk\nconst extractPublicJwk = (key: Key) => key.publicJwk\n\nexport class Keyset<K extends Key = Key> implements Iterable<K> {\n private readonly keys: readonly K[]\n\n constructor(\n iterable: Iterable<K | null | undefined | false>,\n /**\n * The preferred algorithms to use when signing a JWT using this keyset.\n *\n * @see {@link https://datatracker.ietf.org/doc/html/rfc7518#section-3.1}\n */\n public readonly preferredSigningAlgorithms: readonly string[] = iterable instanceof\n Keyset\n ? [...iterable.preferredSigningAlgorithms]\n : [\n // Prefer elliptic curve algorithms\n 'EdDSA',\n 'ES256K',\n 'ES256',\n // https://datatracker.ietf.org/doc/html/rfc7518#section-3.5\n 'PS256',\n 'PS384',\n 'PS512',\n 'HS256',\n 'HS384',\n 'HS512',\n ],\n ) {\n const keys: K[] = []\n\n const keyIds = new Set<string>()\n for (const key of iterable) {\n if (!key) continue\n\n keys.push(key)\n\n if (key.kid) {\n if (keyIds.has(key.kid)) throw new JwkError(`Duplicate key: ${key.kid}`)\n else keyIds.add(key.kid)\n }\n }\n\n this.keys = Object.freeze(keys)\n }\n\n get size(): number {\n return this.keys.length\n }\n\n @cachedGetter\n get signAlgorithms(): readonly string[] {\n const algorithms = new Set<string>()\n for (const key of this) {\n if (key.use !== 'sig') continue\n for (const alg of key.algorithms) {\n algorithms.add(alg)\n }\n }\n return Object.freeze(\n [...algorithms].sort(preferredOrderCmp(this.preferredSigningAlgorithms)),\n )\n }\n\n @cachedGetter\n get publicJwks() {\n return Object.freeze({\n keys: Object.freeze(Array.from(this, extractPublicJwk).filter(isDefined)),\n })\n }\n\n @cachedGetter\n get privateJwks() {\n return Object.freeze({\n keys: Object.freeze(\n Array.from(this, extractPrivateJwk).filter(isDefined),\n ),\n })\n }\n\n has(kid: string): boolean {\n return this.keys.some((key) => key.kid === kid)\n }\n\n get(options: FindKeyOptions): K {\n const key = this.find(options)\n if (key) return key\n\n throw new JwkError(\n `Key not found ${options.kid ?? options.alg ?? options.usage ?? '<unknown>'}`,\n ERR_JWK_NOT_FOUND,\n )\n }\n\n find(options: FindKeyOptions): K | undefined {\n for (const key of this.list(options)) {\n return key\n }\n\n return undefined\n }\n\n *list<O extends FindKeyOptions>(options: O) {\n for (const key of this) {\n if (key.isActive(options) && key.matches(options)) {\n yield key\n }\n }\n }\n\n findPrivateKey({\n kid,\n alg,\n usage,\n ...options\n }: FindKeyOptions & { usage: PrivateKeyUsage }): {\n key: Key\n alg: string\n } {\n const matchingKeys: Key[] = []\n\n // Allow the loop bellow to return early when a single \"alg\" is provided\n if (Array.isArray(alg) && alg.length === 1) alg = alg[0]\n\n for (const key of this.list({ ...options, kid, alg, usage })) {\n // Skip negotiation if a single \"alg\" was provided\n if (typeof alg === 'string') return { key, alg }\n\n matchingKeys.push(key)\n }\n\n const isAllowedAlg = matchesAny(alg)\n const candidates = matchingKeys.map(\n (key) => [key, key.algorithms.filter(isAllowedAlg)] as const,\n )\n\n // Return the first candidates that matches the preferred algorithms\n for (const prefAlg of this.preferredSigningAlgorithms) {\n for (const [matchingKey, matchingAlgs] of candidates) {\n if (matchingAlgs.includes(prefAlg)) {\n return { key: matchingKey, alg: prefAlg }\n }\n }\n }\n\n // Return any candidate\n for (const [matchingKey, matchingAlgs] of candidates) {\n for (const alg of matchingAlgs) {\n return { key: matchingKey, alg }\n }\n }\n\n throw new JwkError(\n `No private key found for ${kid || alg || usage}`,\n ERR_JWK_NOT_FOUND,\n )\n }\n\n [Symbol.iterator](): IterableIterator<K> {\n return this.keys.values()\n }\n\n async createJwt(\n { alg: sAlg, kid: sKid, ...header }: JwtSignHeader,\n payload: JwtPayload | JwtPayloadGetter,\n ): Promise<SignedJwt> {\n try {\n const { key, alg } = this.findPrivateKey({\n alg: sAlg,\n kid: sKid,\n usage: 'sign',\n allowRevoked: false, // For explicitness (default value is false)\n })\n const protectedHeader = { ...header, alg, kid: key.kid }\n\n if (typeof payload === 'function') {\n payload = await payload(protectedHeader, key)\n }\n\n return await key.createJwt(protectedHeader, payload)\n } catch (err) {\n throw JwtCreateError.from(err)\n }\n }\n\n async verifyJwt<C extends string = never>(\n token: SignedJwt,\n options?: ActivityCheckOptions & VerifyOptions<C>,\n ): Promise<VerifyResult<C> & { key: K }> {\n const { header } = unsafeDecodeJwt(token)\n const { kid, alg } = header\n\n const errors: unknown[] = []\n\n for (const key of this.list({ ...options, kid, alg, usage: 'verify' })) {\n try {\n const result = await key.verifyJwt<C>(token, options)\n return { ...result, key }\n } catch (err) {\n errors.push(err)\n }\n }\n\n switch (errors.length) {\n case 0:\n throw new JwtVerifyError('No key matched', ERR_JWKS_NO_MATCHING_KEY)\n case 1:\n throw JwtVerifyError.from(errors[0], ERR_JWT_INVALID)\n default:\n throw JwtVerifyError.from(errors, ERR_JWT_INVALID)\n }\n }\n\n toJSON() {\n // Make a copy to allow mutation of the result\n return structuredClone(this.publicJwks) as JwksPub\n }\n}\n"]}
|
package/dist/util.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAgB,MAAM,KAAK,CAAA;
|
|
1
|
+
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAgB,MAAM,KAAK,CAAA;AAEjD,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAE,GAAG,EAAE,CAAA;AACvD,MAAM,MAAM,QAAQ,CAAC,CAAC,EAAE,CAAC,IAAI,QAAQ,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAA;AAE3D,MAAM,MAAM,WAAW,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,GAAG,KAAK,IAAI,QAAQ,CAC9D,CAAC,GAAG;KACD,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,GAC5B,WAAW,CAAC,OAAO,CAAC,GAAG,IAAI,GAC3B,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC;CAC7B,CACF,CAAA;AAED,eAAO,MAAM,SAAS,GAAI,CAAC,EAAE,GAAG,CAAC,GAAG,SAAS,KAAG,CAAC,IAAI,CAAoB,CAAA;AAEzE,eAAO,MAAM,iBAAiB,GAC3B,CAAC,EAAE,OAAO,SAAS,CAAC,EAAE,MACtB,GAAG,CAAC,EAAE,GAAG,CAAC,WAOV,CAAA;AAGH,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,EACrE,KAAK,EAAE,IAAI,GAAG,SAAS,GAAG,CAAC,GAAG,SAAS,CAAC,EAAE,GACzC,CAAC,CAAC,EAAE,OAAO,KAAK,CAAC,IAAI,CAAC,CAMxB;AAGD;;GAEG;AACH,eAAO,MAAM,YAAY,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,EAC9C,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,EACtB,UAAU,2BAA2B,CAAC,CAAC,EAAE,CAAC,CAAC,MAE1B,MAAM,CAAC,MASzB,CAAA;AAGD,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAIpD;AAED;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,GAAI,MAAM,MAAM,EAAE,KAAK,aAAa,KAAG,IA2BrE,CAAA;AAED;;;;;;;;;;;;GAYG;AACH,KAAK,eAAe,CAClB,CAAC,SAAS,MAAM,EAChB,GAAG,SAAS,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,IAC7B,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,GACvB,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,GACX,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,eAAe,CAAC,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC,EAAE,CAAA;AAEvD;;;;;;GAMG;AACH,eAAO,MAAM,gCAAgC,GAAI,CAAC,SAAS,MAAM,EAC/D,OAAO,CAAC,EACR,sBAAiB,MAST,MAAM,MAAM,EAAE,KAAK,aAAa,KAAG,IAAI,IAAI,eAAe,CAAC,CAAC,CA2CrE,CAAA;AAED,wBAAgB,gBAAgB,CAC9B,CAAC,SAAS,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,EACxE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,CAAC,EAAE,GAAG,OAAO,CAE7C"}
|
package/dist/util.js
CHANGED
|
@@ -1,14 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
exports.parseB64uJson = parseB64uJson;
|
|
6
|
-
exports.isLastOccurrence = isLastOccurrence;
|
|
7
|
-
const base64_1 = require("multiformats/bases/base64");
|
|
8
|
-
const zod_1 = require("zod");
|
|
9
|
-
const isDefined = (i) => i !== undefined;
|
|
10
|
-
exports.isDefined = isDefined;
|
|
11
|
-
const preferredOrderCmp = (order) => (a, b) => {
|
|
1
|
+
import { base64url } from 'multiformats/bases/base64';
|
|
2
|
+
import { ZodIssueCode } from 'zod';
|
|
3
|
+
export const isDefined = (i) => i !== undefined;
|
|
4
|
+
export const preferredOrderCmp = (order) => (a, b) => {
|
|
12
5
|
const aIdx = order.indexOf(a);
|
|
13
6
|
const bIdx = order.indexOf(b);
|
|
14
7
|
if (aIdx === bIdx)
|
|
@@ -19,18 +12,19 @@ const preferredOrderCmp = (order) => (a, b) => {
|
|
|
19
12
|
return -1;
|
|
20
13
|
return aIdx - bIdx;
|
|
21
14
|
};
|
|
22
|
-
|
|
23
|
-
function matchesAny(value) {
|
|
15
|
+
/* eslint-disable @typescript-eslint/no-unused-vars -- `v` is used at runtime in the returned type guards; v8 false-positive */
|
|
16
|
+
export function matchesAny(value) {
|
|
24
17
|
return value == null
|
|
25
18
|
? (v) => true
|
|
26
19
|
: Array.isArray(value)
|
|
27
20
|
? (v) => value.includes(v)
|
|
28
21
|
: (v) => v === value;
|
|
29
22
|
}
|
|
23
|
+
/* eslint-enable @typescript-eslint/no-unused-vars */
|
|
30
24
|
/**
|
|
31
25
|
* Decorator to cache the result of a getter on a class instance.
|
|
32
26
|
*/
|
|
33
|
-
const cachedGetter = (target, _context) => {
|
|
27
|
+
export const cachedGetter = (target, _context) => {
|
|
34
28
|
return function () {
|
|
35
29
|
const value = target.call(this);
|
|
36
30
|
Object.defineProperty(this, target.name, {
|
|
@@ -41,10 +35,9 @@ const cachedGetter = (target, _context) => {
|
|
|
41
35
|
return value;
|
|
42
36
|
};
|
|
43
37
|
};
|
|
44
|
-
exports.cachedGetter = cachedGetter;
|
|
45
38
|
const decoder = new TextDecoder();
|
|
46
|
-
function parseB64uJson(input) {
|
|
47
|
-
const inputBytes =
|
|
39
|
+
export function parseB64uJson(input) {
|
|
40
|
+
const inputBytes = base64url.baseDecode(input);
|
|
48
41
|
const json = decoder.decode(inputBytes);
|
|
49
42
|
return JSON.parse(json);
|
|
50
43
|
}
|
|
@@ -55,7 +48,7 @@ function parseB64uJson(input) {
|
|
|
55
48
|
* const jwtSchema = z.string().superRefine(jwtCharsRefinement)
|
|
56
49
|
* ```
|
|
57
50
|
*/
|
|
58
|
-
const jwtCharsRefinement = (data, ctx) => {
|
|
51
|
+
export const jwtCharsRefinement = (data, ctx) => {
|
|
59
52
|
// Note: this is a hot path, let's avoid using a RegExp
|
|
60
53
|
let char;
|
|
61
54
|
for (let i = 0; i < data.length; i++) {
|
|
@@ -76,13 +69,12 @@ const jwtCharsRefinement = (data, ctx) => {
|
|
|
76
69
|
// Invalid char might be a surrogate pair
|
|
77
70
|
const invalidChar = String.fromCodePoint(data.codePointAt(i));
|
|
78
71
|
return ctx.addIssue({
|
|
79
|
-
code:
|
|
72
|
+
code: ZodIssueCode.custom,
|
|
80
73
|
message: `Invalid character "${invalidChar}" in JWT at position ${i}`,
|
|
81
74
|
});
|
|
82
75
|
}
|
|
83
76
|
}
|
|
84
77
|
};
|
|
85
|
-
exports.jwtCharsRefinement = jwtCharsRefinement;
|
|
86
78
|
/**
|
|
87
79
|
* @example
|
|
88
80
|
* ```ts
|
|
@@ -90,7 +82,7 @@ exports.jwtCharsRefinement = jwtCharsRefinement;
|
|
|
90
82
|
* type Jwt = z.infer<typeof jwtSchema> // `${string}.${string}.${string}`
|
|
91
83
|
* ```
|
|
92
84
|
*/
|
|
93
|
-
const segmentedStringRefinementFactory = (count, minPartLength = 2) => {
|
|
85
|
+
export const segmentedStringRefinementFactory = (count, minPartLength = 2) => {
|
|
94
86
|
if (!Number.isFinite(count) || count < 1 || (count | 0) !== count) {
|
|
95
87
|
throw new TypeError(`Count must be a natural number (got ${count})`);
|
|
96
88
|
}
|
|
@@ -99,7 +91,7 @@ const segmentedStringRefinementFactory = (count, minPartLength = 2) => {
|
|
|
99
91
|
return (data, ctx) => {
|
|
100
92
|
if (data.length < minTotalLength) {
|
|
101
93
|
ctx.addIssue({
|
|
102
|
-
code:
|
|
94
|
+
code: ZodIssueCode.custom,
|
|
103
95
|
message: `${errorPrefix}: too short`,
|
|
104
96
|
});
|
|
105
97
|
return false;
|
|
@@ -109,14 +101,14 @@ const segmentedStringRefinementFactory = (count, minPartLength = 2) => {
|
|
|
109
101
|
const nextDot = data.indexOf('.', currentStart);
|
|
110
102
|
if (nextDot === -1) {
|
|
111
103
|
ctx.addIssue({
|
|
112
|
-
code:
|
|
104
|
+
code: ZodIssueCode.custom,
|
|
113
105
|
message: `${errorPrefix}: expected ${count} segments, got ${i + 1}`,
|
|
114
106
|
});
|
|
115
107
|
return false;
|
|
116
108
|
}
|
|
117
109
|
if (nextDot - currentStart < minPartLength) {
|
|
118
110
|
ctx.addIssue({
|
|
119
|
-
code:
|
|
111
|
+
code: ZodIssueCode.custom,
|
|
120
112
|
message: `${errorPrefix}: segment ${i + 1} is too short`,
|
|
121
113
|
});
|
|
122
114
|
return false;
|
|
@@ -125,14 +117,14 @@ const segmentedStringRefinementFactory = (count, minPartLength = 2) => {
|
|
|
125
117
|
}
|
|
126
118
|
if (data.indexOf('.', currentStart) !== -1) {
|
|
127
119
|
ctx.addIssue({
|
|
128
|
-
code:
|
|
120
|
+
code: ZodIssueCode.custom,
|
|
129
121
|
message: `${errorPrefix}: too many segments`,
|
|
130
122
|
});
|
|
131
123
|
return false;
|
|
132
124
|
}
|
|
133
125
|
if (data.length - currentStart < minPartLength) {
|
|
134
126
|
ctx.addIssue({
|
|
135
|
-
code:
|
|
127
|
+
code: ZodIssueCode.custom,
|
|
136
128
|
message: `${errorPrefix}: last segment is too short`,
|
|
137
129
|
});
|
|
138
130
|
return false;
|
|
@@ -140,8 +132,7 @@ const segmentedStringRefinementFactory = (count, minPartLength = 2) => {
|
|
|
140
132
|
return true;
|
|
141
133
|
};
|
|
142
134
|
};
|
|
143
|
-
|
|
144
|
-
function isLastOccurrence(v, i, arr) {
|
|
135
|
+
export function isLastOccurrence(v, i, arr) {
|
|
145
136
|
return arr.indexOf(v, i + 1) === -1;
|
|
146
137
|
}
|
|
147
138
|
//# sourceMappingURL=util.js.map
|
package/dist/util.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"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","sourcesContent":["import { base64url } from 'multiformats/bases/base64'\nimport { RefinementCtx, ZodIssueCode } from 'zod'\n\n// eslint-disable-next-line @typescript-eslint/ban-types\nexport type Simplify<T> = { [K in keyof T]: T[K] } & {}\nexport type Override<T, V> = Simplify<V & Omit<T, keyof V>>\n\nexport type RequiredKey<T, K extends keyof T = never> = Simplify<\n T & {\n [L in K]-?: unknown extends T[L]\n ? NonNullable<unknown> | null\n : Exclude<T[L], undefined>\n }\n>\n\nexport const isDefined = <T>(i: T | undefined): i is T => i !== undefined\n\nexport const preferredOrderCmp =\n <T>(order: readonly T[]) =>\n (a: T, b: T) => {\n const aIdx = order.indexOf(a)\n const bIdx = order.indexOf(b)\n if (aIdx === bIdx) return 0\n if (aIdx === -1) return 1\n if (bIdx === -1) return -1\n return aIdx - bIdx\n }\n\nexport function matchesAny<T extends string | number | symbol | boolean>(\n value: null | undefined | T | readonly T[],\n): (v: unknown) => v is T {\n return value == null\n ? (v): v is T => true\n : Array.isArray(value)\n ? (v): v is T => value.includes(v)\n : (v): v is T => v === value\n}\n\n/**\n * Decorator to cache the result of a getter on a class instance.\n */\nexport const cachedGetter = <T extends object, V>(\n target: (this: T) => V,\n _context: ClassGetterDecoratorContext<T, V>,\n) => {\n return function (this: T) {\n const value = target.call(this)\n Object.defineProperty(this, target.name, {\n get: () => value,\n enumerable: true,\n configurable: true,\n })\n return value\n }\n}\n\nconst decoder = new TextDecoder()\nexport function parseB64uJson(input: string): unknown {\n const inputBytes = base64url.baseDecode(input)\n const json = decoder.decode(inputBytes)\n return JSON.parse(json)\n}\n\n/**\n * @example\n * ```ts\n * // jwtSchema will only allow base64url chars & \".\" (dot)\n * const jwtSchema = z.string().superRefine(jwtCharsRefinement)\n * ```\n */\nexport const jwtCharsRefinement = (data: string, ctx: RefinementCtx): void => {\n // Note: this is a hot path, let's avoid using a RegExp\n let char\n\n for (let i = 0; i < data.length; i++) {\n char = data.charCodeAt(i)\n\n if (\n // Base64 URL encoding (most frequent)\n (65 <= char && char <= 90) || // A-Z\n (97 <= char && char <= 122) || // a-z\n (48 <= char && char <= 57) || // 0-9\n char === 45 || // -\n char === 95 || // _\n // Boundary (least frequent, check last)\n char === 46 // .\n ) {\n // continue\n } else {\n // Invalid char might be a surrogate pair\n const invalidChar = String.fromCodePoint(data.codePointAt(i)!)\n return ctx.addIssue({\n code: ZodIssueCode.custom,\n message: `Invalid character \"${invalidChar}\" in JWT at position ${i}`,\n })\n }\n }\n}\n\n/**\n * @example\n * ```ts\n * type SegmentedString3 = SegmentedString<3> // `${string}.${string}.${string}`\n * type SegmentedString4 = SegmentedString<4> // `${string}.${string}.${string}.${string}`\n * ```\n *\n * @note\n * This utility only provides one way type safety (A SegmentedString<4> can be\n * assigned to SegmentedString<3> but not vice versa). The purpose of this\n * utility is to improve DX by avoiding as many potential errors as build time.\n * DO NOT rely on this to enforce security or data integrity.\n */\ntype SegmentedString<\n C extends number,\n Acc extends string[] = [string],\n> = Acc['length'] extends C\n ? `${Acc[0]}`\n : `${Acc[0]}.${SegmentedString<C, [string, ...Acc]>}`\n\n/**\n * @example\n * ```ts\n * const jwtSchema = z.string().superRefine(segmentedStringRefinementFactory(3))\n * type Jwt = z.infer<typeof jwtSchema> // `${string}.${string}.${string}`\n * ```\n */\nexport const segmentedStringRefinementFactory = <C extends number>(\n count: C,\n minPartLength = 2,\n) => {\n if (!Number.isFinite(count) || count < 1 || (count | 0) !== count) {\n throw new TypeError(`Count must be a natural number (got ${count})`)\n }\n\n const minTotalLength = count * minPartLength + (count - 1)\n const errorPrefix = `Invalid JWT format`\n\n return (data: string, ctx: RefinementCtx): data is SegmentedString<C> => {\n if (data.length < minTotalLength) {\n ctx.addIssue({\n code: ZodIssueCode.custom,\n message: `${errorPrefix}: too short`,\n })\n return false\n }\n let currentStart = 0\n for (let i = 0; i < count - 1; i++) {\n const nextDot = data.indexOf('.', currentStart)\n if (nextDot === -1) {\n ctx.addIssue({\n code: ZodIssueCode.custom,\n message: `${errorPrefix}: expected ${count} segments, got ${i + 1}`,\n })\n return false\n }\n if (nextDot - currentStart < minPartLength) {\n ctx.addIssue({\n code: ZodIssueCode.custom,\n message: `${errorPrefix}: segment ${i + 1} is too short`,\n })\n return false\n }\n currentStart = nextDot + 1\n }\n if (data.indexOf('.', currentStart) !== -1) {\n ctx.addIssue({\n code: ZodIssueCode.custom,\n message: `${errorPrefix}: too many segments`,\n })\n return false\n }\n if (data.length - currentStart < minPartLength) {\n ctx.addIssue({\n code: ZodIssueCode.custom,\n message: `${errorPrefix}: last segment is too short`,\n })\n return false\n }\n return true\n }\n}\n\nexport function isLastOccurrence<\n T extends number | boolean | string | null | undefined | symbol | bigint,\n>(v: T, i: number, arr: readonly T[]): boolean {\n return arr.indexOf(v, i + 1) === -1\n}\n"]}
|
|
1
|
+
{"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAA;AACrD,OAAO,EAAiB,YAAY,EAAE,MAAM,KAAK,CAAA;AAajD,MAAM,CAAC,MAAM,SAAS,GAAG,CAAI,CAAgB,EAAU,EAAE,CAAC,CAAC,KAAK,SAAS,CAAA;AAEzE,MAAM,CAAC,MAAM,iBAAiB,GAC5B,CAAI,KAAmB,EAAE,EAAE,CAC3B,CAAC,CAAI,EAAE,CAAI,EAAE,EAAE;IACb,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;IAC7B,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;IAC7B,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,CAAC,CAAA;IAC3B,IAAI,IAAI,KAAK,CAAC,CAAC;QAAE,OAAO,CAAC,CAAA;IACzB,IAAI,IAAI,KAAK,CAAC,CAAC;QAAE,OAAO,CAAC,CAAC,CAAA;IAC1B,OAAO,IAAI,GAAG,IAAI,CAAA;AACpB,CAAC,CAAA;AAEH,+HAA+H;AAC/H,MAAM,UAAU,UAAU,CACxB,KAA0C;IAE1C,OAAO,KAAK,IAAI,IAAI;QAClB,CAAC,CAAC,CAAC,CAAC,EAAU,EAAE,CAAC,IAAI;QACrB,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;YACpB,CAAC,CAAC,CAAC,CAAC,EAAU,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;YAClC,CAAC,CAAC,CAAC,CAAC,EAAU,EAAE,CAAC,CAAC,KAAK,KAAK,CAAA;AAClC,CAAC;AACD,qDAAqD;AAErD;;GAEG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAC1B,MAAsB,EACtB,QAA2C,EAC3C,EAAE;IACF,OAAO;QACL,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC/B,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE;YACvC,GAAG,EAAE,GAAG,EAAE,CAAC,KAAK;YAChB,UAAU,EAAE,IAAI;YAChB,YAAY,EAAE,IAAI;SACnB,CAAC,CAAA;QACF,OAAO,KAAK,CAAA;IACd,CAAC,CAAA;AACH,CAAC,CAAA;AAED,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAA;AACjC,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,MAAM,UAAU,GAAG,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC,CAAA;IAC9C,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAA;IACvC,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;AACzB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,IAAY,EAAE,GAAkB,EAAQ,EAAE;IAC3E,uDAAuD;IACvD,IAAI,IAAI,CAAA;IAER,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAA;QAEzB;QACE,sCAAsC;QACtC,CAAC,EAAE,IAAI,IAAI,IAAI,IAAI,IAAI,EAAE,CAAC,IAAI,MAAM;YACpC,CAAC,EAAE,IAAI,IAAI,IAAI,IAAI,IAAI,GAAG,CAAC,IAAI,MAAM;YACrC,CAAC,EAAE,IAAI,IAAI,IAAI,IAAI,IAAI,EAAE,CAAC,IAAI,MAAM;YACpC,IAAI,KAAK,EAAE,IAAI,IAAI;YACnB,IAAI,KAAK,EAAE,IAAI,IAAI;YACnB,wCAAwC;YACxC,IAAI,KAAK,EAAE,CAAC,IAAI;UAChB,CAAC;YACD,WAAW;QACb,CAAC;aAAM,CAAC;YACN,yCAAyC;YACzC,MAAM,WAAW,GAAG,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAE,CAAC,CAAA;YAC9D,OAAO,GAAG,CAAC,QAAQ,CAAC;gBAClB,IAAI,EAAE,YAAY,CAAC,MAAM;gBACzB,OAAO,EAAE,sBAAsB,WAAW,wBAAwB,CAAC,EAAE;aACtE,CAAC,CAAA;QACJ,CAAC;IACH,CAAC;AACH,CAAC,CAAA;AAsBD;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,gCAAgC,GAAG,CAC9C,KAAQ,EACR,aAAa,GAAG,CAAC,EACjB,EAAE;IACF,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,KAAK,EAAE,CAAC;QAClE,MAAM,IAAI,SAAS,CAAC,uCAAuC,KAAK,GAAG,CAAC,CAAA;IACtE,CAAC;IAED,MAAM,cAAc,GAAG,KAAK,GAAG,aAAa,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,CAAA;IAC1D,MAAM,WAAW,GAAG,oBAAoB,CAAA;IAExC,OAAO,CAAC,IAAY,EAAE,GAAkB,EAA8B,EAAE;QACtE,IAAI,IAAI,CAAC,MAAM,GAAG,cAAc,EAAE,CAAC;YACjC,GAAG,CAAC,QAAQ,CAAC;gBACX,IAAI,EAAE,YAAY,CAAC,MAAM;gBACzB,OAAO,EAAE,GAAG,WAAW,aAAa;aACrC,CAAC,CAAA;YACF,OAAO,KAAK,CAAA;QACd,CAAC;QACD,IAAI,YAAY,GAAG,CAAC,CAAA;QACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YACnC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,YAAY,CAAC,CAAA;YAC/C,IAAI,OAAO,KAAK,CAAC,CAAC,EAAE,CAAC;gBACnB,GAAG,CAAC,QAAQ,CAAC;oBACX,IAAI,EAAE,YAAY,CAAC,MAAM;oBACzB,OAAO,EAAE,GAAG,WAAW,cAAc,KAAK,kBAAkB,CAAC,GAAG,CAAC,EAAE;iBACpE,CAAC,CAAA;gBACF,OAAO,KAAK,CAAA;YACd,CAAC;YACD,IAAI,OAAO,GAAG,YAAY,GAAG,aAAa,EAAE,CAAC;gBAC3C,GAAG,CAAC,QAAQ,CAAC;oBACX,IAAI,EAAE,YAAY,CAAC,MAAM;oBACzB,OAAO,EAAE,GAAG,WAAW,aAAa,CAAC,GAAG,CAAC,eAAe;iBACzD,CAAC,CAAA;gBACF,OAAO,KAAK,CAAA;YACd,CAAC;YACD,YAAY,GAAG,OAAO,GAAG,CAAC,CAAA;QAC5B,CAAC;QACD,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;YAC3C,GAAG,CAAC,QAAQ,CAAC;gBACX,IAAI,EAAE,YAAY,CAAC,MAAM;gBACzB,OAAO,EAAE,GAAG,WAAW,qBAAqB;aAC7C,CAAC,CAAA;YACF,OAAO,KAAK,CAAA;QACd,CAAC;QACD,IAAI,IAAI,CAAC,MAAM,GAAG,YAAY,GAAG,aAAa,EAAE,CAAC;YAC/C,GAAG,CAAC,QAAQ,CAAC;gBACX,IAAI,EAAE,YAAY,CAAC,MAAM;gBACzB,OAAO,EAAE,GAAG,WAAW,6BAA6B;aACrD,CAAC,CAAA;YACF,OAAO,KAAK,CAAA;QACd,CAAC;QACD,OAAO,IAAI,CAAA;IACb,CAAC,CAAA;AACH,CAAC,CAAA;AAED,MAAM,UAAU,gBAAgB,CAE9B,CAAI,EAAE,CAAS,EAAE,GAAiB;IAClC,OAAO,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAA;AACrC,CAAC","sourcesContent":["import { base64url } from 'multiformats/bases/base64'\nimport { RefinementCtx, ZodIssueCode } from 'zod'\n\nexport type Simplify<T> = { [K in keyof T]: T[K] } & {}\nexport type Override<T, V> = Simplify<V & Omit<T, keyof V>>\n\nexport type RequiredKey<T, K extends keyof T = never> = Simplify<\n T & {\n [L in K]-?: unknown extends T[L]\n ? NonNullable<unknown> | null\n : Exclude<T[L], undefined>\n }\n>\n\nexport const isDefined = <T>(i: T | undefined): i is T => i !== undefined\n\nexport const preferredOrderCmp =\n <T>(order: readonly T[]) =>\n (a: T, b: T) => {\n const aIdx = order.indexOf(a)\n const bIdx = order.indexOf(b)\n if (aIdx === bIdx) return 0\n if (aIdx === -1) return 1\n if (bIdx === -1) return -1\n return aIdx - bIdx\n }\n\n/* eslint-disable @typescript-eslint/no-unused-vars -- `v` is used at runtime in the returned type guards; v8 false-positive */\nexport function matchesAny<T extends string | number | symbol | boolean>(\n value: null | undefined | T | readonly T[],\n): (v: unknown) => v is T {\n return value == null\n ? (v): v is T => true\n : Array.isArray(value)\n ? (v): v is T => value.includes(v)\n : (v): v is T => v === value\n}\n/* eslint-enable @typescript-eslint/no-unused-vars */\n\n/**\n * Decorator to cache the result of a getter on a class instance.\n */\nexport const cachedGetter = <T extends object, V>(\n target: (this: T) => V,\n _context: ClassGetterDecoratorContext<T, V>,\n) => {\n return function (this: T) {\n const value = target.call(this)\n Object.defineProperty(this, target.name, {\n get: () => value,\n enumerable: true,\n configurable: true,\n })\n return value\n }\n}\n\nconst decoder = new TextDecoder()\nexport function parseB64uJson(input: string): unknown {\n const inputBytes = base64url.baseDecode(input)\n const json = decoder.decode(inputBytes)\n return JSON.parse(json)\n}\n\n/**\n * @example\n * ```ts\n * // jwtSchema will only allow base64url chars & \".\" (dot)\n * const jwtSchema = z.string().superRefine(jwtCharsRefinement)\n * ```\n */\nexport const jwtCharsRefinement = (data: string, ctx: RefinementCtx): void => {\n // Note: this is a hot path, let's avoid using a RegExp\n let char\n\n for (let i = 0; i < data.length; i++) {\n char = data.charCodeAt(i)\n\n if (\n // Base64 URL encoding (most frequent)\n (65 <= char && char <= 90) || // A-Z\n (97 <= char && char <= 122) || // a-z\n (48 <= char && char <= 57) || // 0-9\n char === 45 || // -\n char === 95 || // _\n // Boundary (least frequent, check last)\n char === 46 // .\n ) {\n // continue\n } else {\n // Invalid char might be a surrogate pair\n const invalidChar = String.fromCodePoint(data.codePointAt(i)!)\n return ctx.addIssue({\n code: ZodIssueCode.custom,\n message: `Invalid character \"${invalidChar}\" in JWT at position ${i}`,\n })\n }\n }\n}\n\n/**\n * @example\n * ```ts\n * type SegmentedString3 = SegmentedString<3> // `${string}.${string}.${string}`\n * type SegmentedString4 = SegmentedString<4> // `${string}.${string}.${string}.${string}`\n * ```\n *\n * @note\n * This utility only provides one way type safety (A SegmentedString<4> can be\n * assigned to SegmentedString<3> but not vice versa). The purpose of this\n * utility is to improve DX by avoiding as many potential errors as build time.\n * DO NOT rely on this to enforce security or data integrity.\n */\ntype SegmentedString<\n C extends number,\n Acc extends string[] = [string],\n> = Acc['length'] extends C\n ? `${Acc[0]}`\n : `${Acc[0]}.${SegmentedString<C, [string, ...Acc]>}`\n\n/**\n * @example\n * ```ts\n * const jwtSchema = z.string().superRefine(segmentedStringRefinementFactory(3))\n * type Jwt = z.infer<typeof jwtSchema> // `${string}.${string}.${string}`\n * ```\n */\nexport const segmentedStringRefinementFactory = <C extends number>(\n count: C,\n minPartLength = 2,\n) => {\n if (!Number.isFinite(count) || count < 1 || (count | 0) !== count) {\n throw new TypeError(`Count must be a natural number (got ${count})`)\n }\n\n const minTotalLength = count * minPartLength + (count - 1)\n const errorPrefix = `Invalid JWT format`\n\n return (data: string, ctx: RefinementCtx): data is SegmentedString<C> => {\n if (data.length < minTotalLength) {\n ctx.addIssue({\n code: ZodIssueCode.custom,\n message: `${errorPrefix}: too short`,\n })\n return false\n }\n let currentStart = 0\n for (let i = 0; i < count - 1; i++) {\n const nextDot = data.indexOf('.', currentStart)\n if (nextDot === -1) {\n ctx.addIssue({\n code: ZodIssueCode.custom,\n message: `${errorPrefix}: expected ${count} segments, got ${i + 1}`,\n })\n return false\n }\n if (nextDot - currentStart < minPartLength) {\n ctx.addIssue({\n code: ZodIssueCode.custom,\n message: `${errorPrefix}: segment ${i + 1} is too short`,\n })\n return false\n }\n currentStart = nextDot + 1\n }\n if (data.indexOf('.', currentStart) !== -1) {\n ctx.addIssue({\n code: ZodIssueCode.custom,\n message: `${errorPrefix}: too many segments`,\n })\n return false\n }\n if (data.length - currentStart < minPartLength) {\n ctx.addIssue({\n code: ZodIssueCode.custom,\n message: `${errorPrefix}: last segment is too short`,\n })\n return false\n }\n return true\n }\n}\n\nexport function isLastOccurrence<\n T extends number | boolean | string | null | undefined | symbol | bigint,\n>(v: T, i: number, arr: readonly T[]): boolean {\n return arr.indexOf(v, i + 1) === -1\n}\n"]}
|