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_approval endpoint.

    • 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 WriteApiSmokeTest passed.

    • 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_approval and approval-specific finalization using the existing detached-signature verifier.

    • Valid approvals now commit the canonical reply and adjacent .asc signature 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 WriteApiSmokeTest passed.

    • 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.js passed.

    • BrowserSigningNormalizationTest::testApprovalSigningPreparesSignsAndFinalizesCanonicalApproval passed, confirming the prepare and finalize payloads and detached-signature submission.

  • Notes:

    • The existing BrowserSigning suite has unrelated merged-test mock failures caused by missing querySelectorAll stubs, 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 WriteApiSmokeTest passed.

    • 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 WriteApiSmokeTest passed.

    • 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.