feat: invalidate confirmation token, log IP, purge IP after 90 days#70
Merged
Conversation
…fter 90 days - Null verification_token on confirmation so email links cannot be reused - Guard against re-confirming already-processed requests (422) - Store confirmation_ip (from Flarum ipAddress request attribute) for audit trail - New gdpr:clear-confirmation-ips command purges stored IPs after 90 days (scheduled daily) - ProcessErasureRequestModal shows requested/confirmed/eligible-at timestamps - Update tests and README Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ue constraint violation Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
7 tasks
imorland
added a commit
that referenced
this pull request
Mar 12, 2026
…d IP purge (#4423) * feat(gdpr): port confirmation token invalidation, IP logging and IP purge (#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> * fix(gdpr): use local variable narrowing to satisfy humanTime Date type 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> * chore: fix test * fix(gdpr): use unique user_ids per erasure request in test fixtures 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> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
verification_tokenis set tonullwhen a user confirms their erasure request, so the email link becomes a true one-time link and cannot re-confirm an already-processed request.processedormanualrequest returns 422 instead of silently resetting its status.ipAddressrequest attribute) is stored in a newconfirmation_ipcolumn ongdpr_erasurefor audit purposes.gdpr:clear-confirmation-ipsconsole command (scheduled daily) nullsconfirmation_ipon records whereuser_confirmed_atis older than 90 days, keeping retention proportionate.ProcessErasureRequestModalnow shows requested-at, confirmed-at, and eligible-for-auto-processing dates.Changes
migrations/2026_03_06_000000_add_confirmation_ip_to_gdpr_erasure_table.php— new nullableconfirmation_ipcolumnsrc/Http/Controller/ConfirmErasureController.php— token nulled, IP recorded, processed-request guard addedsrc/Models/ErasureRequest.php—confirmation_ipproperty docblocksrc/Console/ClearConfirmationIps.php— new scheduled commandextend.php— registers and schedulesClearConfirmationIpsjs/src/forum/components/ProcessErasureRequestModal.tsx— timestamps sectionjs/src/forum/components/ErasureRequestsList.js— fixed[object Object]tooltip (was passing vnode toTooltip text, now usesdayjs().format('LLLL'))resources/locale/en.yml— three newprocess_erasurekeystests/integration/forum/ConfirmErasureTest.php— token-null and IP assertions; processed-request guard testtests/integration/console/ClearConfirmationIpsTest.php— new test fileTest plan
verification_tokenisnull,confirmation_ipis setphp artisan gdpr:clear-confirmation-ips→ IPs older than 90 days are cleared, recent ones retained🤖 Generated with Claude Code