unjwt 0.8.3 → 0.8.5
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/README.md +3 -9
- package/dist/_chunks/algorithms.mjs +1541 -0
- package/dist/_chunks/{_codec-jwe.d.mts → codec-jwe.d.mts} +40 -9
- package/dist/_chunks/{_codec-jws.mjs → codec-jws.mjs} +148 -95
- package/dist/_chunks/cookie.mjs +50 -0
- package/dist/_chunks/digest.mjs +10 -3
- package/dist/_chunks/error.d.mts +103 -0
- package/dist/_chunks/export.mjs +97 -0
- package/dist/_chunks/index.d.mts +5 -103
- package/dist/_chunks/index2.d.mts +206 -12
- package/dist/_chunks/index3.d.mts +12 -109
- package/dist/_chunks/{jwe.d.mts → index4.d.mts} +3 -1
- package/dist/_chunks/{jws.d.mts → index5.d.mts} +6 -2
- package/dist/_chunks/index6.d.mts +113 -0
- package/dist/_chunks/jwe.mjs +208 -74
- package/dist/_chunks/jwk.mjs +214 -2237
- package/dist/_chunks/jws.mjs +289 -202
- package/dist/_chunks/jwt.d.mts +2 -1
- package/dist/_chunks/{_jwt-internal.mjs → jwt.mjs} +124 -68
- package/dist/_chunks/libs/unsecure.d.mts +35 -25
- package/dist/_chunks/libs/unsecure.mjs +148 -302
- package/dist/_chunks/{_internal.d.mts → limits.d.mts} +1 -1
- package/dist/_chunks/payload.mjs +23 -0
- package/dist/_chunks/wrap.mjs +209 -0
- package/dist/adapters/elysia/index.d.mts +4 -4
- package/dist/adapters/elysia/index.mjs +5 -3
- package/dist/adapters/h3/index.d.mts +13 -13
- package/dist/adapters/h3/index.mjs +8 -10
- package/dist/adapters/h3v1/index.d.mts +5 -5
- package/dist/adapters/h3v1/index.mjs +6 -8
- package/dist/core/internal.mjs +1 -1
- package/dist/core/{jwe.d.mts → jwe/index.d.mts} +5 -4
- package/dist/core/jwe/index.mjs +5 -0
- package/dist/core/jwk/index.d.mts +6 -0
- package/dist/core/jwk/index.mjs +7 -0
- package/dist/core/{jws.d.mts → jws/index.d.mts} +5 -4
- package/dist/core/jws/index.mjs +5 -0
- package/dist/dpop/index.d.mts +73 -0
- package/dist/dpop/index.mjs +296 -0
- package/dist/error.d.mts +3 -0
- package/dist/error.mjs +20 -0
- package/dist/index.d.mts +10 -9
- package/dist/index.mjs +7 -3
- package/dist/session/index.d.mts +4 -4
- package/dist/session/index.mjs +6 -46
- package/dist/utils/index.d.mts +7 -0
- package/dist/{core/utils → utils}/index.mjs +4 -3
- package/package.json +22 -10
- package/dist/core/jwe.mjs +0 -5
- package/dist/core/jwk.d.mts +0 -207
- package/dist/core/jwk.mjs +0 -4
- package/dist/core/jws.mjs +0 -5
- package/dist/core/utils/index.d.mts +0 -6
- /package/dist/_chunks/{_cookie-attributes.d.mts → cookie-attributes.d.mts} +0 -0
|
@@ -1,109 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
* the URL-safe alphabet and set bits past the final byte are rejected, and a
|
|
14
|
-
* `string` result must be valid UTF-8. The return type mirrors the input unless
|
|
15
|
-
* `returnAs` is given. `{ loose: true }` drops what it cannot use instead of
|
|
16
|
-
* throwing: meant for application data, never for token material.
|
|
17
|
-
*
|
|
18
|
-
* @throws {UnsecureError} `MALFORMED` unless `loose`; `INVALID_TYPE` for input that is neither text nor bytes
|
|
19
|
-
*/
|
|
20
|
-
export declare function base64UrlParse<T extends DecodeReturnAs>(input: string | Uint8Array, options: DecodeOptions & {
|
|
21
|
-
returnAs: T;
|
|
22
|
-
}): T extends "string" ? string : Uint8Array<ArrayBuffer>;
|
|
23
|
-
export declare function base64UrlParse(input: string, options?: DecodeOptions): string;
|
|
24
|
-
export declare function base64UrlParse(input: Uint8Array, options?: DecodeOptions): Uint8Array<ArrayBuffer>;
|
|
25
|
-
/** Encode bytes or a UTF-8 string as standard base64 (RFC 4648 §4), with `=` padding. */
|
|
26
|
-
export declare function base64Stringify(data: string | BytesSource): string;
|
|
27
|
-
/**
|
|
28
|
-
* Decode standard base64 (RFC 4648 §4). Strict: the canonical encoding with its
|
|
29
|
-
* `=` padding present. Otherwise the same contract as {@link base64UrlParse}.
|
|
30
|
-
*
|
|
31
|
-
* @throws {UnsecureError} `MALFORMED` unless `loose`; `INVALID_TYPE` for input that is neither text nor bytes
|
|
32
|
-
*/
|
|
33
|
-
export declare function base64Parse<T extends DecodeReturnAs>(input: string | Uint8Array, options: DecodeOptions & {
|
|
34
|
-
returnAs: T;
|
|
35
|
-
}): T extends "string" ? string : Uint8Array<ArrayBuffer>;
|
|
36
|
-
export declare function base64Parse(input: string, options?: DecodeOptions): string;
|
|
37
|
-
export declare function base64Parse(input: Uint8Array, options?: DecodeOptions): Uint8Array<ArrayBuffer>;
|
|
38
|
-
/** @deprecated Renamed to {@link base64UrlStringify} in v0.8.0; removed in v0.9.0. */
|
|
39
|
-
export declare const base64UrlEncode: typeof base64UrlStringify;
|
|
40
|
-
/** @deprecated Renamed to {@link base64UrlParse} in v0.8.0; removed in v0.9.0. */
|
|
41
|
-
export declare const base64UrlDecode: typeof base64UrlParse;
|
|
42
|
-
/** @deprecated Renamed to {@link base64Stringify} in v0.8.0; removed in v0.9.0. */
|
|
43
|
-
export declare const base64Encode: typeof base64Stringify;
|
|
44
|
-
/** @deprecated Renamed to {@link base64Parse} in v0.8.0; removed in v0.9.0. */
|
|
45
|
-
export declare const base64Decode: typeof base64Parse;
|
|
46
|
-
/** Concatenate multiple `Uint8Array`s into a single contiguous buffer. */
|
|
47
|
-
export declare function concatUint8Arrays(...arrays: Readonly<Uint8Array<ArrayBuffer>[]>): Uint8Array<ArrayBuffer>;
|
|
48
|
-
/** Wrap a value in an array; returns the array unchanged if already an array. */
|
|
49
|
-
export declare function maybeArray<T>(item: T | T[]): T[];
|
|
50
|
-
/** Whether `key` is a JWK whose `kty` this library models (`oct`, `RSA`, `EC`, `OKP`). */
|
|
51
|
-
export declare function isJWK(key: unknown): key is JWK;
|
|
52
|
-
/** Whether `key` is an object with a `keys` array. */
|
|
53
|
-
export declare function isJWKSet(key: unknown): key is JWKSet;
|
|
54
|
-
/** Asserts that `key` is a `CryptoKey`; throws `ERR_JWK_INVALID` otherwise. */
|
|
55
|
-
export declare function assertCryptoKey(key: unknown): asserts key is CryptoKey;
|
|
56
|
-
/** Whether `key` is a `CryptoKey`, checked via `Symbol.toStringTag` to work across realms. */
|
|
57
|
-
export declare function isCryptoKey(key: unknown): key is CryptoKey;
|
|
58
|
-
/** Whether `key` is a `CryptoKeyPair` of two CryptoKeys. */
|
|
59
|
-
export declare const isCryptoKeyPair: (key: unknown) => key is CryptoKeyPair;
|
|
60
|
-
/** Whether the JWK is symmetric (`oct`); its `k` is always secret. */
|
|
61
|
-
export declare function isSymmetricJWK<T extends JWK>(key: T): key is Extract<T, JWK_oct>;
|
|
62
|
-
export declare function isSymmetricJWK(key: unknown): key is JWK_oct;
|
|
63
|
-
/** Whether the JWK is asymmetric (RSA, EC, OKP). */
|
|
64
|
-
export declare function isAsymmetricJWK<T extends JWK>(key: T): key is Exclude<T, JWK_oct>;
|
|
65
|
-
export declare function isAsymmetricJWK(key: unknown): key is Exclude<JWK, JWK_oct>;
|
|
66
|
-
/**
|
|
67
|
-
* Whether the JWK holds asymmetric private material (`d`). It is `false` for `oct` keys,
|
|
68
|
-
* so `!isPrivateJWK(key)` is not a "safe to publish" check; use `isPublicJWK`.
|
|
69
|
-
*/
|
|
70
|
-
export declare function isPrivateJWK<T extends JWK>(key: T): key is Extract<T, JWK_EC_Private | JWK_OKP_Private | JWK_RSA_Private>;
|
|
71
|
-
export declare function isPrivateJWK(key: unknown): key is JWK_Private;
|
|
72
|
-
/** Whether the JWK is an asymmetric public key without `d`: the "safe to publish" check. */
|
|
73
|
-
export declare function isPublicJWK<T extends JWK>(key: T): key is Exclude<Extract<T, JWK_EC_Public | JWK_OKP_Public | JWK_RSA_Public>, JWK_Private>;
|
|
74
|
-
export declare function isPublicJWK(key: unknown): key is JWK_Public;
|
|
75
|
-
/** How a JWK Set's entries are read during algorithm inference. */
|
|
76
|
-
export interface InferAlgorithmsOptions {
|
|
77
|
-
/** Admit `oct` entries of a JWK Set. Defaults to `false`. */
|
|
78
|
-
allowSymmetric?: boolean;
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Infer the JWS algorithms a key unambiguously supports, or `undefined` when it cannot
|
|
82
|
-
* (raw bytes, ambiguous JWK, lookup function) and `options.algorithms` must be passed.
|
|
83
|
-
*/
|
|
84
|
-
export declare function inferJWSAllowedAlgorithms(key: unknown, options?: InferAlgorithmsOptions): JWSAlgorithm[] | undefined;
|
|
85
|
-
/**
|
|
86
|
-
* Infer the JWE key management algorithms a key unambiguously supports, or `undefined`
|
|
87
|
-
* when it cannot; a password string infers the PBES2 variants, raw bytes nothing.
|
|
88
|
-
*/
|
|
89
|
-
export declare function inferJWEAllowedAlgorithms(key: unknown, options?: InferAlgorithmsOptions): KeyManagementAlgorithm[] | undefined;
|
|
90
|
-
/** @deprecated Use `ParsePayloadOptions` from `unjwt/internal`; removed in v0.9.0. */
|
|
91
|
-
export type DecodePayloadOptions = ParsePayloadOptions;
|
|
92
|
-
/** @deprecated Use `ComputeJwtTimeClaimsOptions` from `unjwt/internal`; removed in v0.9.0. */
|
|
93
|
-
export type ComputeJwtTimeClaimsOptions = ComputeJwtTimeClaimsOptions$1;
|
|
94
|
-
/** @deprecated Use `applyTypDefault` from `unjwt/internal`; removed in v0.9.0. */
|
|
95
|
-
export declare const applyTypCtyDefaults: typeof applyTypDefault;
|
|
96
|
-
/** @deprecated Use `parsePayloadBytes` from `unjwt/internal`; removed in v0.9.0. */
|
|
97
|
-
export declare const decodePayloadFromBytes: typeof parsePayloadBytes;
|
|
98
|
-
/** @deprecated Use `parsePayloadSegment` from `unjwt/internal`; removed in v0.9.0. */
|
|
99
|
-
export declare const decodePayloadFromB64UrlSegment: typeof parsePayloadSegment;
|
|
100
|
-
/** @deprecated Use `getPlaintextBytes` from `unjwt/internal`; removed in v0.9.0. */
|
|
101
|
-
export declare const getPlaintextBytes: typeof getPlaintextBytes$1;
|
|
102
|
-
/** @deprecated Use `computeJwtTimeClaims` from `unjwt/internal`; removed in v0.9.0. */
|
|
103
|
-
export declare const computeJwtTimeClaims: typeof computeJwtTimeClaims$1;
|
|
104
|
-
/** @deprecated Use `validateCriticalHeadersJWS` from `unjwt/internal`; removed in v0.9.0. */
|
|
105
|
-
export declare const validateCriticalHeadersJWS: typeof validateCriticalHeadersJWS$1;
|
|
106
|
-
/** @deprecated Use `validateCriticalHeadersJWE` from `unjwt/internal`; removed in v0.9.0. */
|
|
107
|
-
export declare const validateCriticalHeadersJWE: typeof validateCriticalHeadersJWE$1;
|
|
108
|
-
/** @deprecated Use `assertCritShape` from `unjwt/internal`; removed in v0.9.0. */
|
|
109
|
-
export declare const assertCritShape: typeof assertCritShape$1;
|
|
1
|
+
import { JWK } from "./index.mjs";
|
|
2
|
+
import { DigestHash } from "./digest.mjs";
|
|
3
|
+
/** Hash functions RFC 7638 §3.4 leaves open to the application. */
|
|
4
|
+
export type ThumbprintHash = DigestHash;
|
|
5
|
+
/**
|
|
6
|
+
* The base64url JWK Thumbprint of a key (RFC 7638), over its required members only, so a
|
|
7
|
+
* public key and its private counterpart share one. `hash` defaults to `"SHA-256"`
|
|
8
|
+
* (RFC 7638 §3.4); a missing required member or unknown `kty` throws `ERR_JWK_INVALID`.
|
|
9
|
+
*/
|
|
10
|
+
export declare function thumbprint(jwk: JWK, options?: {
|
|
11
|
+
hash?: ThumbprintHash;
|
|
12
|
+
}): Promise<string>;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import "./error.mjs";
|
|
1
2
|
import { ContentEncryptionAlgorithm, JOSEPayload, JOSEPayloadMode, JWEDecryptJWK, JWEDecryptOptions, JWEDecryptResult, JWEEncryptJWK, JWEEncryptOptions, JWEFlattenedSerialization, JWEGeneralSerialization, JWEKeyLookup, JWEMultiDecryptKey, JWEMultiDecryptOptions, JWEMultiDecryptResult, JWEMultiEncryptOptions, JWEMultiRecipient, JWKSet, JWTClaims, KeyManagementAlgorithm, PayloadOf } from "./index.mjs";
|
|
2
|
-
import "./
|
|
3
|
+
import "./limits.mjs";
|
|
3
4
|
/**
|
|
4
5
|
* Encrypt a payload to multiple recipients as JWE General JSON Serialization (RFC 7516 §7.2.1).
|
|
5
6
|
* Each recipient's `alg` comes from `key.alg` (`ERR_JWE_RECIPIENT_ALG_INFERENCE` when absent);
|
|
@@ -49,6 +50,7 @@ export declare function encrypt(payload: JOSEPayload, key: CryptoKey | JWEEncryp
|
|
|
49
50
|
/**
|
|
50
51
|
* Decrypt a JWE Compact Serialization string; `key` may be a lookup function.
|
|
51
52
|
* The payload type follows `options.payload` (claims `T` by default).
|
|
53
|
+
* A compact JWE has five sections (RFC 7516 §3).
|
|
52
54
|
*/
|
|
53
55
|
export declare function decrypt<T extends object = JWTClaims>(jwe: string, key: CryptoKey | JWKSet | JWEDecryptJWK | string | Uint8Array<ArrayBuffer> | JWEKeyLookup, options?: JWEDecryptOptions<"json"> & {
|
|
54
56
|
forceUint8Array?: false;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import "./error.mjs";
|
|
1
2
|
import { JOSEPayload, JOSEPayloadMode, JWKSet, JWSAlgorithm, JWSFlattenedSerialization, JWSGeneralSerialization, JWSKeyLookup, JWSMultiSignOptions, JWSMultiSigner, JWSMultiVerifyAllOptions, JWSMultiVerifyOptions, JWSMultiVerifyOutcome, JWSMultiVerifyResult, JWSSignJWK, JWSSignOptions, JWSVerifyJWK, JWSVerifyOptions, JWSVerifyResult, JWTClaims, PayloadOf } from "./index.mjs";
|
|
2
|
-
import "./
|
|
3
|
+
import "./limits.mjs";
|
|
3
4
|
/**
|
|
4
5
|
* Signs a payload with multiple signers as a JWS General JSON Serialization (RFC 7515 §7.2.1).
|
|
5
6
|
* Each signer's `alg` is inferred from its key when omitted (`ERR_JWS_SIGNER_ALG_INFERENCE`);
|
|
@@ -37,7 +38,10 @@ export declare function verifyMultiAll(jws: JWSGeneralSerialization | JWSFlatten
|
|
|
37
38
|
export declare function verifyMultiAll<Mode extends JOSEPayloadMode = JOSEPayloadMode>(jws: JWSGeneralSerialization | JWSFlattenedSerialization, keyResolver: JWSKeyLookup, options?: JWSMultiVerifyAllOptions<Mode>): Promise<JWSMultiVerifyOutcome<PayloadOf<Mode>>[]>;
|
|
38
39
|
/** Converts a single-signature General JWS to Flattened form (RFC 7515 §7.2.2); otherwise `ERR_JWS_INVALID_SERIALIZATION`. */
|
|
39
40
|
export declare function generalToFlattenedJWS(jws: JWSGeneralSerialization): JWSFlattenedSerialization;
|
|
40
|
-
/**
|
|
41
|
+
/**
|
|
42
|
+
* Creates a JWS Compact Serialization; an object payload is JSON-serialized, `alg` is required unless the JWK carries one.
|
|
43
|
+
* An unencoded (`b64: false`) compact payload cannot contain "." (RFC 7797 §5.2).
|
|
44
|
+
*/
|
|
41
45
|
export declare function sign(payload: JOSEPayload, key: JWSSignJWK, options?: JWSSignOptions): Promise<string>;
|
|
42
46
|
export declare function sign(payload: JOSEPayload, key: CryptoKey | Uint8Array<ArrayBuffer>, options: JWSSignOptions & {
|
|
43
47
|
alg: JWSAlgorithm;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import "./libs/unsecure.mjs";
|
|
2
|
+
import "./error.mjs";
|
|
3
|
+
import { JWK, JWKSet, JWK_EC_Private, JWK_EC_Public, JWK_OKP_Private, JWK_OKP_Public, JWK_Private, JWK_Public, JWK_RSA_Private, JWK_RSA_Public, JWK_oct, JWSAlgorithm, KeyManagementAlgorithm } from "./index.mjs";
|
|
4
|
+
import "./digest.mjs";
|
|
5
|
+
import { ComputeJwtTimeClaimsOptions as ComputeJwtTimeClaimsOptions$1, ParsePayloadOptions, applyTypDefault, assertCritShape as assertCritShape$1, computeJwtTimeClaims as computeJwtTimeClaims$1, getPlaintextBytes as getPlaintextBytes$1, parsePayloadBytes, parsePayloadSegment, validateCriticalHeadersJWE as validateCriticalHeadersJWE$1, validateCriticalHeadersJWS as validateCriticalHeadersJWS$1 } from "./jwt.mjs";
|
|
6
|
+
/** Decoder output shape. `"bytes"` aliases `"uint8array"`. */
|
|
7
|
+
export type DecodeReturnAs = "string" | "uint8array" | "bytes";
|
|
8
|
+
export interface Base64ParseOptions {
|
|
9
|
+
/**
|
|
10
|
+
* Output shape: UTF-8 text, or the bytes themselves.
|
|
11
|
+
* @default "string"
|
|
12
|
+
*/
|
|
13
|
+
returnAs?: DecodeReturnAs;
|
|
14
|
+
}
|
|
15
|
+
/** Encode bytes, or the UTF-8 bytes of a string, as unpadded base64url (RFC 7515 §2). */
|
|
16
|
+
export declare function base64UrlStringify(data: string | Uint8Array): string;
|
|
17
|
+
/** Encode bytes, or the UTF-8 bytes of a string, as padded standard base64 (RFC 4648 §4). */
|
|
18
|
+
export declare function base64Stringify(data: string | Uint8Array): string;
|
|
19
|
+
/**
|
|
20
|
+
* Decode unpadded base64url (RFC 7515 §2). Strict: only the canonical encoding of a byte string
|
|
21
|
+
* is accepted, so `=`, whitespace, characters outside the URL-safe alphabet and set bits past
|
|
22
|
+
* the final byte are rejected; a `string` result must be valid UTF-8.
|
|
23
|
+
*
|
|
24
|
+
* @throws {UnsecureError} `MALFORMED` for text that is not such an encoding; `INVALID_TYPE` for input that is not a string
|
|
25
|
+
*/
|
|
26
|
+
export declare function base64UrlParse<T extends DecodeReturnAs>(text: string, options: Base64ParseOptions & {
|
|
27
|
+
returnAs: T;
|
|
28
|
+
}): T extends "string" ? string : Uint8Array<ArrayBuffer>;
|
|
29
|
+
export declare function base64UrlParse(text: string, options?: Base64ParseOptions): string;
|
|
30
|
+
/**
|
|
31
|
+
* Decode padded standard base64 (RFC 4648 §4). Strict: the canonical encoding with its `=` run
|
|
32
|
+
* present, no whitespace, no set bits past the final byte; a `string` result must be valid UTF-8.
|
|
33
|
+
*
|
|
34
|
+
* @throws {UnsecureError} `MALFORMED` for text that is not such an encoding; `INVALID_TYPE` for input that is not a string
|
|
35
|
+
*/
|
|
36
|
+
export declare function base64Parse<T extends DecodeReturnAs>(text: string, options: Base64ParseOptions & {
|
|
37
|
+
returnAs: T;
|
|
38
|
+
}): T extends "string" ? string : Uint8Array<ArrayBuffer>;
|
|
39
|
+
export declare function base64Parse(text: string, options?: Base64ParseOptions): string;
|
|
40
|
+
/** @deprecated Renamed to {@link Base64ParseOptions}; removed in v0.9.0. */
|
|
41
|
+
export type DecodeOptions = Base64ParseOptions;
|
|
42
|
+
/** @deprecated Renamed to {@link base64UrlStringify} in v0.8.0; removed in v0.9.0. */
|
|
43
|
+
export declare const base64UrlEncode: typeof base64UrlStringify;
|
|
44
|
+
/** @deprecated Renamed to {@link base64UrlParse} in v0.8.0; removed in v0.9.0. */
|
|
45
|
+
export declare const base64UrlDecode: typeof base64UrlParse;
|
|
46
|
+
/** @deprecated Renamed to {@link base64Stringify} in v0.8.0; removed in v0.9.0. */
|
|
47
|
+
export declare const base64Encode: typeof base64Stringify;
|
|
48
|
+
/** @deprecated Renamed to {@link base64Parse} in v0.8.0; removed in v0.9.0. */
|
|
49
|
+
export declare const base64Decode: typeof base64Parse;
|
|
50
|
+
/** Concatenate multiple `Uint8Array`s into a single contiguous buffer. */
|
|
51
|
+
export declare function concatUint8Arrays(...arrays: Readonly<Uint8Array<ArrayBuffer>[]>): Uint8Array<ArrayBuffer>;
|
|
52
|
+
/** Wrap a value in an array; returns the array unchanged if already an array. */
|
|
53
|
+
export declare function maybeArray<T>(item: T | T[]): T[];
|
|
54
|
+
/** Whether `key` is a JWK whose `kty` this library models (`oct`, `RSA`, `EC`, `OKP`). */
|
|
55
|
+
export declare function isJWK(key: unknown): key is JWK;
|
|
56
|
+
/** Whether `key` is an object with a `keys` array. */
|
|
57
|
+
export declare function isJWKSet(key: unknown): key is JWKSet;
|
|
58
|
+
/** Asserts that `key` is a `CryptoKey`; throws `ERR_JWK_INVALID` otherwise. */
|
|
59
|
+
export declare function assertCryptoKey(key: unknown): asserts key is CryptoKey;
|
|
60
|
+
/** Whether `key` is a `CryptoKey`, checked via `Symbol.toStringTag` to work across realms. */
|
|
61
|
+
export declare function isCryptoKey(key: unknown): key is CryptoKey;
|
|
62
|
+
/** Whether `key` is a `CryptoKeyPair` of two CryptoKeys. */
|
|
63
|
+
export declare const isCryptoKeyPair: (key: unknown) => key is CryptoKeyPair;
|
|
64
|
+
/** Whether the JWK is symmetric (`oct`); its `k` is always secret. */
|
|
65
|
+
export declare function isSymmetricJWK<T extends JWK>(key: T): key is Extract<T, JWK_oct>;
|
|
66
|
+
export declare function isSymmetricJWK(key: unknown): key is JWK_oct;
|
|
67
|
+
/** Whether the JWK is asymmetric (RSA, EC, OKP). */
|
|
68
|
+
export declare function isAsymmetricJWK<T extends JWK>(key: T): key is Exclude<T, JWK_oct>;
|
|
69
|
+
export declare function isAsymmetricJWK(key: unknown): key is Exclude<JWK, JWK_oct>;
|
|
70
|
+
/**
|
|
71
|
+
* Whether the JWK holds asymmetric private material (`d`). It is `false` for `oct` keys,
|
|
72
|
+
* so `!isPrivateJWK(key)` is not a "safe to publish" check; use `isPublicJWK`.
|
|
73
|
+
*/
|
|
74
|
+
export declare function isPrivateJWK<T extends JWK>(key: T): key is Extract<T, JWK_EC_Private | JWK_OKP_Private | JWK_RSA_Private>;
|
|
75
|
+
export declare function isPrivateJWK(key: unknown): key is JWK_Private;
|
|
76
|
+
/** Whether the JWK is an asymmetric public key without `d`: the "safe to publish" check. */
|
|
77
|
+
export declare function isPublicJWK<T extends JWK>(key: T): key is Exclude<Extract<T, JWK_EC_Public | JWK_OKP_Public | JWK_RSA_Public>, JWK_Private>;
|
|
78
|
+
export declare function isPublicJWK(key: unknown): key is JWK_Public;
|
|
79
|
+
/** How a JWK Set's entries are read during algorithm inference. */
|
|
80
|
+
export interface InferAlgorithmsOptions {
|
|
81
|
+
/** Admit `oct` entries of a JWK Set. Defaults to `false`. */
|
|
82
|
+
allowSymmetric?: boolean;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Infer the JWS algorithms a key unambiguously supports, or `undefined` when it cannot
|
|
86
|
+
* (raw bytes, ambiguous JWK, lookup function) and `options.algorithms` must be passed.
|
|
87
|
+
*/
|
|
88
|
+
export declare function inferJWSAllowedAlgorithms(key: unknown, options?: InferAlgorithmsOptions): JWSAlgorithm[] | undefined;
|
|
89
|
+
/**
|
|
90
|
+
* Infer the JWE key management algorithms a key unambiguously supports, or `undefined`
|
|
91
|
+
* when it cannot; a password string infers the PBES2 variants, raw bytes nothing.
|
|
92
|
+
*/
|
|
93
|
+
export declare function inferJWEAllowedAlgorithms(key: unknown, options?: InferAlgorithmsOptions): KeyManagementAlgorithm[] | undefined;
|
|
94
|
+
/** @deprecated Use `ParsePayloadOptions` from `unjwt/internal`; removed in v0.9.0. */
|
|
95
|
+
export type DecodePayloadOptions = ParsePayloadOptions;
|
|
96
|
+
/** @deprecated Use `ComputeJwtTimeClaimsOptions` from `unjwt/internal`; removed in v0.9.0. */
|
|
97
|
+
export type ComputeJwtTimeClaimsOptions = ComputeJwtTimeClaimsOptions$1;
|
|
98
|
+
/** @deprecated Use `applyTypDefault` from `unjwt/internal`; removed in v0.9.0. */
|
|
99
|
+
export declare const applyTypCtyDefaults: typeof applyTypDefault;
|
|
100
|
+
/** @deprecated Use `parsePayloadBytes` from `unjwt/internal`; removed in v0.9.0. */
|
|
101
|
+
export declare const decodePayloadFromBytes: typeof parsePayloadBytes;
|
|
102
|
+
/** @deprecated Use `parsePayloadSegment` from `unjwt/internal`; removed in v0.9.0. */
|
|
103
|
+
export declare const decodePayloadFromB64UrlSegment: typeof parsePayloadSegment;
|
|
104
|
+
/** @deprecated Use `getPlaintextBytes` from `unjwt/internal`; removed in v0.9.0. */
|
|
105
|
+
export declare const getPlaintextBytes: typeof getPlaintextBytes$1;
|
|
106
|
+
/** @deprecated Use `computeJwtTimeClaims` from `unjwt/internal`; removed in v0.9.0. */
|
|
107
|
+
export declare const computeJwtTimeClaims: typeof computeJwtTimeClaims$1;
|
|
108
|
+
/** @deprecated Use `validateCriticalHeadersJWS` from `unjwt/internal`; removed in v0.9.0. */
|
|
109
|
+
export declare const validateCriticalHeadersJWS: typeof validateCriticalHeadersJWS$1;
|
|
110
|
+
/** @deprecated Use `validateCriticalHeadersJWE` from `unjwt/internal`; removed in v0.9.0. */
|
|
111
|
+
export declare const validateCriticalHeadersJWE: typeof validateCriticalHeadersJWE$1;
|
|
112
|
+
/** @deprecated Use `assertCritShape` from `unjwt/internal`; removed in v0.9.0. */
|
|
113
|
+
export declare const assertCritShape: typeof assertCritShape$1;
|
package/dist/_chunks/jwe.mjs
CHANGED
|
@@ -1,7 +1,117 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { JWTError
|
|
3
|
-
import {
|
|
4
|
-
import { DEFAULT_PBES2_ITERATIONS,
|
|
1
|
+
import { secureRandomBytes, textEncoder } from "./libs/unsecure.mjs";
|
|
2
|
+
import { JWTError } from "../error.mjs";
|
|
3
|
+
import { applyTypDefault, base64UrlStringify, computeJwtTimeClaims, getPlaintextBytes, isCryptoKey, isJWK, isJWKSet, parsePayloadBytes, validateCriticalHeadersJWE } from "./jwt.mjs";
|
|
4
|
+
import { DEFAULT_PBES2_ITERATIONS, asDecryptionError, asKeyLookupError, assertCompactToken, assertConsumerOptions, assertDirectKeyRole, assertEntryLimit, assertJWEEncSupported, assertJWKSetCandidates, assertOptionEntry, assertPBES2Iterations, assertPBES2Params, assertProducerConfirmation, assertProducerCrit, assertProducerKeyHeaders, assertProtectedOnlyOption, assertSerializationObject, bitLengthCEK, bitLengthIV, bitLengthTag, buildECDHAgreementParams, buildJWKSetFilter, checkAlgAllowed, checkAlgSupported, checkJWEEncSupported, checkProtectedTyp, checkSerializationEntry, copyJsonObject, decodeProtectedHeader, decodeSegment, decrypt as decrypt$1, encrypt as encrypt$1, encryptKey, generateCEK, generateIV, getJWKsFromSet, importKey, keyMatchesHeader, resolveKeyInput, resolveLimit, resolvePasswordKey, serializeProtectedHeader } from "./algorithms.mjs";
|
|
5
|
+
import { inferJWEAllowedAlgorithms, isContentEncryptionAlgorithm, isKeyManagementAlgorithm, isPBES2Algorithm } from "./digest.mjs";
|
|
6
|
+
import { resolvePayloadMode, validateClaimsIfJson } from "./payload.mjs";
|
|
7
|
+
import { unwrapKey } from "./wrap.mjs";
|
|
8
|
+
const JWE_ALG_CTX = /* @__PURE__ */ Object.freeze({
|
|
9
|
+
infer: inferJWEAllowedAlgorithms,
|
|
10
|
+
octRoles: true,
|
|
11
|
+
errorCode: "ERR_JWE_ALG_NOT_ALLOWED",
|
|
12
|
+
label: "Key management algorithm",
|
|
13
|
+
op: "enc"
|
|
14
|
+
});
|
|
15
|
+
const JWE_DIRECT_ALGS = /* @__PURE__ */ new Set(["dir", "ECDH-ES"]);
|
|
16
|
+
function checkJWEAlgSupported(alg) {
|
|
17
|
+
return checkAlgSupported(alg, {
|
|
18
|
+
supported: isKeyManagementAlgorithm,
|
|
19
|
+
code: "ERR_JWE_ALG_NOT_ALLOWED",
|
|
20
|
+
label: "Key management algorithm",
|
|
21
|
+
role: "key management algorithm"
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
function isJWEAlgSupported(alg) {
|
|
25
|
+
return isKeyManagementAlgorithm(alg);
|
|
26
|
+
}
|
|
27
|
+
function assertJWEAlgSupported(alg) {
|
|
28
|
+
const error = checkJWEAlgSupported(alg);
|
|
29
|
+
if (error) throw error;
|
|
30
|
+
}
|
|
31
|
+
function checkJWEEncAllowed(enc, encryptionAlgorithms) {
|
|
32
|
+
if (encryptionAlgorithms === void 0 || encryptionAlgorithms.includes(enc)) return void 0;
|
|
33
|
+
return new JWTError(`Content encryption algorithm not allowed: ${enc}`, "ERR_JWE_ALG_NOT_ALLOWED");
|
|
34
|
+
}
|
|
35
|
+
function assertProducerCEK(cek, enc) {
|
|
36
|
+
if (cek === void 0) return;
|
|
37
|
+
const expected = bitLengthCEK(enc) >> 3;
|
|
38
|
+
if (!(cek instanceof Uint8Array) || cek.length !== expected) throw new JWTError(`"cek" must be ${expected} bytes for ${enc}.`, "ERR_INVALID_OPTION");
|
|
39
|
+
}
|
|
40
|
+
function assertProducerIV(iv, enc) {
|
|
41
|
+
if (iv === void 0) return;
|
|
42
|
+
const expected = bitLengthIV(enc) >> 3;
|
|
43
|
+
if (!(iv instanceof Uint8Array) || iv.length !== expected) throw new JWTError(`"contentEncryptionIV" must be ${expected} bytes for ${enc}.`, "ERR_INVALID_OPTION");
|
|
44
|
+
}
|
|
45
|
+
function checkJWEDirectEncryptedKey(alg, encryptedKey) {
|
|
46
|
+
if (!JWE_DIRECT_ALGS.has(alg) || !encryptedKey) return void 0;
|
|
47
|
+
return new JWTError(`Invalid JWE: Encrypted key must be empty for ${alg}.`, "ERR_JWE_INVALID");
|
|
48
|
+
}
|
|
49
|
+
function checkJWEContentSegments(enc, iv, tag) {
|
|
50
|
+
const ivBytes = bitLengthIV(enc) >> 3;
|
|
51
|
+
if (iv.length !== ivBytes) return new JWTError(`Invalid JWE: Initialization vector must be ${ivBytes} bytes for ${enc} (got ${iv.length}).`, "ERR_JWE_INVALID");
|
|
52
|
+
const tagBytes = bitLengthTag(enc) >> 3;
|
|
53
|
+
if (tag.length !== tagBytes) return new JWTError(`Invalid JWE: Authentication tag must be ${tagBytes} bytes for ${enc} (got ${tag.length}).`, "ERR_JWE_INVALID");
|
|
54
|
+
}
|
|
55
|
+
function checkJWEZip(header) {
|
|
56
|
+
if (!header || !Object.hasOwn(header, "zip")) return void 0;
|
|
57
|
+
return new JWTError("Invalid JWE: compression is not supported.", "ERR_JWE_INVALID");
|
|
58
|
+
}
|
|
59
|
+
function assertNoZipOption(header, tier) {
|
|
60
|
+
if (!header || !Object.hasOwn(header, "zip")) return;
|
|
61
|
+
throw new JWTError(`JWE compression ("zip") in the ${tier} header is not supported.`, "ERR_INVALID_OPTION");
|
|
62
|
+
}
|
|
63
|
+
function checkJWEUnprotectedCrit(header) {
|
|
64
|
+
if (!header || !Object.hasOwn(header, "crit")) return void 0;
|
|
65
|
+
return new JWTError("Invalid JWE: \"crit\" must be integrity protected.", "ERR_JWE_INVALID");
|
|
66
|
+
}
|
|
67
|
+
function createPBES2Budget(limit) {
|
|
68
|
+
let remaining = limit;
|
|
69
|
+
return { spend(attempt) {
|
|
70
|
+
const { alg, p2c } = attempt;
|
|
71
|
+
if (!alg.startsWith("PBES2")) return;
|
|
72
|
+
if (typeof p2c !== "number" || !(p2c > 0)) return;
|
|
73
|
+
assertPBES2Iterations(p2c, attempt);
|
|
74
|
+
if (p2c > remaining) throw new JWTError(`PBES2 iteration budget of ${limit} exhausted.`, "ERR_JWE_INVALID");
|
|
75
|
+
remaining -= p2c;
|
|
76
|
+
} };
|
|
77
|
+
}
|
|
78
|
+
const JWE_ENC_CEK_FORMAT = /* @__PURE__ */ Object.freeze({
|
|
79
|
+
"A128GCM": "cryptokey",
|
|
80
|
+
"A192GCM": "cryptokey",
|
|
81
|
+
"A256GCM": "cryptokey",
|
|
82
|
+
"A128CBC-HS256": "raw",
|
|
83
|
+
"A192CBC-HS384": "raw",
|
|
84
|
+
"A256CBC-HS512": "raw"
|
|
85
|
+
});
|
|
86
|
+
async function exportReturnedCek(cek) {
|
|
87
|
+
if (!isCryptoKey(cek)) return cek;
|
|
88
|
+
if (!cek.extractable) throw new JWTError("\"returnCek\" requires an extractable content encryption key.", "ERR_INVALID_OPTION");
|
|
89
|
+
return new Uint8Array(await crypto.subtle.exportKey("raw", cek));
|
|
90
|
+
}
|
|
91
|
+
function cekFormatForEnc(enc) {
|
|
92
|
+
return JWE_ENC_CEK_FORMAT[enc];
|
|
93
|
+
}
|
|
94
|
+
function buildUnwrapKeyOptions(header, algorithms, options) {
|
|
95
|
+
const { alg, enc } = algorithms;
|
|
96
|
+
const opts = {
|
|
97
|
+
alg,
|
|
98
|
+
enc,
|
|
99
|
+
format: cekFormatForEnc(enc),
|
|
100
|
+
keyUsage: options?.keyUsage || ["decrypt"]
|
|
101
|
+
};
|
|
102
|
+
if (header.iv) opts.iv = header.iv;
|
|
103
|
+
if (header.tag) opts.tag = header.tag;
|
|
104
|
+
if (header.p2s) opts.p2s = header.p2s;
|
|
105
|
+
if (header.p2c) opts.p2c = header.p2c;
|
|
106
|
+
if (header.epk) opts.epk = header.epk;
|
|
107
|
+
if (header.apu) opts.apu = header.apu;
|
|
108
|
+
if (header.apv) opts.apv = header.apv;
|
|
109
|
+
if (options?.unwrappedKeyAlgorithm) opts.unwrappedKeyAlgorithm = options.unwrappedKeyAlgorithm;
|
|
110
|
+
if (options?.extractable !== void 0) opts.extractable = options.extractable;
|
|
111
|
+
if (options?.minIterations !== void 0) opts.minIterations = options.minIterations;
|
|
112
|
+
if (options?.maxIterations !== void 0) opts.maxIterations = options.maxIterations;
|
|
113
|
+
return opts;
|
|
114
|
+
}
|
|
5
115
|
function buildKeyManagementParams(alg, source) {
|
|
6
116
|
const { keyManagementIV, p2s, p2c, ecdh } = source;
|
|
7
117
|
const isPBES2 = alg.startsWith("PBES2");
|
|
@@ -61,6 +171,77 @@ async function unwrapAndDecrypt(alg, rawKeyMaterial, options) {
|
|
|
61
171
|
throw asDecryptionError(err);
|
|
62
172
|
}
|
|
63
173
|
}
|
|
174
|
+
function decodeJWEPayload(plaintext, mode) {
|
|
175
|
+
return parsePayloadBytes(plaintext, {
|
|
176
|
+
payload: mode,
|
|
177
|
+
family: "JWE"
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
function _resolveRecipientAlg(key, index) {
|
|
181
|
+
if (!isJWK(key)) throw new JWTError(`Recipient[${index}] key is not a JWK.`, "ERR_JWE_RECIPIENT_ALG_INFERENCE");
|
|
182
|
+
const declared = key.alg;
|
|
183
|
+
if (!declared) throw new JWTError(`Cannot infer "alg" for recipient[${index}]: the JWK has no "alg" property.`, "ERR_JWE_RECIPIENT_ALG_INFERENCE");
|
|
184
|
+
const alg = key.kty === "oct" && isContentEncryptionAlgorithm(declared) ? "dir" : declared;
|
|
185
|
+
if (JWE_DIRECT_ALGS.has(alg)) throw new JWTError(`Recipient[${index}] "${alg}" allows a single recipient, use encrypt().`, "ERR_JWE_ALG_FORBIDDEN_IN_MULTI");
|
|
186
|
+
assertJWEAlgSupported(alg);
|
|
187
|
+
return alg;
|
|
188
|
+
}
|
|
189
|
+
function _buildPerRecipientHeader(recipient, alg, keyMgmtOut) {
|
|
190
|
+
const header = {};
|
|
191
|
+
if (recipient.key.kid) header.kid = recipient.key.kid;
|
|
192
|
+
const userHeader = copyJsonObject(recipient.header, {
|
|
193
|
+
code: "ERR_INVALID_OPTION",
|
|
194
|
+
message: "A recipient \"header\" must hold only JSON values."
|
|
195
|
+
});
|
|
196
|
+
if (userHeader) Object.assign(header, userHeader);
|
|
197
|
+
if (keyMgmtOut) Object.assign(header, keyMgmtOut);
|
|
198
|
+
header.alg = alg;
|
|
199
|
+
return header;
|
|
200
|
+
}
|
|
201
|
+
function _assertDisjointHeaders(protectedHeader, sharedUnprotected, recipientHeader) {
|
|
202
|
+
const seen = /* @__PURE__ */ new Set();
|
|
203
|
+
const check = (obj) => {
|
|
204
|
+
if (!obj) return;
|
|
205
|
+
for (const k of Object.keys(obj)) {
|
|
206
|
+
if (seen.has(k)) throw new JWTError(`Invalid JWE: header parameter "${k}" is set in more than one header.`, "ERR_JWE_HEADER_PARAMS_NOT_DISJOINT");
|
|
207
|
+
seen.add(k);
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
check(protectedHeader);
|
|
211
|
+
check(sharedUnprotected);
|
|
212
|
+
check(recipientHeader);
|
|
213
|
+
}
|
|
214
|
+
function _mergeHeaders(protectedHeader, sharedUnprotected, recipientHeader) {
|
|
215
|
+
const merged = { ...protectedHeader };
|
|
216
|
+
if (sharedUnprotected) Object.assign(merged, sharedUnprotected);
|
|
217
|
+
if (recipientHeader) Object.assign(merged, recipientHeader);
|
|
218
|
+
return merged;
|
|
219
|
+
}
|
|
220
|
+
function _normalizeSerialization(input) {
|
|
221
|
+
assertSerializationObject(input, "JWE");
|
|
222
|
+
if ("recipients" in input) {
|
|
223
|
+
if ("encrypted_key" in input || "header" in input) throw new JWTError("Invalid JWE JSON Serialization: \"recipients\" excludes top-level \"header\" and \"encrypted_key\".", "ERR_JWE_INVALID_SERIALIZATION");
|
|
224
|
+
return input;
|
|
225
|
+
}
|
|
226
|
+
const flattened = input;
|
|
227
|
+
const recipient = {};
|
|
228
|
+
if (flattened.header !== void 0) recipient.header = flattened.header;
|
|
229
|
+
if (flattened.encrypted_key !== void 0) recipient.encrypted_key = flattened.encrypted_key;
|
|
230
|
+
const general = {
|
|
231
|
+
recipients: [recipient],
|
|
232
|
+
iv: flattened.iv,
|
|
233
|
+
ciphertext: flattened.ciphertext,
|
|
234
|
+
tag: flattened.tag
|
|
235
|
+
};
|
|
236
|
+
if (flattened.protected !== void 0) general.protected = flattened.protected;
|
|
237
|
+
if (flattened.unprotected !== void 0) general.unprotected = flattened.unprotected;
|
|
238
|
+
if (flattened.aad !== void 0) general.aad = flattened.aad;
|
|
239
|
+
return general;
|
|
240
|
+
}
|
|
241
|
+
function _assertAADOption(aad) {
|
|
242
|
+
if (aad === void 0 || typeof aad === "string" || aad instanceof Uint8Array) return;
|
|
243
|
+
throw new JWTError("\"aad\" must be a string or a Uint8Array.", "ERR_INVALID_OPTION");
|
|
244
|
+
}
|
|
64
245
|
async function encryptMulti(payload, recipients, options = {}) {
|
|
65
246
|
if (!Array.isArray(recipients) || recipients.length === 0) throw new JWTError("encryptMulti requires at least one recipient.", "ERR_JWE_INVALID");
|
|
66
247
|
assertOptionEntry(options, {
|
|
@@ -108,8 +289,14 @@ async function encryptMulti(payload, recipients, options = {}) {
|
|
|
108
289
|
p2s: recipient.p2s,
|
|
109
290
|
p2c: recipient.p2c
|
|
110
291
|
});
|
|
111
|
-
const userProtected =
|
|
112
|
-
|
|
292
|
+
const userProtected = copyJsonObject(options.protectedHeader, {
|
|
293
|
+
code: "ERR_INVALID_OPTION",
|
|
294
|
+
message: "\"protectedHeader\" must hold only JSON values."
|
|
295
|
+
});
|
|
296
|
+
const sharedUnprotected = copyJsonObject(options.sharedUnprotectedHeader, {
|
|
297
|
+
code: "ERR_INVALID_OPTION",
|
|
298
|
+
message: "\"sharedUnprotectedHeader\" must hold only JSON values."
|
|
299
|
+
});
|
|
113
300
|
const protectedHeader = {};
|
|
114
301
|
if (userProtected) Object.assign(protectedHeader, userProtected);
|
|
115
302
|
protectedHeader.enc = enc;
|
|
@@ -178,7 +365,10 @@ async function decryptMulti(jwe, keyOrLookup, options = {}) {
|
|
|
178
365
|
if (envelopeError) throw envelopeError;
|
|
179
366
|
const protectedHeaderEncoded = general.protected ?? "";
|
|
180
367
|
const protectedHeader = decodeProtectedHeader(protectedHeaderEncoded || void 0, "JWE");
|
|
181
|
-
const sharedUnprotected =
|
|
368
|
+
const sharedUnprotected = copyJsonObject(general.unprotected, {
|
|
369
|
+
code: "ERR_JWE_INVALID",
|
|
370
|
+
message: "Invalid JWE JSON Serialization: \"unprotected\" must hold only JSON values."
|
|
371
|
+
});
|
|
182
372
|
const sharedError = checkJWEZip(protectedHeader) ?? checkJWEUnprotectedCrit(sharedUnprotected) ?? checkJWEZip(sharedUnprotected);
|
|
183
373
|
if (sharedError) throw sharedError;
|
|
184
374
|
_assertDisjointHeaders(protectedHeader, sharedUnprotected, void 0);
|
|
@@ -219,7 +409,10 @@ async function decryptMulti(jwe, keyOrLookup, options = {}) {
|
|
|
219
409
|
continue;
|
|
220
410
|
}
|
|
221
411
|
const wireRecipient = general.recipients[i];
|
|
222
|
-
const recipientHeader =
|
|
412
|
+
const recipientHeader = copyJsonObject(wireRecipient.header, {
|
|
413
|
+
code: "ERR_JWE_INVALID",
|
|
414
|
+
message: "Invalid JWE JSON Serialization: a recipient \"header\" must hold only JSON values."
|
|
415
|
+
});
|
|
223
416
|
const recipientError = checkJWEUnprotectedCrit(recipientHeader) ?? checkJWEZip(recipientHeader);
|
|
224
417
|
if (recipientError) {
|
|
225
418
|
lastError = recipientError;
|
|
@@ -334,68 +527,6 @@ function generalToFlattened(jwe) {
|
|
|
334
527
|
if (recipient.encrypted_key !== void 0) flattened.encrypted_key = recipient.encrypted_key;
|
|
335
528
|
return flattened;
|
|
336
529
|
}
|
|
337
|
-
function _resolveRecipientAlg(key, index) {
|
|
338
|
-
if (!isJWK(key)) throw new JWTError(`Recipient[${index}] key is not a JWK.`, "ERR_JWE_RECIPIENT_ALG_INFERENCE");
|
|
339
|
-
const declared = key.alg;
|
|
340
|
-
if (!declared) throw new JWTError(`Cannot infer "alg" for recipient[${index}]: the JWK has no "alg" property.`, "ERR_JWE_RECIPIENT_ALG_INFERENCE");
|
|
341
|
-
const alg = key.kty === "oct" && isContentEncryptionAlgorithm(declared) ? "dir" : declared;
|
|
342
|
-
if (JWE_DIRECT_ALGS.has(alg)) throw new JWTError(`Recipient[${index}] resolves to "${alg}", which requires exactly one recipient. Use encrypt() instead.`, "ERR_JWE_ALG_FORBIDDEN_IN_MULTI");
|
|
343
|
-
assertJWEAlgSupported(alg);
|
|
344
|
-
return alg;
|
|
345
|
-
}
|
|
346
|
-
function _buildPerRecipientHeader(recipient, alg, keyMgmtOut) {
|
|
347
|
-
const header = {};
|
|
348
|
-
if (recipient.key.kid) header.kid = recipient.key.kid;
|
|
349
|
-
const userHeader = sanitizeObjectCopy(recipient.header);
|
|
350
|
-
if (userHeader) Object.assign(header, userHeader);
|
|
351
|
-
if (keyMgmtOut) Object.assign(header, keyMgmtOut);
|
|
352
|
-
header.alg = alg;
|
|
353
|
-
return header;
|
|
354
|
-
}
|
|
355
|
-
function _assertDisjointHeaders(protectedHeader, sharedUnprotected, recipientHeader) {
|
|
356
|
-
const seen = /* @__PURE__ */ new Set();
|
|
357
|
-
const check = (obj) => {
|
|
358
|
-
if (!obj) return;
|
|
359
|
-
for (const k of Object.keys(obj)) {
|
|
360
|
-
if (seen.has(k)) throw new JWTError(`JWE header parameter "${k}" appears in multiple header tiers; protected, shared unprotected, and per-recipient headers must be disjoint (RFC 7516 §7.2.1).`, "ERR_JWE_HEADER_PARAMS_NOT_DISJOINT");
|
|
361
|
-
seen.add(k);
|
|
362
|
-
}
|
|
363
|
-
};
|
|
364
|
-
check(protectedHeader);
|
|
365
|
-
check(sharedUnprotected);
|
|
366
|
-
check(recipientHeader);
|
|
367
|
-
}
|
|
368
|
-
function _mergeHeaders(protectedHeader, sharedUnprotected, recipientHeader) {
|
|
369
|
-
const merged = { ...protectedHeader };
|
|
370
|
-
if (sharedUnprotected) Object.assign(merged, sharedUnprotected);
|
|
371
|
-
if (recipientHeader) Object.assign(merged, recipientHeader);
|
|
372
|
-
return merged;
|
|
373
|
-
}
|
|
374
|
-
function _normalizeSerialization(input) {
|
|
375
|
-
assertSerializationObject(input, "JWE");
|
|
376
|
-
if ("recipients" in input) {
|
|
377
|
-
if ("encrypted_key" in input || "header" in input) throw new JWTError("Invalid JWE JSON Serialization: \"recipients\" must not be combined with a top-level \"header\" or \"encrypted_key\".", "ERR_JWE_INVALID_SERIALIZATION");
|
|
378
|
-
return input;
|
|
379
|
-
}
|
|
380
|
-
const flattened = input;
|
|
381
|
-
const recipient = {};
|
|
382
|
-
if (flattened.header !== void 0) recipient.header = flattened.header;
|
|
383
|
-
if (flattened.encrypted_key !== void 0) recipient.encrypted_key = flattened.encrypted_key;
|
|
384
|
-
const general = {
|
|
385
|
-
recipients: [recipient],
|
|
386
|
-
iv: flattened.iv,
|
|
387
|
-
ciphertext: flattened.ciphertext,
|
|
388
|
-
tag: flattened.tag
|
|
389
|
-
};
|
|
390
|
-
if (flattened.protected !== void 0) general.protected = flattened.protected;
|
|
391
|
-
if (flattened.unprotected !== void 0) general.unprotected = flattened.unprotected;
|
|
392
|
-
if (flattened.aad !== void 0) general.aad = flattened.aad;
|
|
393
|
-
return general;
|
|
394
|
-
}
|
|
395
|
-
function _assertAADOption(aad) {
|
|
396
|
-
if (aad === void 0 || typeof aad === "string" || aad instanceof Uint8Array) return;
|
|
397
|
-
throw new JWTError("\"aad\" must be a string or a Uint8Array.", "ERR_INVALID_OPTION");
|
|
398
|
-
}
|
|
399
530
|
async function encrypt(payload, key, options = {}) {
|
|
400
531
|
assertOptionEntry(options, {
|
|
401
532
|
label: "options",
|
|
@@ -416,7 +547,7 @@ async function encrypt(payload, key, options = {}) {
|
|
|
416
547
|
else if (cekRole) alg = "dir";
|
|
417
548
|
else if (isJWK(key)) alg = key.alg;
|
|
418
549
|
}
|
|
419
|
-
if (!alg) throw new JWTError("JWE \"alg\"
|
|
550
|
+
if (!alg) throw new JWTError("JWE \"alg\" must be provided in options or inferable from the key", "ERR_JWE_ALG_MISSING");
|
|
420
551
|
if (!enc) {
|
|
421
552
|
if (alg === "dir") {
|
|
422
553
|
enc = cekRole ?? (isJWK(key) ? key.enc : void 0);
|
|
@@ -466,7 +597,7 @@ async function decrypt(jwe, key, options = {}) {
|
|
|
466
597
|
const keyCandidateLimit = resolveLimit(options.limits, "keyCandidates");
|
|
467
598
|
const pbes2Budget = createPBES2Budget(resolveLimit(options.limits, "pbes2Iterations"));
|
|
468
599
|
const parts = jwe.split(".");
|
|
469
|
-
if (parts.length !== 5) throw new JWTError("Invalid JWE: Must contain five sections
|
|
600
|
+
if (parts.length !== 5) throw new JWTError("Invalid JWE: Must contain five sections.", "ERR_JWE_INVALID");
|
|
470
601
|
const [protectedHeaderEncoded, encryptedKeyEncoded, ivEncoded, ciphertextEncoded, authTagEncoded] = parts;
|
|
471
602
|
const protectedHeader = decodeProtectedHeader(protectedHeaderEncoded, "JWE");
|
|
472
603
|
assertHeaderAlgorithms(protectedHeader);
|
|
@@ -538,7 +669,10 @@ async function decrypt(jwe, key, options = {}) {
|
|
|
538
669
|
return result;
|
|
539
670
|
}
|
|
540
671
|
function _buildJWEHeader(alg, enc, key, userHeader, keyManagementParams, payload) {
|
|
541
|
-
const safeHeader =
|
|
672
|
+
const safeHeader = copyJsonObject(userHeader, {
|
|
673
|
+
code: "ERR_INVALID_OPTION",
|
|
674
|
+
message: "\"protectedHeader\" must hold only JSON values."
|
|
675
|
+
});
|
|
542
676
|
const header = {};
|
|
543
677
|
if (isJWK(key) && key.kid) header.kid = key.kid;
|
|
544
678
|
if (safeHeader) Object.assign(header, safeHeader);
|
|
@@ -550,7 +684,7 @@ function _buildJWEHeader(alg, enc, key, userHeader, keyManagementParams, payload
|
|
|
550
684
|
return header;
|
|
551
685
|
}
|
|
552
686
|
function assertHeaderAlgorithms(header) {
|
|
553
|
-
if (!header.alg || !header.enc) throw new JWTError("Invalid JWE: Protected header must
|
|
687
|
+
if (!header.alg || !header.enc) throw new JWTError("Invalid JWE: Protected header must carry \"alg\" and \"enc\".", "ERR_JWE_INVALID");
|
|
554
688
|
assertJWEAlgSupported(header.alg);
|
|
555
689
|
assertJWEEncSupported(header.enc);
|
|
556
690
|
}
|