hero/interfaces/websocket/server/docs/webhooks.md
2025-07-29 01:15:23 +02:00

357 lines
9.9 KiB
Markdown

# Webhook Integration Architecture
## Overview
This document outlines the architecture for adding webhook handling capabilities to the Circle WebSocket Server. The integration adds HTTP webhook endpoints alongside the existing WebSocket functionality without disrupting the current system.
## Architecture Diagram
```mermaid
graph TB
subgraph "External Services"
A[Stripe Webhooks]
B[iDenfy Webhooks]
end
subgraph "Circle Server"
C[HTTP Router]
D[WebSocket Handler]
E[Webhook Handler]
F[Stripe Verifier]
G[iDenfy Verifier]
H[Script Dispatcher]
I[RhaiDispatcherBuilder]
end
subgraph "Configuration"
J[.env File]
K[Environment Variables]
end
subgraph "Backend"
L[Redis]
M[Rhai Worker]
end
A --> |POST /webhooks/stripe/{circle_pk}| E
B --> |POST /webhooks/idenfy/{circle_pk}| E
C --> D
C --> E
E --> F
E --> G
F --> H
G --> H
H --> I
I --> L
L --> M
J --> K
K --> F
K --> G
D --> I
```
## URL Structure
### Webhook Endpoints
- **Stripe**: `POST /webhooks/stripe/{circle_pk}`
- **iDenfy**: `POST /webhooks/idenfy/{circle_pk}`
### Existing WebSocket Endpoints (Unchanged)
- **WebSocket**: `GET /{circle_pk}` (upgrades to WebSocket)
## Configuration
### Environment Variables (.env file)
```bash
# Webhook secrets for signature verification
STRIPE_WEBHOOK_SECRET=whsec_...
IDENFY_WEBHOOK_SECRET=your_idenfy_secret
# Existing configuration
REDIS_URL=redis://127.0.0.1/
```
### Server Configuration Updates
```rust
pub struct ServerConfig {
// ... existing fields
pub stripe_webhook_secret: Option<String>,
pub idenfy_webhook_secret: Option<String>,
}
```
## Webhook Processing Flow
### 1. Request Reception
```mermaid
sequenceDiagram
participant WS as Webhook Service
participant CS as Circle Server
participant WV as Webhook Verifier
participant SD as Script Dispatcher
participant RC as RhaiDispatcher
participant RW as Rhai Worker
WS->>CS: POST /webhooks/stripe/{circle_pk}
CS->>CS: Extract circle_pk from URL
CS->>CS: Read request body and headers
CS->>WV: Verify webhook signature
alt Stripe Webhook
WV->>WV: Verify Stripe signature using STRIPE_WEBHOOK_SECRET
WV->>WV: Deserialize to Stripe webhook payload
else iDenfy Webhook
WV->>WV: Verify iDenfy signature using IDENFY_WEBHOOK_SECRET
WV->>WV: Deserialize to iDenfy webhook payload
end
WV->>CS: Return verification result + parsed payload
alt Verification Success
CS->>SD: Dispatch appropriate script
SD->>RC: Create RhaiDispatcherBuilder
RC->>RC: Set caller_id="stripe" or "idenfy"
RC->>RC: Set recipient_id=circle_pk
RC->>RC: Set script="stripe_webhook_received" or "idenfy_webhook_received"
RC->>RW: Execute via Redis
RW->>RC: Return result
RC->>CS: Script execution result
CS->>WS: HTTP 200 OK
else Verification Failed
CS->>WS: HTTP 401 Unauthorized
end
```
### 2. Signature Verification
#### Stripe Verification
- Uses `Stripe-Signature` header
- HMAC-SHA256 verification with `STRIPE_WEBHOOK_SECRET`
- Follows Stripe's webhook signature verification protocol
#### iDenfy Verification
- Uses appropriate iDenfy signature header
- HMAC verification with `IDENFY_WEBHOOK_SECRET`
- Follows iDenfy's webhook signature verification protocol
### 3. Payload Deserialization
#### Type Definitions in Heromodels Library
Webhook payload types are now defined in the `heromodels` library for better code organization and reusability:
- **Stripe Types**: Located in `heromodels::models::payment::stripe`
- **iDenfy Types**: Located in `heromodels::models::identity::kyc`
#### Stripe Payload Structure
```rust
// From heromodels::models::payment::StripeWebhookEvent
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct StripeWebhookEvent {
pub id: String,
pub object: String,
pub api_version: Option<String>,
pub created: i64,
pub data: StripeEventData,
pub livemode: bool,
pub pending_webhooks: i32,
pub request: Option<StripeEventRequest>,
#[serde(rename = "type")]
pub event_type: String,
}
```
#### iDenfy Payload Structure
```rust
// From heromodels::models::identity::IdenfyWebhookEvent
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct IdenfyWebhookEvent {
#[serde(rename = "clientId")]
pub client_id: String,
#[serde(rename = "scanRef")]
pub scan_ref: String,
pub status: String,
pub platform: String,
#[serde(rename = "startedAt")]
pub started_at: String,
#[serde(rename = "finishedAt")]
pub finished_at: Option<String>,
pub data: Option<IdenfyVerificationData>,
// ... additional fields
}
```
### 4. Script Execution
#### Script Names
- **Stripe**: `stripe_webhook_received`
- **iDenfy**: `idenfy_webhook_received`
#### Script Context
The Rhai scripts will receive structured data:
```javascript
// For Stripe webhooks
let webhook_data = {
"caller_id": "stripe",
"circle_id": "circle_public_key",
"event_type": "payment_intent.succeeded",
"event_id": "evt_...",
"created": 1234567890,
"livemode": false,
"data": { /* Stripe event data */ }
};
// For iDenfy webhooks
let webhook_data = {
"caller_id": "idenfy",
"circle_id": "circle_public_key",
"final_decision": "APPROVED",
"platform": "PC",
"status": { /* iDenfy status data */ },
"data": { /* iDenfy verification data */ }
};
```
## Implementation Structure
### Current File Structure
```
src/server/src/
├── webhook/
│ ├── mod.rs # Main webhook module with route configuration
│ ├── handlers/
│ │ ├── mod.rs # Handler module exports
│ │ ├── common.rs # Common utilities and app state
│ │ ├── stripe.rs # Stripe webhook handler
│ │ └── idenfy.rs # iDenfy webhook handler
│ ├── verifiers.rs # Signature verification for all providers
│ └── types.rs # Local webhook types (config, errors, etc.)
└── .env # Environment configuration
```
### Heromodels Library Structure
```
heromodels/src/models/
├── payment/
│ ├── mod.rs # Payment module exports
│ └── stripe.rs # Stripe webhook event types
└── identity/
├── mod.rs # Identity module exports
└── kyc.rs # iDenfy KYC webhook event types
```
### Key Architectural Changes
- **Type Organization**: Webhook payload types moved to `heromodels` library for reusability
- **Modular Handlers**: Separate handler files for each webhook provider
- **Simplified Architecture**: Removed unnecessary dispatcher complexity
- **Direct Script Execution**: Handlers directly use `RhaiDispatcher` for script execution
### Modified Files
- `src/lib.rs` - Add webhook routes and module imports
- `Cargo.toml` - Add heromodels dependency and webhook-related dependencies
- `cmd/main.rs` - Load .env file and configure webhook secrets
### Dependencies
```toml
[dependencies]
# Existing dependencies...
# Heromodels library for shared types
heromodels = { path = "../../../db/heromodels" }
# For webhook signature verification
hmac = "0.12"
sha2 = "0.10"
hex = { workspace = true }
# For environment variable loading
dotenv = "0.15"
# For HTTP request handling
bytes = "1.0"
thiserror = { workspace = true }
```
## Security Considerations
### Signature Verification
- **Mandatory**: All webhook requests must have valid signatures
- **Timing Attack Protection**: Use constant-time comparison for signatures
- **Secret Management**: Webhook secrets loaded from environment variables only
### Error Handling
- **No Information Leakage**: Generic error responses for invalid webhooks
- **Logging**: Detailed logging for debugging (same as existing WebSocket errors)
- **Graceful Degradation**: Webhook failures don't affect WebSocket functionality
### Request Validation
- **Content-Type**: Verify appropriate content types
- **Payload Size**: No explicit limits initially (as requested)
- **Rate Limiting**: Consider future implementation
## Backward Compatibility
### WebSocket Functionality
- **Zero Impact**: Existing WebSocket routes and functionality unchanged
- **Authentication**: WebSocket authentication system remains independent
- **Performance**: No performance impact on WebSocket connections
### Configuration
- **Optional**: Webhook functionality only enabled when secrets are configured
- **Graceful Fallback**: Server starts normally even without webhook configuration
## Testing Strategy
### Unit Tests
- Webhook signature verification for both providers
- Payload deserialization
- Error handling scenarios
### Integration Tests
- End-to-end webhook processing
- Script dispatch verification
- Configuration loading
### Mock Testing
- Simulated Stripe webhook calls
- Simulated iDenfy webhook calls
- Invalid signature scenarios
## Deployment Considerations
### Environment Setup
```bash
# .env file in src/server/
STRIPE_WEBHOOK_SECRET=whsec_1234567890abcdef...
IDENFY_WEBHOOK_SECRET=your_idenfy_webhook_secret
REDIS_URL=redis://127.0.0.1/
```
### Server Startup
- Load .env file before server initialization
- Validate webhook secrets if webhook endpoints are to be enabled
- Log webhook endpoint availability
### Monitoring
- Log webhook reception and processing
- Track script execution success/failure rates
- Monitor webhook signature verification failures
## Future Enhancements
### Potential Additions
- Additional webhook providers
- Webhook retry mechanisms
- Webhook event filtering
- Rate limiting implementation
- Webhook event queuing for high-volume scenarios
### Scalability Considerations
- Webhook processing can be made asynchronous if needed
- Multiple server instances can handle webhooks independently
- Redis-based script execution provides natural load distribution