2017-07-21 21:15:43 +00:00
|
|
|
<?php
|
2017-11-17 01:23:18 +00:00
|
|
|
/** @license MIT
|
|
|
|
* Copyright 2017 J. King, Dustin Wilson et al.
|
|
|
|
* See LICENSE and AUTHORS files for details */
|
|
|
|
|
2017-07-21 21:15:43 +00:00
|
|
|
declare(strict_types=1);
|
|
|
|
namespace JKingWeb\Arsse;
|
|
|
|
|
2019-03-25 14:45:05 +00:00
|
|
|
use JKingWeb\Arsse\REST\Fever\User as Fever;
|
2019-04-01 21:24:19 +00:00
|
|
|
use JKingWeb\Arsse\ImportExport\OPML;
|
2018-11-05 14:08:50 +00:00
|
|
|
|
2017-07-21 21:15:43 +00:00
|
|
|
class CLI {
|
2018-11-06 17:32:28 +00:00
|
|
|
const USAGE = <<<USAGE_TEXT
|
2017-07-21 21:15:43 +00:00
|
|
|
Usage:
|
2018-11-06 17:32:28 +00:00
|
|
|
arsse.php daemon
|
2019-03-02 19:59:44 +00:00
|
|
|
arsse.php feed refresh-all
|
2018-11-06 17:32:28 +00:00
|
|
|
arsse.php feed refresh <n>
|
|
|
|
arsse.php conf save-defaults [<file>]
|
|
|
|
arsse.php user [list]
|
|
|
|
arsse.php user add <username> [<password>]
|
|
|
|
arsse.php user remove <username>
|
2019-03-25 14:45:05 +00:00
|
|
|
arsse.php user set-pass <username> [<password>]
|
|
|
|
[--oldpass=<pass>] [--fever]
|
|
|
|
arsse.php user unset-pass <username>
|
|
|
|
[--oldpass=<pass>] [--fever]
|
|
|
|
arsse.php user auth <username> <password> [--fever]
|
2019-04-01 21:24:19 +00:00
|
|
|
arsse.php export <username> [<file>] [-f | --flat]
|
2018-11-06 17:32:28 +00:00
|
|
|
arsse.php --version
|
|
|
|
arsse.php --help | -h
|
2017-07-21 21:15:43 +00:00
|
|
|
|
|
|
|
The Arsse command-line interface currently allows you to start the refresh
|
2019-03-02 19:59:44 +00:00
|
|
|
daemon, refresh all feeds or a specific feed by numeric ID, manage users,
|
|
|
|
or save default configuration to a sample file.
|
2017-07-21 21:15:43 +00:00
|
|
|
USAGE_TEXT;
|
|
|
|
|
2018-11-06 17:32:28 +00:00
|
|
|
protected function usage($prog): string {
|
|
|
|
$prog = basename($prog);
|
|
|
|
return str_replace("arsse.php", $prog, self::USAGE);
|
2017-07-21 21:15:43 +00:00
|
|
|
}
|
|
|
|
|
2018-11-05 14:08:50 +00:00
|
|
|
protected function command(array $options, $args): string {
|
|
|
|
foreach ($options as $cmd) {
|
|
|
|
foreach (explode(" ", $cmd) as $part) {
|
|
|
|
if (!$args[$part]) {
|
|
|
|
continue 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $cmd;
|
|
|
|
}
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
2017-08-20 03:56:32 +00:00
|
|
|
protected function loadConf(): bool {
|
2018-06-18 14:09:43 +00:00
|
|
|
$conf = file_exists(BASE."config.php") ? new Conf(BASE."config.php") : new Conf;
|
|
|
|
Arsse::load($conf);
|
2017-08-20 03:56:32 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-04-01 21:24:19 +00:00
|
|
|
protected function resolveFile($file, string $mode): string {
|
|
|
|
// TODO: checking read/write permissions on the provided path may be useful
|
|
|
|
$stdinOrStdout = in_array($mode, ["r", "r+"]) ? "php://input" : "php://output";
|
|
|
|
return ($file === "-" ? null : $file) ?? $stdinOrStdout;
|
|
|
|
}
|
|
|
|
|
2018-11-06 17:32:28 +00:00
|
|
|
public function dispatch(array $argv = null) {
|
|
|
|
$argv = $argv ?? $_SERVER['argv'];
|
|
|
|
$argv0 = array_shift($argv);
|
|
|
|
$args = \Docopt::handle($this->usage($argv0), [
|
|
|
|
'argv' => $argv,
|
|
|
|
'help' => false,
|
|
|
|
]);
|
2018-11-05 14:08:50 +00:00
|
|
|
try {
|
2019-04-01 21:24:19 +00:00
|
|
|
$cmd = $this->command(["--help", "--version", "daemon", "feed refresh", "feed refresh-all", "conf save-defaults", "user", "export"], $args);
|
|
|
|
if ($cmd && !in_array($cmd, ["--help", "--version", "conf save-defaults"])) {
|
|
|
|
// only certain commands don't require configuration to be loaded
|
|
|
|
$this->loadConf();
|
|
|
|
}
|
|
|
|
switch ($cmd) {
|
2018-11-06 17:32:28 +00:00
|
|
|
case "--help":
|
|
|
|
echo $this->usage($argv0).\PHP_EOL;
|
|
|
|
return 0;
|
|
|
|
case "--version":
|
|
|
|
echo Arsse::VERSION.\PHP_EOL;
|
|
|
|
return 0;
|
2018-11-05 14:08:50 +00:00
|
|
|
case "daemon":
|
2019-04-01 21:24:19 +00:00
|
|
|
$this->getInstance(Service::class)->watch(true);
|
2018-11-06 17:32:28 +00:00
|
|
|
return 0;
|
2018-11-05 14:08:50 +00:00
|
|
|
case "feed refresh":
|
2018-11-06 17:32:28 +00:00
|
|
|
return (int) !Arsse::$db->feedUpdate((int) $args['<n>'], true);
|
2019-03-02 19:59:44 +00:00
|
|
|
case "feed refresh-all":
|
2019-04-01 21:24:19 +00:00
|
|
|
$this->getInstance(Service::class)->watch(false);
|
2019-03-02 19:59:44 +00:00
|
|
|
return 0;
|
2018-11-05 14:08:50 +00:00
|
|
|
case "conf save-defaults":
|
2019-04-01 21:24:19 +00:00
|
|
|
$file = $this->resolveFile($args['<file>'], "w");
|
|
|
|
return (int) !$this->getInstance(Conf::class)->exportFile($file, true);
|
2018-11-05 14:08:50 +00:00
|
|
|
case "user":
|
|
|
|
return $this->userManage($args);
|
2019-04-01 21:24:19 +00:00
|
|
|
case "export":
|
|
|
|
$u = $args['<username>'];
|
|
|
|
$file = $this->resolveFile($args['<file>'], "w");
|
|
|
|
return (int) !$this->getInstance(OPML::class)->exportFile($file, $u, $args['--flat']);
|
2017-08-28 23:38:58 +00:00
|
|
|
}
|
2018-11-05 14:08:50 +00:00
|
|
|
} catch (AbstractException $e) {
|
2018-12-08 01:03:04 +00:00
|
|
|
$this->logError($e->getMessage());
|
2018-11-05 14:08:50 +00:00
|
|
|
return $e->getCode();
|
2017-07-21 21:15:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-08 01:03:04 +00:00
|
|
|
/** @codeCoverageIgnore */
|
|
|
|
protected function logError(string $msg) {
|
2019-01-23 21:34:54 +00:00
|
|
|
fwrite(STDERR, $msg.\PHP_EOL);
|
2018-12-08 01:03:04 +00:00
|
|
|
}
|
|
|
|
|
2019-04-01 21:24:19 +00:00
|
|
|
protected function getInstance(string $class) {
|
|
|
|
return new $class;
|
2019-03-25 14:45:05 +00:00
|
|
|
}
|
|
|
|
|
2018-11-06 17:32:28 +00:00
|
|
|
protected function userManage($args): int {
|
2019-03-25 21:07:28 +00:00
|
|
|
switch ($this->command(["add", "remove", "set-pass", "unset-pass", "list", "auth"], $args)) {
|
2018-11-05 14:08:50 +00:00
|
|
|
case "add":
|
|
|
|
return $this->userAddOrSetPassword("add", $args["<username>"], $args["<password>"]);
|
|
|
|
case "set-pass":
|
2019-03-25 14:45:05 +00:00
|
|
|
if ($args['--fever']) {
|
2019-04-01 21:24:19 +00:00
|
|
|
$passwd = $this->getInstance(Fever::class)->register($args["<username>"], $args["<password>"]);
|
2019-03-25 14:45:05 +00:00
|
|
|
if (is_null($args["<password>"])) {
|
|
|
|
echo $passwd.\PHP_EOL;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
return $this->userAddOrSetPassword("passwordSet", $args["<username>"], $args["<password>"], $args["--oldpass"]);
|
|
|
|
}
|
|
|
|
case "unset-pass":
|
|
|
|
if ($args['--fever']) {
|
2019-04-01 21:24:19 +00:00
|
|
|
$this->getInstance(Fever::class)->unregister($args["<username>"]);
|
2019-03-25 14:45:05 +00:00
|
|
|
} else {
|
|
|
|
Arsse::$user->passwordUnset($args["<username>"], $args["--oldpass"]);
|
|
|
|
}
|
|
|
|
return 0;
|
2018-11-05 14:08:50 +00:00
|
|
|
case "remove":
|
|
|
|
return (int) !Arsse::$user->remove($args["<username>"]);
|
|
|
|
case "auth":
|
2019-03-25 14:45:05 +00:00
|
|
|
return $this->userAuthenticate($args["<username>"], $args["<password>"], $args["--fever"]);
|
2018-11-05 14:08:50 +00:00
|
|
|
case "list":
|
|
|
|
case "":
|
|
|
|
return $this->userList();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function userAddOrSetPassword(string $method, string $user, string $password = null, string $oldpass = null): int {
|
2018-11-06 17:32:28 +00:00
|
|
|
$passwd = Arsse::$user->$method(...array_slice(func_get_args(), 1));
|
2017-08-29 14:50:31 +00:00
|
|
|
if (is_null($password)) {
|
2017-09-28 23:25:31 +00:00
|
|
|
echo $passwd.\PHP_EOL;
|
2017-08-28 23:38:58 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2018-11-05 14:08:50 +00:00
|
|
|
|
|
|
|
protected function userList(): int {
|
|
|
|
$list = Arsse::$user->list();
|
|
|
|
if ($list) {
|
|
|
|
echo implode(\PHP_EOL, $list).\PHP_EOL;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-03-25 14:45:05 +00:00
|
|
|
protected function userAuthenticate(string $user, string $password, bool $fever = false): int {
|
2019-04-01 21:24:19 +00:00
|
|
|
$result = $fever ? $this->getInstance(Fever::class)->authenticate($user, $password) : Arsse::$user->auth($user, $password);
|
2019-03-25 14:45:05 +00:00
|
|
|
if ($result) {
|
2018-11-05 14:08:50 +00:00
|
|
|
echo Arsse::$lang->msg("CLI.Auth.Success").\PHP_EOL;
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
echo Arsse::$lang->msg("CLI.Auth.Failure").\PHP_EOL;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
2017-08-29 14:50:31 +00:00
|
|
|
}
|