{"version":3,"sources":["../src/index.ts","../src/crypto/Hmac.ts","../src/utils/buffer.ts","../src/utils/crypto.ts","../src/utils/error.ts","../src/crypto/SessionCrypto.ts","../src/session/Session.ts","../src/store/MemoryStore.ts","../src/store/SessionStore.ts","../src/plugin.ts"],"sourcesContent":["import fastifyPlugin from \"fastify-plugin\";\nimport { plugin } from \"./plugin\";\n\nexport { HMAC, Hmac, SessionCrypto, type SecretKey } from \"./crypto\";\nexport type { FastifySessionOptions } from \"./plugin\";\nexport { Session, type SessionData } from \"./session\";\nexport { MemoryStore, SessionStore } from \"./store\";\nexport { createError, CRYPTO_SPLIT_CHAR, ErrorWithCode } from \"./utils\";\n\nexport default fastifyPlugin(plugin, {\n  fastify: \">=4.x\",\n  name: \"fastify-session\",\n});\n","import crypto, { type BinaryToTextEncoding } from \"crypto\";\nimport { asBuffer, createError, CRYPTO_SPLIT_CHAR } from \"../utils\";\nimport type { SecretKey, SessionCrypto } from \"./SessionCrypto\";\n\nexport class Hmac implements SessionCrypto {\n  public readonly protocol = \"/hmac\";\n  public readonly stateless = false;\n  private readonly algorithm: string;\n  private readonly encoding: BinaryToTextEncoding;\n  constructor(encoding: BinaryToTextEncoding = \"base64\", algorithm = \"sha256\") {\n    this.encoding = encoding;\n    this.algorithm = algorithm;\n  }\n  public deriveSecretKeys(key?: SecretKey, secret?: Buffer | string): Buffer[] {\n    if (key) {\n      return sanitizeSecretKeys(key, this.encoding);\n    } else if (secret) {\n      return [asBuffer(secret)];\n    }\n    throw createError(\"SecretKeyDerivation\", \"Failed to derive keys from options\");\n  }\n  public sealMessage(message: Buffer, secretKey: Buffer): string {\n    return (\n      message.toString(this.encoding) +\n      CRYPTO_SPLIT_CHAR +\n      crypto.createHmac(this.algorithm, secretKey).update(message).digest(this.encoding).replace(/=+$/, \"\")\n    );\n  }\n  public unsealMessage(message: string, secretKeys: Buffer[]): { buffer: Buffer; rotated: boolean } {\n    const splitCharIndex = message.lastIndexOf(CRYPTO_SPLIT_CHAR);\n    if (splitCharIndex === -1) {\n      throw createError(\"MalformedMessageError\", \"The message is malformed\");\n    }\n    const cleartext = Buffer.from(message.slice(0, splitCharIndex), this.encoding);\n    // const signature = Buffer.from(message.slice(splitCharIndex + 1), this.encoding);\n    // if (signature.length !== 64) {\n    //   throw createError('SignatureLengthError', 'The signature does not have the required length');\n    // }\n\n    let rotated = false;\n    // const messageBuffer = Buffer.from(message);\n    const success = secretKeys.some((secretKey, index) => {\n      const signedBuffer = Buffer.from(this.sealMessage(cleartext, secretKey));\n      const messageBuffer = Buffer.alloc(signedBuffer.length);\n      messageBuffer.write(message);\n      const verified = crypto.timingSafeEqual(signedBuffer, messageBuffer);\n      rotated = verified && index > 0;\n      return verified;\n    });\n\n    if (!success) {\n      throw createError(\"VerifyError\", \"Unable to verify\");\n    }\n\n    return { buffer: cleartext, rotated };\n  }\n}\n\nexport const HMAC = new Hmac();\n\nconst sanitizeSecretKeys = (key: SecretKey, encoding: BufferEncoding = \"base64\"): Buffer[] => {\n  const secretKeys: Buffer[] = Array.isArray(key)\n    ? key.map((v) => asBuffer(v, encoding))\n    : [asBuffer(key, encoding)];\n  return secretKeys;\n};\n","export const asBuffer = (maybeBuffer: Buffer | string, encoding: BufferEncoding = \"ascii\"): Buffer =>\n  Buffer.isBuffer(maybeBuffer) ? maybeBuffer : Buffer.from(maybeBuffer, encoding);\n","import { randomBytes } from \"crypto\";\n\nexport const CRYPTO_SPLIT_CHAR = \".\";\n\nexport const generateRandomKey = (): Buffer => {\n  return randomBytes(32);\n};\n\nexport const generateSalt = (): Buffer => {\n  return randomBytes(32);\n};\n","export class ErrorWithCode extends Error {\n  code: string;\n  constructor(code: string, message?: string) {\n    super(`${code}: ${message}`); // 'Error' breaks prototype chain here\n    Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain\n    this.code = code;\n  }\n}\n\nexport const createError = (code: string, message?: string): ErrorWithCode =>\n  new ErrorWithCode(code, message);\n","export type SecretKey = Buffer | string | (Buffer | string)[];\n\nexport abstract class SessionCrypto {\n  abstract readonly protocol: string;\n  abstract readonly stateless: boolean;\n  abstract deriveSecretKeys(key?: SecretKey, secret?: Buffer | string, salt?: Buffer | string): Buffer[];\n  // Sign or encrypt a message (eg. stringified to cookie)\n  abstract sealMessage(message: Buffer, secretKey: Buffer): string;\n  // Verify or decrypt a message (eg. stringified from cookie)\n  abstract unsealMessage(message: string, secretKeys: Buffer[]): { buffer: Buffer; rotated: boolean };\n}\n","import type { CookieSerializeOptions } from \"@fastify/cookie\";\nimport { nanoid } from \"nanoid\";\nimport assert from \"node:assert\";\nimport { HMAC } from \"../crypto/Hmac\";\nimport type { SessionCrypto } from \"../crypto/SessionCrypto\";\nimport { MEMORY_STORE, SessionStore } from \"../store\";\nimport { createError } from \"../utils\";\nimport type { SessionData } from \"./SessionData\";\n\nexport const kSessionData = Symbol(\"kSessionData\");\nexport const kCookieOptions = Symbol(\"kCookieOptions\");\n\nexport type SessionConfiguration = {\n  cookieOptions?: CookieSerializeOptions;\n  crypto?: SessionCrypto;\n  store?: SessionStore | undefined;\n  secretKeys: Buffer[];\n};\n\nexport type SessionOptions = CookieSerializeOptions & {\n  id?: string;\n};\n\n/**\n * The Session class is responsible for managing user session data.\n * It can operate in a stateful or stateless mode depending on the configuration.\n */\nexport class Session<T extends SessionData = SessionData> {\n  // Session metadata\n  public readonly id: string;\n  public created = false;\n  public rotated = false;\n  public changed = false;\n  public deleted = false;\n  public saved = false;\n  public skipped = false;\n\n  // Private instance fields\n  #sessionData: Partial<T>;\n  #cookieOptions: CookieSerializeOptions;\n  #expiry: number | null = null; // expiration timestamp in ms\n\n  // Private static fields\n  static #secretKeys: Buffer[];\n  static #sessionCrypto: SessionCrypto;\n  static #sessionStore?: SessionStore;\n  static #globalCookieOptions: CookieSerializeOptions;\n  static #configured = false;\n\n  /**\n   * This method is used to setup the Session class with global options.\n   */\n  static configure({\n    secretKeys,\n    crypto = HMAC,\n    store = MEMORY_STORE,\n    cookieOptions = {},\n  }: SessionConfiguration): void {\n    Session.#secretKeys = secretKeys;\n    Session.#sessionCrypto = crypto;\n    Session.#sessionStore = store;\n    Session.#globalCookieOptions = cookieOptions;\n    Session.#configured = true;\n  }\n\n  /**\n   * Private constructor - instances should be created via the static `create` method\n   */\n  private constructor(data?: Partial<T>, options: SessionOptions = {}) {\n    const { id = nanoid(), ...cookieOptions } = options;\n    this.#sessionData = data ?? {};\n    this.#cookieOptions = { ...Session.#globalCookieOptions, ...cookieOptions };\n    this.id = id;\n    this.created = !data;\n  }\n\n  /**\n   * Create a new session instance.\n   * Checks if the class is configured before creating a session.\n   */\n  static async create<T extends SessionData = SessionData>(\n    data?: Partial<T>,\n    options: SessionOptions = {},\n  ): Promise<Session> {\n    if (!Session.#configured) {\n      throw createError(\n        \"MissingConfiguration\",\n        \"Session is not configured. Please call Session.configure before creating a Session instance.\",\n      );\n    }\n    const session = new Session(data, options);\n    await session.touch();\n    return session;\n  }\n\n  /**\n   * Decoding\n   */\n\n  /**\n   * Create a Session from a serialized cookie.\n   * Determines the type of the session (stateful/stateless) and delegates to the appropriate method.\n   */\n  static async fromCookie(cookie: string): Promise<Session> {\n    const { buffer: cleartext, rotated } = Session.#sessionCrypto.unsealMessage(cookie, Session.#secretKeys);\n\n    if (Session.#sessionCrypto.stateless) {\n      return await Session.fromStatelessCookie(cleartext.toString(), rotated);\n    }\n    return await Session.fromStatefulCookie(cleartext.toString(), rotated);\n  }\n\n  /**\n   * Create a Session from a stateless cookie. The session data is all stored in the cookie.\n   */\n  private static async fromStatelessCookie(payload: string, rotated: boolean): Promise<Session> {\n    let data;\n    try {\n      data = JSON.parse(payload) as SessionData;\n    } catch (error) {\n      throw createError(\n        \"InvalidData\",\n        `Failed to parse session data from cookie. Original error: ${String(error)}`,\n      );\n    }\n    const session = await Session.create(data, { id: data.id });\n    session.rotated = rotated;\n    return session;\n  }\n\n  /**\n   * Create a Session from a stateful cookie. The cookie only contains the session id.\n   * The rest of the session data is retrieved from the session store.\n   */\n  private static async fromStatefulCookie(sessionId: string, rotated: boolean): Promise<Session> {\n    assert(Session.#sessionStore);\n    const result = await Session.#sessionStore.get(sessionId);\n    if (!result) {\n      throw createError(\"SessionNotFound\", \"did not found a matching session in the store\");\n    }\n    const [data, expiry] = result;\n    if (expiry && expiry <= Date.now()) {\n      throw createError(\"ExpiredSession\", \"the store returned an expired session\");\n    }\n    const session = await Session.create(data, {\n      id: sessionId,\n      expires: expiry ? new Date(expiry) : undefined,\n    });\n    session.rotated = rotated;\n    return session;\n  }\n\n  /**\n   * Encoding\n   */\n\n  /**\n   * Serialize the Session into a cookie.\n   * The format of the cookie depends on whether the session is stateful or stateless.\n   */\n  // eslint-disable-next-line @typescript-eslint/require-await\n  async toCookie(): Promise<string> {\n    const buffer = Buffer.from(\n      Session.#sessionCrypto.stateless ? JSON.stringify({ ...this.#sessionData, id: this.id }) : this.id,\n    );\n    if (!Session.#secretKeys[0]) {\n      throw createError(\"MissingSecretKey\", \"Missing secret key for session encryption\");\n    }\n    return Session.#sessionCrypto.sealMessage(buffer, Session.#secretKeys[0]);\n  }\n\n  /**\n   * Refresh the expiration time of the session. Only applicable for stateful sessions.\n   */\n  async touch(): Promise<void> {\n    if (Session.#sessionCrypto.stateless) {\n      return;\n    }\n    const { maxAge = Session.#globalCookieOptions.maxAge, expires = Session.#globalCookieOptions.expires } =\n      this.#cookieOptions;\n    if (maxAge) {\n      const expiry = Date.now() + maxAge * 1000;\n      // Get the longest lifespan between \"expires\" and \"maxAge\"\n      this.#expiry = expires ? Math.max(expires.getTime(), expiry) : expiry;\n    } else if (expires) {\n      this.#expiry = expires.getTime();\n    }\n    assert(Session.#sessionStore);\n    // Only relay touch to the store for existing sessions to propagate expiry changes\n    if (!this.created && Session.#sessionStore.touch) {\n      await Session.#sessionStore.touch(this.id, this.#expiry);\n    }\n  }\n\n  /**\n   * Delete the session.\n   */\n  async destroy(): Promise<void> {\n    this.deleted = true;\n    if (Session.#sessionCrypto.stateless) {\n      return;\n    }\n    // Only relay destroy to the store for existing sessions that have not been saved\n    if (this.created && !this.saved) {\n      return;\n    }\n    assert(Session.#sessionStore);\n    await Session.#sessionStore.destroy(this.id);\n  }\n\n  /**\n   * Save the session data to the session store. Only applicable for stateful sessions.\n   */\n  async save(): Promise<void> {\n    if (Session.#sessionCrypto.stateless) {\n      return;\n    }\n    this.saved = true;\n    // Save session to store with store-handled expiry\n    assert(Session.#sessionStore);\n    await Session.#sessionStore.set(this.id, this.#sessionData, this.#expiry);\n  }\n\n  get data(): SessionData {\n    return this.#sessionData;\n  }\n\n  get expiry(): number | null {\n    return this.#expiry;\n  }\n\n  /**\n   * Get a value from the session data.\n   */\n  get<K extends keyof T = keyof T>(key: K): T[K] | undefined {\n    return this.#sessionData[key];\n  }\n\n  set<K extends keyof T = keyof T>(key: K, value: T[K]): void {\n    this.#sessionData[key] = value;\n    this.changed = true;\n  }\n\n  get options(): CookieSerializeOptions {\n    return this.#cookieOptions;\n  }\n\n  /**\n   * Update the session cookie options.\n   */\n  setOptions(options: CookieSerializeOptions): void {\n    Object.assign(this.#cookieOptions, options);\n  }\n\n  /**\n   * Check if the session data is empty.\n   */\n  isEmpty(): boolean {\n    return Object.keys(this.#sessionData).length === 0;\n  }\n}\n","/* eslint-disable @typescript-eslint/require-await */\n\nimport { EventEmitter } from \"events\";\nimport type { SessionData, SessionStore } from \"./SessionStore\";\n\ntype StoredData<T> = [T, number | null]; // [session data, expiry time in ms]\nexport type MemoryStoreOptions<T> = { store?: Map<string, StoredData<T>>; prefix?: string };\n\nexport class MemoryStore<T extends SessionData = SessionData> extends EventEmitter implements SessionStore {\n  private store: Map<string, StoredData<T>>;\n  private readonly prefix: string;\n\n  constructor({ store = new Map(), prefix = \"sess:\" }: MemoryStoreOptions<T> = {}) {\n    super();\n    this.store = store;\n    this.prefix = prefix;\n  }\n\n  private getKey(sessionId: string) {\n    return `${this.prefix}${sessionId}`;\n  }\n\n  async set(sessionId: string, session: T, expiry: number | null = null): Promise<void> {\n    this.store.set(this.getKey(sessionId), [session, expiry]);\n  }\n\n  async get(sessionId: string): Promise<[T, number | null] | null> {\n    const result = this.store.get(this.getKey(sessionId)) ?? null;\n    if (!result) {\n      return null;\n    }\n    const [session, expiry] = result;\n    if (expiry && expiry <= Date.now()) {\n      return null;\n    }\n    return [session, expiry];\n  }\n\n  async destroy(sessionId: string): Promise<void> {\n    this.store.delete(this.getKey(sessionId));\n  }\n\n  async touch(sessionId: string, expiry: number | null = null): Promise<void> {\n    const sessionData = await this.get(sessionId);\n    if (!sessionData) {\n      return;\n    }\n    const [session] = sessionData;\n    await this.set(sessionId, session, expiry);\n  }\n\n  async all(): Promise<Record<string, SessionData>> {\n    return [...this.store.entries()].reduce<Record<string, SessionData>>((soFar, [k, v]) => {\n      soFar[k] = v[0];\n      return soFar;\n    }, {});\n  }\n}\n\nexport const MEMORY_STORE = new MemoryStore();\n","import type { SessionData } from \"../session/SessionData\";\nexport type { SessionData };\n\nexport abstract class SessionStore {\n  // Gets the session from the store given a session ID.\n  abstract get(sid: string): Promise<[SessionData, number | null] | null>;\n\n  // Upsert a session in the store given a session ID and `SessionData`.\n  abstract set(sid: string, session: SessionData, expiry?: number | null): Promise<void>;\n\n  // Destroys the session with the given session ID.\n  abstract destroy(sid: string): Promise<void>;\n\n  // Returns all sessions in the store\n  async all?(): Promise<SessionData[] | Record<string, SessionData> | null>;\n\n  // Returns the amount of sessions in the store.\n  async length?(): Promise<number>;\n\n  // Delete all sessions from the store.\n  async clear?(): Promise<void>;\n\n  // \"Touches\" a given session, resetting the idle timer.\n  async touch?(sid: string, expiry?: number | null): Promise<void>;\n}\n","/* eslint-disable @typescript-eslint/require-await */\nimport type { CookieSerializeOptions } from \"@fastify/cookie\";\nimport type { FastifyPluginAsync, FastifyRequest } from \"fastify\";\nimport { HMAC, SessionCrypto, type SecretKey } from \"./crypto\";\nimport { Session } from \"./session\";\nimport type { SessionStore } from \"./store\";\n\nexport const DEFAULT_COOKIE_NAME = \"Session\";\nexport const DEFAULT_COOKIE_PATH = \"/\";\n\nexport type FastifySessionOptions = {\n  salt?: Buffer | string;\n  secret?: Buffer | string;\n  key?: SecretKey;\n  cookieName?: string;\n  cookie?: CookieSerializeOptions;\n  store?: SessionStore;\n  crypto?: SessionCrypto;\n  saveUninitialized?: boolean;\n  logBindings?: Record<string, unknown>;\n};\n\nexport const plugin: FastifyPluginAsync<FastifySessionOptions> = async (\n  fastify,\n  options = {},\n): Promise<void> => {\n  const {\n    key,\n    secret,\n    salt,\n    cookieName = DEFAULT_COOKIE_NAME,\n    cookie: cookieOptions = {},\n    store,\n    crypto = HMAC as SessionCrypto,\n    saveUninitialized = true,\n    logBindings = { plugin: \"fastify-session\" },\n  } = options;\n\n  if (!key && !secret) {\n    throw new Error(\"key or secret must specified\");\n  }\n  if (!crypto) {\n    throw new Error(\"invalid crypto specified\");\n  }\n\n  if (!cookieOptions.path) {\n    cookieOptions.path = DEFAULT_COOKIE_PATH;\n  }\n  const secretKeys: Buffer[] = crypto.deriveSecretKeys(key, secret, salt);\n  Session.configure({ cookieOptions, secretKeys, store, crypto });\n\n  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n  fastify.decorateRequest(\"session\", null!);\n  async function destroySession(this: FastifyRequest) {\n    if (!this.session) {\n      return;\n    }\n    await this.session.destroy();\n  }\n  fastify.decorateRequest(\"destroySession\", destroySession);\n\n  // decode/create a session for every request\n  fastify.addHook(\"onRequest\", async (request) => {\n    const { cookies, log } = request;\n    const bindings = { ...logBindings, hook: \"onRequest\" };\n\n    const cookie = cookies[cookieName];\n    if (!cookie) {\n      request.session = await Session.create();\n      log.debug(\n        { ...bindings, sessionId: request.session.id },\n        \"There was no cookie, created an empty session\",\n      );\n      return;\n    }\n\n    try {\n      log.debug(bindings, \"Found an existing cookie, attempting to decode session ...\");\n      request.session = await Session.fromCookie(cookie);\n      log.debug({ ...bindings, sessionId: request.session.id }, \"Session successfully decoded\");\n      return;\n    } catch (err) {\n      request.session = await Session.create();\n      log.warn(\n        { ...bindings, err, sessionId: request.session.id },\n        `Failed to decode existing cookie, created an empty session`,\n      );\n      return;\n    }\n  });\n\n  // encode a cookie\n  fastify.addHook(\"onSend\", async (request, reply) => {\n    const { session, log } = request;\n    const bindings = { ...logBindings, hook: \"onSend\" };\n\n    if (!session) {\n      log.debug(bindings, \"There was no session, leaving it as is\");\n      return;\n    } else if (session.deleted) {\n      reply.setCookie(cookieName, \"\", {\n        ...session.options,\n        expires: new Date(0),\n        maxAge: 0,\n      });\n      log.debug(\n        { ...bindings, sessionId: session.id },\n        `Deleted ${session.created ? \"newly created\" : \"existing\"} session`,\n      );\n      return;\n    } else if (!saveUninitialized && session.isEmpty()) {\n      log.debug(\n        { ...bindings, sessionId: session.id },\n        \"Created session is empty and won't be saved, leaving it as is\",\n      );\n      return;\n    } else if (!session.changed && !session.created && !session.rotated) {\n      log.debug(\n        { ...bindings, sessionId: session.id },\n        \"The existing session was not changed, leaving it as is\",\n      );\n      return;\n    } else if (session.skipped) {\n      log.debug({ ...bindings, sessionId: session.id }, \"Skipped session\");\n      return;\n    }\n\n    if (session.created || session.changed) {\n      log.debug(\n        { ...bindings, sessionId: session.id },\n        `About to save a ${session.created ? \"created\" : \"changed\"} session, saving ...`,\n      );\n      await session.save();\n      log.debug(\n        { ...bindings, sessionId: session.id },\n        `${session.created ? \"Created\" : \"Changed\"} session successfully saved`,\n      );\n    }\n    reply.setCookie(cookieName, await session.toCookie(), session.options);\n  });\n};\n"],"mappings":"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","names":["crypto","crypto","assert","crypto","fastifyPlugin"]}