protected-resources-list/classes/RPC.php

153 lines
4.1 KiB
PHP

<?php
class RPC
{
protected Config $config;
protected array $plugins = [];
public function getPlugins(): array
{
return $this->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);
}
}
}