Skip to content

Instantly share code, notes, and snippets.

@rjz
Created August 8, 2023 22:41
Show Gist options
  • Select an option

  • Save rjz/9f1339d1c0dfbbf09be95295b90dded4 to your computer and use it in GitHub Desktop.

Select an option

Save rjz/9f1339d1c0dfbbf09be95295b90dded4 to your computer and use it in GitHub Desktop.

Revisions

  1. rjz created this gist Aug 8, 2023.
    36 changes: 36 additions & 0 deletions codec.ts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,36 @@
    /** `x/crypto` if running in `deno` */
    import { createHmac } from 'node:crypto'

    /** A signing secret */
    const HMAC_SECRET = '<YOUR SIGNING SECRET HERE>'

    /** Length of a hexidecimal HMAC digest */
    const HMAC_LENGTH = 64

    function hmac(message: string): string {
    return createHmac('sha256', HMAC_SECRET).update(message).digest('hex')
    }

    interface Codec<T> {
    encode(payload: T): string
    decode(payload: string): T | null
    }

    function create<T>(codec: Codec<T>): Codec<T> {
    return {
    encode(payload: T) {
    const encoded = codec.encode(payload)
    return hmac(encoded) + encoded
    },
    decode(x: string): T | null {
    const signature = x.substring(0, HMAC_LENGTH)
    const payload = x.substring(HMAC_LENGTH)
    const computed = hmac(payload)
    if (computed !== signature) {
    return null
    }

    return codec.decode(payload)
    },
    }
    }