Files
flood/config.cli.js
2020-10-14 10:58:52 +08:00

185 lines
5.1 KiB
JavaScript

const {spawn} = require('child_process');
const crypto = require('crypto');
const fs = require('fs');
const os = require('os');
const path = require('path');
const {argv} = require('yargs')
.env('FLOOD_OPTION_')
.option('baseuri', {
default: '/',
describe: "This URI will prefix all of Flood's HTTP requests",
type: 'string',
})
.option('rundir', {
alias: 'd',
default: path.join(os.homedir(), '.local/share/flood'),
describe: "Where to store Flood's runtime files (eg. database)",
type: 'string',
})
.option('host', {
alias: 'h',
default: '127.0.0.1',
describe: 'The host that Flood should listen for web connections on',
type: 'string',
})
.option('port', {
alias: 'p',
default: 3000,
describe: 'The port that Flood should listen for web connections on',
type: 'number',
})
.option('secret', {
alias: 's',
describe: 'A unique secret, a random one will be generated if not provided',
type: 'string',
})
.option('noauth', {
alias: 'n',
default: false,
describe: "Disable Flood's builtin access control system, needs rthost+rtport OR rtsocket.",
type: 'boolean',
})
.option('rthost', {
describe: "Depends on noauth: Host of rTorrent's SCGI interface",
type: 'string',
})
.option('rtport', {
describe: "Depends on noauth: Port of rTorrent's SCGI interface",
type: 'number',
})
.option('rtsocket', {
conflicts: ['rthost', 'rtport'],
describe: "Depends on noauth: Path to rTorrent's SCGI unix socket",
type: 'string',
})
.option('ssl', {
default: false,
describe: 'Enable SSL, key.pem and fullchain.pem needed in runtime directory',
type: 'boolean',
})
.option('sslkey', {
describe: 'Depends on ssl: Absolute path to private key for SSL',
implies: 'ssl',
hidden: true,
type: 'string',
})
.option('sslcert', {
describe: 'Depends on ssl: Absolute path to fullchain cert for SSL',
implies: 'ssl',
hidden: true,
type: 'string',
})
.option('allowedpath', {
describe: 'Allowed path for file operations, can be called multiple times',
type: 'string',
})
.option('dbclean', {
default: 1000 * 60 * 60,
describe: 'ADVANCED: Interval between database purge',
hidden: true,
type: 'number',
})
.option('maxhistorystates', {
default: 30,
describe: 'ADVANCED: Number of records of torrent download and upload speeds',
hidden: true,
type: 'number',
})
.option('clientpoll', {
default: 1000 * 2,
describe: 'ADVANCED: How often (in ms) Flood will request the torrent list',
hidden: true,
type: 'number',
})
.option('rtorrent', {
default: false,
describe: 'ADVANCED: rTorrent daemon managed by Flood',
hidden: true,
type: 'boolean',
})
.option('proxy', {
default: 'http://127.0.0.1:3000',
describe: 'DEV ONLY: See the "Local Development" section of README.md',
hidden: true,
type: 'string',
})
.version(require('./package.json').version)
.alias('v', 'version')
.help();
if (argv.rtorrent) {
const rTorrentProcess = spawn('rtorrent', ['-o', 'system.daemon.set=true']);
process.on('exit', () => {
console.log('Killing rTorrent daemon...');
rTorrentProcess.kill('SIGTERM');
});
}
process.on('SIGINT', () => {
process.exit();
});
try {
fs.mkdirSync(path.join(argv.rundir, 'db'), {recursive: true});
fs.mkdirSync(path.join(argv.rundir, 'temp'), {recursive: true});
} catch (error) {
console.error('Failed to access runtime directory');
process.exit(1);
}
const DEFAULT_SECRET_PATH = path.join(argv.rundir, 'flood.secret');
let secret;
if (!argv.secret) {
try {
if (fs.existsSync(DEFAULT_SECRET_PATH)) {
secret = fs.readFileSync(DEFAULT_SECRET_PATH, {encoding: 'utf8'});
} else {
const buf = Buffer.alloc(36);
crypto.randomFillSync(buf);
secret = buf.toString('hex');
fs.writeFileSync(DEFAULT_SECRET_PATH, secret, {mode: 0o600});
}
} catch (error) {
console.error('Failed to read or generate secret');
process.exit(1);
}
} else {
({secret} = argv);
}
const CONFIG = {
baseURI: argv.baseuri,
dbCleanInterval: argv.dbclean,
dbPath: path.resolve(path.join(argv.rundir, 'db')),
tempPath: path.resolve(path.join(argv.rundir, 'temp')),
disableUsersAndAuth: argv.noauth,
configUser:
argv.rtsocket != null
? {
client: 'rTorrent',
type: 'socket',
version: 1,
socket: argv.rtsocket || '/data/rtorrent.sock',
}
: {
client: 'rTorrent',
type: 'tcp',
version: 1,
host: argv.rthost || 'localhost',
port: argv.rtport || 5000,
},
floodServerHost: argv.host,
floodServerPort: argv.port,
floodServerProxy: argv.proxy,
maxHistoryStates: argv.maxhistorystates,
torrentClientPollInterval: argv.clientpoll,
secret,
ssl: argv.ssl,
sslKey: argv.sslkey || path.resolve(path.join(argv.rundir, 'key.pem')),
sslCert: argv.sslcert || path.resolve(path.join(argv.rundir, 'fullchain.pem')),
allowedPaths: argv.allowedpath ? [].concat(argv.allowedpath) : null,
};
module.exports = CONFIG;