Allow document owners to invite external users (no Stirling-PDF account)
to sign documents via a one-time share link.
Backend:
- GuestCertificateService: generates ephemeral PKCS12 keystores keyed by
email, with rfc822Name SAN for industry-traceable digital signatures;
uses emailProtection EKU, cryptographically random serial numbers, and
HMAC-SHA256 derived passwords
- SigningFinalizationService: handles GUEST_CERT case in buildKeystore()
and getKeystorePassword()
- WorkflowParticipantController: defaults certType to GUEST_CERT for
unregistered participants, captures hashed-IP audit trail on submission,
skips password encryption for GUEST_CERT paths
- WorkflowSessionService: sends signing invitation email to guest
participants on session creation; redacts email PII in logs
- EmailService: adds sendSigningInvitationEmail() with HTML-escaped
user-supplied values and javascript: URL guard to prevent XSS
Frontend:
- GuestSignPage: new token-gated route /sign/:token outside AppProviders;
full page-state machine (loading/ready/expired/signed/declined/error)
- GuestCertificateChooser: auto-generated cert vs upload P12 chooser
- SelectParticipantsStep: refactored to support registered + external
(email) participants via tabbed UI with validation
- AddParticipantsFlow: same external email tab added for mid-session adds
- CreateSessionFlow/SignPopout: thread new Participant[] shape through
to split userIds and emails on submit
- App.tsx: /sign/:token route with minimal GuestSigningProviders (no auth)
- i18n: [guestSigning] keys added to en-GB/translation.toml
Tests:
- GuestCertificateServiceTest: keystore generation, SAN, deterministic passwords
- WorkflowParticipantControllerTest: GUEST_CERT defaulting, audit trail,
token guards, encrypt() not called for guest cert
- EmailServiceTest: invitation email, HTML injection safety, JS URL guard
- GuestSignPage.test.tsx: 9 vitest unit tests (all page states + submit)
- SelectParticipantsStep.test.tsx: 15 vitest unit tests
- GuestSigningE2E.spec.ts: 19 Playwright E2E tests (route-mocked, no backend)
- playwright.config.ts: fix testDir to src/core/tests, use port 5174