Skip to content

Commit

Permalink
refactor(utils/jwt): remove some any (#2684)
Browse files Browse the repository at this point in the history
* refactor(jwt): remove some `any`

* refactor(types): remove type confusion

* chore: denoify & lint

* chore: remove eslint comment
  • Loading branch information
fzn0x authored May 16, 2024
1 parent f7225ee commit d87d996
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 74 deletions.
37 changes: 17 additions & 20 deletions deno_dist/utils/jwt/jwt.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { encodeBase64Url, decodeBase64Url } from '../../utils/encode.ts'
import type { SignatureAlgorithm } from './jwa.ts'
import { AlgorithmTypes } from './jwa.ts'
import type { SignatureKey } from './jws.ts'
import { signing, verifying } from './jws.ts'
import { AlgorithmTypes, type SignatureAlgorithm } from './jwa.ts'
import { signing, verifying, type SignatureKey } from './jws.ts'
import { JwtHeaderInvalid, type JWTPayload } from './types.ts'
import {
JwtTokenInvalid,
Expand All @@ -17,23 +15,24 @@ const encodeJwtPart = (part: unknown): string =>
encodeBase64Url(utf8Encoder.encode(JSON.stringify(part))).replace(/=/g, '')
const encodeSignaturePart = (buf: ArrayBufferLike): string => encodeBase64Url(buf).replace(/=/g, '')

const decodeJwtPart = (part: string): unknown =>
const decodeJwtPart = (part: string): TokenHeader | JWTPayload | undefined =>
JSON.parse(utf8Decoder.decode(decodeBase64Url(part)))

export interface TokenHeader {
alg: SignatureAlgorithm
typ?: 'JWT'
}

// eslint-disable-next-line
export function isTokenHeader(obj: any): obj is TokenHeader {
return (
typeof obj === 'object' &&
obj !== null &&
'alg' in obj &&
Object.values(AlgorithmTypes).includes(obj.alg) &&
(!('typ' in obj) || obj.typ === 'JWT')
)
export function isTokenHeader(obj: unknown): obj is TokenHeader {
if (typeof obj === 'object' && obj !== null) {
const objWithAlg = obj as { [key: string]: unknown }
return (
'alg' in objWithAlg &&
Object.values(AlgorithmTypes).includes(objWithAlg.alg as AlgorithmTypes) &&
(!('typ' in objWithAlg) || objWithAlg.typ === 'JWT')
)
}
return false
}

export const sign = async (
Expand All @@ -56,8 +55,7 @@ export const verify = async (
token: string,
publicKey: SignatureKey,
alg: SignatureAlgorithm = 'HS256'
// eslint-disable-next-line @typescript-eslint/no-explicit-any
): Promise<any> => {
): Promise<JWTPayload> => {
const tokenParts = token.split('.')
if (tokenParts.length !== 3) {
throw new JwtTokenInvalid(token)
Expand Down Expand Up @@ -92,12 +90,11 @@ export const verify = async (
return payload
}

// eslint-disable-next-line
export const decode = (token: string): { header: any; payload: any } => {
export const decode = (token: string): { header: TokenHeader; payload: JWTPayload } => {
try {
const [h, p] = token.split('.')
const header = decodeJwtPart(h)
const payload = decodeJwtPart(p)
const header = decodeJwtPart(h) as TokenHeader
const payload = decodeJwtPart(p) as JWTPayload
return {
header,
payload,
Expand Down
32 changes: 15 additions & 17 deletions deno_dist/utils/jwt/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,20 +61,18 @@ export enum CryptoKeyUsage {
/**
* JWT Payload
*/
export type JWTPayload =
| (unknown & {})
| {
[key: string]: unknown
/**
* The token is checked to ensure it has not expired.
*/
exp?: number
/**
* The token is checked to ensure it is not being used before a specified time.
*/
nbf?: number
/**
* The token is checked to ensure it is not issued in the future.
*/
iat?: number
}
export type JWTPayload = {
[key: string]: unknown
/**
* The token is checked to ensure it has not expired.
*/
exp?: number
/**
* The token is checked to ensure it is not being used before a specified time.
*/
nbf?: number
/**
* The token is checked to ensure it is not issued in the future.
*/
iat?: number
}
37 changes: 17 additions & 20 deletions src/utils/jwt/jwt.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { encodeBase64Url, decodeBase64Url } from '../../utils/encode'
import type { SignatureAlgorithm } from './jwa'
import { AlgorithmTypes } from './jwa'
import type { SignatureKey } from './jws'
import { signing, verifying } from './jws'
import { AlgorithmTypes, type SignatureAlgorithm } from './jwa'
import { signing, verifying, type SignatureKey } from './jws'
import { JwtHeaderInvalid, type JWTPayload } from './types'
import {
JwtTokenInvalid,
Expand All @@ -17,23 +15,24 @@ const encodeJwtPart = (part: unknown): string =>
encodeBase64Url(utf8Encoder.encode(JSON.stringify(part))).replace(/=/g, '')
const encodeSignaturePart = (buf: ArrayBufferLike): string => encodeBase64Url(buf).replace(/=/g, '')

const decodeJwtPart = (part: string): unknown =>
const decodeJwtPart = (part: string): TokenHeader | JWTPayload | undefined =>
JSON.parse(utf8Decoder.decode(decodeBase64Url(part)))

export interface TokenHeader {
alg: SignatureAlgorithm
typ?: 'JWT'
}

// eslint-disable-next-line
export function isTokenHeader(obj: any): obj is TokenHeader {
return (
typeof obj === 'object' &&
obj !== null &&
'alg' in obj &&
Object.values(AlgorithmTypes).includes(obj.alg) &&
(!('typ' in obj) || obj.typ === 'JWT')
)
export function isTokenHeader(obj: unknown): obj is TokenHeader {
if (typeof obj === 'object' && obj !== null) {
const objWithAlg = obj as { [key: string]: unknown }
return (
'alg' in objWithAlg &&
Object.values(AlgorithmTypes).includes(objWithAlg.alg as AlgorithmTypes) &&
(!('typ' in objWithAlg) || objWithAlg.typ === 'JWT')
)
}
return false
}

export const sign = async (
Expand All @@ -56,8 +55,7 @@ export const verify = async (
token: string,
publicKey: SignatureKey,
alg: SignatureAlgorithm = 'HS256'
// eslint-disable-next-line @typescript-eslint/no-explicit-any
): Promise<any> => {
): Promise<JWTPayload> => {
const tokenParts = token.split('.')
if (tokenParts.length !== 3) {
throw new JwtTokenInvalid(token)
Expand Down Expand Up @@ -92,12 +90,11 @@ export const verify = async (
return payload
}

// eslint-disable-next-line
export const decode = (token: string): { header: any; payload: any } => {
export const decode = (token: string): { header: TokenHeader; payload: JWTPayload } => {
try {
const [h, p] = token.split('.')
const header = decodeJwtPart(h)
const payload = decodeJwtPart(p)
const header = decodeJwtPart(h) as TokenHeader
const payload = decodeJwtPart(p) as JWTPayload
return {
header,
payload,
Expand Down
32 changes: 15 additions & 17 deletions src/utils/jwt/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,20 +61,18 @@ export enum CryptoKeyUsage {
/**
* JWT Payload
*/
export type JWTPayload =
| (unknown & {})
| {
[key: string]: unknown
/**
* The token is checked to ensure it has not expired.
*/
exp?: number
/**
* The token is checked to ensure it is not being used before a specified time.
*/
nbf?: number
/**
* The token is checked to ensure it is not issued in the future.
*/
iat?: number
}
export type JWTPayload = {
[key: string]: unknown
/**
* The token is checked to ensure it has not expired.
*/
exp?: number
/**
* The token is checked to ensure it is not being used before a specified time.
*/
nbf?: number
/**
* The token is checked to ensure it is not issued in the future.
*/
iat?: number
}

0 comments on commit d87d996

Please sign in to comment.