Skip to content

{2.x] feat(gdpr): port confirmation token invalidation, IP logging and IP purge#4423

Merged
imorland merged 4 commits into2.xfrom
im/gdpr-port-confirmation-security
Mar 8, 2026
Merged

{2.x] feat(gdpr): port confirmation token invalidation, IP logging and IP purge#4423
imorland merged 4 commits into2.xfrom
im/gdpr-port-confirmation-security

Conversation

@imorland
Copy link
Member

@imorland imorland commented Mar 8, 2026

Summary

Ports flarum/gdpr PR #70 (1.x) to 2.x. No controller API layer changes were needed — the existing PSR-7 RequestHandlerInterface and Illuminate\Console\Command patterns are identical between versions.

  • Token invalidationverification_token is set to null on confirmation so the email link is a true one-time link
  • Processed-request guard — re-visiting a confirmation link for a processed or manual request returns 422 instead of silently resetting its status
  • Confirmation IP logging — the confirming client's IP (via $request->getAttribute('ipAddress')) is stored in a new confirmation_ip column on gdpr_erasure
  • 90-day IP purge — new gdpr:clear-confirmation-ips console command (scheduled daily) nulls confirmation_ip on records where user_confirmed_at is older than 90 days
  • Modal timestampsProcessErasureRequestModal now shows requested-at, confirmed-at, and eligible-for-auto-processing dates; ErasureRequestsList shows userConfirmedAt as the datetime

Test plan

  • Run vendor/bin/phpunit tests/integration/forum/ConfirmErasureTest.php — all tests pass including new token nullification, IP storage, and processed/manual guard tests
  • Run vendor/bin/phpunit tests/integration/console/ClearConfirmationIpsTest.php — all tests pass
  • Verify visiting a confirmation URL a second time returns 404 (token nullified)
  • Verify visiting a confirmation link for a processed request returns 422
  • Run php flarum gdpr:clear-confirmation-ips and verify IPs older than 90 days are cleared from DB
  • Verify php flarum schedule:list shows the new command scheduled daily
  • Build frontend and verify modal displays requested/confirmed/eligible timestamps

Closes #4419

🤖 Generated with Claude Code

…urge (#4419)

Ports flarum/gdpr PR #70 (1.x) to 2.x:

- Token invalidation: verification_token set to null on confirmation, making email links true one-time links
- Processed-request guard: re-visiting a confirmation link for a processed/manual request returns 422
- Confirmation IP logging: client IP stored in new confirmation_ip column on gdpr_erasure
- 90-day IP purge: new gdpr:clear-confirmation-ips console command (scheduled daily) nulls confirmation_ip on records where user_confirmed_at is older than 90 days
- Modal timestamps: ProcessErasureRequestModal now shows requested-at, confirmed-at, and eligible-for-auto-processing dates

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@imorland imorland requested a review from a team as a code owner March 8, 2026 20:42
Extract createdAt/userConfirmedAt to local consts so TypeScript's
truthiness narrowing resolves Date | null | undefined to Date, avoiding
any non-null assertions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@imorland imorland changed the title feat(gdpr): port confirmation token invalidation, IP logging and IP purge {2.x] feat(gdpr): port confirmation token invalidation, IP logging and IP purge Mar 8, 2026
@imorland imorland added this to the 2.0.0-beta.8 milestone Mar 8, 2026
imorland and others added 2 commits March 8, 2026 22:02
gdpr_erasure has a unique constraint on user_id. Each test fixture row
needs a distinct user.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@imorland imorland merged commit 838d8d7 into 2.x Mar 8, 2026
27 checks passed
@imorland imorland deleted the im/gdpr-port-confirmation-security branch March 8, 2026 21:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[2.x] gdpr: port confirmation token invalidation, IP logging and IP purge

1 participant