parent
b1d1a09254
commit
c17f89bc96
@ -0,0 +1,86 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
/** |
||||
* @author Robert Strutts |
||||
* @copyright (c) 2026, Robert Strutts |
||||
* @license MIT |
||||
*/ |
||||
|
||||
namespace Project\Classes\Logic; |
||||
|
||||
use \IOcornerstone\Framework\Uuids\UuidV7; |
||||
use \IOcornerstone\Framework\Configure; |
||||
use \Project\Classes\Models\HomeLoginModel; |
||||
|
||||
/** |
||||
* Description of IndexLogin |
||||
* |
||||
* @author Robert Strutts |
||||
*/ |
||||
class IndexLogin |
||||
{ |
||||
|
||||
private static function allowLogin(string $dbHash): bool |
||||
{ |
||||
$uuid = $_POST['token'] ?? false; |
||||
$suuid = $_SESSION['token'] ?? false; |
||||
$pwd = $_POST['pwd'] ?? false; |
||||
if ($pwd === false || empty($pwd) || $uuid === false || $suuid === false) { |
||||
return false; |
||||
} |
||||
$ts = UuidV7::getTimestampFromUuidV7($uuid); |
||||
$ts2 = UuidV7::getTimestampFromUuidV7($suuid); |
||||
$d = UuidV7::getFormatedDate($ts); |
||||
$d2 = UuidV7::getFormatedDate($ts2); |
||||
|
||||
$diffInSeconds = abs(strtotime($d) - strtotime($d2)); |
||||
if ($diffInSeconds > 600) { // 600 seconds = 10 minutes |
||||
return false; |
||||
} |
||||
|
||||
|
||||
// $dbHash = password_hash($pwd, PASSWORD_ARGON2ID); |
||||
|
||||
$allow = password_verify($pwd, $dbHash); |
||||
if (!$allow) { |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
public static function doLogin(): bool |
||||
{ |
||||
$login = $_POST['login'] ?? false; |
||||
if ($login === false) { |
||||
$token = UuidV7::generateUuidV7(); |
||||
$_SESSION['token'] = $token; |
||||
return false; // IE Show Login |
||||
} |
||||
|
||||
$pdo = Configure::get('db'); |
||||
$model = new HomeLoginModel($pdo); |
||||
|
||||
$dbHash = $model->getLogin($login); |
||||
$allow = self::allowLogin($dbHash); |
||||
if ($allow) { |
||||
|
||||
$level = $_SESSION['accessLevel'] ?? 0; |
||||
$user = match ($level) { |
||||
1 => "User", |
||||
2 => "Moderator", |
||||
3 => "Admin", |
||||
default => "Error", |
||||
}; |
||||
|
||||
if ($user === "User") { |
||||
header("Location: /App/Home/Index.html"); |
||||
} |
||||
if ($user === "Admin") { |
||||
header("Location: /Admin/Home/Index.html"); |
||||
} |
||||
} |
||||
return $allow; |
||||
} |
||||
} |
||||
@ -0,0 +1,51 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
/** |
||||
* @author Robert Strutts |
||||
* @copyright (c) 2026, Robert Strutts |
||||
* @license MIT |
||||
*/ |
||||
|
||||
namespace Project\Classes\Models; |
||||
|
||||
/** |
||||
* Description of HomeLoginModel |
||||
* Do Login... |
||||
* @author Robert Strutts |
||||
*/ |
||||
class HomeLoginModel |
||||
{ |
||||
|
||||
public function __construct(private \PDO $pdo) |
||||
{ |
||||
|
||||
} |
||||
|
||||
public function getLogin(string $emailAddress): string |
||||
{ |
||||
try { |
||||
$sqlEmail = "SELECT id, first_name FROM emails WHERE is_active=1 AND email=? LIMIT 1"; |
||||
$stmtEmail = $this->pdo->prepare($sqlEmail); |
||||
$stmtEmail->execute([$emailAddress]); |
||||
$email_row = $stmtEmail->fetch(\PDO::FETCH_ASSOC); |
||||
|
||||
$sqlUser = "SELECT pwd, access_level FROM users WHERE email_id=? LIMIT 1"; |
||||
$stmtUser = $this->pdo->prepare($sqlEmail); |
||||
$stmtUser->execute([$emailAddress]); |
||||
$user_row = $stmtUser->fetch(\PDO::FETCH_ASSOC); |
||||
|
||||
$accessLevel = $user_row['access_level'] ?? 0; |
||||
$_SESSION['accessLevel'] = $accessLevel; |
||||
|
||||
$name = $email_row['first_name'] ?? ""; |
||||
$_SESSION['first_name'] = $name; |
||||
|
||||
return $user_row['pwd']; |
||||
} catch (\PDOException $e) { |
||||
echo $e->getMessage(); |
||||
} |
||||
return ""; |
||||
} |
||||
} |
||||
@ -0,0 +1,28 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
/** |
||||
* @author Robert Strutts |
||||
* @copyright (c) 2026, Robert Strutts |
||||
* @license MIT |
||||
*/ |
||||
|
||||
?> |
||||
<form method="POST"> |
||||
<input type="hidden" name="token" value="<?= $token ?>">
|
||||
<center> |
||||
<fieldset style="width: 300px;"><legend><?= $html->getTitle() ?> - Log In</legend>
|
||||
<table border="0"> |
||||
<tr> |
||||
<th><label for="login">Email:</label></th> |
||||
<td><input type="text" name="login"></td> |
||||
</tr><tr> |
||||
<th><label for="pwd">Password:</label></th> |
||||
<td><input type="password" name="pwd"></td> |
||||
</tr> |
||||
</table> |
||||
<input type="submit" value="Login"> |
||||
</fieldset> |
||||
</center> |
||||
</form> |
||||
@ -0,0 +1,31 @@ |
||||
/* Style the list */ |
||||
ul.breadcrumb { |
||||
padding: 10px 16px; |
||||
list-style: none; |
||||
background-color: #eee; |
||||
} |
||||
|
||||
/* Display list items side by side */ |
||||
ul.breadcrumb li { |
||||
display: inline; |
||||
font-size: 18px; |
||||
} |
||||
|
||||
/* Add a slash symbol (/) before/behind each list item */ |
||||
ul.breadcrumb li+li:before { |
||||
padding: 8px; |
||||
color: black; |
||||
content: "/\00a0"; |
||||
} |
||||
|
||||
/* Add a color to all links inside the list */ |
||||
ul.breadcrumb li a { |
||||
color: #0275d8; |
||||
text-decoration: none; |
||||
} |
||||
|
||||
/* Add a color on mouse-over */ |
||||
ul.breadcrumb li a:hover { |
||||
color: #01447e; |
||||
text-decoration: underline; |
||||
} |
||||
@ -0,0 +1,39 @@ |
||||
button{ |
||||
background:#4CAF50; |
||||
color:#fff; |
||||
border:none; |
||||
padding:10px; |
||||
border-radius:6px; |
||||
cursor:pointer |
||||
} |
||||
button:hover{ |
||||
background:#45a049 |
||||
} |
||||
.btn { |
||||
padding: 12px 24px; |
||||
font-size: 16px; |
||||
border: none; |
||||
border-radius: 6px; |
||||
cursor: pointer; |
||||
transition: all 0.3s ease; |
||||
text-decoration: none; |
||||
color: white; |
||||
} |
||||
|
||||
.login-btn { |
||||
background: #3498db; |
||||
} |
||||
|
||||
.login-btn:hover { |
||||
background: #2980b9; |
||||
transform: translateY(-2px); |
||||
} |
||||
|
||||
.register-btn { |
||||
background: #2ecc71; |
||||
} |
||||
|
||||
.register-btn:hover { |
||||
background: #27ae60; |
||||
transform: translateY(-2px); |
||||
} |
||||
@ -1,44 +1,58 @@ |
||||
body {font-family:Arial;background:#f4f6f9;margin:0} |
||||
.container {max-width:900px;margin:30px auto;background:#fff;padding:20px;border-radius:10px;box-shadow:0 4px 12px rgba(0,0,0,.1)} |
||||
input,textarea{width:100%;padding:10px;margin:8px 0;border-radius:6px;border:1px solid #ccc} |
||||
button{background:#4CAF50;color:#fff;border:none;padding:10px;border-radius:6px;cursor:pointer} |
||||
button:hover{background:#45a049} |
||||
.goal-item{padding:10px;border-bottom:1px solid #eee} |
||||
.advice-box{border:1px solid #ddd;border-radius:8px;padding:15px;margin-top:15px;background:#fafafa} |
||||
.vote{background:#eee;padding:5px 10px;border-radius:6px;display:inline-block} |
||||
.comment{margin-left:20px;border-left:2px solid #ccc;padding-left:8px;margin-top:5px} |
||||
.tag{display:inline-block;background:#3498db;color:#fff;padding:3px 8px;border-radius:5px;margin:2px;font-size:12px;cursor:pointer} |
||||
|
||||
.auth-container { |
||||
display: flex; |
||||
gap: 20px; |
||||
body { |
||||
font-family:Arial; |
||||
background:#f4f6f9; |
||||
margin:0 |
||||
} |
||||
|
||||
.btn { |
||||
padding: 12px 24px; |
||||
font-size: 16px; |
||||
border: none; |
||||
.container { |
||||
max-width:900px; |
||||
margin:30px auto; |
||||
background:#fff; |
||||
padding:20px; |
||||
border-radius:10px; |
||||
box-shadow:0 4px 12px rgba(0,0,0,.1) |
||||
} |
||||
input,textarea{ |
||||
width:100%; |
||||
padding:10px; |
||||
margin:8px 0; |
||||
border-radius:6px; |
||||
cursor: pointer; |
||||
transition: all 0.3s ease; |
||||
text-decoration: none; |
||||
color: white; |
||||
border:1px solid #ccc |
||||
} |
||||
|
||||
.login-btn { |
||||
background: #3498db; |
||||
.goal-item{ |
||||
padding:10px; |
||||
border-bottom:1px solid #eee |
||||
} |
||||
|
||||
.login-btn:hover { |
||||
background: #2980b9; |
||||
transform: translateY(-2px); |
||||
.advice-box{ |
||||
border:1px solid #ddd; |
||||
border-radius:8px; |
||||
padding:15px; |
||||
margin-top:15px; |
||||
background:#fafafa |
||||
} |
||||
|
||||
.register-btn { |
||||
background: #2ecc71; |
||||
.vote{ |
||||
background:#eee; |
||||
padding:5px 10px; |
||||
border-radius:6px; |
||||
display:inline-block |
||||
} |
||||
.comment{ |
||||
margin-left:20px; |
||||
border-left:2px solid #ccc; |
||||
padding-left:8px; |
||||
margin-top:5px |
||||
} |
||||
.tag{ |
||||
display:inline-block; |
||||
background:#3498db; |
||||
color:#fff; |
||||
padding:3px 8px; |
||||
border-radius:5px; |
||||
margin:2px; |
||||
font-size:12px; |
||||
cursor:pointer |
||||
} |
||||
|
||||
.register-btn:hover { |
||||
background: #27ae60; |
||||
transform: translateY(-2px); |
||||
.auth-container { |
||||
display: flex; |
||||
gap: 20px; |
||||
} |
||||
@ -0,0 +1,24 @@ |
||||
body { |
||||
font-family: Arial; |
||||
background:#f5f5f5; |
||||
} |
||||
.container { |
||||
width: 230px; |
||||
margin: 50px auto; |
||||
padding: 20px; |
||||
background: white; |
||||
border-radius: 8px; |
||||
} |
||||
input, button { |
||||
margin: 8px 0; |
||||
padding: 10px; |
||||
} |
||||
.hidden { |
||||
display:none; |
||||
} |
||||
.error { |
||||
color: red; |
||||
} |
||||
.mysuccess { |
||||
color: green; |
||||
} |
||||
@ -0,0 +1,43 @@ |
||||
document.getElementById("myForm").addEventListener('submit', async function (e) { |
||||
e.preventDefault(); |
||||
|
||||
const formData = new FormData(e.target); |
||||
|
||||
/* Log all form data |
||||
for (let [key, value] of formData.entries()) { |
||||
console.log(key + ': ' + value); |
||||
} |
||||
*/ |
||||
|
||||
const formObject = Object.fromEntries(formData.entries()); |
||||
// console.log('Form object:', formObject);
|
||||
|
||||
try { |
||||
const response = await fetch('/Data/RegPost/Save.html', { |
||||
method: 'POST', |
||||
headers: {"Content-Type": "application/json"}, |
||||
body: JSON.stringify(formObject) |
||||
}); |
||||
|
||||
const result = await response.json(); |
||||
|
||||
// Multiple ways to check success
|
||||
if (response.status === 200 && result.success === true) { |
||||
console.log('Success:', result); |
||||
document.getElementById("success").classList.remove("hidden"); |
||||
document.getElementById("errors").textContent = ""; |
||||
document.getElementById("reg").disabled = true; |
||||
|
||||
//} else if (result.success) {
|
||||
// console.log('Success:', result);
|
||||
// } else if (result.error === false) {
|
||||
// console.log('Success:', result);
|
||||
} else { |
||||
document.getElementById("errors").textContent = result.errors; |
||||
console.error('Failed:', result); |
||||
} |
||||
} catch (error) { |
||||
document.getElementById("errors").textContent = error; |
||||
console.error('Error:', error); |
||||
} |
||||
}); |
||||
Loading…
Reference in new issue