148 lines
4.1 KiB
PHP
148 lines
4.1 KiB
PHP
<?php
|
|
|
|
class RPC
|
|
{
|
|
protected Config $config;
|
|
protected array $plugins = [];
|
|
|
|
public function __construct()
|
|
{
|
|
$this->config = new Config();
|
|
$this->config->read();
|
|
|
|
foreach ($this->config["plugins"] as $plugin) {
|
|
try {
|
|
$meta = $this->getPluginMetadata($plugin);
|
|
$inst = $this->loadPlugin($plugin, $meta["class"]);
|
|
$inst->onInit(new PluginContext($this, $this->config, $meta, $plugin));
|
|
} catch (Error $e) {
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
private function getPluginMetadata($name): array
|
|
{
|
|
$root = dirname(__DIR__) . "/plugins/" . $name;
|
|
if (!file_exists($root)) {
|
|
throw new RuntimeException("Plugin $name dir not found");
|
|
}
|
|
$metafile = $root . "/metadata.json";
|
|
if (!file_exists($metafile)) {
|
|
throw new RuntimeException("Plugin $name metadata not found");
|
|
}
|
|
|
|
$meta = @json_decode(@file_get_contents($metafile), true);
|
|
|
|
if ($meta === null) {
|
|
throw new RuntimeException("Unable to parse $name plugin metadata");
|
|
}
|
|
return $meta;
|
|
}
|
|
|
|
private function loadPlugin($name, $classname): IPluggable
|
|
{
|
|
$file = dirname(__DIR__) . "/plugins/" . $name . "/" . $classname . ".php";
|
|
if (!file_exists($file)) {
|
|
throw new RuntimeException("Plugin $name class $classname not found");
|
|
}
|
|
require_once $file;
|
|
|
|
$instance = new $classname();
|
|
if (!($instance instanceof IPluggable)) {
|
|
throw new RuntimeException("Class $classname have to implement IPluggable");
|
|
}
|
|
|
|
return $this->plugins[$name] = $instance;
|
|
}
|
|
|
|
public function getConfig(): array
|
|
{
|
|
$this->checkAuth();
|
|
return $this->config->asArray();
|
|
}
|
|
|
|
public function setConfig($config): bool
|
|
{
|
|
$this->config->fromArray($config);
|
|
$this->config->save();
|
|
return true;
|
|
}
|
|
|
|
private function checkAuth(): void
|
|
{
|
|
$auth = $_SESSION["auth"] ?? false;
|
|
if (!$auth) {
|
|
throw new RuntimeException("Unauthorized");
|
|
}
|
|
}
|
|
|
|
public function getNetworks(): array
|
|
{
|
|
$this->checkAuth();
|
|
return (new NetworkConfigReader())->getConfigs();
|
|
}
|
|
|
|
|
|
public function logout(): void
|
|
{
|
|
$_SESSION["auth"] = false;
|
|
}
|
|
|
|
public function auth($params): bool
|
|
{
|
|
if (isset($params["password"])) {
|
|
if ($this->comparePassword($params["password"])) {
|
|
return $_SESSION["auth"] = true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
return $_SESSION["auth"] ?? false;
|
|
}
|
|
|
|
private function comparePassword($passwd): bool
|
|
{
|
|
$pass = $this->config["password"];
|
|
if ($pass["type"] == "plaintext") {
|
|
return $pass["data"] == $passwd;
|
|
} else if ($pass["type"] == "hash") {
|
|
return $this->hash($passwd) == $pass["data"];
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private function hash($what): string
|
|
{
|
|
return md5(sha1($what) . md5($what));
|
|
}
|
|
|
|
private function isInternalMethod($name)
|
|
{
|
|
$cls = new ReflectionClass(IPluggable::class);
|
|
return $cls->hasMethod($name);
|
|
}
|
|
|
|
public function __invoke($method, $args)
|
|
{
|
|
$parts = explode("::", $method);
|
|
$isPlugin = count($parts) > 1;
|
|
|
|
if ($isPlugin) {
|
|
$this->checkAuth();
|
|
$plugin = $this->plugins[$parts[0]];
|
|
$methodname = $parts[1];
|
|
if ($this->isInternalMethod($methodname)) {
|
|
throw new RuntimeException("Unable to invoke internal methods");
|
|
}
|
|
return call_user_func([$plugin, $methodname], $args);
|
|
} else {
|
|
$cls = new ReflectionClass(__CLASS__);
|
|
$method = $cls->getMethod($method);
|
|
if (!$method or !$method->isPublic()) {
|
|
throw new RuntimeException("Unable to find method");
|
|
}
|
|
return $method->invoke($this, $args);
|
|
}
|
|
}
|
|
} |