sal-modular/sigsocket_client
2025-06-05 20:02:34 +03:00
..
examples Implement native and WASM WebSocket client for sigsocket communication 2025-06-04 13:03:15 +03:00
src feat: Enhance request management in SigSocket client with new methods and structures 2025-06-05 20:02:34 +03:00
tests feat: Enhance request management in SigSocket client with new methods and structures 2025-06-05 20:02:34 +03:00
Cargo.toml Implement native and WASM WebSocket client for sigsocket communication 2025-06-04 13:03:15 +03:00
IMPLEMENTATION.md Implement native and WASM WebSocket client for sigsocket communication 2025-06-04 13:03:15 +03:00
README.md Implement native and WASM WebSocket client for sigsocket communication 2025-06-04 13:03:15 +03:00

SigSocket Client

A WebSocket client library for connecting to sigsocket servers with WASM-first support.

Features

  • 🌐 WASM-first design: Optimized for browser environments
  • 🖥️ Native support: Works in native Rust applications
  • 🔐 No signing logic: Delegates signing to the application
  • 👤 User approval flow: Notifies applications about incoming requests
  • 🔌 sigsocket compatible: Fully compatible with sigsocket server protocol
  • 🚀 Async/await: Modern async Rust API
  • 🔄 Automatic reconnection: Both platforms support reconnection with exponential backoff
  • ⏱️ Connection timeouts: Proper timeout handling and connection management
  • 🛡️ Production ready: Comprehensive error handling and reliability features

Quick Start

Native Usage

use sigsocket_client::{SigSocketClient, SignRequestHandler, SignRequest, Result};

struct MySignHandler;

impl SignRequestHandler for MySignHandler {
    fn handle_sign_request(&self, request: &SignRequest) -> Result<Vec<u8>> {
        // 1. Present request to user
        println!("Sign request: {}", request.message);
        
        // 2. Get user approval
        // ... your UI logic here ...
        
        // 3. Sign the message (using your signing logic)
        let signature = your_signing_function(&request.message_bytes()?)?;
        
        Ok(signature)
    }
}

#[tokio::main]
async fn main() -> Result<()> {
    // Your public key bytes
    let public_key = hex::decode("02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388")?;
    
    // Create and configure client
    let mut client = SigSocketClient::new("ws://localhost:8080/ws", public_key)?;
    client.set_sign_handler(MySignHandler);
    
    // Connect and handle requests
    client.connect().await?;
    
    // Client will automatically handle incoming signature requests
    // Keep the connection alive...
    
    Ok(())
}

WASM Usage

use sigsocket_client::{SigSocketClient, SignRequestHandler, SignRequest, Result};
use wasm_bindgen::prelude::*;

struct WasmSignHandler;

impl SignRequestHandler for WasmSignHandler {
    fn handle_sign_request(&self, request: &SignRequest) -> Result<Vec<u8>> {
        // Show request to user in browser
        web_sys::window()
            .unwrap()
            .alert_with_message(&format!("Sign request: {}", request.id))
            .unwrap();
            
        // Your signing logic here...
        let signature = sign_with_browser_wallet(&request.message_bytes()?)?;
        Ok(signature)
    }
}

#[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)
        .map_err(|e| JsValue::from_str(&e.to_string()))?;
        
    client.set_sign_handler(WasmSignHandler);
    
    client.connect().await
        .map_err(|e| JsValue::from_str(&e.to_string()))?;
        
    Ok(())
}

Protocol

The sigsocket client implements a simple WebSocket protocol:

1. Introduction

Upon connection, the client sends its public key as a hex-encoded string:

02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388

2. Sign Requests

The server sends signature requests as JSON:

{
  "id": "req_123",
  "message": "dGVzdCBtZXNzYWdl"  // base64-encoded message
}

3. Sign Responses

The client responds with signatures as JSON:

{
  "id": "req_123",
  "message": "dGVzdCBtZXNzYWdl",  // original message
  "signature": "c2lnbmF0dXJl"      // base64-encoded signature
}

API Reference

SigSocketClient

Main client for connecting to sigsocket servers.

Methods

  • new(url, public_key) - Create a new client
  • set_sign_handler(handler) - Set the signature request handler
  • connect() - Connect to the server with automatic reconnection
  • disconnect() - Disconnect from the server
  • send_sign_response(response) - Manually send a signature response
  • state() - Get current connection state
  • is_connected() - Check if connected

Reconnection Configuration (WASM only)

  • set_auto_reconnect(enabled) - Enable/disable automatic reconnection
  • set_reconnect_config(max_attempts, initial_delay_ms) - Configure reconnection parameters

Default settings:

  • Max attempts: 5
  • Initial delay: 1000ms (with exponential backoff: 1s, 2s, 4s, 8s, 16s)
  • Auto-reconnect: enabled

SignRequestHandler Trait

Implement this trait to handle incoming signature requests.

trait SignRequestHandler {
    fn handle_sign_request(&self, request: &SignRequest) -> Result<Vec<u8>>;
}

SignRequest

Represents a signature request from the server.

Fields

  • id: String - Unique request identifier
  • message: String - Base64-encoded message to sign

Methods

  • message_bytes() - Decode message to bytes
  • message_hex() - Get message as hex string

SignResponse

Represents a signature response to send to the server.

Methods

  • new(id, message, signature) - Create a new response
  • from_request_and_signature(request, signature) - Create from request and signature bytes

Examples

Run the basic example:

cargo run --example basic_usage

Building

Native Build

cargo build
cargo test
cargo run --example basic_usage

WASM Build

wasm-pack build --target web
wasm-pack test --headless --firefox  # Run WASM tests

Requirements

Native

  • Rust 1.70+
  • tokio runtime

WASM

  • wasm-pack
  • Modern browser with WebSocket support

License

MIT OR Apache-2.0