{"version":3,"sources":["../../../src/server/app-render/encryption-utils-server.ts"],"sourcesContent":["// This file should never be bundled into application's runtime code and should\n// stay in the Next.js server.\nimport path from 'path'\nimport fs from 'fs'\nimport { getStorageDirectory } from '../cache-dir'\nimport { arrayBufferToString } from './encryption-utils'\n\n// Keep the key in memory as it should never change during the lifetime of the server in\n// both development and production.\nlet __next_encryption_key_generation_promise: Promise | null = null\nconst CONFIG_FILE = '.rscinfo'\nconst ENCRYPTION_KEY = 'encryption.key'\nconst ENCRYPTION_EXPIRE_AT = 'encryption.expire_at'\nconst EXPIRATION = 1000 * 60 * 60 * 24 * 14 // 14 days\n\nasync function writeCache(distDir: string, configValue: string) {\n const cacheBaseDir = getStorageDirectory(distDir)\n if (!cacheBaseDir) return\n\n const configPath = path.join(cacheBaseDir, CONFIG_FILE)\n if (!fs.existsSync(cacheBaseDir)) {\n await fs.promises.mkdir(cacheBaseDir, { recursive: true })\n }\n await fs.promises.writeFile(\n configPath,\n JSON.stringify({\n [ENCRYPTION_KEY]: configValue,\n [ENCRYPTION_EXPIRE_AT]: Date.now() + EXPIRATION,\n })\n )\n}\n\n// This utility is used to get a key for the cache directory. If the\n// key is not present, it will generate a new one and store it in the\n// cache directory inside dist.\n// The key will also expire after a certain amount of time. Once it\n// expires, a new one will be generated.\n// During the lifetime of the server, it will be reused and never refreshed.\nasync function loadOrGenerateKey(\n distDir: string,\n isBuild: boolean,\n generateKey: () => Promise\n): Promise {\n const cacheBaseDir = getStorageDirectory(distDir)\n\n if (!cacheBaseDir) {\n // There's no persistent storage available. We generate a new key.\n // This also covers development time.\n return await generateKey()\n }\n\n const configPath = path.join(cacheBaseDir, CONFIG_FILE)\n async function hasCachedKey(): Promise {\n if (!fs.existsSync(configPath)) return false\n try {\n const config = JSON.parse(await fs.promises.readFile(configPath, 'utf8'))\n if (!config) return false\n if (\n typeof config[ENCRYPTION_KEY] !== 'string' ||\n typeof config[ENCRYPTION_EXPIRE_AT] !== 'number'\n ) {\n return false\n }\n // For build time, we need to rotate the key if it's expired. Otherwise\n // (next start) we have to keep the key as it is so the runtime key matches\n // the build time key.\n if (isBuild && config[ENCRYPTION_EXPIRE_AT] < Date.now()) {\n return false\n }\n const cachedKey = config[ENCRYPTION_KEY]\n\n // If encryption key is provided via env, and it's not same as valid cache,\n // we should not use the cached key and respect the env key.\n if (\n cachedKey &&\n process.env.NEXT_SERVER_ACTIONS_ENCRYPTION_KEY &&\n cachedKey !== process.env.NEXT_SERVER_ACTIONS_ENCRYPTION_KEY\n ) {\n return false\n }\n return cachedKey\n } catch {\n // Broken config file. We should generate a new key and overwrite it.\n return false\n }\n }\n const maybeValidKey = await hasCachedKey()\n if (typeof maybeValidKey === 'string') {\n return maybeValidKey\n }\n const key = await generateKey()\n await writeCache(distDir, key)\n\n return key\n}\n\nexport async function generateEncryptionKeyBase64({\n isBuild,\n distDir,\n}: {\n isBuild: boolean\n distDir: string\n}) {\n // This avoids it being generated multiple times in parallel.\n if (!__next_encryption_key_generation_promise) {\n __next_encryption_key_generation_promise = loadOrGenerateKey(\n distDir,\n isBuild,\n async () => {\n const providedKey = process.env.NEXT_SERVER_ACTIONS_ENCRYPTION_KEY\n\n if (providedKey) {\n return providedKey\n }\n const key = await crypto.subtle.generateKey(\n {\n name: 'AES-GCM',\n length: 256,\n },\n true,\n ['encrypt', 'decrypt']\n )\n const exported = await crypto.subtle.exportKey('raw', key)\n return btoa(arrayBufferToString(exported))\n }\n )\n }\n return __next_encryption_key_generation_promise\n}\n"],"names":["path","fs","getStorageDirectory","arrayBufferToString","__next_encryption_key_generation_promise","CONFIG_FILE","ENCRYPTION_KEY","ENCRYPTION_EXPIRE_AT","EXPIRATION","writeCache","distDir","configValue","cacheBaseDir","configPath","join","existsSync","promises","mkdir","recursive","writeFile","JSON","stringify","Date","now","loadOrGenerateKey","isBuild","generateKey","hasCachedKey","config","parse","readFile","cachedKey","process","env","NEXT_SERVER_ACTIONS_ENCRYPTION_KEY","maybeValidKey","key","generateEncryptionKeyBase64","providedKey","crypto","subtle","name","length","exported","exportKey","btoa"],"mappings":"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","ignoreList":[0]}