refactor(actions): centralize wave-2 post/csrf guards

This commit is contained in:
2026-04-24 18:31:17 +02:00
parent cfd867bcd7
commit da7e7c593e
26 changed files with 237 additions and 114 deletions

View File

@@ -0,0 +1,95 @@
{
"task_id": "2026-04-24-action-csrf-centralization-step2",
"plan_ref": ".agents/runs/2026-04-24-action-csrf-centralization-step2/plan.json",
"status": "done",
"changed_files": [
{ "path": "core/Support/helpers/request.php", "summary": "Extended actionRequireCsrf() with optional redirectOnFailure flag for non-redirect POST flows." },
{ "path": "pages/admin/settings/revoke-api-tokens().php", "summary": "Replaced inline POST/CSRF boilerplate with actionRequirePost/actionRequireCsrf." },
{ "path": "pages/admin/settings/expire-remember-tokens().php", "summary": "Replaced inline POST/CSRF boilerplate with actionRequirePost/actionRequireCsrf." },
{ "path": "pages/admin/scheduled-jobs/purge-runs().php", "summary": "Replaced inline POST/CSRF boilerplate with actionRequirePost/actionRequireCsrf." },
{ "path": "pages/admin/scheduled-jobs/run($id).php", "summary": "Centralized method/CSRF guards via actionRequirePost/actionRequireCsrf." },
{ "path": "pages/admin/tenants/custom-field-create($id).php", "summary": "Centralized method/CSRF guard flow via action helpers." },
{ "path": "pages/admin/tenants/custom-field-update($id).php", "summary": "Centralized method/CSRF guard flow via action helpers." },
{ "path": "pages/admin/tenants/custom-field-delete($id).php", "summary": "Centralized method/CSRF guard flow via action helpers." },
{ "path": "pages/admin/users/access-pdf($id).php", "summary": "Kept GET rendering path intact; centralized CSRF check only in POST branch." },
{ "path": "pages/admin/users/access-pdf-bulk().php", "summary": "Replaced inline POST/CSRF boilerplate with actionRequirePost/actionRequireCsrf." },
{ "path": "pages/admin/departments/create().php", "summary": "Replaced inline CSRF block with actionRequireCsrf in POST branch." },
{ "path": "pages/admin/departments/edit($id).php", "summary": "Replaced inline CSRF block with actionRequireCsrf in POST branch." },
{ "path": "pages/admin/permissions/create().php", "summary": "Replaced inline CSRF block with actionRequireCsrf in POST branch." },
{ "path": "pages/admin/permissions/edit($id).php", "summary": "Replaced inline CSRF block with actionRequireCsrf in POST branch." },
{ "path": "pages/admin/roles/create().php", "summary": "Replaced inline CSRF block with actionRequireCsrf in POST branch." },
{ "path": "pages/admin/roles/edit($id).php", "summary": "Replaced inline CSRF block with actionRequireCsrf in POST branch." },
{ "path": "pages/admin/tenants/create().php", "summary": "Replaced inline CSRF block with actionRequireCsrf in POST branch." },
{ "path": "pages/admin/tenants/edit($id).php", "summary": "Replaced inline CSRF block with actionRequireCsrf in POST branch." },
{ "path": "pages/admin/users/edit($id).php", "summary": "Replaced inline CSRF block with actionRequireCsrf in POST branch." },
{ "path": "pages/admin/settings/index().php", "summary": "Replaced inline CSRF block with actionRequireCsrf in POST branch." },
{ "path": "pages/admin/scheduled-jobs/edit($id).php", "summary": "Centralized CSRF validation via actionRequireCsrf(..., redirectOnFailure: false) while preserving in-page error rendering." }
],
"guard_evidence": [
{
"guard_id": "GR-CORE-003",
"status": "pass",
"evidence": "Refactor keeps requestInput()-based handling; no superglobal request/session access introduced."
},
{
"guard_id": "GR-CORE-012",
"status": "pass",
"evidence": "PRG flows in targeted actions remain intact; PostRedirectGetContractTest passes."
},
{
"guard_id": "GR-SEC-001",
"status": "pass",
"evidence": "All Wave-2 targets now verify CSRF through actionRequireCsrf (or non-redirect variant in scheduled-jobs/edit)."
},
{
"guard_id": "GR-SEC-008",
"status": "pass",
"evidence": "Existing policy/ability checks remain unchanged; only guard boilerplate was centralized."
},
{
"guard_id": "GR-SEC-009",
"status": "pass",
"evidence": "Tenant-scope related service and authorization calls were not altered."
},
{
"guard_id": "GR-TEST-001",
"status": "pass",
"evidence": "Architecture test set and full PHPUnit suite pass."
}
],
"commands": [
{ "cmd": "docker compose exec -T php vendor/bin/phpunit tests/Architecture/PostEndpointCsrfContractTest.php", "result": "pass" },
{ "cmd": "docker compose exec -T php vendor/bin/phpunit tests/Architecture/PostRedirectGetContractTest.php", "result": "pass" },
{ "cmd": "docker compose exec -T php vendor/bin/phpunit tests/Architecture/AuthzAdminSettingsContractTest.php tests/Architecture/AuthzAdminMasterDataContractTest.php tests/Architecture/AuthzAdminUsersContractTest.php", "result": "pass" },
{ "cmd": "docker compose exec -T php vendor/bin/phpunit", "result": "pass" },
{ "cmd": "docker compose exec -T php vendor/bin/phpstan analyse -c phpstan.neon --no-progress", "result": "pass" },
{ "cmd": "docker compose exec -T php vendor/bin/phpunit tests/Architecture/CoreStarterkitContractTest.php", "result": "pass" },
{ "cmd": "docker compose exec -T php vendor/bin/php-cs-fixer fix --config=tools/php-cs-fixer/.php-cs-fixer.dist.php --dry-run --diff --verbose", "result": "pass" },
{ "cmd": "bin/docs-link-check.sh", "result": "pass" },
{ "cmd": "bin/docs-drift-check.sh", "result": "pass" },
{ "cmd": "bin/codex-skills-sync.sh --check", "result": "pass" }
],
"quality_gate_results": [
{ "gate_id": "QG-001", "result": "pass", "notes": "PHPUnit full run green: 2023 tests, 28224 assertions." },
{ "gate_id": "QG-002", "result": "pass", "notes": "PHPStan level 5: no errors." },
{ "gate_id": "QG-003", "result": "pass", "notes": "CoreStarterkitContractTest green: 13 tests, 6974 assertions." },
{ "gate_id": "QG-006", "result": "pass", "notes": "php-cs-fixer dry-run green after removing one unused import." },
{ "gate_id": "QG-008", "result": "pass", "notes": "docs-link-check and docs-drift-check green." },
{ "gate_id": "QG-009", "result": "pass", "notes": "codex-skills-sync --check green." }
],
"metrics": {
"wave2_target_files": 20,
"before_requestinput_method_calls": 9,
"after_requestinput_method_calls": 0,
"before_inline_session_csrf_checks": 20,
"after_inline_session_csrf_checks": 0
},
"test_results": [
{ "name": "PostEndpointCsrfContractTest", "result": "pass", "notes": "1 test, 2 assertions." },
{ "name": "PostRedirectGetContractTest", "result": "pass", "notes": "1 test, 2 assertions." },
{ "name": "Authz Admin contract suite", "result": "pass", "notes": "13 tests, 203 assertions." },
{ "name": "CoreStarterkitContractTest", "result": "pass", "notes": "13 tests, 6974 assertions." },
{ "name": "Full PHPUnit suite", "result": "pass", "notes": "2023 tests, 28224 assertions." }
],
"open_items": []
}

