noresponse 5.1.1 → 6.0.1

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.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/lib/no_response/accounts.rb +663 -71
  3. data/lib/no_response/late_results.rb +10 -8
  4. data/lib/no_response/models/operations/listaccounts_request.rb +52 -0
  5. data/lib/no_response/models/operations/listaccounts_request.rbi +26 -0
  6. data/lib/no_response/models/operations/listaccounts_response.rb +32 -0
  7. data/lib/no_response/models/operations/listaccounts_response.rbi +20 -0
  8. data/lib/no_response/models/operations/recordenforcement_request.rb +33 -0
  9. data/lib/no_response/models/operations/recordenforcement_request.rbi +20 -0
  10. data/lib/no_response/models/operations/recordenforcement_response.rb +32 -0
  11. data/lib/no_response/models/operations/recordenforcement_response.rbi +20 -0
  12. data/lib/no_response/models/operations.rb +4 -0
  13. data/lib/no_response/models/shared/accountdeleted.rb +49 -0
  14. data/lib/no_response/models/shared/accountdeleted.rbi +26 -0
  15. data/lib/no_response/models/shared/accountdeletedevent.rb +70 -0
  16. data/lib/no_response/models/shared/accountdeletedevent.rbi +38 -0
  17. data/lib/no_response/models/shared/accountlist.rb +40 -0
  18. data/lib/no_response/models/shared/accountlist.rbi +20 -0
  19. data/lib/no_response/models/shared/accountriskchanged.rb +44 -0
  20. data/lib/no_response/models/shared/accountriskchanged.rbi +20 -0
  21. data/lib/no_response/models/shared/accountriskchangedevent.rb +70 -0
  22. data/lib/no_response/models/shared/accountriskchangedevent.rbi +38 -0
  23. data/lib/no_response/models/shared/assessmentexpired.rb +82 -0
  24. data/lib/no_response/models/shared/assessmentexpired.rbi +38 -0
  25. data/lib/no_response/models/shared/assessmentupdateddata.rb +23 -0
  26. data/lib/no_response/models/shared/assessmentupdateddata.rbi +9 -0
  27. data/lib/no_response/models/shared/assessmentupdatedevent.rb +79 -0
  28. data/lib/no_response/models/shared/assessmentupdatedevent.rbi +38 -0
  29. data/lib/no_response/models/shared/conflicterrorcode.rb +1 -0
  30. data/lib/no_response/models/shared/endpointverification.rb +41 -0
  31. data/lib/no_response/models/shared/endpointverification.rbi +20 -0
  32. data/lib/no_response/models/shared/endpointverificationevent.rb +70 -0
  33. data/lib/no_response/models/shared/endpointverificationevent.rbi +38 -0
  34. data/lib/no_response/models/shared/enforcement.rb +156 -0
  35. data/lib/no_response/models/shared/enforcement.rbi +68 -0
  36. data/lib/no_response/models/shared/enforcementaction.rb +23 -0
  37. data/lib/no_response/models/shared/enforcementaction.rbi +9 -0
  38. data/lib/no_response/models/shared/enforcementprovider.rb +21 -0
  39. data/lib/no_response/models/shared/enforcementprovider.rbi +9 -0
  40. data/lib/no_response/models/shared/enforcementrequest.rb +122 -0
  41. data/lib/no_response/models/shared/enforcementrequest.rbi +50 -0
  42. data/lib/no_response/models/shared/enforcementstate.rb +22 -0
  43. data/lib/no_response/models/shared/enforcementstate.rbi +9 -0
  44. data/lib/no_response/models/shared/enforcementstatus.rb +19 -0
  45. data/lib/no_response/models/shared/enforcementstatus.rbi +9 -0
  46. data/lib/no_response/models/shared/environment.rb +16 -0
  47. data/lib/no_response/models/shared/environment.rbi +9 -0
  48. data/lib/no_response/models/shared/webhookendpointdisabled.rb +49 -0
  49. data/lib/no_response/models/shared/webhookendpointdisabled.rbi +26 -0
  50. data/lib/no_response/models/shared/webhookendpointdisabledevent.rb +70 -0
  51. data/lib/no_response/models/shared/webhookendpointdisabledevent.rbi +38 -0
  52. data/lib/no_response/models/shared/webhookevent.rb +23 -0
  53. data/lib/no_response/models/shared/webhookevent.rbi +9 -0
  54. data/lib/no_response/models/shared/webhookverificationresponse.rb +33 -0
  55. data/lib/no_response/models/shared/webhookverificationresponse.rbi +14 -0
  56. data/lib/no_response/models/shared/workspacedeleted.rb +55 -0
  57. data/lib/no_response/models/shared/workspacedeleted.rbi +26 -0
  58. data/lib/no_response/models/shared/workspacedeletedevent.rb +70 -0
  59. data/lib/no_response/models/shared/workspacedeletedevent.rbi +38 -0
  60. data/lib/no_response/models/shared.rb +23 -0
  61. data/lib/no_response/sdk_hooks/registration.rb +0 -1
  62. data/lib/no_response/sdkconfiguration.rb +2 -2
  63. data/lib/no_response/webhook_verification.rb +170 -0
  64. data/lib/noresponse.rb +2 -0
  65. metadata +56 -2
  66. data/lib/no_response/webhooks.rb +0 -264
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: noresponse
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.1.1
4
+ version: 6.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - NoResponse
@@ -313,6 +313,10 @@ files:
313
313
  - lib/no_response/models/operations/listaccountassessments_request.rbi
