merge branches and cleanup db
This commit is contained in:
327
_archive/websocket/architecture.md
Normal file
327
_archive/websocket/architecture.md
Normal file
@@ -0,0 +1,327 @@
|
||||
# WebSocket Signing Server Architecture Plan
|
||||
|
||||
Based on my analysis of the existing Actix application structure, I've designed a comprehensive architecture for implementing a WebSocket server that handles signing operations. This server will integrate seamlessly with the existing hostbasket application.
|
||||
|
||||
## 1. Overview
|
||||
|
||||
The WebSocket Signing Server will:
|
||||
- Accept WebSocket connections from clients
|
||||
- Allow clients to identify themselves with a public key
|
||||
- Provide a `send_to_sign()` function that takes a public key and a message
|
||||
- Forward the message to the appropriate client for signing
|
||||
- Wait for a signed response (with a 1-minute timeout)
|
||||
- Verify the signature using the client's public key
|
||||
- Return the response message and signature
|
||||
|
||||
## 2. Component Architecture
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[Actix Web Server] --> B[WebSocket Manager]
|
||||
B --> C[Connection Registry]
|
||||
B --> D[Message Handler]
|
||||
D --> E[Signature Verifier]
|
||||
F[Client] <--> B
|
||||
G[Controllers] --> H[SigningService]
|
||||
H --> B
|
||||
```
|
||||
|
||||
### Key Components:
|
||||
|
||||
1. **WebSocket Manager**
|
||||
- Handles WebSocket connections
|
||||
- Manages connection lifecycle
|
||||
- Routes messages to appropriate handlers
|
||||
|
||||
2. **Connection Registry**
|
||||
- Maps public keys to active WebSocket connections
|
||||
- Handles connection tracking and cleanup
|
||||
- Provides lookup functionality
|
||||
|
||||
3. **Message Handler**
|
||||
- Processes incoming messages
|
||||
- Implements the message protocol
|
||||
- Manages timeouts for responses
|
||||
|
||||
4. **Signature Verifier**
|
||||
- Verifies signatures using public keys
|
||||
- Implements cryptographic operations
|
||||
- Ensures security of the signing process
|
||||
|
||||
5. **Signing Service**
|
||||
- Provides a clean API for controllers to use
|
||||
- Abstracts WebSocket complexity from business logic
|
||||
- Handles error cases and timeouts
|
||||
|
||||
## 3. Directory Structure
|
||||
|
||||
```
|
||||
src/
|
||||
├── websocket/
|
||||
│ ├── mod.rs # Module exports
|
||||
│ ├── manager.rs # WebSocket connection manager
|
||||
│ ├── registry.rs # Connection registry
|
||||
│ ├── handler.rs # Message handling logic
|
||||
│ ├── protocol.rs # Message protocol definitions
|
||||
│ ├── crypto.rs # Cryptographic operations
|
||||
│ └── service.rs # Service API for controllers
|
||||
├── controllers/
|
||||
│ └── [existing controllers]
|
||||
│ └── websocket.rs # WebSocket controller (if needed)
|
||||
└── routes/
|
||||
└── mod.rs # Updated to include WebSocket routes
|
||||
```
|
||||
|
||||
## 4. Data Flow
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client
|
||||
participant WebSocketManager
|
||||
participant Registry
|
||||
participant Controller
|
||||
participant SigningService
|
||||
|
||||
Client->>WebSocketManager: Connect
|
||||
Client->>WebSocketManager: Introduce(public_key)
|
||||
WebSocketManager->>Registry: Register(connection, public_key)
|
||||
|
||||
Controller->>SigningService: send_to_sign(public_key, message)
|
||||
SigningService->>Registry: Lookup(public_key)
|
||||
Registry-->>SigningService: connection
|
||||
SigningService->>WebSocketManager: Send message to connection
|
||||
WebSocketManager->>Client: Message to sign
|
||||
|
||||
Client->>WebSocketManager: Signed response
|
||||
WebSocketManager->>SigningService: Forward response
|
||||
SigningService->>SigningService: Verify signature
|
||||
SigningService-->>Controller: Return verified response
|
||||
```
|
||||
|
||||
## 5. Message Protocol
|
||||
|
||||
We'll define a simple JSON-based protocol for communication:
|
||||
|
||||
```json
|
||||
// Client introduction
|
||||
{
|
||||
"type": "introduction",
|
||||
"public_key": "base64_encoded_public_key"
|
||||
}
|
||||
|
||||
// Sign request
|
||||
{
|
||||
"type": "sign_request",
|
||||
"message": "base64_encoded_message",
|
||||
"request_id": "unique_request_id"
|
||||
}
|
||||
|
||||
// Sign response
|
||||
{
|
||||
"type": "sign_response",
|
||||
"request_id": "unique_request_id",
|
||||
"message": "base64_encoded_message",
|
||||
"signature": "base64_encoded_signature"
|
||||
}
|
||||
```
|
||||
|
||||
## 6. Required Dependencies
|
||||
|
||||
We'll need to add the following dependencies to the project:
|
||||
|
||||
```toml
|
||||
# WebSocket support
|
||||
actix-web-actors = "4.2.0"
|
||||
|
||||
# Cryptography
|
||||
ed25519-dalek = "2.0.0" # For Ed25519 signatures
|
||||
base64 = "0.21.0" # For encoding/decoding
|
||||
rand = "0.8.5" # For generating random data
|
||||
```
|
||||
|
||||
## 7. Implementation Details
|
||||
|
||||
### 7.1 WebSocket Manager
|
||||
|
||||
The WebSocket Manager will handle the lifecycle of WebSocket connections:
|
||||
|
||||
```rust
|
||||
pub struct WebSocketManager {
|
||||
registry: Arc<RwLock<ConnectionRegistry>>,
|
||||
}
|
||||
|
||||
impl Actor for WebSocketManager {
|
||||
type Context = ws::WebsocketContext<Self>;
|
||||
|
||||
fn started(&mut self, ctx: &mut Self::Context) {
|
||||
// Handle connection start
|
||||
}
|
||||
|
||||
fn stopped(&mut self, ctx: &mut Self::Context) {
|
||||
// Handle connection close and cleanup
|
||||
}
|
||||
}
|
||||
|
||||
impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for WebSocketManager {
|
||||
fn handle(&mut self, msg: Result<ws::Message, ws::ProtocolError>, ctx: &mut Self::Context) {
|
||||
// Handle different types of WebSocket messages
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 7.2 Connection Registry
|
||||
|
||||
The Connection Registry will maintain a mapping of public keys to active connections:
|
||||
|
||||
```rust
|
||||
pub struct ConnectionRegistry {
|
||||
connections: HashMap<String, Addr<WebSocketManager>>,
|
||||
}
|
||||
|
||||
impl ConnectionRegistry {
|
||||
pub fn register(&mut self, public_key: String, addr: Addr<WebSocketManager>) {
|
||||
self.connections.insert(public_key, addr);
|
||||
}
|
||||
|
||||
pub fn unregister(&mut self, public_key: &str) {
|
||||
self.connections.remove(public_key);
|
||||
}
|
||||
|
||||
pub fn get(&self, public_key: &str) -> Option<&Addr<WebSocketManager>> {
|
||||
self.connections.get(public_key)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 7.3 Signing Service
|
||||
|
||||
The Signing Service will provide a clean API for controllers:
|
||||
|
||||
```rust
|
||||
pub struct SigningService {
|
||||
registry: Arc<RwLock<ConnectionRegistry>>,
|
||||
}
|
||||
|
||||
impl SigningService {
|
||||
pub async fn send_to_sign(&self, public_key: &str, message: &[u8])
|
||||
-> Result<(Vec<u8>, Vec<u8>), SigningError> {
|
||||
|
||||
// 1. Find the connection for the public key
|
||||
let connection = self.registry.read().await.get(public_key).cloned();
|
||||
|
||||
if let Some(conn) = connection {
|
||||
// 2. Generate a unique request ID
|
||||
let request_id = Uuid::new_v4().to_string();
|
||||
|
||||
// 3. Create a response channel
|
||||
let (tx, rx) = oneshot::channel();
|
||||
|
||||
// 4. Register the response channel
|
||||
self.pending_requests.write().await.insert(request_id.clone(), tx);
|
||||
|
||||
// 5. Send the message to the client
|
||||
let sign_request = SignRequest {
|
||||
request_id: request_id.clone(),
|
||||
message: message.to_vec(),
|
||||
};
|
||||
|
||||
conn.do_send(sign_request);
|
||||
|
||||
// 6. Wait for the response with a timeout
|
||||
match tokio::time::timeout(Duration::from_secs(60), rx).await {
|
||||
Ok(Ok(response)) => {
|
||||
// 7. Verify the signature
|
||||
if self.verify_signature(&response.signature, message, public_key) {
|
||||
Ok((response.message, response.signature))
|
||||
} else {
|
||||
Err(SigningError::InvalidSignature)
|
||||
}
|
||||
},
|
||||
Ok(Err(_)) => Err(SigningError::ChannelClosed),
|
||||
Err(_) => Err(SigningError::Timeout),
|
||||
}
|
||||
} else {
|
||||
Err(SigningError::ConnectionNotFound)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 8. Error Handling
|
||||
|
||||
We'll define a comprehensive error type for the signing service:
|
||||
|
||||
```rust
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum SigningError {
|
||||
#[error("Connection not found for the provided public key")]
|
||||
ConnectionNotFound,
|
||||
|
||||
#[error("Timeout waiting for signature")]
|
||||
Timeout,
|
||||
|
||||
#[error("Invalid signature")]
|
||||
InvalidSignature,
|
||||
|
||||
#[error("Channel closed unexpectedly")]
|
||||
ChannelClosed,
|
||||
|
||||
#[error("WebSocket error: {0}")]
|
||||
WebSocketError(#[from] ws::ProtocolError),
|
||||
|
||||
#[error("Serialization error: {0}")]
|
||||
SerializationError(#[from] serde_json::Error),
|
||||
}
|
||||
```
|
||||
|
||||
## 9. Security Considerations
|
||||
|
||||
1. **Public Key Validation**: Validate public keys upon connection to ensure they are properly formatted
|
||||
2. **Message Authentication**: Consider adding a nonce or timestamp to prevent replay attacks
|
||||
3. **Rate Limiting**: Implement rate limiting to prevent DoS attacks
|
||||
4. **Connection Timeouts**: Automatically close inactive connections
|
||||
5. **Error Logging**: Log errors but avoid exposing sensitive information
|
||||
6. **Input Validation**: Validate all inputs to prevent injection attacks
|
||||
|
||||
## 10. Testing Strategy
|
||||
|
||||
1. **Unit Tests**: Test individual components in isolation
|
||||
2. **Integration Tests**: Test the interaction between components
|
||||
3. **End-to-End Tests**: Test the complete flow from client connection to signature verification
|
||||
4. **Load Tests**: Test the system under high load to ensure stability
|
||||
5. **Security Tests**: Test for common security vulnerabilities
|
||||
|
||||
## 11. Integration with Existing Controllers
|
||||
|
||||
Controllers can use the SigningService through dependency injection:
|
||||
|
||||
```rust
|
||||
pub struct SomeController {
|
||||
signing_service: Arc<SigningService>,
|
||||
}
|
||||
|
||||
impl SomeController {
|
||||
pub async fn some_action(&self, public_key: String, message: Vec<u8>) -> HttpResponse {
|
||||
match self.signing_service.send_to_sign(&public_key, &message).await {
|
||||
Ok((response, signature)) => {
|
||||
HttpResponse::Ok().json(json!({
|
||||
"response": base64::encode(response),
|
||||
"signature": base64::encode(signature),
|
||||
}))
|
||||
},
|
||||
Err(e) => {
|
||||
HttpResponse::InternalServerError().json(json!({
|
||||
"error": e.to_string(),
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 12. Deployment Considerations
|
||||
|
||||
1. **Scalability**: The WebSocket server should be designed to scale horizontally
|
||||
2. **Monitoring**: Implement metrics for connection count, message throughput, and error rates
|
||||
3. **Logging**: Log important events for debugging and auditing
|
||||
4. **Documentation**: Document the API and protocol for client implementers
|
Reference in New Issue
Block a user