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

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 . '/';
}
}