mirror of
https://github.com/bolucat/Archive.git
synced 2025-09-26 20:21:35 +08:00
172 lines
6.5 KiB
JavaScript
Executable File
172 lines
6.5 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
|
|
import { callosum, manifest, ssl, storage, uoid, utilitas } from 'utilitas';
|
|
import { consts, Socratex, web } from './index.mjs';
|
|
import { parseArgs } from 'node:util'; // https://kgrz.io/node-has-native-arg-parsing.html
|
|
|
|
// parse args
|
|
const argsOptions = {
|
|
address: { type: 'string', short: 'a', default: '' },
|
|
bypass: { type: 'string', short: 'b', default: '' },
|
|
debug: { type: 'boolean', short: 'd', default: false },
|
|
domain: { type: 'string', short: 'o', default: '' },
|
|
help: { type: 'boolean', short: 'h', default: false },
|
|
http: { type: 'boolean', short: 't', default: false },
|
|
password: { type: 'string', short: 'p', default: '' },
|
|
port: { type: 'string', short: 'o', default: '0' },
|
|
repl: { type: 'boolean', short: 'r', default: false },
|
|
token: { type: 'string', short: 'k', default: '' },
|
|
user: { type: 'string', short: 'u', default: '' },
|
|
version: { type: 'boolean', short: 'v', default: false },
|
|
};
|
|
const { values } = parseArgs({ options: argsOptions });
|
|
const argv = {
|
|
...values, port: ~~values.port,
|
|
getStatus: storage.getConfig,
|
|
setStatus: storage.setConfig,
|
|
bypass: values.bypass && utilitas.uniqueArray(values.bypass).map(i => i.toUpperCase()),
|
|
};
|
|
|
|
// constants
|
|
await utilitas.locate(utilitas.__(import.meta.url, 'package.json')); // keep 1st
|
|
const meta = await utilitas.which();
|
|
const setConfig = async cf => callosum.isPrimary && await storage.setConfig(cf);
|
|
const renderObject = obj => utilitas.renderObject(obj, { asArray: true });
|
|
const log = message => utilitas.log(message, meta.name);
|
|
const logWithTime = message => utilitas.log(message, meta.name, { time: true });
|
|
const warning = message => utilitas.log(message, 'WARNING');
|
|
|
|
const getAddress = (ptcl, server) => {
|
|
const { address, family, port } = server.address();
|
|
const add = `${ptcl}://${_socratex.domain}:${port} (${family} ${address})`;
|
|
return { address, family, port, add };
|
|
};
|
|
|
|
const ensureDomain = async () => {
|
|
if (argv.domain) {
|
|
await setConfig({ domain: argv.domain });
|
|
return argv.domain;
|
|
}
|
|
return (await storage.getConfig())?.config?.domain || '127.0.0.1';
|
|
};
|
|
|
|
const ensureToken = async () => {
|
|
let token = (await storage.getConfig())?.config?.token;
|
|
if (!token) {
|
|
token = uoid.fakeUuid();
|
|
await setConfig({ token });
|
|
}
|
|
return token;
|
|
};
|
|
|
|
const ensureBasicAuth = async () => {
|
|
const optsTrim = { trim: true };
|
|
argv.user = utilitas.ensureString(argv.user, optsTrim);
|
|
argv.password = utilitas.ensureString(argv.password, optsTrim);
|
|
if (argv.user && argv.password) {
|
|
const basicAuth = { user: argv.user, password: argv.password };
|
|
await setConfig(basicAuth);
|
|
return basicAuth;
|
|
}
|
|
const { user, password } = (await storage.getConfig())?.config || {};
|
|
return { user, password };
|
|
};
|
|
|
|
// commands
|
|
if (argv.help) {
|
|
[meta.title, '', `Usage: ${meta.name} [options]`, ''].map(x => console.log(x));
|
|
console.table(argsOptions);
|
|
process.exit();
|
|
} else if (argv.version) {
|
|
[meta.title, `${manifest.name} v${manifest.version}`].map(x => console.log(x));
|
|
process.exit();
|
|
}
|
|
|
|
// init
|
|
globalThis._socratex = {
|
|
https: argv.https = !argv.http, domain: await ensureDomain(),
|
|
};
|
|
const port = argv.port || (_socratex.https ? consts.HTTPS_PORT : consts.HTTP_PORT);
|
|
Object.assign(_socratex, {
|
|
token: await ensureToken(), ...await ensureBasicAuth(), address: (
|
|
_socratex.https ? consts.HTTPS.toUpperCase() : consts.PROXY
|
|
) + ` ${_socratex.domain}:${port}`,
|
|
});
|
|
_socratex.user && _socratex.password && (
|
|
argv.basicAuth = async (username, password) => {
|
|
const result = utilitas.insensitiveCompare(username, _socratex.user)
|
|
&& password === _socratex.password;
|
|
logWithTime(
|
|
`Authenticate ${result ? 'SUCCESS' : 'FAILED'} => `
|
|
+ `${username}:${utilitas.mask(password)}.`
|
|
);
|
|
return result;
|
|
}
|
|
);
|
|
_socratex.token && (
|
|
argv.tokenAuth = async (token) => {
|
|
const result = token === _socratex.token;
|
|
logWithTime(
|
|
`Authenticate ${result ? 'SUCCESS' : 'FAILED'} => `
|
|
+ `TOKEN:${utilitas.mask(token)}.`
|
|
);
|
|
return result;
|
|
}
|
|
);
|
|
|
|
// launch
|
|
await callosum.init({
|
|
initPrimary: async () => {
|
|
const subAdd = `${_socratex.https ? consts.HTTPS : consts.HTTP}://`;
|
|
let webAdd = `${subAdd}${_socratex.domain}`;
|
|
let bscAdd = `${subAdd}${_socratex.user}:${_socratex.password}@${_socratex.domain}`;
|
|
if (_socratex.https && port === consts.HTTPS_PORT) { }
|
|
else if (!_socratex.https && port === consts.HTTP_PORT) { }
|
|
else {
|
|
const tailPort = `:${port}`;
|
|
webAdd += tailPort;
|
|
bscAdd += tailPort;
|
|
}
|
|
const content = [];
|
|
[[true, 'Token authentication', {
|
|
' - PAC': `${webAdd}/proxy.pac?token=${_socratex.token}`,
|
|
' - WPAD': `${webAdd}/wpad.dat?token=${_socratex.token}`,
|
|
' - Log': `${webAdd}/console?token=${_socratex.token}`,
|
|
}], [_socratex.user && _socratex.password, 'Basic authentication', {
|
|
' - PAC': `${bscAdd}/proxy.pac`,
|
|
' - WPAD': `${bscAdd}/wpad.dat`,
|
|
' - Log': `${bscAdd}/console`,
|
|
' - Proxy': `${bscAdd}`,
|
|
}], [true, 'Get help', {
|
|
' - GitHub': 'https://github.com/Leask/socratex',
|
|
' - Email': 'Leask Wong <i@leaskh.com>',
|
|
}]].map((x, k) => x[0] && content.push(
|
|
...~~k ? [''] : [], `* ${x[1]}:`, ...renderObject(x[2]))
|
|
);
|
|
console.log(utilitas.renderBox(content, { title: meta?.title, width: 120 }));
|
|
},
|
|
initWorker: async () => {
|
|
globalThis.socratex = new Socratex(argv);
|
|
return await new Promise((resolve, _) => {
|
|
socratex.listen(port, argv.address, () => {
|
|
const { add } = getAddress(
|
|
_socratex.https ? consts.HTTPS : consts.HTTP, socratex
|
|
);
|
|
return resolve({
|
|
message: `${_socratex.https
|
|
? 'Secure ' : ''}Web Proxy started at ${add}.`
|
|
});
|
|
});
|
|
});
|
|
},
|
|
onReady: async () => {
|
|
if (_socratex.https) {
|
|
ssl.isLocalhost(_socratex.domain)
|
|
? warning(`Using self-signed certificate for ${_socratex.domain}.`)
|
|
: await ssl.init(_socratex.domain, { debug: argv.debug });
|
|
} else { warning('HTTP-only mode is not recommended.'); }
|
|
web.init(argv);
|
|
argv.repl && (await import('repl')).start('> ');
|
|
},
|
|
});
|