View File

@@ -0,0 +1,12 @@
{
"task_id": "2026-04-24-action-csrf-centralization-step2",
"ready_to_finalize": true,
"code_review": "pass",
"security_review": "pass",
"acceptance_review": "pass",
"ci_status": "required-gates-pass",
"final_action": "commit",
"hold_reason": "",
"commit_message": "refactor(actions): centralize wave-2 post/csrf guards",
"notes": "Wave 2.1 + 2.2 executed. Required gates QG-001/002/003/006/008/009 green."
}

View File

@@ -0,0 +1,44 @@
{
"task_id": "2026-04-24-action-csrf-centralization-step2",
"verdict": "pass",
"checked_criterion_ids": [
"SC-001",
"SC-002",
"SC-003",
"SC-004",
"SC-005"
],
"checks": [
{
"criterion_id": "SC-001",
"criterion": "All Wave-2.1/2.2 targets use actionRequirePost() and actionRequireCsrf() where semantically applicable without changing endpoint behavior.",
"result": "pass",
"evidence": "All planned Wave-2 targets were migrated to helper-based method/CSRF guards; mixed GET/POST access-pdf endpoint kept GET path unchanged."
},
{
"criterion_id": "SC-002",
"criterion": "No regressions in PRG/authz flows: PostRedirectGetContractTest and Authz architecture suites remain green.",
"result": "pass",
"evidence": "PostRedirectGetContractTest and AuthzAdminSettings/AuthzAdminMasterData/AuthzAdminUsers contract tests pass."
},
{
"criterion_id": "SC-003",
"criterion": "POST actions without CSRF/helper remain 0 in pages/ after the change.",
"result": "pass",
"evidence": "PostEndpointCsrfContractTest passes with no missing POST handlers."
},
{
"criterion_id": "SC-004",
"criterion": "Inline method-check and inline CSRF-check occurrences in Wave-2 scope are reduced substantially (target: method checks -60%+, csrf checks -60%+ in targeted files).",
"result": "pass",
"evidence": "Wave-2 file metrics: requestInput()->method() 9 -> 0, Session::checkCsrfToken() 20 -> 0."
},
{
"criterion_id": "SC-005",
"criterion": "Required gate set QG-001/002/003/006/008/009 passes; non-scope qa-required extras are reported separately if failing.",
"result": "pass",
"evidence": "All required gates were run individually and passed."
}
],
"missing_or_wrong": []
}

View File

@@ -0,0 +1,18 @@
{
"task_id": "2026-04-24-action-csrf-centralization-step2",
"verdict": "pass",
"checked_guard_ids": [
"GR-CORE-003",
"GR-CORE-012",
"GR-TEST-001"
],
"checked_quality_gate_ids": [
"QG-001",
"QG-002",
"QG-003",
"QG-006",
"QG-008",
"QG-009"
],
"findings": []
}

