initial upload

This commit is contained in:
Collin 2024-01-31 13:32:14 +00:00
commit 6d1891a583
15 changed files with 637 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
build/debug/*
build/release/*
src/vendor/

3
build-phar Normal file
View File

@ -0,0 +1,3 @@
#!/usr/bin/env bash
php -dphar.readonly=0 build/build-phar.php

75
build/build-phar.php Normal file
View File

@ -0,0 +1,75 @@
<?php
function builderLog(string $message){
echo(date("Y-m-d h:m", time())." ".$message."\n");
}
echo chr(27).chr(91).'H'.chr(27).chr(91).'J';
echo "[LonaDB Phar compiler]\n";
$config = json_decode(file_get_contents("build_config.json"));
$path = $config->{"path"};
$filename = $config->{"filename"};
$version = $config->{"version"};
$branch = "debug";
if($config->{"debug"}) $path = $path."/debug";
else {
$path = $path."/release";
$branch = "release";
}
echo "[CONF] Debug=".$config->{"debug"}."\n";
echo "[CONF] Path=".$path."\n";
echo "[CONF] Filename=".$filename."\n";
echo "[CONF] Version=".$version."\n";
echo "\nBuild? (Y/n)\n";
$handle = fopen ("php://stdin","r");
$line = fgets($handle);
if(trim(strtolower($line)) === 'no' || trim(strtolower($line)) === "n"){
echo "ABORTING!\n";
exit;
}
$start = time();
builderLog("[COMPOSER] Running 'composer install'");
exec("cd src ; ./composer.phar install");
if(file_exists($path."/".$filename."-".$version.".phar")){
unlink($path."/".$filename."-".$version.".phar");
builderLog("[CLEANUP] Deleted an old build");
}
if(file_exists("build/run-phar.sh")){
unlink(__DIR__."/run-phar.sh");
builderLog("[CLEANUP] Deleted an old runner");
}
try {
builderLog("[BUILD] Creating a new Phar object");
$phar = new Phar($path."/".$filename."-".$version.".phar", 0, $path."/".$filename."-".$version.".phar");
builderLog("[BUILD] Adding files to the Phar archive");
$phar->buildFromDirectory(__DIR__ . '/../src');
builderLog("[BUILD] Set the default stub file");
$phar->setDefaultStub('LonaDB/LonaDB.php', 'LonaDB/LonaBD.php');
$phar->setAlias($filename."-".$version.".phar");
builderLog("[BUILD] Saving the new Phar archive");
$phar->stopBuffering();
builderLog("[INFO] Phar archive created successfully");
builderLog("[RUN] Generating run script");
file_put_contents("./build/run-phar.sh", "cd ".$path." ; php ".$filename."-".$version.".phar");
builderLog("[RUN] Adding Permissions to run script");
exec("chmod 777 ./build/run-phar.sh");
echo "Done!\nBuilt in ".(time() - $start) ." ms!\n";
} catch (Exception $e) {
builderLog('[ERROR] '.$e->getMessage());
}

1
build/run-phar.sh Executable file
View File

@ -0,0 +1 @@
cd build/debug ; php LonaDB-2.0.phar

6
build_config.json Normal file
View File

@ -0,0 +1,6 @@
{
"filename": "LonaDB",
"version": "4.0.0-beta",
"path": "build",
"debug": true
}

3
run Normal file
View File

@ -0,0 +1,3 @@
#!/usr/bin/env bash
./build/run-phar.sh

70
src/LonaDB/Logger.php Normal file
View File

@ -0,0 +1,70 @@
<?php
namespace LonaDB;
require 'vendor/autoload.php';
use LonaDB\LonaDB;
class Logger{
private $LogFile;
private string $infoCache = "";
private LonaDB $LonaDB;
public function __construct(LonaDB $lonaDB){
$this->LonaDB = $lonaDB;
}
private function log(string $message){
echo($message);
if($this->LonaDB->config["logging"]) fwrite($this->LogFile, $message);
}
public function LoadLogger(){
if($this->LonaDB->config["logging"]) $this->LogFile = fopen('log.txt','a');
}
public function Warning($msg){
$log = date("Y-m-d h:i:s")." [WARNING] ".$msg."\n";
$this->log($log);
}
public function Error($msg){
$log = date("Y-m-d h:i:s")." [ERROR] ".$msg."\n";
$this->log($log);
}
public function Create($msg){
$log = date("Y-m-d h:i:s")." [CREATE] ".$msg."\n";
$this->log($log);
}
public function Load($msg){
$log = date("Y-m-d h:i:s")." [LOAD] ".$msg."\n";
$this->log($log);
}
public function Info($msg){
$log = date("Y-m-d h:i:s")." [INFO] ".$msg."\n";
$this->log($log);
}
public function Table($msg){
$log = date("Y-m-d h:i:s")." [TABLE] ".$msg."\n";
$this->log($log);
}
public function User($msg){
$log = date("Y-m-d h:i:s")." [USER] ".$msg."\n";
$this->log($log);
}
public function InfoCache($msg){
$log = date("Y-m-d h:i:s")." [INFO] ".$msg."\n";
echo($log);
$this->infoCache = $this->infoCache.$log;
}
public function DropCache(){
if($this->LonaDB->config["logging"]) fwrite($this->LogFile, $this->infoCache);
}
}

122
src/LonaDB/LonaDB.php Normal file
View File

@ -0,0 +1,122 @@
<?php
namespace LonaDB;
define('AES_256_CBC', 'aes-256-cbc');
require 'vendor/autoload.php';
use LonaDB\Server;
use LonaDB\Logger;
use LonaDB\Tables\TableManager;
use LonaDB\Users\UserManager;
class LonaDB {
public array $config;
public string $EncryptionKey;
public Logger $Logger;
public Server $Server;
public TableManager $TableManager;
public UserManager $UserManager;
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);
$this->Logger = new Logger($this);
try{
echo chr(27).chr(91).'H'.chr(27).chr(91).'J';
error_reporting(E_ERROR | E_PARSE);
$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();
else{
$parts = explode(':', file_get_contents("./configuration.lona"));
$decrypted = openssl_decrypt($parts[0], AES_256_CBC, $this->EncryptionKey, 0, base64_decode($parts[1]));
if(!json_decode($decrypted, true)) {
echo "Encryption Key does not match the existing Configuration file. Exiting.\n";
exit;
}
}
$this->Logger->InfoCache("Loading config.");
$parts = explode(':', file_get_contents("./configuration.lona"));
$decrypted = openssl_decrypt($parts[0], AES_256_CBC, $this->EncryptionKey, 0, base64_decode($parts[1]));
$this->config = json_decode($decrypted, true);
$this->Logger->InfoCache("Checking config.");
if(!$this->config["port"] || !$this->config["address"] || !$this->config["encryptionKey"] || !$this->config["root"]) {
$this->setup();
}
$this->Logger->LoadLogger();
$this->Logger->DropCache();
$this->Logger->Info("Loading Server class.");
$this->Server = new Server($this);
$this->Logger->Info("Loading TableManager class.");
$this->TableManager = new TableManager($this);
$this->Logger->Info("Loading UserManager class.");
$this->UserManager = new UserManager($this);
}
catch (\Exception $e){
$this->Logger->Error($e);
}
}
private function setup() {
$this->Logger->InfoCache("Invalid or missing config. Starting setup.");
echo "Database port:\n";
$portHandle = fopen ("php://stdin","r");
$port = fgets($portHandle);
fclose($portHandle);
echo "Database address:\n";
$addrHandle = fopen ("php://stdin","r");
$addr = fgets($addrHandle);
fclose($addrHandle);
echo "Table encryption key:\n";
$keyHandle = fopen ("php://stdin","r");
$key = fgets($keyHandle);
fclose($keyHandle);
echo "Password for root user:\n";
$rootHandle = fopen ("php://stdin","r");
$root = fgets($rootHandle);
fclose($rootHandle);
echo "Enable logging? (y/N):\n";
$logHandle = fopen ("php://stdin","r");
$logAns = fgets($logHandle);
fclose($logHandle);
$log = false;
if(trim(strtolower($logAns)) === "y") $log = true;
$this->Logger->InfoCache("Saving config.");
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length(AES_256_CBC));
$save = array(
"port" => str_replace("\n","",$port),
"address" => str_replace("\n","",$addr),
"logging" => $log,
"encryptionKey" => str_replace("\n","",$key),
"root" => str_replace("\n","",$root)
);
$encrypted = openssl_encrypt(json_encode($save), AES_256_CBC, $this->EncryptionKey, 0, $iv);
file_put_contents("./configuration.lona", $encrypted.":".base64_encode($iv));
}
}
$run = new LonaDB();

18
src/LonaDB/Server.php Normal file
View File

@ -0,0 +1,18 @@
<?php
namespace LonaDB;
require 'vendor/autoload.php';
use LonaDB\LonaDB;
class Server {
private array $config;
private LonaDB $LonaDB;
public function __construct(LonaDB $lonaDB) {
$this->LonaDB = $lonaDB;
$this->config = $lonaDB->config;
}
}
?>

135
src/LonaDB/Tables/Table.php Normal file
View File

@ -0,0 +1,135 @@
<?php
namespace LonaDB\Tables;
define('AES_256_CBC', 'aes-256-cbc');
use LonaDB\LonaDB;
class Table{
private string $file;
private array $data;
private array $permissions;
private string $Owner;
public string $Name;
private LonaDB $LonaDB;
public function __construct(LonaDB $lonaDB, bool $create, string $name, string $owner = ""){
$this->LonaDB = $lonaDB;
if(!$create){
$this->LonaDB->Logger->Load("Trying to load table '".$name."'");
$parts = explode(':', file_get_contents("./data/tables/".$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->data = $temp["data"];
$this->permissions = $temp["permissions"];
$this->Owner = $temp["owner"];
}
else{
$this->LonaDB->Logger->Table("Trying to generate table '".$name."'");
$this->file = $name;
$this->data = array();
$this->permissions = array();
$this->Owner = $owner;
$this->Save();
}
$this->Name = $this->file;
}
public function GetOwner(string $user = ""){
if($user === "") return $this->Owner;
$this->LonaDB->Logger->Table("(".$this->file.") User '".$user."' is trying to get the owner name.");
if($this->CheckPermission($user, "read")) return;
return $this->Owner;
}
public function SetOwner(string $name, string $user){
$this->LonaDB->Logger->Table("(".$this->file.") User '".$user."' is trying to change the owner to '".$name."'");
if($user !== "root" && $user !== $this->Owner) return;
$this->Owner = $name;
$this->Save();
}
public function Set(string $name, mixed $value, string $user){
$this->LonaDB->Logger->Table("(".$this->file.") User '".$user."' is trying to set the variable '".$name."' to '".strval($value)."'");
if(!$this->CheckPermission($user, "write")) return;
$this->data[$name] = $value;
$this->Save();
$this->LonaDB->Logger->Table("(".$this->file.") User '".$user."' set the variable '".$name."' to '".strval($value)."'");
}
public function Delete(string $name, string $user){
$this->LonaDB->Logger->Table("(".$this->file.") User '".$user."' is trying to delete the variable '".$name."'");
if(!$this->CheckPermission($user, "write")) return;
unset($this->data[$name]);
$this->Save();
$this->LonaDB->Logger->Table("(".$this->file.") User '".$user."' deleted the variable '".$name."'");
}
public function Get(string $name, string $user){
$this->LonaDB->Logger->Table("(".$this->file.") User '".$user."' is trying to get the variable '".$name."'");
if(!$this->CheckPermission($user, "read")) return null;
return $this->data->{$name};
}
public function CheckPermission(string $user, string $permission){
$this->LonaDB->Logger->Table("(".$this->file.") Checkin permission '".$permission."' for user '".$user."'");
if($user === $this->Owner || $this->permissions[$user]["admin"]) return true;
if(!$this->permissions[$user][$permission]) return false;
return true;
}
public function AddPermission(string $name, string $permission, string $user){
if($user !== $this->Owner && !$this->permissions[$user]["admin"]) return
$this->LonaDB->Logger->Table("(".$this->file.") Missing permission! Adding permission '".$permission."' for user '".$name."', requested by '".$user."'");
if($user !== $this->Owner && $permission === "admin") return
$this->LonaDB->Logger->Table("(".$this->file.") Not the Owner! Adding permission '".$permission."' for user '".$name."', requested by '".$user."'");
$this->LonaDB->Logger->Table("(".$this->file.") Adding permission '".$permission."' for user '".$name."', requested by '".$user."'");
$this->permissions[$name][$permission] = true;
$this->Save();
}
public function RemovePermission(string $name, string $permission, string $user){
if($user !== $this->Owner && !$this->permissions[$user]["admin"]) return
$this->LonaDB->Logger->Table("(".$this->file.") Missing permission! Removing permission '".$permission."' for user '".$name."', requested by '".$user."'");
if($user !== $this->Owner && $permission === "admin") return
$this->LonaDB->Logger->Table("(".$this->file.") Not the Owner! Removing permission '".$permission."' for user '".$name."', requested by '".$user."'");
$this->LonaDB->Logger->Table("(".$this->file.") Removing permission '".$permission."' for user '".$name."', requested by '".$user."'");
unset($this->permissions[$name][$permission]);
if($this->permissions[$name] === array()) unset($this->permissions[$name]);
$this->Save();
}
private function Save(){
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length(AES_256_CBC));
$save = array(
"data" => $this->data,
"permissions" => $this->permissions,
"owner" => $this->Owner
);
$encrypted = openssl_encrypt(json_encode($save), AES_256_CBC, $this->LonaDB->config["encryptionKey"], 0, $iv);
file_put_contents("./data/tables/".$this->file.".lona", $encrypted.":".base64_encode($iv));
}
}

View File

@ -0,0 +1,80 @@
<?php
namespace LonaDB\Tables;
require 'vendor/autoload.php';
use LonaDB\LonaDB;
class TableManager{
private LonaDB $LonaDB;
private array $Tables;
public function __construct(LonaDB $lonaDB){
$this->LonaDB = $lonaDB;
$this->Tables = array();
if(!is_dir("data/")) mkdir("data/");
if(!is_dir("data/tables/")) mkdir("data/tables/");
$counter = 0;
foreach (new \DirectoryIterator('data/tables') as $fileInfo) {
if(str_ends_with($fileInfo->getFilename(), ".lona")){
$this->LonaDB->Logger->Load("Loading table from file '" . $fileInfo . "'");
$this->Tables[substr($fileInfo->getFilename(), 0, -5)] = new Table($this->LonaDB, false, $fileInfo->getFilename());
$counter = $counter + 1;
}
}
if($counter === 0){
$this->CreateTable("Default", "root");
}
}
public function GetTable(string $name){
if(!$this->Tables[$name]) return false;
return $this->Tables[$name];
}
public function ListTables(string $user = ""){
$tables = array();
if($user !== ""){
foreach($this->Tables as $table){
if($table->CheckPermission($user, "write")) array_push($tables, $table->Name);
else if($table->CheckPermission($user, "read")) array_push($tables, $table->Name);
}
}
else{
foreach($this->Tables as $table){
array_push($tables, $table->Name);
}
}
return $tables;
}
public function CreateTable(string $name, string $owner){
$this->LonaDB->Logger->Table("Trying to create table '" . $name . "', owned by user '" . $owner . "'");
if($this->Tables[$name]) {
$this->LonaDB->Logger->Error("Table '" . $name . "' already exists");
return false;
}
$this->Tables[$name] = new Table($this->LonaDB, true, $name, $owner);
$this->LonaDB->Logger->Table("Table '" . $name . "' has been created");
}
public function DeleteTable(string $name, string $user){
$this->LonaDB->Logger->Table("Trying to delete table '" . $name . "', requested by user '" . $user . "'");
if(!$this->Tables[$name]) {
$this->LonaDB->Logger->Error("Table '" . $name . "' doesn't exist");
return;
}
if($user !== $this->Tables[$name]->GetOwner()) return
$this->LonaDB->Logger->Table("Not the owner! Trying to delete table '" . $name . "', requested by user '" . $user . "'");
unlink("data/".$name.".json");
unset($this->Tables[$name]);
$this->LonaDB->Logger->Table("Deleted table '" . $name . "', requested by user '" . $user . "'");
}
}

View File

@ -0,0 +1,86 @@
<?php
namespace LonaDB\Users;
define('AES_256_CBC', 'aes-256-cbc');
require 'vendor/autoload.php';
use LonaDB\LonaDB;
class UserManager{
private LonaDB $LonaDB;
private array $Users;
public function __construct(LonaDB $lonaDB){
$this->LonaDB = $lonaDB;
$this->Tables = array();
if(!is_dir("data/")) mkdir("data/");
file_put_contents("data/Users.lona", file_get_contents("data/Users.lona"));
if(file_get_contents("data/Users.lona") === "") {
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length(AES_256_CBC));
$save = array();
$encrypted = openssl_encrypt(json_encode($save), AES_256_CBC, $this->LonaDB->config["encryptionKey"], 0, $iv);
file_put_contents("./data/Users.lona", $encrypted.":".base64_encode($iv));
}
$parts = explode(':', file_get_contents("./data/Users.lona"));
$this->Users = json_decode(openssl_decrypt($parts[0], AES_256_CBC, $this->LonaDB->config["encryptionKey"], 0, base64_decode($parts[1])), true);
}
public function CheckPassword(string $name, string $password){
$this->LonaDB->Logger->User("Trying to check password for user '" . $name . "'");
if($name === "root" && $password === $this->LonaDB->config["root"]) return true;
if(!$this->Users[$name]) {
$this->LonaDB->Logger->User("User '".$name."'doesn't exist");
return false;
}
if($this->Users[$name]["password"] !== $password) return false;
return true;
}
public function CreateUser(string $name, string $password){
if($name === "root") return;
$this->LonaDB->Logger->User("Trying to create user '" . $name . "'");
if($this->Users[$name]) {
$this->LonaDB->Logger->Error("User '" . $name . "' already exists");
return false;
}
$this->Users[$name] = array(
"role" => "user",
"password" => $password,
"permissions" => []
);
$this->LonaDB->Logger->User("User '" . $name . "' has been created");
$this->Save();
}
public function DeleteUser(string $name){
if($name === "root") return;
$this->LonaDB->Logger->User("Trying to delete user '" . $name . "'");
if(!$this->Users[$name]) {
$this->LonaDB->Logger->Error("User '" . $name . "' doesn't exist");
return;
}
unset($this->Users[$name]);
$this->LonaDB->Logger->User("Deleted user '" . $name . "'");
$this->Save();
}
public function Save(){
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length(AES_256_CBC));
$encrypted = openssl_encrypt(json_encode($this->Users), AES_256_CBC, $this->LonaDB->config["encryptionKey"], 0, $iv);
file_put_contents("./data/Users.lona", $encrypted.":".base64_encode($iv));
}
}

17
src/composer.json Normal file
View File

@ -0,0 +1,17 @@
{
"name": "lona/database",
"description": "Object oriented DBMS",
"type": "project",
"license": "GNU AGPLv3",
"autoload": {
"psr-4": {
"LonaDB\\": "LonaDB/"
}
},
"authors": [
{
"name": "Lona Devs"
}
],
"require": {}
}

18
src/composer.lock generated Normal file
View File

@ -0,0 +1,18 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "dc4784b5c77dc7aef8720fbec77a7d65",
"packages": [],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
"platform-dev": [],
"plugin-api-version": "2.6.0"
}

BIN
src/composer.phar Executable file

Binary file not shown.