314
314
  - lib/no_response/models/operations/listaccountassessments_response.rb
315
315
  - lib/no_response/models/operations/listaccountassessments_response.rbi
316
+ - lib/no_response/models/operations/listaccounts_request.rb
317
+ - lib/no_response/models/operations/listaccounts_request.rbi
318
+ - lib/no_response/models/operations/listaccounts_response.rb
319
+ - lib/no_response/models/operations/listaccounts_response.rbi
316
320
  - lib/no_response/models/operations/listintegrations_response.rb
317
321
  - lib/no_response/models/operations/listintegrations_response.rbi
318
322
  - lib/no_response/models/operations/listwebhookdeliveries_request.rb
@@ -327,6 +331,10 @@ files:
327
331
  - lib/no_response/models/operations/recordassessmentoutcome_request.rbi
328
332
  - lib/no_response/models/operations/recordassessmentoutcome_response.rb
329
333
  - lib/no_response/models/operations/recordassessmentoutcome_response.rbi
334
+ - lib/no_response/models/operations/recordenforcement_request.rb
335
+ - lib/no_response/models/operations/recordenforcement_request.rbi
336
+ - lib/no_response/models/operations/recordenforcement_response.rb
337
+ - lib/no_response/models/operations/recordenforcement_response.rbi
330
338
  - lib/no_response/models/operations/recordkeyusage_request.rb
331
339
  - lib/no_response/models/operations/recordkeyusage_request.rbi
332
340
  - lib/no_response/models/operations/recordkeyusage_response.rb
@@ -356,10 +364,20 @@ files:
356
364
  - lib/no_response/models/shared/accountdecision.rbi
357
365
  - lib/no_response/models/shared/accountdecisionsbyflow.rb
358
366
  - lib/no_response/models/shared/accountdecisionsbyflow.rbi
367
+ - lib/no_response/models/shared/accountdeleted.rb
368
+ - lib/no_response/models/shared/accountdeleted.rbi
369
+ - lib/no_response/models/shared/accountdeletedevent.rb
370
+ - lib/no_response/models/shared/accountdeletedevent.rbi
359
371
  - lib/no_response/models/shared/accountdeletion.rb
360
372
  - lib/no_response/models/shared/accountdeletion.rbi
373
+ - lib/no_response/models/shared/accountlist.rb
374
+ - lib/no_response/models/shared/accountlist.rbi
361
375
  - lib/no_response/models/shared/accountrisk.rb
362
376
  - lib/no_response/models/shared/accountrisk.rbi
