@tachybase/plugin-auth-oidc 0.23.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/.turbo/turbo-build.log +12 -0
  2. package/README.md +11 -0
  3. package/README.zh-CN.md +38 -0
  4. package/client.d.ts +2 -0
  5. package/client.js +1 -0
  6. package/dist/client/OIDCButton.d.ts +9 -0
  7. package/dist/client/Options.d.ts +2 -0
  8. package/dist/client/index.d.ts +5 -0
  9. package/dist/client/index.js +3 -0
  10. package/dist/client/locale/index.d.ts +3 -0
  11. package/dist/constants.d.ts +3 -0
  12. package/dist/constants.js +34 -0
  13. package/dist/externalVersion.js +14 -0
  14. package/dist/index.d.ts +2 -0
  15. package/dist/index.js +39 -0
  16. package/dist/locale/en-US.json +40 -0
  17. package/dist/locale/es-ES.json +25 -0
  18. package/dist/locale/fr-FR.json +21 -0
  19. package/dist/locale/ko_KR.json +28 -0
  20. package/dist/locale/pt-BR.json +21 -0
  21. package/dist/locale/zh-CN.json +28 -0
  22. package/dist/node_modules/nanoid/.devcontainer.json +23 -0
  23. package/dist/node_modules/nanoid/LICENSE +20 -0
  24. package/dist/node_modules/nanoid/async/index.browser.cjs +69 -0
  25. package/dist/node_modules/nanoid/async/index.browser.js +69 -0
  26. package/dist/node_modules/nanoid/async/index.cjs +71 -0
  27. package/dist/node_modules/nanoid/async/index.d.ts +56 -0
  28. package/dist/node_modules/nanoid/async/index.js +71 -0
  29. package/dist/node_modules/nanoid/async/index.native.js +57 -0
  30. package/dist/node_modules/nanoid/async/package.json +12 -0
  31. package/dist/node_modules/nanoid/bin/nanoid.cjs +55 -0
  32. package/dist/node_modules/nanoid/index.browser.cjs +72 -0
  33. package/dist/node_modules/nanoid/index.browser.js +72 -0
  34. package/dist/node_modules/nanoid/index.cjs +1 -0
  35. package/dist/node_modules/nanoid/index.d.cts +91 -0
  36. package/dist/node_modules/nanoid/index.d.ts +91 -0
  37. package/dist/node_modules/nanoid/index.js +85 -0
  38. package/dist/node_modules/nanoid/nanoid.js +1 -0
  39. package/dist/node_modules/nanoid/non-secure/index.cjs +34 -0
  40. package/dist/node_modules/nanoid/non-secure/index.d.ts +33 -0
  41. package/dist/node_modules/nanoid/non-secure/index.js +34 -0
  42. package/dist/node_modules/nanoid/non-secure/package.json +6 -0
  43. package/dist/node_modules/nanoid/package.json +1 -0
  44. package/dist/node_modules/nanoid/url-alphabet/index.cjs +7 -0
  45. package/dist/node_modules/nanoid/url-alphabet/index.js +7 -0
  46. package/dist/node_modules/nanoid/url-alphabet/package.json +6 -0
  47. package/dist/node_modules/openid-client/lib/client.js +1884 -0
  48. package/dist/node_modules/openid-client/lib/device_flow_handle.js +125 -0
  49. package/dist/node_modules/openid-client/lib/errors.js +55 -0
  50. package/dist/node_modules/openid-client/lib/helpers/assert.js +24 -0
  51. package/dist/node_modules/openid-client/lib/helpers/base64url.js +13 -0
  52. package/dist/node_modules/openid-client/lib/helpers/client.js +208 -0
  53. package/dist/node_modules/openid-client/lib/helpers/consts.js +7 -0
  54. package/dist/node_modules/openid-client/lib/helpers/decode_jwt.js +27 -0
  55. package/dist/node_modules/openid-client/lib/helpers/deep_clone.js +1 -0
  56. package/dist/node_modules/openid-client/lib/helpers/defaults.js +27 -0
  57. package/dist/node_modules/openid-client/lib/helpers/generators.js +14 -0
  58. package/dist/node_modules/openid-client/lib/helpers/is_key_object.js +4 -0
  59. package/dist/node_modules/openid-client/lib/helpers/is_plain_object.js +1 -0
  60. package/dist/node_modules/openid-client/lib/helpers/issuer.js +111 -0
  61. package/dist/node_modules/openid-client/lib/helpers/keystore.js +298 -0
  62. package/dist/node_modules/openid-client/lib/helpers/merge.js +24 -0
  63. package/dist/node_modules/openid-client/lib/helpers/pick.js +9 -0
  64. package/dist/node_modules/openid-client/lib/helpers/process_response.js +71 -0
  65. package/dist/node_modules/openid-client/lib/helpers/request.js +200 -0
  66. package/dist/node_modules/openid-client/lib/helpers/unix_timestamp.js +1 -0
  67. package/dist/node_modules/openid-client/lib/helpers/weak_cache.js +1 -0
  68. package/dist/node_modules/openid-client/lib/helpers/webfinger_normalize.js +71 -0
  69. package/dist/node_modules/openid-client/lib/helpers/www_authenticate_parser.js +14 -0
  70. package/dist/node_modules/openid-client/lib/index.js +1 -0
  71. package/dist/node_modules/openid-client/lib/issuer.js +192 -0
  72. package/dist/node_modules/openid-client/lib/issuer_registry.js +3 -0
  73. package/dist/node_modules/openid-client/lib/passport_strategy.js +205 -0
  74. package/dist/node_modules/openid-client/lib/token_set.js +35 -0
  75. package/dist/node_modules/openid-client/package.json +1 -0
  76. package/dist/node_modules/openid-client/types/index.d.ts +623 -0
  77. package/dist/server/actions/getAuthUrl.d.ts +2 -0
  78. package/dist/server/actions/getAuthUrl.js +47 -0
  79. package/dist/server/actions/redirect.d.ts +2 -0
  80. package/dist/server/actions/redirect.js +55 -0
  81. package/dist/server/index.d.ts +1 -0
  82. package/dist/server/index.js +33 -0
  83. package/dist/server/migrations/20231007124508-update-autosignup.d.ts +6 -0
  84. package/dist/server/migrations/20231007124508-update-autosignup.js +52 -0
  85. package/dist/server/oidc-auth.d.ts +15 -0
  86. package/dist/server/oidc-auth.js +154 -0
  87. package/dist/server/plugin.d.ts +11 -0
  88. package/dist/server/plugin.js +83 -0
  89. package/dist/swagger/index.d.ts +143 -0
  90. package/dist/swagger/index.js +178 -0
  91. package/package.json +37 -0
  92. package/server.d.ts +2 -0
  93. package/server.js +1 -0
