{"version":3,"sources":["../../src/clerk/index.ts","../../../utils/logger/index.ts","../../src/cts/index.ts","../../../utils/config/index.ts","../../src/index.ts"],"sourcesContent":["import type { ClerkMiddlewareAuth } from '@clerk/nextjs/server'\nimport type { NextRequest } from 'next/server'\nimport { NextResponse } from 'next/server'\nimport { logger } from '../../../utils/logger'\nimport { setCtsToken } from '../cts'\nimport { CS_COOKIE_NAME, resetCtsToken } from '../index'\n\nexport const protectClerkMiddleware = async (\n  auth: ClerkMiddlewareAuth,\n  req: NextRequest,\n) => {\n  const { userId, getToken } = await auth()\n  const ctsSession = req.cookies.has(CS_COOKIE_NAME)\n\n  if (userId && !ctsSession) {\n    const oidcToken = await getToken()\n\n    if (!oidcToken) {\n      logger.debug(\n        'No Clerk token found in the request, so the CipherStash session was not set.',\n      )\n\n      return NextResponse.next()\n    }\n\n    return await setCtsToken(oidcToken)\n  }\n\n  if (!userId && ctsSession) {\n    logger.debug(\n      'No Clerk token found in the request, so the CipherStash session was reset.',\n    )\n\n    return resetCtsToken()\n  }\n\n  logger.debug(\n    'No Clerk token found in the request, so the CipherStash session was not set.',\n  )\n\n  return NextResponse.next()\n}\n","function getLevelValue(level: string): number {\n  switch (level) {\n    case 'debug':\n      return 10\n    case 'info':\n      return 20\n    case 'error':\n      return 30\n    default:\n      return 30 // default to error level\n  }\n}\n\nconst envLogLevel = process.env.PROTECT_LOG_LEVEL || 'info'\nconst currentLevel = getLevelValue(envLogLevel)\n\nfunction debug(...args: unknown[]): void {\n  if (currentLevel <= getLevelValue('debug')) {\n    console.debug('[protect] DEBUG', ...args)\n  }\n}\n\nfunction info(...args: unknown[]): void {\n  if (currentLevel <= getLevelValue('info')) {\n    console.info('[protect] INFO', ...args)\n  }\n}\n\nfunction error(...args: unknown[]): void {\n  if (currentLevel <= getLevelValue('error')) {\n    console.error('[protect] ERROR', ...args)\n  }\n}\n\nexport const logger = {\n  debug,\n  info,\n  error,\n}\n","import { NextResponse } from 'next/server'\nimport { logger } from '../../../utils/logger'\nimport { loadWorkSpaceId } from '../../../utils/config'\nimport {\n  CS_COOKIE_NAME,\n  type CtsToken,\n  type GetCtsTokenResponse,\n} from '../index'\n\n// Can be used independently of the Next.js middleware\nexport const fetchCtsToken = async (oidcToken: string): GetCtsTokenResponse => {\n  const workspaceId = loadWorkSpaceId()\n\n  if (!workspaceId) {\n    logger.error(\n      'The \"CS_WORKSPACE_ID\" environment variable is not set, and is required by protectClerkMiddleware. No CipherStash session will be set.',\n    )\n\n    return {\n      success: false,\n      error: 'The \"CS_WORKSPACE_ID\" environment variable is not set.',\n    }\n  }\n\n  const ctsEndoint =\n    process.env.CS_CTS_ENDPOINT ||\n    'https://ap-southeast-2.aws.auth.viturhosted.net'\n\n  const ctsResponse = await fetch(`${ctsEndoint}/api/authorize`, {\n    method: 'POST',\n    headers: {\n      'Content-Type': 'application/json',\n    },\n    body: JSON.stringify({\n      workspaceId,\n      oidcToken,\n    }),\n  })\n\n  if (!ctsResponse.ok) {\n    logger.debug(`Failed to fetch CTS token: ${ctsResponse.statusText}`)\n\n    logger.error(\n      'There was an issue communicating with the CipherStash CTS API, the CipherStash session was not set. If the issue persists, please contact support.',\n    )\n\n    return {\n      success: false,\n      error: `Failed to fetch CTS token: ${ctsResponse.statusText}`,\n    }\n  }\n\n  const cts_token = (await ctsResponse.json()) as CtsToken\n\n  return {\n    success: true,\n    ctsToken: cts_token,\n  }\n}\n\n// Used in the Next.js middleware\nexport const setCtsToken = async (oidcToken: string, res?: NextResponse) => {\n  const ctsResponse = await fetchCtsToken(oidcToken)\n  const cts_token = ctsResponse.ctsToken\n\n  if (!cts_token) {\n    logger.debug(`Failed to fetch CTS token: ${ctsResponse.error}`)\n\n    logger.error(\n      'There was an issue fetching the CipherStash session, the CipherStash session was not set. If the issue persists, please contact support.',\n    )\n\n    return res ?? NextResponse.next()\n  }\n\n  // Setting cookies on the request and response using the `ResponseCookies` API\n  const response = res ?? NextResponse.next()\n  response.cookies.set({\n    name: CS_COOKIE_NAME,\n    value: JSON.stringify(cts_token),\n    expires: new Date(cts_token.expiry * 1000),\n    sameSite: 'lax',\n    path: '/',\n  })\n\n  return response\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\n\n/**\n * A lightweight function that parses a TOML-like string\n * and returns the `workspace_crn` value found under `[auth]`.\n *\n * @param tomlString The contents of the TOML file as a string.\n * @returns The workspace_crn if found, otherwise undefined.\n */\nfunction getWorkspaceCrn(tomlString: string): string | undefined {\n  let currentSection = ''\n  let workspaceCrn: string | undefined\n\n  const lines = tomlString.split(/\\r?\\n/)\n\n  for (const line of lines) {\n    const trimmedLine = line.trim()\n\n    if (!trimmedLine || trimmedLine.startsWith('#')) {\n      continue\n    }\n\n    const sectionMatch = trimmedLine.match(/^\\[([^\\]]+)\\]$/)\n    if (sectionMatch) {\n      currentSection = sectionMatch[1]\n      continue\n    }\n\n    const kvMatch = trimmedLine.match(/^(\\w+)\\s*=\\s*\"([^\"]+)\"$/)\n    if (kvMatch) {\n      const [_, key, value] = kvMatch\n\n      if (currentSection === 'auth' && key === 'workspace_crn') {\n        workspaceCrn = value\n        break\n      }\n    }\n  }\n\n  return workspaceCrn\n}\n\n/**\n * Extracts the workspace ID from a CRN string.\n * CRN format: crn:region.aws:ID\n *\n * @param crn The CRN string to extract from\n * @returns The workspace ID portion of the CRN\n */\nfunction extractWorkspaceIdFromCrn(crn: string): string {\n  const match = crn.match(/crn:[^:]+:([^:]+)$/)\n  if (!match) {\n    throw new Error('Invalid CRN format')\n  }\n  return match[1]\n}\n\nexport function loadWorkSpaceId(): string {\n  const configPath = path.join(process.cwd(), 'cipherstash.toml')\n\n  if (!fs.existsSync(configPath) && !process.env.CS_WORKSPACE_CRN) {\n    throw new Error(\n      'You have not defined a workspace CRN in your config file, or the CS_WORKSPACE_CRN environment variable.',\n    )\n  }\n\n  // Environment variables take precedence over config files\n  if (process.env.CS_WORKSPACE_CRN) {\n    return extractWorkspaceIdFromCrn(process.env.CS_WORKSPACE_CRN)\n  }\n\n  if (!fs.existsSync(configPath)) {\n    throw new Error(\n      'You have not defined a workspace CRN in your config file, or the CS_WORKSPACE_CRN environment variable.',\n    )\n  }\n\n  const tomlString = fs.readFileSync(configPath, 'utf8')\n  const workspaceCrn = getWorkspaceCrn(tomlString)\n\n  if (!workspaceCrn) {\n    throw new Error(\n      'You have not defined a workspace CRN in your config file, or the CS_WORKSPACE_CRN environment variable.',\n    )\n  }\n\n  return extractWorkspaceIdFromCrn(workspaceCrn)\n}\n","import { decodeJwt } from 'jose'\nimport { cookies } from 'next/headers'\nimport type { NextRequest } from 'next/server'\nimport { NextResponse } from 'next/server'\nimport { logger } from '../../utils/logger'\nimport { fetchCtsToken, setCtsToken } from './cts'\n\nfunction getSubjectFromToken(jwt: string): string | undefined {\n  const payload = decodeJwt(jwt)\n\n  // The CTS JWT payload has a sub field that starts with \"CS|\"\n  if (typeof payload?.sub === 'string' && payload?.sub.startsWith('CS|')) {\n    return payload.sub.slice(3)\n  }\n\n  return payload?.sub\n}\n\nexport const CS_COOKIE_NAME = '__cipherstash_cts_session'\n\nexport type CtsToken = {\n  accessToken: string\n  expiry: number\n}\n\nexport type GetCtsTokenResponse = Promise<\n  | {\n      success: boolean\n      error: string\n      ctsToken?: never\n    }\n  | {\n      success: boolean\n      error?: never\n      ctsToken: CtsToken\n    }\n>\n\nexport const getCtsToken = async (oidcToken?: string): GetCtsTokenResponse => {\n  const cookieStore = await cookies()\n  const cookieData = cookieStore.get(CS_COOKIE_NAME)?.value\n\n  if (oidcToken && !cookieData) {\n    logger.debug(\n      'The CipherStash session cookie was not found in the request, but a JWT token was provided. The JWT token will be used to fetch a new CipherStash session.',\n    )\n\n    return await fetchCtsToken(oidcToken)\n  }\n\n  if (!cookieData) {\n    logger.debug('No CipherStash session cookie found in the request.')\n    return {\n      success: false,\n      error: 'No CipherStash session cookie found in the request.',\n    }\n  }\n\n  const cts_token = JSON.parse(cookieData) as CtsToken\n  return {\n    success: true,\n    ctsToken: cts_token,\n  }\n}\n\nexport const resetCtsToken = (res?: NextResponse) => {\n  if (res) {\n    res.cookies.delete(CS_COOKIE_NAME)\n    return res\n  }\n\n  const response = NextResponse.next()\n  response.cookies.delete(CS_COOKIE_NAME)\n  return response\n}\n\nexport const protectMiddleware = async (\n  oidcToken: string,\n  req: NextRequest,\n  res?: NextResponse,\n) => {\n  const ctsSession = req.cookies.get(CS_COOKIE_NAME)?.value\n\n  if (oidcToken && ctsSession) {\n    const ctsToken = JSON.parse(ctsSession) as CtsToken\n    const ctsTokenSubject = getSubjectFromToken(ctsToken.accessToken)\n    const oidcTokenSubject = getSubjectFromToken(oidcToken)\n\n    if (ctsTokenSubject === oidcTokenSubject) {\n      logger.debug(\n        'The JWT token and the CipherStash session are both valid for the same user.',\n      )\n\n      return res ?? NextResponse.next()\n    }\n\n    return await setCtsToken(oidcToken, res)\n  }\n\n  if (oidcToken && !ctsSession) {\n    logger.debug(\n      'The JWT token was defined, so the CipherStash session will be set.',\n    )\n\n    return await setCtsToken(oidcToken, res)\n  }\n\n  if (!oidcToken && ctsSession) {\n    logger.debug(\n      'The JWT token was undefined, so the CipherStash session was reset.',\n    )\n\n    return resetCtsToken(res)\n  }\n\n  logger.debug(\n    'The JWT token was undefined, so the CipherStash session was not set.',\n  )\n\n  if (res) {\n    return res\n  }\n\n  return NextResponse.next()\n}\n"],"mappings":"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","names":["import_server","import_server","path","fs"]}