smart-id-ruby-client 0.1.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.
Files changed (86) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +14 -0
  4. data/CHANGELOG.md +13 -0
  5. data/CODE_OF_CONDUCT.md +132 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +436 -0
  8. data/Rakefile +12 -0
  9. data/lib/smart-id-ruby-client.rb +3 -0
  10. data/lib/smart_id_ruby/callback_url.rb +18 -0
  11. data/lib/smart_id_ruby/callback_url_util.rb +54 -0
  12. data/lib/smart_id_ruby/client.rb +124 -0
  13. data/lib/smart_id_ruby/configuration.rb +184 -0
  14. data/lib/smart_id_ruby/device_link_builder.rb +301 -0
  15. data/lib/smart_id_ruby/device_link_interaction.rb +67 -0
  16. data/lib/smart_id_ruby/errors/certificate_level_mismatch_error.rb +8 -0
  17. data/lib/smart_id_ruby/errors/document_unusable_error.rb +12 -0
  18. data/lib/smart_id_ruby/errors/error.rb +8 -0
  19. data/lib/smart_id_ruby/errors/expected_linked_session_error.rb +15 -0
  20. data/lib/smart_id_ruby/errors/no_suitable_account_of_requested_type_found_error.rb +10 -0
  21. data/lib/smart_id_ruby/errors/person_should_view_smart_id_portal_error.rb +8 -0
  22. data/lib/smart_id_ruby/errors/protocol_failure_error.rb +13 -0
  23. data/lib/smart_id_ruby/errors/relying_party_account_configuration_error.rb +10 -0
  24. data/lib/smart_id_ruby/errors/request_setup_error.rb +10 -0
  25. data/lib/smart_id_ruby/errors/request_validation_error.rb +8 -0
  26. data/lib/smart_id_ruby/errors/required_interaction_not_supported_by_app_error.rb +13 -0
  27. data/lib/smart_id_ruby/errors/response_error.rb +8 -0
  28. data/lib/smart_id_ruby/errors/server_maintenance_error.rb +8 -0
  29. data/lib/smart_id_ruby/errors/session_end_result_error.rb +15 -0
  30. data/lib/smart_id_ruby/errors/session_not_complete_error.rb +8 -0
  31. data/lib/smart_id_ruby/errors/session_not_found_error.rb +8 -0
  32. data/lib/smart_id_ruby/errors/session_secret_mismatch_error.rb +8 -0
  33. data/lib/smart_id_ruby/errors/session_timeout_error.rb +12 -0
  34. data/lib/smart_id_ruby/errors/smart_id_server_error.rb +12 -0
  35. data/lib/smart_id_ruby/errors/unprocessable_response_error.rb +9 -0
  36. data/lib/smart_id_ruby/errors/unsupported_client_api_version_error.rb +8 -0
  37. data/lib/smart_id_ruby/errors/user_account_not_found_error.rb +8 -0
  38. data/lib/smart_id_ruby/errors/user_account_unusable_error.rb +12 -0
  39. data/lib/smart_id_ruby/errors/user_refused_cert_choice_error.rb +14 -0
  40. data/lib/smart_id_ruby/errors/user_refused_confirmation_message_error.rb +13 -0
  41. data/lib/smart_id_ruby/errors/user_refused_confirmation_message_with_verification_choice_error.rb +13 -0
  42. data/lib/smart_id_ruby/errors/user_refused_display_text_and_pin_error.rb +13 -0
  43. data/lib/smart_id_ruby/errors/user_refused_error.rb +12 -0
  44. data/lib/smart_id_ruby/errors/user_selected_wrong_verification_code_error.rb +13 -0
  45. data/lib/smart_id_ruby/errors.rb +31 -0
  46. data/lib/smart_id_ruby/flows/base_builder.rb +90 -0
  47. data/lib/smart_id_ruby/flows/certificate_by_document_number_request_builder.rb +130 -0
  48. data/lib/smart_id_ruby/flows/device_link_authentication_session_request_builder.rb +208 -0
  49. data/lib/smart_id_ruby/flows/device_link_certificate_choice_session_request_builder.rb +112 -0
  50. data/lib/smart_id_ruby/flows/device_link_signature_session_request_builder.rb +286 -0
  51. data/lib/smart_id_ruby/flows/linked_notification_signature_session_request_builder.rb +235 -0
  52. data/lib/smart_id_ruby/flows/notification_authentication_session_request_builder.rb +184 -0
  53. data/lib/smart_id_ruby/flows/notification_certificate_choice_session_request_builder.rb +96 -0
  54. data/lib/smart_id_ruby/flows/notification_signature_session_request_builder.rb +272 -0
  55. data/lib/smart_id_ruby/models/authentication_identity.rb +19 -0
  56. data/lib/smart_id_ruby/models/authentication_response.rb +38 -0
  57. data/lib/smart_id_ruby/models/certificate_choice_response.rb +19 -0
  58. data/lib/smart_id_ruby/models/device_link_session_response.rb +34 -0
  59. data/lib/smart_id_ruby/models/notification_authentication_session_response.rb +25 -0
  60. data/lib/smart_id_ruby/models/notification_certificate_choice_session_response.rb +25 -0
  61. data/lib/smart_id_ruby/models/notification_signature_session_response.rb +29 -0
  62. data/lib/smart_id_ruby/models/session_status.rb +261 -0
  63. data/lib/smart_id_ruby/models/signature_response.rb +38 -0
  64. data/lib/smart_id_ruby/notification_interaction.rb +70 -0
  65. data/lib/smart_id_ruby/qr_code_generator.rb +65 -0
  66. data/lib/smart_id_ruby/rest/connector.rb +364 -0
  67. data/lib/smart_id_ruby/rest/session_status_poller.rb +125 -0
  68. data/lib/smart_id_ruby/rp_challenge.rb +37 -0
  69. data/lib/smart_id_ruby/rp_challenge_generator.rb +28 -0
  70. data/lib/smart_id_ruby/semantics_identifier.rb +35 -0
  71. data/lib/smart_id_ruby/validation/authentication_certificate_validator.rb +90 -0
  72. data/lib/smart_id_ruby/validation/authentication_identity_mapper.rb +227 -0
  73. data/lib/smart_id_ruby/validation/base_authentication_response_validator.rb +304 -0
  74. data/lib/smart_id_ruby/validation/certificate_choice_response_validator.rb +104 -0
  75. data/lib/smart_id_ruby/validation/certificate_validator.rb +170 -0
  76. data/lib/smart_id_ruby/validation/device_link_authentication_response_validator.rb +76 -0
  77. data/lib/smart_id_ruby/validation/error_result_handler.rb +88 -0
  78. data/lib/smart_id_ruby/validation/notification_authentication_response_validator.rb +16 -0
  79. data/lib/smart_id_ruby/validation/signature_payload_builder.rb +62 -0
  80. data/lib/smart_id_ruby/validation/signature_response_validator.rb +345 -0
  81. data/lib/smart_id_ruby/validation/signature_value_validator.rb +76 -0
  82. data/lib/smart_id_ruby/validation/trusted_ca_cert_store.rb +20 -0
  83. data/lib/smart_id_ruby/verification_code_calculator.rb +31 -0
  84. data/lib/smart_id_ruby/version.rb +5 -0
  85. data/lib/smart_id_ruby.rb +76 -0
  86. metadata +173 -0
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SmartIdRuby
4
+ module Flows
5
+ # Builds notification certificate choice session requests.
6
+ class NotificationCertificateChoiceSessionRequestBuilder < BaseBuilder
7
+ NONCE_MAX_LENGTH = 30
8
+
9
+ def initialize(connector)
10
+ super(connector)
11
+ @certificate_level = nil
12
+ @nonce = nil
13
+ @capabilities = nil
14
+ @share_md_client_ip_address = nil
15
+ @semantics_identifier = nil
16
+ end
17
+
18
+ def with_certificate_level(certificate_level)
19
+ @certificate_level = certificate_level
20
+ self
21
+ end
22
+
23
+ def with_nonce(nonce)
24
+ @nonce = nonce
25
+ self
26
+ end
27
+
28
+ def with_capabilities(*capabilities)
29
+ @capabilities = normalize_capabilities(capabilities)
30
+ self
31
+ end
32
+
33
+ def with_share_md_client_ip_address(share_md_client_ip_address)
34
+ @share_md_client_ip_address = share_md_client_ip_address
35
+ self
36
+ end
37
+
38
+ def with_semantics_identifier(semantics_identifier)
39
+ @semantics_identifier = semantics_identifier
40
+ self
41
+ end
42
+
43
+ def init_certificate_choice
44
+ validate_request_parameters
45
+ request = create_certificate_choice_request
46
+ response = init_certificate_choice_session(request)
47
+ validate_response_parameters(response)
48
+ SmartIdRuby::Models::NotificationCertificateChoiceSessionResponse.from_h(response)
49
+ end
50
+
51
+ private
52
+
53
+ def init_certificate_choice_session(request)
54
+ if @semantics_identifier.nil?
55
+ raise SmartIdRuby::Errors::RequestSetupError, "Value for 'semanticIdentifier' must be set"
56
+ end
57
+
58
+ connector.init_notification_certificate_choice(request, @semantics_identifier)
59
+ end
60
+
61
+ def validate_request_parameters
62
+ if blank?(relying_party_uuid)
63
+ raise SmartIdRuby::Errors::RequestSetupError, "Value for 'relyingPartyUUID' cannot be empty"
64
+ end
65
+ if blank?(relying_party_name)
66
+ raise SmartIdRuby::Errors::RequestSetupError, "Value for 'relyingPartyName' cannot be empty"
67
+ end
68
+ if !@nonce.nil? && (@nonce.empty? || @nonce.length > NONCE_MAX_LENGTH)
69
+ raise SmartIdRuby::Errors::RequestSetupError, "Value for 'nonce' length must be between 1 and 30 characters"
70
+ end
71
+ end
72
+
73
+ def create_certificate_choice_request
74
+ {
75
+ relyingPartyUUID: relying_party_uuid,
76
+ relyingPartyName: relying_party_name,
77
+ certificateLevel: @certificate_level&.to_s,
78
+ nonce: @nonce,
79
+ capabilities: @capabilities,
80
+ requestProperties: request_properties
81
+ }.compact
82
+ end
83
+
84
+ def request_properties
85
+ request_properties_for_share_md(@share_md_client_ip_address)
86
+ end
87
+
88
+ def validate_response_parameters(response)
89
+ return unless blank?(fetch_value(response, :sessionID))
90
+
91
+ raise SmartIdRuby::Errors::UnprocessableResponseError,
92
+ "Notification-based certificate choice response field 'sessionID' is missing or empty"
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,272 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "base64"
4
+ require "openssl"
5
+
6
+ module SmartIdRuby
7
+ module Flows
8
+ # Builds notification signature session requests.
9
+ class NotificationSignatureSessionRequestBuilder < BaseBuilder
10
+ VERIFICATION_CODE_PATTERN = /\A[0-9]{4}\z/
11
+ NONCE_MAX_LENGTH = 30
12
+ DEFAULT_HASH_ALGORITHM = "SHA-512"
13
+ SUPPORTED_VC_TYPE = "numeric4"
14
+
15
+ def initialize(connector)
16
+ super(connector)
17
+ @document_number = nil
18
+ @semantics_identifier = nil
19
+ @certificate_level = nil
20
+ @nonce = nil
21
+ @capabilities = nil
22
+ @interactions = nil
23
+ @share_md_client_ip_address = nil
24
+ @signature_algorithm = "rsassa-pss"
25
+ @digest_input = nil
26
+ end
27
+
28
+ def with_document_number(document_number)
29
+ @document_number = document_number
30
+ self
31
+ end
32
+
33
+ def with_semantics_identifier(semantics_identifier)
34
+ @semantics_identifier = semantics_identifier
35
+ self
36
+ end
37
+
38
+ def with_certificate_level(certificate_level)
39
+ @certificate_level = certificate_level
40
+ self
41
+ end
42
+
43
+ def with_nonce(nonce)
44
+ @nonce = nonce
45
+ self
46
+ end
47
+
48
+ def with_capabilities(*capabilities)
49
+ @capabilities = normalize_capabilities(capabilities)
50
+ self
51
+ end
52
+
53
+ def with_interactions(interactions)
54
+ @interactions = interactions
55
+ self
56
+ end
57
+
58
+ def with_share_md_client_ip_address(share_md_client_ip_address)
59
+ @share_md_client_ip_address = share_md_client_ip_address
60
+ self
61
+ end
62
+
63
+ def with_signature_algorithm(signature_algorithm)
64
+ @signature_algorithm = signature_algorithm
65
+ self
66
+ end
67
+
68
+ def with_signable_data(signable_data)
69
+ if digest_input_kind == :signable_hash
70
+ raise SmartIdRuby::Errors::RequestSetupError, "Value for 'digestInput' has already been set with SignableHash"
71
+ end
72
+
73
+ @digest_input = build_signable_data_digest_input(signable_data)
74
+ self
75
+ end
76
+
77
+ def with_signable_hash(signable_hash)
78
+ if digest_input_kind == :signable_data
79
+ raise SmartIdRuby::Errors::RequestSetupError, "Value for 'digestInput' has already been set with SignableData"
80
+ end
81
+
82
+ @digest_input = build_signable_hash_digest_input(signable_hash)
83
+ self
84
+ end
85
+
86
+ def init_signature_session
87
+ validate_request_parameters
88
+ request = create_signature_session_request
89
+ response = init_session(request)
90
+ validate_response_parameters(response)
91
+ SmartIdRuby::Models::NotificationSignatureSessionResponse.from_h(response)
92
+ end
93
+
94
+ private
95
+
96
+ def init_session(request)
97
+ if @semantics_identifier && @document_number
98
+ raise SmartIdRuby::Errors::RequestSetupError, "Only one of 'semanticsIdentifier' or 'documentNumber' may be set"
99
+ end
100
+
101
+ if @document_number
102
+ connector.init_notification_signature_with_document(request, @document_number)
103
+ elsif @semantics_identifier
104
+ connector.init_notification_signature(request, @semantics_identifier)
105
+ else
106
+ raise SmartIdRuby::Errors::RequestSetupError, "Either 'documentNumber' or 'semanticsIdentifier' must be set"
107
+ end
108
+ end
109
+
110
+ def create_signature_session_request
111
+ {
112
+ relyingPartyUUID: relying_party_uuid,
113
+ relyingPartyName: relying_party_name,
114
+ certificateLevel: @certificate_level&.to_s,
115
+ signatureProtocol: "RAW_DIGEST_SIGNATURE",
116
+ signatureProtocolParameters: {
117
+ digest: @digest_input[:digest],
118
+ signatureAlgorithm: @signature_algorithm.to_s,
119
+ signatureAlgorithmParameters: {
120
+ hashAlgorithm: @digest_input[:hash_algorithm].to_s
121
+ }
122
+ },
123
+ nonce: @nonce,
124
+ capabilities: @capabilities,
125
+ interactions: encode_interactions(@interactions),
126
+ requestProperties: request_properties
127
+ }.compact
128
+ end
129
+
130
+ def validate_request_parameters
131
+ if blank?(relying_party_uuid)
132
+ raise SmartIdRuby::Errors::RequestSetupError, "Value for 'relyingPartyUUID' cannot be empty"
133
+ end
134
+ if blank?(relying_party_name)
135
+ raise SmartIdRuby::Errors::RequestSetupError, "Value for 'relyingPartyName' cannot be empty"
136
+ end
137
+ if @signature_algorithm.nil?
138
+ raise SmartIdRuby::Errors::RequestSetupError, "Value for 'signatureAlgorithm' must be set"
139
+ end
140
+ if @digest_input.nil?
141
+ raise SmartIdRuby::Errors::RequestSetupError, "Value for 'digestInput' must be set with either SignableData or SignableHash"
142
+ end
143
+
144
+ validate_interactions
145
+ validate_nonce
146
+ end
147
+
148
+ def validate_interactions
149
+ normalized_interactions = normalize_interactions(@interactions)
150
+ if normalized_interactions.empty?
151
+ raise SmartIdRuby::Errors::RequestSetupError, "Value for 'interactions' cannot be empty"
152
+ end
153
+
154
+ interaction_types = normalized_interactions.map { |interaction| interaction[:type] }
155
+ if interaction_types.uniq.length != interaction_types.length
156
+ raise SmartIdRuby::Errors::RequestSetupError, "Value for 'interactions' cannot contain duplicate types"
157
+ end
158
+ end
159
+
160
+ def validate_nonce
161
+ return if @nonce.nil?
162
+ return if @nonce.length.between?(1, NONCE_MAX_LENGTH)
163
+
164
+ raise SmartIdRuby::Errors::RequestSetupError, "Value for 'nonce' length must be between 1 and 30 characters"
165
+ end
166
+
167
+ def validate_response_parameters(response)
168
+ if blank?(fetch_value(response, :sessionID))
169
+ raise SmartIdRuby::Errors::UnprocessableResponseError,
170
+ "Notification-based signature response field 'sessionID' is missing or empty"
171
+ end
172
+
173
+ verification_code = fetch_value(response, :vc)
174
+ if verification_code.nil?
175
+ raise SmartIdRuby::Errors::UnprocessableResponseError, "Notification-based signature response field 'vc' is missing"
176
+ end
177
+
178
+ vc_type = fetch_value(verification_code, :type)
179
+ if blank?(vc_type)
180
+ raise SmartIdRuby::Errors::UnprocessableResponseError,
181
+ "Notification-based signature response field 'vc.type' is missing or empty"
182
+ end
183
+ unless vc_type == SUPPORTED_VC_TYPE
184
+ raise SmartIdRuby::Errors::UnprocessableResponseError,
185
+ "Notification-based signature response field 'vc.type' contains unsupported value"
186
+ end
187
+
188
+ vc_value = fetch_value(verification_code, :value)
189
+ if blank?(vc_value)
190
+ raise SmartIdRuby::Errors::UnprocessableResponseError,
191
+ "Notification-based signature response field 'vc.value' is missing or empty"
192
+ end
193
+ return if VERIFICATION_CODE_PATTERN.match?(vc_value.to_s)
194
+
195
+ raise SmartIdRuby::Errors::UnprocessableResponseError,
196
+ "Notification-based signature response field 'vc.value' does not match the required pattern"
197
+ end
198
+
199
+ def request_properties
200
+ request_properties_for_share_md(@share_md_client_ip_address)
201
+ end
202
+
203
+ def build_signable_data_digest_input(signable_data)
204
+ return nil if signable_data.nil?
205
+
206
+ data_to_sign, hash_algorithm = extract_signable_data(signable_data)
207
+ data = normalize_binary_input(data_to_sign)
208
+ algorithm_name = normalize_hash_algorithm(hash_algorithm)
209
+
210
+ digest = OpenSSL::Digest.new(openssl_algorithm_name(algorithm_name)).digest(data)
211
+ { kind: :signable_data, digest: Base64.strict_encode64(digest), hash_algorithm: algorithm_name }
212
+ end
213
+
214
+ def build_signable_hash_digest_input(signable_hash)
215
+ return nil if signable_hash.nil?
216
+
217
+ hash_to_sign, hash_algorithm = extract_signable_hash(signable_hash)
218
+ hash_bytes = normalize_binary_input(hash_to_sign)
219
+ algorithm_name = normalize_hash_algorithm(hash_algorithm)
220
+
221
+ { kind: :signable_hash, digest: Base64.strict_encode64(hash_bytes), hash_algorithm: algorithm_name }
222
+ end
223
+
224
+ def extract_signable_data(input)
225
+ if input.respond_to?(:to_h)
226
+ normalized = input.to_h.transform_keys(&:to_sym)
227
+ [normalized[:data_to_sign] || normalized[:data], normalized[:hash_algorithm]]
228
+ elsif input.respond_to?(:data_to_sign)
229
+ [input.data_to_sign, input.respond_to?(:hash_algorithm) ? input.hash_algorithm : nil]
230
+ else
231
+ [input, nil]
232
+ end
233
+ end
234
+
235
+ def extract_signable_hash(input)
236
+ if input.respond_to?(:to_h)
237
+ normalized = input.to_h.transform_keys(&:to_sym)
238
+ [normalized[:hash_to_sign] || normalized[:hash] || normalized[:digest], normalized[:hash_algorithm]]
239
+ elsif input.respond_to?(:hash_to_sign)
240
+ [input.hash_to_sign, input.respond_to?(:hash_algorithm) ? input.hash_algorithm : nil]
241
+ else
242
+ [input, nil]
243
+ end
244
+ end
245
+
246
+ def normalize_binary_input(input)
247
+ data = input.is_a?(String) ? input.dup : input
248
+ data = data.pack("C*") if data.is_a?(Array) && data.all? { |value| value.is_a?(Integer) && value.between?(0, 255) }
249
+ if data.nil? || data.to_s.bytesize.zero?
250
+ raise SmartIdRuby::Errors::RequestSetupError, "Value for 'digestInput' must be set with either SignableData or SignableHash"
251
+ end
252
+
253
+ data
254
+ end
255
+
256
+ def normalize_hash_algorithm(hash_algorithm)
257
+ value = hash_algorithm&.to_s
258
+ return DEFAULT_HASH_ALGORITHM if blank?(value)
259
+
260
+ value
261
+ end
262
+
263
+ def openssl_algorithm_name(hash_algorithm)
264
+ hash_algorithm.to_s.delete("-")
265
+ end
266
+
267
+ def digest_input_kind
268
+ @digest_input && @digest_input[:kind]
269
+ end
270
+ end
271
+ end
272
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SmartIdRuby
4
+ module Models
5
+ # Represents mapped identity details from authentication certificate.
6
+ class AuthenticationIdentity
7
+ attr_reader :given_name, :surname, :identity_number, :country, :auth_certificate, :date_of_birth
8
+
9
+ def initialize(given_name: nil, surname: nil, identity_number: nil, country: nil, auth_certificate: nil, date_of_birth: nil)
10
+ @given_name = given_name
11
+ @surname = surname
12
+ @identity_number = identity_number
13
+ @country = country
14
+ @auth_certificate = auth_certificate
15
+ @date_of_birth = date_of_birth
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SmartIdRuby
4
+ module Models
5
+ # Represents validated authentication response data.
6
+ class AuthenticationResponse
7
+ attr_reader :end_result, :document_number, :signature_value_base64, :server_random,
8
+ :user_challenge, :flow_type, :signature_algorithm, :certificate_value,
9
+ :certificate_level, :interaction_type_used, :device_ip_address
10
+
11
+ def initialize(
12
+ end_result:,
13
+ document_number:,
14
+ signature_value_base64:,
15
+ server_random:,
16
+ user_challenge:,
17
+ flow_type:,
18
+ signature_algorithm:,
19
+ certificate_value:,
20
+ certificate_level:,
21
+ interaction_type_used:,
22
+ device_ip_address:
23
+ )
24
+ @end_result = end_result
25
+ @document_number = document_number
26
+ @signature_value_base64 = signature_value_base64
27
+ @server_random = server_random
28
+ @user_challenge = user_challenge
29
+ @flow_type = flow_type
30
+ @signature_algorithm = signature_algorithm
31
+ @certificate_value = certificate_value
32
+ @certificate_level = certificate_level
33
+ @interaction_type_used = interaction_type_used
34
+ @device_ip_address = device_ip_address
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SmartIdRuby
4
+ module Models
5
+ # Represents validated certificate choice response data.
6
+ class CertificateChoiceResponse
7
+ attr_reader :end_result, :certificate, :certificate_level, :document_number, :interaction_flow_used, :device_ip_address
8
+
9
+ def initialize(end_result:, certificate:, certificate_level:, document_number:, interaction_flow_used:, device_ip_address:)
10
+ @end_result = end_result
11
+ @certificate = certificate
12
+ @certificate_level = certificate_level
13
+ @document_number = document_number
14
+ @interaction_flow_used = interaction_flow_used
15
+ @device_ip_address = device_ip_address
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SmartIdRuby
4
+ module Models
5
+ # Represents device-link session initialization response.
6
+ class DeviceLinkSessionResponse
7
+ attr_reader :session_id, :session_token, :session_secret, :device_link_base, :received_at
8
+
9
+ def initialize(session_id:, session_token:, session_secret:, device_link_base:, received_at: Time.now)
10
+ @session_id = session_id
11
+ @session_token = session_token
12
+ @session_secret = session_secret
13
+ @device_link_base = device_link_base
14
+ @received_at = received_at
15
+ end
16
+
17
+ def self.from_h(payload)
18
+ return payload if payload.is_a?(self)
19
+ return new(session_id: nil, session_token: nil, session_secret: nil, device_link_base: nil) unless payload.is_a?(Hash)
20
+
21
+ new(
22
+ session_id: fetch(payload, :sessionID),
23
+ session_token: fetch(payload, :sessionToken),
24
+ session_secret: fetch(payload, :sessionSecret),
25
+ device_link_base: fetch(payload, :deviceLinkBase)
26
+ )
27
+ end
28
+
29
+ def self.fetch(payload, key)
30
+ payload[key] || payload[key.to_s]
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SmartIdRuby
4
+ module Models
5
+ # Represents notification-based authentication session initialization response.
6
+ class NotificationAuthenticationSessionResponse
7
+ attr_reader :session_id
8
+
9
+ def initialize(session_id:)
10
+ @session_id = session_id
11
+ end
12
+
13
+ def self.from_h(payload)
14
+ return payload if payload.is_a?(self)
15
+ return new(session_id: nil) unless payload.is_a?(Hash)
16
+
17
+ new(session_id: fetch(payload, :sessionID))
18
+ end
19
+
20
+ def self.fetch(payload, key)
21
+ payload[key] || payload[key.to_s]
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SmartIdRuby
4
+ module Models
5
+ # Represents notification-based certificate choice session initialization response.
6
+ class NotificationCertificateChoiceSessionResponse
7
+ attr_reader :session_id
8
+
9
+ def initialize(session_id:)
10
+ @session_id = session_id
11
+ end
12
+
13
+ def self.from_h(payload)
14
+ return payload if payload.is_a?(self)
15
+ return new(session_id: nil) unless payload.is_a?(Hash)
16
+
17
+ new(session_id: fetch(payload, :sessionID))
18
+ end
19
+
20
+ def self.fetch(payload, key)
21
+ payload[key] || payload[key.to_s]
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SmartIdRuby
4
+ module Models
5
+ # Represents notification-based signature session initialization response.
6
+ class NotificationSignatureSessionResponse
7
+ attr_reader :session_id, :vc
8
+
9
+ def initialize(session_id:, vc:)
10
+ @session_id = session_id
11
+ @vc = vc
12
+ end
13
+
14
+ def self.from_h(payload)
15
+ return payload if payload.is_a?(self)
16
+ return new(session_id: nil, vc: nil) unless payload.is_a?(Hash)
17
+
18
+ new(
19
+ session_id: fetch(payload, :sessionID),
20
+ vc: fetch(payload, :vc)
21
+ )
22
+ end
23
+
24
+ def self.fetch(payload, key)
25
+ payload[key] || payload[key.to_s]
26
+ end
27
+ end
28
+ end
29
+ end