Skip to content

Commit

Permalink
fix(types): headers and payloads may only be JSON values and primitives
Browse files Browse the repository at this point in the history
  • Loading branch information
panva committed Apr 26, 2023
1 parent a60399f commit 24f306e
Show file tree
Hide file tree
Showing 12 changed files with 108 additions and 14 deletions.
4 changes: 4 additions & 0 deletions docs/modules/types.md
Expand Up @@ -10,6 +10,10 @@ Support from the community to continue maintaining and improving this module is

### Type Aliases

- [JsonArray](../types/types.JsonArray.md)
- [JsonObject](../types/types.JsonObject.md)
- [JsonPrimitive](../types/types.JsonPrimitive.md)
- [JsonValue](../types/types.JsonValue.md)
- [KeyLike](../types/types.KeyLike.md)

### Interfaces
Expand Down
9 changes: 9 additions & 0 deletions docs/types/types.JsonArray.md
@@ -0,0 +1,9 @@
# Type alias: JsonArray

## [💗 Help the project](https://github.com/sponsors/panva)

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).

---

Ƭ **JsonArray**: [`JsonValue`](types.JsonValue.md)[]
9 changes: 9 additions & 0 deletions docs/types/types.JsonObject.md
@@ -0,0 +1,9 @@
# Type alias: JsonObject

## [💗 Help the project](https://github.com/sponsors/panva)

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).

---

Ƭ **JsonObject**: { [Key in string]?: JsonValue }
9 changes: 9 additions & 0 deletions docs/types/types.JsonPrimitive.md
@@ -0,0 +1,9 @@
# Type alias: JsonPrimitive

## [💗 Help the project](https://github.com/sponsors/panva)

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).

---

Ƭ **JsonPrimitive**: `string` \| `number` \| `boolean` \| ``null``
9 changes: 9 additions & 0 deletions docs/types/types.JsonValue.md
@@ -0,0 +1,9 @@
# Type alias: JsonValue

## [💗 Help the project](https://github.com/sponsors/panva)

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).

---

Ƭ **JsonValue**: [`JsonPrimitive`](types.JsonPrimitive.md) \| [`JsonObject`](types.JsonObject.md) \| [`JsonArray`](types.JsonArray.md)
3 changes: 2 additions & 1 deletion src/jwe/flattened/encrypt.ts
Expand Up @@ -3,6 +3,7 @@ import encrypt from '../../runtime/encrypt.js'
import { deflate } from '../../runtime/zlib.js'

