nexo-pairing
Phase 26 — pairing protocol primitives for Nexo. DM-challenge gate for inbound allowlisting + setup-code issuer (HMAC-signed bootstrap tokens + QR rendering) for hands-off companion-app pairing.
This crate is part of Nexo — a multi-agent Rust framework with a NATS event bus, pluggable LLM providers (MiniMax, Anthropic, OpenAI-compat, Gemini, DeepSeek), per-agent credentials, MCP support, and channel plugins for WhatsApp, Telegram, Email, and Browser (CDP).
- Main repo: https://github.com/lordmacu/nexo-rs
- Runtime engine:
nexo-core - Public docs: https://lordmacu.github.io/nexo-rs/
What this crate does
DM-challenge gate (opt-in inbound allowlist)
PairingStore— SQLite-backed;pairing_pending(TTL 60 min) +pairing_allow_from(durable, soft-delete on revoke).PairingGate::should_admit— consulted on the runtime intake hot path; withauto_challenge: truean unknown sender gets a one-time human-friendly code and the operator approves vianexo pair approve.PairingChannelAdaptertrait + per-channel impls for WhatsApp + Telegram. Normalises sender ids (+5491155556666@c.us→+5491155556666) so cache keys match the canonical form, and delivers challenge messages through the channel's outbound topic.PairingAdapterRegistry—channel_id → Arc<dyn PairingChannelAdapter>lookup the runtime owns.
Setup-code (operator-initiated)
SetupCodeIssuer::issue— HMAC-signed bootstrap token- URL packed into a base64url payload. Companion app
decodes via
decode_setup_code.
- URL packed into a base64url payload. Companion app
decodes via
- QR rendering — text (
render_ansi) for terminals + PNG (render_pngbehind theqr-pngfeature) for hands-off scanning. - Token expiry — short-lived (60s default, configurable
via
pairing.yaml); claim-sideexpires_atbaked into the JWT-shaped token so a leaked code can't be replayed. - URL resolver — priority chain (
--public-url→pairing.yaml→NEXO_TUNNEL_URL→$NEXO_HOME/state/ tunnel.urlsidecar → loopback fail-closed). Cleartextws://only on hosts in the allow-list (loopback, RFC1918, link-local,.local,10.0.2.2).
Telemetry
pairing_requests_pending{channel}gaugepairing_approvals_total{channel,result}counterpairing_codes_expired_totalcounterpairing_bootstrap_tokens_issued_total{profile}counterpairing_inbound_challenged_total{channel,result}counter
Public API
;
;
;
Configuration
# config/pairing.yaml (optional; absent = legacy hardcoded paths)
pairing:
storage:
path: /var/lib/nexo/pairing/pairing.db
setup_code:
secret_path: /var/lib/nexo/pairing/pairing.key
default_ttl_secs: 600
public_url: wss://nexo.example.com/pair
ws_cleartext_allow:
- kitchen-pi.local
Install
[]
= "0.1"
Disable PNG rendering if only text QR is needed:
= { = "0.1", = false }
Documentation for this crate
License
Licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE)
- MIT license (LICENSE-MIT)
at your option.