WIP
This commit is contained in:
parent
21977588d8
commit
f7fa124535
21 changed files with 388 additions and 58 deletions
|
@ -9,7 +9,8 @@
|
|||
}
|
||||
],
|
||||
"require": {
|
||||
"ext-pdo": "*"
|
||||
"ext-pdo": "*",
|
||||
"ext-http": "*"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
|
|
@ -27,3 +27,16 @@ create table if not exists data
|
|||
datatype enum ('content', 'form')
|
||||
)
|
||||
comment 'DataLoader File';
|
||||
|
||||
create table if not exists users
|
||||
(
|
||||
id int(255) auto_increment not null unique primary key,
|
||||
username varchar(255) not null unique,
|
||||
email varchar(255) not null,
|
||||
password varchar(255) not null,
|
||||
token varchar(255) not null,
|
||||
salt varchar(255) not null,
|
||||
roles text default 'ROLE_GUEST' not null,
|
||||
isActive tinyint(1) default 1 null
|
||||
)
|
||||
comment 'User File';
|
|
@ -1,7 +0,0 @@
|
|||
RewriteEngine On
|
||||
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
|
||||
RewriteCond %{REQUEST_URI} (/[^.]*|\.)$ [NC]
|
||||
RewriteRule .* index.php [L]
|
|
@ -1,24 +0,0 @@
|
|||
<?php
|
||||
|
||||
use Venom\Core\Config;
|
||||
use Venom\Core\Setup;
|
||||
use Venom\Venom;
|
||||
|
||||
require_once '../../vendor/autoload.php';
|
||||
Setup::loadConfig(true);
|
||||
Setup::loadLanguage();
|
||||
|
||||
$config = Config::getInstance();
|
||||
if ($config->isMaintenance()) {
|
||||
echo 'Currently not available';
|
||||
exit;
|
||||
}
|
||||
//if devMode is on show all errors!
|
||||
if ($config->isDevMode()) {
|
||||
error_reporting(E_ALL);
|
||||
ini_set('error_reporting', E_ALL);
|
||||
}
|
||||
$venom = new Venom();
|
||||
Setup::loadRouters($venom);
|
||||
Setup::loadModules($venom);
|
||||
$venom->run();
|
|
@ -2,10 +2,12 @@
|
|||
|
||||
use Venom\Core\Config;
|
||||
use Venom\Core\Setup;
|
||||
use Venom\Helper\URLHelper;
|
||||
use Venom\Venom;
|
||||
|
||||
require_once '../vendor/autoload.php';
|
||||
Setup::loadConfig(false);
|
||||
session_start();
|
||||
Setup::loadConfig(URLHelper::getInstance()->isAdminUrl());
|
||||
Setup::loadLanguage();
|
||||
|
||||
$config = Config::getInstance();
|
||||
|
@ -21,4 +23,4 @@ if ($config->isDevMode()) {
|
|||
$venom = new Venom();
|
||||
Setup::loadRouters($venom);
|
||||
Setup::loadModules($venom);
|
||||
$venom->run();
|
||||
$venom->inject();
|
22
public/theme/admin/css/test.css
Normal file
22
public/theme/admin/css/test.css
Normal file
|
@ -0,0 +1,22 @@
|
|||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html, body {
|
||||
margin: 0;
|
||||
font-size: 16px;
|
||||
color: #fff;
|
||||
background-color: #333;
|
||||
font-family: sans-serif;
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
}
|
||||
|
||||
header {
|
||||
font-size: 5vw;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
header:hover {
|
||||
color: #ff0323;
|
||||
}
|
0
public/theme/admin/js/test.js
Normal file
0
public/theme/admin/js/test.js
Normal file
35
src/Venom/Admin/AdminController.php
Normal file
35
src/Venom/Admin/AdminController.php
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
|
||||
namespace Venom\Admin;
|
||||
|
||||
|
||||
use Venom\Helper\URLHelper;
|
||||
use Venom\Views\RenderController;
|
||||
use Venom\Views\VenomRenderer;
|
||||
|
||||
class AdminController implements RenderController
|
||||
|
||||
{
|
||||
|
||||
private string $tpl = 'default';
|
||||
|
||||
public function register(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function render(VenomRenderer $renderer): bool
|
||||
{
|
||||
if (URLHelper::getInstance()->getUrl() !== '/admin/') {
|
||||
http_response_code(404);
|
||||
$this->tpl = 'async';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getTemplate(): string
|
||||
{
|
||||
return $this->tpl;
|
||||
}
|
||||
}
|
23
src/Venom/Admin/AdminRouterInit.php
Normal file
23
src/Venom/Admin/AdminRouterInit.php
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
|
||||
namespace Venom\Admin;
|
||||
|
||||
|
||||
use Venom\Routing\Router;
|
||||
use Venom\Venom;
|
||||
|
||||
class AdminRouterInit
|
||||
{
|
||||
public static function registerAdminRouters(Venom $venom): void
|
||||
{
|
||||
$router = new Router(Router::ADMIN_ROUTER, 1.0, '/admin/api');
|
||||
$router->addRoutes(self::getRoutes());
|
||||
$venom->addRouter(Router::ADMIN_ROUTER, $router);
|
||||
}
|
||||
|
||||
public static function getRoutes(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
15
src/Venom/Admin/Routes/LoginRoute.php
Normal file
15
src/Venom/Admin/Routes/LoginRoute.php
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
|
||||
namespace Venom\Admin\Routes;
|
||||
|
||||
|
||||
use Venom\Routing\Route;
|
||||
|
||||
class LoginRoute implements Route
|
||||
{
|
||||
|
||||
public function getAll(): bool {
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@ class ArgumentHandler
|
|||
{
|
||||
public static ?ArgumentHandler $instance = null;
|
||||
private array $arguments = [];
|
||||
private array $post = [];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
|
@ -16,6 +17,7 @@ class ArgumentHandler
|
|||
}
|
||||
foreach ($_POST as $key => $item) {
|
||||
$this->arguments[htmlspecialchars($key)] = htmlspecialchars($item);
|
||||
$this->post[htmlspecialchars($key)] = htmlspecialchars($item);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,4 +43,14 @@ class ArgumentHandler
|
|||
{
|
||||
return isset($this->arguments[$key]);
|
||||
}
|
||||
|
||||
public function getPostItem(string $key, $default = null)
|
||||
{
|
||||
return $this->post[$key] ?? $default;
|
||||
}
|
||||
|
||||
public function hasPostItem(string $key): bool
|
||||
{
|
||||
return isset($this->post[$key]);
|
||||
}
|
||||
}
|
|
@ -42,4 +42,9 @@ class URLHelper
|
|||
{
|
||||
return $url;
|
||||
}
|
||||
|
||||
public function isAdminUrl(): bool
|
||||
{
|
||||
return strpos($this->parsedUrl, '/admin/') === 0;
|
||||
}
|
||||
}
|
|
@ -4,11 +4,124 @@
|
|||
namespace Venom\Models;
|
||||
|
||||
|
||||
use Venom\Core\DatabaseHandler;
|
||||
|
||||
class User
|
||||
{
|
||||
private string $username;
|
||||
private string $password;
|
||||
private string $salt;
|
||||
private string $token;
|
||||
private array $roles;
|
||||
public const ADMIN_ROLE = 'ROLE_ADMIN';
|
||||
public const GUEST_ROLE = 'ROLE_GUEST';
|
||||
private string $username = 'GUEST';
|
||||
private string $email = 'GUEST';
|
||||
private string $password = '---';
|
||||
private string $salt = '---';
|
||||
private string $token = '---';
|
||||
private string $id = '-1';
|
||||
private array $roles = [];
|
||||
private bool $isLoaded = false;
|
||||
|
||||
public function hasRole(string $role): bool
|
||||
{
|
||||
return in_array($role, $this->roles, true);
|
||||
}
|
||||
|
||||
public function loadUser(): bool
|
||||
{
|
||||
if (isset($_SESSION['userID'])) {
|
||||
// try to load user from id!
|
||||
$user = DatabaseHandler::get()->getOne("SELECT * FROM users WHERE id = :id OR username = :name AND isActive = 1", [
|
||||
':id' => $_SESSION['userID'],
|
||||
':name' => $this->username
|
||||
]);
|
||||
if ($user) {
|
||||
$this->username = $user->username ?? '';
|
||||
$this->email = $user->email ?? '';
|
||||
$this->password = $user->password ?? '';
|
||||
$this->token = $user->token ?? '';
|
||||
$this->salt = $user->salt ?? '';
|
||||
$this->id = $user->id ?? '-1';
|
||||
$this->roles = explode(',', $user->roles ?? '');
|
||||
$this->isLoaded = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getUsername(): string
|
||||
{
|
||||
return $this->username;
|
||||
}
|
||||
|
||||
public function setUsername(string $username): void
|
||||
{
|
||||
$this->username = $username;
|
||||
}
|
||||
|
||||
public function getEmail(): string
|
||||
{
|
||||
return $this->email;
|
||||
}
|
||||
|
||||
public function setEmail(string $email): void
|
||||
{
|
||||
$this->email = $email;
|
||||
}
|
||||
|
||||
public function getPassword(): string
|
||||
{
|
||||
return $this->password;
|
||||
}
|
||||
|
||||
public function setPassword(string $password): void
|
||||
{
|
||||
$this->password = $password;
|
||||
}
|
||||
|
||||
public function getSalt(): string
|
||||
{
|
||||
return $this->salt;
|
||||
}
|
||||
|
||||
public function setSalt(string $salt): void
|
||||
{
|
||||
$this->salt = $salt;
|
||||
}
|
||||
|
||||
public function getToken(): string
|
||||
{
|
||||
return $this->token;
|
||||
}
|
||||
|
||||
public function setToken(string $token): void
|
||||
{
|
||||
$this->token = $token;
|
||||
}
|
||||
|
||||
public function getRoles(): array
|
||||
{
|
||||
return $this->roles;
|
||||
}
|
||||
|
||||
public function setRoles(array $roles): void
|
||||
{
|
||||
$this->roles = $roles;
|
||||
}
|
||||
|
||||
public function addRole($value): void
|
||||
{
|
||||
if (!in_array($value, $this->roles, true)) {
|
||||
$this->roles[] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
public function isLoaded(): bool
|
||||
{
|
||||
return $this->isLoaded;
|
||||
}
|
||||
|
||||
public function getId(): string
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
}
|
|
@ -5,9 +5,14 @@ namespace Venom\Routing;
|
|||
|
||||
|
||||
use Exception;
|
||||
use Venom\Core\Config;
|
||||
use Venom\Models\User;
|
||||
use Venom\Security\Security;
|
||||
|
||||
class Router
|
||||
{
|
||||
public const DEFAULT_ROUTER = 'defaultRouter';
|
||||
public const ADMIN_ROUTER = 'adminRouter';
|
||||
protected string $id = 'defaultRouter';
|
||||
protected int $version;
|
||||
protected string $prefix = '';
|
||||
|
@ -66,6 +71,12 @@ class Router
|
|||
$subRouteFound = isset($this->routes[$url]['routes'][$subRoute]);
|
||||
$methodFound = isset($this->routes[$url]['routes'][$subRoute][$method]);
|
||||
if ($routeAvailable && $subRouteFound && $methodFound) {
|
||||
if ((Config::getInstance()->getSecurity()->useSecurity || $this->id === self::ADMIN_ROUTER) && isset($this->routes[$url]['roles'])) {
|
||||
$roles = $this->routes[$url]['roles'];
|
||||
if (!in_array(User::GUEST_ROLE, $roles, true) && !Security::get()->hasRoles($roles)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return [
|
||||
'cl' => $this->routes[$url]['cl'],
|
||||
'fnc' => $this->routes[$url]['routes'][$subRoute][$method],
|
||||
|
|
|
@ -4,10 +4,48 @@
|
|||
namespace Venom\Security;
|
||||
|
||||
|
||||
use Venom\Core\ArgumentHandler;
|
||||
use Venom\Core\Config;
|
||||
use Venom\Helper\URLHelper;
|
||||
use Venom\Models\User;
|
||||
|
||||
/**
|
||||
* Class that Login stupid via Password, Username
|
||||
*/
|
||||
class BaseLogin
|
||||
class BaseLogin implements Login
|
||||
{
|
||||
|
||||
private User $user;
|
||||
|
||||
public function __construct(User $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
public function checkCredentials(): bool
|
||||
{
|
||||
$handler = ArgumentHandler::get();
|
||||
return $handler->hasPostItem('USERNAME') && $handler->hasPostItem('PASSWORD');
|
||||
}
|
||||
|
||||
public function redirect(): void
|
||||
{
|
||||
http_redirect(URLHelper::getInstance()->getUrl(), ['redirect' => 'true'], true);
|
||||
}
|
||||
|
||||
public function login(): bool
|
||||
{
|
||||
$sec = Config::getInstance()->getSecurity();
|
||||
$this->user->setUsername(ArgumentHandler::get()->getPostItem('USERNAME'));
|
||||
if (!$this->user->loadUser()) {
|
||||
return false;
|
||||
}
|
||||
$secret = $sec->secret ?? 'venom';
|
||||
$hashed = hash($sec->algo ?? 'SHA256', ArgumentHandler::get()->getPostItem('PASSWORD') . $secret . $this->user->getSalt());
|
||||
if ($this->user->getPassword() === $hashed) {
|
||||
$_SESSION['userID'] = $this->user->getId();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -10,10 +10,6 @@ interface Login
|
|||
{
|
||||
public function __construct(User $user);
|
||||
|
||||
public function checkUsername(): bool;
|
||||
|
||||
public function checkPassword(): bool;
|
||||
|
||||
public function checkCredentials(): bool;
|
||||
|
||||
public function login(): bool;
|
||||
|
|
|
@ -3,10 +3,20 @@
|
|||
|
||||
namespace Venom\Security;
|
||||
|
||||
use http\Exception\RuntimeException;
|
||||
use Venom\Core\Config;
|
||||
use Venom\Models\User;
|
||||
|
||||
class Security
|
||||
{
|
||||
private static ?Security $instance = null;
|
||||
private ?User $user;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->user = new User();
|
||||
$this->user->loadData();
|
||||
}
|
||||
|
||||
public static function get(): Security
|
||||
{
|
||||
|
@ -16,15 +26,39 @@ class Security
|
|||
return self::$instance;
|
||||
}
|
||||
|
||||
/* @todo implement logic */
|
||||
public function hasRole(string $role): bool
|
||||
{
|
||||
return $this->user->hasRole($role);
|
||||
}
|
||||
|
||||
public function hasRoles(array $roles): bool
|
||||
{
|
||||
foreach ($roles as $role) {
|
||||
if (!$this->user->hasRole($role)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* @todo implement logic */
|
||||
public function hasRoles(array $roles): bool
|
||||
public function login(): void
|
||||
{
|
||||
return true;
|
||||
if (!$this->user->isLoaded()) {
|
||||
throw new RuntimeException('Try to re-login!');
|
||||
}
|
||||
$sec = Config::getInstance()->getSecurity();
|
||||
$login = new $sec->securityClass;
|
||||
if ($login instanceof Login) {
|
||||
if (!$login->checkCredentials() || !$login->login()) {
|
||||
http_response_code(401);
|
||||
}
|
||||
$login->redirect();
|
||||
}
|
||||
}
|
||||
|
||||
public function logout(): void
|
||||
{
|
||||
unset($_SESSION['userID']);
|
||||
$this->user = new User();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
namespace Venom;
|
||||
|
||||
|
||||
use Venom\Admin\AdminController;
|
||||
use Venom\Admin\AdminRouterInit;
|
||||
use Venom\Core\ArgumentHandler;
|
||||
use Venom\Core\Config;
|
||||
use Venom\Core\Module;
|
||||
|
@ -30,13 +32,22 @@ class Venom
|
|||
Asset::get()->setRenderer($this->renderer);
|
||||
}
|
||||
|
||||
public function inject(): void
|
||||
{
|
||||
$this->run();
|
||||
}
|
||||
|
||||
public function run(): void
|
||||
{
|
||||
$arguments = ArgumentHandler::get();
|
||||
$arguments->setItem(ErrorHandler::ERROR_KEY, false);
|
||||
$config = Config::getInstance();
|
||||
if ($config->isAdmin()) {
|
||||
$this->initAdmin();
|
||||
}
|
||||
// we need to load the current controller and the current start template.
|
||||
// after this we can start the renderer
|
||||
if (Config::getInstance()->isRouterEnabled()) {
|
||||
if ($config->isRouterEnabled() || $config->isAdmin()) {
|
||||
$status = $this->useRouter();
|
||||
if ($status['found']) {
|
||||
if ($status['status']) {
|
||||
|
@ -48,18 +59,32 @@ class Venom
|
|||
$registry = Registry::getInstance();
|
||||
$registry->getLang()->initLang();
|
||||
// if site is errored then dont load via SEO
|
||||
if (!$arguments->getItem(ErrorHandler::ERROR_KEY)) {
|
||||
if (!$config->isAdmin() && !$arguments->getItem(ErrorHandler::ERROR_KEY)) {
|
||||
$registry->getSeo()->loadSite();
|
||||
}
|
||||
$this->renderer->init($this->findController());
|
||||
$this->renderer->render();
|
||||
}
|
||||
|
||||
public function initAdmin(): void
|
||||
{
|
||||
$this->controllers['adminCtrl'] = AdminController::class;
|
||||
AdminRouterInit::registerAdminRouters($this);
|
||||
ArgumentHandler::get()->setItem('cl', 'adminCtrl');
|
||||
}
|
||||
|
||||
private function useRouter(): array
|
||||
{
|
||||
$url = URLHelper::getInstance()->getUrl();
|
||||
$isAdmin = Config::getInstance()->isAdmin();
|
||||
/** @var Router $router */
|
||||
foreach ($this->routers as $router) {
|
||||
foreach ($this->routers as $key => $router) {
|
||||
if ($isAdmin && $key !== Router::ADMIN_ROUTER) {
|
||||
continue;
|
||||
}
|
||||
if (!$isAdmin && $key === Router::ADMIN_ROUTER) {
|
||||
continue;
|
||||
}
|
||||
$route = $router->findRoute($url, $_SERVER['REQUEST_METHOD']);
|
||||
$status = $router->tryFunctionCall($route);
|
||||
if ($route !== null) {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
namespace Venom\Views;
|
||||
|
||||
use RuntimeException;
|
||||
use \RuntimeException;
|
||||
use Venom\Core\DatabaseHandler;
|
||||
use Venom\Models\DataModel;
|
||||
|
||||
|
@ -87,8 +87,8 @@ class DataLoader
|
|||
private function generateID(string $id = ''): string
|
||||
{
|
||||
if ($id === '') {
|
||||
$id = bin2hex(random_bytes(16));
|
||||
$id = bin2hex(random_bytes(32));
|
||||
}
|
||||
return $id;
|
||||
return hash('SHA256', $id);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -84,7 +84,7 @@ class VenomRenderer
|
|||
return $this->vars[$name];
|
||||
}
|
||||
|
||||
public function deleteVar($name)
|
||||
public function deleteVar($name): void
|
||||
{
|
||||
unset($this->vars[$name]);
|
||||
}
|
||||
|
@ -93,7 +93,13 @@ class VenomRenderer
|
|||
{
|
||||
$this->controller = $controller;
|
||||
$data = Config::getInstance()->getRenderer();
|
||||
$this->baseTemplate = $data->baseFile . '.php' ?? 'base.php';
|
||||
$this->templateDir = __DIR__ . '/../../../tpl/' . $data->theme . '/';
|
||||
$theme = $data->theme;
|
||||
$base = $data->baseFile ?? 'base';
|
||||
if (Config::getInstance()->isAdmin()) {
|
||||
$base = 'base';
|
||||
$theme = 'admin';
|
||||
}
|
||||
$this->baseTemplate = $base . '.php';
|
||||
$this->templateDir = __DIR__ . '/../../../tpl/' . $theme . '/';
|
||||
}
|
||||
}
|
||||
|
|
10
tpl/admin/base.php
Normal file
10
tpl/admin/base.php
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
use Venom\Models\User;
|
||||
use \Venom\Security\Security;
|
||||
|
||||
if (!Security::get()->hasRole(User::ADMIN_ROLE)) {
|
||||
echo 'Login!';
|
||||
} else {
|
||||
echo 'Admin Interface!';
|
||||
}
|
Loading…
Reference in a new issue