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

This commit is contained in:
Ruben Solvang 2026-02-01 20:12:41 +01:00
commit 093dfb9d0a
5 changed files with 54 additions and 32 deletions

View file

@ -9,3 +9,5 @@ services:
- ./custom:/var/www/custom:z - ./custom:/var/www/custom:z
ports: ports:
- "4040:80" - "4040:80"
command: >
bash -c "chown -R www-data:www-data /var/www/custom/data && apache2-foreground"

View file

@ -266,8 +266,14 @@ function sendEmail(string $to, string $toName, string $subject, string $body): a
$fromEmail = $config['petition']['from_email'] ?? $config['from_email']; $fromEmail = $config['petition']['from_email'] ?? $config['from_email'];
$fromName = $config['petition']['from_name'] ?? $config['from_name']; $fromName = $config['petition']['from_name'] ?? $config['from_name'];
// Get petition-specific SMTP settings (allows separate SMTP account for better deliverability)
$smtpHost = $config['petition']['host'] ?? $config['host'];
$smtpPort = $config['petition']['port'] ?? $config['port'];
$smtpUser = $config['petition']['username'] ?? $config['username'];
$smtpPass = $config['petition']['password'] ?? $config['password'];
// Pre-flight check // Pre-flight check
$fp = @fsockopen($config['host'], $config['port'], $errno, $errstr, 10); $fp = @fsockopen($smtpHost, $smtpPort, $errno, $errstr, 10);
if (!$fp) { if (!$fp) {
return ['success' => false, 'error' => "Tilkobling feilet: {$errno} - {$errstr}"]; return ['success' => false, 'error' => "Tilkobling feilet: {$errno} - {$errstr}"];
} }
@ -278,10 +284,10 @@ function sendEmail(string $to, string $toName, string $subject, string $body): a
$mail = new \codeworxtech\PHPMailerLite\PHPMailerLite(); $mail = new \codeworxtech\PHPMailerLite\PHPMailerLite();
$mail->SetSMTPhost($config['host']); $mail->SetSMTPhost($smtpHost);
$mail->SetSMTPport($config['port']); $mail->SetSMTPport($smtpPort);
$mail->SetSMTPuser($config['username']); $mail->SetSMTPuser($smtpUser);
$mail->SetSMTPpass($config['password']); $mail->SetSMTPpass($smtpPass);
$mail->SetSender([$fromEmail => $fromName]); $mail->SetSender([$fromEmail => $fromName]);
$mail->AddRecipient([$to => $toName]); $mail->AddRecipient([$to => $toName]);

View file

