fix: clone public identity fields before cross-frame signer handoff

This commit is contained in:
archipelago
2026-10-05 21:11:03 -04:00
parent 041f1fa2d3
commit 6f098cd9c2
4 changed files with 108 additions and 3 deletions
+42
View File
@@ -0,0 +1,42 @@
# IndeeHub native signer follow-up
## Reproduced on Yaya
The installed app and dashboard have the same provider SHA256
`529fe82e7c16b51c62678427f565048c3dd93ca28320bd8494c17236ff57bb81`.
A clean mobile Chromium session opens the identity picker. After selecting the
existing profile and Authenticate, the picker disappears but the broker stays
full-screen (`aria-hidden=false`, 390 by 844). Its document has no visible text
or buttons, and the app still shows Sign In. The trace contains signer-ready and
signer-show but no signer-identity or signer-hide through 18 seconds.
The picker emits an entry from a Vue reactive array. NostrTabSigner passes that
proxy object directly to cross-frame postMessage after hiding the picker.
Structured cloning rejects reactive proxies, interrupting the handoff before
it schedules the broker hide. Reload uses the already-serialized identity from
localStorage, explaining why refresh can appear to repair the problem.
## Candidate fix
Send an explicit plain object containing only the selected public identity
fields. The private signer remains on the node; unrelated metadata is excluded.
Consent behavior and the existing green completion animation are unchanged.
A regression uses a real Vue reactive identity and structuredClone, verifies
that the proxy itself is rejected, the public handoff is cloneable, metadata is
excluded, and the overlay closes. Eleven focused signer/provider tests pass,
and frontend typecheck passes. A browser qualification using candidate dashboard
assets with the actual Yaya app/auth backend is in progress. No deployment or
actual companion acceptance is claimed yet.
## App source and further review
The canonical app is the Vite/Vue source in the separate IndeeHub repository,
not the obsolete Next.js Dockerfile under apps/indeedhub. Its existing local
nginx edit and untracked workflow documentation were preserved; new app work
uses a separate worktree.
Review found additional app-side concerns to test: production network failures
can flip the app into mock mode and fabricate subscribed users, and the header
can discard a valid backend Nostr session when the local signer account has not
been restored. Do not claim these repaired by the broker object-cloning fix.
@@ -101,3 +101,23 @@ nodes before further restarts: only Shorty had an affected message store at the
expected paths; its bytes were verified after backup. No message contents or
wallet data were exported. Actual candidate build/deployment and store reload
acceptance still remain; do not equate source-test success with delivery.
## Production storage candidate qualification
The cfd9a596 production binary (SHA256
3d720c6ddb2622ddef956b5ef0d54ecef64617e4bd16d07327b55ac737d00fe7)
was exercised in the disposable installed-system VM. Independent Python
ChaCha20-Poly1305 fixtures used the guest's key locally, without exporting it.
Encrypted nonces starting with `{` and `[` loaded through the real message RPC,
retained their exact ciphertext, and survived a second service restart. Legacy
JSON with leading whitespace migrated to authenticated ciphertext and survived
another restart with all message fields intact.
Fixture corrections were required: the first root-owned 0600 file was unreadable
by the service; the next legacy assertion omitted optional fields that serde
normally emits as null. Both initial failures remain in the qualification logs.
The corrected run passed all three data cases. SSH disconnected during final
cleanup, so restoration was completed as a guest systemd job and independently
checked: original 560aa600 backend, active service, and original absent message
store restored. The VM was then shut down. This is not live-fleet deployment or
proof of every corrupt-store recovery path.