flow_chat 0.4.2 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +418 -295
- data/SECURITY.md +365 -0
- data/examples/initializer.rb +55 -0
- data/examples/multi_tenant_whatsapp_controller.rb +5 -1
- data/examples/simulator_controller.rb +95 -0
- data/examples/whatsapp_controller.rb +92 -3
- data/lib/flow_chat/base_processor.rb +2 -1
- data/lib/flow_chat/config.rb +3 -1
- data/lib/flow_chat/simulator/controller.rb +34 -5
- data/lib/flow_chat/simulator/views/simulator.html.erb +4 -2
- data/lib/flow_chat/version.rb +1 -1
- data/lib/flow_chat/whatsapp/client.rb +3 -5
- data/lib/flow_chat/whatsapp/configuration.rb +13 -12
- data/lib/flow_chat/whatsapp/gateway/cloud_api.rb +121 -9
- data/lib/flow_chat/whatsapp/template_manager.rb +3 -3
- data/lib/flow_chat.rb +1 -0
- metadata +4 -2
data/SECURITY.md
ADDED
@@ -0,0 +1,365 @@
|
|
1
|
+
# FlowChat Security Guide
|
2
|
+
|
3
|
+
This guide covers the security features and best practices for FlowChat, including webhook signature validation and simulator authentication.
|
4
|
+
|
5
|
+
## Overview
|
6
|
+
|
7
|
+
FlowChat includes comprehensive security features to protect your WhatsApp and USSD applications:
|
8
|
+
|
9
|
+
- **Webhook Signature Validation**: Verify that WhatsApp webhooks are authentic
|
10
|
+
- **Simulator Authentication**: Secure access to the testing simulator
|
11
|
+
- **Configuration Validation**: Prevent insecure configurations
|
12
|
+
- **Environment-Specific Security**: Different security levels per environment
|
13
|
+
|
14
|
+
## WhatsApp Webhook Security
|
15
|
+
|
16
|
+
### Signature Validation
|
17
|
+
|
18
|
+
FlowChat automatically validates WhatsApp webhook signatures using HMAC-SHA256 to ensure requests come from WhatsApp.
|
19
|
+
|
20
|
+
#### Required Configuration
|
21
|
+
|
22
|
+
For webhook signature validation, you need to configure your WhatsApp app secret:
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
# Using Rails credentials
|
26
|
+
rails credentials:edit
|
27
|
+
```
|
28
|
+
|
29
|
+
```yaml
|
30
|
+
whatsapp:
|
31
|
+
app_secret: "your_whatsapp_app_secret"
|
32
|
+
# ... other credentials
|
33
|
+
```
|
34
|
+
|
35
|
+
Or using environment variables:
|
36
|
+
|
37
|
+
```bash
|
38
|
+
export WHATSAPP_APP_SECRET="your_whatsapp_app_secret"
|
39
|
+
```
|
40
|
+
|
41
|
+
#### Security Modes
|
42
|
+
|
43
|
+
FlowChat supports two security modes for webhook validation:
|
44
|
+
|
45
|
+
**1. Full Security (Recommended for Production)**
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
config = FlowChat::Whatsapp::Configuration.new
|
49
|
+
config.app_secret = "your_whatsapp_app_secret" # Required
|
50
|
+
config.skip_signature_validation = false # Default: enforce validation
|
51
|
+
```
|
52
|
+
|
53
|
+
**2. Development Mode (Testing Only)**
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
config = FlowChat::Whatsapp::Configuration.new
|
57
|
+
config.app_secret = nil # Not required when disabled
|
58
|
+
config.skip_signature_validation = true # Explicitly disable validation
|
59
|
+
```
|
60
|
+
|
61
|
+
⚠️ **Security Warning**: Never disable signature validation in production environments.
|
62
|
+
|
63
|
+
#### Configuration Error Handling
|
64
|
+
|
65
|
+
When `app_secret` is missing and validation is not explicitly disabled, FlowChat raises a `ConfigurationError`:
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
begin
|
69
|
+
processor.run WelcomeFlow, :main_page
|
70
|
+
rescue FlowChat::Whatsapp::ConfigurationError => e
|
71
|
+
Rails.logger.error "Security configuration error: #{e.message}"
|
72
|
+
head :internal_server_error
|
73
|
+
end
|
74
|
+
```
|
75
|
+
|
76
|
+
The error message provides clear guidance:
|
77
|
+
|
78
|
+
```
|
79
|
+
WhatsApp app_secret is required for webhook signature validation.
|
80
|
+
Either configure app_secret or set skip_signature_validation=true to explicitly disable validation.
|
81
|
+
```
|
82
|
+
|
83
|
+
### Environment-Specific Security
|
84
|
+
|
85
|
+
Configure different security levels per environment:
|
86
|
+
|
87
|
+
```ruby
|
88
|
+
# config/initializers/flowchat.rb
|
89
|
+
case Rails.env
|
90
|
+
when 'development'
|
91
|
+
# Relaxed security for easier development
|
92
|
+
config.skip_signature_validation = true
|
93
|
+
|
94
|
+
when 'test'
|
95
|
+
# Skip validation for deterministic testing
|
96
|
+
config.skip_signature_validation = true
|
97
|
+
|
98
|
+
when 'staging', 'production'
|
99
|
+
# Full security for production-like environments
|
100
|
+
config.skip_signature_validation = false
|
101
|
+
|
102
|
+
# Ensure app_secret is configured
|
103
|
+
if ENV['WHATSAPP_APP_SECRET'].blank?
|
104
|
+
raise "WHATSAPP_APP_SECRET required for #{Rails.env} environment"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
```
|
108
|
+
|
109
|
+
## Simulator Security
|
110
|
+
|
111
|
+
### Authentication System
|
112
|
+
|
113
|
+
The FlowChat simulator uses secure HMAC-SHA256 signed cookies for authentication. This prevents unauthorized access to your simulator endpoints.
|
114
|
+
|
115
|
+
#### Required Configuration
|
116
|
+
|
117
|
+
Configure a simulator secret in your initializer:
|
118
|
+
|
119
|
+
```ruby
|
120
|
+
# config/initializers/flowchat.rb
|
121
|
+
FlowChat::Config.simulator_secret = "your_secure_secret_here"
|
122
|
+
```
|
123
|
+
|
124
|
+
#### Environment-Specific Secrets
|
125
|
+
|
126
|
+
Use different secrets per environment:
|
127
|
+
|
128
|
+
```ruby
|
129
|
+
case Rails.env
|
130
|
+
when 'development', 'test'
|
131
|
+
# Use Rails secret key with environment suffix
|
132
|
+
FlowChat::Config.simulator_secret = Rails.application.secret_key_base + "_#{Rails.env}"
|
133
|
+
|
134
|
+
when 'staging', 'production'
|
135
|
+
# Use environment variable for production
|
136
|
+
FlowChat::Config.simulator_secret = ENV['FLOWCHAT_SIMULATOR_SECRET']
|
137
|
+
|
138
|
+
if FlowChat::Config.simulator_secret.blank?
|
139
|
+
Rails.logger.warn "FLOWCHAT_SIMULATOR_SECRET not configured. Simulator will be unavailable."
|
140
|
+
end
|
141
|
+
end
|
142
|
+
```
|
143
|
+
|
144
|
+
#### Cookie Security
|
145
|
+
|
146
|
+
Simulator cookies are automatically configured with security best practices:
|
147
|
+
|
148
|
+
- **HMAC-SHA256 signed**: Prevents tampering
|
149
|
+
- **24-hour expiration**: Limits exposure window
|
150
|
+
- **Secure flag**: Only sent over HTTPS in production
|
151
|
+
- **HttpOnly flag**: Prevents XSS access
|
152
|
+
- **SameSite=Lax**: CSRF protection
|
153
|
+
|
154
|
+
#### Enabling Simulator Mode
|
155
|
+
|
156
|
+
Enable simulator mode only when needed:
|
157
|
+
|
158
|
+
```ruby
|
159
|
+
# Enable simulator only in development/staging
|
160
|
+
enable_simulator = Rails.env.development? || Rails.env.staging?
|
161
|
+
|
162
|
+
processor = FlowChat::Whatsapp::Processor.new(self, enable_simulator: enable_simulator) do |config|
|
163
|
+
config.use_gateway FlowChat::Whatsapp::Gateway::CloudApi
|
164
|
+
config.use_session_store FlowChat::Session::CacheSessionStore
|
165
|
+
end
|
166
|
+
```
|
167
|
+
|
168
|
+
### Simulator Request Flow
|
169
|
+
|
170
|
+
1. **User visits simulator**: Browser requests `/simulator`
|
171
|
+
2. **Cookie generation**: Server generates HMAC-signed cookie
|
172
|
+
3. **Simulator requests**: Include valid cookie for authentication
|
173
|
+
4. **Cookie validation**: Server validates HMAC signature and timestamp
|
174
|
+
5. **Request processing**: Continues if authentication succeeds
|
175
|
+
|
176
|
+
## Security Best Practices
|
177
|
+
|
178
|
+
### Production Checklist
|
179
|
+
|
180
|
+
✅ **WhatsApp Security**
|
181
|
+
- Configure `app_secret` for webhook validation
|
182
|
+
- Set `skip_signature_validation = false`
|
183
|
+
- Use environment variables for secrets
|
184
|
+
- Handle `ConfigurationError` exceptions
|
185
|
+
|
186
|
+
✅ **Simulator Security**
|
187
|
+
- Configure `simulator_secret` using environment variables
|
188
|
+
- Enable simulator only in development/staging
|
189
|
+
- Use unique secrets per environment
|
190
|
+
|
191
|
+
✅ **Environment Configuration**
|
192
|
+
- Different security levels per environment
|
193
|
+
- Fail fast on missing required configuration
|
194
|
+
- Log security warnings appropriately
|
195
|
+
|
196
|
+
✅ **Error Handling**
|
197
|
+
- Catch and log `ConfigurationError` exceptions
|
198
|
+
- Return appropriate HTTP status codes
|
199
|
+
- Don't expose sensitive information in errors
|
200
|
+
|
201
|
+
### Development Guidelines
|
202
|
+
|
203
|
+
**DO:**
|
204
|
+
- Use Rails `secret_key_base` + suffix for development secrets
|
205
|
+
- Skip webhook validation in development for easier testing
|
206
|
+
- Enable simulator mode for testing
|
207
|
+
- Use test-specific credentials in test environment
|
208
|
+
|
209
|
+
**DON'T:**
|
210
|
+
- Hardcode secrets in source code
|
211
|
+
- Disable security in production
|
212
|
+
- Use production secrets in development
|
213
|
+
- Commit secrets to version control
|
214
|
+
|
215
|
+
### Example Secure Configuration
|
216
|
+
|
217
|
+
```ruby
|
218
|
+
# config/initializers/flowchat.rb
|
219
|
+
case Rails.env
|
220
|
+
when 'development'
|
221
|
+
FlowChat::Config.simulator_secret = Rails.application.secret_key_base + "_dev"
|
222
|
+
FlowChat::Config.whatsapp.message_handling_mode = :simulator
|
223
|
+
|
224
|
+
when 'test'
|
225
|
+
FlowChat::Config.simulator_secret = "test_secret_#{Rails.application.secret_key_base}"
|
226
|
+
FlowChat::Config.whatsapp.message_handling_mode = :simulator
|
227
|
+
|
228
|
+
when 'staging'
|
229
|
+
FlowChat::Config.simulator_secret = ENV.fetch('FLOWCHAT_SIMULATOR_SECRET')
|
230
|
+
FlowChat::Config.whatsapp.message_handling_mode = :inline
|
231
|
+
|
232
|
+
when 'production'
|
233
|
+
FlowChat::Config.simulator_secret = ENV.fetch('FLOWCHAT_SIMULATOR_SECRET')
|
234
|
+
FlowChat::Config.whatsapp.message_handling_mode = :background
|
235
|
+
FlowChat::Config.whatsapp.background_job_class = 'WhatsappMessageJob'
|
236
|
+
end
|
237
|
+
```
|
238
|
+
|
239
|
+
## Testing Security Features
|
240
|
+
|
241
|
+
### Webhook Signature Validation Tests
|
242
|
+
|
243
|
+
```ruby
|
244
|
+
test "webhook accepts valid signature" do
|
245
|
+
payload = valid_webhook_payload.to_json
|
246
|
+
signature = OpenSSL::HMAC.hexdigest(
|
247
|
+
OpenSSL::Digest.new("sha256"),
|
248
|
+
"your_app_secret",
|
249
|
+
payload
|
250
|
+
)
|
251
|
+
|
252
|
+
post "/whatsapp/webhook",
|
253
|
+
params: payload,
|
254
|
+
headers: {
|
255
|
+
"Content-Type" => "application/json",
|
256
|
+
"X-Hub-Signature-256" => "sha256=#{signature}"
|
257
|
+
}
|
258
|
+
|
259
|
+
assert_response :success
|
260
|
+
end
|
261
|
+
|
262
|
+
test "webhook rejects invalid signature" do
|
263
|
+
post "/whatsapp/webhook",
|
264
|
+
params: valid_webhook_payload,
|
265
|
+
headers: { "X-Hub-Signature-256" => "sha256=invalid_signature" }
|
266
|
+
|
267
|
+
assert_response :unauthorized
|
268
|
+
end
|
269
|
+
|
270
|
+
test "webhook rejects missing signature" do
|
271
|
+
post "/whatsapp/webhook", params: valid_webhook_payload
|
272
|
+
assert_response :unauthorized
|
273
|
+
end
|
274
|
+
```
|
275
|
+
|
276
|
+
### Simulator Authentication Tests
|
277
|
+
|
278
|
+
```ruby
|
279
|
+
test "simulator requires valid authentication" do
|
280
|
+
post "/whatsapp/webhook", params: {
|
281
|
+
simulator_mode: true,
|
282
|
+
# ... webhook payload
|
283
|
+
}
|
284
|
+
|
285
|
+
assert_response :unauthorized # No valid simulator cookie
|
286
|
+
end
|
287
|
+
|
288
|
+
test "simulator accepts valid authentication" do
|
289
|
+
# Generate valid simulator cookie
|
290
|
+
timestamp = Time.now.to_i
|
291
|
+
message = "simulator:#{timestamp}"
|
292
|
+
signature = OpenSSL::HMAC.hexdigest(
|
293
|
+
OpenSSL::Digest.new("sha256"),
|
294
|
+
FlowChat::Config.simulator_secret,
|
295
|
+
message
|
296
|
+
)
|
297
|
+
|
298
|
+
post "/whatsapp/webhook",
|
299
|
+
params: { simulator_mode: true, /* ... */ },
|
300
|
+
cookies: { flowchat_simulator: "#{timestamp}:#{signature}" }
|
301
|
+
|
302
|
+
assert_response :success
|
303
|
+
end
|
304
|
+
```
|
305
|
+
|
306
|
+
## Troubleshooting
|
307
|
+
|
308
|
+
### Common Issues
|
309
|
+
|
310
|
+
**1. ConfigurationError: app_secret required**
|
311
|
+
|
312
|
+
```
|
313
|
+
WhatsApp app_secret is required for webhook signature validation.
|
314
|
+
```
|
315
|
+
|
316
|
+
**Solution**: Configure `WHATSAPP_APP_SECRET` environment variable or disable validation explicitly.
|
317
|
+
|
318
|
+
**2. Invalid webhook signature**
|
319
|
+
|
320
|
+
```
|
321
|
+
Invalid webhook signature received
|
322
|
+
```
|
323
|
+
|
324
|
+
**Solution**: Verify your `app_secret` matches your WhatsApp app configuration.
|
325
|
+
|
326
|
+
**3. Simulator authentication failed**
|
327
|
+
|
328
|
+
```
|
329
|
+
Invalid simulator cookie format
|
330
|
+
```
|
331
|
+
|
332
|
+
**Solution**: Ensure `FlowChat::Config.simulator_secret` is properly configured.
|
333
|
+
|
334
|
+
**4. Missing simulator secret**
|
335
|
+
|
336
|
+
```
|
337
|
+
Simulator secret not configured
|
338
|
+
```
|
339
|
+
|
340
|
+
**Solution**: Set `FLOWCHAT_SIMULATOR_SECRET` environment variable or configure in initializer.
|
341
|
+
|
342
|
+
### Debug Mode
|
343
|
+
|
344
|
+
Enable debug logging for security events:
|
345
|
+
|
346
|
+
```ruby
|
347
|
+
# config/initializers/flowchat.rb
|
348
|
+
if Rails.env.development?
|
349
|
+
FlowChat::Config.logger.level = Logger::DEBUG
|
350
|
+
end
|
351
|
+
```
|
352
|
+
|
353
|
+
This will log security validation attempts and help troubleshoot configuration issues.
|
354
|
+
|
355
|
+
## Security Updates
|
356
|
+
|
357
|
+
This security system was introduced in FlowChat v2.0.0 and includes:
|
358
|
+
|
359
|
+
- HMAC-SHA256 webhook signature validation
|
360
|
+
- Secure simulator authentication with signed cookies
|
361
|
+
- Environment-specific security configuration
|
362
|
+
- Comprehensive error handling and logging
|
363
|
+
- Timing-attack resistant signature comparison
|
364
|
+
|
365
|
+
For the latest security updates and recommendations, check the FlowChat changelog and security advisories.
|
data/examples/initializer.rb
CHANGED
@@ -19,6 +19,22 @@ FlowChat::Config.cache = Rails.cache
|
|
19
19
|
# Configure logger (optional)
|
20
20
|
FlowChat::Config.logger = Rails.logger
|
21
21
|
|
22
|
+
# Configure simulator security (REQUIRED for simulator mode)
|
23
|
+
# This secret is used to authenticate simulator requests via signed cookies
|
24
|
+
case Rails.env
|
25
|
+
when 'development', 'test'
|
26
|
+
# Use Rails secret key with environment suffix for development
|
27
|
+
FlowChat::Config.simulator_secret = Rails.application.secret_key_base + "_#{Rails.env}"
|
28
|
+
when 'staging', 'production'
|
29
|
+
# Use environment variable for production security
|
30
|
+
FlowChat::Config.simulator_secret = ENV['FLOWCHAT_SIMULATOR_SECRET']
|
31
|
+
|
32
|
+
# Fail fast if simulator secret is not configured but might be needed
|
33
|
+
if FlowChat::Config.simulator_secret.blank?
|
34
|
+
Rails.logger.warn "FLOWCHAT_SIMULATOR_SECRET not configured. Simulator mode will be unavailable."
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
22
38
|
# Configure USSD pagination (optional)
|
23
39
|
FlowChat::Config.ussd.pagination_page_size = 140
|
24
40
|
FlowChat::Config.ussd.pagination_back_option = "0"
|
@@ -29,3 +45,42 @@ FlowChat::Config.ussd.pagination_next_text = "More"
|
|
29
45
|
# Configure resumable sessions (optional)
|
30
46
|
FlowChat::Config.ussd.resumable_sessions_enabled = true
|
31
47
|
FlowChat::Config.ussd.resumable_sessions_timeout_seconds = 300 # 5 minutes
|
48
|
+
|
49
|
+
# Configure WhatsApp message handling mode based on environment
|
50
|
+
case Rails.env
|
51
|
+
when 'development'
|
52
|
+
# Development: Use simulator mode for easy testing
|
53
|
+
FlowChat::Config.whatsapp.message_handling_mode = :simulator
|
54
|
+
|
55
|
+
when 'test'
|
56
|
+
# Test: Use simulator mode for deterministic testing
|
57
|
+
FlowChat::Config.whatsapp.message_handling_mode = :simulator
|
58
|
+
|
59
|
+
when 'staging'
|
60
|
+
# Staging: Use inline mode for real WhatsApp testing
|
61
|
+
FlowChat::Config.whatsapp.message_handling_mode = :inline
|
62
|
+
|
63
|
+
when 'production'
|
64
|
+
# Production: Use background mode for high volume
|
65
|
+
FlowChat::Config.whatsapp.message_handling_mode = :background
|
66
|
+
FlowChat::Config.whatsapp.background_job_class = 'WhatsappMessageJob'
|
67
|
+
end
|
68
|
+
|
69
|
+
# Configure per-environment WhatsApp security
|
70
|
+
# Note: These are global defaults. You can override per-configuration in your controllers.
|
71
|
+
|
72
|
+
# Example of per-environment WhatsApp security configuration:
|
73
|
+
#
|
74
|
+
# For development/test: You might want to disable signature validation for easier testing
|
75
|
+
# For staging: Enable validation to match production behavior
|
76
|
+
# For production: Always enable validation for security
|
77
|
+
#
|
78
|
+
# Individual WhatsApp configurations can override these settings:
|
79
|
+
#
|
80
|
+
# config = FlowChat::Whatsapp::Configuration.new
|
81
|
+
# config.access_token = "your_token"
|
82
|
+
# config.app_secret = "your_app_secret" # Required for webhook validation
|
83
|
+
# config.skip_signature_validation = false # false = validate signatures (recommended)
|
84
|
+
#
|
85
|
+
# Development override example:
|
86
|
+
# config.skip_signature_validation = Rails.env.development? # Only skip in development
|
@@ -11,7 +11,11 @@ class MultiTenantWhatsappController < ApplicationController
|
|
11
11
|
# Get tenant-specific WhatsApp configuration
|
12
12
|
whatsapp_config = get_whatsapp_config_for_tenant(tenant)
|
13
13
|
|
14
|
-
|
14
|
+
# Enable simulator for local endpoint testing during development
|
15
|
+
# This allows testing different tenant endpoints via the simulator interface
|
16
|
+
enable_simulator = Rails.env.development? || Rails.env.staging?
|
17
|
+
|
18
|
+
processor = FlowChat::Whatsapp::Processor.new(self, enable_simulator: enable_simulator) do |config|
|
15
19
|
config.use_gateway FlowChat::Whatsapp::Gateway::CloudApi, whatsapp_config
|
16
20
|
config.use_session_store FlowChat::Session::CacheSessionStore
|
17
21
|
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# Example Simulator Controller
|
2
|
+
# Add this to your Rails application as app/controllers/simulator_controller.rb
|
3
|
+
|
4
|
+
class SimulatorController < ApplicationController
|
5
|
+
include FlowChat::Simulator::Controller
|
6
|
+
|
7
|
+
def index
|
8
|
+
flowchat_simulator
|
9
|
+
end
|
10
|
+
|
11
|
+
protected
|
12
|
+
|
13
|
+
# Define different local endpoints to test on the same server
|
14
|
+
def configurations
|
15
|
+
{
|
16
|
+
ussd_main: {
|
17
|
+
name: "Main USSD Endpoint",
|
18
|
+
description: "Primary USSD integration endpoint",
|
19
|
+
processor_type: "ussd",
|
20
|
+
provider: "nalo",
|
21
|
+
endpoint: "/ussd",
|
22
|
+
icon: "📱",
|
23
|
+
color: "#28a745"
|
24
|
+
},
|
25
|
+
whatsapp_main: {
|
26
|
+
name: "Main WhatsApp Endpoint",
|
27
|
+
description: "Primary WhatsApp webhook endpoint",
|
28
|
+
processor_type: "whatsapp",
|
29
|
+
provider: "cloud_api",
|
30
|
+
endpoint: "/whatsapp/webhook",
|
31
|
+
icon: "💬",
|
32
|
+
color: "#25D366"
|
33
|
+
},
|
34
|
+
whatsapp_v2: {
|
35
|
+
name: "WhatsApp API v2",
|
36
|
+
description: "Alternative WhatsApp endpoint (v2 API)",
|
37
|
+
processor_type: "whatsapp",
|
38
|
+
provider: "cloud_api",
|
39
|
+
endpoint: "/api/v2/whatsapp/webhook",
|
40
|
+
icon: "🔄",
|
41
|
+
color: "#17a2b8"
|
42
|
+
},
|
43
|
+
whatsapp_tenant_a: {
|
44
|
+
name: "Tenant A WhatsApp",
|
45
|
+
description: "Multi-tenant WhatsApp endpoint for Tenant A",
|
46
|
+
processor_type: "whatsapp",
|
47
|
+
provider: "cloud_api",
|
48
|
+
endpoint: "/tenants/a/whatsapp/webhook",
|
49
|
+
icon: "🏢",
|
50
|
+
color: "#fd7e14"
|
51
|
+
},
|
52
|
+
whatsapp_legacy: {
|
53
|
+
name: "Legacy WhatsApp",
|
54
|
+
description: "Legacy WhatsApp endpoint for backward compatibility",
|
55
|
+
processor_type: "whatsapp",
|
56
|
+
provider: "cloud_api",
|
57
|
+
endpoint: "/legacy/whatsapp",
|
58
|
+
icon: "📦",
|
59
|
+
color: "#6c757d"
|
60
|
+
}
|
61
|
+
}
|
62
|
+
end
|
63
|
+
|
64
|
+
# Default configuration to start with
|
65
|
+
def default_config_key
|
66
|
+
:whatsapp_main
|
67
|
+
end
|
68
|
+
|
69
|
+
# Default test phone number
|
70
|
+
def default_phone_number
|
71
|
+
"+1234567890"
|
72
|
+
end
|
73
|
+
|
74
|
+
# Default test contact name
|
75
|
+
def default_contact_name
|
76
|
+
"Test User"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Add this route to your config/routes.rb:
|
81
|
+
# get '/simulator' => 'simulator#index'
|
82
|
+
|
83
|
+
# Usage:
|
84
|
+
# 1. Start your Rails server: rails server
|
85
|
+
# 2. Visit http://localhost:3000/simulator
|
86
|
+
# 3. Select different endpoints from the dropdown to test
|
87
|
+
# 4. Send test messages to see how each endpoint responds
|
88
|
+
# 5. View request/response logs in real-time
|
89
|
+
|
90
|
+
# This allows you to test:
|
91
|
+
# - Different controller implementations on the same server
|
92
|
+
# - Different API versions (v1, v2, etc.)
|
93
|
+
# - Multi-tenant endpoints with different configurations
|
94
|
+
# - Legacy endpoints alongside new ones
|
95
|
+
# - Different flow implementations for different endpoints
|
@@ -5,17 +5,24 @@ class WhatsappController < ApplicationController
|
|
5
5
|
skip_forgery_protection
|
6
6
|
|
7
7
|
def webhook
|
8
|
-
|
8
|
+
# Enable simulator mode for local endpoint testing in development
|
9
|
+
processor = FlowChat::Whatsapp::Processor.new(self, enable_simulator: Rails.env.development?) do |config|
|
9
10
|
config.use_gateway FlowChat::Whatsapp::Gateway::CloudApi
|
10
11
|
# Use cache-based session store for longer WhatsApp conversations
|
11
12
|
config.use_session_store FlowChat::Session::CacheSessionStore
|
12
13
|
end
|
13
14
|
|
14
15
|
processor.run WelcomeFlow, :main_page
|
16
|
+
rescue FlowChat::Whatsapp::ConfigurationError => e
|
17
|
+
Rails.logger.error "WhatsApp configuration error: #{e.message}"
|
18
|
+
head :internal_server_error
|
19
|
+
rescue => e
|
20
|
+
Rails.logger.error "Unexpected error processing WhatsApp webhook: #{e.message}"
|
21
|
+
head :internal_server_error
|
15
22
|
end
|
16
23
|
end
|
17
24
|
|
18
|
-
# Example with Custom Configuration
|
25
|
+
# Example with Custom Configuration and Security
|
19
26
|
class CustomWhatsappController < ApplicationController
|
20
27
|
skip_forgery_protection
|
21
28
|
|
@@ -28,13 +35,95 @@ class CustomWhatsappController < ApplicationController
|
|
28
35
|
custom_config.app_id = ENV["MY_WHATSAPP_APP_ID"]
|
29
36
|
custom_config.app_secret = ENV["MY_WHATSAPP_APP_SECRET"]
|
30
37
|
custom_config.business_account_id = ENV["MY_WHATSAPP_BUSINESS_ACCOUNT_ID"]
|
38
|
+
|
39
|
+
# Security configuration
|
40
|
+
custom_config.skip_signature_validation = !Rails.env.production? # Only skip in non-production
|
31
41
|
|
32
|
-
|
42
|
+
# Enable simulator for local endpoint testing in non-production environments
|
43
|
+
processor = FlowChat::Whatsapp::Processor.new(self, enable_simulator: !Rails.env.production?) do |config|
|
33
44
|
config.use_gateway FlowChat::Whatsapp::Gateway::CloudApi, custom_config
|
34
45
|
config.use_session_store FlowChat::Session::CacheSessionStore
|
35
46
|
end
|
36
47
|
|
37
48
|
processor.run WelcomeFlow, :main_page
|
49
|
+
rescue FlowChat::Whatsapp::ConfigurationError => e
|
50
|
+
Rails.logger.error "WhatsApp configuration error: #{e.message}"
|
51
|
+
head :internal_server_error
|
52
|
+
rescue => e
|
53
|
+
Rails.logger.error "Unexpected error processing WhatsApp webhook: #{e.message}"
|
54
|
+
head :internal_server_error
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Example with Environment-Specific Security
|
59
|
+
class EnvironmentAwareWhatsappController < ApplicationController
|
60
|
+
skip_forgery_protection
|
61
|
+
|
62
|
+
def webhook
|
63
|
+
# Configure security based on environment
|
64
|
+
custom_config = build_whatsapp_config
|
65
|
+
|
66
|
+
# Enable simulator for local endpoint testing in development/staging
|
67
|
+
enable_simulator = Rails.env.development? || Rails.env.staging?
|
68
|
+
|
69
|
+
processor = FlowChat::Whatsapp::Processor.new(self, enable_simulator: enable_simulator) do |config|
|
70
|
+
config.use_gateway FlowChat::Whatsapp::Gateway::CloudApi, custom_config
|
71
|
+
config.use_session_store FlowChat::Session::CacheSessionStore
|
72
|
+
end
|
73
|
+
|
74
|
+
processor.run WelcomeFlow, :main_page
|
75
|
+
rescue FlowChat::Whatsapp::ConfigurationError => e
|
76
|
+
Rails.logger.error "WhatsApp configuration error: #{e.message}"
|
77
|
+
head :internal_server_error
|
78
|
+
rescue => e
|
79
|
+
Rails.logger.error "Unexpected error processing WhatsApp webhook: #{e.message}"
|
80
|
+
head :internal_server_error
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
def build_whatsapp_config
|
86
|
+
config = FlowChat::Whatsapp::Configuration.new
|
87
|
+
|
88
|
+
case Rails.env
|
89
|
+
when 'development'
|
90
|
+
# Development: More relaxed security for easier testing
|
91
|
+
config.access_token = ENV["WHATSAPP_ACCESS_TOKEN"]
|
92
|
+
config.phone_number_id = ENV["WHATSAPP_PHONE_NUMBER_ID"]
|
93
|
+
config.verify_token = ENV["WHATSAPP_VERIFY_TOKEN"]
|
94
|
+
config.app_id = ENV["WHATSAPP_APP_ID"]
|
95
|
+
config.app_secret = ENV["WHATSAPP_APP_SECRET"] # Optional in development
|
96
|
+
config.business_account_id = ENV["WHATSAPP_BUSINESS_ACCOUNT_ID"]
|
97
|
+
config.skip_signature_validation = true # Skip validation for easier development
|
98
|
+
|
99
|
+
when 'test'
|
100
|
+
# Test: Use test credentials
|
101
|
+
config.access_token = "test_token"
|
102
|
+
config.phone_number_id = "test_phone_id"
|
103
|
+
config.verify_token = "test_verify_token"
|
104
|
+
config.app_id = "test_app_id"
|
105
|
+
config.app_secret = "test_app_secret"
|
106
|
+
config.business_account_id = "test_business_id"
|
107
|
+
config.skip_signature_validation = true # Skip validation in tests
|
108
|
+
|
109
|
+
when 'staging', 'production'
|
110
|
+
# Production: Full security enabled
|
111
|
+
config.access_token = ENV["WHATSAPP_ACCESS_TOKEN"]
|
112
|
+
config.phone_number_id = ENV["WHATSAPP_PHONE_NUMBER_ID"]
|
113
|
+
config.verify_token = ENV["WHATSAPP_VERIFY_TOKEN"]
|
114
|
+
config.app_id = ENV["WHATSAPP_APP_ID"]
|
115
|
+
config.app_secret = ENV["WHATSAPP_APP_SECRET"] # Required for security
|
116
|
+
config.business_account_id = ENV["WHATSAPP_BUSINESS_ACCOUNT_ID"]
|
117
|
+
config.skip_signature_validation = false # Always validate in production
|
118
|
+
|
119
|
+
# Ensure required security configuration is present
|
120
|
+
if config.app_secret.blank?
|
121
|
+
raise FlowChat::Whatsapp::ConfigurationError,
|
122
|
+
"WHATSAPP_APP_SECRET is required for webhook signature validation in #{Rails.env}"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
config
|
38
127
|
end
|
39
128
|
end
|
40
129
|
|
@@ -4,9 +4,10 @@ module FlowChat
|
|
4
4
|
class BaseProcessor
|
5
5
|
attr_reader :middleware
|
6
6
|
|
7
|
-
def initialize(controller)
|
7
|
+
def initialize(controller, enable_simulator: nil)
|
8
8
|
@context = FlowChat::Context.new
|
9
9
|
@context["controller"] = controller
|
10
|
+
@context["enable_simulator"] = enable_simulator.nil? ? (defined?(Rails) && Rails.env.local?) : enable_simulator
|
10
11
|
@middleware = ::Middleware::Builder.new(name: middleware_name)
|
11
12
|
|
12
13
|
yield self if block_given?
|
data/lib/flow_chat/config.rb
CHANGED
@@ -3,6 +3,7 @@ module FlowChat
|
|
3
3
|
# General framework configuration
|
4
4
|
mattr_accessor :logger, default: Logger.new($stdout)
|
5
5
|
mattr_accessor :cache, default: nil
|
6
|
+
mattr_accessor :simulator_secret, default: nil
|
6
7
|
|
7
8
|
# USSD-specific configuration object
|
8
9
|
def self.ussd
|
@@ -33,11 +34,12 @@ module FlowChat
|
|
33
34
|
|
34
35
|
class WhatsappConfig
|
35
36
|
attr_accessor :background_job_class
|
36
|
-
attr_reader :message_handling_mode
|
37
|
+
attr_reader :message_handling_mode, :api_base_url
|
37
38
|
|
38
39
|
def initialize
|
39
40
|
@message_handling_mode = :inline
|
40
41
|
@background_job_class = "WhatsappMessageJob"
|
42
|
+
@api_base_url = "https://graph.facebook.com/v22.0"
|
41
43
|
end
|
42
44
|
|
43
45
|
# Validate message handling mode
|