@ -713,11 +713,17 @@ function petitionSendConfirmationEmailInternal(array $data, string $confirmUrl,
$subject = petitionT($ctx, 'petition', 'email_subject'); $subject = petitionT($ctx, 'petition', 'email_subject');
// Get petition-specific SMTP settings (allows separate SMTP account for better deliverability)
$smtpHost = $config['petition']['host'] ?? $config['host'];
$smtpPort = $config['petition']['port'] ?? $config['port'];
$smtpUser = $config['petition']['username'] ?? $config['username'];
$smtpPass = $config['petition']['password'] ?? $config['password'];
// Pre-flight check // Pre-flight check
$fp = @fsockopen($config['host'], $config['port'], $errno, $errstr, 10); $fp = @fsockopen($smtpHost, $smtpPort, $errno, $errstr, 10);
if (!$fp) { if (!$fp) {
$errorMessage = "Connection failed: {$errno} - {$errstr}"; $errorMessage = "Connection failed: {$errno} - {$errstr}";
error_log("Petition SMTP pre-flight failed: {$config['host']}:{$config['port']} - {$errno} - {$errstr}"); error_log("Petition SMTP pre-flight failed: {$smtpHost}:{$smtpPort} - {$errno} - {$errstr}");
return false; return false;
} }
fclose($fp); fclose($fp);
@ -727,10 +733,10 @@ function petitionSendConfirmationEmailInternal(array $data, string $confirmUrl,
$mail = new \codeworxtech\PHPMailerLite\PHPMailerLite(); $mail = new \codeworxtech\PHPMailerLite\PHPMailerLite();
$mail->SetSMTPhost($config['host']); $mail->SetSMTPhost($smtpHost);
$mail->SetSMTPport($config['port']); $mail->SetSMTPport($smtpPort);
$mail->SetSMTPuser($config['username']); $mail->SetSMTPuser($smtpUser);
$mail->SetSMTPpass($config['password']); $mail->SetSMTPpass($smtpPass);
$recipientName = $data['firstname'] . ' ' . $data['surname']; $recipientName = $data['firstname'] . ' ' . $data['surname'];
$mail->SetSender([$fromEmail => $fromName]); $mail->SetSender([$fromEmail => $fromName]);
@ -859,11 +865,17 @@ function petitionSendThankYouEmailInternal(string $token, string $deleteUrl, str
$subject = petitionT($ctx, 'petition', 'email_thankyou_subject'); $subject = petitionT($ctx, 'petition', 'email_thankyou_subject');
// Get petition-specific SMTP settings (allows separate SMTP account for better deliverability)
$smtpHost = $config['petition']['host'] ?? $config['host'];
$smtpPort = $config['petition']['port'] ?? $config['port'];
$smtpUser = $config['petition']['username'] ?? $config['username'];
$smtpPass = $config['petition']['password'] ?? $config['password'];
// Pre-flight check // Pre-flight check
$fp = @fsockopen($config['host'], $config['port'], $errno, $errstr, 10); $fp = @fsockopen($smtpHost, $smtpPort, $errno, $errstr, 10);
if (!$fp) { if (!$fp) {
$errorMessage = "Connection failed: {$errno} - {$errstr}"; $errorMessage = "Connection failed: {$errno} - {$errstr}";
error_log("Petition SMTP pre-flight failed: {$config['host']}:{$config['port']} - {$errno} - {$errstr}"); error_log("Petition SMTP pre-flight failed: {$smtpHost}:{$smtpPort} - {$errno} - {$errstr}");
return false; return false;
} }
fclose($fp); fclose($fp);
@ -873,10 +885,10 @@ function petitionSendThankYouEmailInternal(string $token, string $deleteUrl, str
$mail = new \codeworxtech\PHPMailerLite\PHPMailerLite(); $mail = new \codeworxtech\PHPMailerLite\PHPMailerLite();
$mail->SetSMTPhost($config['host']); $mail->SetSMTPhost($smtpHost);
$mail->SetSMTPport($config['port']); $mail->SetSMTPport($smtpPort);
$mail->SetSMTPuser($config['username']); $mail->SetSMTPuser($smtpUser);
$mail->SetSMTPpass($config['password']); $mail->SetSMTPpass($smtpPass);
$recipientName = $signature['firstname'] . ' ' . $signature['surname']; $recipientName = $signature['firstname'] . ' ' . $signature['surname'];
$mail->SetSender([$fromEmail => $fromName]); $mail->SetSender([$fromEmail => $fromName]);

View file

@ -17,9 +17,18 @@ return [
'to_email' => 'email@example.com', 'to_email' => 'email@example.com',
'to_name' => 'Stopp Lidelsen', 'to_name' => 'Stopp Lidelsen',
// Petition-specific overrides (optional) // Petition-specific settings (optional)
// If not set, the default values above will be used // If not set, the default values above will be used
//
// IMPORTANT: For better email deliverability, use a separate SMTP account
// for petitions where the from_email matches the SMTP username.
// This ensures SPF/DKIM/DMARC checks pass.
'petition' => [ 'petition' => [
// Separate SMTP account (recommended for deliverability)
// 'host' => 'smtp.example.com',
// 'port' => 587,
// 'username' => 'underskrifter@example.com',
// 'password' => 'petition-smtp-password',
// 'from_email' => 'underskrifter@example.com', // 'from_email' => 'underskrifter@example.com',
// 'from_name' => 'Underskriftskampanje', // 'from_name' => 'Underskriftskampanje',
], ],

View file

@ -709,18 +709,15 @@ class PHPMailerLite
} }
$tld = substr($url, strpos($url, ".") + 1); $tld = substr($url, strpos($url, ".") + 1);
if ($validate === "is_valid") { if ($validate === "is_valid") {
$url = $tld; // Just check if the SMTP host is reachable via DNS (A record)
// The original check compared SMTP host to MX records which breaks
// third-party SMTP services like Mailgun, SendGrid, etc.
return checkdnsrr($url, 'A') || checkdnsrr($url, 'AAAA');
} }
if (preg_match('/(?P<domain>[a-z0-9][a-z0-9\-]{1,63}\.[a-z\.]{2,6})$/i', $tld, $match)) { if (preg_match('/(?P<domain>[a-z0-9][a-z0-9\-]{1,63}\.[a-z\.]{2,6})$/i', $tld, $match)) {
getmxrr($match['domain'], $mx_details); getmxrr($match['domain'], $mx_details);
if (is_array($mx_details) && count($mx_details) > 0) { if (is_array($mx_details) && count($mx_details) > 0) {
if ($validate === "is_valid") { return reset($mx_details);
if ($url == reset($mx_details)) {
return true;
}
} else {
return reset($mx_details);
}
} }
} }
return false; return false;
@ -961,12 +958,8 @@ class PHPMailerLite
$rz = false; $rz = false;
} }
if ($rz) { if ($rz) {
$rz = false; // Check DNS records instead of port 80 (mail-only subdomains don't have web servers)
$check = @fsockopen($domn, 80, $errno, $errstr, 1); $rz = (checkdnsrr($domn, 'MX') || checkdnsrr($domn, 'A'));
if ($check) {
$rz = true;
@fclose($check);
}
} }
if ($rz) { if ($rz) {
$rz = (bool) preg_match('/^(?!(?:(?:\x22?\x5C[\x00-\x7E]\x22?)|(?:\x22?[^\x5C\x22]\x22?)){255,})(?!(?:(?:\x22?\x5C[\x00-\x7E]\x22?)|(?:\x22?[^\x5C\x22]\x22?)){65,}@)(?:(?:[\x21\x23-\x27\x2A\x2B\x2D\x2F-\x39\x3D\x3F\x5E-\x7E]+)|(?:\x22(?:[\x01-\x08\x0B\x0C\x0E-\x1F\x21\x23-\x5B\x5D-\x7F]|(?:\x5C[\x00-\x7F]))*\x22))(?:\.(?:(?:[\x21\x23-\x27\x2A\x2B\x2D\x2F-\x39\x3D\x3F\x5E-\x7E]+)|(?:\x22(?:[\x01-\x08\x0B\x0C\x0E-\x1F\x21\x23-\x5B\x5D-\x7F]|(?:\x5C[\x00-\x7F]))*\x22)))*@(?:(?:(?!.*[^.]{64,})(?:(?:(?:xn--)?[a-z0-9]+(?:-[a-z0-9]+)*\.){1,126}){1,}(?:(?:[a-z][a-z0-9]*)|(?:(?:xn--)[a-z0-9]+))(?:-[a-z0-9]+)*)|(?:\[(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){7})|(?:(?!(?:.*[a-f0-9][:\]]){7,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?)))|(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){5}:)|(?:(?!(?:.*[a-f0-9]:){5,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3}:)?)))?(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))(?:\.(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))){3}))\]))$/iD', $email); $rz = (bool) preg_match('/^(?!(?:(?:\x22?\x5C[\x00-\x7E]\x22?)|(?:\x22?[^\x5C\x22]\x22?)){255,})(?!(?:(?:\x22?\x5C[\x00-\x7E]\x22?)|(?:\x22?[^\x5C\x22]\x22?)){65,}@)(?:(?:[\x21\x23-\x27\x2A\x2B\x2D\x2F-\x39\x3D\x3F\x5E-\x7E]+)|(?:\x22(?:[\x01-\x08\x0B\x0C\x0E-\x1F\x21\x23-\x5B\x5D-\x7F]|(?:\x5C[\x00-\x7F]))*\x22))(?:\.(?:(?:[\x21\x23-\x27\x2A\x2B\x2D\x2F-\x39\x3D\x3F\x5E-\x7E]+)|(?:\x22(?:[\x01-\x08\x0B\x0C\x0E-\x1F\x21\x23-\x5B\x5D-\x7F]|(?:\x5C[\x00-\x7F]))*\x22)))*@(?:(?:(?!.*[^.]{64,})(?:(?:(?:xn--)?[a-z0-9]+(?:-[a-z0-9]+)*\.){1,126}){1,}(?:(?:[a-z][a-z0-9]*)|(?:(?:xn--)[a-z0-9]+))(?:-[a-z0-9]+)*)|(?:\[(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){7})|(?:(?!(?:.*[a-f0-9][:\]]){7,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?)))|(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){5}:)|(?:(?!(?:.*[a-f0-9]:){5,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3}:)?)))?(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))(?:\.(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))){3}))\]))$/iD', $email);