# synckit-client End-to-end encrypted cloud sync SDK for Rust applications, built for the [MNW SyncKit](https://makenot.work) server. All row data and binary blobs are encrypted client-side (XChaCha20-Poly1305) before leaving the device. The server only ever stores ciphertext. ## Features - **E2E encryption** -- XChaCha20-Poly1305 with Argon2id key derivation (64 MB, 3 iterations) - **OS keychain integration** -- master key cached in macOS Keychain, Linux secret-service, or Windows Credential Manager - **Blob encryption** -- binary files encrypted with fixed 40-byte overhead (no base64 expansion) - **Retry with backoff** -- transient failures (network, 5xx, 429) retried up to 3 times with exponential delay - **OAuth2 PKCE** -- browser-based auth flow alongside email/password - **Token expiry detection** -- client-side JWT check with 30-second buffer ## Quick Start ```rust use synckit_client::{SyncKitClient, SyncKitConfig, ChangeEntry, ChangeOp}; use chrono::Utc; let client = SyncKitClient::new(SyncKitConfig { server_url: "https://makenot.work".into(), api_key: "your-api-key".into(), }); // Authenticate let (user_id, app_id) = client.authenticate("user@example.com", "password").await?; // Set up encryption (first device) client.setup_encryption_new("password").await?; // Register this device let device = client.register_device("MacBook Pro", "macos").await?; // Push encrypted data let cursor = client.push(device.id, vec![ ChangeEntry { table: "tasks".into(), op: ChangeOp::Insert, row_id: uuid::Uuid::new_v4().to_string(), timestamp: Utc::now(), data: Some(serde_json::json!({"title": "Buy milk"})), }, ]).await?; // Pull and auto-decrypt let (changes, cursor, has_more) = client.pull(device.id, 0).await?; ``` ## Crate Structure | File | Role | |------|------| | `lib.rs` | Crate root, re-exports, doc example | | `client.rs` | `SyncKitClient` -- HTTP methods, retry logic, token expiry detection | | `crypto.rs` | Key derivation (Argon2id), key wrapping, per-entry and per-blob encrypt/decrypt | | `error.rs` | `SyncKitError` enum (10 variants: HTTP, server, JSON, crypto, keychain, auth) | | `keystore.rs` | OS keychain read/write/delete, feature-gated with no-op stubs | | `types.rs` | Wire protocol types (`ChangeEntry`, `ChangeOp`, `Device`, `SyncStatus`) | ## Feature Flags | Flag | Default | Description | |------|---------|-------------| | `keychain` | on | OS keychain storage via the `keyring` crate. Disable with `default-features = false` for headless/CI environments. | ## Security Properties - **Server-zero-knowledge** -- the server never receives the plaintext master key or user data - **Key zeroization** -- volatile writes clear the master key from memory on drop - **Random salt per wrap** -- re-wrapping with the same password produces a different envelope - **Minimum ciphertext validation** -- decryption rejects inputs shorter than 40 bytes (24-byte nonce + 16-byte tag) - **No key material in logs** -- tracing events never include key bytes or ciphertext ## License PolyForm Noncommercial 1.0.0