Signing keypair enrolment (silent; enforces nothing) #39
Labels
No labels
area:docs
area:identity
area:ops
area:plugin
area:server
channel:community
channel:direct
channel:owned
channel:press
channel:social
e2ee-constrained
gate:at-ga
gate:pre-ga
marketing
parity
relay:absent
relay:planned
relay:requested
relay:supported
risk:additive
risk:contract
risk:none
usability
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Nectenda/nectenda#39
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Part of #37.
What Relay does
"Advanced permissions — granular read/write controls at folder level" is
Active on their roadmap (read 21 Sep 2026), tracking their issue #26, open
since 2025. They do not ship it: their docs state read-only access is
unsupported, and
enableReaderRoleinsrc/flags.tsdefaults tofalse.What we do today
No read-only membership.
docs/sync-limitations.md:555records that aviewerrole was built and removed — the editor half worked, but Obsidian offers no
cancellable file-operation hook, so a viewer could still delete files from the
explorer and the deletion would propagate.
That same section sketches the E2EE-compatible answer: sign each update with
the author's identity key so the relay refuses a non-writer's write without
decrypting anything.
Why enrolment is separate from enforcement
This issue is enrolment only. It ships a signing key to every device and
enforces nothing. That matters because it removes the deadline: once every
device carries a signing key, enforcement can be switched on per folder whenever
someone wants it, with coverage already in hand.
And enrolment can be silent. The master key is cached per-device in the OS
credential store, not merely per session (
docs/security-model.md: "Your key iskept for the device, not just the session";
main.ts:613,main.ts:1801). So asigned-in device can generate a signing keypair, wrap the private half under the
master key it already holds, and upload the public half with no passphrase
prompt and no user-visible step. A device with no credential store migrates the
next time it asks for the passphrase anyway.
This is why the product does not need to be taken offline.
What changes, and the two traps
It must be a second keypair.
packages/shared/src/crypto.ts:254:ECDH with
deriveBitscannot sign. So: a newsigning_public_keycolumn, asecond wrapped private key, and changes to
EnrollKeysRequest,ReplaceCredentialsRequestand the recovery flow.Recovery must preserve it byte-for-byte.
docs/sync-limitations.mdrecordsthat recovery deliberately preserves the identity keypair so shared folders
survive a password reset. The signing key needs identical treatment, or a
password reset silently invalidates every signature the user ever made.
Risk
risk:contract. The wire change is additive andMIN_PLUGIN_VERSION(
config.ts:169, enforced atws-server.ts:370withWS_CLOSE_UPDATE_PLUGIN)already exists as a floor mechanism. What changes is the account contract: every
account acquires a signing key. Silent today; a forced passphrase-flow migration
if left until the user base is large.
Verification
identity keypair. Both tests fail when inverted.
case before changing anything, and update
docs/sync-limitations.md.Moved to the Vikunja board as NEC-16: https://projectron.nerchure.com/tasks/16