repocairn 0.1.6 → 0.1.7

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 (62) hide show
  1. package/node_modules/fast-uri/index.js +201 -48
  2. package/node_modules/fast-uri/lib/schemes.js +9 -4
  3. package/node_modules/fast-uri/lib/utils.js +388 -91
  4. package/node_modules/fast-uri/package.json +1 -1
  5. package/node_modules/fast-uri/test/component-safe-serialization.test.js +105 -0
  6. package/node_modules/fast-uri/test/equal.test.js +31 -3
  7. package/node_modules/fast-uri/test/fixtures/uri-js-parse.json +2 -0
  8. package/node_modules/fast-uri/test/ipv6-canonical.test.js +34 -0
  9. package/node_modules/fast-uri/test/ipv6-validation.test.js +90 -0
  10. package/node_modules/fast-uri/test/malformed-percent.test.js +77 -0
  11. package/node_modules/fast-uri/test/malformed-urn.test.js +61 -0
  12. package/node_modules/fast-uri/test/parse.test.js +7 -3
  13. package/node_modules/fast-uri/test/query-fragment-normalization.test.js +33 -0
  14. package/node_modules/fast-uri/test/reserved-path-normalization.test.js +109 -0
  15. package/node_modules/fast-uri/test/scheme-validation.test.js +124 -0
  16. package/node_modules/fast-uri/test/security-normalization.test.js +101 -0
  17. package/node_modules/fast-uri/test/security.test.js +75 -3
  18. package/node_modules/fast-uri/test/urn-full-input.test.js +29 -0
  19. package/node_modules/fast-uri/test/websocket-query-preservation.test.js +24 -0
  20. package/node_modules/jose/dist/types/jwks/remote.d.ts +4 -4
  21. package/node_modules/jose/dist/types/jws/general/verify.d.ts +3 -3
  22. package/node_modules/jose/dist/types/jwt/encrypt.d.ts +8 -14
  23. package/node_modules/jose/dist/types/jwt/sign.d.ts +8 -14
  24. package/node_modules/jose/dist/types/jwt/unsecured.d.ts +9 -15
  25. package/node_modules/jose/dist/webapi/jwe/compact/encrypt.js +30 -8
  26. package/node_modules/jose/dist/webapi/jwe/flattened/decrypt.js +8 -4
  27. package/node_modules/jose/dist/webapi/jwe/flattened/encrypt.js +6 -13
  28. package/node_modules/jose/dist/webapi/jwe/general/decrypt.js +19 -19
  29. package/node_modules/jose/dist/webapi/jwe/general/encrypt.js +27 -20
  30. package/node_modules/jose/dist/webapi/jwk/embedded.js +15 -1
  31. package/node_modules/jose/dist/webapi/jwk/thumbprint.js +11 -5
  32. package/node_modules/jose/dist/webapi/jwks/local.js +45 -53
  33. package/node_modules/jose/dist/webapi/jwks/remote.js +82 -103
  34. package/node_modules/jose/dist/webapi/jws/compact/sign.js +10 -9
  35. package/node_modules/jose/dist/webapi/jws/flattened/sign.js +2 -1
  36. package/node_modules/jose/dist/webapi/jws/flattened/verify.js +8 -7
  37. package/node_modules/jose/dist/webapi/jws/general/sign.js +5 -3
  38. package/node_modules/jose/dist/webapi/jws/general/verify.js +51 -21
  39. package/node_modules/jose/dist/webapi/jwt/decrypt.js +7 -9
  40. package/node_modules/jose/dist/webapi/jwt/encrypt.js +21 -50
  41. package/node_modules/jose/dist/webapi/jwt/sign.js +8 -41
  42. package/node_modules/jose/dist/webapi/jwt/unsecured.js +21 -42
  43. package/node_modules/jose/dist/webapi/key/generate_key_pair.js +6 -2
  44. package/node_modules/jose/dist/webapi/key/generate_secret.js +7 -6
  45. package/node_modules/jose/dist/webapi/key/import.js +16 -12
  46. package/node_modules/jose/dist/webapi/lib/asn1.js +7 -2
  47. package/node_modules/jose/dist/webapi/lib/content_encryption.js +7 -15
  48. package/node_modules/jose/dist/webapi/lib/deflate.js +8 -0
  49. package/node_modules/jose/dist/webapi/lib/helpers.js +1 -1
  50. package/node_modules/jose/dist/webapi/lib/jwe_decrypt.js +85 -28
  51. package/node_modules/jose/dist/webapi/lib/jwe_encrypt.js +40 -12
  52. package/node_modules/jose/dist/webapi/lib/jwk_metadata.js +20 -0
  53. package/node_modules/jose/dist/webapi/lib/jws_sign.js +47 -36
  54. package/node_modules/jose/dist/webapi/lib/jws_verify.js +77 -45
  55. package/node_modules/jose/dist/webapi/lib/jwt_claims_set.js +82 -47
  56. package/node_modules/jose/dist/webapi/lib/key.js +24 -9
  57. package/node_modules/jose/dist/webapi/lib/key_management.js +10 -4
  58. package/node_modules/jose/dist/webapi/lib/key_options.js +6 -0
  59. package/node_modules/jose/dist/webapi/lib/options.js +26 -0
  60. package/node_modules/jose/dist/webapi/lib/type_checks.js +11 -13
  61. package/node_modules/jose/package.json +1 -1
  62. package/package.json +1 -1