377
+ - lib/no_response/models/shared/accountriskchanged.rb
378
+ - lib/no_response/models/shared/accountriskchanged.rbi
379
+ - lib/no_response/models/shared/accountriskchangedevent.rb
380
+ - lib/no_response/models/shared/accountriskchangedevent.rbi
363
381
  - lib/no_response/models/shared/accountriskreason.rb
364
382
  - lib/no_response/models/shared/accountriskreason.rbi
365
383
  - lib/no_response/models/shared/alternate_name.rb
@@ -378,6 +396,8 @@ files:
378
396
  - lib/no_response/models/shared/assessmentdetailauthcontext.rbi
379
397
  - lib/no_response/models/shared/assessmentdetailtiming.rb
380
398
  - lib/no_response/models/shared/assessmentdetailtiming.rbi
399
+ - lib/no_response/models/shared/assessmentexpired.rb
400
+ - lib/no_response/models/shared/assessmentexpired.rbi
381
401
  - lib/no_response/models/shared/assessmentlist.rb
382
402
  - lib/no_response/models/shared/assessmentlist.rbi
383
403
  - lib/no_response/models/shared/assessmentoutcome.rb
@@ -396,6 +416,10 @@ files:
396
416
  - lib/no_response/models/shared/assessmentrequestissuedcredential.rbi
397
417
  - lib/no_response/models/shared/assessmentrequestpolicycontext.rb
398
418
  - lib/no_response/models/shared/assessmentrequestpolicycontext.rbi
419
+ - lib/no_response/models/shared/assessmentupdateddata.rb
420
+ - lib/no_response/models/shared/assessmentupdateddata.rbi
421
+ - lib/no_response/models/shared/assessmentupdatedevent.rb
422
+ - lib/no_response/models/shared/assessmentupdatedevent.rbi
399
423
  - lib/no_response/models/shared/assurancelevel.rb
400
424
  - lib/no_response/models/shared/assurancelevel.rbi
401
425
  - lib/no_response/models/shared/authcontext.rb
@@ -434,6 +458,24 @@ files:
434
458
  - lib/no_response/models/shared/email.rbi
435
459
  - lib/no_response/models/shared/email_union.rb
436
460
  - lib/no_response/models/shared/email_union.rbi
461
+ - lib/no_response/models/shared/endpointverification.rb
462
+ - lib/no_response/models/shared/endpointverification.rbi
463
+ - lib/no_response/models/shared/endpointverificationevent.rb
464
+ - lib/no_response/models/shared/endpointverificationevent.rbi
465
+ - lib/no_response/models/shared/enforcement.rb
466
+ - lib/no_response/models/shared/enforcement.rbi
467
+ - lib/no_response/models/shared/enforcementaction.rb
468
+ - lib/no_response/models/shared/enforcementaction.rbi
469
+ - lib/no_response/models/shared/enforcementprovider.rb
470
+ - lib/no_response/models/shared/enforcementprovider.rbi
471
+ - lib/no_response/models/shared/enforcementrequest.rb
472
+ - lib/no_response/models/shared/enforcementrequest.rbi
473
+ - lib/no_response/models/shared/enforcementstate.rb
474
+ - lib/no_response/models/shared/enforcementstate.rbi
475
+ - lib/no_response/models/shared/enforcementstatus.rb
476
+ - lib/no_response/models/shared/enforcementstatus.rbi
477
+ - lib/no_response/models/shared/environment.rb
478
+ - lib/no_response/models/shared/environment.rbi
437
479
  - lib/no_response/models/shared/failure.rb
438
480
  - lib/no_response/models/shared/failure.rbi
439
481
  - lib/no_response/models/shared/failurereason.rb
@@ -568,12 +610,18 @@ files:
568
610
  - lib/no_response/models/shared/webhookendpoint.rbi
569
611
  - lib/no_response/models/shared/webhookendpointcreated.rb
570
612
  - lib/no_response/models/shared/webhookendpointcreated.rbi
