277 lines
12 KiB
PHP
277 lines
12 KiB
PHP
<?php
|
|
|
|
use com\fwdekker\deathnotifier\Database;
|
|
use com\fwdekker\deathnotifier\mailer\Mailer;
|
|
use com\fwdekker\deathnotifier\Mediawiki;
|
|
use com\fwdekker\deathnotifier\Response;
|
|
use com\fwdekker\deathnotifier\trackings\TrackingManager;
|
|
use com\fwdekker\deathnotifier\UserManager;
|
|
use com\fwdekker\deathnotifier\Util;
|
|
use com\fwdekker\deathnotifier\validator\IsEmailRule;
|
|
use com\fwdekker\deathnotifier\validator\IsNotBlankRule;
|
|
use com\fwdekker\deathnotifier\validator\IsSetRule;
|
|
use com\fwdekker\deathnotifier\validator\LengthRule;
|
|
use com\fwdekker\deathnotifier\validator\Validator;
|
|
|
|
/** @noinspection PhpIncludeInspection Exists after `npm run deploy` */
|
|
require_once __DIR__ . "/.vendor/autoload.php";
|
|
|
|
|
|
// Preamble
|
|
$_POST = Util::parse_post();
|
|
$config = Util::read_config() ?? Util::http_exit(500);
|
|
// TODO: Improve logging specificity and usefulness
|
|
$logger = Util::create_logger($config["logger"]);
|
|
$db = new Database($logger->withName("Database"), $config["database"]["filename"]);
|
|
|
|
$mailer = new Mailer($config, $logger->withName("Mailer"), $db->conn);
|
|
$mediawiki = new Mediawiki($logger->withName("Mediawiki"));
|
|
$user_manager = new UserManager($logger->withName("UserManager"), $db->conn, $mailer);
|
|
$tracking_manager = new TrackingManager($logger->withName("TrackingManager"), $db->conn, $mailer, $mediawiki);
|
|
|
|
$db->auto_install($mailer, $user_manager, $tracking_manager);
|
|
$db->auto_migrate();
|
|
|
|
session_start();
|
|
$_SESSION["token"] = $_SESSION["token"] ?? Util::generate_csrf_token($logger) ?? Util::http_exit(500);
|
|
|
|
|
|
// Process request
|
|
$response = null;
|
|
|
|
if (isset($_POST["action"])) {
|
|
// POST requests; alter state
|
|
switch ($_POST["action"]) {
|
|
case "register":
|
|
$response =
|
|
Validator::validate_logged_out($_SESSION) ??
|
|
Validator::validate_token($_POST, $_SESSION["token"]) ??
|
|
Validator::validate_inputs($_POST,
|
|
[
|
|
"email" => [new IsEmailRule()],
|
|
"password" => [
|
|
new LengthRule(UserManager::MIN_PASSWORD_LENGTH, UserManager::MAX_PASSWORD_LENGTH)
|
|
]
|
|
]
|
|
) ??
|
|
$user_manager->register_user($_POST["email"], $_POST["password"]);
|
|
break;
|
|
case "login":
|
|
$response =
|
|
Validator::validate_logged_out($_SESSION) ??
|
|
Validator::validate_token($_POST, $_SESSION["token"]) ??
|
|
Validator::validate_inputs($_POST, ["email" => [new IsEmailRule()]]);
|
|
if ($response !== null) break;
|
|
|
|
[$response, $uuid] = $user_manager->check_login($_POST["email"], $_POST["password"]);
|
|
if ($response->satisfied) $_SESSION["uuid"] = $uuid;
|
|
break;
|
|
case "logout":
|
|
$response =
|
|
Validator::validate_logged_in($_SESSION) ??
|
|
Validator::validate_token($_POST, $_SESSION["token"]);
|
|
if ($response !== null) break;
|
|
|
|
session_destroy();
|
|
session_start();
|
|
$_SESSION["token"] = Util::generate_csrf_token($logger) ?? Util::http_exit(500);
|
|
|
|
$response = Response::satisfied();
|
|
break;
|
|
case "update-email":
|
|
$response =
|
|
Validator::validate_logged_in($_SESSION) ??
|
|
Validator::validate_token($_POST, $_SESSION["token"]) ??
|
|
Validator::validate_inputs($_POST, ["email" => [new IsEmailRule()]]) ??
|
|
$user_manager->set_email($_SESSION["uuid"], $_POST["email"]);
|
|
break;
|
|
case "verify-email":
|
|
$response =
|
|
// User does not need to be logged in
|
|
Validator::validate_token($_POST, $_SESSION["token"]) ??
|
|
Validator::validate_inputs($_POST,
|
|
[
|
|
"email" => [new IsEmailRule()],
|
|
"verify_token" => [new IsSetRule()],
|
|
]
|
|
) ??
|
|
$user_manager->verify_email($_POST["email"], $_POST["verify_token"]);
|
|
break;
|
|
case "resend-verify-email":
|
|
$response =
|
|
Validator::validate_logged_in($_SESSION) ??
|
|
Validator::validate_token($_POST, $_SESSION["token"]) ??
|
|
$user_manager->resend_verify_email($_SESSION["uuid"]);
|
|
break;
|
|
case "toggle-notifications":
|
|
$response =
|
|
Validator::validate_logged_in($_SESSION) ??
|
|
Validator::validate_token($_POST, $_SESSION["token"]) ??
|
|
$user_manager->toggle_notifications($_SESSION["uuid"]);
|
|
break;
|
|
case "send-password-reset":
|
|
$response =
|
|
// User does not need to be logged in
|
|
Validator::validate_token($_POST, $_SESSION["token"]) ??
|
|
Validator::validate_inputs($_POST, ["email" => [new IsEmailRule()]]) ??
|
|
$user_manager->send_password_reset($_POST["email"]);
|
|
break;
|
|
case "reset-password":
|
|
$response =
|
|
// User does not need to be logged in
|
|
Validator::validate_token($_POST, $_SESSION["token"]) ??
|
|
Validator::validate_inputs($_POST,
|
|
[
|
|
"password" => [
|
|
new LengthRule(UserManager::MIN_PASSWORD_LENGTH, UserManager::MAX_PASSWORD_LENGTH)
|
|
],
|
|
]
|
|
) ??
|
|
$user_manager->reset_password($_POST["email"], $_POST["reset_token"], $_POST["password"]);
|
|
break;
|
|
case "update-password":
|
|
$response =
|
|
Validator::validate_logged_in($_SESSION) ??
|
|
Validator::validate_token($_POST, $_SESSION["token"]) ??
|
|
Validator::validate_inputs($_POST,
|
|
[
|
|
"password_old" => [new IsSetRule()],
|
|
"password_new" => [
|
|
new LengthRule(UserManager::MIN_PASSWORD_LENGTH, UserManager::MAX_PASSWORD_LENGTH)
|
|
],
|
|
]
|
|
) ??
|
|
$user_manager->set_password($_SESSION["uuid"], $_POST["password_old"], $_POST["password_new"]);
|
|
break;
|
|
case "user-delete":
|
|
$response =
|
|
Validator::validate_logged_in($_SESSION) ??
|
|
Validator::validate_token($_POST, $_SESSION["token"]) ??
|
|
$user_manager->delete_user($_SESSION["uuid"]);
|
|
|
|
session_destroy();
|
|
session_start();
|
|
$_SESSION["token"] = Util::generate_csrf_token($logger) ?? Util::http_exit(500);
|
|
break;
|
|
case "add-tracking":
|
|
$response =
|
|
Validator::validate_logged_in($_SESSION) ??
|
|
Validator::validate_token($_POST, $_SESSION["token"]) ??
|
|
Validator::validate_inputs($_POST,
|
|
[
|
|
"person_name" => [
|
|
new LengthRule(TrackingManager::MIN_TITLE_LENGTH, TrackingManager::MAX_TITLE_LENGTH),
|
|
new IsNotBlankRule()
|
|
],
|
|
]
|
|
) ??
|
|
$tracking_manager->add_tracking($_SESSION["uuid"], $_POST["person_name"]);
|
|
break;
|
|
case "remove-tracking":
|
|
$response =
|
|
Validator::validate_logged_in($_SESSION) ??
|
|
Validator::validate_token($_POST, $_SESSION["token"]) ??
|
|
Validator::validate_inputs($_POST,
|
|
[
|
|
"person_name" => [
|
|
new LengthRule(TrackingManager::MIN_TITLE_LENGTH, TrackingManager::MAX_TITLE_LENGTH),
|
|
new IsNotBlankRule()
|
|
],
|
|
]) ??
|
|
$tracking_manager->remove_tracking($_SESSION["uuid"], $_POST["person_name"]);
|
|
break;
|
|
default:
|
|
$response = Response::unsatisfied("Unknown POST action '" . htmlentities($_POST["action"]) . "'.");
|
|
break;
|
|
}
|
|
} elseif (isset($_GET["action"])) {
|
|
// GET requests; do not alter state
|
|
switch ($_GET["action"]) {
|
|
case "start-session":
|
|
if (!isset($_SESSION["uuid"])) {
|
|
$response = Response::satisfied(["logged_in" => false]);
|
|
} else if (!$user_manager->user_exists($_SESSION["uuid"])) {
|
|
// User account was deleted
|
|
session_destroy();
|
|
session_start();
|
|
$_SESSION["token"] = Util::generate_csrf_token($logger) ?? Util::http_exit(500);
|
|
|
|
$response = Response::satisfied(["logged_in" => false]);
|
|
} else {
|
|
$response = Response::satisfied(["logged_in" => true]);
|
|
}
|
|
|
|
if (isset($config["server"]["global_message"]) && trim($config["server"]["global_message"]) !== "")
|
|
$response->payload["global_message"] = trim($config["server"]["global_message"]);
|
|
break;
|
|
case "validate-password-reset-token":
|
|
$response =
|
|
// User does not need to be logged in
|
|
Validator::validate_token($_GET, $_SESSION["token"]) ??
|
|
Validator::validate_inputs($_GET,
|
|
[
|
|
"reset_token" => [new IsSetRule()],
|
|
"email" => [new IsEmailRule()]
|
|
]
|
|
) ??
|
|
$user_manager->validate_password_reset_token($_GET["email"], $_GET["reset_token"]);
|
|
break;
|
|
case "get-user-data":
|
|
$response =
|
|
Validator::validate_logged_in($_SESSION) ??
|
|
Validator::validate_token($_GET, $_SESSION["token"]) ??
|
|
$user_manager->get_user($_SESSION["uuid"]);
|
|
break;
|
|
case "list-trackings":
|
|
$response =
|
|
Validator::validate_logged_in($_SESSION) ??
|
|
Validator::validate_token($_GET, $_SESSION["token"]) ??
|
|
$tracking_manager->list_trackings($_SESSION["uuid"]);
|
|
break;
|
|
default:
|
|
$response = Response::unsatisfied("Unknown GET action '" . htmlentities($_GET["action"]) . "'.");
|
|
}
|
|
} elseif ($argc > 1) {
|
|
// CLI
|
|
// TODO: Read secret from file
|
|
if (hash_equals($config["admin"]["cli_secret"], "REPLACE THIS WITH A SECRET VALUE"))
|
|
exit("Default value for 'cli_secret' detected. Feature disabled.");
|
|
if (!hash_equals($config["admin"]["cli_secret"], $argv[2]))
|
|
exit("Incorrect value for 'cli_secret'.");
|
|
|
|
switch ($argv[1]) {
|
|
case "emulate-cron":
|
|
/* @phpstan-ignore-next-line Intentional infinite loop */
|
|
while (true) {
|
|
print("Updating all trackings\n");
|
|
$tracking_manager->update_trackings($tracking_manager->list_all_unique_person_names());
|
|
print("Processing email queue\n");
|
|
$mailer->process_queue();
|
|
print("Done\n");
|
|
sleep(15);
|
|
}
|
|
case "update-all-trackings":
|
|
$logger->info("Updating all trackings.");
|
|
$tracking_manager->update_trackings($tracking_manager->list_all_unique_person_names());
|
|
exit("Successfully updated all trackings.");
|
|
case "process-email-queue":
|
|
$logger->info("Processing email queue.");
|
|
$mailer->process_queue();
|
|
exit("Successfully processed email queue.");
|
|
default:
|
|
exit("Unknown CLI action '$argv[1]'.");
|
|
}
|
|
} else {
|
|
// No request, no actions, so that's a success
|
|
$response = Response::satisfied();
|
|
}
|
|
|
|
|
|
// Respond
|
|
header("Content-type:application/json;charset=utf-8");
|
|
exit(json_encode(array(
|
|
"payload" => $response->payload,
|
|
"satisfied" => $response->satisfied,
|
|
"token" => $_SESSION["token"]
|
|
)));
|