fix: store identification documents of external signers under the file owner - #8368
Conversation
…e owner When an unauthenticated signer uploads an identification document, IdDocsService::addFilesToDocumentFolder() called saveFile() without a userManager. FolderService then had no user id, so the node was written to the unauthenticated appdata folder, while the File row received the owner of the signed file as user_id — the value getPdfByUuid() later uses to look the node up. The document was intact on disk but unreachable from the validation UI (empty viewer, 404 on download). Resolve the owner of the signed file with the same lookup saveFile() already uses for user_id and pass it as userManager, mirroring addIdDocs(). Uploads for a sign request whose owner cannot be resolved keep the current behaviour. Resolves: LibreSign#8364 Assisted-by: Claude Code:claude-opus-5 Signed-off-by: André Maia <andrefnkmm@gmail.com>
vitormattos
left a comment
There was a problem hiding this comment.
The fix looks correct overall. I am requesting one change before merge: please narrow the catch (\Throwable) to the expected exception from FileMapper::getById(), so unexpected failures are not silently converted into the unauthenticated storage fallback.
As a non-blocking follow-up, this bug may be worth an architecture issue. The storage decision needs the correct user context before the node is created, while saveFile() can also infer the owner later from the SignRequest when setting File.user_id. This allowed storage and metadata to disagree.
The amount of setup needed in the new unit tests may be another sign that this responsibility is spread across too many collaborators. It may be worth reviewing this flow separately to see if it can be made harder to misuse and simpler to test.
…cs storage getOwnerOfSignedFile() caught \Throwable, which turned unexpected database or programming errors into the unauthenticated appdata fallback — the same inconsistent state this change is fixing. Catch only the DoesNotExistException documented by FileMapper::getById() and let other failures surface. Add one test for the missing row (falls back, no userManager) and one asserting that an unexpected exception is propagated before saveFile() is reached. Assisted-by: Claude Code:claude-opus-5 Signed-off-by: André Maia <andrefnkmm@gmail.com>
|
Done in 9dd0790: On the follow-up: agreed that the storage decision and |
|
/backport to stable35 |
|
/backport to stable34 |
|
/backport to stable33 |
|
/backport to stable32 |
Resolves: #8364
📝 Summary
When an unauthenticated (external) signer uploads an identification document,
IdDocsService::addFilesToDocumentFolder()calledRequestSignatureService::saveFile()without auserManager.FileService::getNodeFromData()only sets theFolderServiceuser id from that key, so the node was written toappdata_<id>/libresign/unauthenticated/. In the same call,saveFile()setsFile.user_idto the owner of the signed file — andAccountService::getPdfByUuid()later uses thatuser_idto look the node up in the owner's folder, where it never was. Result: intact file on disk, empty viewer and 404 on download in the validation UI.The fix resolves the owner of the signed file with the same lookup
saveFile()already uses foruser_id(SignRequest::getFileId()→FileMapper::getById()→getUserId()→IUserManager::get()) and passes it asuserManager, mirroringaddIdDocs(). If the owner cannot be resolved (no file id, missing row, deleted account) nothing is passed and the current behaviour is kept.IUserManageris appended at the end of the constructor so the change applies to the stable branches, whose constructor differs frommainafter #8336.🧪 How to test
Unit tests in
IdDocsServiceTest:testAddFilesToDocumentFolderStoresFilesUnderTheOwnerOfTheSignedFile— fails onmainwithFailed asserting that null is identical to an object of class IUser, passes with the fix;testAddFilesToDocumentFolderWithoutResolvableOwnerKeepsCurrentBehaviour—userManageris not set when the owner cannot be resolved.Local checks in the devcontainer:
IdDocsServiceTestOK (7 tests, 18 assertions); psalm onIdDocsServiceunchanged (2 pre-existingMissingDependency); php-cs-fixer clean.Manual, as in the issue: enable Require identification documents, request a signature from an email recipient without an account, upload the document as that signer, then as an
approval_groupadmin open it in Documents Validation — the viewer shows the pages and download works. The node now lives in the owner's LibreSign folder.⚙️ API / Back‑end changes
IdDocsServicegains anIUserManagerdependency (container-resolved); no API change🚧 Backport
Bug present on
stable32–stable35; the cherry-pick applies cleanly to all four (checked locally on each branch).Not covered on purpose
✅ Checklist
🤖 AI (if applicable)