613
+ - lib/no_response/models/shared/webhookendpointdisabled.rb
614
+ - lib/no_response/models/shared/webhookendpointdisabled.rbi
615
+ - lib/no_response/models/shared/webhookendpointdisabledevent.rb
616
+ - lib/no_response/models/shared/webhookendpointdisabledevent.rbi
571
617
  - lib/no_response/models/shared/webhookendpointlist.rb
572
618
  - lib/no_response/models/shared/webhookendpointlist.rbi
573
619
  - lib/no_response/models/shared/webhookendpointrequest.rb
574
620
  - lib/no_response/models/shared/webhookendpointrequest.rbi
575
621
  - lib/no_response/models/shared/webhookendpointstate.rb
576
622
  - lib/no_response/models/shared/webhookendpointstate.rbi
623
+ - lib/no_response/models/shared/webhookevent.rb
624
+ - lib/no_response/models/shared/webhookevent.rbi
577
625
  - lib/no_response/models/shared/webhookkeyrotation.rb
578
626
  - lib/no_response/models/shared/webhookkeyrotation.rbi
579
627
  - lib/no_response/models/shared/webhookkeyrotationrequest.rb
@@ -588,10 +636,16 @@ files:
588
636
  - lib/no_response/models/shared/webhooktestrequest.rbi
589
637
  - lib/no_response/models/shared/webhooktestrequestevent.rb
590
638
  - lib/no_response/models/shared/webhooktestrequestevent.rbi
639
+ - lib/no_response/models/shared/webhookverificationresponse.rb
640
+ - lib/no_response/models/shared/webhookverificationresponse.rbi
591
641
  - lib/no_response/models/shared/website.rb
592
642
  - lib/no_response/models/shared/website.rbi
593
643
  - lib/no_response/models/shared/website_union.rb
594
644
  - lib/no_response/models/shared/website_union.rbi
645
+ - lib/no_response/models/shared/workspacedeleted.rb
646
+ - lib/no_response/models/shared/workspacedeleted.rbi
647
+ - lib/no_response/models/shared/workspacedeletedevent.rb
648
+ - lib/no_response/models/shared/workspacedeletedevent.rbi
595
649
  - lib/no_response/noresponseclient.rb
596
650
  - lib/no_response/sdk_hooks/hooks.rb
597
651
  - lib/no_response/sdk_hooks/idempotency_key_hook.rb
@@ -608,8 +662,8 @@ files:
608
662
  - lib/no_response/utils/url.rb
609
663
  - lib/no_response/utils/utils.rb
610
664
  - lib/no_response/wait.rb
665
+ - lib/no_response/webhook_verification.rb
611
666
  - lib/no_response/webhookendpoints.rb
612
- - lib/no_response/webhooks.rb
613
667
  - lib/noresponse.rb
614
668
  homepage:
615
669
  licenses:
