90 lines
2.7 KiB
JavaScript
90 lines
2.7 KiB
JavaScript
import crypto from 'node:crypto';
|
|
import fs from 'node:fs/promises';
|
|
import path from 'node:path';
|
|
|
|
function getUserPersistencePaths(profileDir, userId) {
|
|
const rootDir = path.resolve(profileDir);
|
|
const safeUserDir = crypto
|
|
.createHash('sha256')
|
|
.update(String(userId))
|
|
.digest('hex')
|
|
.slice(0, 32);
|
|
|
|
const userDir = path.join(rootDir, safeUserDir);
|
|
return {
|
|
rootDir,
|
|
userDir,
|
|
storageStatePath: path.join(userDir, 'storage-state.json'),
|
|
metaPath: path.join(userDir, 'meta.json'),
|
|
};
|
|
}
|
|
|
|
async function loadPersistedStorageState(profileDir, userId, logger = console) {
|
|
if (!profileDir) return undefined;
|
|
|
|
const { storageStatePath } = getUserPersistencePaths(profileDir, userId);
|
|
|
|
try {
|
|
const raw = await fs.readFile(storageStatePath, 'utf8');
|
|
const parsed = JSON.parse(raw);
|
|
if (!parsed || typeof parsed !== 'object') return undefined;
|
|
if (!Array.isArray(parsed.cookies)) return undefined;
|
|
if (parsed.origins !== undefined && !Array.isArray(parsed.origins)) return undefined;
|
|
return storageStatePath;
|
|
} catch (err) {
|
|
if (err?.code === 'ENOENT') return undefined;
|
|
logger?.warn?.('failed to load persisted storage state', {
|
|
userId: String(userId),
|
|
storageStatePath,
|
|
error: err?.message || String(err),
|
|
});
|
|
return undefined;
|
|
}
|
|
}
|
|
|
|
async function persistStorageState({ profileDir, userId, context, logger = console }) {
|
|
if (!profileDir || !context) {
|
|
return { persisted: false, reason: 'disabled' };
|
|
}
|
|
|
|
const { userDir, storageStatePath, metaPath } = getUserPersistencePaths(profileDir, userId);
|
|
const suffix = `.tmp-${process.pid}-${Date.now()}`;
|
|
const tmpStoragePath = `${storageStatePath}${suffix}`;
|
|
const tmpMetaPath = `${metaPath}${suffix}`;
|
|
|
|
try {
|
|
await fs.mkdir(userDir, { recursive: true });
|
|
await context.storageState({ path: tmpStoragePath });
|
|
await fs.rename(tmpStoragePath, storageStatePath);
|
|
await fs.writeFile(
|
|
tmpMetaPath,
|
|
JSON.stringify(
|
|
{
|
|
userId: String(userId),
|
|
updatedAt: new Date().toISOString(),
|
|
storageStatePath,
|
|
},
|
|
null,
|
|
2
|
|
)
|
|
);
|
|
await fs.rename(tmpMetaPath, metaPath);
|
|
return { persisted: true, userDir, storageStatePath, metaPath };
|
|
} catch (err) {
|
|
await fs.unlink(tmpStoragePath).catch(() => {});
|
|
await fs.unlink(tmpMetaPath).catch(() => {});
|
|
logger?.warn?.('failed to persist storage state', {
|
|
userId: String(userId),
|
|
storageStatePath,
|
|
error: err?.message || String(err),
|
|
});
|
|
return { persisted: false, reason: 'error', error: err };
|
|
}
|
|
}
|
|
|
|
export {
|
|
getUserPersistencePaths,
|
|
loadPersistedStorageState,
|
|
persistStorageState,
|
|
};
|