79 lines
2.9 KiB
JavaScript
79 lines
2.9 KiB
JavaScript
|
|
#!/usr/bin/env node
|
||
|
|
// Web console: serves the Pithos UI in a browser.
|
||
|
|
//
|
||
|
|
// pithos-web loopback only, prints a sign-in link
|
||
|
|
// pithos-web --listen 0.0.0.0:8700 remote access; requires PITHOS_PASSWORD
|
||
|
|
// (or --password-file) and a TLS proxy in front
|
||
|
|
//
|
||
|
|
// Flags: --listen host:port, --config <s3d.yml>, --s3d <binary>, --bin-dir <dir>,
|
||
|
|
// --password-file <file>, --allow-host <name[:port]> (repeatable)
|
||
|
|
|
||
|
|
import fs from 'node:fs';
|
||
|
|
import path from 'node:path';
|
||
|
|
import { fileURLToPath } from 'node:url';
|
||
|
|
import { createPithos } from '../core/server.js';
|
||
|
|
|
||
|
|
const HERE = path.dirname(fileURLToPath(import.meta.url));
|
||
|
|
|
||
|
|
function parseArgs(argv) {
|
||
|
|
const out = { allowHosts: [] };
|
||
|
|
for (let i = 0; i < argv.length; i++) {
|
||
|
|
const a = argv[i];
|
||
|
|
const next = () => { if (i + 1 >= argv.length) fail(`${a} needs a value`); return argv[++i]; };
|
||
|
|
switch (a) {
|
||
|
|
case '--listen': out.listen = next(); break;
|
||
|
|
case '--config': out.config = next(); break;
|
||
|
|
case '--s3d': out.s3d = next(); break;
|
||
|
|
case '--bin-dir': out.binDir = next(); break;
|
||
|
|
case '--password-file': out.passwordFile = next(); break;
|
||
|
|
case '--allow-host': out.allowHosts.push(next().toLowerCase()); break;
|
||
|
|
case '-h': case '--help':
|
||
|
|
console.log(fs.readFileSync(fileURLToPath(import.meta.url), 'utf8').split('\n').slice(1, 11).map((l) => l.replace(/^\/\/ ?/, '')).join('\n'));
|
||
|
|
process.exit(0);
|
||
|
|
default: fail(`unknown flag ${a}`);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return out;
|
||
|
|
}
|
||
|
|
|
||
|
|
function fail(msg) { console.error(`pithos-web: ${msg}`); process.exit(2); }
|
||
|
|
|
||
|
|
const args = parseArgs(process.argv.slice(2));
|
||
|
|
const [host, portStr] = splitHostPort(args.listen || '127.0.0.1:8700');
|
||
|
|
const loopback = ['127.0.0.1', 'localhost', '::1'].includes(host);
|
||
|
|
|
||
|
|
let password = process.env.PITHOS_PASSWORD || '';
|
||
|
|
if (args.passwordFile) password = fs.readFileSync(args.passwordFile, 'utf8').trim();
|
||
|
|
if (!loopback && password.length < 12) fail('listening beyond loopback needs PITHOS_PASSWORD or --password-file (12+ characters)');
|
||
|
|
|
||
|
|
const pithos = await createPithos({
|
||
|
|
host,
|
||
|
|
port: Number(portStr),
|
||
|
|
configFile: args.config,
|
||
|
|
binary: args.s3d,
|
||
|
|
binDir: args.binDir || HERE,
|
||
|
|
password: password || undefined,
|
||
|
|
allowedHosts: args.allowHosts,
|
||
|
|
hostName: 'web',
|
||
|
|
});
|
||
|
|
|
||
|
|
console.log(`Pithos web console on ${pithos.url}`);
|
||
|
|
if (loopback) console.log(`Sign in: ${pithos.authUrl}`);
|
||
|
|
else console.log('Sign in with the configured password. Put a TLS reverse proxy in front of this port.');
|
||
|
|
console.log(`s3d config: ${pithos.daemon.configFile}`);
|
||
|
|
console.log(`s3d binary: ${pithos.daemon.binary || '(not found - install it from the console)'}`);
|
||
|
|
|
||
|
|
const shutdown = async () => {
|
||
|
|
console.log('stopping...');
|
||
|
|
await pithos.close();
|
||
|
|
process.exit(0);
|
||
|
|
};
|
||
|
|
process.on('SIGINT', shutdown);
|
||
|
|
process.on('SIGTERM', shutdown);
|
||
|
|
|
||
|
|
function splitHostPort(s) {
|
||
|
|
const m = s.match(/^\[?([^\]]+?)\]?:(\d+)$/);
|
||
|
|
if (!m) fail(`--listen wants host:port, got ${s}`);
|
||
|
|
return [m[1], m[2]];
|
||
|
|
}
|