This commit is contained in:
Maurice Grönwoldt 2020-09-25 21:33:54 +02:00
parent 21977588d8
commit f7fa124535
21 changed files with 388 additions and 58 deletions

View file

@ -9,7 +9,8 @@
}
],
"require": {
"ext-pdo": "*"
"ext-pdo": "*",
"ext-http": "*"
},
"autoload": {
"psr-4": {

View file

@ -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';

View file

@ -1,7 +0,0 @@
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (/[^.]*|\.)$ [NC]
RewriteRule .* index.php [L]

View file

@ -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();

View file

@ -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();

View 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;
}

View file

View 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;
}
}

View 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 [];
}
}

View file

@ -0,0 +1,15 @@
<?php
namespace Venom\Admin\Routes;
use Venom\Routing\Route;
class LoginRoute implements Route
{
public function getAll(): bool {
return true;
}
}

View file

@ -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]);
}
}

View file

@ -42,4 +42,9 @@ class URLHelper
{
return $url;
}
public function isAdminUrl(): bool
{
return strpos($this->parsedUrl, '/admin/') === 0;
}
}

View file

@ -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;
}
}

View file

@ -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],

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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();
}
}

View file

@ -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) {

View file

@ -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);
}
}

View file

@ -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
View 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!';
}