Merge branch 'latest' of forge.dmz.skyfritt.net:stopplidelsen/innhold into latest
This commit is contained in:
commit
9f046a368d
4 changed files with 126 additions and 92 deletions
|
|
@ -5,10 +5,25 @@ $formSuccess = false;
|
||||||
$formErrors = [];
|
$formErrors = [];
|
||||||
$formData = ['name' => '', 'email' => '', 'message' => ''];
|
$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
|
// Process form submission
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['contact_form_submit'])) {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['contact_form_submit'])) {
|
||||||
$formSubmitted = true;
|
$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)
|
// Spam Prevention 1: Honeypot field (should be empty)
|
||||||
if (!empty($_POST['website'])) {
|
if (!empty($_POST['website'])) {
|
||||||
$formErrors[] = 'Spam detected.';
|
$formErrors[] = 'Spam detected.';
|
||||||
|
|
@ -32,10 +47,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['contact_form_submit']
|
||||||
}
|
}
|
||||||
|
|
||||||
// Spam Prevention 4: Rate limiting (session-based)
|
// 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;
|
$lastSubmitTime = isset($_SESSION['last_contact_submit']) ? $_SESSION['last_contact_submit'] : 0;
|
||||||
if (time() - $lastSubmitTime < 60) {
|
if (time() - $lastSubmitTime < 60) {
|
||||||
$formErrors[] = 'Vennligst vent litt før du sender inn igjen.';
|
$formErrors[] = 'Vennligst vent litt før du sender inn igjen.';
|
||||||
|
|
@ -208,11 +219,14 @@ $currentTime = time();
|
||||||
<?php if (!$formSuccess): ?>
|
<?php if (!$formSuccess): ?>
|
||||||
<form method="post" action="<?= htmlspecialchars($_SERVER['REQUEST_URI']) ?>" class="contact-form-inner">
|
<form method="post" action="<?= htmlspecialchars($_SERVER['REQUEST_URI']) ?>" class="contact-form-inner">
|
||||||
<!-- Honeypot field (hidden from users, bots will fill it) -->
|
<!-- 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>
|
<label for="website">Website</label>
|
||||||
<input type="text" id="website" name="website" tabindex="-1" autocomplete="off">
|
<input type="text" id="website" name="website" tabindex="-1" autocomplete="off">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- CSRF Token -->
|
||||||
|
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token']) ?>">
|
||||||
|
|
||||||
<!-- Time-based token -->
|
<!-- Time-based token -->
|
||||||
<input type="hidden" name="form_start_time" value="<?= $currentTime ?>">
|
<input type="hidden" name="form_start_time" value="<?= $currentTime ?>">
|
||||||
|
|
||||||
|
|
|
||||||
97
content/kontakt/styles.css
Normal file
97
content/kontakt/styles.css
Normal 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
10
custom/.htaccess
Normal 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>
|
||||||
|
|
@ -185,93 +185,6 @@ main {
|
||||||
|
|
||||||
/* FOOTER */
|
/* 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 {
|
footer {
|
||||||
color: var(--color-green-light);
|
color: var(--color-green-light);
|
||||||
a {
|
a {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue