Skip to content

Commit

Permalink
Merge pull request #13 from lewmilburn/web-user-auth
Browse files Browse the repository at this point in the history
[WEB] User authentication + encryption
  • Loading branch information
lewmilburn authored Oct 31, 2023
2 parents 16ed428 + a1de08a commit c31b380
Show file tree
Hide file tree
Showing 20 changed files with 515 additions and 2 deletions.
3 changes: 1 addition & 2 deletions .github/workflows/sonarcloud.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,7 @@ jobs:
# mandatory
-Dsonar.projectKey=lewmilburn_Vault
-Dsonar.organization=lewmilburn
# Comma-separated paths to directories containing main source files.
#-Dsonar.sources= # optional, default is project base directory
#-Dsonar.sources=
# When you need the analysis to take place in a directory other than the one from which it was launched
#-Dsonar.projectBaseDir= # optional, default is .
# Comma-separated paths to directories containing test source files.
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/.idea/
users.json
admin.vault
Binary file added Web/assets/images/vault.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
60 changes: 60 additions & 0 deletions Web/authentication/authenticationManager.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

namespace Vault\authentication;

use Vault\Data\dataManager;
use Vault\Event\errorHandler;

class authenticationManager
{
public function login(string $username, string $password)
{
if ($username == null || $password == null) {
return false;
}

if (session_status() == PHP_SESSION_ACTIVE) {
$data = new dataManager();
$user = $data->getUserData($username);

if ($user == null) {
return false;
}

if (password_verify($password, $user->passkey)) {
$tm = new tokenManager();
$token = $tm->generateToken($user->user);
$_SESSION['user'] = $user->user;
$_SESSION['token'] = $token;

return true;
} else {
return false;
}
} else {
$eh = new errorHandler();
$eh->sessionRequired('authentication', 'authenticationManager', 'Login');
exit;
}
}

public function logout()
{
$sm = new sessionManager();
if ($sm->end()) {
header('Location: /');
exit;
}
}

public function authenticated()
{
$sm = new sessionManager();
$tm = new tokenManager();
if ($sm->authTokens() && $tm->validToken($_SESSION['token'], $_SESSION['user'])) {
return true;
} else {
return false;
}
}
}
36 changes: 36 additions & 0 deletions Web/authentication/sessionManager.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

namespace Vault\authentication;

class sessionManager
{
public function active(): bool
{
if (session_status() == PHP_SESSION_ACTIVE) {
return true;
} else {
return false;
}
}

public function end(): bool
{
if ($this->active()) {
session_unset();
session_destroy();

return true;
} else {
return false;
}
}

public function authTokens(): bool
{
if (isset($_SESSION['token']) && isset($_SESSION['user'])) {
return true;
} else {
return false;
}
}
}
20 changes: 20 additions & 0 deletions Web/authentication/tokenManager.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace Vault\authentication;

class tokenManager
{
public function generateToken(string $uuid): string
{
return hash('sha3-512', $uuid.date('Y-m-d'));
}

public function validToken(string $token, string $user): string
{
if ($token == hash('sha3-512', $user.date('Y-m-d'))) {
return true;
} else {
return false;
}
}
}
6 changes: 6 additions & 0 deletions Web/data/const.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?php

const DEV = 0;
const PROD = 1;
const DATABASE = 0;
const FILESYSTEM = 1;
22 changes: 22 additions & 0 deletions Web/data/dataManager.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace Vault\data;

class dataManager
{
/**
* @throws \Exception Invalid data type.
*/
public function getUserData(string $username): object|null
{
if (STORAGE_TYPE == DATABASE) {
$dm = new databaseManager();
} elseif (STORAGE_TYPE == FILESYSTEM) {
$dm = new fileManager();
} else {
throw new \Exception('Data type is invalid.');
}

return $dm->getUserData($username);
}
}
11 changes: 11 additions & 0 deletions Web/data/databaseManager.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace Vault\data;

class databaseManager
{
public function getUserData(string $username)
{
return ''; //temp
}
}
56 changes: 56 additions & 0 deletions Web/data/fileManager.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

namespace Vault\data;

use Vault\security\encryptionManager;

