Repository source: docs/plans/archive/signed_user_approvals_step4_implementation_summary.md
Signed User-to-User Approvals — Step 4: Implementation Summary
Stage 1 - Prepare canonical approval replies
Changes:
Added a signed-approval preparation contract and
/api/prepare_approvalendpoint.The endpoint applies existing approver, self-approval, target, and approval-state checks, then returns a short-lived canonical approval reply without writing it.
Verification:
php tests/run.php WriteApiSmokeTestpassed.Coverage confirms prepared replies contain the expected approval fields, do not create a post or approval, and reject unapproved/self approvers.
Notes:
Stage 2 will verify the detached signature and make the paired record/signature write atomic.
Stage 2 - Verify and finalize signed approvals
Changes:
Added
/api/create_prepared_approvaland approval-specific finalization using the existing detached-signature verifier.Valid approvals now commit the canonical reply and adjacent
.ascsignature together, then use the existing approval-derived-state refresh and invalidation path.Invalid signatures leave the prepared record available for retry without creating a post or changing approval state.
Verification:
php tests/run.php WriteApiSmokeTestpassed.A generated signing key produced a valid approval signature; the test confirms the paired commit, target approval, and cleanup of the prepared token after success.
The same prepared approval with an invalid signature creates no record and leaves the target unapproved.
Notes:
Stage 3 will reuse the existing browser signing facilities to drive these two endpoints from the browser.
Stage 3 - Shared browser approval signing
Changes:
Added
ForumBrowserSigning.submitSignedApproval(), which prepares an approval, verifies the local identity matches the prepared record, signs that exact canonical record, and finalizes it through the signed approval endpoint.Added approval-specific signature failure wording while preserving the existing browser-key and OpenPGP validation behavior.
Verification:
node --check public/assets/browser_signing.jspassed.BrowserSigningNormalizationTest::testApprovalSigningPreparesSignsAndFinalizesCanonicalApprovalpassed, confirming the prepare and finalize payloads and detached-signature submission.
Notes:
The existing BrowserSigning suite has unrelated merged-test mock failures caused by missing
querySelectorAllstubs, plus its pre-existing reaction-handler failures; Stage 4 consumes the new helper rather than changing those unrelated tests.
Stage 4 - Signed profile and pending-user approvals
Changes:
Loaded the OpenPGP and shared browser-signing assets on profile and pending-user approval pages.
Wired both controls through the shared signed approval helper, with progress, duplicate-submission prevention, error feedback, and profile success navigation.
Changed legacy direct approval API and form submissions to return a browser-signature-required error instead of writing an unsigned approval.
Verification:
php tests/run.php WriteApiSmokeTestpassed.Render coverage confirms both approval surfaces load the signing assets and the profile form exposes the signed-approval contract.
The legacy API test confirms an unsigned request leaves the pending user in place.
Notes:
Stage 5 will verify that signed approvals appear with their signature and signing key through the existing source and activity displays.
Stage 5 - Audit signed approvals through existing views
Changes:
Added end-to-end regression coverage for a real signed approval across the post page and both approval activity views.
Reused existing source metadata and shared activity manifest presentation without new display components.
Verification:
php tests/run.php WriteApiSmokeTestpassed.The test confirms the approval post links its adjacent signature and author public key, while Classic and Forte Activity show the signing identity and public-key link.
Notes:
Approval seeds remain unchanged trust anchors and are not expected to carry user signatures.