@invisra/rendezvous-cli
v0.1.2
Published
CLI client for pinging a Rendezvous protected endpoint: fetch the current message or publish a new one.
Readme
@invisra/rendezvous-cli
A command-line client for a Rendezvous protected endpoint: generates the current HOTP/TOTP codes and either fetches the message or publishes a new one. Built on @invisra/rendezvous-core; works against any Rendezvous-compatible server, including apps/fastapi (the Python reference app), since both implement the same HOTP/TOTP scheme.
Install
Within this monorepo:
npm install
npm run build --workspace=@invisra/rendezvous-core
npm run build --workspace=@invisra/rendezvous-cli
node apps/cli/dist/index.js getOnce published, install it globally:
npm install -g @invisra/rendezvous-cli
rendezvous getConfiguration
Reads BASE_URL, HOTP_SECRET, TOTP1_SECRET, and TOTP2_SECRET from the environment by default; each has a matching flag (--base-url, --hotp-secret, --totp1-secret, --totp2-secret) that overrides it.
Usage
Fetch the current message:
rendezvous getPublish a new message:
rendezvous post "already-encrypted-message"
# from a file
rendezvous post --file message.txt
# from stdin
echo "already-encrypted-message" | rendezvous postOptional: end-to-end encryption
If the deployment owner has configured a /key endpoint (see apps/web or apps/fastapi), you can encrypt client-side instead of sending plaintext:
# Fetch and cache the server's public key (default: ~/.rendezvous/key.pub)
rendezvous key install
# Encrypt to the installed key before posting
rendezvous post --encrypt "the actual secret"Decrypting requires the deployment owner's private key — only they have it, which is the point:
rendezvous get --decrypt --private-key "AGE-SECRET-KEY-1..."
# or: MESSAGE_PRIVATE_KEY=AGE-SECRET-KEY-1... rendezvous get --decryptThis is a one-way dead-drop, not mutual encryption: anyone who ran key install can encrypt a message, but only the private-key holder can read anything, including messages they encrypted themselves.
Threads (multi-user admin/reply model)
The commands above talk to a single shared secret for the whole deployment. If the server also supports the thread model (see "Threads" in apps/web or apps/fastapi), each admin↔user conversation gets its own independently derived secrets — nobody, including the server operator, needs to share a single long-lived secret across every conversation.
As the admin
# One-time setup: generates your identity keypairs and a local, password-encrypted
# SQLite database (~/.rendezvous/admin.db by default). Prints the values to deploy
# on the server (MESSAGE_PUBLIC_KEY, ADMIN_API_KEY) and the value to hand out to
# thread users (ADMIN_THREAD_PUBLIC_KEY).
rendezvous admin init --base-url https://your-deployment.example --password "correct horse battery staple"
# Create a thread once a user has sent you their THREAD_PUBLIC_KEY and
# MESSAGE_PUBLIC_KEY (from `rendezvous identity create`, below). Prints a join
# code — send that to the user over whatever channel you already trust.
#
# Use --flag=value (not --flag value) for the key options: these are
# base64url-encoded and can legitimately start with "-", which a
# space-separated value would get misparsed as another flag.
rendezvous admin thread create \
--user-thread-key="<their-thread-public-key>" \
--user-message-key="<their-message-public-key>" \
--description "Jane, re: the Q3 filing" \
--password "correct horse battery staple"
rendezvous admin thread list --password "correct horse battery staple"
rendezvous admin messages <threadId> --password "correct horse battery staple"
rendezvous admin reply <threadId> "got it, thanks" --password "correct horse battery staple"
# Revoke a thread — e.g. the user's device was lost or compromised. This
# permanently deletes the thread and its messages server-side, so its codes
# stop working immediately; idempotent, and marks the thread revoked in
# your local record (rendezvous admin thread list will show it) rather
# than deleting that local record.
rendezvous admin thread revoke <threadId> --password "correct horse battery staple"
# If your API key leaks, rotate it: this updates the local database only —
# you still have to redeploy the server with the printed value yourself.
# The old key keeps working until you do.
rendezvous admin rotate-key --password "correct horse battery staple"Back up your admin database. ~/.rendezvous/admin.db holds your only copies of your message and thread private keys — lose it and you permanently lose the ability to decrypt past thread messages or reply on existing threads. Back it up regularly:
rendezvous admin export --password "correct horse battery staple" --output admin-backup.json
# ...disk failure, wiped laptop, etc...
rendezvous admin import admin-backup.json --db ~/.rendezvous/admin.dbThe export is JSON but still password-encrypted — treat the file exactly as carefully as admin.db itself. import refuses to overwrite an existing file. Both admin.db and its exports are cross-language compatible: a database (or backup) created here can be opened by apps/cli-py (the Python client) with the same password, and vice versa.
--password can also be set via RENDEZVOUS_ADMIN_PASSWORD to keep it off the command line/shell history. Private keys and the database password never leave ~/.rendezvous/admin.db; only MESSAGE_PUBLIC_KEY and ADMIN_API_KEY need to be deployed to the server.
As a thread user
# One-time setup: generates your identity keypairs, saved to
# ~/.rendezvous/config.json by default. Prints the two public keys to send
# to whoever will create a thread with you.
rendezvous identity create
# Once the admin sends you a join code:
rendezvous identity join <the-join-code>
rendezvous identity threads
# Talk on the thread:
rendezvous post --thread <threadId> --encrypt "the actual message"
rendezvous get --thread <threadId> --decrypt--encrypt/--decrypt on --thread commands use the keys exchanged via the join code (the admin's message key to encrypt posts, your own message key to decrypt replies) — no separate key install step needed for threads.
Development
npm run build --workspace=@invisra/rendezvous-core
npm run typecheck --workspace=@invisra/rendezvous-cli
npm run test --workspace=@invisra/rendezvous-cliOne-hour invitation codes
Set RENDEZVOUS_BASE_URL=https://invisra.ai/rendezvous for short-code joins.
rendezvous admin invite create --password "..."
rendezvous identity join ABCD-EFGH
rendezvous admin invite approve ABCD-EFGH --password "..." --description "..."
rendezvous identity join ABCD-EFGH --claim-token "<token printed by the claim>"Codes use an unambiguous eight-character alphabet, expire after one hour, and can be claimed once. The claim token is independent high-entropy proof needed to finish. Existing encoded join codes remain supported.
