fix aws
This commit is contained in:
264
webapp/login.php
264
webapp/login.php
@@ -1,9 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* Geofeed Manager Login Page
|
||||
* Simplified for Cloudflare Access authentication
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/config.php';
|
||||
require_once __DIR__ . '/includes/auth.php';
|
||||
|
||||
$error = '';
|
||||
$success = '';
|
||||
@@ -11,36 +13,50 @@ $success = '';
|
||||
// Handle logout
|
||||
if (isset($_GET['logout'])) {
|
||||
logoutUser();
|
||||
header('Location: login.php');
|
||||
header('Location: login.php?logged_out=1');
|
||||
exit;
|
||||
}
|
||||
|
||||
// Already authenticated? Redirect to main page
|
||||
if (isAuthenticated()) {
|
||||
header('Location: index.php');
|
||||
exit;
|
||||
// Check for logout success message
|
||||
if (isset($_GET['logged_out'])) {
|
||||
$success = 'You have been logged out successfully.';
|
||||
}
|
||||
|
||||
// Handle login form submission
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$username = trim($_POST['username'] ?? '');
|
||||
$password = $_POST['password'] ?? '';
|
||||
// Check for unauthorized error
|
||||
if (isset($_GET['error']) && $_GET['error'] === 'unauthorized') {
|
||||
$error = 'You do not have permission to access that page.';
|
||||
}
|
||||
|
||||
// Get Cloudflare Access user info
|
||||
$cfUser = getCurrentUser();
|
||||
|
||||
// Handle session login (when user clicks "Continue" button)
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'login') {
|
||||
// Validate CSRF
|
||||
if (!validateCSRFToken($_POST['csrf_token'] ?? '')) {
|
||||
$error = 'Invalid security token. Please try again.';
|
||||
} elseif (empty($username) || empty($password)) {
|
||||
$error = 'Please enter both username and password.';
|
||||
} elseif (authenticateUser($username, $password)) {
|
||||
} elseif ($cfUser) {
|
||||
// Start session with Cloudflare Access user
|
||||
if (session_status() === PHP_SESSION_NONE) {
|
||||
session_start();
|
||||
}
|
||||
$_SESSION['authenticated'] = true;
|
||||
$_SESSION['user'] = $cfUser['email'];
|
||||
$_SESSION['login_time'] = time();
|
||||
|
||||
header('Location: index.php');
|
||||
exit;
|
||||
} else {
|
||||
$error = 'Invalid username or password.';
|
||||
// Add small delay to prevent brute force
|
||||
usleep(500000);
|
||||
$error = 'Unable to authenticate. Please ensure you are signed in via Cloudflare Access.';
|
||||
}
|
||||
}
|
||||
|
||||
// If already authenticated via session, redirect to main page
|
||||
if (isAuthenticated()) {
|
||||
header('Location: index.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$csrfToken = generateCSRFToken();
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
@@ -88,6 +104,8 @@ $csrfToken = generateCSRFToken();
|
||||
--error-bg: rgba(220, 53, 69, 0.1);
|
||||
--success: #28a745;
|
||||
--success-bg: rgba(40, 167, 69, 0.1);
|
||||
--warning: #ffc107;
|
||||
--warning-bg: rgba(255, 193, 7, 0.1);
|
||||
|
||||
--transition: all 0.2s ease;
|
||||
|
||||
@@ -119,6 +137,7 @@ $csrfToken = generateCSRFToken();
|
||||
|
||||
--error-bg: rgba(220, 53, 69, 0.2);
|
||||
--success-bg: rgba(40, 167, 69, 0.2);
|
||||
--warning-bg: rgba(255, 193, 7, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,46 +223,77 @@ $csrfToken = generateCSRFToken();
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.login-form {
|
||||
.login-body {
|
||||
padding: 32px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
.user-info {
|
||||
text-align: center;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
display: block;
|
||||
font-size: 13px;
|
||||
.user-avatar {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
background: var(--purple-lighter);
|
||||
color: var(--purple-primary);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: var(--text-secondary);
|
||||
margin-bottom: 8px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.03em;
|
||||
margin: 0 auto 16px;
|
||||
}
|
||||
|
||||
.form-input {
|
||||
width: 100%;
|
||||
padding: 14px 16px;
|
||||
.user-email {
|
||||
font-size: 16px;
|
||||
font-family: inherit;
|
||||
background: var(--bg-tertiary);
|
||||
border: 2px solid var(--border);
|
||||
border-radius: var(--radius-md);
|
||||
font-weight: 500;
|
||||
color: var(--text-primary);
|
||||
transition: var(--transition);
|
||||
outline: none;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.form-input:focus {
|
||||
border-color: var(--purple-primary);
|
||||
box-shadow: 0 0 0 4px rgba(107, 45, 123, 0.1);
|
||||
.user-role {
|
||||
font-size: 13px;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.form-input::placeholder {
|
||||
.user-role .badge {
|
||||
display: inline-block;
|
||||
padding: 4px 10px;
|
||||
border-radius: 20px;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.badge-admin {
|
||||
background: var(--purple-lighter);
|
||||
color: var(--purple-primary);
|
||||
}
|
||||
|
||||
.badge-staff {
|
||||
background: rgba(59, 130, 246, 0.15);
|
||||
color: #3b82f6;
|
||||
}
|
||||
|
||||
.auth-method {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
margin-top: 12px;
|
||||
font-size: 12px;
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
|
||||
.auth-method svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
color: #f48120;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
@@ -260,6 +310,7 @@ $csrfToken = generateCSRFToken();
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.btn:active {
|
||||
@@ -305,6 +356,18 @@ $csrfToken = generateCSRFToken();
|
||||
border: 1px solid rgba(40, 167, 69, 0.3);
|
||||
}
|
||||
|
||||
.alert-warning {
|
||||
background: var(--warning-bg);
|
||||
color: #856404;
|
||||
border: 1px solid rgba(255, 193, 7, 0.3);
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.alert-warning {
|
||||
color: #ffc107;
|
||||
}
|
||||
}
|
||||
|
||||
.alert-icon {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
@@ -325,28 +388,22 @@ $csrfToken = generateCSRFToken();
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* Loading spinner */
|
||||
.spinner {
|
||||
display: none;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border: 2px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 50%;
|
||||
border-top-color: white;
|
||||
animation: spin 0.8s linear infinite;
|
||||
margin-right: 8px;
|
||||
.no-user-message {
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
background: var(--bg-tertiary);
|
||||
border-radius: var(--radius-md);
|
||||
}
|
||||
|
||||
.btn.loading .spinner {
|
||||
display: inline-block;
|
||||
.no-user-message h3 {
|
||||
font-size: 16px;
|
||||
margin-bottom: 8px;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.btn.loading .btn-text {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to { transform: rotate(360deg); }
|
||||
.no-user-message p {
|
||||
font-size: 14px;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
/* Shake animation for errors */
|
||||
@@ -377,9 +434,7 @@ $csrfToken = generateCSRFToken();
|
||||
<p class="login-subtitle">Sign in to manage your geofeed entries</p>
|
||||
</div>
|
||||
|
||||
<form class="login-form" method="POST" action="login.php" id="loginForm">
|
||||
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($csrfToken) ?>">
|
||||
|
||||
<div class="login-body">
|
||||
<?php if ($error): ?>
|
||||
<div class="alert alert-error shake">
|
||||
<svg class="alert-icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
@@ -391,44 +446,75 @@ $csrfToken = generateCSRFToken();
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="username">Username</label>
|
||||
<input type="text" id="username" name="username" class="form-input" placeholder="Enter your username" required autocomplete="username" autofocus>
|
||||
<?php if ($success): ?>
|
||||
<div class="alert alert-success">
|
||||
<svg class="alert-icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/>
|
||||
<polyline points="22 4 12 14.01 9 11.01"/>
|
||||
</svg>
|
||||
<span><?= htmlspecialchars($success) ?></span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="password">Password</label>
|
||||
<input type="password" id="password" name="password" class="form-input" placeholder="Enter your password" required autocomplete="current-password">
|
||||
</div>
|
||||
<?php if ($cfUser): ?>
|
||||
<!-- Cloudflare Access user detected -->
|
||||
<div class="user-info">
|
||||
<?php
|
||||
$email = $cfUser['email'];
|
||||
$namePart = explode('@', $email)[0];
|
||||
$initials = strtoupper(substr($namePart, 0, 2));
|
||||
$role = $cfUser['role'];
|
||||
?>
|
||||
<div class="user-avatar"><?= htmlspecialchars($initials) ?></div>
|
||||
<div class="user-email"><?= htmlspecialchars($email) ?></div>
|
||||
<div class="user-role">
|
||||
<span class="badge <?= $role === 'admin' ? 'badge-admin' : 'badge-staff' ?>">
|
||||
<?= $role === 'admin' ? 'Administrator' : 'Staff' ?>
|
||||
</span>
|
||||
</div>
|
||||
<div class="auth-method">
|
||||
<svg viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M16.5 7.5h-9v9h9v-9z"/>
|
||||
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/>
|
||||
</svg>
|
||||
Authenticated via Cloudflare Access
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary" id="submitBtn">
|
||||
<span class="spinner"></span>
|
||||
<span class="btn-text">Sign In</span>
|
||||
</button>
|
||||
</form>
|
||||
<form method="POST" action="login.php">
|
||||
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($csrfToken) ?>">
|
||||
<input type="hidden" name="action" value="login">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4"/>
|
||||
<polyline points="10 17 15 12 10 7"/>
|
||||
<line x1="15" y1="12" x2="3" y2="12"/>
|
||||
</svg>
|
||||
Continue to Dashboard
|
||||
</button>
|
||||
</form>
|
||||
<?php else: ?>
|
||||
<!-- No Cloudflare Access user detected -->
|
||||
<div class="alert alert-warning">
|
||||
<svg class="alert-icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/>
|
||||
<line x1="12" y1="9" x2="12" y2="13"/>
|
||||
<line x1="12" y1="17" x2="12.01" y2="17"/>
|
||||
</svg>
|
||||
<span>Cloudflare Access authentication required</span>
|
||||
</div>
|
||||
|
||||
<div class="no-user-message">
|
||||
<h3>Authentication Required</h3>
|
||||
<p>Please sign in through Cloudflare Access to continue. If you're seeing this message after authenticating, please contact your administrator.</p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="login-footer">
|
||||
<p>Powered by <a href="https://purplecomputing.com" target="_blank" rel="noopener">Purple Computing</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Add loading state on form submit
|
||||
document.getElementById('loginForm').addEventListener('submit', function(e) {
|
||||
const btn = document.getElementById('submitBtn');
|
||||
btn.classList.add('loading');
|
||||
btn.disabled = true;
|
||||
});
|
||||
|
||||
// Focus first empty field
|
||||
const usernameField = document.getElementById('username');
|
||||
const passwordField = document.getElementById('password');
|
||||
if (usernameField.value) {
|
||||
passwordField.focus();
|
||||
} else {
|
||||
usernameField.focus();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user