View File

@@ -0,0 +1,10 @@
{
"task_id": "2026-04-24-action-csrf-centralization-step2",
"verdict": "pass",
"checked_guard_ids": [
"GR-SEC-001",
"GR-SEC-008",
"GR-SEC-009"
],
"findings": []
}

View File

@@ -78,7 +78,8 @@ function actionRequireCsrf(
string $flashKeyPrefix = 'csrf_expired', string $flashKeyPrefix = 'csrf_expired',
bool $jsonAware = false, bool $jsonAware = false,
string $jsonError = 'csrf', string $jsonError = 'csrf',
bool $flashOnFailure = true bool $flashOnFailure = true,
bool $redirectOnFailure = true
): bool { ): bool {
if (Session::checkCsrfToken()) { if (Session::checkCsrfToken()) {
return true; return true;
@@ -96,7 +97,9 @@ function actionRequireCsrf(
flashFormErrors($errorBag, $flashScope ?? $redirect, $flashKeyPrefix); flashFormErrors($errorBag, $flashScope ?? $redirect, $flashKeyPrefix);
} }
Router::redirect($redirect); if ($redirectOnFailure) {
Router::redirect($redirect);
}
return false; return false;
} }

View File

@@ -4,7 +4,6 @@ use MintyPHP\Buffer;
use MintyPHP\Http\SessionStoreInterface; use MintyPHP\Http\SessionStoreInterface;
use MintyPHP\Router; use MintyPHP\Router;
use MintyPHP\Service\Access\DepartmentAuthorizationPolicy; use MintyPHP\Service\Access\DepartmentAuthorizationPolicy;
use MintyPHP\Session;
use MintyPHP\Support\Flash; use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard; use MintyPHP\Support\Guard;
@@ -50,9 +49,7 @@ if ($allowedTenantIds) {
$tenants = []; $tenants = [];
} }
if ($request->isMethod('POST') && !Session::checkCsrfToken()) { if ($request->isMethod('POST') && !actionRequireCsrf($createTarget, $createTarget, 'csrf_expired')) {
Flash::error(t('Form expired, please try again'), $createTarget, 'csrf_expired');
Router::redirect($createTarget);
return; return;
} }

View File

@@ -4,7 +4,6 @@ use MintyPHP\Buffer;
use MintyPHP\Http\SessionStoreInterface; use MintyPHP\Http\SessionStoreInterface;
use MintyPHP\Router; use MintyPHP\Router;
use MintyPHP\Service\Access\DepartmentAuthorizationPolicy; use MintyPHP\Service\Access\DepartmentAuthorizationPolicy;
use MintyPHP\Session;
use MintyPHP\Support\Flash; use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard; use MintyPHP\Support\Guard;
@@ -81,9 +80,7 @@ if ($allowedTenantIds) {
$form['tenant_id'] = 0; $form['tenant_id'] = 0;
} }
if ($request->isMethod('POST') && !Session::checkCsrfToken()) { if ($request->isMethod('POST') && !actionRequireCsrf($editTarget, $editTarget, 'csrf_expired')) {
Flash::error(t('Form expired, please try again'), $editTarget, 'csrf_expired');
Router::redirect($editTarget);
return; return;
} }

View File

@@ -4,7 +4,6 @@ use MintyPHP\Buffer;
use MintyPHP\Http\SessionStoreInterface; use MintyPHP\Http\SessionStoreInterface;
use MintyPHP\Router; use MintyPHP\Router;
use MintyPHP\Service\Access\PermissionAuthorizationPolicy; use MintyPHP\Service\Access\PermissionAuthorizationPolicy;
use MintyPHP\Session;
use MintyPHP\Support\Flash; use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard; use MintyPHP\Support\Guard;
@@ -33,9 +32,7 @@ $form = [
'is_system' => 0, 'is_system' => 0,
]; ];
if ($request->isMethod('POST') && !Session::checkCsrfToken()) { if ($request->isMethod('POST') && !actionRequireCsrf($createTarget, $createTarget, 'csrf_expired')) {
Flash::error(t('Form expired, please try again'), $createTarget, 'csrf_expired');
Router::redirect($createTarget);
return; return;
} }

View File

@@ -5,7 +5,6 @@ use MintyPHP\Http\SessionStoreInterface;
use MintyPHP\Repository\Access\RoleRepository; use MintyPHP\Repository\Access\RoleRepository;
use MintyPHP\Router; use MintyPHP\Router;
use MintyPHP\Service\Access\PermissionAuthorizationPolicy; use MintyPHP\Service\Access\PermissionAuthorizationPolicy;
use MintyPHP\Session;
use MintyPHP\Support\Flash; use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard; use MintyPHP\Support\Guard;
@@ -48,9 +47,7 @@ $userWriteRepository = app(\MintyPHP\Repository\User\UserWriteRepository::class)
$selectedRoleIds = $rolePermissionRepository->listRoleIdsByPermissionId($id); $selectedRoleIds = $rolePermissionRepository->listRoleIdsByPermissionId($id);
$previousRoleIds = $selectedRoleIds; $previousRoleIds = $selectedRoleIds;
if ($request->isMethod('POST') && !Session::checkCsrfToken()) { if ($request->isMethod('POST') && !actionRequireCsrf($editTarget, $editTarget, 'csrf_expired')) {
Flash::error(t('Form expired, please try again'), $editTarget, 'csrf_expired');
Router::redirect($editTarget);
return; return;
} }

