cognito-client 0.4.1 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +2 -1
- data/Gemfile +37 -0
- data/Guardfile +4 -0
- data/README.md +55 -18
- data/Rakefile +3 -5
- data/bin/console +1 -1
- data/circle.yml +7 -0
- data/cognito.gemspec +4 -6
- data/config/devtools.yml +2 -0
- data/config/errors.yml +2 -0
- data/config/flay.yml +5 -0
- data/config/flog.yml +5 -0
- data/config/mutant.yml +6 -0
- data/config/reek.yml +111 -0
- data/config/rubocop.yml +91 -0
- data/config/yardstick.yml +2 -0
- data/lib/cognito/client.rb +59 -96
- data/lib/cognito/client/command.rb +34 -0
- data/lib/cognito/client/commands/create_identity.rb +22 -0
- data/lib/cognito/client/commands/create_identity_assessment.rb +26 -0
- data/lib/cognito/client/commands/create_identity_search.rb +37 -0
- data/lib/cognito/client/commands/create_profile.rb +24 -0
- data/lib/cognito/client/commands/mixins/create_behavior.rb +20 -0
- data/lib/cognito/client/commands/retrieve_identity_location.rb +28 -0
- data/lib/cognito/client/commands/retrieve_identity_search_job.rb +40 -0
- data/lib/cognito/client/connection.rb +36 -0
- data/lib/cognito/client/document.rb +32 -0
- data/lib/cognito/client/params.rb +13 -0
- data/lib/cognito/client/params/identity.rb +48 -0
- data/lib/cognito/client/params/identity_assessment.rb +23 -0
- data/lib/cognito/client/params/identity_search.rb +25 -0
- data/lib/cognito/client/params/omitted.rb +9 -0
- data/lib/cognito/client/request.rb +98 -0
- data/lib/cognito/client/resource.rb +124 -0
- data/lib/cognito/client/resource/identity_assessment.rb +53 -0
- data/lib/cognito/client/resource/identity_search.rb +64 -0
- data/lib/cognito/client/resource/identity_search_job.rb +12 -0
- data/lib/cognito/client/resource/profile.rb +10 -0
- data/lib/cognito/client/resource_identifier.rb +17 -0
- data/lib/cognito/client/response.rb +17 -0
- data/lib/cognito/client/response/builder.rb +48 -0
- data/lib/cognito/client/response/identity_assessment.rb +10 -0
- data/lib/cognito/client/response/identity_search.rb +32 -0
- data/lib/cognito/client/response/identity_search_job.rb +20 -0
- data/lib/cognito/client/response/profile.rb +10 -0
- data/lib/cognito/version.rb +3 -3
- metadata +77 -83
- data/.rubocop.yml +0 -57
- data/.travis.yml +0 -4
- data/lib/cognito.rb +0 -32
- data/lib/cognito/cleaner.rb +0 -30
- data/lib/cognito/constants.rb +0 -8
- data/lib/cognito/document.rb +0 -33
- data/lib/cognito/error.rb +0 -8
- data/lib/cognito/notary.rb +0 -56
- data/lib/cognito/resource.rb +0 -129
- data/lib/cognito/resource/identity_assessment.rb +0 -40
- data/lib/cognito/resource/identity_search.rb +0 -63
- data/lib/cognito/resource/identity_search_job.rb +0 -11
- data/lib/cognito/resource/profile.rb +0 -9
- data/lib/cognito/responder.rb +0 -61
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
class Cognito
|
3
|
+
class Client
|
4
|
+
class Document
|
5
|
+
include Anima.new(:data, :included), Adamantium
|
6
|
+
|
7
|
+
def initialize(data:, included: [])
|
8
|
+
super
|
9
|
+
end
|
10
|
+
|
11
|
+
def resolve(resource_object)
|
12
|
+
lookup.fetch(resource_object).first
|
13
|
+
end
|
14
|
+
|
15
|
+
def include(resource)
|
16
|
+
with(included: included + resource.included)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def lookup
|
22
|
+
resources.group_by(&ResourceIdentifier)
|
23
|
+
end
|
24
|
+
memoize(:lookup)
|
25
|
+
|
26
|
+
def resources
|
27
|
+
included + [data]
|
28
|
+
end
|
29
|
+
memoize :resources
|
30
|
+
end # Document
|
31
|
+
end # Client
|
32
|
+
end # Cognito
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Cognito
|
4
|
+
class Client
|
5
|
+
class Params
|
6
|
+
class Identity < self
|
7
|
+
include AbstractType, Anima.new(:name, :phone_number)
|
8
|
+
|
9
|
+
abstract_method :relationships
|
10
|
+
|
11
|
+
def to_h
|
12
|
+
relationship_params.tap do |params|
|
13
|
+
params[:data][:attributes] = attributes unless attributes.empty?
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def relationship_params
|
18
|
+
{
|
19
|
+
data: {
|
20
|
+
type: self.class::TYPE,
|
21
|
+
relationships: relationships
|
22
|
+
}
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def attributes
|
29
|
+
full_attributes.reject { |_, val| val.instance_of?(Omitted) }
|
30
|
+
end
|
31
|
+
memoize :attributes
|
32
|
+
|
33
|
+
def full_attributes
|
34
|
+
{
|
35
|
+
name: name,
|
36
|
+
phone: phone
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
def phone
|
41
|
+
return phone_number if phone_number.instance_of?(Omitted)
|
42
|
+
|
43
|
+
{ number: phone_number }
|
44
|
+
end
|
45
|
+
end # Identity
|
46
|
+
end # Params
|
47
|
+
end # Client
|
48
|
+
end # Cognito
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Cognito
|
4
|
+
class Client
|
5
|
+
class Params
|
6
|
+
class IdentityAssessment < Identity
|
7
|
+
include anima.add(:identity_search_identifier)
|
8
|
+
|
9
|
+
TYPE = 'identity_assessment'
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def relationships
|
14
|
+
{
|
15
|
+
identity_search: {
|
16
|
+
data: identity_search_identifier
|
17
|
+
}
|
18
|
+
}
|
19
|
+
end
|
20
|
+
end # IdentityAssessment
|
21
|
+
end # Params
|
22
|
+
end # Client
|
23
|
+
end # Cognito
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Cognito
|
4
|
+
class Client
|
5
|
+
class Params
|
6
|
+
class IdentitySearch < Identity
|
7
|
+
include anima.add(:profile_id)
|
8
|
+
|
9
|
+
TYPE = 'identity_search'
|
10
|
+
RELATIONSHIP_TYPE = 'profile'
|
11
|
+
|
12
|
+
def relationships
|
13
|
+
{
|
14
|
+
profile: {
|
15
|
+
data: {
|
16
|
+
type: RELATIONSHIP_TYPE,
|
17
|
+
id: profile_id
|
18
|
+
}
|
19
|
+
}
|
20
|
+
}
|
21
|
+
end
|
22
|
+
end # IdentitySearch
|
23
|
+
end # Params
|
24
|
+
end # Client
|
25
|
+
end # Cognito
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
class Cognito
|
3
|
+
class Client
|
4
|
+
class Request
|
5
|
+
CONSTANT_HEADERS = IceNine.deep_freeze(
|
6
|
+
'Content-Type' => 'application/vnd.api+json'
|
7
|
+
)
|
8
|
+
|
9
|
+
include Anima.new(:verb, :endpoint, :data, :headers), Adamantium
|
10
|
+
|
11
|
+
def self.post(*arguments)
|
12
|
+
build(:post, *arguments)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.get(endpoint)
|
16
|
+
build(:get, endpoint, nil)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.build(verb, endpoint, data)
|
20
|
+
new(
|
21
|
+
verb: verb,
|
22
|
+
endpoint: endpoint,
|
23
|
+
data: data,
|
24
|
+
headers: CONSTANT_HEADERS
|
25
|
+
)
|
26
|
+
end
|
27
|
+
private_class_method :build
|
28
|
+
|
29
|
+
def sign(**signature_params)
|
30
|
+
with(headers: SigningHeaders.call(request: self, **signature_params))
|
31
|
+
end
|
32
|
+
|
33
|
+
class SigningHeaders
|
34
|
+
include Procto.call(:to_h), Anima.new(:request, :date, :api_key, :api_secret), Adamantium
|
35
|
+
|
36
|
+
DIGEST_HEADER = 'SHA-256=%<digest>s'
|
37
|
+
EMPTY_BODY = ''
|
38
|
+
SHA256 = IceNine.deep_freeze(OpenSSL::Digest::SHA256.new)
|
39
|
+
|
40
|
+
AUTHORIZATION_STRING = [
|
41
|
+
'Signature keyId="%<api_key>s"',
|
42
|
+
'algorithm="hmac-sha256"',
|
43
|
+
'headers="date digest (request-target)"',
|
44
|
+
'signature="%<signature>s"'
|
45
|
+
].join(',').freeze
|
46
|
+
|
47
|
+
SIGNING_STRING = [
|
48
|
+
'date: %<date>s',
|
49
|
+
'digest: %<digest>s',
|
50
|
+
'(request-target): %<request_target>s'
|
51
|
+
].join("\n").freeze
|
52
|
+
|
53
|
+
def to_h
|
54
|
+
request.headers.merge(
|
55
|
+
'Authorization' => auth_header,
|
56
|
+
'Digest' => digest_header,
|
57
|
+
'Date' => date
|
58
|
+
)
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def auth_header
|
64
|
+
format(AUTHORIZATION_STRING, api_key: api_key, signature: signature)
|
65
|
+
end
|
66
|
+
|
67
|
+
def signature
|
68
|
+
Base64.strict_encode64(OpenSSL::HMAC.digest(SHA256, api_secret, signing_string))
|
69
|
+
end
|
70
|
+
|
71
|
+
def signing_string
|
72
|
+
format(SIGNING_STRING, date: date, digest: digest_header, request_target: request_target)
|
73
|
+
end
|
74
|
+
|
75
|
+
def digest_header
|
76
|
+
format(DIGEST_HEADER, digest: digest)
|
77
|
+
end
|
78
|
+
|
79
|
+
def request_target
|
80
|
+
"#{request.verb} #{request.endpoint}"
|
81
|
+
end
|
82
|
+
|
83
|
+
def digest
|
84
|
+
Base64.strict_encode64(SHA256.digest(request_body))
|
85
|
+
end
|
86
|
+
memoize :digest
|
87
|
+
|
88
|
+
def request_body
|
89
|
+
return EMPTY_BODY unless request.data
|
90
|
+
|
91
|
+
JSON.dump(request.data)
|
92
|
+
end
|
93
|
+
|
94
|
+
private_constant(*constants(false))
|
95
|
+
end # SigningHeaders
|
96
|
+
end # Request
|
97
|
+
end # Client
|
98
|
+
end # Cognito
|
@@ -0,0 +1,124 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
class Cognito
|
3
|
+
class Client
|
4
|
+
class Resource
|
5
|
+
include AbstractType,
|
6
|
+
Memoizable,
|
7
|
+
Anima.new(:id, :type, :attributes, :relationships, :parent)
|
8
|
+
|
9
|
+
class MissingRelation < StandardError
|
10
|
+
MESSAGE = "Registered relation key, '%s', not in relationships"\
|
11
|
+
' for resource: %p'
|
12
|
+
|
13
|
+
def initialize(key, resource)
|
14
|
+
super(format(MESSAGE, *[key, resource]))
|
15
|
+
end
|
16
|
+
end # MissingRelation
|
17
|
+
|
18
|
+
def self.register_type(type)
|
19
|
+
REGISTRY.add(type, self)
|
20
|
+
end
|
21
|
+
private_class_method :register_type
|
22
|
+
|
23
|
+
# ignores :reek:TooManyStatements:
|
24
|
+
def self.one(key)
|
25
|
+
define_relationship(key) do
|
26
|
+
identifier = relationship_data(key)
|
27
|
+
return unless identifier
|
28
|
+
|
29
|
+
find_identifier(identifier)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
private_class_method :one
|
33
|
+
|
34
|
+
def self.many(key)
|
35
|
+
define_relationship(key) do
|
36
|
+
relationship_data(key).map(&method(:find_identifier))
|
37
|
+
end
|
38
|
+
end
|
39
|
+
private_class_method :many
|
40
|
+
|
41
|
+
def self.attribute(key, method_name = key)
|
42
|
+
define_method(method_name) do
|
43
|
+
attributes[key]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.define_relationship(key, &block)
|
48
|
+
memoize(define_method(key, &block))
|
49
|
+
end
|
50
|
+
private_class_method :define_relationship
|
51
|
+
|
52
|
+
def self.build(data, parent)
|
53
|
+
new(data.merge(parent: parent))
|
54
|
+
end
|
55
|
+
|
56
|
+
def include(resource)
|
57
|
+
with(parent: parent.include(resource))
|
58
|
+
end
|
59
|
+
|
60
|
+
def included
|
61
|
+
parent.included
|
62
|
+
end
|
63
|
+
|
64
|
+
def initialize(relationships: nil, **options)
|
65
|
+
super
|
66
|
+
end
|
67
|
+
|
68
|
+
protected
|
69
|
+
|
70
|
+
def resolve(identifier)
|
71
|
+
parent.resolve(identifier)
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def find_identifier(identifier)
|
77
|
+
resource_class = REGISTRY.lookup(identifier.fetch(:type).to_sym)
|
78
|
+
resource_class.build(resolve(identifier), self)
|
79
|
+
end
|
80
|
+
|
81
|
+
def relationship_data(key)
|
82
|
+
fail MissingRelation.new(key, self) unless relationships && relationships.key?(key)
|
83
|
+
|
84
|
+
relationships.fetch(key).fetch(:data)
|
85
|
+
end
|
86
|
+
|
87
|
+
class Registry
|
88
|
+
include Concord.new(:registry)
|
89
|
+
|
90
|
+
class Error < StandardError
|
91
|
+
def initialize(type)
|
92
|
+
super(format(self.class::MESSAGE, type: type))
|
93
|
+
end
|
94
|
+
end # Error
|
95
|
+
|
96
|
+
class MissingError < Error
|
97
|
+
MESSAGE = 'Resource type not registered: %<type>s'
|
98
|
+
end # MissingError
|
99
|
+
|
100
|
+
class DuplicateTypeError < Error
|
101
|
+
MESSAGE = 'Resource type already registered: %<type>s'
|
102
|
+
end # DuplicateTypeError
|
103
|
+
|
104
|
+
def initialize
|
105
|
+
super({})
|
106
|
+
end
|
107
|
+
|
108
|
+
def lookup(type)
|
109
|
+
registry.fetch(type) do
|
110
|
+
fail MissingError, type
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def add(type, resource_class)
|
115
|
+
fail DuplicateTypeError, type if registry.key?(type)
|
116
|
+
|
117
|
+
registry[type] = resource_class
|
118
|
+
end
|
119
|
+
end # Registry
|
120
|
+
|
121
|
+
REGISTRY = Registry.new
|
122
|
+
end # Resource
|
123
|
+
end # Client
|
124
|
+
end # Cognito
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
class Cognito
|
3
|
+
class Client
|
4
|
+
class Resource
|
5
|
+
class IdentityAssessment < self
|
6
|
+
register_type :identity_assessment
|
7
|
+
|
8
|
+
attribute :name
|
9
|
+
attribute :phone
|
10
|
+
|
11
|
+
many :identity_record_comparisons
|
12
|
+
end # IdentityAssessment
|
13
|
+
|
14
|
+
class IdentityRecordComparison < self
|
15
|
+
register_type :identity_record_comparison
|
16
|
+
|
17
|
+
many :name_comparisons
|
18
|
+
many :phone_comparisons
|
19
|
+
one :identity_record
|
20
|
+
|
21
|
+
attribute :score
|
22
|
+
end # IdentityRecordComparison
|
23
|
+
|
24
|
+
class PhoneComparison < self
|
25
|
+
register_type :phone_comparison
|
26
|
+
|
27
|
+
attribute :score
|
28
|
+
|
29
|
+
one :source_record
|
30
|
+
end # PhoneComparison
|
31
|
+
|
32
|
+
class NameComparison < self
|
33
|
+
register_type :name_comparison
|
34
|
+
|
35
|
+
attribute :score
|
36
|
+
|
37
|
+
one :source_record
|
38
|
+
|
39
|
+
class Components
|
40
|
+
include Anima.new(:first, :middle, :last), Adamantium
|
41
|
+
|
42
|
+
class Component
|
43
|
+
include Anima.new(:source, :input, :score)
|
44
|
+
|
45
|
+
class Name
|
46
|
+
include Concord.new(:name), Adamantium
|
47
|
+
end # Name
|
48
|
+
end # Component
|
49
|
+
end # Components
|
50
|
+
end # NameComparison
|
51
|
+
end # Resource
|
52
|
+
end # Client
|
53
|
+
end # Cognito
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
class Cognito
|
3
|
+
class Client
|
4
|
+
class Resource
|
5
|
+
class IdentitySearch < self
|
6
|
+
register_type :identity_search
|
7
|
+
|
8
|
+
many :identity_records
|
9
|
+
end # IdentitySearch
|
10
|
+
|
11
|
+
class IdentityRecord < self
|
12
|
+
register_type :identity_record
|
13
|
+
|
14
|
+
many :addresses
|
15
|
+
many :names
|
16
|
+
many :ssns
|
17
|
+
many :phones
|
18
|
+
many :births
|
19
|
+
many :deaths
|
20
|
+
end # IdentityRecord
|
21
|
+
|
22
|
+
class USAddress < self
|
23
|
+
register_type :us_address
|
24
|
+
|
25
|
+
attribute :street
|
26
|
+
attribute :city
|
27
|
+
attribute :subdivision
|
28
|
+
attribute :postal_code
|
29
|
+
end # USAddress
|
30
|
+
|
31
|
+
class PartialName < self
|
32
|
+
register_type :name
|
33
|
+
|
34
|
+
attribute :first
|
35
|
+
attribute :middle
|
36
|
+
attribute :last
|
37
|
+
end # PartialName
|
38
|
+
|
39
|
+
class SSN < self
|
40
|
+
register_type :ssn
|
41
|
+
|
42
|
+
attribute :number
|
43
|
+
end # SSN
|
44
|
+
|
45
|
+
class Phone < self
|
46
|
+
register_type :phone
|
47
|
+
end # Phone
|
48
|
+
|
49
|
+
class PartialDate < self
|
50
|
+
attribute :day
|
51
|
+
attribute :month
|
52
|
+
attribute :year
|
53
|
+
end # PartialDate
|
54
|
+
|
55
|
+
class Birth < PartialDate
|
56
|
+
register_type :birth
|
57
|
+
end # Birth
|
58
|
+
|
59
|
+
class Death < PartialDate
|
60
|
+
register_type :death
|
61
|
+
end # Death
|
62
|
+
end # Resource
|
63
|
+
end # Client
|
64
|
+
end # Cognito
|