unjwt 0.7.3 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/dist/THIRD-PARTY-LICENSES.md.gz +0 -0
- package/dist/_chunks/_codec-jwe.d.mts +170 -0
- package/dist/_chunks/_codec-jws.mjs +878 -0
- package/dist/_chunks/_internal.d.mts +7 -0
- package/dist/_chunks/_jwt-internal.mjs +388 -0
- package/dist/_chunks/algorithms.mjs +186 -0
- package/dist/_chunks/index.d.mts +500 -808
- package/dist/_chunks/index2.d.mts +11 -0
- package/dist/_chunks/index3.d.mts +108 -0
- package/dist/_chunks/jwe.d.mts +43 -66
- package/dist/_chunks/jwe.mjs +384 -252
- package/dist/_chunks/jwk.mjs +1374 -607
- package/dist/_chunks/jws.d.mts +48 -103
- package/dist/_chunks/jws.mjs +372 -184
- package/dist/_chunks/jwt.d.mts +56 -0
- package/dist/_chunks/libs/unsecure.d.mts +164 -85
- package/dist/_chunks/libs/unsecure.mjs +390 -123
- package/dist/adapters/elysia/index.d.mts +33 -171
- package/dist/adapters/elysia/index.mjs +106 -575
- package/dist/adapters/h3v1/index.d.mts +59 -344
- package/dist/adapters/h3v1/index.mjs +114 -619
- package/dist/adapters/h3v2/index.d.mts +58 -326
- package/dist/adapters/h3v2/index.mjs +108 -611
- package/dist/core/internal.d.mts +2 -0
- package/dist/core/internal.mjs +1 -0
- package/dist/core/jwe.d.mts +4 -2
- package/dist/core/jwe.mjs +4 -2
- package/dist/core/jwk.d.mts +183 -371
- package/dist/core/jwk.mjs +4 -3
- package/dist/core/jws.d.mts +4 -2
- package/dist/core/jws.mjs +4 -2
- package/dist/core/utils/index.d.mts +5 -158
- package/dist/core/utils/index.mjs +12 -3
- package/dist/index.d.mts +8 -4
- package/dist/index.mjs +6 -3
- package/package.json +29 -30
- package/dist/_chunks/_internal.mjs +0 -88
- package/dist/_chunks/utils.mjs +0 -392
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Duration, JOSEPayloadMode, JWTClaimValidationOptions, JWTClaims, JWTErrorCode, JWTTimeClaimOptions, PayloadOf } from "./index.mjs";
|
|
2
|
+
/** Set `typ: "JWT"` on a header without `typ` when the payload is an object (not a `Uint8Array`). */
|
|
3
|
+
export declare function applyTypDefault<T extends {
|
|
4
|
+
typ?: string;
|
|
5
|
+
}>(header: T, payload: unknown): T;
|
|
6
|
+
/** Options for {@link parsePayloadBytes} and {@link parsePayloadSegment}. */
|
|
7
|
+
export interface ParsePayloadOptions<Mode extends JOSEPayloadMode = JOSEPayloadMode> {
|
|
8
|
+
/** How to interpret the payload bytes; the return type follows it. @default "json" */
|
|
9
|
+
payload?: Mode;
|
|
10
|
+
/** Family the rejection is reported under (`ERR_JWS_INVALID` / `ERR_JWE_INVALID`). @default "JWS" */
|
|
11
|
+
family?: "JWS" | "JWE";
|
|
12
|
+
}
|
|
13
|
+
/** Parse payload bytes under the declared mode: `"json"` needs a UTF-8 JSON object, `"string"` UTF-8; throws `ERR_JWS_INVALID` / `ERR_JWE_INVALID`. */
|
|
14
|
+
export declare function parsePayloadBytes<T = JWTClaims>(bytes: Uint8Array<ArrayBuffer>, options?: ParsePayloadOptions<"json">): T;
|
|
15
|
+
export declare function parsePayloadBytes<Mode extends JOSEPayloadMode = JOSEPayloadMode>(bytes: Uint8Array<ArrayBuffer>, options?: ParsePayloadOptions<Mode>): PayloadOf<Mode>;
|
|
16
|
+
/** Decode payload bytes as UTF-8; throws `ERR_JWS_INVALID` / `ERR_JWE_INVALID` otherwise. */
|
|
17
|
+
export declare function parsePayloadText(bytes: Uint8Array<ArrayBuffer>, options?: Pick<ParsePayloadOptions, "family">): string;
|
|
18
|
+
/** {@link parsePayloadBytes} over a Base64URL-encoded payload segment. */
|
|
19
|
+
export declare function parsePayloadSegment<T = JWTClaims>(payloadEncoded: string, options?: ParsePayloadOptions<"json">): T;
|
|
20
|
+
export declare function parsePayloadSegment<Mode extends JOSEPayloadMode = JOSEPayloadMode>(payloadEncoded: string, options?: ParsePayloadOptions<Mode>): PayloadOf<Mode>;
|
|
21
|
+
/** Encode a payload to bytes; a non-serializable one throws `ERR_INVALID_OPTION`. */
|
|
22
|
+
export declare function getPlaintextBytes(payload: string | Uint8Array<ArrayBuffer> | Record<string, unknown>): Uint8Array<ArrayBuffer>;
|
|
23
|
+
/** Options for {@link computeJwtTimeClaims}. */
|
|
24
|
+
export type ComputeJwtTimeClaimsOptions = JWTTimeClaimOptions;
|
|
25
|
+
/**
|
|
26
|
+
* Return a copy of an object payload with `iat` and the requested `exp` / `nbf`, or `undefined` when none applies.
|
|
27
|
+
* Both members of `expiresIn`/`expiresAt` or `notBeforeIn`/`notBeforeAt` throw `ERR_JWT_CLAIM_INVALID`.
|
|
28
|
+
*/
|
|
29
|
+
export declare function computeJwtTimeClaims(payload: unknown, options?: ComputeJwtTimeClaimsOptions): JWTClaims | undefined;
|
|
30
|
+
/** Validate critical headers in JWS semantics. */
|
|
31
|
+
export declare function validateCriticalHeadersJWS(protectedHeader: {
|
|
32
|
+
crit?: string[];
|
|
33
|
+
} & Record<string, unknown>, recognizedHeaders?: string[]): void;
|
|
34
|
+
/** Validate critical headers in JWE semantics. */
|
|
35
|
+
export declare function validateCriticalHeadersJWE(protectedHeader: {
|
|
36
|
+
crit?: string[];
|
|
37
|
+
} & Record<string, unknown>, recognizedHeaders?: string[]): void;
|
|
38
|
+
/** Assert `crit` is a non-empty string array with no registered header name (RFC 7515 §4.1.11 / RFC 7516 §4.1.13). */
|
|
39
|
+
export declare function assertCritShape(crit: unknown, options: {
|
|
40
|
+
family: "JWS" | "JWE";
|
|
41
|
+
code?: JWTErrorCode;
|
|
42
|
+
}): asserts crit is string[];
|
|
43
|
+
/** Whether headers declare JSON content: a string `typ` naming JWT, or a JSON `cty`. */
|
|
44
|
+
export declare function isJWTContent(header: {
|
|
45
|
+
typ?: string;
|
|
46
|
+
cty?: string;
|
|
47
|
+
} | undefined): boolean;
|
|
48
|
+
/** Parse a `Duration` (e.g. `3600` or `"10m"`) into positive integer seconds; else `ERR_INVALID_OPTION`. */
|
|
49
|
+
export declare function computeDurationInSeconds(duration: Duration): number;
|
|
50
|
+
/** The `ERR_JWT_EXPIRED` message for a token whose `exp` (NumericDate seconds) has passed. */
|
|
51
|
+
export declare function expiredClaimMessage(exp: number): string;
|
|
52
|
+
/**
|
|
53
|
+
* Validate JWT claims against the set expectations. A malformed expectation throws
|
|
54
|
+
* `ERR_INVALID_OPTION`; an empty `audience` or `issuer` list matches no token.
|
|
55
|
+
*/
|
|
56
|
+
export declare function validateJwtClaims(jwtClaims: JWTClaims, options?: JWTClaimValidationOptions): void;
|
|
@@ -1,94 +1,173 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
|
|
10
|
-
|
|
2
|
+
* What kind of mistake an {@link UnsecureError} reports.
|
|
3
|
+
*
|
|
4
|
+
* This is the complete set for this release, so a `switch` over it is
|
|
5
|
+
* exhaustive today. A later minor may add a member — keep a default branch, or
|
|
6
|
+
* a new code will fall through unhandled.
|
|
7
|
+
*
|
|
8
|
+
* - `INVALID_TYPE` — a value of the wrong JavaScript type, or nothing where a
|
|
9
|
+
* value is required.
|
|
10
|
+
* - `OUT_OF_RANGE` — the right type, outside its documented domain: a number
|
|
11
|
+
* past its bounds, an empty secret, an alphabet that is not 32 distinct
|
|
12
|
+
* ASCII characters, no character set selected.
|
|
13
|
+
* - `MALFORMED` — text that is not what it claims to be: a non-canonical
|
|
14
|
+
* encoding, decoded bytes that are not valid UTF-8, JSON that does not parse.
|
|
15
|
+
* - `UNSUPPORTED` — a name outside the set the library accepts: a digest
|
|
16
|
+
* algorithm, a `returnAs`, an `otpauthURI` `type`.
|
|
17
|
+
* - `FROZEN` — a dangerous key cannot be removed because the object holding it
|
|
18
|
+
* is frozen or sealed.
|
|
19
|
+
* - `PLATFORM` — the runtime's Web Crypto refused an operation the library had
|
|
20
|
+
* already validated; `cause` carries the platform error.
|
|
21
|
+
*/
|
|
22
|
+
export type UnsecureErrorCode = "INVALID_TYPE" | "OUT_OF_RANGE" | "MALFORMED" | "UNSUPPORTED" | "FROZEN" | "PLATFORM";
|
|
11
23
|
/**
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
|
|
24
|
+
* Everything this library throws.
|
|
25
|
+
*
|
|
26
|
+
* `message` says what was found and where; `code` is the machine-readable
|
|
27
|
+
* version of the same judgement, and is what a caller should branch on. A
|
|
28
|
+
* failure that came from outside the library — the runtime's Web Crypto, or
|
|
29
|
+
* `JSON.parse` — carries the original in `cause`.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* try {
|
|
33
|
+
* await hmacVerify(secret, body, signature);
|
|
34
|
+
* } catch (error) {
|
|
35
|
+
* if (!(error instanceof UnsecureError)) throw error;
|
|
36
|
+
* switch (error.code) {
|
|
37
|
+
* case "OUT_OF_RANGE": {
|
|
38
|
+
* // The secret failed to load: a deployment problem, not a bad request.
|
|
39
|
+
* return respond(500);
|
|
40
|
+
* }
|
|
41
|
+
* case "PLATFORM": {
|
|
42
|
+
* return respond(503, { cause: error.cause });
|
|
43
|
+
* }
|
|
44
|
+
* default: {
|
|
45
|
+
* return respond(400, { reason: error.code });
|
|
46
|
+
* }
|
|
47
|
+
* }
|
|
48
|
+
* }
|
|
49
|
+
*/
|
|
50
|
+
export declare class UnsecureError extends Error {
|
|
51
|
+
readonly code: UnsecureErrorCode;
|
|
52
|
+
constructor(code: UnsecureErrorCode, message: string, options?: ErrorOptions);
|
|
53
|
+
}
|
|
22
54
|
/**
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* @
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
declare function safeJsonParse<T = any>(json: string): T;
|
|
55
|
+
* Generate a Uint8Array of cryptographically secure random bytes. Up to 64
|
|
56
|
+
* bytes come from the shared entropy pool; longer requests go to
|
|
57
|
+
* `crypto.getRandomValues` directly, in 65536-byte chunks.
|
|
58
|
+
*
|
|
59
|
+
* @param length Number of random bytes to generate, from 0 to `2**31 - 1`.
|
|
60
|
+
* @returns A Uint8Array filled with random bytes.
|
|
61
|
+
*
|
|
62
|
+
* @throws {UnsecureError} `OUT_OF_RANGE` if `length` is not an integer in
|
|
63
|
+
* `[0, 2**31 - 1]`.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* const key = secureRandomBytes(32); // 256-bit key material
|
|
67
|
+
*/
|
|
68
|
+
export declare function secureRandomBytes(length: number): Uint8Array<ArrayBuffer>;
|
|
38
69
|
/**
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
|
|
47
|
-
|
|
70
|
+
* Parse JSON and strip prototype-pollution vectors from the result.
|
|
71
|
+
*
|
|
72
|
+
* `JSON.parse` runs first, then the in-place sanitizer walks the parsed value
|
|
73
|
+
* and removes own properties named `__proto__`, `prototype`, or `constructor`
|
|
74
|
+
* at every depth. Nothing holding a dangerous key survives the call — the
|
|
75
|
+
* sanitizer finishes before the value is returned — and no caller-visible
|
|
76
|
+
* object is ever assigned through, so no prototype is polluted along the way.
|
|
77
|
+
*
|
|
78
|
+
* Any JSON root is handled: objects, arrays, and primitives alike.
|
|
79
|
+
*
|
|
80
|
+
* @param json The JSON text to parse.
|
|
81
|
+
* @returns The parsed value with dangerous keys stripped.
|
|
82
|
+
* @throws {UnsecureError} `MALFORMED` if `json` is not valid JSON — the engine's
|
|
83
|
+
* own error travels as `cause`; `FROZEN` if a dangerous key
|
|
84
|
+
* sits on a frozen or sealed object, see
|
|
85
|
+
* {@link sanitizeObject}.
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* const payload = safeJsonParse<{ user: { name: string } }>(untrustedInput);
|
|
89
|
+
*/
|
|
90
|
+
export declare function safeJsonParse<T = any>(json: string): T;
|
|
48
91
|
/**
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
|
|
59
|
-
|
|
92
|
+
* Remove prototype-pollution vectors from a plain record in-place.
|
|
93
|
+
*
|
|
94
|
+
* Strips own properties named `__proto__`, `prototype`, and `constructor`
|
|
95
|
+
* through nested objects and arrays, enumerable or not. Cycle-safe.
|
|
96
|
+
*
|
|
97
|
+
* Values are read from their property descriptors — array elements included —
|
|
98
|
+
* so a getter is never invoked: an accessor is neither traversed nor removed
|
|
99
|
+
* unless its name is one of the three. A `Proxy` is the exception and cannot
|
|
100
|
+
* be otherwise: its traps run for every property operation, so a proxied
|
|
101
|
+
* object is traversed through its own traps.
|
|
102
|
+
*
|
|
103
|
+
* Traversal reaches every object held in a data property, whatever its
|
|
104
|
+
* prototype. What such an object *holds* internally is another matter: `Map`
|
|
105
|
+
* entries, `Set` members and anything else living outside own properties are
|
|
106
|
+
* never read, so they are never sanitized.
|
|
107
|
+
*
|
|
108
|
+
* Returns the same reference for convenience. Use {@link sanitizeObjectCopy}
|
|
109
|
+
* if you need a deep copy with the original preserved.
|
|
110
|
+
*
|
|
111
|
+
* @throws {UnsecureError} `FROZEN` if a dangerous key cannot be removed because
|
|
112
|
+
* the object holding it is frozen or sealed. Leaving the
|
|
113
|
+
* key in place would report a sanitized object that is not
|
|
114
|
+
* one.
|
|
115
|
+
*/
|
|
116
|
+
export declare function sanitizeObject<T extends Record<string, unknown> | undefined>(obj: T): T;
|
|
60
117
|
/**
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
|
|
64
|
-
|
|
118
|
+
* Return a sanitized deep copy of `obj`. The input is never mutated.
|
|
119
|
+
*
|
|
120
|
+
* Dangerous keys (`__proto__`, `prototype`, `constructor`) are stripped from
|
|
121
|
+
* every array and plain object reached. A plain object is one rooted on
|
|
122
|
+
* `Object.prototype` or on `null`; copies of both are rooted on
|
|
123
|
+
* `Object.prototype`. Every other value — `Date`, `Map`, `Set`, typed
|
|
124
|
+
* arrays, `RegExp`, class instances, functions — is carried into the copy by
|
|
125
|
+
* reference, exactly as {@link sanitizeObject} leaves it in place. By
|
|
126
|
+
* reference means unchanged *and* unsanitized: what a `Map` or `Set` holds is
|
|
127
|
+
* never read by either function.
|
|
128
|
+
*
|
|
129
|
+
* Only own enumerable data properties are copied — the JSON shape. Accessors
|
|
130
|
+
* are skipped rather than invoked, so the copy never runs caller code; an
|
|
131
|
+
* accessor at an array index leaves a hole there and the elements after it
|
|
132
|
+
* keep their positions. A `Proxy` is traversed through its own traps, which
|
|
133
|
+
* run whatever the copy asks for.
|
|
134
|
+
*
|
|
135
|
+
* Cycle-safe: circular references in the input are preserved in the output
|
|
136
|
+
* (pointing at the copied node, not the original reference).
|
|
137
|
+
*
|
|
138
|
+
* Non-object / undefined inputs — and objects that are not arrays or plain
|
|
139
|
+
* objects — are returned unchanged.
|
|
140
|
+
*/
|
|
141
|
+
export declare function sanitizeObjectCopy<T extends Record<string, unknown> | undefined>(obj: T): T;
|
|
65
142
|
/**
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*/
|
|
69
|
-
declare
|
|
70
|
-
declare function base64Decode<T extends DecodeReturnAs>(data: string | Uint8Array, options: {
|
|
71
|
-
returnAs: T;
|
|
72
|
-
}): T extends "string" ? string : Uint8Array<ArrayBuffer>;
|
|
73
|
-
declare function base64Decode(data: string): string;
|
|
74
|
-
declare function base64Decode(data: Uint8Array): Uint8Array<ArrayBuffer>;
|
|
75
|
-
declare function base64UrlDecode<T extends DecodeReturnAs>(data: string | Uint8Array, options: {
|
|
76
|
-
returnAs: T;
|
|
77
|
-
}): T extends "string" ? string : Uint8Array<ArrayBuffer>;
|
|
78
|
-
declare function base64UrlDecode(data: string): string;
|
|
79
|
-
declare function base64UrlDecode(data: Uint8Array): Uint8Array<ArrayBuffer>;
|
|
143
|
+
* Shared UTF-8 `TextEncoder`. Encoding holds no state between calls, so a
|
|
144
|
+
* single instance serves every caller.
|
|
145
|
+
*/
|
|
146
|
+
export declare const textEncoder: TextEncoder;
|
|
80
147
|
/**
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
|
|
148
|
+
* Any byte container the library accepts: an `ArrayBuffer` — shared or not —
|
|
149
|
+
* or a view over one. Wider than the DOM `BufferSource`, which excludes
|
|
150
|
+
* `SharedArrayBuffer`-backed views.
|
|
151
|
+
*/
|
|
152
|
+
export type BytesSource = ArrayBufferLike | ArrayBufferView<ArrayBufferLike>;
|
|
84
153
|
/**
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
export
|
|
154
|
+
* Shared UTF-8 `TextDecoder` instance. `ignoreBOM` keeps a leading U+FEFF in
|
|
155
|
+
* the output: what the codecs decode is a byte string, and a BOM inside it is
|
|
156
|
+
* payload, not a signature to swallow.
|
|
157
|
+
*/
|
|
158
|
+
export declare const textDecoder: TextDecoder;
|
|
159
|
+
/**
|
|
160
|
+
* Decoder output shape. Omit to mirror the input (`string` in → `string` out,
|
|
161
|
+
* `Uint8Array` in → `Uint8Array` out). `"bytes"` aliases `"uint8array"`.
|
|
162
|
+
*/
|
|
163
|
+
export type DecodeReturnAs = "string" | "uint8array" | "bytes";
|
|
164
|
+
/** Shared `parse` options. */
|
|
165
|
+
export interface DecodeOptions {
|
|
166
|
+
/** Output shape. Mirrors the input type when omitted. */
|
|
167
|
+
returnAs?: DecodeReturnAs;
|
|
168
|
+
/**
|
|
169
|
+
* Tolerate malformed input (skip/normalize) instead of throwing.
|
|
170
|
+
* @default false
|
|
171
|
+
*/
|
|
172
|
+
loose?: boolean;
|
|
173
|
+
}
|