@@ -1,264 +0,0 @@
1
- # typed: true
2
- # frozen_string_literal: true
3
-
4
- # Webhook verification. Hand-written beside the generated client.
5
- #
6
- # Verify the exact bytes received: the signature is HMAC-SHA256 over
7
- # "<timestamp>.<raw body>", so re-serialising parsed JSON breaks it.
8
-
9
- require 'json'
10
- require 'openssl'
11
- require 'time'
12
-
13
- module NoResponse
14
- module Webhooks
15
- DEFAULT_TOLERANCE_SECONDS = 300
16
-
17
- REQUIRED = %w[nr-webhook-id nr-webhook-timestamp nr-webhook-key-id nr-webhook-signature].freeze
18
- KEY_ID = /\Awhk_[A-Za-z0-9]{8,64}\z/
19
- SIGNATURE = /\Av1=[0-9a-f]{64}\z/
20
- TIMESTAMP = /\A[0-9]{1,12}\z/
21
- CHALLENGE = /\A[A-Za-z0-9_-]{43}\z/
22
- EVENT_ID = /\Aevt_[0-9A-HJKMNP-TV-Z]{26}\z/
23
- ASSESSMENT_ID = /\Aasm_[0-9A-HJKMNP-TV-Z]{26}\z/
24
- ACCOUNT_ID = /\A[A-Za-z0-9][A-Za-z0-9._:|-]{0,127}\z/
25
- ENDPOINT_ID = /\Awhe_[0-9A-HJKMNP-TV-Z]{26}\z/
26
- WORKSPACE_ID = /\A[A-Za-z0-9][A-Za-z0-9_.-]{0,122}\z/
27
-
28
- # Raised by construct_event. Answer 400 and do not process the delivery.
29
- # code is one of :missing_header, :duplicate_header, :invalid_timestamp,
30
- # :unknown_key, :invalid_signature or :invalid_payload.
31
- class VerificationError < StandardError
32
- attr_reader :code
33
-
34
- def initialize(code, message)
35
- super(message)
36
- @code = code
37
- end
38
- end
39
-
40
- # The final event for an assessment: it has expired and get now answers
41
- # 404. assessment_version is the last served version.
42
- AssessmentExpired = Struct.new(:assessment_id, :account_id, :assessment_version, keyword_init: true) do
43
- def status = 'expired'
44
- def change_reason = 'expired'
45
- end
46
-
47
- EndpointVerification = Struct.new(:endpoint_id, :challenge, keyword_init: true)
48
-
49
- # An account you erased with accounts.delete: delete what you hold for it.
50
- # assessments_deleted is at least 1, and deleted_at equals deleted_at in
51
- # the delete answer.
52
- AccountDeleted = Struct.new(:account_id, :assessments_deleted, :deleted_at, keyword_init: true)
53
-
54
- # The workspace was deleted. Sent once per environment ("live" or "test")
55
- # before its endpoints are torn down: the last event this endpoint receives.
56
- WorkspaceDeleted = Struct.new(:workspace_id, :environment, :deleted_at, keyword_init: true)
57
-
58
- # Another endpoint of this environment was disabled after failing
59
- # continuously for 72 hours, since failing_since. It receives nothing more
60
- # until it is verified again.
61
- EndpointDisabled = Struct.new(:endpoint_id, :failing_since, :disabled_at, keyword_init: true)
62
-
63
- # The account's decision for at least one flow changed. account is a
64
- # Models::Shared::Account exactly as accounts.get returns it, with its new
65
- # risk and decisions; previous_decisions_by_flow is a
66
- # Models::Shared::AccountDecisionsByFlow holding the decisions it replaced.
67
- # It is not sent when the score moves within the same decision, nor for an
68
- # account's first risk.
69
- AccountRiskChanged = Struct.new(:account, :previous_decisions_by_flow, keyword_init: true)
70
-
71
- # A verified delivery. data is a Models::Shared::Assessment (exactly as
72
- # assessments.get returns it) or an AssessmentExpired for type
73
- # "assessment.updated", an EndpointVerification for
74
- # "endpoint.verification", an AccountDeleted for "account.deleted", a
75
- # WorkspaceDeleted for "workspace.deleted", an EndpointDisabled for
76
- # "webhook_endpoint.disabled" and an AccountRiskChanged for
77
- # "account.risk_changed". Deliveries are at least once and unordered:
78
- # deduplicate on id and keep the highest detail.assessment_version.
79
- Event = Struct.new(:id, :type, :created_at, :data, :test, keyword_init: true) do
80
- # True for the terminal expiry event: delete what you hold and fetch nothing.
81
- def expired? = data.is_a?(AssessmentExpired)
82
-
83
- # True on an event sent by the send-test-event call: data is a fixed
84
- # example assessment, not one of yours. Acknowledge it and apply nothing.
85
- def test? = test == true
86
- end
87
-
88
- class << self
89
-
90
- # Verify one delivery and return the typed Event.
91
- #
92
- # payload is the raw request body. headers is a Hash, Rack env-style
93
- # pairs or any object with each; each NR-Webhook-* header must appear
94
- # exactly once, in any letter case. secrets maps each whk_ key id
95
- # NoResponse gave you to its secret; hold both during a rotation.
96
- def construct_event(payload, headers, secrets, tolerance_seconds: DEFAULT_TOLERANCE_SECONDS, now: Time.now.to_i)
97
- raw = payload.to_s.b
98
- found = collect(headers)
99
- timestamp = found['nr-webhook-timestamp']
100
- if !TIMESTAMP.match?(timestamp) || (now.to_i - timestamp.to_i).abs > tolerance_seconds
101
- raise VerificationError.new(:invalid_timestamp, 'Webhook timestamp is outside the replay window')
102
- end
103
-
104
- key_id = found['nr-webhook-key-id']
105
- unless KEY_ID.match?(key_id) && secrets.key?(key_id)
106
- raise VerificationError.new(:unknown_key, 'Webhook key id is not one this receiver holds')
107
- end
108
-
109
- signature = found['nr-webhook-signature']
110
- raise VerificationError.new(:invalid_signature, 'Webhook signature is malformed') unless SIGNATURE.match?(signature)
111
-
112
- expected = OpenSSL::HMAC.hexdigest('SHA256', secrets.fetch(key_id).to_s, "#{timestamp}.".b + raw)
113
- unless OpenSSL.fixed_length_secure_compare(expected, signature.delete_prefix('v1='))
114
- raise VerificationError.new(:invalid_signature, 'Webhook signature does not match')
115
- end
116
-
117
- event(raw, found['nr-webhook-id'])
118
- end
119
-
120
- # The body to answer an endpoint.verification event with, as JSON, status 200.
121
- def verification_response(event)
122
- unless event.data.is_a?(EndpointVerification)
123
- raise VerificationError.new(:invalid_payload, 'Not an endpoint.verification event')
124
- end
125
-
126
- { 'challenge' => event.data.challenge }
127
- end
128
-
129
- private
130
-
131
- def collect(headers)
132
- found = {}
133
- headers.each do |name, value|
134
- key = name.to_s.downcase.tr('_', '-').delete_prefix('http-')
135
- next unless REQUIRED.include?(key)
136
-
137
- values = Array(value)
138
- if values.length != 1 || found.key?(key)
139
- raise VerificationError.new(:duplicate_header, "Webhook header #{key} is repeated")
140
- end
141
-
142
- found[key] = values.first.to_s
143
- end
144
- REQUIRED.each do |key|
145
- raise VerificationError.new(:missing_header, "Webhook header #{key} is missing") if found[key].to_s.empty?
146
- end
147
- found
148
- end
149
-
150
- def event(raw, header_id)
151
- body = begin
152
- JSON.parse(raw)
153
- rescue JSON::ParserError
154
- raise VerificationError.new(:invalid_payload, 'Webhook body is not JSON')
155
- end
156
- unless body.is_a?(Hash) && body['id'] == header_id && EVENT_ID.match?(body['id'].to_s)
157
- raise VerificationError.new(:invalid_payload, 'Webhook event id does not match NR-Webhook-Id')
158
- end
159
-
160
- data = body['data']
161
- unless body['created_at'].is_a?(String) && valid_datetime?(body['created_at']) && data.is_a?(Hash)
162
- raise VerificationError.new(:invalid_payload, 'Webhook event envelope is malformed')
163
- end
164
-
165
- Event.new(id: body['id'], type: body['type'], created_at: body['created_at'], data: event_data(body['type'], data),
166
- test: body['test'] == true && body['type'] == 'assessment.updated')
167
- end
168
-
169
- def event_data(type, data)
170
- case type
171
- when 'endpoint.verification'
172
- unless ENDPOINT_ID.match?(data['endpoint_id'].to_s) && CHALLENGE.match?(data['challenge'].to_s)
173
- raise VerificationError.new(:invalid_payload, 'Endpoint verification event is malformed')
174
- end
175
-
176
- EndpointVerification.new(endpoint_id: data['endpoint_id'], challenge: data['challenge'])
177
- when 'assessment.updated'
178
- return expired(data) if data['status'] == 'expired'
179
- begin
180
- Crystalline.unmarshal_json(data, Models::Shared::Assessment)
181
- rescue KeyError, TypeError, ArgumentError, NoMethodError
182
- raise VerificationError.new(:invalid_payload, 'Webhook data is not an assessment')
183
- end
184
- when 'account.deleted'
185
- account_deleted(data)
186
- when 'workspace.deleted'
187
- workspace_deleted(data)
188
- when 'webhook_endpoint.disabled'
189
- endpoint_disabled(data)
190
- when 'account.risk_changed'
191
- account_risk_changed(data)
192
- else
193
- raise VerificationError.new(:invalid_payload, 'Unknown webhook event type')
194
- end
195
- end
196
-
197
- def expired(data)
198
- unless ASSESSMENT_ID.match?(data['assessment_id'].to_s) &&
199
- ACCOUNT_ID.match?(data['account_id'].to_s) && data['assessment_version'].is_a?(Integer) &&
200
- data['assessment_version'] >= 1 && data['status'] == 'expired' && data['change_reason'] == 'expired'
201
- raise VerificationError.new(:invalid_payload, 'Expired assessment event is malformed')
202
- end
203
-
204
- AssessmentExpired.new(assessment_id: data['assessment_id'], account_id: data['account_id'],
205
- assessment_version: data['assessment_version'])
206
- end
207
-
208
- def account_deleted(data)
209
- unless data['account_id'].is_a?(String) && ACCOUNT_ID.match?(data['account_id']) &&
210
- data['assessments_deleted'].is_a?(Integer) && data['assessments_deleted'] >= 1 &&
211
- data['deleted_at'].is_a?(String) && valid_datetime?(data['deleted_at'])
212
- raise VerificationError.new(:invalid_payload, 'Account deleted event is malformed')
213
- end
214
-
215
- AccountDeleted.new(account_id: data['account_id'], assessments_deleted: data['assessments_deleted'],
216
- deleted_at: data['deleted_at'])
217
- end
218
-
219
- def workspace_deleted(data)
220
- unless data['workspace_id'].is_a?(String) && WORKSPACE_ID.match?(data['workspace_id']) &&
221
- %w[live test].include?(data['environment']) &&
222
- data['deleted_at'].is_a?(String) && valid_datetime?(data['deleted_at'])
223
- raise VerificationError.new(:invalid_payload, 'Workspace deleted event is malformed')
224
- end
225
-
226
- WorkspaceDeleted.new(workspace_id: data['workspace_id'], environment: data['environment'],
227
- deleted_at: data['deleted_at'])
228
- end
229
-
230
- def endpoint_disabled(data)
231
- unless data['endpoint_id'].is_a?(String) && ENDPOINT_ID.match?(data['endpoint_id']) &&
232
- data['failing_since'].is_a?(String) && valid_datetime?(data['failing_since']) &&
233
- data['disabled_at'].is_a?(String) && valid_datetime?(data['disabled_at'])
234
- raise VerificationError.new(:invalid_payload, 'Endpoint disabled event is malformed')
235
- end
236
-
237
- EndpointDisabled.new(endpoint_id: data['endpoint_id'], failing_since: data['failing_since'],
238
- disabled_at: data['disabled_at'])
239
- end
240
-
241
- def account_risk_changed(data)
242
- account = data['account']
243
- previous = data['previous_decisions_by_flow']
244
- unless account.is_a?(Hash) && previous.is_a?(Hash) && account['id'].is_a?(String) && ACCOUNT_ID.match?(account['id'])
245
- raise VerificationError.new(:invalid_payload, 'Account risk changed event is malformed')
246
- end
247
-
248
- begin
249
- AccountRiskChanged.new(account: Crystalline.unmarshal_json(account, Models::Shared::Account),
250
- previous_decisions_by_flow: Crystalline.unmarshal_json(previous, Models::Shared::AccountDecisionsByFlow))
251
- rescue KeyError, TypeError, ArgumentError, NoMethodError
252
- raise VerificationError.new(:invalid_payload, 'Account risk changed event is malformed')
253
- end
254
- end
255
-
256
- def valid_datetime?(value)
257
- Time.iso8601(value)
258
- true
259
- rescue ArgumentError
260
- false
261
- end
262
- end
263
- end
264
- end