Skip to content

Commit 24f306e

Browse files
committed
fix(types): headers and payloads may only be JSON values and primitives
1 parent a60399f commit 24f306e

File tree

12 files changed

+108
-14
lines changed

12 files changed

+108
-14
lines changed

docs/modules/types.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ Support from the community to continue maintaining and improving this module is
1010

1111
### Type Aliases
1212

13+
- [JsonArray](../types/types.JsonArray.md)
14+
- [JsonObject](../types/types.JsonObject.md)
15+
- [JsonPrimitive](../types/types.JsonPrimitive.md)
16+
- [JsonValue](../types/types.JsonValue.md)
1317
- [KeyLike](../types/types.KeyLike.md)
1418

1519
### Interfaces

docs/types/types.JsonArray.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Type alias: JsonArray
2+
3+
## [💗 Help the project](https://github.com/sponsors/panva)
4+
5+
Support from the community to continue maintaining and improving this module is welcome. If you find the module useful, please consider supporting the project by [becoming a sponsor](https://github.com/sponsors/panva).
6+
7+
---
8+
9+
Ƭ **JsonArray**: [`JsonValue`](types.JsonValue.md)[]

docs/types/types.JsonObject.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Type alias: JsonObject
2+
3+
## [💗 Help the project](https://github.com/sponsors/panva)
4+
5+
Support from the community to continue maintaining and improving this module is welcome. If you find the module useful, please consider supporting the project by [becoming a sponsor](https://github.com/sponsors/panva).
6+
7+
---
8+
9+
Ƭ **JsonObject**: { [Key in string]?: JsonValue }

docs/types/types.JsonPrimitive.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Type alias: JsonPrimitive
2+
3+
## [💗 Help the project](https://github.com/sponsors/panva)
4+
5+
Support from the community to continue maintaining and improving this module is welcome. If you find the module useful, please consider supporting the project by [becoming a sponsor](https://github.com/sponsors/panva).
6+
7+
---
8+
9+
Ƭ **JsonPrimitive**: `string` \| `number` \| `boolean` \| ``null``

docs/types/types.JsonValue.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Type alias: JsonValue
2+
3+
## [💗 Help the project](https://github.com/sponsors/panva)
4+
5+
Support from the community to continue maintaining and improving this module is welcome. If you find the module useful, please consider supporting the project by [becoming a sponsor](https://github.com/sponsors/panva).
6+
7+
---
8+
9+
Ƭ **JsonValue**: [`JsonPrimitive`](types.JsonPrimitive.md) \| [`JsonObject`](types.JsonObject.md) \| [`JsonArray`](types.JsonArray.md)

src/jwe/flattened/encrypt.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import encrypt from '../../runtime/encrypt.js'
33
import { deflate } from '../../runtime/zlib.js'
44

55
import type {
6+
JsonValue,
67
KeyLike,
78
FlattenedJWE,
89
JWEHeaderParameters,
@@ -225,7 +226,7 @@ export class FlattenedEncrypt {
225226

226227
let cek: KeyLike | Uint8Array
227228
{
228-
let parameters: { [propName: string]: unknown } | undefined
229+
let parameters: { [parameter: string]: JsonValue | undefined } | undefined
229230
;({ cek, encryptedKey, parameters } = await encryptKeyManagement(
230231
alg,
231232
enc,

src/lib/jwt_claims_set.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type {
2+
JsonValue,
23
JWTPayload,
34
JWTClaimVerificationOptions,
45
JWEHeaderParameters,
@@ -40,7 +41,7 @@ export default (
4041
throw new JWTClaimValidationFailed('unexpected "typ" JWT header value', 'typ', 'check_failed')
4142
}
4243

43-
let payload!: { [propName: string]: unknown }
44+
let payload!: { [propName: string]: JsonValue | undefined }
4445
try {
4546
payload = JSON.parse(decoder.decode(encodedPayload))
4647
} catch {

src/lib/validate_crit.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1+
import type { JsonValue } from '../types.d'
12
import { JOSENotSupported, JWEInvalid, JWSInvalid } from '../util/errors.js'
23

34
interface CritCheckHeader {
45
b64?: boolean
56
crit?: string[]
6-
[propName: string]: unknown
7+
[propName: string]: JsonValue | undefined
78
}
89

910
function validateCrit(

src/runtime/interfaces.d.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { JWK, KeyLike } from '../types.d'
1+
import type { JWK, KeyLike, JsonValue } from '../types.d'
22
import type { PEMImportOptions } from '../key/import.js'
33

44
type AsyncOrSync<T> = Promise<T> | T
@@ -57,7 +57,9 @@ export interface DecryptFunction {
5757
): AsyncOrSync<Uint8Array>
5858
}
5959
export interface FetchFunction {
60-
(url: URL, timeout: number, options?: any): Promise<{ [propName: string]: unknown }>
60+
(url: URL, timeout: number, options?: any): Promise<{
61+
[parameter: string]: JsonValue | undefined
62+
}>
6163
}
6264
export interface DigestFunction {
6365
(digest: 'sha256' | 'sha384' | 'sha512', data: Uint8Array): AsyncOrSync<Uint8Array>

src/runtime/node/key_to_jwk.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ const keyToJWK: JWKExportFunction = (key: unknown): JWK => {
3636
) {
3737
throw new JOSENotSupported('Unsupported key asymmetricKeyType')
3838
}
39-
return keyObject.export({ format: 'jwk' })
39+
return <JWK>keyObject.export({ format: 'jwk' })
4040
}
4141

4242
switch (keyObject.type) {
@@ -112,7 +112,7 @@ const keyToJWK: JWKExportFunction = (key: unknown): JWK => {
112112
if (der.length < 100) {
113113
offset += correction
114114
}
115-
return {
115+
return <JWK>{
116116
...keyToJWK(createPublicKey(keyObject)),
117117
d: base64url(der.subarray(offset, offset + len / 2)),
118118
}
@@ -130,7 +130,7 @@ const keyToJWK: JWKExportFunction = (key: unknown): JWK => {
130130
}
131131

132132
const der = keyObject.export({ type: 'pkcs8', format: 'der' })
133-
return {
133+
return <JWK>{
134134
...keyToJWK(createPublicKey(keyObject)),
135135
d: base64url(der.subarray(-32)),
136136
}
@@ -148,7 +148,7 @@ const keyToJWK: JWKExportFunction = (key: unknown): JWK => {
148148
}
149149

150150
const der = keyObject.export({ type: 'pkcs8', format: 'der' })
151-
return {
151+
return <JWK>{
152152
...keyToJWK(createPublicKey(keyObject)),
153153
d: base64url(der.subarray(crv === 'Ed448' ? -57 : -56)),
154154
}

src/types.d.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,11 @@
9191
*/
9292
export type KeyLike = { type: string }
9393

94+
type JsonObject = { [Key in string]?: JsonValue }
95+
type JsonArray = JsonValue[]
96+
type JsonPrimitive = string | number | boolean | null
97+
type JsonValue = JsonPrimitive | JsonObject | JsonArray
98+
9499
/**
95100
* JSON Web Key ({@link https://www.rfc-editor.org/rfc/rfc7517 JWK}). "RSA", "EC", "OKP", and "oct"
96101
* key types are supported.
@@ -134,7 +139,7 @@ export interface JWK {
134139
/** JWK "x5u" (X.509 URL) Parameter. */
135140
x5u?: string
136141

137-
[propName: string]: unknown
142+
[propName: string]: JsonValue | undefined
138143
}
139144

140145
/**
@@ -258,7 +263,7 @@ export interface JWSHeaderParameters extends JoseHeaderParameters {
258263
crit?: string[]
259264

260265
/** Any other JWS Header member. */
261-
[propName: string]: unknown
266+
[propName: string]: JsonValue | undefined
262267
}
263268

264269
/** Recognized JWE Key Management-related Header Parameters. */
@@ -366,7 +371,7 @@ export interface JWEHeaderParameters extends JoseHeaderParameters {
366371
zip?: string
367372

368373
/** Any other JWE Header member. */
369-
[propName: string]: unknown
374+
[propName: string]: JsonValue | undefined
370375
}
371376

372377
/** Shared Interface with a "crit" property for all sign, verify, encrypt and decrypt operations. */
@@ -540,7 +545,7 @@ export interface JWTPayload {
540545
iat?: number
541546

542547
/** Any other JWT Claim Set member. */
543-
[propName: string]: unknown
548+
[propName: string]: JsonValue | undefined
544549
}
545550

546551
/**

test/types/index.test-d.ts

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { KeyObject } from 'crypto'
2-
import { expectType } from 'tsd'
2+
import { expectError, expectType } from 'tsd'
33

44
import * as lib from '../../dist/types'
55

@@ -208,3 +208,47 @@ expectType<KeyObject>(await lib.createRemoteJWKSet<KeyObject>(new URL(''))())
208208
expectType<lib.KeyLike>(await lib.EmbeddedJWK())
209209
expectType<CryptoKey>(await lib.EmbeddedJWK())
210210
expectType<KeyObject>(await lib.EmbeddedJWK())
211+
212+
{
213+
const result = await lib.jwtVerify('', new Uint8Array())
214+
switch (typeof result.payload.unknown) {
215+
case 'bigint':
216+
case 'function':
217+
case 'symbol':
218+
expectType<never>(result.payload.unknown)
219+
}
220+
221+
switch (typeof result.protectedHeader.unknown) {
222+
case 'bigint':
223+
case 'function':
224+
case 'symbol':
225+
expectType<never>(result.protectedHeader.unknown)
226+
}
227+
}
228+
229+
{
230+
const result = await lib.decodeJwt('')
231+
switch (typeof result.unknown) {
232+
case 'bigint':
233+
case 'function':
234+
case 'symbol':
235+
expectType<never>(result.unknown)
236+
}
237+
}
238+
239+
{
240+
const result = await lib.decodeProtectedHeader('')
241+
switch (typeof result.unknown) {
242+
case 'bigint':
243+
case 'function':
244+
case 'symbol':
245+
expectType<never>(result.unknown)
246+
}
247+
}
248+
249+
expectError(new lib.SignJWT({ foo() {} }))
250+
expectError(new lib.SignJWT({}).setProtectedHeader({ foo() {} }))
251+
expectError(new lib.SignJWT({ foo: Symbol() }))
252+
expectError(new lib.SignJWT({}).setProtectedHeader({ foo: Symbol() }))
253+
expectError(new lib.SignJWT({ foo: 0n }))
254+
expectError(new lib.SignJWT({}).setProtectedHeader({ foo: 0n }))

0 commit comments

Comments
 (0)