noresponse 5.1.1 → 6.0.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 +4 -4
- data/lib/no_response/late_results.rb +10 -8
- data/lib/no_response/models/shared/accountdeleted.rb +49 -0
- data/lib/no_response/models/shared/accountdeleted.rbi +26 -0
- data/lib/no_response/models/shared/accountdeletedevent.rb +70 -0
- data/lib/no_response/models/shared/accountdeletedevent.rbi +38 -0
- data/lib/no_response/models/shared/accountriskchanged.rb +44 -0
- data/lib/no_response/models/shared/accountriskchanged.rbi +20 -0
- data/lib/no_response/models/shared/accountriskchangedevent.rb +70 -0
- data/lib/no_response/models/shared/accountriskchangedevent.rbi +38 -0
- data/lib/no_response/models/shared/assessmentexpired.rb +82 -0
- data/lib/no_response/models/shared/assessmentexpired.rbi +38 -0
- data/lib/no_response/models/shared/assessmentupdateddata.rb +23 -0
- data/lib/no_response/models/shared/assessmentupdateddata.rbi +9 -0
- data/lib/no_response/models/shared/assessmentupdatedevent.rb +79 -0
- data/lib/no_response/models/shared/assessmentupdatedevent.rbi +38 -0
- data/lib/no_response/models/shared/endpointverification.rb +41 -0
- data/lib/no_response/models/shared/endpointverification.rbi +20 -0
- data/lib/no_response/models/shared/endpointverificationevent.rb +70 -0
- data/lib/no_response/models/shared/endpointverificationevent.rbi +38 -0
- data/lib/no_response/models/shared/environment.rb +16 -0
- data/lib/no_response/models/shared/environment.rbi +9 -0
- data/lib/no_response/models/shared/webhookendpointdisabled.rb +49 -0
- data/lib/no_response/models/shared/webhookendpointdisabled.rbi +26 -0
- data/lib/no_response/models/shared/webhookendpointdisabledevent.rb +70 -0
- data/lib/no_response/models/shared/webhookendpointdisabledevent.rbi +38 -0
- data/lib/no_response/models/shared/webhookevent.rb +23 -0
- data/lib/no_response/models/shared/webhookevent.rbi +9 -0
- data/lib/no_response/models/shared/webhookverificationresponse.rb +33 -0
- data/lib/no_response/models/shared/webhookverificationresponse.rbi +14 -0
- data/lib/no_response/models/shared/workspacedeleted.rb +55 -0
- data/lib/no_response/models/shared/workspacedeleted.rbi +26 -0
- data/lib/no_response/models/shared/workspacedeletedevent.rb +70 -0
- data/lib/no_response/models/shared/workspacedeletedevent.rbi +38 -0
- data/lib/no_response/models/shared.rb +16 -0
- data/lib/no_response/sdk_hooks/registration.rb +0 -1
- data/lib/no_response/sdkconfiguration.rb +2 -2
- data/lib/no_response/webhook_verification.rb +170 -0
- data/lib/noresponse.rb +2 -0
- metadata +34 -2
- data/lib/no_response/webhooks.rb +0 -264
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fd8954a2530d7155206de245bf0a37d1634544e60667c805dfc59bc0469a5f9f
|
|
4
|
+
data.tar.gz: 6abb5ea2ee270b1e6aae69e6c9a388797fdff932cdb83793777d88a2cc98b8d3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8c1836d4b11868110075208ae16b8a8682db62afdeba32de713400208b5e841a436306944ea9feae1d12df032ddfa0ea8b3d337918a5b1246676bd023bc53c4b
|
|
7
|
+
data.tar.gz: ef9ade678b73ce8ebcabb013c98ba54a6022dc62dd175ab22224b8fe3c4384383a0e3edd6fda773f70c52a10193ab3601614c5b3d514e713816b487dd71c047d
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
# An assessment can be revised after the account creation was allowed: a slow source
|
|
7
7
|
# settles and the account's decision rises. NoResponse sends the new version as a
|
|
8
8
|
# signed assessment.updated webhook. LateResults.handle verifies that delivery
|
|
9
|
-
# with
|
|
9
|
+
# with WebhookVerification.construct_event, picks an action from your policy, and acts
|
|
10
10
|
# through the auth provider's admin API: revoke the user's sessions or ban the
|
|
11
11
|
# user.
|
|
12
12
|
#
|
|
@@ -20,7 +20,6 @@ require 'erb'
|
|
|
20
20
|
require 'json'
|
|
21
21
|
require 'net/http'
|
|
22
22
|
require 'uri'
|
|
23
|
-
require_relative 'webhooks'
|
|
24
23
|
|
|
25
24
|
module NoResponse
|
|
26
25
|
module LateResults
|
|
@@ -53,13 +52,14 @@ module NoResponse
|
|
|
53
52
|
end
|
|
54
53
|
end
|
|
55
54
|
|
|
56
|
-
# event is the verified
|
|
55
|
+
# event is the verified event from WebhookVerification.construct_event,
|
|
56
|
+
# such as a Models::Shared::AssessmentUpdatedEvent. action is the action that ran:
|
|
57
57
|
# NONE when the policy, the event or the user id called for nothing. It can
|
|
58
58
|
# be stronger than the policy's action when the provider had to fall back:
|
|
59
59
|
# the auth0 provider reports BAN when it blocked the user because the
|
|
60
60
|
# tenant's plan cannot end sessions. user_id is
|
|
61
61
|
# the provider user id acted on, set only when an action was taken. Answer
|
|
62
|
-
# an endpoint.verification with
|
|
62
|
+
# an endpoint.verification with { 'challenge' => event.data.challenge }.
|
|
63
63
|
Result = Struct.new(:event, :action, :user_id, keyword_init: true)
|
|
64
64
|
|
|
65
65
|
class << self
|
|
@@ -70,7 +70,8 @@ module NoResponse
|
|
|
70
70
|
# strings or symbols) to NONE, REVOKE_SESSIONS or BAN; a decision you
|
|
71
71
|
# leave out does nothing. An unknown action raises ArgumentError.
|
|
72
72
|
def action_for(event, policy = DEFAULT_POLICY)
|
|
73
|
-
|
|
73
|
+
# Only an assessment.updated event can be a test event.
|
|
74
|
+
return NONE if event.type == 'assessment.updated' && event.test == true
|
|
74
75
|
|
|
75
76
|
data = event.data
|
|
76
77
|
if event.type == 'account.risk_changed'
|
|
@@ -79,6 +80,7 @@ module NoResponse
|
|
|
79
80
|
decision = data.account.decisions_by_flow.login.to_s
|
|
80
81
|
return NONE if data.previous_decisions_by_flow&.login.to_s == decision
|
|
81
82
|
elsif event.type == 'assessment.updated'
|
|
83
|
+
return NONE if data.is_a?(Models::Shared::AssessmentExpired)
|
|
82
84
|
return NONE if data.status == Models::Shared::Status::PENDING || data.account.nil?
|
|
83
85
|
decision = data.account.risk.decision.to_s
|
|
84
86
|
else
|
|
@@ -101,8 +103,8 @@ module NoResponse
|
|
|
101
103
|
# Verify a webhook delivery and apply your policy to it.
|
|
102
104
|
#
|
|
103
105
|
# payload, headers and secrets, plus tolerance_seconds and now, are
|
|
104
|
-
# exactly what
|
|
105
|
-
# verification raises
|
|
106
|
+
# exactly what WebhookVerification.construct_event takes; a delivery that fails
|
|
107
|
+
# verification raises WebhookVerification::VerificationError before any provider
|
|
106
108
|
# call. Deduplicate on result.event.id and ignore versions older than one
|
|
107
109
|
# you have acted on.
|
|
108
110
|
#
|
|
@@ -111,7 +113,7 @@ module NoResponse
|
|
|
111
113
|
# account_id; it defaults to the account_id itself, as when you assess
|
|
112
114
|
# with the provider's user id. Return nil or "" to take no action.
|
|
113
115
|
def handle(payload, headers, secrets, provider, policy: DEFAULT_POLICY, user_id: nil, **verify)
|
|
114
|
-
event =
|
|
116
|
+
event = WebhookVerification.construct_event(payload, headers, secrets, **verify)
|
|
115
117
|
action = action_for(event, policy)
|
|
116
118
|
return Result.new(event: event, action: NONE) if action == NONE
|
|
117
119
|
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module NoResponse
|
|
5
|
+
module Models
|
|
6
|
+
module Shared
|
|
7
|
+
# Terminal for the account's assessments created at or before deleted_at in the receiving endpoint's environment: delete what you hold from them and ignore later-arriving updates of them. deleted_at is no earlier than the creation of any assessment it erased. An assessment created after it belongs to the account assessed again: keep it, even when this event arrives after it.
|
|
8
|
+
class AccountDeleted
|
|
9
|
+
extend T::Sig
|
|
10
|
+
include Crystalline::MetadataFields
|
|
11
|
+
|
|
12
|
+
# Your own opaque identifier for the account being checked, scoped to your workspace. Use an id you mint, with no direct identifier (email, phone, name or national id) in it. '|' is accepted so an Auth0 user id such as 'auth0|64abc' passes unchanged; '@', '+', '$' and whitespace are refused by the pattern, as is an exact-shape JWT; a hex digest such as a SHA-256 is allowed, because hashing an internal id is a common pseudonymous scheme. A value such as '07700900123' or 'jane.doe.gmail.com' cannot be told apart from an opaque id. It travels in bodies, and in a URL only as the path segment of GET /v1/accounts/{account_id} and its /assessments. An assessment requested by a provider hook at pre_registration, which has no account yet, carries the server-issued account_id pre: followed by its assessment_id.
|
|
13
|
+
field(
|
|
14
|
+
:account_id,
|
|
15
|
+
::String,
|
|
16
|
+
{'format_json': {'letter_case': ::NoResponse::Utils.field_name("account_id"), required: true}}
|
|
17
|
+
)
|
|
18
|
+
# How many assessments the erasure deleted.
|
|
19
|
+
field(
|
|
20
|
+
:assessments_deleted,
|
|
21
|
+
::Integer,
|
|
22
|
+
{'format_json': {'letter_case': ::NoResponse::Utils.field_name("assessments_deleted"), required: true}}
|
|
23
|
+
)
|
|
24
|
+
# When the erasure took effect, equal to deleted_at in the DELETE answer.
|
|
25
|
+
field(
|
|
26
|
+
:deleted_at,
|
|
27
|
+
::String,
|
|
28
|
+
{'format_json': {'letter_case': ::NoResponse::Utils.field_name("deleted_at"), required: true}}
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
sig { params(account_id: ::String, assessments_deleted: ::Integer, deleted_at: ::String).void }
|
|
32
|
+
def initialize(account_id:, assessments_deleted:, deleted_at:)
|
|
33
|
+
@account_id = account_id
|
|
34
|
+
@assessments_deleted = assessments_deleted
|
|
35
|
+
@deleted_at = deleted_at
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
sig { params(other: T.untyped).returns(T::Boolean) }
|
|
39
|
+
def ==(other)
|
|
40
|
+
return false unless other.is_a?(self.class)
|
|
41
|
+
return false unless @account_id == other.account_id
|
|
42
|
+
return false unless @assessments_deleted == other.assessments_deleted
|
|
43
|
+
return false unless @deleted_at == other.deleted_at
|
|
44
|
+
true
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
class NoResponse::Models::Shared::AccountDeleted
|
|
5
|
+
extend ::Crystalline::MetadataFields::ClassMethods
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
class NoResponse::Models::Shared::AccountDeleted
|
|
9
|
+
def account_id
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def account_id=(str_)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def assessments_deleted
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def assessments_deleted=(str_)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def deleted_at
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def deleted_at=(str_)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module NoResponse
|
|
5
|
+
module Models
|
|
6
|
+
module Shared
|
|
7
|
+
# The account.deleted event.
|
|
8
|
+
class AccountDeletedEvent
|
|
9
|
+
extend T::Sig
|
|
10
|
+
include Crystalline::MetadataFields
|
|
11
|
+
|
|
12
|
+
# The event id, equal to the NR-Webhook-Id header and across redeliveries and every endpoint the event fans out to.
|
|
13
|
+
field :id, ::String, {'format_json': {'letter_case': ::NoResponse::Utils.field_name("id"), required: true}}
|
|
14
|
+
# When the event was created. Equal across redeliveries; the signing timestamp header is per delivery.
|
|
15
|
+
field(
|
|
16
|
+
:created_at,
|
|
17
|
+
::String,
|
|
18
|
+
{'format_json': {'letter_case': ::NoResponse::Utils.field_name("created_at"), required: true}}
|
|
19
|
+
)
|
|
20
|
+
# Terminal for the account's assessments created at or before deleted_at in the receiving endpoint's environment: delete what you hold from them and ignore later-arriving updates of them. deleted_at is no earlier than the creation of any assessment it erased. An assessment created after it belongs to the account assessed again: keep it, even when this event arrives after it.
|
|
21
|
+
field(
|
|
22
|
+
:data,
|
|
23
|
+
Models::Shared::AccountDeleted,
|
|
24
|
+
{'format_json': {'letter_case': ::NoResponse::Utils.field_name("data"), required: true}}
|
|
25
|
+
)
|
|
26
|
+
# Always account.deleted.
|
|
27
|
+
field :type, ::String, {'format_json': {'letter_case': ::NoResponse::Utils.field_name("type"), required: true}}
|
|
28
|
+
# Present, and true, only on an event sent by POST /v1/webhooks/{endpoint_id}/test: its data is a fixed example assessment, not one of the workspace's, so a receiver acknowledges it and applies nothing. Real events have no test member.
|
|
29
|
+
field(
|
|
30
|
+
:test,
|
|
31
|
+
Crystalline::Nilable.new(Crystalline::Boolean.new),
|
|
32
|
+
{'format_json': {'letter_case': ::NoResponse::Utils.field_name("test")}}
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
sig {
|
|
36
|
+
params(
|
|
37
|
+
id: ::String,
|
|
38
|
+
created_at: ::String,
|
|
39
|
+
data: Models::Shared::AccountDeleted,
|
|
40
|
+
type: ::String,
|
|
41
|
+
test: T.nilable(T::Boolean)
|
|
42
|
+
)
|
|
43
|
+
.void
|
|
44
|
+
}
|
|
45
|
+
def initialize(id:, created_at:, data:, type: "account.deleted", test: nil)
|
|
46
|
+
@id = id
|
|
47
|
+
@created_at = created_at
|
|
48
|
+
@data = data
|
|
49
|
+
unless type == "account.deleted"
|
|
50
|
+
raise ArgumentError, "Invalid value for type"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
@type = "account.deleted"
|
|
54
|
+
@test = test
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
sig { params(other: T.untyped).returns(T::Boolean) }
|
|
58
|
+
def ==(other)
|
|
59
|
+
return false unless other.is_a?(self.class)
|
|
60
|
+
return false unless @id == other.id
|
|
61
|
+
return false unless @created_at == other.created_at
|
|
62
|
+
return false unless @data == other.data
|
|
63
|
+
return false unless @type == other.type
|
|
64
|
+
return false unless @test == other.test
|
|
65
|
+
true
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
class NoResponse::Models::Shared::AccountDeletedEvent
|
|
5
|
+
extend ::Crystalline::MetadataFields::ClassMethods
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
class NoResponse::Models::Shared::AccountDeletedEvent
|
|
9
|
+
def id
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def id=(str_)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def created_at
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def created_at=(str_)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def data
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def data=(str_)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def type
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def type=(str_)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def test
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def test=(str_)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module NoResponse
|
|
5
|
+
module Models
|
|
6
|
+
module Shared
|
|
7
|
+
# The account's decision for at least one flow changed. account is the account as GET /v1/accounts/{account_id} answers it for the revision that made the change: its new score, decision, reasons and decisions_by_flow, and the assessment the risk comes from. previous_decisions_by_flow are the decisions it replaced, so account.decisions_by_flow differs from them for at least one flow. On the account's first decision, previous_decisions_by_flow is allow for every flow. Events of one account are not ordered: account.risk_version orders them, so keep the account with the highest risk_version and ignore an event whose account is older than the one held.
|
|
8
|
+
class AccountRiskChanged
|
|
9
|
+
extend T::Sig
|
|
10
|
+
include Crystalline::MetadataFields
|
|
11
|
+
|
|
12
|
+
# Body of the 200 answer to GET /v1/accounts/{account_id}: the one current risk of one of the calling workspace's accounts. It is the risk of the account's latest assessment that has a decision (status complete or partial), by created_at and then assessment_id, scored exactly as GET /v1/assessments/{assessment_id} scores that assessment, plus the account's own reason shared_api_key when a key issued to the account was used from many IP addresses or countries (POST /v1/key_usage/batches). Its assessments are the account's history (GET /v1/accounts/{account_id}/assessments).
|
|
13
|
+
field(
|
|
14
|
+
:account,
|
|
15
|
+
Models::Shared::Account,
|
|
16
|
+
{'format_json': {'letter_case': ::NoResponse::Utils.field_name("account"), required: true}}
|
|
17
|
+
)
|
|
18
|
+
# The decision for each flow: the account's score under that flow's thresholds. A flow the workspace has not set uses its account_creation thresholds, so the flows differ only where it set them.
|
|
19
|
+
field(
|
|
20
|
+
:previous_decisions_by_flow,
|
|
21
|
+
Models::Shared::AccountDecisionsByFlow,
|
|
22
|
+
{'format_json': {'letter_case': ::NoResponse::Utils.field_name("previous_decisions_by_flow"), required: true}}
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
sig {
|
|
26
|
+
params(account: Models::Shared::Account, previous_decisions_by_flow: Models::Shared::AccountDecisionsByFlow)
|
|
27
|
+
.void
|
|
28
|
+
}
|
|
29
|
+
def initialize(account:, previous_decisions_by_flow:)
|
|
30
|
+
@account = account
|
|
31
|
+
@previous_decisions_by_flow = previous_decisions_by_flow
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
sig { params(other: T.untyped).returns(T::Boolean) }
|
|
35
|
+
def ==(other)
|
|
36
|
+
return false unless other.is_a?(self.class)
|
|
37
|
+
return false unless @account == other.account
|
|
38
|
+
return false unless @previous_decisions_by_flow == other.previous_decisions_by_flow
|
|
39
|
+
true
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
class NoResponse::Models::Shared::AccountRiskChanged
|
|
5
|
+
extend ::Crystalline::MetadataFields::ClassMethods
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
class NoResponse::Models::Shared::AccountRiskChanged
|
|
9
|
+
def account
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def account=(str_)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def previous_decisions_by_flow
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def previous_decisions_by_flow=(str_)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module NoResponse
|
|
5
|
+
module Models
|
|
6
|
+
module Shared
|
|
7
|
+
# The account.risk_changed event.
|
|
8
|
+
class AccountRiskChangedEvent
|
|
9
|
+
extend T::Sig
|
|
10
|
+
include Crystalline::MetadataFields
|
|
11
|
+
|
|
12
|
+
# The event id, equal to the NR-Webhook-Id header and across redeliveries and every endpoint the event fans out to.
|
|
13
|
+
field :id, ::String, {'format_json': {'letter_case': ::NoResponse::Utils.field_name("id"), required: true}}
|
|
14
|
+
# When the event was created. Equal across redeliveries; the signing timestamp header is per delivery.
|
|
15
|
+
field(
|
|
16
|
+
:created_at,
|
|
17
|
+
::String,
|
|
18
|
+
{'format_json': {'letter_case': ::NoResponse::Utils.field_name("created_at"), required: true}}
|
|
19
|
+
)
|
|
20
|
+
# The account's decision for at least one flow changed. account is the account as GET /v1/accounts/{account_id} answers it for the revision that made the change: its new score, decision, reasons and decisions_by_flow, and the assessment the risk comes from. previous_decisions_by_flow are the decisions it replaced, so account.decisions_by_flow differs from them for at least one flow. On the account's first decision, previous_decisions_by_flow is allow for every flow. Events of one account are not ordered: account.risk_version orders them, so keep the account with the highest risk_version and ignore an event whose account is older than the one held.
|
|
21
|
+
field(
|
|
22
|
+
:data,
|
|
23
|
+
Models::Shared::AccountRiskChanged,
|
|
24
|
+
{'format_json': {'letter_case': ::NoResponse::Utils.field_name("data"), required: true}}
|
|
25
|
+
)
|
|
26
|
+
# Always account.risk_changed.
|
|
27
|
+
field :type, ::String, {'format_json': {'letter_case': ::NoResponse::Utils.field_name("type"), required: true}}
|
|
28
|
+
# Present, and true, only on an event sent by POST /v1/webhooks/{endpoint_id}/test: its data is a fixed example assessment, not one of the workspace's, so a receiver acknowledges it and applies nothing. Real events have no test member.
|
|
29
|
+
field(
|
|
30
|
+
:test,
|
|
31
|
+
Crystalline::Nilable.new(Crystalline::Boolean.new),
|
|
32
|
+
{'format_json': {'letter_case': ::NoResponse::Utils.field_name("test")}}
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
sig {
|
|
36
|
+
params(
|
|
37
|
+
id: ::String,
|
|
38
|
+
created_at: ::String,
|
|
39
|
+
data: Models::Shared::AccountRiskChanged,
|
|
40
|
+
type: ::String,
|
|
41
|
+
test: T.nilable(T::Boolean)
|
|
42
|
+
)
|
|
43
|
+
.void
|
|
44
|
+
}
|
|
45
|
+
def initialize(id:, created_at:, data:, type: "account.risk_changed", test: nil)
|
|
46
|
+
@id = id
|
|
47
|
+
@created_at = created_at
|
|
48
|
+
@data = data
|
|
49
|
+
unless type == "account.risk_changed"
|
|
50
|
+
raise ArgumentError, "Invalid value for type"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
@type = "account.risk_changed"
|
|
54
|
+
@test = test
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
sig { params(other: T.untyped).returns(T::Boolean) }
|
|
58
|
+
def ==(other)
|
|
59
|
+
return false unless other.is_a?(self.class)
|
|
60
|
+
return false unless @id == other.id
|
|
61
|
+
return false unless @created_at == other.created_at
|
|
62
|
+
return false unless @data == other.data
|
|
63
|
+
return false unless @type == other.type
|
|
64
|
+
return false unless @test == other.test
|
|
65
|
+
true
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
class NoResponse::Models::Shared::AccountRiskChangedEvent
|
|
5
|
+
extend ::Crystalline::MetadataFields::ClassMethods
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
class NoResponse::Models::Shared::AccountRiskChangedEvent
|
|
9
|
+
def id
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def id=(str_)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def created_at
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def created_at=(str_)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def data
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def data=(str_)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def type
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def type=(str_)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def test
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def test=(str_)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module NoResponse
|
|
5
|
+
module Models
|
|
6
|
+
module Shared
|
|
7
|
+
# Terminal. Nothing to fetch; the consumer deletes its state for assessment_id.
|
|
8
|
+
class AssessmentExpired
|
|
9
|
+
extend T::Sig
|
|
10
|
+
include Crystalline::MetadataFields
|
|
11
|
+
|
|
12
|
+
# Opaque, server-assigned assessment id: 'asm_' and a 26-character Crockford base32 ULID. Unique within the workspace; another workspace's assessment id answers 404.
|
|
13
|
+
field(
|
|
14
|
+
:assessment_id,
|
|
15
|
+
::String,
|
|
16
|
+
{'format_json': {'letter_case': ::NoResponse::Utils.field_name("assessment_id"), required: true}}
|
|
17
|
+
)
|
|
18
|
+
# Your own opaque identifier for the account being checked, scoped to your workspace. Use an id you mint, with no direct identifier (email, phone, name or national id) in it. '|' is accepted so an Auth0 user id such as 'auth0|64abc' passes unchanged; '@', '+', '$' and whitespace are refused by the pattern, as is an exact-shape JWT; a hex digest such as a SHA-256 is allowed, because hashing an internal id is a common pseudonymous scheme. A value such as '07700900123' or 'jane.doe.gmail.com' cannot be told apart from an opaque id. It travels in bodies, and in a URL only as the path segment of GET /v1/accounts/{account_id} and its /assessments. An assessment requested by a provider hook at pre_registration, which has no account yet, carries the server-issued account_id pre: followed by its assessment_id.
|
|
19
|
+
field(
|
|
20
|
+
:account_id,
|
|
21
|
+
::String,
|
|
22
|
+
{'format_json': {'letter_case': ::NoResponse::Utils.field_name("account_id"), required: true}}
|
|
23
|
+
)
|
|
24
|
+
# The last served version: expiry is not a revision.
|
|
25
|
+
field(
|
|
26
|
+
:assessment_version,
|
|
27
|
+
::Integer,
|
|
28
|
+
{'format_json': {'letter_case': ::NoResponse::Utils.field_name("assessment_version"), required: true}}
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
field(
|
|
32
|
+
:status,
|
|
33
|
+
::String,
|
|
34
|
+
{'format_json': {'letter_case': ::NoResponse::Utils.field_name("status"), required: true}}
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
field(
|
|
38
|
+
:change_reason,
|
|
39
|
+
::String,
|
|
40
|
+
{'format_json': {'letter_case': ::NoResponse::Utils.field_name("change_reason"), required: true}}
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
sig {
|
|
44
|
+
params(
|
|
45
|
+
assessment_id: ::String,
|
|
46
|
+
account_id: ::String,
|
|
47
|
+
assessment_version: ::Integer,
|
|
48
|
+
status: ::String,
|
|
49
|
+
change_reason: ::String
|
|
50
|
+
)
|
|
51
|
+
.void
|
|
52
|
+
}
|
|
53
|
+
def initialize(assessment_id:, account_id:, assessment_version:, status: "expired", change_reason: "expired")
|
|
54
|
+
@assessment_id = assessment_id
|
|
55
|
+
@account_id = account_id
|
|
56
|
+
@assessment_version = assessment_version
|
|
57
|
+
unless status == "expired"
|
|
58
|
+
raise ArgumentError, "Invalid value for status"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
@status = "expired"
|
|
62
|
+
unless change_reason == "expired"
|
|
63
|
+
raise ArgumentError, "Invalid value for change_reason"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
@change_reason = "expired"
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
sig { params(other: T.untyped).returns(T::Boolean) }
|
|
70
|
+
def ==(other)
|
|
71
|
+
return false unless other.is_a?(self.class)
|
|
72
|
+
return false unless @assessment_id == other.assessment_id
|
|
73
|
+
return false unless @account_id == other.account_id
|
|
74
|
+
return false unless @assessment_version == other.assessment_version
|
|
75
|
+
return false unless @status == other.status
|
|
76
|
+
return false unless @change_reason == other.change_reason
|
|
77
|
+
true
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
class NoResponse::Models::Shared::AssessmentExpired
|
|
5
|
+
extend ::Crystalline::MetadataFields::ClassMethods
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
class NoResponse::Models::Shared::AssessmentExpired
|
|
9
|
+
def assessment_id
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def assessment_id=(str_)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def account_id
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def account_id=(str_)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def assessment_version
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def assessment_version=(str_)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def status
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def status=(str_)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def change_reason
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def change_reason=(str_)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module NoResponse
|
|
5
|
+
module Models
|
|
6
|
+
module Shared
|
|
7
|
+
# The assessment, or the minimal notice that it expired.
|
|
8
|
+
class AssessmentUpdatedData
|
|
9
|
+
extend T::Sig
|
|
10
|
+
include Crystalline::MetadataFields
|
|
11
|
+
|
|
12
|
+
def initialize
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
sig { params(other: T.untyped).returns(T::Boolean) }
|
|
16
|
+
def ==(other)
|
|
17
|
+
return false unless other.is_a?(self.class)
|
|
18
|
+
true
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|