Merge branch 'latest' of forge.dmz.skyfritt.net:stopplidelsen/innhold into latest

This commit is contained in:
Ruben Solvang 2025-11-04 21:39:42 +00:00
commit 9f046a368d
4 changed files with 126 additions and 92 deletions

View file

@ -5,10 +5,25 @@ $formSuccess = false;
$formErrors = [];
$formData = ['name' => '', 'email' => '', 'message' => ''];
// Start session for CSRF token and rate limiting
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
// Generate CSRF token if not exists
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
// Process form submission
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['contact_form_submit'])) {
$formSubmitted = true;
// Security: CSRF Token Validation
if (!isset($_POST['csrf_token']) || !hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) {
$formErrors[] = 'Ugyldig sikkerhetskode. Vennligst prøv igjen.';
}
// Spam Prevention 1: Honeypot field (should be empty)
if (!empty($_POST['website'])) {
$formErrors[] = 'Spam detected.';
@ -32,10 +47,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['contact_form_submit']
}
// Spam Prevention 4: Rate limiting (session-based)
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
$lastSubmitTime = isset($_SESSION['last_contact_submit']) ? $_SESSION['last_contact_submit'] : 0;
if (time() - $lastSubmitTime < 60) {
$formErrors[] = 'Vennligst vent litt før du sender inn igjen.';
@ -208,11 +219,14 @@ $currentTime = time();
<?php if (!$formSuccess): ?>
<form method="post" action="<?= htmlspecialchars($_SERVER['REQUEST_URI']) ?>" class="contact-form-inner">
<!-- Honeypot field (hidden from users, bots will fill it) -->
<div style="position: absolute; left: -5000px;" aria-hidden="true">
<div class="hp-field" aria-hidden="true">
<label for="website">Website</label>
<input type="text" id="website" name="website" tabindex="-1" autocomplete="off">
</div>
<!-- CSRF Token -->
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token']) ?>">
<!-- Time-based token -->
<input type="hidden" name="form_start_time" value="<?= $currentTime ?>">

View file

@ -0,0 +1,97 @@
/* Contact Form Styles */
/* Honeypot field - hidden from users but looks normal to bots */
.hp-field {
position: absolute;
left: -5000px;
}
/* Contact form section */
.contact-form {
margin-top: 2rem;
margin-bottom: 2rem;
}
/* Success message */
.form-success {
background-color: #d4edda;
border: 1px solid #c3e6cb;
color: #155724;
padding: 1rem;
border-radius: 0.25rem;
margin-bottom: 1rem;
}
/* Error messages */
.form-errors {
background-color: #f8d7da;
border: 1px solid #f5c6cb;
color: #721c24;
padding: 1rem;
border-radius: 0.25rem;
margin-bottom: 1rem;
}
.form-errors ul {
margin: 0.5rem 0 0 0;
padding-left: 1.5rem;
}
/* Form fields */
.contact-form-inner .form-group {
margin-bottom: 1.3rem;
}
.contact-form-inner .form-group label {
display: block;
font-weight: 600;
margin-bottom: 0.3rem;
color: var(--color-grey);
}
.contact-form-inner .form-group label .required {
color: #dc3545;
}
.contact-form-inner .form-group input[type="text"],
.contact-form-inner .form-group input[type="email"],
.contact-form-inner .form-group textarea {
width: 100%;
padding: 0.6rem;
border: 1px solid #ccc;
border-radius: 0.25rem;
font-family: inherit;
font-size: 1rem;
box-sizing: border-box;
}
.contact-form-inner .form-group input[type="text"]:focus,
.contact-form-inner .form-group input[type="email"]:focus,
.contact-form-inner .form-group textarea:focus {
outline: none;
border-color: var(--color-green);
box-shadow: 0 0 0 0.2rem rgba(0, 156, 128, 0.25);
}
.contact-form-inner .form-group textarea {
resize: vertical;
min-height: 150px;
}
.contact-form-inner .form-group small {
display: block;
margin-top: 0.3rem;
color: #6c757d;
font-size: 0.875rem;
}
.contact-form-inner .form-group button[type="submit"] {
cursor: pointer;
border: none;
font-size: 1rem;
font-family: inherit;
}
.contact-form-inner .form-group button[type="submit"]:hover {
cursor: pointer;
}

10
custom/.htaccess Normal file
View file

@ -0,0 +1,10 @@
# Deny access to all files in custom directory
# Only allow access through PHP includes
<Files "*">
Require all denied
</Files>
# Allow access to CSS and font files
<FilesMatch "\.(css|woff|woff2|ttf|eot|svg)$">
Require all granted
</FilesMatch>

View file

@ -185,93 +185,6 @@ main {
/* FOOTER */
/* CONTACT FORM */
.contact-form {
margin-top: 2rem;
margin-bottom: 2rem;
.form-success {
background-color: #d4edda;
border: 1px solid #c3e6cb;
color: #155724;
padding: 1rem;
border-radius: 0.25rem;
margin-bottom: 1rem;
}
.form-errors {
background-color: #f8d7da;
border: 1px solid #f5c6cb;
color: #721c24;
padding: 1rem;
border-radius: 0.25rem;
margin-bottom: 1rem;
ul {
margin: 0.5rem 0 0 0;
padding-left: 1.5rem;
}
}
.contact-form-inner {
.form-group {
margin-bottom: 1.3rem;
label {
display: block;
font-weight: 600;
margin-bottom: 0.3rem;
color: var(--color-grey);
.required {
color: #dc3545;
}
}
input[type="text"],
input[type="email"],
textarea {
width: 100%;
padding: 0.6rem;
border: 1px solid #ccc;
border-radius: 0.25rem;
font-family: inherit;
font-size: 1rem;
box-sizing: border-box;
&:focus {
outline: none;
border-color: var(--color-green);
box-shadow: 0 0 0 0.2rem rgba(0, 156, 128, 0.25);
}
}
textarea {
resize: vertical;
min-height: 150px;
}
small {
display: block;
margin-top: 0.3rem;
color: #6c757d;
font-size: 0.875rem;
}
button[type="submit"] {
cursor: pointer;
border: none;
font-size: 1rem;
font-family: inherit;
&:hover {
cursor: pointer;
}
}
}
}
}
footer {
color: var(--color-green-light);
a {