trusona 0.16.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
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.env.example +4 -0
- data/.gitignore +20 -0
- data/.rspec +3 -0
- data/.ruby-version +1 -0
- data/.travis.yml +24 -0
- data/Gemfile +8 -0
- data/Guardfile +54 -0
- data/LICENSE +201 -0
- data/README.md +234 -0
- data/Rakefile +8 -0
- data/bin/console +21 -0
- data/bin/setup +8 -0
- data/certs/trusona.pem +26 -0
- data/checksum/trusona-0.16.0.gem.sha512 +1 -0
- data/integrations/device_user_binding_integration_spec.rb +6 -0
- data/integrations/identity_documents_spec.rb +28 -0
- data/integrations/spec_helper.rb +23 -0
- data/integrations/tru_code_spec.rb +80 -0
- data/integrations/trusonafication_spec.rb +61 -0
- data/integrations/user_accounts_spec.rb +39 -0
- data/integrations/user_identifiers_spec.rb +32 -0
- data/lib/trusona.rb +157 -0
- data/lib/trusona/api/client.rb +60 -0
- data/lib/trusona/api/hashed_message.rb +71 -0
- data/lib/trusona/api/signed_request.rb +96 -0
- data/lib/trusona/api/verified_response.rb +85 -0
- data/lib/trusona/device.rb +31 -0
- data/lib/trusona/device_user_binding.rb +56 -0
- data/lib/trusona/errors.rb +51 -0
- data/lib/trusona/helpers/key_normalizer.rb +15 -0
- data/lib/trusona/helpers/time_normalizer.rb +17 -0
- data/lib/trusona/identity_document.rb +64 -0
- data/lib/trusona/mappers/base_mapper.rb +69 -0
- data/lib/trusona/mappers/device_mapper.rb +13 -0
- data/lib/trusona/mappers/device_user_binding_mapper.rb +13 -0
- data/lib/trusona/mappers/identity_document_mapper.rb +17 -0
- data/lib/trusona/mappers/nil_mapper.rb +11 -0
- data/lib/trusona/mappers/tru_code_mapper.rb +13 -0
- data/lib/trusona/mappers/trusonafication_mapper.rb +19 -0
- data/lib/trusona/mappers/user_account_mapper.rb +13 -0
- data/lib/trusona/mappers/user_identifier_mapper.rb +13 -0
- data/lib/trusona/resources/base_resource.rb +29 -0
- data/lib/trusona/resources/device.rb +22 -0
- data/lib/trusona/resources/device_user_binding.rb +30 -0
- data/lib/trusona/resources/device_user_binding_activation.rb +27 -0
- data/lib/trusona/resources/identity_document.rb +36 -0
- data/lib/trusona/resources/tru_code.rb +42 -0
- data/lib/trusona/resources/trusonafication.rb +137 -0
- data/lib/trusona/resources/user_account.rb +84 -0
- data/lib/trusona/resources/user_identifier.rb +49 -0
- data/lib/trusona/resources/validators.rb +22 -0
- data/lib/trusona/services/account_lookups_service.rb +17 -0
- data/lib/trusona/services/base_service.rb +117 -0
- data/lib/trusona/services/device_user_bindings_service.rb +22 -0
- data/lib/trusona/services/devices_service.rb +15 -0
- data/lib/trusona/services/identity_documents_service.rb +31 -0
- data/lib/trusona/services/tru_codes_service.rb +26 -0
- data/lib/trusona/services/trusonafication_service.rb +16 -0
- data/lib/trusona/services/user_accounts_service.rb +17 -0
- data/lib/trusona/services/user_identifiers_service.rb +16 -0
- data/lib/trusona/tru_code.rb +38 -0
- data/lib/trusona/tru_code_config.rb +45 -0
- data/lib/trusona/trusonafication.rb +133 -0
- data/lib/trusona/user_account.rb +17 -0
- data/lib/trusona/user_identifier.rb +15 -0
- data/lib/trusona/version.rb +5 -0
- data/lib/trusona/workers/device_finder.rb +18 -0
- data/lib/trusona/workers/device_user_binding_activator.rb +25 -0
- data/lib/trusona/workers/device_user_binding_creator.rb +26 -0
- data/lib/trusona/workers/identity_document_finder.rb +25 -0
- data/lib/trusona/workers/tru_code_creator.rb +17 -0
- data/lib/trusona/workers/tru_code_finder.rb +19 -0
- data/lib/trusona/workers/trusonafication_creator.rb +46 -0
- data/lib/trusona/workers/trusonafication_finder.rb +27 -0
- data/lib/trusona/workers/user_account_finder.rb +39 -0
- data/lib/trusona/workers/user_identifier_creator.rb +17 -0
- data/lib/trusona/workers/user_identifier_finder.rb +29 -0
- data/release-gem +17 -0
- data/trusona.gemspec +43 -0
- metadata +333 -0
- metadata.gz.sig +1 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Trusona
|
4
|
+
module Services
|
5
|
+
#
|
6
|
+
## Device User Bindings Service
|
7
|
+
class DeviceUserBindingsService < BaseService
|
8
|
+
def initialize(
|
9
|
+
client: Trusona::Api::HTTPClient.new(Trusona.config.api_host),
|
10
|
+
mapper: Trusona::Mappers::DeviceUserBindingMapper.new
|
11
|
+
)
|
12
|
+
@client = client
|
13
|
+
@mapper = mapper
|
14
|
+
@resource_path = '/api/v2/user_devices'
|
15
|
+
end
|
16
|
+
|
17
|
+
def verify_response(_response)
|
18
|
+
true
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Trusona
|
4
|
+
module Services
|
5
|
+
##
|
6
|
+
# A service to interact with the Device resource in the Trusona REST API
|
7
|
+
class DevicesService < BaseService
|
8
|
+
def initialize(client: Trusona::Api::HTTPClient.new,
|
9
|
+
mapper: Trusona::Mappers::DeviceMapper.new)
|
10
|
+
super
|
11
|
+
@resource_path = '/api/v2/devices'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Trusona
|
4
|
+
module Services
|
5
|
+
#
|
6
|
+
## Identity Documents Service
|
7
|
+
class IdentityDocumentsService < BaseService
|
8
|
+
def initialize(
|
9
|
+
client: Trusona::Api::HTTPClient.new(Trusona.config.api_host),
|
10
|
+
mapper: Trusona::Mappers::IdentityDocumentMapper.new
|
11
|
+
)
|
12
|
+
@client = client
|
13
|
+
@mapper = mapper
|
14
|
+
@resource_path = '/api/v2/identity_documents'
|
15
|
+
end
|
16
|
+
|
17
|
+
def index(user_identifier = nil)
|
18
|
+
modified_collection_path =
|
19
|
+
"#{collection_path}?user_identifier=#{user_identifier}"
|
20
|
+
|
21
|
+
handle(@client.get(modified_collection_path))
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def not_found
|
27
|
+
nil
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Trusona
|
4
|
+
module Services
|
5
|
+
#
|
6
|
+
## A service for interacting with TruCode TruCodes
|
7
|
+
class TruCodesService < BaseService
|
8
|
+
def initialize(
|
9
|
+
client: Trusona::Api::HTTPClient.new(Trusona.config.tru_codes_host),
|
10
|
+
mapper: Trusona::Mappers::TruCodeMapper.new
|
11
|
+
)
|
12
|
+
@client = client
|
13
|
+
@mapper = mapper
|
14
|
+
@resource_path = '/api/v2/trucodes'
|
15
|
+
end
|
16
|
+
|
17
|
+
def member_path(resource)
|
18
|
+
[@resource_path, resource.id].join('/')
|
19
|
+
end
|
20
|
+
|
21
|
+
def verify_response(_response)
|
22
|
+
true
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Trusona
|
4
|
+
module Services
|
5
|
+
##
|
6
|
+
# A service to interact with the Trusonafications resource
|
7
|
+
# in the Trusona REST API
|
8
|
+
class TrusonaficationService < BaseService
|
9
|
+
def initialize(client: Trusona::Api::HTTPClient.new,
|
10
|
+
mapper: Trusona::Mappers::TrusonaficationMapper.new)
|
11
|
+
super
|
12
|
+
@resource_path = '/api/v2/trusonafications'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Trusona
|
4
|
+
module Services
|
5
|
+
#
|
6
|
+
## User Accounts Service
|
7
|
+
class UserAccountsService < BaseService
|
8
|
+
def initialize(client: nil, mapper: nil)
|
9
|
+
@client = client || Trusona::Api::HTTPClient.new(
|
10
|
+
Trusona.config.api_host
|
11
|
+
)
|
12
|
+
@mapper = mapper || Trusona::Mappers::UserAccountMapper.new
|
13
|
+
@resource_path = '/internal/v1/users'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Trusona
|
4
|
+
module Services
|
5
|
+
#
|
6
|
+
## User Identifiers Service
|
7
|
+
class UserIdentifiersService < BaseService
|
8
|
+
def initialize(client: nil, mapper: nil)
|
9
|
+
@client = client ||
|
10
|
+
Trusona::Api::HTTPClient.new(Trusona.config.api_host)
|
11
|
+
@mapper = mapper || Trusona::Mappers::UserIdentifierMapper.new
|
12
|
+
@resource_path = '/api/v2/user_identifiers'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Trusona
|
4
|
+
##
|
5
|
+
# A scannable, pairable TruCode to assist magic logins
|
6
|
+
class TruCode
|
7
|
+
##
|
8
|
+
# Finds a TruCode using its ID
|
9
|
+
#
|
10
|
+
# @param id [String] The id of the TruCode we're looking for
|
11
|
+
# @return [Trusona::Resources::TruCode] The found TruCode
|
12
|
+
# @raise [Trusona::ResourceNotFoundError] if the TruCode cannot be found
|
13
|
+
# @raise [Trusona::BadRequestError] if the request is improperly formatted
|
14
|
+
# @raise [Trusona::UnauthorizedRequestError] if the request is unauthorized.
|
15
|
+
# Typically the result of invalid or revoked Trusona SDK keys.
|
16
|
+
# @raise [Trusona::ApiError] if the Trusona API is experiencing problems.
|
17
|
+
# @raise [ArgumentError] if the TruCode id is missing
|
18
|
+
#
|
19
|
+
def self.find(id)
|
20
|
+
Trusona::Workers::TruCodeFinder.new.find(id)
|
21
|
+
end
|
22
|
+
|
23
|
+
##
|
24
|
+
# Finds a TruCode using its ID
|
25
|
+
#
|
26
|
+
# @param id [String] The id of the TruCode we're looking for
|
27
|
+
# @return [Trusona::Resources::TruCode] The found TruCode
|
28
|
+
# @raise (see .find)
|
29
|
+
#
|
30
|
+
def self.status(id)
|
31
|
+
Trusona::Workers::TruCodeStatus.new.status(id)
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.create(code)
|
35
|
+
Trusona::Workers::TruCodeCreator.new.create(code)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Trusona
|
4
|
+
##
|
5
|
+
#
|
6
|
+
class TruCodeConfig
|
7
|
+
def tru_code_url
|
8
|
+
"https://api.example.net/?relying_party_id=#{relying_party_id}"
|
9
|
+
end
|
10
|
+
|
11
|
+
def relying_party_id
|
12
|
+
jwt = Trusona.config.token ||
|
13
|
+
raise_token_error
|
14
|
+
middle = jwt_body(jwt)
|
15
|
+
decoded = Base64.decode64(middle)
|
16
|
+
parsed = parse_jwt(decoded)
|
17
|
+
relying_party_id = extract_subject(parsed)
|
18
|
+
|
19
|
+
relying_party_id
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def jwt_body(jwt)
|
25
|
+
split_jwt = jwt.split('.')
|
26
|
+
raise_token_error if split_jwt.empty? || split_jwt[1].nil?
|
27
|
+
split_jwt[1]
|
28
|
+
end
|
29
|
+
|
30
|
+
def parse_jwt(decoded)
|
31
|
+
JSON.parse(decoded)
|
32
|
+
rescue JSON::ParserError
|
33
|
+
raise_token_error('JWT Format is Invalid.')
|
34
|
+
end
|
35
|
+
|
36
|
+
def extract_subject(parsed)
|
37
|
+
raise_token_error('Subject is Missing.') if parsed['sub'].nil?
|
38
|
+
parsed['sub']
|
39
|
+
end
|
40
|
+
|
41
|
+
def raise_token_error(msg = 'API Token is missing.')
|
42
|
+
raise(Trusona::ConfigurationError, msg)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Trusona
|
4
|
+
##
|
5
|
+
# Defines a nice public api for interacting with Trusonafications
|
6
|
+
class Trusonafication
|
7
|
+
extend Trusona::Helpers::KeyNormalizer
|
8
|
+
|
9
|
+
##
|
10
|
+
# Finds existing Trusonafications using their ID
|
11
|
+
#
|
12
|
+
# @param trusonafication_id [String] the ID of an existing Trusonafication
|
13
|
+
# @return [Trusona::Resources::Trusonafication] The found Trusonafication
|
14
|
+
# @raise [Trusona::InvalidRecordIdentifier] if the +trusonafication_id+ is
|
15
|
+
# empty or nil.
|
16
|
+
# @raise [Trusona::ResourceNotFoundError] if the resource does not exist
|
17
|
+
# in the Trusona API
|
18
|
+
# @raise (see .create)
|
19
|
+
#
|
20
|
+
# @example
|
21
|
+
# Trusona::Trusonafication.find('602CB166-A6FC-4EBE-BE83-82E54CF5D161')
|
22
|
+
#
|
23
|
+
def self.find(trusonafication_id)
|
24
|
+
if trusonafication_id.nil? || trusonafication_id.empty?
|
25
|
+
raise Trusona::InvalidRecordIdentifier, 'Trusonafication ID is missing'
|
26
|
+
end
|
27
|
+
|
28
|
+
Trusona::Workers::TrusonaficationFinder.new.find(trusonafication_id)
|
29
|
+
end
|
30
|
+
|
31
|
+
##
|
32
|
+
# Creates a Trusonafication using the supplied options
|
33
|
+
#
|
34
|
+
# @param [Hash] params A list of options for creating the Trusonafication
|
35
|
+
# @option params [String] :action The action you want the user to take
|
36
|
+
# (e.g. 'login', 'verify')
|
37
|
+
# @option params [String] :resource The resource to which the user is
|
38
|
+
# performing the action (e.g. 'website', 'account')
|
39
|
+
# @option params [String] :device_identifier The device identifier,
|
40
|
+
# retrieved from the mobile SDK, of the device to which this
|
41
|
+
# Trusonafication will be sent.
|
42
|
+
# @option params [String] :user_identifier The user identifier,
|
43
|
+
# previously registered with Trusona, of the user to which this
|
44
|
+
# Trusonafication will be sent.
|
45
|
+
# @option params [String] :trucode_id The TruCode ID that has either been
|
46
|
+
# scanned or will be scanned using the mobile SDK that will be used to
|
47
|
+
# determine which device to send the Trusonafication to.
|
48
|
+
# @option params [Boolean] :user_presence (true) Should the user be required
|
49
|
+
# to demonstrate presence (e.g. via Biometric) when accepting this
|
50
|
+
# Trusonafication?
|
51
|
+
# @option params [Boolean] :prompt (true) Should the user be prompted to
|
52
|
+
# Accept or Reject this Trusonafication?
|
53
|
+
# @option params [String] :callback_url ('') A URL that will be called when
|
54
|
+
# the Trusonafication is completed.
|
55
|
+
# @option params [String] :expires_at ('90 seconds') The ISO-8601 UTC
|
56
|
+
# timestamp of the Trusonafication's expiration.
|
57
|
+
# @param timeout [Int] (30) The max amount of time, in seconds, to wait
|
58
|
+
# for a response from the Trusona API when polling for a Trusonafication
|
59
|
+
# result
|
60
|
+
# @yield [Trusona::Resources::Trusonafication] Yields the completed
|
61
|
+
# Trusonafication to the block
|
62
|
+
# @raise [Trusona::InvalidResourceError] if the resource is not +valid?+
|
63
|
+
# @see Trusona::Resources::BaseResource#valid?
|
64
|
+
# @raise [Trusona::BadRequestError] if the request is improperly formatted
|
65
|
+
# @raise [Trusona::UnauthorizedRequestError] if the request is unauthorized.
|
66
|
+
# Typically the result of invalid or revoked Trusona SDK keys.
|
67
|
+
# @raise [Trusona::ApiError] if the Trusona API is experiencing problems.
|
68
|
+
#
|
69
|
+
def self.create(params: {}, timeout: nil, &block)
|
70
|
+
normal = normalize_keys(params)
|
71
|
+
|
72
|
+
raise ArgumentError, 'Missing user identifier' unless
|
73
|
+
identifier_present?(normal)
|
74
|
+
|
75
|
+
raise ArgumentError, 'Missing action and resource' unless
|
76
|
+
normal[:action] && normal[:resource]
|
77
|
+
|
78
|
+
Trusona::Workers::TrusonaficationCreator.new.create(
|
79
|
+
params: normal,
|
80
|
+
timeout: timeout,
|
81
|
+
&block
|
82
|
+
)
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.identifier_present?(normalized_params)
|
86
|
+
normalized_params[:user_identifier] ||
|
87
|
+
normalized_params[:device_identifier] ||
|
88
|
+
normalized_params[:trucode_id] ||
|
89
|
+
normalized_params[:trusona_id]
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
##
|
94
|
+
# Creates Essential level Trusonafications. Syntactic sugar on top of
|
95
|
+
# {Trusona::Trusonafication}.
|
96
|
+
#
|
97
|
+
# @example
|
98
|
+
# Trusona::EssentialTrusonafication.create(params: {
|
99
|
+
# action: 'login',
|
100
|
+
# resource: 'Acme Bank',
|
101
|
+
# device_identifier: 'PBanKaajTmz_Cq1pDkrRzyeISBSBoGjExzp5r6-UjcI'
|
102
|
+
# })
|
103
|
+
#
|
104
|
+
# @see Trusona::Trusonafication.create
|
105
|
+
# @see Trusona::Trusonafication.find
|
106
|
+
#
|
107
|
+
class EssentialTrusonafication < Trusonafication
|
108
|
+
def self.create(params: {}, timeout: nil, &block)
|
109
|
+
level = params[:user_presence] == false ? 1 : 2
|
110
|
+
super(params: params.merge!(level: level), timeout: timeout, &block)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
##
|
115
|
+
# Creates Executive level Trusonafications. Syntactic sugar on top of
|
116
|
+
# {Trusona::Trusonafication}.
|
117
|
+
#
|
118
|
+
# @example
|
119
|
+
# Trusona::ExecutiveLevelTrusonafication.create(params: {
|
120
|
+
# action: 'login',
|
121
|
+
# resource: 'Acme Bank',
|
122
|
+
# device_identifier: 'PBanKaajTmz_Cq1pDkrRzyeISBSBoGjExzp5r6-UjcI'
|
123
|
+
# })
|
124
|
+
#
|
125
|
+
# @see Trusona::Trusonafication.create
|
126
|
+
# @see Trusona::Trusonafication.find
|
127
|
+
#
|
128
|
+
class ExecutiveTrusonafication < Trusonafication
|
129
|
+
def self.create(params: {}, timeout: nil, &block)
|
130
|
+
super(params: params.merge!(level: 3), timeout: timeout, &block)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Trusona
|
4
|
+
#
|
5
|
+
## Makes it easy to interface with the User and Accounts APIs
|
6
|
+
class UserAccounts
|
7
|
+
def self.find_by(opts = {})
|
8
|
+
raise ArgumentError unless
|
9
|
+
opts[:trusona_id] ||
|
10
|
+
opts[:email] ||
|
11
|
+
opts['trusona_id'] ||
|
12
|
+
opts['email']
|
13
|
+
|
14
|
+
Trusona::Workers::UserAccountFinder.new.find(opts)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Trusona
|
4
|
+
#
|
5
|
+
## Makes it easy to interface with the User Identifier APIs
|
6
|
+
class UserIdentifier
|
7
|
+
def self.find_by(opts = {})
|
8
|
+
Trusona::Workers::UserIdentifierFinder.new.find(opts)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.create(identifier)
|
12
|
+
Trusona::Workers::UserIdentifierCreator.new.create(identifier)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Trusona
|
4
|
+
module Workers
|
5
|
+
#
|
6
|
+
## Handles finding Devices
|
7
|
+
class DeviceFinder
|
8
|
+
def initialize(service: Trusona::Services::DevicesService.new)
|
9
|
+
@service = service
|
10
|
+
end
|
11
|
+
|
12
|
+
def find(id = nil)
|
13
|
+
raise(ArgumentError, 'A device identifier is required.') unless id
|
14
|
+
@service.get(Trusona::Resources::Device.new(id: id))
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Trusona
|
4
|
+
module Workers
|
5
|
+
#
|
6
|
+
## Activates Device and User binding records
|
7
|
+
class DeviceUserBindingActivator
|
8
|
+
def initialize(service: nil)
|
9
|
+
@service = service || Trusona::Services::DeviceUserBindingsService.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def activate(id: nil)
|
13
|
+
raise ArgumentError, 'Missing Device+User Binding Id' if
|
14
|
+
id.nil? || id.empty?
|
15
|
+
|
16
|
+
resource = Trusona::Resources::DeviceUserBindingActivation.new(
|
17
|
+
id: id,
|
18
|
+
active: true
|
19
|
+
)
|
20
|
+
|
21
|
+
@service.update(resource)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|