2023-03-05 15:30:06 +01:00
|
|
|
<?php
|
|
|
|
|
|
|
|
namespace Core\Documents;
|
|
|
|
|
|
|
|
|
|
|
|
use Core\Configuration\Settings;
|
|
|
|
use Core\Elements\Document;
|
|
|
|
use Core\Objects\DatabaseEntity\GpgKey;
|
|
|
|
use Core\Objects\DatabaseEntity\Language;
|
|
|
|
use Core\Objects\Router\Router;
|
2024-03-27 20:50:57 +01:00
|
|
|
use DateTimeInterface;
|
2023-03-05 15:30:06 +01:00
|
|
|
|
|
|
|
// Source: https://www.rfc-editor.org/rfc/rfc9116
|
|
|
|
class Security extends Document {
|
|
|
|
|
|
|
|
public function __construct(Router $router) {
|
|
|
|
parent::__construct($router);
|
|
|
|
$this->searchable = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getTitle(): string {
|
|
|
|
return "security.txt";
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getCode(array $params = []) {
|
|
|
|
|
|
|
|
$activeRoute = $this->router->getActiveRoute();
|
|
|
|
|
|
|
|
$sql = $this->getContext()->getSQL();
|
|
|
|
$settings = $this->getSettings();
|
2024-05-11 16:12:15 +02:00
|
|
|
$gpgKey = $settings->getContactGPGKey();
|
2023-03-05 15:30:06 +01:00
|
|
|
|
|
|
|
if ($activeRoute->getPattern() === "/.well-known/security.txt") {
|
|
|
|
|
|
|
|
// The order in which they appear is not an indication of priority; the listed languages are intended to have equal priority.
|
|
|
|
$languageCodes = implode(", ", array_map(function (Language $language) {
|
|
|
|
return $language->getShortCode();
|
|
|
|
}, Language::findAll($sql)));
|
|
|
|
|
|
|
|
$expires = (new \DateTime())->setTime(0, 0, 0)->modify("+3 months");
|
|
|
|
$baseUrl = $settings->getBaseUrl();
|
2024-05-11 16:12:15 +02:00
|
|
|
// $gpgKey = null;
|
2023-03-05 15:30:06 +01:00
|
|
|
|
|
|
|
$lines = [
|
|
|
|
"# This project is based on the open-source framework hosted on https://github.com/rhergenreder/web-base",
|
2024-03-27 20:50:57 +01:00
|
|
|
"# Any non site-specific issues can be reported via the github security reporting feature:",
|
2023-03-05 15:30:06 +01:00
|
|
|
"# https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing/privately-reporting-a-security-vulnerability",
|
2024-04-22 19:01:04 +02:00
|
|
|
"# or by contacting me directly: mail(at)romanh(dot)de",
|
2023-03-05 15:30:06 +01:00
|
|
|
"",
|
|
|
|
"Canonical: $baseUrl/.well-known/security.txt",
|
|
|
|
"Preferred-Languages: $languageCodes",
|
2024-03-27 20:50:57 +01:00
|
|
|
"Expires: " . $expires->format(DateTimeInterface::ATOM),
|
2023-03-05 15:30:06 +01:00
|
|
|
"",
|
|
|
|
];
|
|
|
|
|
2024-05-11 16:12:15 +02:00
|
|
|
$contactAddress = $settings->getContactMail();
|
|
|
|
if (!empty($contactAddress)) {
|
|
|
|
$lines[] = "Contact: " . $contactAddress;
|
|
|
|
}
|
2023-03-05 15:30:06 +01:00
|
|
|
|
2024-05-11 16:12:15 +02:00
|
|
|
if ($gpgKey !== null) {
|
|
|
|
$lines[] = "Encryption: $baseUrl/.well-known/gpg-key.txt";
|
2023-03-05 15:30:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
$code = implode("\n", $lines);
|
|
|
|
if ($gpgKey !== null) {
|
|
|
|
$res = GpgKey::sign($code, $gpgKey->getFingerprint());
|
|
|
|
if ($res["success"]) {
|
|
|
|
$code = $res["data"];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $code;
|
|
|
|
} else if ($activeRoute->getPattern() === "/.well-known/gpg-key.txt") {
|
2024-05-11 16:12:15 +02:00
|
|
|
if ($gpgKey !== null) {
|
|
|
|
$res = $gpgKey->_export(true);
|
|
|
|
if ($res["success"]) {
|
2023-03-05 15:30:06 +01:00
|
|
|
header("Content-Type: text/plain");
|
2024-05-11 16:12:15 +02:00
|
|
|
return $res["data"];
|
|
|
|
} else {
|
|
|
|
http_response_code(500);
|
|
|
|
return "Error exporting public key: " . $res["msg"];
|
2023-03-05 15:30:06 +01:00
|
|
|
}
|
2024-03-27 20:50:57 +01:00
|
|
|
} else {
|
|
|
|
http_response_code(412);
|
|
|
|
return "No gpg key configured yet.";
|
2023-03-05 15:30:06 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
http_response_code(404);
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
public function sendHeaders(): void {
|
|
|
|
parent::sendHeaders();
|
|
|
|
header("Content-Type: text/plain");
|
|
|
|
}
|
|
|
|
}
|