diff --git a/build/build-phar.php b/build/build-phar.php index 95c0a89..642d5a7 100644 --- a/build/build-phar.php +++ b/build/build-phar.php @@ -69,7 +69,7 @@ try { builderLog("[INFO] Phar archive created successfully"); builderLog("[RUN] Generating run script"); - file_put_contents("./build/run-phar.sh", 'cd '.$path.' ; printf "test\n" | php -dextension=openswoole.so '.$filename.'-'.$version.'.phar'); + file_put_contents("./build/run-phar.sh", 'cd '.$path.' ; printf "test\n" | php -dextension=openswoole.so -dphar.readonly=0 '.$filename.'-'.$version.'.phar'); builderLog("[RUN] Adding Permissions to run script"); exec("chmod 777 ./build/run-phar.sh"); diff --git a/build/run-phar.sh b/build/run-phar.sh index 22d07fc..25e9c72 100755 --- a/build/run-phar.sh +++ b/build/run-phar.sh @@ -1 +1 @@ -cd build/release ; printf "test\n" | php -dextension=openswoole.so LonaDB-4.0.0-stable.phar \ No newline at end of file +cd build/release ; printf "test\n" | php -dextension=openswoole.so -dphar.readonly=0 LonaDB-4.3.0-stable.phar \ No newline at end of file diff --git a/build_config.json b/build_config.json index c377240..2329c20 100644 --- a/build_config.json +++ b/build_config.json @@ -1,6 +1,6 @@ { "filename": "LonaDB", - "version": "4.0.0-stable", + "version": "4.3.0-stable", "path": "build", "debug": false } \ No newline at end of file diff --git a/src/LonaDB/Actions/add_function.php b/src/LonaDB/Actions/add_function.php new file mode 100644 index 0000000..3c04557 --- /dev/null +++ b/src/LonaDB/Actions/add_function.php @@ -0,0 +1,18 @@ +UserManager->CheckPermission($data['login']['name'], "create_function")) { + $response = json_encode(["success" => false, "err" => "no_permission", "process" => $data['process']]); + $server->send($fd, $response); + $server->close($fd); + return; + } + + $function = $LonaDB->FunctionManager->Create($data['function']['name'], $data['function']['content']); + + $response = json_encode(["success" => true, "process" => $data['process']]); + $server->send($fd, $response); + $server->close($fd); + } +}; diff --git a/src/LonaDB/Actions/delete_function.php b/src/LonaDB/Actions/delete_function.php new file mode 100644 index 0000000..726b634 --- /dev/null +++ b/src/LonaDB/Actions/delete_function.php @@ -0,0 +1,18 @@ +UserManager->CheckPermission($data['login']['name'], "create_function")) { + $response = json_encode(["success" => false, "err" => "no_permission", "process" => $data['process']]); + $server->send($fd, $response); + $server->close($fd); + return; + } + + $function = $LonaDB->FunctionManager->Delete($data['function']['name']); + + $response = json_encode(["success" => true, "process" => $data['process']]); + $server->send($fd, $response); + $server->close($fd); + } +}; diff --git a/src/LonaDB/Actions/execute_function.php b/src/LonaDB/Actions/execute_function.php new file mode 100644 index 0000000..f8c5dd7 --- /dev/null +++ b/src/LonaDB/Actions/execute_function.php @@ -0,0 +1,9 @@ +FunctionManager->GetFunction($data['name']); + + $function->Execute($LonaDB, $data, $server, $fd); + } +}; diff --git a/src/LonaDB/Functions/FunctionManager.php b/src/LonaDB/Functions/FunctionManager.php new file mode 100644 index 0000000..d749d65 --- /dev/null +++ b/src/LonaDB/Functions/FunctionManager.php @@ -0,0 +1,55 @@ +LonaDB = $lonaDB; + $this->Functions = array(); + + if(!is_dir("data/")) mkdir("data/"); + if(!is_dir("data/functions/")) mkdir("data/functions/"); + + foreach (new \DirectoryIterator('data/functions') as $fileInfo) { + if(str_ends_with($fileInfo->getFilename(), ".lona")){ + $this->Functions[substr($fileInfo->getFilename(), 0, -5)] = new LonaFunction($this->LonaDB, $fileInfo->getFilename()); + } + } + } + + public function GetFunction(string $name) : mixed { + if(!$this->Functions[$name]) return false; + + return $this->Functions[$name]; + } + + public function Create(string $name, string $content) : bool { + if($this->Functions[$name]) return false; + + $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length(AES_256_CBC)); + + $encrypted = openssl_encrypt(json_encode($content), AES_256_CBC, $this->LonaDB->config["encryptionKey"], 0, $iv); + file_put_contents("./data/functions/".$name.".lona", $encrypted.":".base64_encode($iv)); + + $this->Functions[$name] = new LonaFunction($this->LonaDB, $name . ".lona"); + + return true; + } + + public function Delete(string $name) : bool { + if(!$this->Functions[$name]) return false; + + unset($this->Functions[$name]); + unlink("./data/functions/".$name.".lona"); + return true; + } +} \ No newline at end of file diff --git a/src/LonaDB/Functions/LonaFunction.php b/src/LonaDB/Functions/LonaFunction.php new file mode 100644 index 0000000..c0a607f --- /dev/null +++ b/src/LonaDB/Functions/LonaFunction.php @@ -0,0 +1,40 @@ +LonaDB = $lonaDB; + + $this->LonaDB->Logger->Load("Trying to load function '".$name."'"); + + $parts = explode(':', file_get_contents("./data/functions/".$name)); + $temp = json_decode(openssl_decrypt($parts[0], AES_256_CBC, $this->LonaDB->config["encryptionKey"], 0, base64_decode($parts[1])), true); + + $this->file = substr($name, 0, -5); + $this->Name = $this->file; + + $function = "\$this->data['" . $this->Name . "'] = new class {\n"; + $function .= "public function run(\$LonaDB, \$data, \$server, \$fd) {\n"; + $function .= $temp; + $function .= "\n} \n};"; + + eval($function); + + $this->LonaDB->Logger->Load("Function '" . $this->Name . "' has been loaded"); + } + + public function Execute(LonaDB $LonaDB, array $data, $server, $fd) : mixed { + return $this->data[$this->Name]->run($LonaDB, $data, $server, $fd); + } +} \ No newline at end of file diff --git a/src/LonaDB/LonaDB.php b/src/LonaDB/LonaDB.php index f309e75..477f663 100644 --- a/src/LonaDB/LonaDB.php +++ b/src/LonaDB/LonaDB.php @@ -9,25 +9,23 @@ use LonaDB\Server; use LonaDB\Logger; use LonaDB\Tables\TableManager; use LonaDB\Users\UserManager; +use LonaDB\Functions\FunctionManager; +use LonaDB\Plugins\PluginManager; class LonaDB { public array $config; + private bool $Running = true; public string $EncryptionKey; public Logger $Logger; public Server $Server; public TableManager $TableManager; public UserManager $UserManager; + public FunctionManager $FunctionManager; + public PluginManager $PluginManager; - public function __construct() { - echo "Encryption key:\n"; - $keyHandle = fopen ("php://stdin","r"); - $key = fgets($keyHandle); - fclose($keyHandle); - - $this->EncryptionKey = str_replace("\n","",$key); - unset($key); - + public function __construct(string $key) { + $this->EncryptionKey = $key; $this->Logger = new Logger($this); try{ @@ -36,7 +34,6 @@ class LonaDB { $this->Logger->InfoCache("Looking for config."); - //somehow file_exists() always retuns false for me... But this checks if the file did exist in the first place. file_put_contents("configuration.lona", file_get_contents("configuration.lona")); if(file_get_contents("configuration.lona") === "") $this->setup(); @@ -66,14 +63,58 @@ class LonaDB { $this->TableManager = new TableManager($this); $this->Logger->Info("Loading UserManager class."); $this->UserManager = new UserManager($this); - $this->Logger->Info("Loading Server class."); - $this->Server = new Server($this); + $this->Logger->Info("Loading FunctionManager class."); + $this->FunctionManager = new FunctionManager($this); + + $this->Logger->Info("Loading PluginManager class."); + $this->PluginManager = new PluginManager($this); + + $pid = @ pcntl_fork(); + if( $pid == -1 ) { + throw new Exception( $this->getError( Thread::COULD_NOT_FORK ), Thread::COULD_NOT_FORK ); + } + if( $pid ) { + // parent + $this->pid = $pid; + } + else { + $this->PluginManager->LoadPlugins(); + } + + $serverpid = @ pcntl_fork(); + if( $serverpid == -1 ) { + throw new Exception( $this->getError( Thread::COULD_NOT_FORK ), Thread::COULD_NOT_FORK ); + } + if( $serverpid ) { + // parent + $this->serverpid = $serverpid; + } + else { + $this->Logger->Info("Loading Server class."); + $this->Server = new Server($this); + } + + while($this->Running){ + + } } catch (\Exception $e){ $this->Logger->Error($e); } } + private function Load() : void { + $pid = @ pcntl_fork(); + if( $pid == -1 ) { + throw new Exception( $this->getError( Thread::COULD_NOT_FORK ), Thread::COULD_NOT_FORK ); + } + if( $pid ) { + $this->pid = $pid; + } + else { + } + } + private function setup() : void { $this->Logger->InfoCache("Invalid or missing config. Starting setup."); echo "Database port:\n"; @@ -117,6 +158,21 @@ class LonaDB { $encrypted = openssl_encrypt(json_encode($save), AES_256_CBC, $this->EncryptionKey, 0, $iv); file_put_contents("./configuration.lona", $encrypted.":".base64_encode($iv)); } + + public function Stop() : void { + posix_kill( $this->pid, SIGKILL ); + posix_kill( $this->serverpid, SIGKILL ); + $this->Running = false; + } } -$run = new LonaDB(); + +echo "Encryption key:\n"; +$keyHandle = fopen ("php://stdin","r"); +$key = fgets($keyHandle); +fclose($keyHandle); + +$encryptionKey = str_replace("\n","",$key); +unset($key); + +$run = new LonaDB($encryptionKey); \ No newline at end of file diff --git a/src/LonaDB/Plugins/PluginManager.php b/src/LonaDB/Plugins/PluginManager.php new file mode 100644 index 0000000..90b969a --- /dev/null +++ b/src/LonaDB/Plugins/PluginManager.php @@ -0,0 +1,118 @@ +LonaDB = $lonaDB; + $this->Tables = array(); + } + + public function LoadPlugins () : void { + if(!is_dir("plugins/")) mkdir("plugins/"); + + $results = scandir("plugins/"); + + foreach($results as $r){ + if(str_ends_with($r, ".phar")){ + $phar = new \Phar("plugins/" . $r, 0); + + foreach (new \RecursiveIteratorIterator($phar) as $file) { + if($file->getFileName() === "plugin.json") { + $conf = json_decode(file_get_contents($file->getPathName()), true); + eval("\$path = substr(\$file->getPathName(), 0, -". strlen($file->getFileName()) .");"); + } + } + + if($conf['main'] && $conf['main']['path'] && $conf['main']['class'] && $conf['main']['namespace'] && $conf['name']){ + file_put_contents($path . $conf['main']['path'], file_get_contents($path . $conf['main']['path'])); + if(file_get_contents($path. $conf['main']['path']) !== ""){ + try{ + $this->load_classphp($path, $phar); + + eval("\$this->Plugins[\$conf['name']] = new " . $conf['main']['namespace'] . "\\" . $conf['main']['class'] . "();"); + + $this->Plugins[$conf['name']]->onEnable($this->LonaDB); + } + catch(e){ + $this->LonaDB->Logger->Error("Could not load main file for plugin '" . $conf['name'] . "'"); + } + } + else $this->LonaDB->Logger->Error("Main file for plugin '" . $conf['name'] . "' is declared in config but doesn't exist"); + } + else{ + $this->LonaDB->Logger->Error("Could not load the plugin in '" . $r . "'"); + } + } + else if($r != "." && $r !== ".."){ + $debugscan = scandir("plugins/" . $r); + + if(in_array("plugin.json", $debugscan)) $conf = json_decode(file_get_contents("plugins/" . $r . "/plugin.json"), true); + + if($conf['main'] && $conf['main']['path'] && $conf['main']['class'] && $conf['main']['namespace'] && $conf['name']){ + file_put_contents("plugins/" . $r . "/" . $conf['main']['path'], file_get_contents("plugins/" . $r . "/" . $conf['main']['path'])); + if(file_get_contents("plugins/" . $r . "/" . $conf['main']['path']) !== ""){ + try{ + $this->load_classphp("plugins/" . $r . "/"); + + if($conf['build']){ + $phar = new \Phar("plugins/".$conf['name']."-".$conf['version'].".phar", 0, "plugins/".$conf['name']."-".$conf['version'].".phar"); + + $phar->buildFromDirectory("plugins/".$r."/"); + + $phar->setDefaultStub($conf['main']['namespace'].'/'.$conf['main']['class'].'.php', $conf['main']['namespace'].'/'.$conf['main']['class'].'.php'); + + $phar->setAlias($conf['name']."-".$conf['version'].".phar"); + + $phar->stopBuffering(); + } + + eval("\$this->Plugins[\$conf['name']] = new " . $conf['main']['namespace'] . "\\" . $conf['main']['class'] . "();"); + + $this->Plugins[$conf['name']]->onEnable($this->LonaDB); + } + catch(e){ + $this->LonaDB->Logger->Error("Could not load main file for plugin '" . $conf['name'] . "'"); + } + } + else $this->LonaDB->Logger->Error("Main file for plugin '" . $conf['name'] . "' is declared in config but doesn't exist"); + } + else{ + $this->LonaDB->Logger->Error("Could not load the plugin in '" . $r . "'"); + } + } + } + } + + public function GetPlugin(string $name) : mixed { + if($this->Plugins[$name]) return $this->Plugins[$name]; + else return false; + } + + private function load_classphp(string $path, \Phar $phar = null) : void { + if(str_starts_with($path, "phar")){ + foreach (new \RecursiveIteratorIterator($phar) as $file) { + if(str_ends_with($file->getPathName(), ".php")) require_once $file->getPathName(); + } + } + if(str_ends_with($path, "/")) $path = substr($path, 0, -1); + $items = glob( $path . "/*" ); + + foreach( $items as $item ) { + $isPhp = str_ends_with($item, ".php"); + + if ( $isPhp ) { + require_once $item; + } else{ + $this->load_classphp( $item . "/" ); + } + } + } +} \ No newline at end of file diff --git a/src/LonaDB/Server.php b/src/LonaDB/Server.php index 903680d..4ed03bb 100644 --- a/src/LonaDB/Server.php +++ b/src/LonaDB/Server.php @@ -50,7 +50,16 @@ class Server { $this->handleData($data, $server, $fd); }); - $this->server->start(); + try{ + $this->server->start(); + } + catch(e){ + $this->LonaDB->Logger->Error(e); + } + } + + public function Stop() : void { + $this->server->stop(); } private function handleData(string $dataString, TCPServer $server, int $fd) : void { diff --git a/src/LonaDB/Tables/Table.php b/src/LonaDB/Tables/Table.php index 11ef898..167046f 100644 --- a/src/LonaDB/Tables/Table.php +++ b/src/LonaDB/Tables/Table.php @@ -146,7 +146,7 @@ class Table{ $this->Save(); } - private function Save(){ + private function Save() : void { $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length(AES_256_CBC)); $save = array( "data" => $this->data,