Prove WHOSE signature Finish counts, and report the live one

FixDocsService
Shipped
August 6, 2026 at 7:20 PM UTC
Author
Kamo
Commit
593ffe7

verify() compared the caller to assignment.teamMemberId but never to the ENVELOPE RECIPIENT's member — it trusted the recipientUid the delivery fan-out wrote. A mis-bound uid (a delivery bug, a reused envelope, a hand-repaired row) would let one employee's WORM attestation rest on a colleague's signature, on a row whose entity refuses updates. The recipient's own memberId is now carried back by LegalEsignClient and asserted. Absence does NOT refuse: ESigService omits memberId for an external signer and a build predating the field omits it for everyone, so a deploy-order skew must not become "nobody can finish a package". Fail open on unknown, closed on wrong. LegalAssignmentDocumentDto gains recipientStatus, populated by the new LegalMemberRecipientStatus. Nothing in this service writes SIGNED or ACKNOWLEDGED to a document row before finish() does, so the row alone reports every document a member signed yesterday as outstanding; the wizard then re-opens a signing session and EsignPublicService.submit answers 409 "Recipient already signed", permanently. It is a separate component called by the controller, not two lines inside detail(): that method is transactional AND writes, and N outbound calls inside it would hold a write transaction across every timeout — while a non-transactional wrapper on the same bean would be self-invocation and silently lose the annotation. LegalClientIp.isIpLiteral was a character-class check, so "1.2.3.4.5" passed and InetAddress.getByName resolved it as a HOSTNAME — an outbound DNS query, on the request path, for a name the client writes into a header. It now counts groups and ranges. And an over-long sourceIp is recorded as NULL rather than truncated: 45 characters is the longest textual IP there is, so anything longer is not an address, and its first 45 characters would read as a real one forever.

All changes

Like what you see shipping?

Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.

Start Free ForeverView Pricing