@@ -37,3 +37,104 @@ test('equal does not treat reserved path escapes as live path syntax', (t) => {
37
37
 
38
38
  t.end()
39
39
  })
40
+
41
+ test('serialize preserves literal RFC 3986 reserved path characters', (t) => {
42
+ // GHSA-7mh8-fcmq-x23c: literal reserved path chars must not be rewritten to
43
+ // percent escapes by the escape()-style safe set.
44
+ const cases = [
45
+ 'http://example.com/a;b',
46
+ 'http://example.com/a=b',
47
+ 'http://example.com/a&b',
48
+ 'http://example.com/a$b',
49
+ 'http://example.com/a:b',
50
+ 'http://example.com/a@b'
51
+ ]
52
+
53
+ t.plan(cases.length)
54
+
55
+ cases.forEach((uri) => {
56
+ t.equal(fastURI.serialize(fastURI.parse(uri)), uri, uri)
57
+ })
58
+ t.end()
59
+ })
60
+
61
+ test('serialize preserves existing reserved path escapes as data', (t) => {
62
+ // GHSA-7mh8-fcmq-x23c: an existing %3A escape must stay %3A instead of being
63
+ // rewritten into a live colon.
64
+ const cases = [
65
+ 'http://example.com/a%3Ab',
66
+ 'http://example.com/a%3Bb',
67
+ 'http://example.com/a%3D%3D'
68
+ ]
69
+
70
+ t.plan(cases.length)
71
+
72
+ cases.forEach((uri) => {
73
+ t.equal(fastURI.serialize(fastURI.parse(uri)), uri, uri)
74
+ })
75
+ t.end()
76
+ })
77
+
78
+ test('serialize keeps path-noscheme colon escaping', (t) => {
79
+ // Without a scheme a literal colon would be reparsed as a scheme separator,
80
+ // so it must stay percent-escaped while an existing %3A is preserved.
81
+ t.equal(fastURI.serialize({ path: 'foo:bar' }), 'foo%3Abar')
82
+ t.equal(fastURI.serialize({ path: 'a%3Ab' }), 'a%3Ab')
83
+ t.end()
84
+ })
85
+
86
+ test('hostname normalization never decodes an escape more than once', (t) => {
87
+ const encodedLocalhost = 'http://%256c%256f%2563%2561%256c%2568%256f%2573%2574/'
88
+ const encodedLoopback = '//127%252e0%252e0%252e1/private'
89
+ const encodedMetadataAddress = '//169%252E254%252E169%252E254/latest/meta-data/'
90
+
91
+ t.equal(fastURI.normalize(encodedLocalhost), encodedLocalhost, 'nested hostname letters remain encoded')
92
+ t.equal(fastURI.normalize(encodedLoopback), encodedLoopback, 'nested IPv4 dots remain encoded')
93
+ t.equal(
94
+ fastURI.resolve('https://safe.example/', encodedLoopback),
95
+ 'https://127%252e0%252e0%252e1/private',
96
+ 'resolve does not turn nested dots into a loopback address'
97
+ )
98
+ t.equal(
99
+ fastURI.resolve('https://allowed.com/api/v1/', encodedMetadataAddress),
100
+ 'https://169%252e254%252e169%252e254/latest/meta-data/',
101
+ 'resolve does not turn nested dots into a metadata address'
102
+ )
103
+ t.equal(
104
+ fastURI.normalize('http://allowed.com%255Cevil.com/'),
105
+ 'http://allowed.com%255Cevil.com/',
106
+ 'normalize does not activate a nested backslash'
107
+ )
108
+ t.equal(
109
+ fastURI.serialize({ scheme: 'http', host: '%256cocalhost', path: '/' }),
110
+ 'http://%256cocalhost/',
111
+ 'component serialization preserves an encoded percent sign'
112
+ )
113
+ t.equal(
114
+ fastURI.equal(encodedLocalhost, 'http://localhost/', {}),
115
+ false,
116
+ 'nested escapes do not compare equal to their twice-decoded target'
117
+ )
118
+ t.end()
119
+ })
120
+
121
+ test('hostname normalization decodes only current unreserved escapes', (t) => {
122
+ t.equal(fastURI.normalize('x://%6cocalhost/'), 'x://localhost/', 'a current unreserved escape is decoded')
123
+ t.equal(fastURI.normalize('x://%256cocalhost/'), 'x://%256cocalhost/', 'an encoded percent is preserved')
124
+ t.equal(fastURI.normalize('x://host%2540evil/'), 'x://host%2540evil/', 'a nested authority delimiter stays inert')
125
+ t.equal(fastURI.normalize('x://%2525/'), 'x://%2525/', 'nested encoded percent signs stay encoded')
126
+ t.end()
127
+ })
128
+
129
+ test('host conversion failures are not treated as comparable URLs', (t) => {
130
+ const malformedHost = 'http://trusted.test%2540evil.test/'
131
+
132
+ t.equal(fastURI.normalize(malformedHost), malformedHost, 'normalization preserves the failing input')
133
+ t.equal(fastURI.equal(malformedHost, malformedHost, {}), false, 'equal rejects a failed host conversion')
134
+ t.throws(
135
+ () => fastURI.resolve(malformedHost, 'child', { domainHost: true }),
136
+ /Host's domain name can not be converted to ASCII/,
137
+ 'resolve propagates a host conversion failure'
138
+ )
139
+ t.end()
140
+ })
@@ -125,11 +125,13 @@ test('serialize escapes authority delimiters in host field', (t) => {
125
125
  })
