Source-candidate: poe d9a564e6d20f5f0fd75ce45b12cbbf8bb4c9d568\nSource-candidate: magica38ba5762b06716db1dee00d0afec162656488f5c\nValidated321whole-file phase plus whole bus1349/model-proxy100/webui490; final gate tooling checks pending, not landed.
70 lines
4.1 KiB
JavaScript
70 lines
4.1 KiB
JavaScript
import { CliError } from './errors.mjs';
|
|
import { refuseInsideAgent } from './transport.mjs';
|
|
import { fetchPinned } from '../../model-proxy/src/fetch.mjs';
|
|
import { validManagementKey, proxyTiming } from '../../model-proxy/src/common.mjs';
|
|
const failure = (code, exitCode = 2) => Object.assign(new CliError(code, exitCode), { code });
|
|
// A raw terminal suppresses echo; input is never argv, env, readline history or stdout.
|
|
export function promptProxyKey(io, label) {
|
|
if (!io.stdin.isTTY || !io.stdout.isTTY || typeof io.stdin.setRawMode !== 'function') throw failure('proxy-terminal-required', 3);
|
|
io.stderr.write(label);
|
|
const wasRaw = io.stdin.isRaw;
|
|
return new Promise((resolve, reject) => {
|
|
let value = '';
|
|
const finish = (error) => {
|
|
io.stdin.off('data', data); io.stdin.off('end', end); io.stdin.off('error', failed);
|
|
io.stdin.setRawMode(wasRaw); io.stdin.pause(); io.stderr.write('\n');
|
|
error ? reject(error) : resolve(value);
|
|
};
|
|
const end = () => finish(failure('proxy-key-invalid'));
|
|
const failed = () => finish(failure('proxy-key-invalid'));
|
|
const data = chunk => {
|
|
for (const char of chunk.toString()) {
|
|
if (char === '\u0003' || char === '\u0004') return finish(failure('proxy-key-invalid'));
|
|
if (char === '\r' || char === '\n') return finish();
|
|
if (char === '\u007f' || char === '\b') value = value.slice(0, -1);
|
|
else value += char;
|
|
if (value.length > 4096) return finish(failure('proxy-key-invalid'));
|
|
}
|
|
};
|
|
io.stdin.setRawMode(true); io.stdin.on('data', data); io.stdin.once('end', end); io.stdin.once('error', failed); io.stdin.resume();
|
|
});
|
|
}
|
|
export async function proxyCommand(args, io, { system, callFor, prompt = promptProxyKey, fetch = fetchPinned }) {
|
|
const [verb, ...rest] = args;
|
|
if (args.includes('--tester')) throw failure('human-required', 3);
|
|
if (verb === 'init' || verb === 'fetch') {
|
|
try { refuseInsideAgent(io.env); } catch { throw failure('human-required', 3); }
|
|
}
|
|
if (!['fetch', 'init'].includes(verb)) throw failure('proxy-usage', 4);
|
|
const parsed = { flags: new Set(), values: {} }; let port;
|
|
for (let i = 0; i < rest.length; i++) {
|
|
const flag = rest[i];
|
|
if (verb !== 'init' || !['--business', '--port', '--rotate-grace-minutes', '--first-output-seconds'].includes(flag) || parsed.values[flag] !== undefined || !rest[i + 1]) throw failure('proxy-usage', 4);
|
|
parsed.values[flag] = rest[++i];
|
|
}
|
|
if (parsed.values['--port'] !== undefined) {
|
|
if (!/^[0-9]+$/.test(parsed.values['--port'])) throw failure('proxy-config-invalid');
|
|
port = Number(parsed.values['--port']);
|
|
if (port < 1024 || port > 65535 || port === 8317) throw failure('proxy-config-invalid');
|
|
}
|
|
const timing = {};
|
|
for (const [flag, field] of [['--rotate-grace-minutes', 'rotateGraceMinutes'], ['--first-output-seconds', 'firstOutputSeconds']])
|
|
if (parsed.values[flag] !== undefined) timing[field] = /^[0-9]+$/.test(parsed.values[flag]) ? Number(parsed.values[flag]) : NaN;
|
|
try { proxyTiming(timing); } catch (error) { throw failure(error.code); }
|
|
try {
|
|
const config = typeof system === 'function' ? system() : system;
|
|
if (verb === 'fetch') { const result = await fetch({ dataRoot: config.dataRoot }); io.stdout.write(JSON.stringify({ binary: result.binary, panel: result.panel }) + '\n'); return; }
|
|
if (!io.stdin.isTTY || !io.stdout.isTTY) throw failure('proxy-terminal-required', 3);
|
|
// Establish that the CLI is eligible before reading sensitive input. The bus verifies the proof.
|
|
const call = callFor(parsed);
|
|
const first = await prompt(io, 'Management key: '), second = await prompt(io, 'Repeat management key: ');
|
|
if (first !== second) throw failure('proxy-key-mismatch');
|
|
if (!validManagementKey(first)) throw failure('proxy-key-invalid');
|
|
const result = await call('proxy.init', { key: first, ...(port === undefined ? {} : { port }), ...timing });
|
|
io.stdout.write(JSON.stringify(result) + '\n');
|
|
} catch (e) {
|
|
if (e instanceof CliError) throw e;
|
|
throw failure(/^proxy-[a-z-]+$/.test(e.code ?? '') ? e.code : verb === 'fetch' ? 'proxy-fetch-failed' : 'proxy-init-failed');
|
|
}
|
|
}
|