class fileManager
{
private string $usersFile;
private string $defaultVault;

public function __construct()
{
$this->usersFile = __DIR__.'/../'.SECURE_LOCATION.USERS_FILE;
$this->defaultVault = __DIR__.'/../'.SECURE_LOCATION.DEFAULT_USER.'.vault';

if (!file_exists($this->usersFile)) {
$this->initialiseUsers();
}

if (!file_exists($this->defaultVault)) {
$this->initialiseVault();
}
}

public function getUserData(string $username): object|null
{
$usersFile = file_get_contents($this->usersFile);
$users = json_decode($usersFile);
foreach ($users as $user) {
if ($user->user == $username) {
return $user;
}
}

return null;
}

private function initialiseUsers(): void
{
$UserFile = fopen($this->usersFile, 'w');
fwrite($UserFile, '[{"user":"admin","passkey":"'.password_hash(TEMPORARY_PASSWORD, PASSWORD_DEFAULT).'"}]');
fclose($UserFile);
}

private function initialiseVault(): void
{
$VaultFile = fopen($this->defaultVault, 'w');

$em = new encryptionManager();
$EncryptedData = $em->encrypt('[{}]', $em->generateKey(PASSWORD_DEFAULT));

fwrite($VaultFile, $EncryptedData[0].FILE_SEPARATOR.$EncryptedData[1]);
fclose($VaultFile);
}
}
48 changes: 48 additions & 0 deletions Web/event/errorHandler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

namespace Vault\event;

class errorHandler
{
public function error(string|null $namespace, string|null $class, string|null $function, string $message, string $code): void
{
http_response_code($code);
ob_end_clean();
echo' <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Vault Error</title>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
</head>
<body class="p-4">
<div class="text-center">
<img src="/assets/images/vault.png" alt="Vault" style="width:4rem">
<h1>Error '.$code.'</h1>
</div>
<table class="table">
<tr>
<th scope="row">Function</th>
<td>Vault\\'.$namespace.'\\'.$class.'::'.$function.'</td>
</tr>
<tr>
<th scope="row">Error</th>
<td>'.$message.'</td>
</tr>
</table>
</body>
</html>';
exit;
}

public function sessionRequired(string $namespace, string $class, string $function): void
{
$this->error($namespace, $class, $function, 'Internal Server Error - An active PHP session is required to run this function.', 500);
}

public function fileNotFound(string $namespace, string $class, string $function)
{
$this->error($namespace, $class, $function, 'File Not Found - The requested file could not be found.', 404);
}
}
27 changes: 27 additions & 0 deletions Web/event/login.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

use Vault\authentication\authenticationManager;
use Vault\data\dataManager;
use Vault\inputManager;

if (!isset($_POST['user']) || !isset($_POST['pass'])) {
header('Location: /');
exit;
}

$am = new authenticationManager();
$dm = new dataManager();
$im = new inputManager();

$user = $im->escapeString($_POST['user']);
$pass = $im->escapeString($_POST['pass']);

if ($user == null || $pass == null) {
header('Location: /');
exit;
}

$am->login($user, $pass);

header('Location: /');
exit;
47 changes: 47 additions & 0 deletions Web/event/routeHandler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

namespace Vault\event;

use JetBrains\PhpStorm\NoReturn;

class routeHandler
{
#[NoReturn]
public function getRequest($url, $file): void
{
$this->request($url, $file, 'GET');
}

#[NoReturn]
public function postRequest(string $url, string $file): void
{
$this->request($url, $file, 'POST');
}

#[NoReturn]
public function request(string $url, string $file, string $method): void
{
if ($_SERVER['REQUEST_URI'] === $url && $_SERVER['REQUEST_METHOD'] === $method) {
$this->runFile($file);
}
}

#[NoReturn]
public function endRouter(): void
{
$eh = new errorHandler();
$eh->fileNotFound('event', 'routeHandler', 'endRouter');
}

#[NoReturn]
private function runFile($file): void
{
if (file_exists(__DIR__.'/../'.$file)) {
require_once __DIR__.'/../'.$file;
} else {
$eh = new errorHandler();
$eh->fileNotFound('event', 'routeHandler', 'displayFile');
}
exit;
}
}
28 changes: 28 additions & 0 deletions Web/index.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

/**
* @author Lewis Milburn
* @license Apache 2.0 International License
*/

use Vault\authentication\authenticationManager;
use Vault\event\routeHandler;

ob_start();
session_start();

require_once __DIR__.'/loader.php';

$router = new routeHandler();
$auth = new authenticationManager();

if ($auth->authenticated()) {
$router->getRequest('/', 'view/dashboard.php');
} else {
$router->getRequest('/', 'view/login.php');
$router->postRequest('/auth', 'event/login.php');
}

$router->endRouter();

ob_end_flush();
Loading

0 comments on commit c31b380

Please sign in to comment.