126
126
 
127
127
  test('normalize does not double-decode %2540 into a live @', (t) => {
128
- const result = fastURI.normalize('http://trusted.com%2540evil.com/')
128
+ const input = 'http://trusted.com%2540evil.com/'
129
+ const result = fastURI.normalize(input)
129
130
  const parsed = fastURI.parse(result)
130
131
 
131
- t.plan(1)
132
- t.notEqual(parsed.host, 'trusted.com@evil.com', 'http://trusted.com%2540evil.com/')
132
+ t.plan(2)
133
+ t.equal(result, input, 'the encoded percent sign is preserved')
134
+ t.notEqual(parsed.host, 'trusted.com@evil.com', input)
133
135
  })
134
136
 
135
137
  test('parse canonicalises IDN / Unicode hosts to their ASCII form', (t) => {
@@ -160,6 +162,76 @@ test('parse canonicalises IDN / Unicode hosts to their ASCII form', (t) => {
160
162
  })
161
163
  })
162
164
 
165
+ test('resolve canonicalises the host using the final resolved scheme', (t) => {
166
+ const cases = [
167
+ {
168
+ base: 'http://trusted.example/base',
169
+ relative: '//127\u30020\u30020\u30021/private',
170
+ expected: 'http://127.0.0.1/private',
171
+ expectedHost: '127.0.0.1',
172
+ description: 'scheme-relative loopback host'
173
+ },
174
+ {
175
+ base: 'https://ex\u00ADample.com/base',
176
+ relative: 'child',
177
+ expected: 'https://example.com/child',
178
+ expectedHost: 'example.com',
179
+ description: 'host inherited from the base'
180
+ },
181
+ {
182
+ base: 'http://trusted.example/base',
183
+ relative: 'http://ex\u200Bample.com/',
184
+ expected: 'http://example.com/',
185
+ expectedHost: 'example.com',
186
+ description: 'absolute relative reference'
187
+ }
188
+ ]
189
+
190
+ t.plan(cases.length * 2)
191
+
192
+ cases.forEach(({ base, relative, expected, expectedHost, description }) => {
193
+ const resolved = fastURI.resolve(base, relative)
194
+ t.equal(resolved, expected, description)
195
+ t.equal(fastURI.parse(resolved).host, expectedHost, `${description} reparses consistently`)
196
+ })
197
+ })
198
+
199
+ test('resolve applies domain canonicalisation only when the effective scheme opts in', (t) => {
200
+ const host = 'ex\u00ADample.com'
201
+
202
+ t.plan(2)
203
+ t.equal(
204
+ fastURI.resolve('uri://trusted.example/', `//${host}/`),
205
+ `uri://${host}/`,
206
+ 'an unsupported scheme preserves the host'
207
+ )
208
+ t.equal(
209
+ fastURI.resolve('http://trusted.example/', `//${host}/`, { unicodeSupport: true }),
210
+ `http://${host}/`,
211
+ 'unicodeSupport preserves the Unicode host'
212
+ )
213
+ })
214
+
215
+ test('resolve throws when the final scheme cannot canonicalise the host', (t) => {
216
+ const invalidHost = '\u200D.example'
217
+ const cases = [
218
+ ['http://trusted.example/', `//${invalidHost}/`],
219
+ [`https://${invalidHost}/base`, 'child'],
220
+ ['http://trusted.example/', `http://${invalidHost}/`],
221
+ ['http://trusted.example/', `//${invalidHost}%2Etest/`]
222
+ ]
223
+
224
+ t.plan(cases.length)
225
+
226
+ cases.forEach(([base, relative]) => {
227
+ t.throws(
228
+ () => fastURI.resolve(base, relative),
229
+ /Host's domain name can not be converted to ASCII/,
230
+ `${base} + ${relative}`
231
+ )
232
+ })
233
+ })
234
+
163
235
  test('parse rejects a literal backslash in the authority as malformed (RFC 3986)', (t) => {
164
236
  // Regression for the host-confusion bypass: a literal "\" is invalid RFC 3986
165
237
  // syntax and must be flagged malformed, not silently rewritten. Otherwise "\"
@@ -0,0 +1,29 @@
1
+ 'use strict'
2
+
3
+ const test = require('tape')
4
+ const fastURI = require('..')
5
+
6
+ test('URN parsing validates the complete scheme-specific input', (t) => {
7
+ const embedded = fastURI.parse('urn:x|foo:bar')
8
+ t.equal(embedded.error, 'URN can not be parsed.', 'does not search for a later nid:nss substring')
9
+ t.equal(embedded.nid, undefined, 'does not adopt the later nid')
10
+ t.equal(embedded.nss, undefined, 'does not adopt the later nss')
11
+
12
+ const trailing = fastURI.parse('urn:foo:bar|ignored')
13
+ t.equal(trailing.error, 'URN can not be parsed.', 'rejects trailing input outside the RFC 2141 NSS grammar')
14
+ t.equal(trailing.nid, undefined, 'does not return an nid from a partial match')
15
+ t.equal(trailing.nss, undefined, 'does not return a truncated nss')
16
+
17
+ t.end()
18
+ })
19
+
20
+ test('URN parsing preserves the complete RFC 2141 NSS', (t) => {
21
+ const parsed = fastURI.parse('urn:foo:allowed/evil')
22
+ t.equal(parsed.error, undefined, 'accepts slash in an RFC 2141 NSS')
23
+ t.equal(parsed.nid, 'foo', 'parses the nid')
24
+ t.equal(parsed.nss, 'allowed/evil', 'preserves the complete NSS')
25
+ t.equal(fastURI.normalize('urn:foo:allowed/evil'), 'urn:foo:allowed/evil', 'normalization retains slash data')
26
+ t.equal(fastURI.equal('urn:foo:allowed/evil', 'urn:foo:allowed'), false, 'distinct NSS values do not compare equal')
27
+
28
+ t.end()
29
+ })
@@ -0,0 +1,24 @@
1
+ 'use strict'
2
+
3
+ const test = require('tape')
4
+ const fastURI = require('..')
5
+
6
+ test('WebSocket queries preserve additional question marks', (t) => {
7
+ for (const scheme of ['ws', 'wss']) {
8
+ const uri = `${scheme}://example.com/chat?a?b`
9
+ const truncatedURI = `${scheme}://example.com/chat?a`
10
+ const parsed = fastURI.parse(uri)
11
+
12
+ t.equal(parsed.resourceName, '/chat?a?b', `${scheme} parse preserves the resource name`)
13
+ t.equal(fastURI.serialize(parsed), uri, `${scheme} parsed components round-trip`)
14
+ t.equal(
15
+ fastURI.serialize({ scheme, host: 'example.com', resourceName: '/chat?a?b' }),
16
+ uri,
17
+ `${scheme} resource name serializes without truncation`
18
+ )
19
+ t.equal(fastURI.normalize(uri), uri, `${scheme} normalization preserves the full query`)
20
+ t.equal(fastURI.equal(uri, truncatedURI), false, `${scheme} equality distinguishes the full query`)
21
+ }
22
+
23
+ t.end()
24
+ })
@@ -36,17 +36,17 @@ export declare const jwksCache: unique symbol;
36
36
  export interface RemoteJWKSetOptions {
37
37
  /**
38
38
  * Timeout (in milliseconds) for the HTTP request. When reached the request will be aborted and
39
- * the verification will fail. Default is 5000 (5 seconds).
39
+ * the verification will fail. Must be a non-negative integer. Default is 5000 (5 seconds).
40
40
  */
41
41
  timeoutDuration?: number;
42
42
  /**
43
43
  * Duration (in milliseconds) for which no more HTTP requests will be triggered after a previous
44
- * successful fetch. Default is 30000 (30 seconds).
44
+ * successful fetch. Must not be `NaN`. Default is 30000 (30 seconds).
45
45
  */
46
46
  cooldownDuration?: number;
47
47
  /**
48
48
  * Maximum time (in milliseconds) between successful HTTP requests. Default is 600000 (10
49
- * minutes).
49
+ * minutes). Must not be `NaN`.
50
50
  */
51
51
  cacheMaxAge?: number | typeof Infinity;
52
52
  /** Headers to be sent with the HTTP request. */
@@ -60,7 +60,7 @@ export interface RemoteJWKSetOptions {
60
60
  export interface ExportedJWKSCache {
61
61
  /** Current cached JSON Web Key Set */
62
62
  jwks: types.JSONWebKeySet;
63
- /** Last updated at timestamp (seconds since epoch) */
63
+ /** Last updated at timestamp (milliseconds since epoch) */
64
64
  uat: number;
65
65
  }
66
66
  /** See {@link jwksCache}. */
@@ -11,9 +11,9 @@ export interface GeneralVerifyGetKey<KeyType extends types.CryptoKey | Uint8Arra
11
11
  * > Note: The function iterates over the `signatures` array in the General JWS and returns the verification
12
12
  * > result of the first signature entry that can be successfully verified. The result only contains
13
13
  * > the payload, protected header, and unprotected header of that successfully verified signature
14
- * > entry. Other signature entries in the General JWS are not validated, and their headers are not
15
- * > included in the returned result. Recipients of a General JWS should only rely on the returned
16
- * > (verified) data.
14
+ * > entry. Other signature entries' headers may be inspected solely to reject inconsistent use of the
15
+ * > JWS Unencoded Payload Option, and their headers are not included in the returned result.
16
+ * > Recipients of a General JWS should only rely on the returned (verified) data.
17
17
  *
18
18
  * @param jws General JWS.
19
19
  * @param key Key to verify the JWS with. See
@@ -1,20 +1,13 @@
1
1
  import type * as types from '../types.d.ts';
2
+ /**
3
+ * EncryptJWT constructor
4
+ *
5
+ * @param payload The JWT Claims Set object. Defaults to an empty object.
6
+ */
7
+ declare const EncryptJWT_base: new (payload?: types.JWTPayload) => types.ProduceJWT;
2
8
  /** The EncryptJWT class is used to build and encrypt Compact JWE formatted JSON Web Tokens. */
3
- export declare class EncryptJWT implements types.ProduceJWT {
9
+ export declare class EncryptJWT extends EncryptJWT_base {
4
10
  #private;
5
- /**
6
- * {@link EncryptJWT} constructor
7
- *
8
- * @param payload The JWT Claims Set object. Defaults to an empty object.
9
- */
10
- constructor(payload?: types.JWTPayload);
11
- setIssuer(issuer: string): this;
12
- setSubject(subject: string): this;
13
- setAudience(audience: string | string[]): this;
14
- setJti(jwtId: string): this;
15
- setNotBefore(input: number | string | Date): this;
16
- setExpirationTime(input: number | string | Date): this;
17
- setIssuedAt(input?: number | string | Date): this;
18
11
  /**
19
12
  * Sets the JWE Protected Header on the EncryptJWT object.
20
13
  *
@@ -66,3 +59,4 @@ export declare class EncryptJWT implements types.ProduceJWT {
66
59
  */
67
60
  encrypt(key: types.KeyInput, options?: types.EncryptOptions): Promise<string>;
68
61
  }
62
+ export {};
@@ -1,20 +1,13 @@
1
1
  import type * as types from '../types.d.ts';
2
+ /**
3
+ * SignJWT constructor
4
+ *
5
+ * @param payload The JWT Claims Set object. Defaults to an empty object.
6
+ */
7
+ declare const SignJWT_base: new (payload?: types.JWTPayload) => types.ProduceJWT;
2
8
  /** The SignJWT class is used to build and sign Compact JWS formatted JSON Web Tokens. */
3
- export declare class SignJWT implements types.ProduceJWT {
9
+ export declare class SignJWT extends SignJWT_base {
4
10
  #private;
5
- /**
6
- * {@link SignJWT} constructor
7
- *
8
- * @param payload The JWT Claims Set object. Defaults to an empty object.
9
- */
10
- constructor(payload?: types.JWTPayload);
11
- setIssuer(issuer: string): this;
12
- setSubject(subject: string): this;
13
- setAudience(audience: string | string[]): this;
14
- setJti(jwtId: string): this;
15
- setNotBefore(input: number | string | Date): this;
16
- setExpirationTime(input: number | string | Date): this;
17
- setIssuedAt(input?: number | string | Date): this;
18
11
  /**
19
12
  * Sets the JWS Protected Header on the SignJWT object.
20
13
  *
@@ -30,3 +23,4 @@ export declare class SignJWT implements types.ProduceJWT {
30
23
  */
31
24
  sign(key: types.KeyInput, options?: types.SignOptions): Promise<string>;
32
25
  }
26
+ export {};
@@ -6,24 +6,17 @@ export interface UnsecuredResult<PayloadType = types.JWTPayload> {
6
6
  /** The decoded JOSE Header; always `{ "alg": "none" }` for an Unsecured JWT. */
7
7
  header: types.JWSHeaderParameters;
8
8
  }
9
+ /**
10
+ * UnsecuredJWT constructor
11
+ *
12
+ * @param payload The JWT Claims Set object. Defaults to an empty object.
13
+ */
14
+ declare const UnsecuredJWT_base: new (payload?: types.JWTPayload) => types.ProduceJWT;
9
15
  /** The UnsecuredJWT class is a utility for dealing with `{ "alg": "none" }` Unsecured JWTs. */
10
- export declare class UnsecuredJWT implements types.ProduceJWT {
11
- #private;
12
- /**
13
- * {@link UnsecuredJWT} constructor
14
- *
15
- * @param payload The JWT Claims Set object. Defaults to an empty object.
16
- */
17
- constructor(payload?: types.JWTPayload);
16
+ export declare class UnsecuredJWT extends UnsecuredJWT_base {
17
+ private jwt;
18
18
  /** Encodes the Unsecured JWT. */
19
19
  encode(): string;
20
- setIssuer(issuer: string): this;
21
- setSubject(subject: string): this;
22
- setAudience(audience: string | string[]): this;
23
- setJti(jwtId: string): this;
24
- setNotBefore(input: number | string | Date): this;
25
- setExpirationTime(input: number | string | Date): this;
26
- setIssuedAt(input?: number | string | Date): this;
27
20
  /**
28
21
  * Decodes an unsecured JWT.
29
22
  *
@@ -32,3 +25,4 @@ export declare class UnsecuredJWT implements types.ProduceJWT {
32
25
  */
33
26
  static decode<PayloadType = types.JWTPayload>(jwt: string, options?: types.JWTClaimVerificationOptions): UnsecuredResult<PayloadType>;
34
27
  }
28
+ export {};
@@ -1,27 +1,49 @@
1
- import { FlattenedEncrypt } from '../flattened/encrypt.js';
1
+ import { assertNotSet } from '../../lib/helpers.js';
2
+ import { assertUint8Array } from '../../lib/type_checks.js';
3
+ import { createJWE } from '../../lib/jwe_encrypt.js';
2
4
  export class CompactEncrypt {
3
- #flattened;
5
+ #plaintext;
6
+ #protectedHeader;
7
+ #cek;
8
+ #iv;
9
+ #keyManagementParameters;
4
10
  constructor(plaintext) {
5
- this.#flattened = new FlattenedEncrypt(plaintext);
11
+ assertUint8Array(plaintext, 'plaintext');
12
+ this.#plaintext = plaintext;
6
13
  }
7
14
  setContentEncryptionKey(cek) {
8
- this.#flattened.setContentEncryptionKey(cek);
15
+ assertNotSet(this.#cek, 'setContentEncryptionKey');
16
+ this.#cek = cek;
9
17
  return this;
10
18
  }
11
19
  setInitializationVector(iv) {
12
- this.#flattened.setInitializationVector(iv);
20
+ assertNotSet(this.#iv, 'setInitializationVector');
21
+ this.#iv = iv;
13
22
  return this;
14
23
  }
15
24
  setProtectedHeader(protectedHeader) {
16
- this.#flattened.setProtectedHeader(protectedHeader);
25
+ assertNotSet(this.#protectedHeader, 'setProtectedHeader');
26
+ this.#protectedHeader = protectedHeader;
17
27
  return this;
18
28
  }
19
29
  setKeyManagementParameters(parameters) {
20
- this.#flattened.setKeyManagementParameters(parameters);
30
+ assertNotSet(this.#keyManagementParameters, 'setKeyManagementParameters');
31
+ this.#keyManagementParameters = parameters;
21
32
  return this;
22
33
  }
23
34
  async encrypt(key, options) {
24
- const jwe = await this.#flattened.encrypt(key, options);
35
+ const jwe = await createJWE([
36
+ this.#plaintext,
37
+ this.#protectedHeader,
38
+ undefined,
39
+ undefined,
40
+ undefined,
41
+ this.#cek,
42
+ this.#iv,
43
+ this.#keyManagementParameters,
44
+ undefined,
45
+ false,
46
+ ], key, options);
25
47
  return [jwe.protected, jwe.encrypted_key, jwe.iv, jwe.ciphertext, jwe.tag].join('.');
26
48
  }
27
49
  }
@@ -1,11 +1,15 @@
1
1
  import { JWEInvalid } from '../../util/errors.js';
2
2
  import { isObject } from '../../lib/type_checks.js';
3
- import { prepareDecrypt, decryptJWE, decryptResult, checkShared, checkRecipient, } from '../../lib/jwe_decrypt.js';
3
+ import { prepareDecrypt, decryptJWE, decryptResult, checkRecipient, snapshotSharedJWE, snapshotRecipientJWE, } from '../../lib/jwe_decrypt.js';
4
4
  export async function flattenedDecrypt(jwe, key, options) {
5
5
  if (!isObject(jwe)) {
6
6
  throw new JWEInvalid('Flattened JWE must be an object');
7
7
  }
8
- checkShared(jwe);
9
- checkRecipient(jwe);
10
- return decryptResult(jwe, await decryptJWE(jwe, prepareDecrypt(options), key));
8
+ const shared = snapshotSharedJWE(jwe);
9
+ const [recipient, , error] = snapshotRecipientJWE(jwe);
10
+ if (!recipient)
11
+ throw error;
12
+ const snapshot = { ...shared, ...recipient };
13
+ checkRecipient(snapshot);
14
+ return decryptResult(snapshot, await decryptJWE(snapshot, prepareDecrypt(options), key));
11
15
  }
@@ -1,7 +1,6 @@
1
- import { unprotected, assertNotSet } from '../../lib/helpers.js';
2
- import { JWEInvalid } from '../../util/errors.js';
1
+ import { assertNotSet } from '../../lib/helpers.js';
3
2
  import { createJWE } from '../../lib/jwe_encrypt.js';
4
- import { validateCritDuplicates } from '../../lib/options.js';
3
+ import { assertUint8Array } from '../../lib/type_checks.js';
5
4
  export class FlattenedEncrypt {
6
5
  #plaintext;
7
6
  #protectedHeader;
@@ -12,9 +11,7 @@ export class FlattenedEncrypt {
12
11
  #iv;
13
12
  #keyManagementParameters;
14
13
  constructor(plaintext) {
15
- if (!(plaintext instanceof Uint8Array)) {
16
- throw new TypeError('plaintext must be an instance of Uint8Array');
17
- }
14
+ assertUint8Array(plaintext, 'plaintext');
18
15
  this.#plaintext = plaintext;
19
16
  }
20
17
  setKeyManagementParameters(parameters) {
@@ -52,10 +49,6 @@ export class FlattenedEncrypt {
52
49
  return this;
53
50
  }
54
51
  async encrypt(key, options) {
55
- if (!this.#protectedHeader && !this.#unprotectedHeader && !this.#sharedUnprotectedHeader) {
56
- throw new JWEInvalid('either setProtectedHeader, setUnprotectedHeader, or sharedUnprotectedHeader must be called before #encrypt()');
57
- }
58
- validateCritDuplicates(JWEInvalid, this.#protectedHeader);
59
52
  return createJWE([
60
53
  this.#plaintext,
61
54
  this.#protectedHeader,
@@ -65,8 +58,8 @@ export class FlattenedEncrypt {
65
58
  this.#cek,
66
59
  this.#iv,
67
60
  this.#keyManagementParameters,
68
- options?.crit,
69
- options ? unprotected in options : false,
70
- ], key);
61
+ undefined,
62
+ false,
63
+ ], key, options);
71
64
  }
72
65
  }
@@ -1,46 +1,46 @@
1
- import { prepareDecrypt, shareJWE, decryptRecipient, decryptResult, checkShared, checkRecipient, } from '../../lib/jwe_decrypt.js';
1
+ import { prepareDecrypt, shareJWE, decryptRecipient, decryptResult, checkRecipient, snapshotSharedJWE, snapshotRecipientJWE, } from '../../lib/jwe_decrypt.js';
2
2
  import { JWEDecryptionFailed, JWEInvalid } from '../../util/errors.js';
3
3
  import { isObject } from '../../lib/type_checks.js';
4
4
  export async function generalDecrypt(jwe, key, options) {
5
5
  if (!isObject(jwe)) {
6
6
  throw new JWEInvalid('General JWE must be an object');
7
7
  }
8
- if (!Array.isArray(jwe.recipients) || !jwe.recipients.every(isObject)) {
8
+ const inputRecipients = jwe.recipients;
9
+ if (!Array.isArray(inputRecipients)) {
9
10
  throw new JWEInvalid('JWE Recipients missing or incorrect type');
10
11
  }
11
- if (!jwe.recipients.length) {
12
+ const recipients = Array.from(inputRecipients);
13
+ if (!recipients.every(isObject)) {
14
+ throw new JWEInvalid('JWE Recipients missing or incorrect type');
15
+ }
16
+ if (!recipients.length) {
12
17
  throw new JWEInvalid('JWE Recipients has no members');
13
18
  }
14
19
  let shared;
20
+ let sharedJwe;
15
21
  let token;
16
22
  try {
17
- checkShared(jwe);
18
23
  shared = prepareDecrypt(options);
19
- token = shareJWE(jwe);
24
+ sharedJwe = snapshotSharedJWE(jwe);
25
+ token = shareJWE(sharedJwe);
20
26
  }
21
27
  catch {
22
28
  throw new JWEDecryptionFailed();
23
29
  }
24
- if (jwe.recipients.length > 1) {
25
- for (const { header } of jwe.recipients) {
26
- const alg = token[0]?.alg ?? header?.alg ?? jwe.unprotected?.alg;
30
+ const recipientSnapshots = recipients.map((recipient) => snapshotRecipientJWE(recipient));
31
+ if (recipients.length > 1) {
32
+ for (const [, headerAlg] of recipientSnapshots) {
33
+ const alg = token[0]?.alg ?? headerAlg ?? sharedJwe.unprotected?.alg;
27
34
  if (alg === 'dir' || alg === 'ECDH-ES') {
28
35
  throw new JWEInvalid(`"${alg}" alg may only have a single recipient`);
29
36
  }
30
37
  }
31
38
  }
32
- for (const recipient of jwe.recipients) {
39
+ for (const [recipient] of recipientSnapshots) {
40
+ if (!recipient)
41
+ continue;
33
42
  try {
34
- const flattened = {
35
- aad: jwe.aad,
36
- ciphertext: jwe.ciphertext,
37
- encrypted_key: recipient.encrypted_key,
38
- header: recipient.header,
39
- iv: jwe.iv,
40
- protected: jwe.protected,
41
- tag: jwe.tag,
42
- unprotected: jwe.unprotected,
43
- };
43
+ const flattened = { ...sharedJwe, ...recipient };
44
44
  checkRecipient(flattened);
45
45
  return decryptResult(flattened, await decryptRecipient(flattened, token, shared, key));
46
46
  }