Files
api/services/nginx/app/routes/intimidateRoute.php
T
Jeppe B 0060fb45ca Add in-app account deletion (#319)
## Summary
- Add self-service deletion for the authenticated customer or subuser
identity only.
- Preserve shared customer grants, reset keys, bookings, order bookings,
vehicles, invoices, and legally required history.
- Require password/TOTP or a fresh deletion-specific, five-minute,
single-use WebAuthn assertion.
- Reject support impersonation and expired legacy plain-session tokens.
- Use durable database throttling, transactional request processing, a
durable outbox, and terminal `manual_review` state.
- Keep API and worker default-off behind separate
`account_deletion.api_enabled` and `account_deletion.worker_enabled`
module-config flags.

## Safe rollout
1. Keep both flags disabled.
2. Run `php scripts/account-deletion-schema.php check`.
3. If needed, run `php scripts/account-deletion-schema.php apply --yes`,
then rerun `check` until `ready:true`.
4. Deploy the frontend companion PR while the API remains disabled.
5. Enable `api_enabled` for a controlled canary; verify password and
passwordless request flows plus immediate authentication revocation.
6. Inspect queued request/outbox state, then enable `worker_enabled`.
7. Verify anonymization, preserved tenant/history data, outbox delivery,
retries, and manual-review behavior before broad rollout.

## Verification
- Account deletion unit tests: 2 passed, 43 assertions.
- PHP lint, both OpenAPI YAML parses, runtime-DDL scan,
destructive-scope scan, and `git diff --check` passed.
- Full API/unit/integration evidence is required from exact-head CI;
local Docker is unavailable and shared-vendor tests were explicitly
discarded.

## Security notes
- Schema mutation is CLI-only; web and cron paths perform read-only
readiness checks.
- Runtime behavior fails closed when schema/config/throttle/delivery
prerequisites are unavailable.
2026-07-22 19:22:17 +02:00

47 lines
1.6 KiB
PHP

<?php
namespace routes;
use classes\authentication;
use objects\logs_o;
use objects\users_o;
use traits\route_t;
class intimidateRoute
{
use route_t;
public function run(): void
{
$this->post('/su/intimidate', function () {
// Get the post data
global $response;
// Make sure the user has the SUPERUSER_INTIMIDATE permission
$this->requirePermission('SUPERUSER_INTIMIDATE');
// Get the user object
$user = (new authentication())->get_user();
// Get the post data
$data = json_decode(file_get_contents('php://input'), true);
// Check if the customer number, and password are set
if (!isset($data['user_id'])) {
$response->error('User id is required', 400);
}
// Get the user object
$intimidated_user = (new users_o())->getUserById($data['user_id']);
// Log the incident
(new logs_o())->add('auth', 'global', 1, $user->id, 'AUTH_SUCCESS_INTIMIDATE', 'Created intimidate token for customer: ' . $data['user_id']);
// If the credentials are valid, create a token (We're using the create_employee_token, since it's using user_id, and not customer_numbers.)
$token = (new authentication())->create_impersonation_token(
(int)$data['user_id'],
(int)$user->id
);
// Return the token
$response->success(['token' => $token]);
},
[
'SUPERUSER_INTIMIDATE' => 'Intimidate a user'
]
);
}
}