Files
stack/packages/model-proxy/src/common.mjs
T
jason.woltje 362893d043 feat: integrate reviewed proxy page and managed model keys
Source-candidate: poe d9a564e6d20f5f0fd75ce45b12cbbf8bb4c9d568\nSource-candidate: magica38ba5762b06716db1dee00d0afec162656488f5c\nValidated321whole-file phase plus whole bus1349/model-proxy100/webui490; final gate tooling checks pending, not landed.
2026-10-26 12:04:21 -05:00

28 lines
1.3 KiB
JavaScript

import fs from 'node:fs';
import path from 'node:path';
import { createHash } from 'node:crypto';
import { ProxyError, refuse, validManagementKey, proxyTiming } from './validation.mjs';
export { ProxyError, refuse, validManagementKey, proxyTiming };
export const sha256 = value => createHash('sha256').update(value).digest('hex');
export const PIN = Object.freeze(JSON.parse(fs.readFileSync(new URL('../PIN', import.meta.url), 'utf8')));
// Refuse symlink components before handling any state. Callers only create owned new leaves.
export function safePath(file, code) {
if (typeof file !== 'string' || !path.isAbsolute(file) || path.resolve(file) !== file) refuse(code);
let current = path.parse(file).root;
for (const part of file.slice(current.length).split('/').filter(Boolean)) {
current = path.join(current, part);
try { if (fs.lstatSync(current).isSymbolicLink()) refuse(code); }
catch (e) { if (e.code !== 'ENOENT') throw e; }
}
}
export function regularBytes(file, code) {
safePath(file, code);
let fd;
try {
fd = fs.openSync(file, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);
if (!fs.fstatSync(fd).isFile()) refuse(code);
return fs.readFileSync(fd);
} catch { refuse(code); }
finally { if (fd !== undefined) fs.closeSync(fd); }
}