View File

@@ -4,7 +4,6 @@ use MintyPHP\Buffer;
use MintyPHP\Http\SessionStoreInterface; use MintyPHP\Http\SessionStoreInterface;
use MintyPHP\Router; use MintyPHP\Router;
use MintyPHP\Service\Access\RoleAuthorizationPolicy; use MintyPHP\Service\Access\RoleAuthorizationPolicy;
use MintyPHP\Session;
use MintyPHP\Support\Flash; use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard; use MintyPHP\Support\Guard;
@@ -37,9 +36,7 @@ $rolePermissionRepository = app(\MintyPHP\Repository\Access\RolePermissionReposi
$permissions = $permissionRepository->listActive(); $permissions = $permissionRepository->listActive();
$selectedPermissionIds = []; $selectedPermissionIds = [];
if ($request->isMethod('POST') && !Session::checkCsrfToken()) { if ($request->isMethod('POST') && !actionRequireCsrf($createTarget, $createTarget, 'csrf_expired')) {
Flash::error(t('Form expired, please try again'), $createTarget, 'csrf_expired');
Router::redirect($createTarget);
return; return;
} }

View File

@@ -4,7 +4,6 @@ use MintyPHP\Buffer;
use MintyPHP\Http\SessionStoreInterface; use MintyPHP\Http\SessionStoreInterface;
use MintyPHP\Router; use MintyPHP\Router;
use MintyPHP\Service\Access\RoleAuthorizationPolicy; use MintyPHP\Service\Access\RoleAuthorizationPolicy;
use MintyPHP\Session;
use MintyPHP\Support\Flash; use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard; use MintyPHP\Support\Guard;
@@ -53,9 +52,7 @@ $assignableRoleRepo = app(\MintyPHP\Repository\Access\RoleAssignableRoleReposito
$allRolesForAssignable = app(\MintyPHP\Service\Access\RoleService::class)->listActive(); $allRolesForAssignable = app(\MintyPHP\Service\Access\RoleService::class)->listActive();
$selectedAssignableRoleIds = $assignableRoleRepo->listAssignableRoleIdsByRoleId($roleId); $selectedAssignableRoleIds = $assignableRoleRepo->listAssignableRoleIdsByRoleId($roleId);
if ($request->isMethod('POST') && !Session::checkCsrfToken()) { if ($request->isMethod('POST') && !actionRequireCsrf($editTarget, $editTarget, 'csrf_expired')) {
Flash::error(t('Form expired, please try again'), $editTarget, 'csrf_expired');
Router::redirect($editTarget);
return; return;
} }

View File

@@ -3,17 +3,18 @@
use MintyPHP\Buffer; use MintyPHP\Buffer;
use MintyPHP\Http\SessionStoreInterface; use MintyPHP\Http\SessionStoreInterface;
use MintyPHP\Router; use MintyPHP\Router;
use MintyPHP\Session;
use MintyPHP\Support\Flash; use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard; use MintyPHP\Support\Guard;
$session = app(SessionStoreInterface::class)->all(); $session = app(SessionStoreInterface::class)->all();
Guard::requireLogin(); Guard::requireLogin();
Guard::requireAbility(\MintyPHP\Service\Access\OperationsAuthorizationPolicy::ABILITY_ADMIN_JOBS_VIEW); Guard::requireAbility(\MintyPHP\Service\Access\OperationsAuthorizationPolicy::ABILITY_ADMIN_JOBS_VIEW);
$request = requestInput();
$scheduledJobService = app(\MintyPHP\Service\Scheduler\ScheduledJobService::class); $scheduledJobService = app(\MintyPHP\Service\Scheduler\ScheduledJobService::class);
$jobId = (int) ($id ?? 0); $jobId = (int) ($id ?? 0);
$editTarget = "admin/scheduled-jobs/edit/$jobId";
$job = $jobId > 0 ? $scheduledJobService->find($jobId) : null; $job = $jobId > 0 ? $scheduledJobService->find($jobId) : null;
if (!$job) { if (!$job) {
Flash::error(t('Scheduled job not found'), 'admin/scheduled-jobs', 'scheduled_job_not_found'); Flash::error(t('Scheduled job not found'), 'admin/scheduled-jobs', 'scheduled_job_not_found');
@@ -47,22 +48,22 @@ if (!$isRegistered) {
$errorBag->addGlobal(t('This scheduled job is no longer registered and cannot be edited. It has been superseded by a newer version.')); $errorBag->addGlobal(t('This scheduled job is no longer registered and cannot be edited. It has been superseded by a newer version.'));
} }
if (requestInput()->method() === 'POST') { if ($request->isMethod('POST')) {
if (!$canManage) { if (!$canManage) {
Guard::deny(); Guard::deny();
} }
if (!Session::checkCsrfToken()) { if (!actionRequireCsrf($editTarget, flashOnFailure: false, redirectOnFailure: false)) {
$errorBag->addGlobal(t('Form expired, please try again')); $errorBag->addGlobal(t('Form expired, please try again'));
} }
if (!$errorBag->hasAny()) { if (!$errorBag->hasAny()) {
$saved = $scheduledJobService->updateFromAdmin($jobId, requestInput()->bodyAll()); $saved = $scheduledJobService->updateFromAdmin($jobId, $request->bodyAll());
if (!($saved['ok'] ?? false)) { if (!($saved['ok'] ?? false)) {
$errorBag->merge((array) ($saved['errors'] ?? [t('Scheduled job could not be saved')])); $errorBag->merge((array) ($saved['errors'] ?? [t('Scheduled job could not be saved')]));
$form = array_merge($form, (array) ($saved['form'] ?? [])); $form = array_merge($form, (array) ($saved['form'] ?? []));
} else { } else {
Flash::success(t('Scheduled job saved'), "admin/scheduled-jobs/edit/$jobId", 'scheduled_job_saved'); Flash::success(t('Scheduled job saved'), $editTarget, 'scheduled_job_saved');
$job = $saved['job'] ?? $job; $job = $saved['job'] ?? $job;
$form = [ $form = [
'enabled' => (int) ($job['enabled'] ?? 0), 'enabled' => (int) ($job['enabled'] ?? 0),

View File

@@ -1,21 +1,18 @@
<?php <?php
use MintyPHP\Router; use MintyPHP\Router;
use MintyPHP\Session;
use MintyPHP\Support\Flash; use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard; use MintyPHP\Support\Guard;
Guard::requireLogin(); Guard::requireLogin();
Guard::requireAbility(\MintyPHP\Service\Access\SettingsAuthorizationPolicy::ABILITY_ADMIN_SETTINGS_UPDATE); Guard::requireAbility(\MintyPHP\Service\Access\SettingsAuthorizationPolicy::ABILITY_ADMIN_SETTINGS_UPDATE);
if (strtoupper((string) (requestInput()->method())) !== 'POST') { if (!actionRequirePost('admin/scheduled-jobs')) {
Router::redirect('admin/scheduled-jobs'); return;
} }
$errorBag = formErrors();
if (!Session::checkCsrfToken()) { if (!actionRequireCsrf('admin/scheduled-jobs', 'admin/scheduled-jobs', 'scheduled_job_purge')) {
$errorBag->addGlobal(t('Form expired, please try again')); return;
flashFormErrors($errorBag, 'admin/scheduled-jobs', 'scheduled_job_purge');
Router::redirect('admin/scheduled-jobs');
} }
$deleted = app(\MintyPHP\Service\Scheduler\ScheduledJobService::class)->purgeRunsExpired(); $deleted = app(\MintyPHP\Service\Scheduler\ScheduledJobService::class)->purgeRunsExpired();

View File

@@ -4,7 +4,6 @@ use MintyPHP\Domain\Taxonomy\ScheduledJobRunStatus;
use MintyPHP\Domain\Taxonomy\SchedulerRuntimeResult; use MintyPHP\Domain\Taxonomy\SchedulerRuntimeResult;
use MintyPHP\Http\SessionStoreInterface; use MintyPHP\Http\SessionStoreInterface;
use MintyPHP\Router; use MintyPHP\Router;
use MintyPHP\Session;
use MintyPHP\Support\Flash; use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard; use MintyPHP\Support\Guard;
@@ -13,16 +12,16 @@ Guard::requireLogin();
Guard::requireAbility(\MintyPHP\Service\Access\OperationsAuthorizationPolicy::ABILITY_ADMIN_JOBS_RUN_NOW); Guard::requireAbility(\MintyPHP\Service\Access\OperationsAuthorizationPolicy::ABILITY_ADMIN_JOBS_RUN_NOW);
$jobId = (int) ($id ?? 0); $jobId = (int) ($id ?? 0);
if (strtoupper((string) (requestInput()->method())) !== 'POST') { $redirectTarget = "admin/scheduled-jobs/edit/$jobId";
Router::redirect("admin/scheduled-jobs/edit/$jobId"); if (!actionRequirePost($redirectTarget)) {
} return;
$errorBag = formErrors();
if (!Session::checkCsrfToken()) {
$errorBag->addGlobal(t('Form expired, please try again'));
flashFormErrors($errorBag, "admin/scheduled-jobs/edit/$jobId", 'scheduled_job_run');
Router::redirect("admin/scheduled-jobs/edit/$jobId");
} }
if (!actionRequireCsrf($redirectTarget, $redirectTarget, 'scheduled_job_run')) {
return;
}
$errorBag = formErrors();
$result = app(\MintyPHP\Service\Scheduler\SchedulerRunService::class)->runJobNow($jobId, (int) ($session['user']['id'] ?? 0)); $result = app(\MintyPHP\Service\Scheduler\SchedulerRunService::class)->runJobNow($jobId, (int) ($session['user']['id'] ?? 0));
if (!($result['ok'] ?? false)) { if (!($result['ok'] ?? false)) {
$error = (string) ($result['error'] ?? ''); $error = (string) ($result['error'] ?? '');

View File

@@ -3,7 +3,6 @@
use MintyPHP\Http\SessionStoreInterface; use MintyPHP\Http\SessionStoreInterface;
use MintyPHP\Router; use MintyPHP\Router;
use MintyPHP\Service\Access\SettingsAuthorizationPolicy; use MintyPHP\Service\Access\SettingsAuthorizationPolicy;
use MintyPHP\Session;
use MintyPHP\Support\Flash; use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard; use MintyPHP\Support\Guard;
@@ -19,15 +18,12 @@ if (!$decision->isAllowed()) {
Guard::deny(); Guard::deny();
} }
if (requestInput()->method() !== 'POST') { if (!actionRequirePost('admin/settings')) {
Router::redirect('admin/settings'); return;
} }
$errorBag = formErrors(); if (!actionRequireCsrf('admin/settings', 'admin/settings', 'settings_tokens_expire')) {
if (!Session::checkCsrfToken()) { return;
$errorBag->addGlobal(t('Form expired, please try again'));
flashFormErrors($errorBag, 'admin/settings', 'settings_tokens_expire');
Router::redirect('admin/settings');
} }
$rememberMeService = app(\MintyPHP\Service\Auth\RememberMeService::class); $rememberMeService = app(\MintyPHP\Service\Auth\RememberMeService::class);

View File

@@ -5,7 +5,6 @@ use MintyPHP\Http\SessionStoreInterface;
use MintyPHP\Router; use MintyPHP\Router;
use MintyPHP\Service\Access\SettingsAuthorizationPolicy; use MintyPHP\Service\Access\SettingsAuthorizationPolicy;
use MintyPHP\Service\Settings\AdminSettingsService; use MintyPHP\Service\Settings\AdminSettingsService;
use MintyPHP\Session;
use MintyPHP\Support\Flash; use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard; use MintyPHP\Support\Guard;
@@ -34,9 +33,7 @@ $settings = is_array($pageData['settings'] ?? null) ? $pageData['settings'] : []
$activeLoginTokens = (int) ($pageData['active_login_tokens'] ?? 0); $activeLoginTokens = (int) ($pageData['active_login_tokens'] ?? 0);
$activeApiTokens = (int) ($pageData['active_api_tokens'] ?? 0); $activeApiTokens = (int) ($pageData['active_api_tokens'] ?? 0);
if ($request->isMethod('POST') && !Session::checkCsrfToken()) { if ($request->isMethod('POST') && !actionRequireCsrf('admin/settings', 'admin/settings', 'csrf_expired')) {
Flash::error(t('Form expired, please try again'), 'admin/settings', 'csrf_expired');
Router::redirect('admin/settings');
return; return;
} }

View File

@@ -3,7 +3,6 @@
use MintyPHP\Http\SessionStoreInterface; use MintyPHP\Http\SessionStoreInterface;
use MintyPHP\Router; use MintyPHP\Router;
use MintyPHP\Service\Access\SettingsAuthorizationPolicy; use MintyPHP\Service\Access\SettingsAuthorizationPolicy;
use MintyPHP\Session;
use MintyPHP\Support\Flash; use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard; use MintyPHP\Support\Guard;
@@ -19,15 +18,12 @@ if (!$decision->isAllowed()) {
Guard::deny(); Guard::deny();
} }
if (requestInput()->method() !== 'POST') { if (!actionRequirePost('admin/settings')) {
Router::redirect('admin/settings'); return;
} }
$errorBag = formErrors(); if (!actionRequireCsrf('admin/settings', 'admin/settings', 'settings_tokens_revoke')) {
if (!Session::checkCsrfToken()) { return;
$errorBag->addGlobal(t('Form expired, please try again'));
flashFormErrors($errorBag, 'admin/settings', 'settings_tokens_revoke');
Router::redirect('admin/settings');
} }
$apiTokenService = app(\MintyPHP\Service\Auth\ApiTokenService::class); $apiTokenService = app(\MintyPHP\Service\Auth\ApiTokenService::class);

View File

@@ -4,7 +4,6 @@ use MintyPHP\Buffer;
use MintyPHP\Http\SessionStoreInterface; use MintyPHP\Http\SessionStoreInterface;
use MintyPHP\Router; use MintyPHP\Router;
use MintyPHP\Service\Access\TenantAuthorizationPolicy; use MintyPHP\Service\Access\TenantAuthorizationPolicy;
use MintyPHP\Session;
use MintyPHP\Support\Flash; use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard; use MintyPHP\Support\Guard;
@@ -56,9 +55,7 @@ $form = [
]; ];
$ssoUiState = $canManageSso ? $tenantSsoService->buildMicrosoftUiState(0, $form) : []; $ssoUiState = $canManageSso ? $tenantSsoService->buildMicrosoftUiState(0, $form) : [];
if ($request->isMethod('POST') && !Session::checkCsrfToken()) { if ($request->isMethod('POST') && !actionRequireCsrf($createTarget, $createTarget, 'csrf_expired')) {
Flash::error(t('Form expired, please try again'), $createTarget, 'csrf_expired');
Router::redirect($createTarget);
return; return;
} }

View File

@@ -4,7 +4,6 @@ use MintyPHP\Http\SessionStoreInterface;
use MintyPHP\Router; use MintyPHP\Router;
use MintyPHP\Service\Access\TenantAuthorizationPolicy; use MintyPHP\Service\Access\TenantAuthorizationPolicy;
use MintyPHP\Service\CustomField\TenantCustomFieldService; use MintyPHP\Service\CustomField\TenantCustomFieldService;
use MintyPHP\Session;
use MintyPHP\Support\Flash; use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard; use MintyPHP\Support\Guard;
@@ -35,13 +34,11 @@ if (!$decision->isAllowed()) {
$flashScope = 'admin/tenants/edit/' . $tenantUuid; $flashScope = 'admin/tenants/edit/' . $tenantUuid;
$redirect = $flashScope . '?tab=custom_fields'; $redirect = $flashScope . '?tab=custom_fields';
if (!$request->isMethod('POST')) { if (!actionRequirePost($redirect)) {
Router::redirect($redirect);
return; return;
} }
if (!Session::checkCsrfToken()) {
Flash::error(t('Form expired, please try again'), $flashScope, 'tenant_custom_fields_csrf'); if (!actionRequireCsrf($redirect, $flashScope, 'tenant_custom_fields_csrf')) {
Router::redirect($redirect);
return; return;
} }

View File

@@ -4,7 +4,6 @@ use MintyPHP\Http\SessionStoreInterface;
use MintyPHP\Router; use MintyPHP\Router;
use MintyPHP\Service\Access\TenantAuthorizationPolicy; use MintyPHP\Service\Access\TenantAuthorizationPolicy;
use MintyPHP\Service\CustomField\TenantCustomFieldService; use MintyPHP\Service\CustomField\TenantCustomFieldService;
use MintyPHP\Session;
use MintyPHP\Support\Flash; use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard; use MintyPHP\Support\Guard;
@@ -44,14 +43,11 @@ if ($tenantUuid === '') {
$flashScope = 'admin/tenants/edit/' . $tenantUuid; $flashScope = 'admin/tenants/edit/' . $tenantUuid;
$redirect = $flashScope . '?tab=custom_fields'; $redirect = $flashScope . '?tab=custom_fields';
if ((requestInput()->method()) !== 'POST') { if (!actionRequirePost($redirect)) {
Router::redirect($redirect);
return; return;
} }
if (!Session::checkCsrfToken()) {
$errorBag->addGlobal(t('Form expired, please try again')); if (!actionRequireCsrf($redirect, $flashScope, 'tenant_custom_fields')) {
flashFormErrors($errorBag, $flashScope, 'tenant_custom_fields');
Router::redirect($redirect);
return; return;
} }

View File

@@ -4,7 +4,6 @@ use MintyPHP\Http\SessionStoreInterface;
use MintyPHP\Router; use MintyPHP\Router;
use MintyPHP\Service\Access\TenantAuthorizationPolicy; use MintyPHP\Service\Access\TenantAuthorizationPolicy;
use MintyPHP\Service\CustomField\TenantCustomFieldService; use MintyPHP\Service\CustomField\TenantCustomFieldService;
use MintyPHP\Session;
use MintyPHP\Support\Flash; use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard; use MintyPHP\Support\Guard;
@@ -42,13 +41,11 @@ if ($tenantUuid === '') {
$flashScope = 'admin/tenants/edit/' . $tenantUuid; $flashScope = 'admin/tenants/edit/' . $tenantUuid;
$redirect = $flashScope . '?tab=custom_fields'; $redirect = $flashScope . '?tab=custom_fields';
if (!$request->isMethod('POST')) { if (!actionRequirePost($redirect)) {
Router::redirect($redirect);
return; return;
} }
if (!Session::checkCsrfToken()) {
Flash::error(t('Form expired, please try again'), $flashScope, 'tenant_custom_fields_csrf'); if (!actionRequireCsrf($redirect, $flashScope, 'tenant_custom_fields_csrf')) {
Router::redirect($redirect);
return; return;
} }

View File

@@ -5,7 +5,6 @@ use MintyPHP\Http\SessionStoreInterface;
use MintyPHP\Router; use MintyPHP\Router;
use MintyPHP\Service\Access\TenantAuthorizationPolicy; use MintyPHP\Service\Access\TenantAuthorizationPolicy;
use MintyPHP\Service\CustomField\TenantCustomFieldService; use MintyPHP\Service\CustomField\TenantCustomFieldService;
use MintyPHP\Session;
use MintyPHP\Support\Flash; use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard; use MintyPHP\Support\Guard;
@@ -77,9 +76,7 @@ $form = array_merge($tenant, $ssoConfig);
$form['microsoft_enabled'] = $ssoConfig['enabled'] ?? false; $form['microsoft_enabled'] = $ssoConfig['enabled'] ?? false;
$form['ldap_enabled'] = $ldapConfig['enabled'] ?? false; $form['ldap_enabled'] = $ldapConfig['enabled'] ?? false;
if ($request->isMethod('POST') && !Session::checkCsrfToken()) { if ($request->isMethod('POST') && !actionRequireCsrf($editTarget, $editTarget, 'csrf_expired')) {
Flash::error(t('Form expired, please try again'), $editTarget, 'csrf_expired');
Router::redirect($editTarget);
return; return;
} }

View File

@@ -4,7 +4,6 @@ use MintyPHP\Http\SessionStoreInterface;
use MintyPHP\Router; use MintyPHP\Router;
use MintyPHP\Service\Access\UserAuthorizationPolicy; use MintyPHP\Service\Access\UserAuthorizationPolicy;
use MintyPHP\Service\User\UserAccessPdfService; use MintyPHP\Service\User\UserAccessPdfService;
use MintyPHP\Session;
use MintyPHP\Support\Guard; use MintyPHP\Support\Guard;
$session = app(SessionStoreInterface::class)->all(); $session = app(SessionStoreInterface::class)->all();
@@ -15,22 +14,20 @@ Guard::requireLogin();
$authorizationService = app(\MintyPHP\Service\Access\AuthorizationService::class); $authorizationService = app(\MintyPHP\Service\Access\AuthorizationService::class);
$userAccountService = app(\MintyPHP\Service\User\UserAccountService::class); $userAccountService = app(\MintyPHP\Service\User\UserAccountService::class);
$userAccessPdfService = app(UserAccessPdfService::class); $userAccessPdfService = app(UserAccessPdfService::class);
$request = requestInput();
$errorBag = formErrors(); $errorBag = formErrors();
// Support both route param and POSTed uuid (POST avoids exposing uuid in URL/history). // Support both route param and POSTed uuid (POST avoids exposing uuid in URL/history).
$uuid = trim((string) ($id ?? '')); $uuid = trim((string) ($id ?? ''));
if ($uuid === '' && strtoupper((string) (requestInput()->method())) === 'POST') { if ($uuid === '' && $request->isMethod('POST')) {
if (!Session::checkCsrfToken()) { if (!actionRequireCsrf('admin/users', 'admin/users', 'users_access_pdf')) {
$errorBag->addGlobal(t('Form expired, please try again'));
flashFormErrors($errorBag, 'admin/users', 'users_access_pdf');
Router::redirect('admin/users');
return; return;
} }
$uuid = trim((string) (requestInput()->bodyAll()['uuid'] ?? '')); $uuid = trim((string) ($request->bodyAll()['uuid'] ?? ''));
} }
$user = $uuid !== '' ? $userAccountService->findByUuid($uuid) : null; $user = $uuid !== '' ? $userAccountService->findByUuid($uuid) : null;
if (!$user) { if (!$user) {
if (strtoupper((string) (requestInput()->method())) === 'POST') { if ($request->isMethod('POST')) {
$errorBag->addGlobal(t('User not found')); $errorBag->addGlobal(t('User not found'));
flashFormErrors($errorBag, 'admin/users', 'users_access_pdf'); flashFormErrors($errorBag, 'admin/users', 'users_access_pdf');
Router::redirect('admin/users'); Router::redirect('admin/users');

View File

@@ -4,8 +4,6 @@ use MintyPHP\Http\SessionStoreInterface;
use MintyPHP\Router; use MintyPHP\Router;
use MintyPHP\Service\Access\UserAuthorizationPolicy; use MintyPHP\Service\Access\UserAuthorizationPolicy;
use MintyPHP\Service\User\UserAccessPdfService; use MintyPHP\Service\User\UserAccessPdfService;
use MintyPHP\Session;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard; use MintyPHP\Support\Guard;
$session = app(SessionStoreInterface::class)->all(); $session = app(SessionStoreInterface::class)->all();
@@ -24,14 +22,11 @@ if (!$decision->isAllowed()) {
$userAccountService = app(\MintyPHP\Service\User\UserAccountService::class); $userAccountService = app(\MintyPHP\Service\User\UserAccountService::class);
$userAccessPdfService = app(UserAccessPdfService::class); $userAccessPdfService = app(UserAccessPdfService::class);
if (strtoupper((string) (requestInput()->method())) !== 'POST') { if (!actionRequirePost('admin/users')) {
Router::redirect('admin/users');
return; return;
} }
if (!Session::checkCsrfToken()) { if (!actionRequireCsrf('admin/users', 'admin/users', 'csrf_expired')) {
Flash::error(t('Form expired, please try again'), 'admin/users', 'csrf_expired');
Router::redirect('admin/users');
return; return;
} }

View File

@@ -8,7 +8,6 @@ use MintyPHP\Repository\Auth\RememberTokenRepository;
use MintyPHP\Router; use MintyPHP\Router;
use MintyPHP\Service\Access\UserAuthorizationPolicy; use MintyPHP\Service\Access\UserAuthorizationPolicy;
use MintyPHP\Service\CustomField\UserCustomFieldValueService; use MintyPHP\Service\CustomField\UserCustomFieldValueService;
use MintyPHP\Session;
use MintyPHP\Support\Flash; use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard; use MintyPHP\Support\Guard;
@@ -155,9 +154,7 @@ if ($canViewSecurityArtifacts) {
$canManageApiTokens = $canManageApiTokens && $canViewSecurityArtifacts; $canManageApiTokens = $canManageApiTokens && $canViewSecurityArtifacts;
$showApiTokens = $canViewSecurityArtifacts; $showApiTokens = $canViewSecurityArtifacts;
if ($request->isMethod('POST') && !Session::checkCsrfToken()) { if ($request->isMethod('POST') && !actionRequireCsrf($editTarget, $editTarget, 'csrf_expired')) {
Flash::error(t('Form expired, please try again'), $editTarget, 'csrf_expired');
Router::redirect($editTarget);
return; return;
} }