reset.php 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. <?php
  2. declare(strict_types=1);
  3. use App\App\Bootstrap;
  4. use App\Security\Csrf;
  5. use App\Security\FormAccess;
  6. use App\Security\RateLimiter;
  7. use App\Storage\FileSystem;
  8. use App\Storage\JsonStore;
  9. require dirname(__DIR__) . '/src/autoload.php';
  10. Bootstrap::init();
  11. if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
  12. Bootstrap::jsonResponse(['ok' => false, 'message' => 'Method not allowed'], 405);
  13. }
  14. $csrf = $_POST['csrf'] ?? '';
  15. if (!Csrf::validate(is_string($csrf) ? $csrf : null)) {
  16. Bootstrap::jsonResponse(['ok' => false, 'message' => 'Ungültiges CSRF-Token.'], 419);
  17. }
  18. if (trim((string) ($_POST['website'] ?? '')) !== '') {
  19. Bootstrap::jsonResponse(['ok' => false, 'message' => 'Anfrage blockiert.'], 400);
  20. }
  21. $email = strtolower(trim((string) ($_POST['email'] ?? '')));
  22. if (filter_var($email, FILTER_VALIDATE_EMAIL) === false) {
  23. Bootstrap::jsonResponse(['ok' => false, 'message' => 'Bitte gültige E-Mail eingeben.'], 422);
  24. }
  25. $activityRaw = $_POST['last_user_activity_at'] ?? null;
  26. $lastUserActivityAt = is_scalar($activityRaw) ? (int) $activityRaw : null;
  27. $formAccess = new FormAccess();
  28. $auth = $formAccess->assertVerifiedForEmail($email, $lastUserActivityAt);
  29. if (($auth['ok'] ?? false) !== true) {
  30. $reason = (string) ($auth['reason'] ?? '');
  31. Bootstrap::jsonResponse([
  32. 'ok' => false,
  33. 'message' => (string) ($auth['message'] ?? 'Bitte E-Mail erneut verifizieren.'),
  34. 'auth_required' => $reason === 'auth_required',
  35. 'auth_expired' => $reason === 'auth_expired',
  36. ], (int) ($auth['status_code'] ?? 401));
  37. }
  38. $app = Bootstrap::config('app');
  39. $limiter = new RateLimiter();
  40. $ip = $_SERVER['REMOTE_ADDR'] ?? 'unknown';
  41. $rateKey = sprintf('reset:%s:%s', $ip, $email);
  42. if (!$limiter->allow($rateKey, (int) $app['rate_limit']['requests'], (int) $app['rate_limit']['window_seconds'])) {
  43. Bootstrap::jsonResponse(['ok' => false, 'message' => 'Zu viele Löschanfragen. Bitte später erneut versuchen.'], 429);
  44. }
  45. $store = new JsonStore();
  46. try {
  47. $result = $store->withEmailLock($email, static function () use ($store, $app, $email): array {
  48. $hadDraft = $store->getDraft($email) !== null;
  49. $submission = $store->getSubmissionByEmail($email);
  50. $hadSubmission = $submission !== null;
  51. if ($hadSubmission) {
  52. return [
  53. 'ok' => false,
  54. 'status' => 409,
  55. 'message' => 'Für diese E-Mail liegt bereits ein abgeschlossener Antrag vor. Ein Zurücksetzen ist nicht möglich.',
  56. 'had_draft' => $hadDraft,
  57. 'had_submission' => true,
  58. ];
  59. }
  60. $store->deleteDraft($email);
  61. $uploadDir = rtrim((string) $app['storage']['uploads'], '/') . '/' . $store->emailKey($email);
  62. FileSystem::removeTree($uploadDir);
  63. return [
  64. 'ok' => true,
  65. 'status' => 200,
  66. 'had_draft' => $hadDraft,
  67. 'had_submission' => $hadSubmission,
  68. ];
  69. });
  70. } catch (Throwable $e) {
  71. Bootstrap::log('app', 'reset error: ' . $e->getMessage());
  72. Bootstrap::jsonResponse(['ok' => false, 'message' => 'Daten konnten nicht gelöscht werden.'], 500);
  73. }
  74. if (($result['ok'] ?? false) !== true) {
  75. Bootstrap::jsonResponse([
  76. 'ok' => false,
  77. 'message' => (string) ($result['message'] ?? 'Daten konnten nicht gelöscht werden.'),
  78. 'had_draft' => (bool) ($result['had_draft'] ?? false),
  79. 'had_submission' => (bool) ($result['had_submission'] ?? false),
  80. ], (int) ($result['status'] ?? 422));
  81. }
  82. Bootstrap::jsonResponse([
  83. 'ok' => true,
  84. 'message' => 'Gespeicherte Daten wurden gelöscht.',
  85. 'had_draft' => (bool) ($result['had_draft'] ?? false),
  86. 'had_submission' => (bool) ($result['had_submission'] ?? false),
  87. ]);