Repository: honojs/hono
File: src/utils/cookie.ts (TypeScript)

Code before:
  signingSecret?: string
  sameSite?: 'Strict' | 'Lax' | 'None'
}

const makeSignature = async (value: string, secret: string): Promise<string> => {
  const algorithm = { name: 'HMAC', hash: 'SHA-256' }
  const encoder = new TextEncoder()
  const key = await crypto.subtle.importKey('raw', encoder.encode(secret), algorithm, false, [
    'sign',
    'verify',
  ])
  const signature = await crypto.subtle.sign(algorithm.name, key, encoder.encode(value))
  // the returned base64 encoded signature will always be 44 characters long and end with one or two equal signs
  return btoa(String.fromCharCode(...new Uint8Array(signature)))
}

const _parseCookiePairs = (cookie: string, name?: string): string[][] => {
  const pairs = cookie.split(/;\s*/g)
  const cookiePairs = pairs.map((pairStr: string) => pairStr.split(/\s*=\s*([^\s]+)/))
  if (!name) return cookiePairs
  return cookiePairs.filter((pair) => pair[0] === name)
}

export const parse = (cookie: string, name?: string): Cookie => {
  const parsedCookie: Cookie = {}
  const unsingedCookies = _parseCookiePairs(cookie, name).filter((pair) => {
    // ignore signed cookies, assuming they always have that commonly accepted format
    const valueSplit = pair[1].split('.')
    const signature = valueSplit[1] ? decodeURIComponent_(valueSplit[1]) : undefined
    if (
      valueSplit.length === 2 &&
      signature &&
      signature.length === 44 &&
      signature.endsWith('=')
    ) {
      return false
    }
    return true
  })
  for (let [key, value] of unsingedCookies) {
    value = decodeURIComponent_(value)
    parsedCookie[key] = value
  }
  return parsedCookie
}

export const parseSigned = async (
  cookie: string,
  secret: string,
  name?: string
): Promise<SignedCookie> => {

Review comment (suggestion):
It's typo! `unsingedCookies` should be `unsignedCookies`.

Code after:
  signingSecret?: string
  sameSite?: 'Strict' | 'Lax' | 'None'
}

const makeSignature = async (value: string, secret: string): Promise<string> => {
  const algorithm = { name: 'HMAC', hash: 'SHA-256' }
  const encoder = new TextEncoder()
  const key = await crypto.subtle.importKey('raw', encoder.encode(secret), algorithm, false, [
    'sign',
    'verify',
  ])
  const signature = await crypto.subtle.sign(algorithm.name, key, encoder.encode(value))
  // the returned base64 encoded signature will always be 44 characters long and end with one or two equal signs
  return btoa(String.fromCharCode(...new Uint8Array(signature)))
}

const _parseCookiePairs = (cookie: string, name?: string): string[][] => {
  const pairs = cookie.split(/;\s*/g)
  const cookiePairs = pairs.map((pairStr: string) => pairStr.split(/\s*=\s*([^\s]+)/))
  if (!name) return cookiePairs
  return cookiePairs.filter((pair) => pair[0] === name)
}

export const parse = (cookie: string, name?: string): Cookie => {
  const parsedCookie: Cookie = {}
  const unsignedCookies = _parseCookiePairs(cookie, name).filter((pair) => {
    // ignore signed cookies, assuming they always have that commonly accepted format
    const valueSplit = pair[1].split('.')
    const signature = valueSplit[1] ? decodeURIComponent_(valueSplit[1]) : undefined
    if (
      valueSplit.length === 2 &&
      signature &&
      signature.length === 44 &&
      signature.endsWith('=')
    ) {
      return false
    }
    return true
  })
  for (let [key, value] of unsignedCookies) {
    value = decodeURIComponent_(value)
    parsedCookie[key] = value
  }
  return parsedCookie
}

export const parseSigned = async (
  cookie: string,
  secret: string,
  name?: string
): Promise<SignedCookie> => {