Skip to content

feat: portable identity export/import between River UI and riverctl#137

Merged
sanity merged 4 commits intomainfrom
identity-export
Mar 6, 2026
Merged

feat: portable identity export/import between River UI and riverctl#137
sanity merged 4 commits intomainfrom
identity-export

Conversation

@sanity
Copy link
Contributor

@sanity sanity commented Mar 6, 2026

Summary

Adds a portable identity bundle that lets users transfer their room identity (signing key + membership proof) between the River UI and riverctl, or between different devices.

Problem

There was no way to use the same identity across River clients. A user who joined via the UI couldn't use riverctl for the same room, and vice versa. (Issue #136)

Approach

New IdentityExport struct in common/

  • Contains: signing key, AuthorizedMember, invite chain, optional MemberInfo (nickname)
  • PEM-like armored encoding (CBOR → base58, wrapped in -----BEGIN/END RIVER IDENTITY-----)
  • Validates that signing key matches authorized member on decode
  • ~400-800 character token, easily copyable

riverctl identity export/import

  • riverctl identity export <room_key> — exports armored token to stdout
  • riverctl identity import --token <token> or --file <path> or stdin
  • Import fetches fresh room state from network and stores everything locally

UI Export/Import

  • Export button in members panel → modal with copyable armored token
  • Import button → modal with paste area, validates and adds room on import

Testing

  • 3 unit tests for IdentityExport: roundtrip encoding, key mismatch rejection, whitespace handling
  • cargo test -p river-core -p riverctl — all pass
  • cargo fmt / cargo clippy — clean
  • UI code compiles cleanly (only errors are missing build artifacts in worktree)

Notes

  • Does NOT affect delegate WASM or contract WASM — no migration needed
  • Private room secrets are NOT included in the bundle — the importing client gets them via the existing ECIES distribution on subscription

Closes #136

[AI-assisted - Claude]

sanity and others added 4 commits March 6, 2026 13:03
Add IdentityExport struct in common/ with PEM-like armored encoding
(CBOR + base58 with -----BEGIN/END RIVER IDENTITY----- markers).

The bundle includes:
- Signing key (private)
- AuthorizedMember (signed membership proof)
- Invite chain (for rejoin after pruning)
- MemberInfo (nickname)

Changes:
- common/src/room_state/identity.rs: IdentityExport with armored
  encode/decode and validation (key must match authorized member)
- cli/src/commands/identity.rs: `riverctl identity export/import`
- ui/src/components/members.rs: Export/Import Identity buttons and
  modals in the members panel

Closes #136

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Validate AuthorizedMember and invite chain signatures on import
  (verifies against owner key and chain member keys)
- Add tests: invite chain roundtrip, member_info roundtrip, tampered
  signature rejection, truncated token, empty token, imported key signing

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add warning text in export modal that token contains private key
- Clear token_text signal when export modal is closed (both backdrop and button)
- Add stderr warning in CLI export command for human output format

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adding identity.rs to common/ changes the delegate WASM hash. Add the
current delegate's key and code_hash to LEGACY_DELEGATES so existing
users' secrets are migrated to the new delegate.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@sanity sanity merged commit c2dd6f4 into main Mar 6, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: portable identity export/import between River UI and riverctl

1 participant