adasd
This commit is contained in:
@@ -144,6 +144,16 @@ body {
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.login-honeypot {
|
||||
position: absolute;
|
||||
left: -9999px;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
overflow: hidden;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.login-form-grid {
|
||||
display: grid;
|
||||
gap: 14px;
|
||||
@@ -175,6 +185,31 @@ body {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.login-password-row {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.login-password-row input {
|
||||
padding-right: 56px;
|
||||
}
|
||||
|
||||
.login-password-toggle {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 10px;
|
||||
transform: translateY(-50%);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border: 0;
|
||||
border-radius: 999px;
|
||||
background: transparent;
|
||||
color: rgba(15, 23, 42, 0.56);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.login-field textarea {
|
||||
min-height: 120px;
|
||||
resize: vertical;
|
||||
|
||||
18
public/assets/auth/password-visibility.js
Normal file
18
public/assets/auth/password-visibility.js
Normal file
@@ -0,0 +1,18 @@
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const rows = document.querySelectorAll('.login-password-row');
|
||||
|
||||
rows.forEach((row) => {
|
||||
const input = row.querySelector('[data-password-field]');
|
||||
const toggle = row.querySelector('[data-password-toggle]');
|
||||
|
||||
if (!(input instanceof HTMLInputElement) || !(toggle instanceof HTMLButtonElement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
toggle.addEventListener('click', () => {
|
||||
const isHidden = input.type === 'password';
|
||||
input.type = isHidden ? 'text' : 'password';
|
||||
toggle.setAttribute('aria-label', isHidden ? 'Passwort verbergen' : 'Passwort anzeigen');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -5,23 +5,49 @@ declare(strict_types=1);
|
||||
require_once dirname(__DIR__, 3) . '/src/App/bootstrap.php';
|
||||
|
||||
use App\ConfigLoader;
|
||||
use App\PublicFormProtection;
|
||||
use App\RegistrationService;
|
||||
|
||||
session_start();
|
||||
|
||||
$projectRoot = dirname(__DIR__, 3);
|
||||
$registration = new RegistrationService($projectRoot, ConfigLoader::load($projectRoot, 'registration'));
|
||||
$registrationConfig = ConfigLoader::load($projectRoot, 'registration');
|
||||
$registration = new RegistrationService($projectRoot, $registrationConfig);
|
||||
$formProtection = new PublicFormProtection($projectRoot, $registrationConfig);
|
||||
$message = null;
|
||||
$error = null;
|
||||
$username = '';
|
||||
$csrfToken = (string) ($_SESSION['forgot_password_form_token'] ?? '');
|
||||
$honeypotField = $formProtection->honeypotField();
|
||||
|
||||
if ($csrfToken === '') {
|
||||
$csrfToken = bin2hex(random_bytes(16));
|
||||
$_SESSION['forgot_password_form_token'] = $csrfToken;
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$username = trim((string) ($_POST['username'] ?? ''));
|
||||
$origin = ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http') . '://' . ($_SERVER['HTTP_HOST'] ?? 'localhost');
|
||||
$result = $registration->sendPasswordReset($username, $origin);
|
||||
$postedToken = (string) ($_POST['csrf_token'] ?? '');
|
||||
|
||||
if ($result['success'] ?? false) {
|
||||
$message = (string) ($result['message'] ?? '');
|
||||
if ($postedToken === '' || !hash_equals($csrfToken, $postedToken)) {
|
||||
$error = 'Die Formularprüfung ist fehlgeschlagen. Bitte versuche es erneut.';
|
||||
} else {
|
||||
$error = (string) ($result['message'] ?? '');
|
||||
$protection = $formProtection->guard('password_reset', $_POST);
|
||||
|
||||
if (!($protection['success'] ?? false)) {
|
||||
$error = implode(' ', array_map('strval', (array) ($protection['errors'] ?? [])));
|
||||
} else {
|
||||
$origin = ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http') . '://' . ($_SERVER['HTTP_HOST'] ?? 'localhost');
|
||||
$result = $registration->sendPasswordReset($username, $origin);
|
||||
|
||||
if ($result['success'] ?? false) {
|
||||
$message = (string) ($result['message'] ?? '');
|
||||
$csrfToken = bin2hex(random_bytes(16));
|
||||
$_SESSION['forgot_password_form_token'] = $csrfToken;
|
||||
} else {
|
||||
$error = (string) ($result['message'] ?? '');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
?><!DOCTYPE html>
|
||||
@@ -38,7 +64,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
<div class="login-panel-top">
|
||||
<p class="login-kicker">Kusche.Berlin</p>
|
||||
<h1>Passwort vergessen</h1>
|
||||
<p class="login-copy">Gib deinen Benutzernamen an. Wenn der LDAP-Benutzer eine E-Mail-Adresse hat, senden wir einen 8 Stunden gültigen Reset-Link.</p>
|
||||
<p class="login-copy">Gib deinen Benutzernamen an. Wenn für das Konto eine E-Mail-Adresse hinterlegt ist, senden wir einen 8 Stunden gültigen Link zum Zurücksetzen.</p>
|
||||
</div>
|
||||
|
||||
<?php if ($message !== null): ?>
|
||||
@@ -50,6 +76,14 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
<?php endif; ?>
|
||||
|
||||
<form class="login-form" method="post" action="/auth/forgot-password/">
|
||||
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($csrfToken, ENT_QUOTES) ?>">
|
||||
<div class="login-honeypot" aria-hidden="true">
|
||||
<label>
|
||||
<span>Website</span>
|
||||
<input type="text" name="<?= htmlspecialchars($honeypotField, ENT_QUOTES) ?>" value="" tabindex="-1" autocomplete="off">
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<label class="login-field">
|
||||
<span>Benutzername</span>
|
||||
<input type="text" name="username" value="<?= htmlspecialchars($username, ENT_QUOTES) ?>" required>
|
||||
|
||||
@@ -5,12 +5,15 @@ declare(strict_types=1);
|
||||
require_once dirname(__DIR__, 3) . '/src/App/bootstrap.php';
|
||||
|
||||
use App\ConfigLoader;
|
||||
use App\PublicFormProtection;
|
||||
use App\RegistrationService;
|
||||
|
||||
session_start();
|
||||
|
||||
$projectRoot = dirname(__DIR__, 3);
|
||||
$registration = new RegistrationService($projectRoot, ConfigLoader::load($projectRoot, 'registration'));
|
||||
$registrationConfig = ConfigLoader::load($projectRoot, 'registration');
|
||||
$registration = new RegistrationService($projectRoot, $registrationConfig);
|
||||
$formProtection = new PublicFormProtection($projectRoot, $registrationConfig);
|
||||
|
||||
if (!$registration->isEnabled()) {
|
||||
http_response_code(404);
|
||||
@@ -26,11 +29,13 @@ if ($csrfToken === '') {
|
||||
}
|
||||
|
||||
$errors = [];
|
||||
$honeypotField = $formProtection->honeypotField();
|
||||
$form = [
|
||||
'username' => '',
|
||||
'given_name' => '',
|
||||
'family_name' => '',
|
||||
'email' => '',
|
||||
'note' => '',
|
||||
'password' => '',
|
||||
'password_confirm' => '',
|
||||
];
|
||||
@@ -41,6 +46,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
'given_name' => trim((string) ($_POST['given_name'] ?? '')),
|
||||
'family_name' => trim((string) ($_POST['family_name'] ?? '')),
|
||||
'email' => trim((string) ($_POST['email'] ?? '')),
|
||||
'note' => trim((string) ($_POST['note'] ?? '')),
|
||||
'password' => (string) ($_POST['password'] ?? ''),
|
||||
'password_confirm' => (string) ($_POST['password_confirm'] ?? ''),
|
||||
];
|
||||
@@ -50,21 +56,27 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
if ($postedToken === '' || !hash_equals($csrfToken, $postedToken)) {
|
||||
$errors[] = 'Die Formularprüfung ist fehlgeschlagen. Bitte versuche es erneut.';
|
||||
} else {
|
||||
$result = $registration->submit($form);
|
||||
$protection = $formProtection->guard('registration', $_POST);
|
||||
|
||||
if (($result['success'] ?? false) !== true) {
|
||||
$errors = array_values(array_map('strval', (array) ($result['errors'] ?? [])));
|
||||
if (!($protection['success'] ?? false)) {
|
||||
$errors = array_values(array_map('strval', (array) ($protection['errors'] ?? [])));
|
||||
} else {
|
||||
$createdRequest = is_array($result['request'] ?? null) ? $result['request'] : [];
|
||||
$_SESSION['registration_confirmation'] = [
|
||||
'id' => (string) ($createdRequest['id'] ?? ''),
|
||||
'username' => (string) ($createdRequest['username'] ?? ''),
|
||||
'email' => (string) ($createdRequest['email'] ?? ''),
|
||||
];
|
||||
$csrfToken = bin2hex(random_bytes(16));
|
||||
$_SESSION['registration_form_token'] = $csrfToken;
|
||||
header('Location: /auth/register/confirmation/', true, 302);
|
||||
exit;
|
||||
$result = $registration->submit($form);
|
||||
|
||||
if (($result['success'] ?? false) !== true) {
|
||||
$errors = array_values(array_map('strval', (array) ($result['errors'] ?? [])));
|
||||
} else {
|
||||
$createdRequest = is_array($result['request'] ?? null) ? $result['request'] : [];
|
||||
$_SESSION['registration_confirmation'] = [
|
||||
'id' => (string) ($createdRequest['id'] ?? ''),
|
||||
'username' => (string) ($createdRequest['username'] ?? ''),
|
||||
'email' => (string) ($createdRequest['email'] ?? ''),
|
||||
];
|
||||
$csrfToken = bin2hex(random_bytes(16));
|
||||
$_SESSION['registration_form_token'] = $csrfToken;
|
||||
header('Location: /auth/register/confirmation/', true, 302);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -82,7 +94,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
<div class="login-panel-top">
|
||||
<p class="login-kicker">Kusche.Berlin</p>
|
||||
<h1>Registrierung anfragen</h1>
|
||||
<p class="login-copy">Neue Konten werden nicht sofort freigeschaltet. Deine Anfrage wird geprüft und erst danach für LDAP, NAS und Desktop vorbereitet.</p>
|
||||
<p class="login-copy">Erstelle deinen Zugang für den persönlichen Desktop-Bereich von Kusche.Berlin. Nach dem Absenden kannst du alle weiteren Schritte direkt von hier aus verfolgen.</p>
|
||||
</div>
|
||||
|
||||
<?php if ($errors !== []): ?>
|
||||
@@ -98,6 +110,12 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
|
||||
<form class="login-form" method="post" action="/auth/register/">
|
||||
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($csrfToken, ENT_QUOTES) ?>">
|
||||
<div class="login-honeypot" aria-hidden="true">
|
||||
<label>
|
||||
<span>Website</span>
|
||||
<input type="text" name="<?= htmlspecialchars($honeypotField, ENT_QUOTES) ?>" value="" tabindex="-1" autocomplete="off">
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="login-form-grid">
|
||||
<label class="login-field">
|
||||
@@ -124,15 +142,30 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
<div class="login-form-grid">
|
||||
<label class="login-field">
|
||||
<span>Passwort</span>
|
||||
<input type="password" name="password" value="" required>
|
||||
<div class="login-password-row">
|
||||
<input type="password" name="password" value="" required data-password-field>
|
||||
<button class="login-password-toggle" type="button" data-password-toggle aria-label="Passwort anzeigen">
|
||||
<span aria-hidden="true">◉</span>
|
||||
</button>
|
||||
</div>
|
||||
</label>
|
||||
|
||||
<label class="login-field">
|
||||
<span>Passwort wiederholen</span>
|
||||
<input type="password" name="password_confirm" value="" required>
|
||||
<div class="login-password-row">
|
||||
<input type="password" name="password_confirm" value="" required data-password-field>
|
||||
<button class="login-password-toggle" type="button" data-password-toggle aria-label="Passwort anzeigen">
|
||||
<span aria-hidden="true">◉</span>
|
||||
</button>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<label class="login-field">
|
||||
<span>Hinweise für Freischaltung</span>
|
||||
<textarea name="note" rows="4" placeholder="Optional: Zusätzliche Hinweise zu dir oder deinem Zugangswunsch."><?= htmlspecialchars($form['note'], ENT_QUOTES) ?></textarea>
|
||||
</label>
|
||||
|
||||
<div class="login-actions">
|
||||
<button class="login-button login-button-primary" type="submit">Registrierung absenden</button>
|
||||
<a class="login-button login-button-secondary" href="/auth/keycloak">Zurück zum Login</a>
|
||||
@@ -140,5 +173,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
</form>
|
||||
</section>
|
||||
</main>
|
||||
<script src="/assets/auth/password-visibility.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user