webhukhs 0.5.0
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 +7 -0
- data/.editorconfig +14 -0
- data/.rubocop.yml +9 -0
- data/.standard.yml +3 -0
- data/Appraisals +13 -0
- data/CHANGELOG.md +54 -0
- data/LICENSE +21 -0
- data/README.md +71 -0
- data/Rakefile +26 -0
- data/config/routes.rb +3 -0
- data/example/.gitattributes +7 -0
- data/example/.gitignore +29 -0
- data/example/.ruby-version +1 -0
- data/example/Gemfile +32 -0
- data/example/Gemfile.lock +228 -0
- data/example/README.md +24 -0
- data/example/Rakefile +8 -0
- data/example/app/assets/images/.keep +0 -0
- data/example/app/assets/stylesheets/application.css +1 -0
- data/example/app/controllers/application_controller.rb +4 -0
- data/example/app/controllers/concerns/.keep +0 -0
- data/example/app/helpers/application_helper.rb +4 -0
- data/example/app/models/application_record.rb +5 -0
- data/example/app/models/concerns/.keep +0 -0
- data/example/app/views/layouts/application.html.erb +15 -0
- data/example/app/webhooks/webhook_test_handler.rb +13 -0
- data/example/bin/bundle +109 -0
- data/example/bin/rails +4 -0
- data/example/bin/rake +4 -0
- data/example/bin/setup +33 -0
- data/example/config/application.rb +39 -0
- data/example/config/boot.rb +5 -0
- data/example/config/credentials.yml.enc +1 -0
- data/example/config/database.yml +25 -0
- data/example/config/environment.rb +7 -0
- data/example/config/environments/development.rb +61 -0
- data/example/config/environments/production.rb +71 -0
- data/example/config/environments/test.rb +52 -0
- data/example/config/initializers/assets.rb +14 -0
- data/example/config/initializers/content_security_policy.rb +27 -0
- data/example/config/initializers/filter_parameter_logging.rb +10 -0
- data/example/config/initializers/generators.rb +7 -0
- data/example/config/initializers/inflections.rb +18 -0
- data/example/config/initializers/permissions_policy.rb +13 -0
- data/example/config/initializers/webhukhs.rb +9 -0
- data/example/config/locales/en.yml +33 -0
- data/example/config/puma.rb +45 -0
- data/example/config/routes.rb +5 -0
- data/example/config.ru +8 -0
- data/example/db/migrate/20240523125859_create_webhukhs_tables.rb +22 -0
- data/example/db/schema.rb +24 -0
- data/example/db/seeds.rb +9 -0
- data/example/lib/assets/.keep +0 -0
- data/example/lib/tasks/.keep +0 -0
- data/example/log/.keep +0 -0
- data/example/public/404.html +67 -0
- data/example/public/422.html +67 -0
- data/example/public/500.html +66 -0
- data/example/public/apple-touch-icon-precomposed.png +0 -0
- data/example/public/apple-touch-icon.png +0 -0
- data/example/public/favicon.ico +0 -0
- data/example/public/robots.txt +1 -0
- data/example/test/controllers/.keep +0 -0
- data/example/test/fixtures/files/.keep +0 -0
- data/example/test/helpers/.keep +0 -0
- data/example/test/integration/.keep +0 -0
- data/example/test/models/.keep +0 -0
- data/example/test/test_helper.rb +15 -0
- data/example/tmp/.keep +0 -0
- data/example/tmp/pids/.keep +0 -0
- data/example/vendor/.keep +0 -0
- data/gemfiles/rails_7.1.gemfile +10 -0
- data/gemfiles/rails_7.1.gemfile.lock +412 -0
- data/gemfiles/rails_8.0.gemfile +10 -0
- data/gemfiles/rails_8.0.gemfile.lock +405 -0
- data/gemfiles/rails_8.1.gemfile +10 -0
- data/gemfiles/rails_8.1.gemfile.lock +405 -0
- data/handler-examples/customer_io_handler.rb +36 -0
- data/handler-examples/revolut_business_v1_handler.rb +29 -0
- data/handler-examples/revolut_business_v2_handler.rb +42 -0
- data/handler-examples/starling_payments_handler.rb +25 -0
- data/lib/tasks/webhukhs_tasks.rake +4 -0
- data/lib/webhukhs/base_handler.rb +100 -0
- data/lib/webhukhs/controllers/receive_webhooks_controller.rb +55 -0
- data/lib/webhukhs/engine.rb +24 -0
- data/lib/webhukhs/install_generator.rb +31 -0
- data/lib/webhukhs/jobs/processing_job.rb +33 -0
- data/lib/webhukhs/models/received_webhook.rb +99 -0
- data/lib/webhukhs/templates/add_headers_to_webhukhs_webhooks.rb.erb +5 -0
- data/lib/webhukhs/templates/create_webhukhs_tables.rb.erb +23 -0
- data/lib/webhukhs/templates/webhukhs.rb +40 -0
- data/lib/webhukhs/version.rb +5 -0
- data/lib/webhukhs.rb +23 -0
- data/test/test-webhook-handlers/.DS_Store +0 -0
- data/test/test-webhook-handlers/extract_id_handler.rb +5 -0
- data/test/test-webhook-handlers/failing_with_concealed_errors.rb +7 -0
- data/test/test-webhook-handlers/failing_with_exposed_errors.rb +7 -0
- data/test/test-webhook-handlers/inactive_handler.rb +5 -0
- data/test/test-webhook-handlers/invalid_handler.rb +5 -0
- data/test/test-webhook-handlers/private_handler.rb +3 -0
- data/test/test-webhook-handlers/webhook_test_handler.rb +13 -0
- data/test/test_app.rb +66 -0
- data/test/test_helper.rb +50 -0
- data/test/webhukhs_test.rb +203 -0
- metadata +247 -0
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: ..
|
|
3
|
+
specs:
|
|
4
|
+
webhukhs (0.5.0)
|
|
5
|
+
rails (>= 7.0)
|
|
6
|
+
state_machine_enum
|
|
7
|
+
|
|
8
|
+
GEM
|
|
9
|
+
remote: https://rubygems.org/
|
|
10
|
+
specs:
|
|
11
|
+
action_text-trix (2.1.16)
|
|
12
|
+
railties
|
|
13
|
+
actioncable (8.1.1)
|
|
14
|
+
actionpack (= 8.1.1)
|
|
15
|
+
activesupport (= 8.1.1)
|
|
16
|
+
nio4r (~> 2.0)
|
|
17
|
+
websocket-driver (>= 0.6.1)
|
|
18
|
+
zeitwerk (~> 2.6)
|
|
19
|
+
actionmailbox (8.1.1)
|
|
20
|
+
actionpack (= 8.1.1)
|
|
21
|
+
activejob (= 8.1.1)
|
|
22
|
+
activerecord (= 8.1.1)
|
|
23
|
+
activestorage (= 8.1.1)
|
|
24
|
+
activesupport (= 8.1.1)
|
|
25
|
+
mail (>= 2.8.0)
|
|
26
|
+
actionmailer (8.1.1)
|
|
27
|
+
actionpack (= 8.1.1)
|
|
28
|
+
actionview (= 8.1.1)
|
|
29
|
+
activejob (= 8.1.1)
|
|
30
|
+
activesupport (= 8.1.1)
|
|
31
|
+
mail (>= 2.8.0)
|
|
32
|
+
rails-dom-testing (~> 2.2)
|
|
33
|
+
actionpack (8.1.1)
|
|
34
|
+
actionview (= 8.1.1)
|
|
35
|
+
activesupport (= 8.1.1)
|
|
36
|
+
nokogiri (>= 1.8.5)
|
|
37
|
+
rack (>= 2.2.4)
|
|
38
|
+
rack-session (>= 1.0.1)
|
|
39
|
+
rack-test (>= 0.6.3)
|
|
40
|
+
rails-dom-testing (~> 2.2)
|
|
41
|
+
rails-html-sanitizer (~> 1.6)
|
|
42
|
+
useragent (~> 0.16)
|
|
43
|
+
actiontext (8.1.1)
|
|
44
|
+
action_text-trix (~> 2.1.15)
|
|
45
|
+
actionpack (= 8.1.1)
|
|
46
|
+
activerecord (= 8.1.1)
|
|
47
|
+
activestorage (= 8.1.1)
|
|
48
|
+
activesupport (= 8.1.1)
|
|
49
|
+
globalid (>= 0.6.0)
|
|
50
|
+
nokogiri (>= 1.8.5)
|
|
51
|
+
actionview (8.1.1)
|
|
52
|
+
activesupport (= 8.1.1)
|
|
53
|
+
builder (~> 3.1)
|
|
54
|
+
erubi (~> 1.11)
|
|
55
|
+
rails-dom-testing (~> 2.2)
|
|
56
|
+
rails-html-sanitizer (~> 1.6)
|
|
57
|
+
activejob (8.1.1)
|
|
58
|
+
activesupport (= 8.1.1)
|
|
59
|
+
globalid (>= 0.3.6)
|
|
60
|
+
activemodel (8.1.1)
|
|
61
|
+
activesupport (= 8.1.1)
|
|
62
|
+
activerecord (8.1.1)
|
|
63
|
+
activemodel (= 8.1.1)
|
|
64
|
+
activesupport (= 8.1.1)
|
|
65
|
+
timeout (>= 0.4.0)
|
|
66
|
+
activestorage (8.1.1)
|
|
67
|
+
actionpack (= 8.1.1)
|
|
68
|
+
activejob (= 8.1.1)
|
|
69
|
+
activerecord (= 8.1.1)
|
|
70
|
+
activesupport (= 8.1.1)
|
|
71
|
+
marcel (~> 1.0)
|
|
72
|
+
activesupport (8.1.1)
|
|
73
|
+
base64
|
|
74
|
+
bigdecimal
|
|
75
|
+
concurrent-ruby (~> 1.0, >= 1.3.1)
|
|
76
|
+
connection_pool (>= 2.2.5)
|
|
77
|
+
drb
|
|
78
|
+
i18n (>= 1.6, < 2)
|
|
79
|
+
json
|
|
80
|
+
logger (>= 1.4.2)
|
|
81
|
+
minitest (>= 5.1)
|
|
82
|
+
securerandom (>= 0.3)
|
|
83
|
+
tzinfo (~> 2.0, >= 2.0.5)
|
|
84
|
+
uri (>= 0.13.1)
|
|
85
|
+
appraisal (2.5.0)
|
|
86
|
+
bundler
|
|
87
|
+
rake
|
|
88
|
+
thor (>= 0.14.0)
|
|
89
|
+
ast (2.4.3)
|
|
90
|
+
base64 (0.3.0)
|
|
91
|
+
bigdecimal (4.0.1)
|
|
92
|
+
builder (3.3.0)
|
|
93
|
+
concurrent-ruby (1.3.6)
|
|
94
|
+
connection_pool (3.0.2)
|
|
95
|
+
crass (1.0.6)
|
|
96
|
+
date (3.5.1)
|
|
97
|
+
drb (2.2.3)
|
|
98
|
+
erb (6.0.1)
|
|
99
|
+
erubi (1.13.1)
|
|
100
|
+
globalid (1.3.0)
|
|
101
|
+
activesupport (>= 6.1)
|
|
102
|
+
i18n (1.14.8)
|
|
103
|
+
concurrent-ruby (~> 1.0)
|
|
104
|
+
io-console (0.8.2)
|
|
105
|
+
irb (1.16.0)
|
|
106
|
+
pp (>= 0.6.0)
|
|
107
|
+
rdoc (>= 4.0.0)
|
|
108
|
+
reline (>= 0.4.2)
|
|
109
|
+
json (2.18.0)
|
|
110
|
+
language_server-protocol (3.17.0.5)
|
|
111
|
+
lint_roller (1.1.0)
|
|
112
|
+
logger (1.7.0)
|
|
113
|
+
loofah (2.25.0)
|
|
114
|
+
crass (~> 1.0.2)
|
|
115
|
+
nokogiri (>= 1.12.0)
|
|
116
|
+
magic_frozen_string_literal (1.2.0)
|
|
117
|
+
mail (2.9.0)
|
|
118
|
+
logger
|
|
119
|
+
mini_mime (>= 0.1.1)
|
|
120
|
+
net-imap
|
|
121
|
+
net-pop
|
|
122
|
+
net-smtp
|
|
123
|
+
marcel (1.1.0)
|
|
124
|
+
mini_mime (1.1.5)
|
|
125
|
+
minitest (5.27.0)
|
|
126
|
+
net-imap (0.6.2)
|
|
127
|
+
date
|
|
128
|
+
net-protocol
|
|
129
|
+
net-pop (0.1.2)
|
|
130
|
+
net-protocol
|
|
131
|
+
net-protocol (0.2.2)
|
|
132
|
+
timeout
|
|
133
|
+
net-smtp (0.5.1)
|
|
134
|
+
net-protocol
|
|
135
|
+
nio4r (2.7.5)
|
|
136
|
+
nokogiri (1.19.0-aarch64-linux-gnu)
|
|
137
|
+
racc (~> 1.4)
|
|
138
|
+
nokogiri (1.19.0-aarch64-linux-musl)
|
|
139
|
+
racc (~> 1.4)
|
|
140
|
+
nokogiri (1.19.0-arm-linux-gnu)
|
|
141
|
+
racc (~> 1.4)
|
|
142
|
+
nokogiri (1.19.0-arm-linux-musl)
|
|
143
|
+
racc (~> 1.4)
|
|
144
|
+
nokogiri (1.19.0-arm64-darwin)
|
|
145
|
+
racc (~> 1.4)
|
|
146
|
+
nokogiri (1.19.0-x86_64-darwin)
|
|
147
|
+
racc (~> 1.4)
|
|
148
|
+
nokogiri (1.19.0-x86_64-linux-gnu)
|
|
149
|
+
racc (~> 1.4)
|
|
150
|
+
nokogiri (1.19.0-x86_64-linux-musl)
|
|
151
|
+
racc (~> 1.4)
|
|
152
|
+
parallel (1.27.0)
|
|
153
|
+
parser (3.3.10.0)
|
|
154
|
+
ast (~> 2.4.1)
|
|
155
|
+
racc
|
|
156
|
+
pp (0.6.3)
|
|
157
|
+
prettyprint
|
|
158
|
+
prettyprint (0.2.0)
|
|
159
|
+
prism (1.7.0)
|
|
160
|
+
psych (5.3.1)
|
|
161
|
+
date
|
|
162
|
+
stringio
|
|
163
|
+
racc (1.8.1)
|
|
164
|
+
rack (3.2.4)
|
|
165
|
+
rack-session (2.1.1)
|
|
166
|
+
base64 (>= 0.1.0)
|
|
167
|
+
rack (>= 3.0.0)
|
|
168
|
+
rack-test (2.2.0)
|
|
169
|
+
rack (>= 1.3)
|
|
170
|
+
rackup (2.3.1)
|
|
171
|
+
rack (>= 3)
|
|
172
|
+
rails (8.1.1)
|
|
173
|
+
actioncable (= 8.1.1)
|
|
174
|
+
actionmailbox (= 8.1.1)
|
|
175
|
+
actionmailer (= 8.1.1)
|
|
176
|
+
actionpack (= 8.1.1)
|
|
177
|
+
actiontext (= 8.1.1)
|
|
178
|
+
actionview (= 8.1.1)
|
|
179
|
+
activejob (= 8.1.1)
|
|
180
|
+
activemodel (= 8.1.1)
|
|
181
|
+
activerecord (= 8.1.1)
|
|
182
|
+
activestorage (= 8.1.1)
|
|
183
|
+
activesupport (= 8.1.1)
|
|
184
|
+
bundler (>= 1.15.0)
|
|
185
|
+
railties (= 8.1.1)
|
|
186
|
+
rails-dom-testing (2.3.0)
|
|
187
|
+
activesupport (>= 5.0.0)
|
|
188
|
+
minitest
|
|
189
|
+
nokogiri (>= 1.6)
|
|
190
|
+
rails-html-sanitizer (1.6.2)
|
|
191
|
+
loofah (~> 2.21)
|
|
192
|
+
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
|
|
193
|
+
railties (8.1.1)
|
|
194
|
+
actionpack (= 8.1.1)
|
|
195
|
+
activesupport (= 8.1.1)
|
|
196
|
+
irb (~> 1.13)
|
|
197
|
+
rackup (>= 1.0.0)
|
|
198
|
+
rake (>= 12.2)
|
|
199
|
+
thor (~> 1.0, >= 1.2.2)
|
|
200
|
+
tsort (>= 0.2)
|
|
201
|
+
zeitwerk (~> 2.6)
|
|
202
|
+
rainbow (3.1.1)
|
|
203
|
+
rake (13.3.1)
|
|
204
|
+
rdoc (7.0.3)
|
|
205
|
+
erb
|
|
206
|
+
psych (>= 4.0.0)
|
|
207
|
+
tsort
|
|
208
|
+
regexp_parser (2.11.3)
|
|
209
|
+
reline (0.6.3)
|
|
210
|
+
io-console (~> 0.5)
|
|
211
|
+
rubocop (1.81.7)
|
|
212
|
+
json (~> 2.3)
|
|
213
|
+
language_server-protocol (~> 3.17.0.2)
|
|
214
|
+
lint_roller (~> 1.1.0)
|
|
215
|
+
parallel (~> 1.10)
|
|
216
|
+
parser (>= 3.3.0.2)
|
|
217
|
+
rainbow (>= 2.2.2, < 4.0)
|
|
218
|
+
regexp_parser (>= 2.9.3, < 3.0)
|
|
219
|
+
rubocop-ast (>= 1.47.1, < 2.0)
|
|
220
|
+
ruby-progressbar (~> 1.7)
|
|
221
|
+
unicode-display_width (>= 2.4.0, < 4.0)
|
|
222
|
+
rubocop-ast (1.49.0)
|
|
223
|
+
parser (>= 3.3.7.2)
|
|
224
|
+
prism (~> 1.7)
|
|
225
|
+
rubocop-performance (1.26.1)
|
|
226
|
+
lint_roller (~> 1.1)
|
|
227
|
+
rubocop (>= 1.75.0, < 2.0)
|
|
228
|
+
rubocop-ast (>= 1.47.1, < 2.0)
|
|
229
|
+
ruby-progressbar (1.13.0)
|
|
230
|
+
securerandom (0.4.1)
|
|
231
|
+
sprockets (4.2.2)
|
|
232
|
+
concurrent-ruby (~> 1.0)
|
|
233
|
+
logger
|
|
234
|
+
rack (>= 2.2.4, < 4)
|
|
235
|
+
sprockets-rails (3.5.2)
|
|
236
|
+
actionpack (>= 6.1)
|
|
237
|
+
activesupport (>= 6.1)
|
|
238
|
+
sprockets (>= 3.0.0)
|
|
239
|
+
sqlite3 (2.9.0-aarch64-linux-gnu)
|
|
240
|
+
sqlite3 (2.9.0-aarch64-linux-musl)
|
|
241
|
+
sqlite3 (2.9.0-arm-linux-gnu)
|
|
242
|
+
sqlite3 (2.9.0-arm-linux-musl)
|
|
243
|
+
sqlite3 (2.9.0-arm64-darwin)
|
|
244
|
+
sqlite3 (2.9.0-x86_64-darwin)
|
|
245
|
+
sqlite3 (2.9.0-x86_64-linux-gnu)
|
|
246
|
+
sqlite3 (2.9.0-x86_64-linux-musl)
|
|
247
|
+
standard (1.52.0)
|
|
248
|
+
language_server-protocol (~> 3.17.0.2)
|
|
249
|
+
lint_roller (~> 1.0)
|
|
250
|
+
rubocop (~> 1.81.7)
|
|
251
|
+
standard-custom (~> 1.0.0)
|
|
252
|
+
standard-performance (~> 1.8)
|
|
253
|
+
standard-custom (1.0.2)
|
|
254
|
+
lint_roller (~> 1.0)
|
|
255
|
+
rubocop (~> 1.50)
|
|
256
|
+
standard-performance (1.9.0)
|
|
257
|
+
lint_roller (~> 1.1)
|
|
258
|
+
rubocop-performance (~> 1.26.0)
|
|
259
|
+
state_machine_enum (0.1.4)
|
|
260
|
+
activesupport (>= 7.0)
|
|
261
|
+
stringio (3.2.0)
|
|
262
|
+
thor (1.4.0)
|
|
263
|
+
timeout (0.6.0)
|
|
264
|
+
tsort (0.2.0)
|
|
265
|
+
tzinfo (2.0.6)
|
|
266
|
+
concurrent-ruby (~> 1.0)
|
|
267
|
+
unicode-display_width (3.2.0)
|
|
268
|
+
unicode-emoji (~> 4.1)
|
|
269
|
+
unicode-emoji (4.2.0)
|
|
270
|
+
uri (1.1.1)
|
|
271
|
+
useragent (0.16.11)
|
|
272
|
+
websocket-driver (0.8.0)
|
|
273
|
+
base64
|
|
274
|
+
websocket-extensions (>= 0.1.0)
|
|
275
|
+
websocket-extensions (0.1.5)
|
|
276
|
+
zeitwerk (2.7.4)
|
|
277
|
+
|
|
278
|
+
PLATFORMS
|
|
279
|
+
aarch64-linux-gnu
|
|
280
|
+
aarch64-linux-musl
|
|
281
|
+
arm-linux-gnu
|
|
282
|
+
arm-linux-musl
|
|
283
|
+
arm64-darwin
|
|
284
|
+
x86_64-darwin
|
|
285
|
+
x86_64-linux-gnu
|
|
286
|
+
x86_64-linux-musl
|
|
287
|
+
|
|
288
|
+
DEPENDENCIES
|
|
289
|
+
appraisal
|
|
290
|
+
magic_frozen_string_literal
|
|
291
|
+
minitest (~> 5.0)
|
|
292
|
+
rails (~> 8.1)
|
|
293
|
+
rake (~> 13.0)
|
|
294
|
+
sprockets-rails
|
|
295
|
+
sqlite3
|
|
296
|
+
standard
|
|
297
|
+
webhukhs!
|
|
298
|
+
|
|
299
|
+
CHECKSUMS
|
|
300
|
+
action_text-trix (2.1.16) sha256=f645a2c21821b8449fd1d6770708f4031c91a2eedf9ef476e9be93c64e703a8a
|
|
301
|
+
actioncable (8.1.1) sha256=7262307e9693f09b299e281590110ce4b6ba7e4e4cee6da4b9d987eaf56f9139
|
|
302
|
+
actionmailbox (8.1.1) sha256=aa99703a9b2fa32c5a4a93bb21fef79e2935d8db4d1fd5ef0772847be5d43205
|
|
303
|
+
actionmailer (8.1.1) sha256=45755d7d4561363490ae82b17a5919bdef4dfe3bb400831819947c3a1d82afdf
|
|
304
|
+
actionpack (8.1.1) sha256=192e27c39a63c7d801ac7b6d50505f265e389516985eed9b2ee364896a6a06d7
|
|
305
|
+
actiontext (8.1.1) sha256=fd8d8da1e6bc0b04ff72fccfd127e78431238a99a82e736c7b52727c576a7640
|
|
306
|
+
actionview (8.1.1) sha256=ca480c8b099dea0862b0934f24182b84c2d29092e7dbf464fb3e6d4eb9b468dc
|
|
307
|
+
activejob (8.1.1) sha256=94f438a9f3b5a6b130fef53d8313f869dbd379309e7d639891bda36b12509383
|
|
308
|
+
activemodel (8.1.1) sha256=8b7e2496b9e333ced06248c16a43217b950192c98e0fe3aa117eee21501c6fbd
|
|
309
|
+
activerecord (8.1.1) sha256=e32c3a03e364fd803498eb4150c21bedc995aa83bc27122a94d480ab1dcb3d17
|
|
310
|
+
activestorage (8.1.1) sha256=bc01d8b4c55e309a0a2e218bfe502c382c9f232e28b1f4b0adc9d8719d2bf28d
|
|
311
|
+
activesupport (8.1.1) sha256=5e92534e8d0c8b8b5e6b16789c69dbea65c1d7b752269f71a39422e9546cea67
|
|
312
|
+
appraisal (2.5.0) sha256=36989221be127913b0dba8d114da2001e6b2dceea7bd4951200eaba764eed3ce
|
|
313
|
+
ast (2.4.3) sha256=954615157c1d6a382bc27d690d973195e79db7f55e9765ac7c481c60bdb4d383
|
|
314
|
+
base64 (0.3.0) sha256=27337aeabad6ffae05c265c450490628ef3ebd4b67be58257393227588f5a97b
|
|
315
|
+
bigdecimal (4.0.1) sha256=8b07d3d065a9f921c80ceaea7c9d4ae596697295b584c296fe599dd0ad01c4a7
|
|
316
|
+
builder (3.3.0) sha256=497918d2f9dca528fdca4b88d84e4ef4387256d984b8154e9d5d3fe5a9c8835f
|
|
317
|
+
concurrent-ruby (1.3.6) sha256=6b56837e1e7e5292f9864f34b69c5a2cbc75c0cf5338f1ce9903d10fa762d5ab
|
|
318
|
+
connection_pool (3.0.2) sha256=33fff5ba71a12d2aa26cb72b1db8bba2a1a01823559fb01d29eb74c286e62e0a
|
|
319
|
+
crass (1.0.6) sha256=dc516022a56e7b3b156099abc81b6d2b08ea1ed12676ac7a5657617f012bd45d
|
|
320
|
+
date (3.5.1) sha256=750d06384d7b9c15d562c76291407d89e368dda4d4fff957eb94962d325a0dc0
|
|
321
|
+
drb (2.2.3) sha256=0b00d6fdb50995fe4a45dea13663493c841112e4068656854646f418fda13373
|
|
322
|
+
erb (6.0.1) sha256=28ecdd99c5472aebd5674d6061e3c6b0a45c049578b071e5a52c2a7f13c197e5
|
|
323
|
+
erubi (1.13.1) sha256=a082103b0885dbc5ecf1172fede897f9ebdb745a4b97a5e8dc63953db1ee4ad9
|
|
324
|
+
globalid (1.3.0) sha256=05c639ad6eb4594522a0b07983022f04aa7254626ab69445a0e493aa3786ff11
|
|
325
|
+
i18n (1.14.8) sha256=285778639134865c5e0f6269e0b818256017e8cde89993fdfcbfb64d088824a5
|
|
326
|
+
io-console (0.8.2) sha256=d6e3ae7a7cc7574f4b8893b4fca2162e57a825b223a177b7afa236c5ef9814cc
|
|
327
|
+
irb (1.16.0) sha256=2abe56c9ac947cdcb2f150572904ba798c1e93c890c256f8429981a7675b0806
|
|
328
|
+
json (2.18.0) sha256=b10506aee4183f5cf49e0efc48073d7b75843ce3782c68dbeb763351c08fd505
|
|
329
|
+
language_server-protocol (3.17.0.5) sha256=fd1e39a51a28bf3eec959379985a72e296e9f9acfce46f6a79d31ca8760803cc
|
|
330
|
+
lint_roller (1.1.0) sha256=2c0c845b632a7d172cb849cc90c1bce937a28c5c8ccccb50dfd46a485003cc87
|
|
331
|
+
logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203
|
|
332
|
+
loofah (2.25.0) sha256=df5ed7ac3bac6a4ec802df3877ee5cc86d027299f8952e6243b3dac446b060e6
|
|
333
|
+
magic_frozen_string_literal (1.2.0) sha256=ba2014401bdd571339960c122f7bafe98f2dee6bcc2fe2600548666f65042eb7
|
|
334
|
+
mail (2.9.0) sha256=6fa6673ecd71c60c2d996260f9ee3dd387d4673b8169b502134659ece6d34941
|
|
335
|
+
marcel (1.1.0) sha256=fdcfcfa33cc52e93c4308d40e4090a5d4ea279e160a7f6af988260fa970e0bee
|
|
336
|
+
mini_mime (1.1.5) sha256=8681b7e2e4215f2a159f9400b5816d85e9d8c6c6b491e96a12797e798f8bccef
|
|
337
|
+
minitest (5.27.0) sha256=2d3b17f8a36fe7801c1adcffdbc38233b938eb0b4966e97a6739055a45fa77d5
|
|
338
|
+
net-imap (0.6.2) sha256=08caacad486853c61676cca0c0c47df93db02abc4a8239a8b67eb0981428acc6
|
|
339
|
+
net-pop (0.1.2) sha256=848b4e982013c15b2f0382792268763b748cce91c9e91e36b0f27ed26420dff3
|
|
340
|
+
net-protocol (0.2.2) sha256=aa73e0cba6a125369de9837b8d8ef82a61849360eba0521900e2c3713aa162a8
|
|
341
|
+
net-smtp (0.5.1) sha256=ed96a0af63c524fceb4b29b0d352195c30d82dd916a42f03c62a3a70e5b70736
|
|
342
|
+
nio4r (2.7.5) sha256=6c90168e48fb5f8e768419c93abb94ba2b892a1d0602cb06eef16d8b7df1dca1
|
|
343
|
+
nokogiri (1.19.0-aarch64-linux-gnu) sha256=11a97ecc3c0e7e5edcf395720b10860ef493b768f6aa80c539573530bc933767
|
|
344
|
+
nokogiri (1.19.0-aarch64-linux-musl) sha256=eb70507f5e01bc23dad9b8dbec2b36ad0e61d227b42d292835020ff754fb7ba9
|
|
345
|
+
nokogiri (1.19.0-arm-linux-gnu) sha256=572a259026b2c8b7c161fdb6469fa2d0edd2b61cd599db4bbda93289abefbfe5
|
|
346
|
+
nokogiri (1.19.0-arm-linux-musl) sha256=23ed90922f1a38aed555d3de4d058e90850c731c5b756d191b3dc8055948e73c
|
|
347
|
+
nokogiri (1.19.0-arm64-darwin) sha256=0811dfd936d5f6dd3f6d32ef790568bf29b2b7bead9ba68866847b33c9cf5810
|
|
348
|
+
nokogiri (1.19.0-x86_64-darwin) sha256=1dad56220b603a8edb9750cd95798bffa2b8dd9dd9aa47f664009ee5b43e3067
|
|
349
|
+
nokogiri (1.19.0-x86_64-linux-gnu) sha256=f482b95c713d60031d48c44ce14562f8d2ce31e3a9e8dd0ccb131e9e5a68b58c
|
|
350
|
+
nokogiri (1.19.0-x86_64-linux-musl) sha256=1c4ca6b381622420073ce6043443af1d321e8ed93cc18b08e2666e5bd02ffae4
|
|
351
|
+
parallel (1.27.0) sha256=4ac151e1806b755fb4e2dc2332cbf0e54f2e24ba821ff2d3dcf86bf6dc4ae130
|
|
352
|
+
parser (3.3.10.0) sha256=ce3587fa5cc55a88c4ba5b2b37621b3329aadf5728f9eafa36bbd121462aabd6
|
|
353
|
+
pp (0.6.3) sha256=2951d514450b93ccfeb1df7d021cae0da16e0a7f95ee1e2273719669d0ab9df6
|
|
354
|
+
prettyprint (0.2.0) sha256=2bc9e15581a94742064a3cc8b0fb9d45aae3d03a1baa6ef80922627a0766f193
|
|
355
|
+
prism (1.7.0) sha256=10062f734bf7985c8424c44fac382ac04a58124ea3d220ec3ba9fe4f2da65103
|
|
356
|
+
psych (5.3.1) sha256=eb7a57cef10c9d70173ff74e739d843ac3b2c019a003de48447b2963d81b1974
|
|
357
|
+
racc (1.8.1) sha256=4a7f6929691dbec8b5209a0b373bc2614882b55fc5d2e447a21aaa691303d62f
|
|
358
|
+
rack (3.2.4) sha256=5d74b6f75082a643f43c1e76b419c40f0e5527fcfee1e669ac1e6b73c0ccb6f6
|
|
359
|
+
rack-session (2.1.1) sha256=0b6dc07dea7e4b583f58a48e8b806d4c9f1c6c9214ebc202ec94562cbea2e4e9
|
|
360
|
+
rack-test (2.2.0) sha256=005a36692c306ac0b4a9350355ee080fd09ddef1148a5f8b2ac636c720f5c463
|
|
361
|
+
rackup (2.3.1) sha256=6c79c26753778e90983761d677a48937ee3192b3ffef6bc963c0950f94688868
|
|
362
|
+
rails (8.1.1) sha256=877509b7aef309239978685883097d2c03e21383a50a3f78882cf9b3b5c136f7
|
|
363
|
+
rails-dom-testing (2.3.0) sha256=8acc7953a7b911ca44588bf08737bc16719f431a1cc3091a292bca7317925c1d
|
|
364
|
+
rails-html-sanitizer (1.6.2) sha256=35fce2ca8242da8775c83b6ba9c1bcaad6751d9eb73c1abaa8403475ab89a560
|
|
365
|
+
railties (8.1.1) sha256=fb0c7038b147bea41bf6697fa443ff1c5c47d3bb1eedd9ecf1bceeb90efcb868
|
|
366
|
+
rainbow (3.1.1) sha256=039491aa3a89f42efa1d6dec2fc4e62ede96eb6acd95e52f1ad581182b79bc6a
|
|
367
|
+
rake (13.3.1) sha256=8c9e89d09f66a26a01264e7e3480ec0607f0c497a861ef16063604b1b08eb19c
|
|
368
|
+
rdoc (7.0.3) sha256=dfe3d0981d19b7bba71d9dbaeb57c9f4e3a7a4103162148a559c4fc687ea81f9
|
|
369
|
+
regexp_parser (2.11.3) sha256=ca13f381a173b7a93450e53459075c9b76a10433caadcb2f1180f2c741fc55a4
|
|
370
|
+
reline (0.6.3) sha256=1198b04973565b36ec0f11542ab3f5cfeeec34823f4e54cebde90968092b1835
|
|
371
|
+
rubocop (1.81.7) sha256=6fb5cc298c731691e2a414fe0041a13eb1beed7bab23aec131da1bcc527af094
|
|
372
|
+
rubocop-ast (1.49.0) sha256=49c3676d3123a0923d333e20c6c2dbaaae2d2287b475273fddee0c61da9f71fd
|
|
373
|
+
rubocop-performance (1.26.1) sha256=cd19b936ff196df85829d264b522fd4f98b6c89ad271fa52744a8c11b8f71834
|
|
374
|
+
ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33
|
|
375
|
+
securerandom (0.4.1) sha256=cc5193d414a4341b6e225f0cb4446aceca8e50d5e1888743fac16987638ea0b1
|
|
376
|
+
sprockets (4.2.2) sha256=761e5a49f1c288704763f73139763564c845a8f856d52fba013458f8af1b59b1
|
|
377
|
+
sprockets-rails (3.5.2) sha256=a9e88e6ce9f8c912d349aa5401509165ec42326baf9e942a85de4b76dbc4119e
|
|
378
|
+
sqlite3 (2.9.0-aarch64-linux-gnu) sha256=cfe1e0216f46d7483839719bf827129151e6c680317b99d7b8fc1597a3e13473
|
|
379
|
+
sqlite3 (2.9.0-aarch64-linux-musl) sha256=56a35cb2d70779afc2ac191baf2c2148242285ecfed72f9b021218c5c4917913
|
|
380
|
+
sqlite3 (2.9.0-arm-linux-gnu) sha256=a19a21504b0d7c8c825fbbf37b358ae316b6bd0d0134c619874060b2eef05435
|
|
381
|
+
sqlite3 (2.9.0-arm-linux-musl) sha256=fca5b26197c70e3363115d3faaea34d7b2ad9c7f5fa8d8312e31b64e7556ee07
|
|
382
|
+
sqlite3 (2.9.0-arm64-darwin) sha256=a917bd9b84285766ff3300b7d79cd583f5a067594c8c1263e6441618c04a6ed3
|
|
383
|
+
sqlite3 (2.9.0-x86_64-darwin) sha256=59fe51baa3cb33c36d27ce78b4ed9360cd33ccca09498c2ae63850c97c0a6026
|
|
384
|
+
sqlite3 (2.9.0-x86_64-linux-gnu) sha256=72fff9bd750070ba3af695511ba5f0e0a2d8a9206f84869640b3e99dfaf3d5a5
|
|
385
|
+
sqlite3 (2.9.0-x86_64-linux-musl) sha256=ef716ba7a66d7deb1ccc402ac3a6d7343da17fac862793b7f0be3d2917253c90
|
|
386
|
+
standard (1.52.0) sha256=ec050e63228e31fabe40da3ef96da7edda476f7acdf3e7c2ad47b6e153f6a076
|
|
387
|
+
standard-custom (1.0.2) sha256=424adc84179a074f1a2a309bb9cf7cd6bfdb2b6541f20c6bf9436c0ba22a652b
|
|
388
|
+
standard-performance (1.9.0) sha256=49483d31be448292951d80e5e67cdcb576c2502103c7b40aec6f1b6e9c88e3f2
|
|
389
|
+
state_machine_enum (0.1.4) sha256=959d72af8d00e31b995a447738716e76667aadfb3612c17f59f566c083b31aac
|
|
390
|
+
stringio (3.2.0) sha256=c37cb2e58b4ffbd33fe5cd948c05934af997b36e0b6ca6fdf43afa234cf222e1
|
|
391
|
+
thor (1.4.0) sha256=8763e822ccb0f1d7bee88cde131b19a65606657b847cc7b7b4b82e772bcd8a3d
|
|
392
|
+
timeout (0.6.0) sha256=6d722ad619f96ee383a0c557ec6eb8c4ecb08af3af62098a0be5057bf00de1af
|
|
393
|
+
tsort (0.2.0) sha256=9650a793f6859a43b6641671278f79cfead60ac714148aabe4e3f0060480089f
|
|
394
|
+
tzinfo (2.0.6) sha256=8daf828cc77bcf7d63b0e3bdb6caa47e2272dcfaf4fbfe46f8c3a9df087a829b
|
|
395
|
+
unicode-display_width (3.2.0) sha256=0cdd96b5681a5949cdbc2c55e7b420facae74c4aaf9a9815eee1087cb1853c42
|
|
396
|
+
unicode-emoji (4.2.0) sha256=519e69150f75652e40bf736106cfbc8f0f73aa3fb6a65afe62fefa7f80b0f80f
|
|
397
|
+
uri (1.1.1) sha256=379fa58d27ffb1387eaada68c749d1426738bd0f654d812fcc07e7568f5c57c6
|
|
398
|
+
useragent (0.16.11) sha256=700e6413ad4bb954bb63547fa098dddf7b0ebe75b40cc6f93b8d54255b173844
|
|
399
|
+
webhukhs (0.5.0)
|
|
400
|
+
websocket-driver (0.8.0) sha256=ed0dba4b943c22f17f9a734817e808bc84cdce6a7e22045f5315aa57676d4962
|
|
401
|
+
websocket-extensions (0.1.5) sha256=1c6ba63092cda343eb53fc657110c71c754c56484aad42578495227d717a8241
|
|
402
|
+
zeitwerk (2.7.4) sha256=2bef90f356bdafe9a6c2bd32bcd804f83a4f9b8bc27f3600fff051eb3edcec8b
|
|
403
|
+
|
|
404
|
+
BUNDLED WITH
|
|
405
|
+
4.0.1
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# This is an example handler for Customer.io reporting webhooks. You
|
|
2
|
+
# can find more documentation here https://customer.io/docs/api/webhooks/#operation/reportingWebhook
|
|
3
|
+
class Webhooks::CustomerIoHandler < Webhukhs::BaseHandler
|
|
4
|
+
def process(webhook)
|
|
5
|
+
json = JSON.parse(webhook.body, symbolize_names: true)
|
|
6
|
+
case json[:metric]
|
|
7
|
+
when "subscribed"
|
|
8
|
+
# ...
|
|
9
|
+
when "unsubscribed"
|
|
10
|
+
# ...
|
|
11
|
+
when "cio_subscription_preferences_changed"
|
|
12
|
+
# ...
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def extract_event_id_from_request(action_dispatch_request)
|
|
17
|
+
action_dispatch_request.params.fetch(:event_id)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Verify that request is actually comming from customer.io here
|
|
21
|
+
# @see https://customer.io/docs/api/webhooks/#section/Securely-Verifying-Requests
|
|
22
|
+
#
|
|
23
|
+
# - Should have "X-CIO-Signature", "X-CIO-Timestamp" headers.
|
|
24
|
+
# - Combine the version number, timestamp and body delimited by colons to form a string in the form v0:<timestamp>:<body>
|
|
25
|
+
# - Using HMAC-SHA256, hash the string using your webhook signing secret as the hash key.
|
|
26
|
+
# - Compare this value to the value of the X-CIO-Signature header sent with the request to confirm
|
|
27
|
+
def valid?(action_dispatch_request)
|
|
28
|
+
signing_key = Rails.application.secrets.customer_io_webhook_signing_key
|
|
29
|
+
xcio_signature = action_dispatch_request.headers["HTTP_X_CIO_SIGNATURE"]
|
|
30
|
+
xcio_timestamp = action_dispatch_request.headers["HTTP_X_CIO_TIMESTAMP"]
|
|
31
|
+
request_body = action_dispatch_request.body.read
|
|
32
|
+
string_to_sign = "v0:#{xcio_timestamp}:#{request_body}"
|
|
33
|
+
hmac = OpenSSL::HMAC.hexdigest("SHA256", signing_key, string_to_sign)
|
|
34
|
+
Rack::Utils.secure_compare(hmac, xcio_signature)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# This is for Revolut V1 API for webhooks - https://developer.revolut.com/docs/business/webhooks-v-1-deprecated
|
|
2
|
+
class RevolutBusinessV1Handler < Webhukhs::BaseHandler
|
|
3
|
+
def valid?(_)
|
|
4
|
+
# V1 of Revolut webhooks does not support signatures
|
|
5
|
+
true
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def process(webhook)
|
|
9
|
+
parsed_payload = JSON.parse(webhook.body)
|
|
10
|
+
topic = parsed_payload.fetch("Topic")
|
|
11
|
+
case topic
|
|
12
|
+
when "tokens" # Account access revocation payload
|
|
13
|
+
# ...
|
|
14
|
+
when "draftpayments/transfers" # Draft payment transfer notification payload
|
|
15
|
+
# ...
|
|
16
|
+
else
|
|
17
|
+
# ...
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def extract_event_id_from_request(action_dispatch_request)
|
|
22
|
+
# Since b-tree indices generally divide from the start of the string, place the highest
|
|
23
|
+
# entropy component at the start (the EventId)
|
|
24
|
+
key_components = %w[EventId Topic Version]
|
|
25
|
+
key_components.map do |key|
|
|
26
|
+
action_dispatch_request.params.fetch(key)
|
|
27
|
+
end.join("-")
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# This is for Revolut V2 API for webhooks - https://developer.revolut.com/docs/business/webhooks-v-2
|
|
2
|
+
class RevolutBusinessV2Handler < Webhukhs::BaseHandler
|
|
3
|
+
def valid?(request)
|
|
4
|
+
# 1 - Validate the timestamp of the request. Prevent replay attacks.
|
|
5
|
+
# "To validate the event, make sure that the Revolut-Request-Timestamp date-time is within a 5-minute time tolerance of the current universal time (UTC)".
|
|
6
|
+
# Their examples list `timestamp = '1683650202360'` as a sample value, so their timestamp is in millis - not in seconds
|
|
7
|
+
timestamp_str_from_headers = request.headers["HTTP_REVOLUT_REQUEST_TIMESTAMP"]
|
|
8
|
+
delta_t_seconds = (timestamp_str_from_headers / 1000) - Time.now.to_i
|
|
9
|
+
return false unless delta_t_seconds.abs < (5 * 60)
|
|
10
|
+
|
|
11
|
+
# 2 - Validate the signature
|
|
12
|
+
# https://developer.revolut.com/docs/guides/manage-accounts/tutorials/work-with-webhooks/verify-the-payload-signature
|
|
13
|
+
string_to_sign = [
|
|
14
|
+
"v1",
|
|
15
|
+
timestamp_str_from_headers,
|
|
16
|
+
request.body.read
|
|
17
|
+
].join(".")
|
|
18
|
+
computed_signature = "v1=" + OpenSSL::HMAC.hexdigest("SHA256", Rails.application.secrets.revolut_business_webhook_signing_key, string_to_sign)
|
|
19
|
+
# Note: "This means that in the period when multiple signing secrets remain valid, multiple signatures are sent."
|
|
20
|
+
# https://developer.revolut.com/docs/guides/manage-accounts/tutorials/work-with-webhooks/manage-webhooks#rotate-a-webhook-signing-secret
|
|
21
|
+
# https://developer.revolut.com/docs/guides/manage-accounts/tutorials/work-with-webhooks/about-webhooks#security
|
|
22
|
+
# An HTTP header may contain multiple values if it gets sent multiple times. But it does mean we need to test for multiple provided
|
|
23
|
+
# signatures in case of rotation.
|
|
24
|
+
provided_signatures = request.headers["HTTP_REVOLUT_SIGNATURE"].split(",")
|
|
25
|
+
# Use #select instead of `find` to compare all signatures even if only one matches - this to avoid timing leaks.
|
|
26
|
+
# Small effort but might be useful.
|
|
27
|
+
matches = provided_signatures.select do |provided_signature|
|
|
28
|
+
ActiveSupport::SecurityUtils.secure_compare(provided_signature, computed_signature)
|
|
29
|
+
end
|
|
30
|
+
matches.any?
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def process(webhook)
|
|
34
|
+
Rails.logger.info { "Processing Revolut webhook #{webhook.body.inspect}" }
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def extract_event_id_from_request(action_dispatch_request)
|
|
38
|
+
# The event ID is only available when you retrieve the failed webhooks, which is sad.
|
|
39
|
+
# We can divinate a synthetic ID though by taking a hash of the entire payload though.
|
|
40
|
+
Digest::SHA256.hexdigest(action_dispatch_request.body.read)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This handler is an example for Starling Payments API,
|
|
4
|
+
# you can find the documentation here https://developer.starlingbank.com/payments/docs#account-and-address-structure-1
|
|
5
|
+
class StarlingPaymentsHandler < Webhukhs::BaseHandler
|
|
6
|
+
# This method will be used to process webhook by async worker.
|
|
7
|
+
def process(received_webhook)
|
|
8
|
+
Rails.logger.info { received_webhook.body }
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Starling supplies signatures in the form SHA512(secret + request_body)
|
|
12
|
+
def valid?(action_dispatch_request)
|
|
13
|
+
supplied_signature = action_dispatch_request.headers.fetch("X-Hook-Signature")
|
|
14
|
+
supplied_digest_bytes = Base64.strict_decode64(supplied_signature)
|
|
15
|
+
sha512 = Digest::SHA2.new(512)
|
|
16
|
+
signing_secret = Rails.credentials.starling_payments_webhook_signing_secret
|
|
17
|
+
computed_digest_bytes = sha512.digest(signing_secret.b + action_dispatch_request.body.b)
|
|
18
|
+
ActiveSupport::SecurityUtils.secure_compare(computed_digest_bytes, supplied_digest_bytes)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Some Starling webhooks do not provide a notification UID, but for those which do we can deduplicate
|
|
22
|
+
def extract_event_id_from_request(action_dispatch_request)
|
|
23
|
+
action_dispatch_request.params.fetch("notificationUid", SecureRandom.uuid)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "jobs/processing_job"
|
|
4
|
+
|
|
5
|
+
module Webhukhs
|
|
6
|
+
class BaseHandler
|
|
7
|
+
# `handle` accepts the ActionDispatch HTTP request and saves the webhook for later processing. It then
|
|
8
|
+
# enqueues an ActiveJob which will perform the processing using `process`.
|
|
9
|
+
#
|
|
10
|
+
# @param action_dispatch_request[ActionDispatch::Request] the request from the controller
|
|
11
|
+
# @return [void]
|
|
12
|
+
def handle(action_dispatch_request)
|
|
13
|
+
handler_module_name = is_a?(Webhukhs::BaseHandler) ? self.class.name : to_s
|
|
14
|
+
handler_event_id = extract_event_id_from_request(action_dispatch_request)
|
|
15
|
+
|
|
16
|
+
webhook = Webhukhs::ReceivedWebhook.new(request: action_dispatch_request, handler_event_id: handler_event_id, handler_module_name: handler_module_name)
|
|
17
|
+
webhook.save!
|
|
18
|
+
|
|
19
|
+
enqueue(webhook)
|
|
20
|
+
rescue ActiveRecord::RecordNotUnique # Webhook deduplicated
|
|
21
|
+
Rails.logger.info { "#{inspect} Webhook #{handler_event_id} is a duplicate delivery and will not be stored." }
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Enqueues the processing job to process webhook asynchronously. The job class could be configured.
|
|
25
|
+
#
|
|
26
|
+
# @param webhook [Webhukhs::ReceivedWebhook]
|
|
27
|
+
# @return [void]
|
|
28
|
+
def enqueue(webhook)
|
|
29
|
+
# The configured job class can be a class name or a module, to support lazy loading
|
|
30
|
+
job_class_or_module_name = Webhukhs.configuration.processing_job_class
|
|
31
|
+
job_class = if job_class_or_module_name.respond_to?(:perform_later)
|
|
32
|
+
job_class_or_module_name
|
|
33
|
+
else
|
|
34
|
+
job_class_or_module_name.constantize
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
job_class.perform_later(webhook)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# This is the heart of your webhook processing. Override this method and define your processing inside of it.
|
|
41
|
+
# The `received_webhook` will provide access to the `ReceivedWebhook` model, which contains the received
|
|
42
|
+
# body of the webhook request, but also the full (as-full-as-possible) clone of the original ActionDispatch::Request
|
|
43
|
+
# that you can use.
|
|
44
|
+
#
|
|
45
|
+
# @param received_webhook[Webhukhs::ReceivedWebhook]
|
|
46
|
+
# @return [void]
|
|
47
|
+
def process(received_webhook)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# This method verifies that request is not malformed and actually comes from the webhook sender:
|
|
51
|
+
# signature validation, HTTP authentication, IP whitelisting and the like. There is a difference depending
|
|
52
|
+
# on whether you validate sync (in the receiving controller) or async (in the processing job):
|
|
53
|
+
# Validation is async - it takes place in the background job that gets enqueued to process the webhook.
|
|
54
|
+
# The `action_dispatch_request` will be reconstructed from the `ReceivedWebhook` data. Background validation
|
|
55
|
+
# is used because the most common misconfiguration that may occur is usually forgetting or misidentifying the
|
|
56
|
+
# signature for signed webhooks. If such a misconfiguration has taken place, the background validation
|
|
57
|
+
# (instead of rejecting the webhook at input) permits you to still process the webhook once the secrets
|
|
58
|
+
# have been configured correctly.
|
|
59
|
+
#
|
|
60
|
+
# If this method returns `false`, the webhook will be marked as `failed_validation` in the database. If this
|
|
61
|
+
# method returns `true`, the `process` method of the handler is going to be called.
|
|
62
|
+
#
|
|
63
|
+
# @see Webhukhs::ReceivedWebhook#request
|
|
64
|
+
# @param action_dispatch_request[ActionDispatch::Request] the reconstructed request from the controller
|
|
65
|
+
# @return [Boolean]
|
|
66
|
+
def valid?(action_dispatch_request)
|
|
67
|
+
true
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Default implementation just generates a random UUID, but if the webhook sender sends us
|
|
71
|
+
# an event ID we use it for deduplication. A duplicate webhook is not going to be
|
|
72
|
+
# stored in the database if it is already present there.
|
|
73
|
+
#
|
|
74
|
+
# @return [String]
|
|
75
|
+
def extract_event_id_from_request(action_dispatch_request)
|
|
76
|
+
SecureRandom.uuid
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Webhook senders have varying retry behaviors, and often you want to "pretend"
|
|
80
|
+
# everything is fine even though there is an error so that they keep sending you
|
|
81
|
+
# data and do not disable your endpoint forcibly. We allow this to be configured
|
|
82
|
+
# on a per-handler basis - a better webhooks sender will be able to make out
|
|
83
|
+
# some sense of the errors.
|
|
84
|
+
#
|
|
85
|
+
# @return [Boolean]
|
|
86
|
+
def expose_errors_to_sender?
|
|
87
|
+
true
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Tells the controller whether this handler is active or not. This can be used
|
|
91
|
+
# to deactivate a particular handler via feature flags for example, or use other
|
|
92
|
+
# logic to determine whether the handler may be used to create new received webhooks
|
|
93
|
+
# in the system. This is primarily needed for load shedding.
|
|
94
|
+
#
|
|
95
|
+
# @return [Boolean]
|
|
96
|
+
def active?
|
|
97
|
+
true
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|