import type {
JsonValue,
KeyLike,
FlattenedJWE,
JWEHeaderParameters,
Expand Down Expand Up @@ -225,7 +226,7 @@ export class FlattenedEncrypt {

let cek: KeyLike | Uint8Array
{
let parameters: { [propName: string]: unknown } | undefined
let parameters: { [parameter: string]: JsonValue | undefined } | undefined
;({ cek, encryptedKey, parameters } = await encryptKeyManagement(
alg,
enc,
Expand Down
3 changes: 2 additions & 1 deletion src/lib/jwt_claims_set.ts
@@ -1,4 +1,5 @@
import type {
JsonValue,
JWTPayload,
JWTClaimVerificationOptions,
JWEHeaderParameters,
Expand Down Expand Up @@ -40,7 +41,7 @@ export default (
throw new JWTClaimValidationFailed('unexpected "typ" JWT header value', 'typ', 'check_failed')
}

let payload!: { [propName: string]: unknown }
let payload!: { [propName: string]: JsonValue | undefined }
try {
payload = JSON.parse(decoder.decode(encodedPayload))
} catch {
Expand Down
3 changes: 2 additions & 1 deletion src/lib/validate_crit.ts
@@ -1,9 +1,10 @@
import type { JsonValue } from '../types.d'
import { JOSENotSupported, JWEInvalid, JWSInvalid } from '../util/errors.js'

interface CritCheckHeader {
b64?: boolean
crit?: string[]
[propName: string]: unknown
[propName: string]: JsonValue | undefined
}

function validateCrit(
Expand Down
6 changes: 4 additions & 2 deletions src/runtime/interfaces.d.ts
@@ -1,4 +1,4 @@
import type { JWK, KeyLike } from '../types.d'
import type { JWK, KeyLike, JsonValue } from '../types.d'
import type { PEMImportOptions } from '../key/import.js'

type AsyncOrSync<T> = Promise<T> | T
Expand Down Expand Up @@ -57,7 +57,9 @@ export interface DecryptFunction {
): AsyncOrSync<Uint8Array>
}
export interface FetchFunction {
(url: URL, timeout: number, options?: any): Promise<{ [propName: string]: unknown }>
(url: URL, timeout: number, options?: any): Promise<{
[parameter: string]: JsonValue | undefined
}>
}
export interface DigestFunction {
(digest: 'sha256' | 'sha384' | 'sha512', data: Uint8Array): AsyncOrSync<Uint8Array>
Expand Down
8 changes: 4 additions & 4 deletions src/runtime/node/key_to_jwk.ts
Expand Up @@ -36,7 +36,7 @@ const keyToJWK: JWKExportFunction = (key: unknown): JWK => {
) {
throw new JOSENotSupported('Unsupported key asymmetricKeyType')
}
return keyObject.export({ format: 'jwk' })
return <JWK>keyObject.export({ format: 'jwk' })
}

switch (keyObject.type) {
Expand Down Expand Up @@ -112,7 +112,7 @@ const keyToJWK: JWKExportFunction = (key: unknown): JWK => {
if (der.length < 100) {
offset += correction
}
return {
return <JWK>{
...keyToJWK(createPublicKey(keyObject)),
d: base64url(der.subarray(offset, offset + len / 2)),
}
Expand All @@ -130,7 +130,7 @@ const keyToJWK: JWKExportFunction = (key: unknown): JWK => {
}

const der = keyObject.export({ type: 'pkcs8', format: 'der' })
return {
return <JWK>{
...keyToJWK(createPublicKey(keyObject)),
d: base64url(der.subarray(-32)),
}
Expand All @@ -148,7 +148,7 @@ const keyToJWK: JWKExportFunction = (key: unknown): JWK => {
}

const der = keyObject.export({ type: 'pkcs8', format: 'der' })
return {
return <JWK>{
...keyToJWK(createPublicKey(keyObject)),
d: base64url(der.subarray(crv === 'Ed448' ? -57 : -56)),
}
Expand Down
13 changes: 9 additions & 4 deletions src/types.d.ts
Expand Up @@ -91,6 +91,11 @@
*/
export type KeyLike = { type: string }

type JsonObject = { [Key in string]?: JsonValue }
type JsonArray = JsonValue[]
type JsonPrimitive = string | number | boolean | null
type JsonValue = JsonPrimitive | JsonObject | JsonArray

/**
* JSON Web Key ({@link https://www.rfc-editor.org/rfc/rfc7517 JWK}). "RSA", "EC", "OKP", and "oct"
* key types are supported.
Expand Down Expand Up @@ -134,7 +139,7 @@ export interface JWK {
/** JWK "x5u" (X.509 URL) Parameter. */
x5u?: string

[propName: string]: unknown
[propName: string]: JsonValue | undefined
}

/**
Expand Down Expand Up @@ -258,7 +263,7 @@ export interface JWSHeaderParameters extends JoseHeaderParameters {
crit?: string[]

/** Any other JWS Header member. */
[propName: string]: unknown
[propName: string]: JsonValue | undefined
}

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

/** Any other JWE Header member. */
[propName: string]: unknown
[propName: string]: JsonValue | undefined
}

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

/** Any other JWT Claim Set member. */
[propName: string]: unknown
[propName: string]: JsonValue | undefined
}

/**
Expand Down
46 changes: 45 additions & 1 deletion test/types/index.test-d.ts
@@ -1,5 +1,5 @@
import type { KeyObject } from 'crypto'
import { expectType } from 'tsd'
import { expectError, expectType } from 'tsd'

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

Expand Down Expand Up @@ -208,3 +208,47 @@ expectType<KeyObject>(await lib.createRemoteJWKSet<KeyObject>(new URL(''))())
expectType<lib.KeyLike>(await lib.EmbeddedJWK())
expectType<CryptoKey>(await lib.EmbeddedJWK())
expectType<KeyObject>(await lib.EmbeddedJWK())

{
const result = await lib.jwtVerify('', new Uint8Array())
switch (typeof result.payload.unknown) {
case 'bigint':
case 'function':
case 'symbol':
expectType<never>(result.payload.unknown)
}

switch (typeof result.protectedHeader.unknown) {
case 'bigint':
case 'function':
case 'symbol':
expectType<never>(result.protectedHeader.unknown)
}
}

{
const result = await lib.decodeJwt('')
switch (typeof result.unknown) {
case 'bigint':
case 'function':
case 'symbol':
expectType<never>(result.unknown)
}
}

{
const result = await lib.decodeProtectedHeader('')
switch (typeof result.unknown) {
case 'bigint':
case 'function':
case 'symbol':
expectType<never>(result.unknown)
}
}

expectError(new lib.SignJWT({ foo() {} }))
expectError(new lib.SignJWT({}).setProtectedHeader({ foo() {} }))
expectError(new lib.SignJWT({ foo: Symbol() }))
expectError(new lib.SignJWT({}).setProtectedHeader({ foo: Symbol() }))
expectError(new lib.SignJWT({ foo: 0n }))
expectError(new lib.SignJWT({}).setProtectedHeader({ foo: 0n }))

0 comments on commit 24f306e

Please sign in to comment.