feat: Add basic logging for rate limiting

This commit is contained in:
overflowerror 2023-11-25 13:07:05 +01:00
parent 275eddf025
commit 8255421d0e
9 changed files with 139 additions and 7 deletions

5
context.php Normal file
View file

@ -0,0 +1,5 @@
<?php
const DB_CONNECTION = "DB_CONNECTION";
const REPOSITORIES = "REPOSITORIES";
const RENDERER = "RENDERER";

View file

@ -1,6 +1,7 @@
<?php <?php
require_once(ROOT . "/middleware/renderer.php"); require_once(ROOT . "/middleware/renderer.php");
require_once(ROOT . "/middleware/log.php");
function fromController(string $path) { function fromController(string $path) {
return function(array $context) use ($path) { return function(array $context) use ($path) {
@ -12,8 +13,29 @@ return function(Router $router) {
$router->addRoute(GET, "/", fromController("/GET")); $router->addRoute(GET, "/", fromController("/GET"));
$router->addRoute(GET, "/test", useRenderer(fromController("/test/GET"))); $router->addRoute(GET, "/test", useRenderer(fromController("/test/GET")));
$router->addRoute(GET, "/ipaddress", useRenderer(fromController("/ipaddress/GET"))); $router->addRoute(GET, "/ipaddress",
$router->addRoute(GET, "/whois", useRenderer(fromController("/whois/GET"))); useLog(
useRenderer(
fromController("/ipaddress/GET")
),
"ipaddress"
)
);
$router->addRoute(GET, "/whois",
useLog(
useRenderer(
fromController("/whois/GET")
),
"whois"
)
);
$router->addRoute(GET, "/punycode", useRenderer(fromController("/punycode/GET"))); $router->addRoute(GET, "/punycode",
useLog(
useRenderer(
fromController("/punycode/GET")
),
"punycode"
)
);
}; };

View file

@ -10,9 +10,16 @@ if (MAINTENANCE_MODE) {
$connection = require_once(ROOT . "/persistence/connection.php"); $connection = require_once(ROOT . "/persistence/connection.php");
(require(ROOT . "/persistence/migrate.php"))($connection); (require(ROOT . "/persistence/migrate.php"))($connection);
$repositories = (require_once(ROOT . "/persistence/Repositories.php"))($connection);
$router = require(ROOT . "/router/Router.php"); $router = require(ROOT . "/router/Router.php");
(require(ROOT . "/controllers/routes.php"))($router); (require(ROOT . "/controllers/routes.php"))($router);
$router->execute([
"DB_CONNECTION" => $connection, require_once(ROOT . "/context.php");
]); $context = [
DB_CONNECTION => $connection,
REPOSITORIES => $repositories,
];
$router->execute($context);
} }

20
middleware/log.php Normal file
View file

@ -0,0 +1,20 @@
<?php
require_once(ROOT . "/persistence/models/LogEntry.php");
function useLog($handler, string $endpoint) {
return function (array $context) use ($handler, $endpoint) {
$result = $handler($context);
$accessKey = $context["ACCESS_KEY"] ?? "";
$entry = new LogEntry(
$endpoint,
$_SERVER['REMOTE_ADDR'],
$accessKey,
);
$context[REPOSITORIES]->logs()->add($entry);
return $result;
};
}

View file

@ -7,7 +7,7 @@ function useRenderer($handler, string $default = "JSON", string $query_param = "
$rendererMap = require(ROOT . "/renderer/renderer.php"); $rendererMap = require(ROOT . "/renderer/renderer.php");
$renderer = $rendererMap[strtoupper($_GET[$query_param] ?? "")] ?? $rendererMap[$default]; $renderer = $rendererMap[strtoupper($_GET[$query_param] ?? "")] ?? $rendererMap[$default];
$context["renderer"] = $renderer; $context[RENDERER] = $renderer;
$result = $handler($context); $result = $handler($context);
if ($result !== null) { if ($result !== null) {

View file

@ -0,0 +1,19 @@
<?php
require_once(__DIR__ . "/repositories/Logs.php");
class Repositories {
private $map = [];
public function __construct(PDO $connection) {
$this->map[Logs::class] = new Logs($connection);
}
public function logs(): Logs {
return $this->map[Logs::class];
}
}
return function(PDO $connection): Repositories {
return new Repositories($connection);
};

View file

@ -0,0 +1,13 @@
CREATE TABLE `ua_logs` (
`id` BIGINT AUTO_INCREMENT PRIMARY KEY,
`timestamp` DATETIME DEFAULT CURRENT_TIMESTAMP,
`endpoint` VARCHAR(100),
`client_address` VARCHAR(46),
`access_key` VARCHAR(255),
`clean` BOOLEAN DEFAULT 0,
INDEX (`endpoint`),
INDEX (`client_address`),
INDEX (`access_key`)
);

View file

@ -0,0 +1,20 @@
<?php
class LogEntry {
public int $id;
public DateTime $timestamp;
public string $endpoint;
public string $clientAddress;
public string $accessKey;
public bool $isClean;
public function __construct(
string $endpoint,
string $clientAddress,
string $accessKey,
) {
$this->endpoint = $endpoint;
$this->clientAddress = $clientAddress;
$this->accessKey = $accessKey;
}
}

View file

@ -0,0 +1,26 @@
<?php
require_once(__DIR__ . "/../models/LogEntry.php");
class Logs {
private string $table = "ua_logs";
private PDO $connection;
public function __construct(PDO $connection) {
$this->connection = $connection;
}
public function add(LogEntry $entry) {
$statement = $this->connection->prepare(<<<EOF
INSERT INTO `$this->table`
(`endpoint`, `client_address`, `access_key`) VALUES
(?, ?, ?)
EOF);
$statement->execute([
$entry->endpoint,
$entry->clientAddress,
$entry->accessKey,
]);
}
}