- Added `NativeClient` for non-WASM environments with automatic reconnection and message handling. - Introduced `WasmClient` for WASM environments, supporting WebSocket communication and reconnection logic. - Created protocol definitions for `SignRequest` and `SignResponse` with serialization and deserialization. - Developed integration tests for the client functionality and sign request handling. - Implemented WASM-specific tests to ensure compatibility and functionality in browser environments.
6.3 KiB
6.3 KiB
SigSocket Client Implementation
Overview
This document describes the implementation of the sigsocket_client
crate, a WebSocket client library designed for connecting to sigsocket servers with WASM-first support.
Architecture
Core Design Principles
- WASM-First: Designed primarily for browser environments with native support as a secondary target
- No Signing Logic: The client delegates all signing operations to the application
- User Approval Flow: Applications are notified about incoming requests and handle user approval
- Protocol Compatibility: Fully compatible with the sigsocket server protocol
- Async/Await: Modern async Rust API throughout
Module Structure
sigsocket_client/
├── src/
│ ├── lib.rs # Main library entry point
│ ├── error.rs # Error types (native + WASM versions)
│ ├── protocol.rs # Protocol message definitions
│ ├── client.rs # Main client interface
│ ├── native.rs # Native (tokio) implementation
│ └── wasm.rs # WASM (web-sys) implementation
├── examples/
│ ├── basic_usage.rs # Native usage example
│ └── wasm_usage.rs # WASM usage example
├── tests/
│ └── integration_test.rs
└── README.md
Protocol Implementation
The sigsocket protocol is simple and consists of three message types:
1. Introduction Message
When connecting, the client sends its public key as a hex-encoded string:
02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9
2. Sign Request (Server → Client)
{
"id": "req_123",
"message": "dGVzdCBtZXNzYWdl" // base64-encoded message
}
3. Sign Response (Client → Server)
{
"id": "req_123",
"message": "dGVzdCBtZXNzYWdl", // original message
"signature": "c2lnbmF0dXJl" // base64-encoded signature
}
Key Features Implemented
✅ Dual Platform Support
- Native: Uses
tokio
andtokio-tungstenite
for async WebSocket communication - WASM: Uses
web-sys
andwasm-bindgen
for browser WebSocket API
✅ Type-Safe Protocol
SignRequest
andSignResponse
structs with serde serialization- Helper methods for base64 encoding/decoding
- Comprehensive error handling
✅ Flexible Sign Handler Interface
trait SignRequestHandler {
fn handle_sign_request(&self, request: &SignRequest) -> Result<Vec<u8>>;
}
✅ Connection Management
- Automatic connection state tracking
- Clean disconnect handling
- Connection status queries
✅ Error Handling
- Comprehensive error types for different failure modes
- Platform-specific error conversions
- WASM-compatible error handling (no
std::error::Error
dependency)
Platform-Specific Implementations
Native Implementation (native.rs
)
- Uses
tokio-tungstenite
for WebSocket communication - Spawns separate tasks for reading and writing
- Thread-safe with
Arc<RwLock<T>>
for shared state - Supports
Send + Sync
trait bounds
WASM Implementation (wasm.rs
)
- Uses
web-sys::WebSocket
for browser WebSocket API - Event-driven with JavaScript closures
- Single-threaded (no
Send + Sync
requirements) - Browser console logging for debugging
Usage Patterns
Native Usage
#[tokio::main]
async fn main() -> Result<()> {
let public_key = hex::decode("02f9308a...")?;
let mut client = SigSocketClient::new("ws://localhost:8080/ws", public_key)?;
client.set_sign_handler(MySignHandler);
client.connect().await?;
// Client handles requests automatically
Ok(())
}
WASM Usage
#[wasm_bindgen]
pub async fn connect_to_sigsocket() -> Result<(), JsValue> {
let public_key = get_user_public_key()?;
let mut client = SigSocketClient::new("ws://localhost:8080/ws", public_key)?;
client.set_sign_handler(WasmSignHandler);
client.connect().await?;
Ok(())
}
Testing
Unit Tests
- Protocol message serialization/deserialization
- Error handling and conversion
- Client creation and configuration
Integration Tests
- End-to-end usage patterns
- Sign request/response cycles
- Error scenarios
Documentation Tests
- Example code in documentation is verified to compile
Dependencies
Core Dependencies (Both Platforms)
serde
+serde_json
- JSON serializationhex
- Hex encoding/decodingbase64
- Base64 encoding/decodingurl
- URL parsing and validation
Native-Only Dependencies
tokio
- Async runtimetokio-tungstenite
- WebSocket clientfutures-util
- Stream utilitiesthiserror
- Error derive macros
WASM-Only Dependencies
wasm-bindgen
- Rust/JavaScript interopweb-sys
- Browser API bindingsjs-sys
- JavaScript type bindingswasm-bindgen-futures
- Async support
Build Targets
Native Build
cargo build --features native
cargo test --features native
cargo run --example basic_usage --features native
WASM Build
cargo check --target wasm32-unknown-unknown --features wasm
wasm-pack build --target web --features wasm
Future Enhancements
Potential Improvements
- Reconnection Logic: Automatic reconnection with exponential backoff
- Request Queuing: Queue multiple concurrent sign requests
- Timeout Handling: Configurable timeouts for requests
- Metrics: Connection and request metrics
- Logging: Structured logging with configurable levels
WASM Enhancements
- Better Callback System: More ergonomic callback handling in WASM
- Browser Wallet Integration: Direct integration with MetaMask, etc.
- Service Worker Support: Background request handling
Security Considerations
- No Private Key Storage: The client never handles private keys
- User Approval Required: All signing requires explicit user approval
- Message Validation: All incoming messages are validated
- Secure Transport: Requires WebSocket Secure (WSS) in production
Compatibility
- Rust Version: 1.70+
- WASM Target:
wasm32-unknown-unknown
- Browser Support: Modern browsers with WebSocket support
- Server Compatibility: Compatible with sigsocket server protocol
This implementation provides a solid foundation for applications that need to connect to sigsocket servers while maintaining security and user control over signing operations.