Files
lcbp3.np-dms.work/frontend/node_modules/next/dist/esm/build/preview-key-utils.js
2025-09-21 20:29:15 +07:00

81 lines
3.3 KiB
JavaScript
Executable File

import path from 'path';
import fs from 'fs';
import crypto from 'crypto';
import { getStorageDirectory } from '../server/cache-dir';
const CONFIG_FILE = '.previewinfo';
const PREVIEW_ID = 'previewModeId';
const PREVIEW_SIGNING_KEY = 'previewModeSigningKey';
const PREVIEW_ENCRYPTION_KEY = 'previewModeEncryptionKey';
const PREVIEW_EXPIRE_AT = 'expireAt';
const EXPIRATION = 1000 * 60 * 60 * 24 * 14 // 14 days
;
async function writeCache(distDir, config) {
const cacheBaseDir = getStorageDirectory(distDir);
if (!cacheBaseDir) return;
const configPath = path.join(cacheBaseDir, CONFIG_FILE);
if (!fs.existsSync(cacheBaseDir)) {
await fs.promises.mkdir(cacheBaseDir, {
recursive: true
});
}
await fs.promises.writeFile(configPath, JSON.stringify({
[PREVIEW_ID]: config.previewModeId,
[PREVIEW_SIGNING_KEY]: config.previewModeSigningKey,
[PREVIEW_ENCRYPTION_KEY]: config.previewModeEncryptionKey,
[PREVIEW_EXPIRE_AT]: Date.now() + EXPIRATION
}));
}
function generateConfig() {
return {
previewModeId: crypto.randomBytes(16).toString('hex'),
previewModeSigningKey: crypto.randomBytes(32).toString('hex'),
previewModeEncryptionKey: crypto.randomBytes(32).toString('hex')
};
}
// This utility is used to get a key for the cache directory. If the
// key is not present, it will generate a new one and store it in the
// cache directory inside dist.
// The key will also expire after a certain amount of time. Once it
// expires, a new one will be generated.
export async function generatePreviewKeys({ distDir, isBuild }) {
const cacheBaseDir = getStorageDirectory(distDir);
if (!cacheBaseDir) {
// There's no persistent storage available. We generate a new config.
// This also covers development time.
return generateConfig();
}
const configPath = path.join(cacheBaseDir, CONFIG_FILE);
async function tryReadCachedConfig() {
if (!fs.existsSync(configPath)) return false;
try {
const config = JSON.parse(await fs.promises.readFile(configPath, 'utf8'));
if (!config) return false;
if (typeof config[PREVIEW_ID] !== 'string' || typeof config[PREVIEW_ENCRYPTION_KEY] !== 'string' || typeof config[PREVIEW_SIGNING_KEY] !== 'string' || typeof config[PREVIEW_EXPIRE_AT] !== 'number') {
return false;
}
// For build time, we need to rotate the key if it's expired. Otherwise
// (next start) we have to keep the key as it is so the runtime key matches
// the build time key.
if (isBuild && config[PREVIEW_EXPIRE_AT] < Date.now()) {
return false;
}
return {
previewModeId: config[PREVIEW_ID],
previewModeSigningKey: config[PREVIEW_SIGNING_KEY],
previewModeEncryptionKey: config[PREVIEW_ENCRYPTION_KEY]
};
} catch (e) {
// Broken config file. We should generate a new key and overwrite it.
return false;
}
}
const maybeValidConfig = await tryReadCachedConfig();
if (maybeValidConfig !== false) {
return maybeValidConfig;
}
const config = generateConfig();
await writeCache(distDir, config);
return config;
}
//# sourceMappingURL=preview-key-utils.js.map