@@ -0,0 +1,298 @@
1
+ const jose = require('jose');
2
+
3
+ const clone = require('./deep_clone');
4
+ const isPlainObject = require('./is_plain_object');
5
+
6
+ const internal = Symbol();
7
+
8
+ const keyscore = (key, { alg, use }) => {
9
+ let score = 0;
10
+
11
+ if (alg && key.alg) {
12
+ score++;
13
+ }
14
+
15
+ if (use && key.use) {
16
+ score++;
17
+ }
18
+
19
+ return score;
20
+ };
21
+
22
+ function getKtyFromAlg(alg) {
23
+ switch (typeof alg === 'string' && alg.slice(0, 2)) {
24
+ case 'RS':
25
+ case 'PS':
26
+ return 'RSA';
27
+ case 'ES':
28
+ return 'EC';
29
+ case 'Ed':
30
+ return 'OKP';
31
+ default:
32
+ return undefined;
33
+ }
34
+ }
35
+
36
+ function getAlgorithms(use, alg, kty, crv) {
37
+ // Ed25519, Ed448, and secp256k1 always have "alg"
38
+ // OKP always has "use"
39
+ if (alg) {
40
+ return new Set([alg]);
41
+ }
42
+
43
+ switch (kty) {
44
+ case 'EC': {
45
+ let algs = [];
46
+
47
+ if (use === 'enc' || use === undefined) {
48
+ algs = algs.concat(['ECDH-ES', 'ECDH-ES+A128KW', 'ECDH-ES+A192KW', 'ECDH-ES+A256KW']);
49
+ }
50
+
51
+ if (use === 'sig' || use === undefined) {
52
+ switch (crv) {
53
+ case 'P-256':
54
+ case 'P-384':
55
+ algs = algs.concat([`ES${crv.slice(-3)}`]);
56
+ break;
57
+ case 'P-521':
58
+ algs = algs.concat(['ES512']);
59
+ break;
60
+ case 'secp256k1':
61
+ if (jose.cryptoRuntime === 'node:crypto') {
62
+ algs = algs.concat(['ES256K']);
63
+ }
64
+ break;
65
+ }
66
+ }
67
+
68
+ return new Set(algs);
69
+ }
70
+ case 'OKP': {
71
+ return new Set(['ECDH-ES', 'ECDH-ES+A128KW', 'ECDH-ES+A192KW', 'ECDH-ES+A256KW']);
72
+ }
73
+ case 'RSA': {
74
+ let algs = [];
75
+
76
+ if (use === 'enc' || use === undefined) {
77
+ algs = algs.concat(['RSA-OAEP', 'RSA-OAEP-256', 'RSA-OAEP-384', 'RSA-OAEP-512']);
78
+ if (jose.cryptoRuntime === 'node:crypto') {
79
+ algs = algs.concat(['RSA1_5']);
80
+ }
81
+ }
82
+
83
+ if (use === 'sig' || use === undefined) {
84
+ algs = algs.concat(['PS256', 'PS384', 'PS512', 'RS256', 'RS384', 'RS512']);
85
+ }
86
+
87
+ return new Set(algs);
88
+ }
89
+ default:
90
+ throw new Error('unreachable');
91
+ }
92
+ }
93
+
94
+ module.exports = class KeyStore {
95
+ #keys;
96
+
97
+ constructor(i, keys) {
98
+ if (i !== internal) throw new Error('invalid constructor call');
99
+ this.#keys = keys;
100
+ }
101
+
102
+ toJWKS() {
103
+ return {
104
+ keys: this.map(({ jwk: { d, p, q, dp, dq, qi, ...jwk } }) => jwk),
105
+ };
106
+ }
107
+
108
+ all({ alg, kid, use } = {}) {
109
+ if (!use || !alg) {
110
+ throw new Error();
111
+ }
112
+
113
+ const kty = getKtyFromAlg(alg);
114
+
115
+ const search = { alg, use };
116
+ return this.filter((key) => {
117
+ let candidate = true;
118
+
119
+ if (candidate && kty !== undefined && key.jwk.kty !== kty) {
120
+ candidate = false;
121
+ }
122
+
123
+ if (candidate && kid !== undefined && key.jwk.kid !== kid) {
124
+ candidate = false;
125
+ }
126
+
127
+ if (candidate && use !== undefined && key.jwk.use !== undefined && key.jwk.use !== use) {
128
+ candidate = false;
129
+ }
130
+
131
+ if (candidate && key.jwk.alg && key.jwk.alg !== alg) {
132
+ candidate = false;
133
+ } else if (!key.algorithms.has(alg)) {
134
+ candidate = false;
135
+ }
136
+
137
+ return candidate;
138
+ }).sort((first, second) => keyscore(second, search) - keyscore(first, search));
139
+ }
140
+
141
+ get(...args) {
142
+ return this.all(...args)[0];
143
+ }
144
+
145
+ static async fromJWKS(jwks, { onlyPublic = false, onlyPrivate = false } = {}) {
146
+ if (
147
+ !isPlainObject(jwks) ||
148
+ !Array.isArray(jwks.keys) ||
149
+ jwks.keys.some((k) => !isPlainObject(k) || !('kty' in k))
150
+ ) {
151
+ throw new TypeError('jwks must be a JSON Web Key Set formatted object');
152
+ }
153
+
154
+ const keys = [];
155
+
156
+ for (let jwk of jwks.keys) {
157
+ jwk = clone(jwk);
158
+ const { kty, kid, crv } = jwk;
159
+
160
+ let { alg, use } = jwk;
161
+
162
+ if (typeof kty !== 'string' || !kty) {
163
+ continue;
164
+ }
165
+
166
+ if (use !== undefined && use !== 'sig' && use !== 'enc') {
167
+ continue;
168
+ }
169
+
170
+ if (typeof alg !== 'string' && alg !== undefined) {
171
+ continue;
172
+ }
173
+
174
+ if (typeof kid !== 'string' && kid !== undefined) {
175
+ continue;
176
+ }
177
+
178
+ if (kty === 'EC' && use === 'sig') {
179
+ switch (crv) {
180
+ case 'P-256':
181
+ alg = 'ES256';
182
+ break;
183
+ case 'P-384':
184
+ alg = 'ES384';
185
+ break;
186
+ case 'P-521':
187
+ alg = 'ES512';
188
+ break;
189
+ default:
190
+ break;
191
+ }
192
+ }
193
+
194
+ if (crv === 'secp256k1') {
195
+ use = 'sig';
196
+ alg = 'ES256K';
197
+ }
198
+
199
+ if (kty === 'OKP') {
200
+ switch (crv) {
201
+ case 'Ed25519':
202
+ case 'Ed448':
203
+ use = 'sig';
204
+ alg = 'EdDSA';
205
+ break;
206
+ case 'X25519':
207
+ case 'X448':
208
+ use = 'enc';
209
+ break;
210
+ default:
211
+ break;
212
+ }
213
+ }
214
+
215
+ if (alg && !use) {
216
+ switch (true) {
217
+ case alg.startsWith('ECDH'):
218
+ use = 'enc';
219
+ break;
220
+ case alg.startsWith('RSA'):
221
+ use = 'enc';
222
+ break;
223
+ default:
224
+ break;
225
+ }
226
+ }
227
+
228
+ if (onlyPrivate && (jwk.kty === 'oct' || !jwk.d)) {
229
+ throw new Error('jwks must only contain private keys');
230
+ }
231
+
232
+ if (onlyPublic && (jwk.d || jwk.k)) {
233
+ continue;
234
+ }
235
+
236
+ keys.push({
237
+ jwk: { ...jwk, alg, use },
238
+ async keyObject(alg) {
239
+ if (this[alg]) {
240
+ return this[alg];
241
+ }
242
+
243
+ const keyObject = await jose.importJWK(this.jwk, alg);
244
+ this[alg] = keyObject;
245
+ return keyObject;
246
+ },
247
+ get algorithms() {
248
+ Object.defineProperty(this, 'algorithms', {
249
+ value: getAlgorithms(this.jwk.use, this.jwk.alg, this.jwk.kty, this.jwk.crv),
250
+ enumerable: true,
251
+ configurable: false,
252
+ });
253
+ return this.algorithms;
254
+ },
255
+ });
256
+ }
257
+
258
+ return new this(internal, keys);
259
+ }
260
+
261
+ filter(...args) {
262
+ return this.#keys.filter(...args);
263
+ }
264
+
265
+ find(...args) {
266
+ return this.#keys.find(...args);
267
+ }
268
+
269
+ every(...args) {
270
+ return this.#keys.every(...args);
271
+ }
272
+
273
+ some(...args) {
274
+ return this.#keys.some(...args);
275
+ }
276
+
277
+ map(...args) {
278
+ return this.#keys.map(...args);
279
+ }
280
+
281
+ forEach(...args) {
282
+ return this.#keys.forEach(...args);
283
+ }
284
+
285
+ reduce(...args) {
286
+ return this.#keys.reduce(...args);
287
+ }
288
+
289
+ sort(...args) {
290
+ return this.#keys.sort(...args);
291
+ }
292
+
293
+ *[Symbol.iterator]() {
294
+ for (const key of this.#keys) {
295
+ yield key;
296
+ }
297
+ }
298
+ };
@@ -0,0 +1,24 @@
1
+ const isPlainObject = require('./is_plain_object');
2
+
3
+ function merge(target, ...sources) {
4
+ for (const source of sources) {
5
+ if (!isPlainObject(source)) {
6
+ continue;
7
+ }
8
+ for (const [key, value] of Object.entries(source)) {
9
+ /* istanbul ignore if */
10
+ if (key === '__proto__' || key === 'constructor') {
11
+ continue;
12
+ }
13
+ if (isPlainObject(target[key]) && isPlainObject(value)) {
14
+ target[key] = merge(target[key], value);
15
+ } else if (typeof value !== 'undefined') {
16
+ target[key] = value;
17
+ }
18
+ }
19
+ }
20
+
21
+ return target;
22
+ }
23
+
24
+ module.exports = merge;
@@ -0,0 +1,9 @@
1
+ module.exports = function pick(object, ...paths) {
2
+ const obj = {};
3
+ for (const path of paths) {
4
+ if (object[path] !== undefined) {
5
+ obj[path] = object[path];
6
+ }
7
+ }
8
+ return obj;
9
+ };
@@ -0,0 +1,71 @@
1
+ const { STATUS_CODES } = require('http');
2
+ const { format } = require('util');
3
+
4
+ const { OPError } = require('../errors');
5
+ const parseWwwAuthenticate = require('./www_authenticate_parser');
6
+
7
+ const throwAuthenticateErrors = (response) => {
8
+ const params = parseWwwAuthenticate(response.headers['www-authenticate']);
9
+
10
+ if (params.error) {
11
+ throw new OPError(params, response);
12
+ }
13
+ };
14
+
15
+ const isStandardBodyError = (response) => {
16
+ let result = false;
17
+ try {
18
+ let jsonbody;
19
+ if (typeof response.body !== 'object' || Buffer.isBuffer(response.body)) {
20
+ jsonbody = JSON.parse(response.body);
21
+ } else {
22
+ jsonbody = response.body;
23
+ }
24
+ result = typeof jsonbody.error === 'string' && jsonbody.error.length;
25
+ if (result) Object.defineProperty(response, 'body', { value: jsonbody, configurable: true });
26
+ } catch (err) {}
27
+
28
+ return result;
29
+ };
30
+
31
+ function processResponse(response, { statusCode = 200, body = true, bearer = false } = {}) {
32
+ if (response.statusCode !== statusCode) {
33
+ if (bearer) {
34
+ throwAuthenticateErrors(response);
35
+ }
36
+
37
+ if (isStandardBodyError(response)) {
38
+ throw new OPError(response.body, response);
39
+ }
40
+
41
+ throw new OPError(
42
+ {
43
+ error: format(
44
+ 'expected %i %s, got: %i %s',
45
+ statusCode,
46
+ STATUS_CODES[statusCode],
47
+ response.statusCode,
48
+ STATUS_CODES[response.statusCode],
49
+ ),
50
+ },
51
+ response,
52
+ );
53
+ }
54
+
55
+ if (body && !response.body) {
56
+ throw new OPError(
57
+ {
58
+ error: format(
59
+ 'expected %i %s with body but no body was returned',
60
+ statusCode,
61
+ STATUS_CODES[statusCode],
62
+ ),
63
+ },
64
+ response,
65
+ );
66
+ }
67
+
68
+ return response.body;
69
+ }
70
+
71
+ module.exports = processResponse;
@@ -0,0 +1,200 @@
1
+ const assert = require('assert');
2
+ const querystring = require('querystring');
3
+ const http = require('http');
4
+ const https = require('https');
5
+ const { once } = require('events');
6
+ const { URL } = require('url');
7
+
8
+ const LRU = require('lru-cache');
9
+
10
+ const pkg = require('../../package.json');
11
+ const { RPError } = require('../errors');
12
+
13
+ const pick = require('./pick');
14
+ const { deep: defaultsDeep } = require('./defaults');
15
+ const { HTTP_OPTIONS } = require('./consts');
16
+
17
+ let DEFAULT_HTTP_OPTIONS;
18
+ const NQCHAR = /^[\x21\x23-\x5B\x5D-\x7E]+$/;
19
+
20
+ const allowed = [
21
+ 'agent',
22
+ 'ca',
23
+ 'cert',
24
+ 'crl',
25
+ 'headers',
26
+ 'key',
27
+ 'lookup',
28
+ 'passphrase',
29
+ 'pfx',
30
+ 'timeout',
31
+ ];
32
+
33
+ const setDefaults = (props, options) => {
34
+ DEFAULT_HTTP_OPTIONS = defaultsDeep(
35
+ {},
36
+ props.length ? pick(options, ...props) : options,
37
+ DEFAULT_HTTP_OPTIONS,
38
+ );
39
+ };
40
+
41
+ setDefaults([], {
42
+ headers: {
43
+ 'User-Agent': `${pkg.name}/${pkg.version} (${pkg.homepage})`,
44
+ 'Accept-Encoding': 'identity',
45
+ },
46
+ timeout: 3500,
47
+ });
48
+
49
+ function send(req, body, contentType) {
50
+ if (contentType) {
51
+ req.removeHeader('content-type');
52
+ req.setHeader('content-type', contentType);
53
+ }
54
+ if (body) {
55
+ req.removeHeader('content-length');
56
+ req.setHeader('content-length', Buffer.byteLength(body));
57
+ req.write(body);
58
+ }
59
+ req.end();
60
+ }
61
+
62
+ const nonces = new LRU({ max: 100 });
63
+
64
+ module.exports = async function request(options, { accessToken, mTLS = false, DPoP } = {}) {
65
+ let url;
66
+ try {
67
+ url = new URL(options.url);
68
+ delete options.url;
69
+ assert(/^(https?:)$/.test(url.protocol));
70
+ } catch (err) {
71
+ throw new TypeError('only valid absolute URLs can be requested');
72
+ }
73
+ const optsFn = this[HTTP_OPTIONS];
74
+ let opts = options;
75
+
76
+ const nonceKey = `${url.origin}${url.pathname}`;
77
+ if (DPoP && 'dpopProof' in this) {
78
+ opts.headers = opts.headers || {};
79
+ opts.headers.DPoP = await this.dpopProof(
80
+ {
81
+ htu: `${url.origin}${url.pathname}`,
82
+ htm: options.method || 'GET',
83
+ nonce: nonces.get(nonceKey),
84
+ },
85
+ DPoP,
86
+ accessToken,
87
+ );
88
+ }
89
+
90
+ let userOptions;
91
+ if (optsFn) {
92
+ userOptions = pick(
93
+ optsFn.call(this, url, defaultsDeep({}, opts, DEFAULT_HTTP_OPTIONS)),
94
+ ...allowed,
95
+ );
96
+ }
97
+ opts = defaultsDeep({}, userOptions, opts, DEFAULT_HTTP_OPTIONS);
98
+
99
+ if (mTLS && !opts.pfx && !(opts.key && opts.cert)) {
100
+ throw new TypeError('mutual-TLS certificate and key not set');
101
+ }
102
+
103
+ if (opts.searchParams) {
104
+ for (const [key, value] of Object.entries(opts.searchParams)) {
105
+ url.searchParams.delete(key);
106
+ url.searchParams.set(key, value);
107
+ }
108
+ }
109
+
110
+ let responseType;
111
+ let form;
112
+ let json;
113
+ let body;
114
+ ({ form, responseType, json, body, ...opts } = opts);
115
+
116
+ for (const [key, value] of Object.entries(opts.headers || {})) {
117
+ if (value === undefined) {
118
+ delete opts.headers[key];
119
+ }
120
+ }
121
+
122
+ let response;
123
+ const req = (url.protocol === 'https:' ? https.request : http.request)(url.href, opts);
124
+ return (async () => {
125
+ if (json) {
126
+ send(req, JSON.stringify(json), 'application/json');
127
+ } else if (form) {
128
+ send(req, querystring.stringify(form), 'application/x-www-form-urlencoded');
129
+ } else if (body) {
130
+ send(req, body);
131
+ } else {
132
+ send(req);
133
+ }
134
+
135
+ [response] = await Promise.race([once(req, 'response'), once(req, 'timeout')]);
136
+
137
+ // timeout reached
138
+ if (!response) {
139
+ req.destroy();
140
+ throw new RPError(`outgoing request timed out after ${opts.timeout}ms`);
141
+ }
142
+
143
+ const parts = [];
144
+
145
+ for await (const part of response) {
146
+ parts.push(part);
147
+ }
148
+
149
+ if (parts.length) {
150
+ switch (responseType) {
151
+ case 'json': {
152
+ Object.defineProperty(response, 'body', {
153
+ get() {
154
+ let value = Buffer.concat(parts);
155
+ try {
156
+ value = JSON.parse(value);
157
+ } catch (err) {
158
+ Object.defineProperty(err, 'response', { value: response });
159
+ throw err;
160
+ } finally {
161
+ Object.defineProperty(response, 'body', { value, configurable: true });
162
+ }
163
+ return value;
164
+ },
165
+ configurable: true,
166
+ });
167
+ break;
168
+ }
169
+ case undefined:
170
+ case 'buffer': {
171
+ Object.defineProperty(response, 'body', {
172
+ get() {
173
+ const value = Buffer.concat(parts);
174
+ Object.defineProperty(response, 'body', { value, configurable: true });
175
+ return value;
176
+ },
177
+ configurable: true,
178
+ });
179
+ break;
180
+ }
181
+ default:
182
+ throw new TypeError('unsupported responseType request option');
183
+ }
184
+ }
185
+
186
+ return response;
187
+ })()
188
+ .catch((err) => {
189
+ if (response) Object.defineProperty(err, 'response', { value: response });
190
+ throw err;
191
+ })
192
+ .finally(() => {
193
+ const dpopNonce = response && response.headers['dpop-nonce'];
194
+ if (dpopNonce && NQCHAR.test(dpopNonce)) {
195
+ nonces.set(nonceKey, dpopNonce);
196
+ }
197
+ });
198
+ };
199
+
200
+ module.exports.setDefaults = setDefaults.bind(undefined, allowed);
@@ -0,0 +1 @@
1
+ module.exports = () => Math.floor(Date.now() / 1000);
@@ -0,0 +1 @@
1
+ module.exports.keystores = new WeakMap();
@@ -0,0 +1,71 @@
1
+ // Credit: https://github.com/rohe/pyoidc/blob/master/src/oic/utils/webfinger.py
2
+
3
+ // -- Normalization --
4
+ // A string of any other type is interpreted as a URI either the form of scheme
5
+ // "://" authority path-abempty [ "?" query ] [ "#" fragment ] or authority
6
+ // path-abempty [ "?" query ] [ "#" fragment ] per RFC 3986 [RFC3986] and is
7
+ // normalized according to the following rules:
8
+ //
9
+ // If the user input Identifier does not have an RFC 3986 [RFC3986] scheme
10
+ // portion, the string is interpreted as [userinfo "@"] host [":" port]
11
+ // path-abempty [ "?" query ] [ "#" fragment ] per RFC 3986 [RFC3986].
12
+ // If the userinfo component is present and all of the path component, query
13
+ // component, and port component are empty, the acct scheme is assumed. In this
14
+ // case, the normalized URI is formed by prefixing acct: to the string as the
15
+ // scheme. Per the 'acct' URI Scheme [I‑D.ietf‑appsawg‑acct‑uri], if there is an
16
+ // at-sign character ('@') in the userinfo component, it needs to be
17
+ // percent-encoded as described in RFC 3986 [RFC3986].
18
+ // For all other inputs without a scheme portion, the https scheme is assumed,
19
+ // and the normalized URI is formed by prefixing https:// to the string as the
20
+ // scheme.
21
+ // If the resulting URI contains a fragment portion, it MUST be stripped off
22
+ // together with the fragment delimiter character "#".
23
+ // The WebFinger [I‑D.ietf‑appsawg‑webfinger] Resource in this case is the
24
+ // resulting URI, and the WebFinger Host is the authority component.
25
+ //
26
+ // Note: Since the definition of authority in RFC 3986 [RFC3986] is
27
+ // [ userinfo "@" ] host [ ":" port ], it is legal to have a user input
28
+ // identifier like userinfo@host:port, e.g., alice@example.com:8080.
29
+
30
+ const PORT = /^\d+$/;
31
+
32
+ function hasScheme(input) {
33
+ if (input.includes('://')) return true;
34
+
35
+ const authority = input.replace(/(\/|\?)/g, '#').split('#')[0];
36
+ if (authority.includes(':')) {
37
+ const index = authority.indexOf(':');
38
+ const hostOrPort = authority.slice(index + 1);
39
+ if (!PORT.test(hostOrPort)) {
40
+ return true;
41
+ }
42
+ }
43
+
44
+ return false;
45
+ }
46
+
47
+ function acctSchemeAssumed(input) {
48
+ if (!input.includes('@')) return false;
49
+ const parts = input.split('@');
50
+ const host = parts[parts.length - 1];
51
+ return !(host.includes(':') || host.includes('/') || host.includes('?'));
52
+ }
53
+
54
+ function normalize(input) {
55
+ if (typeof input !== 'string') {
56
+ throw new TypeError('input must be a string');
57
+ }
58
+
59
+ let output;
60
+ if (hasScheme(input)) {
61
+ output = input;
62
+ } else if (acctSchemeAssumed(input)) {
63
+ output = `acct:${input}`;
64
+ } else {
65
+ output = `https://${input}`;
66
+ }
67
+
68
+ return output.split('#')[0];
69
+ }
70
+
71
+ module.exports = normalize;
@@ -0,0 +1,14 @@
1
+ const REGEXP = /(\w+)=("[^"]*")/g;
2
+
3
+ module.exports = (wwwAuthenticate) => {
4
+ const params = {};
5
+ try {
6
+ while (REGEXP.exec(wwwAuthenticate) !== null) {
7
+ if (RegExp.$1 && RegExp.$2) {
8
+ params[RegExp.$1] = RegExp.$2.slice(1, -1);
9
+ }
10
+ }
11
+ } catch (err) {}
12
+
13
+ return params;
14
+ };