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,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "base64"
4
+ require "openssl"
5
+
6
+ module SmartIdRuby
7
+ module Flows
8
+ # Builds certificate by document number requests.
9
+ class CertificateByDocumentNumberRequestBuilder < BaseBuilder
10
+ BASE64_PATTERN = /\A[A-Za-z0-9+\/]+={0,2}\z/
11
+ SUPPORTED_STATES = %w[OK DOCUMENT_UNUSABLE].freeze
12
+ CERTIFICATE_LEVEL_ORDER = {
13
+ "ADVANCED" => 1,
14
+ "QUALIFIED" => 2,
15
+ "QSCD" => 2
16
+ }.freeze
17
+ DEFAULT_CERTIFICATE_LEVEL = "QUALIFIED"
18
+
19
+ def initialize(connector)
20
+ super(connector)
21
+ @document_number = nil
22
+ @certificate_level = DEFAULT_CERTIFICATE_LEVEL
23
+ end
24
+
25
+ def with_document_number(document_number)
26
+ @document_number = document_number
27
+ self
28
+ end
29
+
30
+ def with_certificate_level(certificate_level)
31
+ @certificate_level = certificate_level
32
+ self
33
+ end
34
+
35
+ def get_certificate_by_document_number
36
+ validate_request_parameters
37
+ request = create_request
38
+ response = connector.get_certificate_by_document_number(@document_number, request)
39
+ validate_response_parameters(response)
40
+
41
+ cert = fetch_value(response, :cert)
42
+ cert_level = fetch_value(cert, :certificateLevel).to_s
43
+ cert_value = fetch_value(cert, :value).to_s
44
+ {
45
+ certificate_level: cert_level,
46
+ certificate: OpenSSL::X509::Certificate.new(Base64.strict_decode64(cert_value))
47
+ }
48
+ end
49
+
50
+ private
51
+
52
+ def create_request
53
+ {
54
+ relyingPartyUUID: relying_party_uuid,
55
+ relyingPartyName: relying_party_name,
56
+ certificateLevel: @certificate_level&.to_s
57
+ }.compact
58
+ end
59
+
60
+ def validate_request_parameters
61
+ if blank?(@document_number)
62
+ raise SmartIdRuby::Errors::RequestSetupError, "Value for 'documentNumber' cannot be empty"
63
+ end
64
+ if blank?(relying_party_uuid)
65
+ raise SmartIdRuby::Errors::RequestSetupError, "Value for 'relyingPartyUUID' cannot be empty"
66
+ end
67
+ if blank?(relying_party_name)
68
+ raise SmartIdRuby::Errors::RequestSetupError, "Value for 'relyingPartyName' cannot be empty"
69
+ end
70
+ end
71
+
72
+ def validate_response_parameters(response)
73
+ if response.nil?
74
+ raise SmartIdRuby::Errors::UnprocessableResponseError, "Queried certificate response is not provided"
75
+ end
76
+
77
+ validate_state(response)
78
+ cert = fetch_value(response, :cert)
79
+ if cert.nil?
80
+ raise SmartIdRuby::Errors::UnprocessableResponseError, "Queried certificate response field 'cert' is missing"
81
+ end
82
+
83
+ validate_certificate_level(cert)
84
+ validate_certificate_value(cert)
85
+ end
86
+
87
+ def validate_state(response)
88
+ state = fetch_value(response, :state)
89
+ if blank?(state)
90
+ raise SmartIdRuby::Errors::UnprocessableResponseError, "Queried certificate response field 'state' is missing"
91
+ end
92
+ unless SUPPORTED_STATES.include?(state)
93
+ raise SmartIdRuby::Errors::UnprocessableResponseError, "Queried certificate response field 'state' has unsupported value"
94
+ end
95
+ if state == "DOCUMENT_UNUSABLE"
96
+ raise SmartIdRuby::Errors::DocumentUnusableError
97
+ end
98
+ end
99
+
100
+ def validate_certificate_level(cert)
101
+ response_level = fetch_value(cert, :certificateLevel)
102
+ if blank?(response_level)
103
+ raise SmartIdRuby::Errors::UnprocessableResponseError, "Queried certificate response field 'cert.certificateLevel' is missing"
104
+ end
105
+
106
+ unless CERTIFICATE_LEVEL_ORDER.key?(response_level)
107
+ raise SmartIdRuby::Errors::UnprocessableResponseError,
108
+ "Queried certificate response field 'cert.certificateLevel' has unsupported value"
109
+ end
110
+
111
+ requested_level = @certificate_level.nil? ? DEFAULT_CERTIFICATE_LEVEL : @certificate_level.to_s
112
+ if CERTIFICATE_LEVEL_ORDER[response_level] < CERTIFICATE_LEVEL_ORDER.fetch(requested_level, CERTIFICATE_LEVEL_ORDER[DEFAULT_CERTIFICATE_LEVEL])
113
+ raise SmartIdRuby::Errors::UnprocessableResponseError, "Queried certificate has lower level than requested"
114
+ end
115
+ end
116
+
117
+ def validate_certificate_value(cert)
118
+ cert_value = fetch_value(cert, :value)
119
+ if blank?(cert_value)
120
+ raise SmartIdRuby::Errors::UnprocessableResponseError, "Queried certificate response field 'cert.value' is missing"
121
+ end
122
+
123
+ return if BASE64_PATTERN.match?(cert_value)
124
+
125
+ raise SmartIdRuby::Errors::UnprocessableResponseError,
126
+ "Queried certificate response field 'cert.value' does not have Base64-encoded value"
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,208 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "base64"
4
+
5
+ module SmartIdRuby
6
+ module Flows
7
+ # Builds device link authentication session requests.
8
+ class DeviceLinkAuthenticationSessionRequestBuilder < BaseBuilder
9
+ INITIAL_CALLBACK_URL_PATTERN = %r{\Ahttps://[^|]+\z}
10
+ RP_CHALLENGE_MIN_LENGTH = 44
11
+ RP_CHALLENGE_MAX_LENGTH = 88
12
+
13
+ attr_reader :authentication_session_request
14
+
15
+ def initialize(connector)
16
+ super(connector)
17
+ @certificate_level = "QUALIFIED"
18
+ @signature_algorithm = "rsassa-pss"
19
+ @hash_algorithm = "SHA3-512"
20
+ @interactions = nil
21
+ @share_md_client_ip_address = nil
22
+ @capabilities = nil
23
+ @semantics_identifier = nil
24
+ @document_number = nil
25
+ @initial_callback_url = nil
26
+ @rp_challenge = nil
27
+ end
28
+
29
+ def with_certificate_level(certificate_level)
30
+ @certificate_level = certificate_level
31
+ self
32
+ end
33
+
34
+ def with_rp_challenge(rp_challenge)
35
+ @rp_challenge = rp_challenge
36
+ self
37
+ end
38
+
39
+ def with_signature_algorithm(signature_algorithm)
40
+ @signature_algorithm = signature_algorithm
41
+ self
42
+ end
43
+
44
+ def with_hash_algorithm(hash_algorithm)
45
+ @hash_algorithm = hash_algorithm
46
+ self
47
+ end
48
+
49
+ def with_interactions(interactions)
50
+ @interactions = interactions
51
+ self
52
+ end
53
+
54
+ def with_share_md_client_ip_address(share_md_client_ip_address)
55
+ @share_md_client_ip_address = share_md_client_ip_address
56
+ self
57
+ end
58
+
59
+ def with_capabilities(*capabilities)
60
+ @capabilities = normalize_capabilities(capabilities, strip: false, reject_empty: false)
61
+ self
62
+ end
63
+
64
+ def with_semantics_identifier(semantics_identifier)
65
+ @semantics_identifier = semantics_identifier
66
+ self
67
+ end
68
+
69
+ def with_document_number(document_number)
70
+ @document_number = document_number
71
+ self
72
+ end
73
+
74
+ def with_initial_callback_url(initial_callback_url)
75
+ @initial_callback_url = initial_callback_url
76
+ self
77
+ end
78
+
79
+ def init_authentication_session
80
+ validate_request_parameters
81
+ request = create_authentication_request
82
+ response = init_session(request)
83
+ validate_response_parameters(response)
84
+ @authentication_session_request = request
85
+
86
+ SmartIdRuby::Models::DeviceLinkSessionResponse.from_h(response)
87
+ end
88
+
89
+ private
90
+
91
+ def init_session(request)
92
+ if @semantics_identifier && @document_number
93
+ raise SmartIdRuby::Errors::RequestSetupError, "Only one of 'semanticsIdentifier' or 'documentNumber' may be set"
94
+ end
95
+
96
+ if @semantics_identifier
97
+ connector.init_device_link_authentication(request, @semantics_identifier)
98
+ elsif @document_number
99
+ connector.init_device_link_authentication_with_document(request, @document_number)
100
+ else
101
+ connector.init_anonymous_device_link_authentication(request)
102
+ end
103
+ end
104
+
105
+ def validate_request_parameters
106
+ if blank?(relying_party_uuid)
107
+ raise SmartIdRuby::Errors::RequestSetupError, "Value for 'relyingPartyUUID' cannot be empty"
108
+ end
109
+ if blank?(relying_party_name)
110
+ raise SmartIdRuby::Errors::RequestSetupError, "Value for 'relyingPartyName' cannot be empty"
111
+ end
112
+
113
+ validate_signature_parameters
114
+ validate_interactions
115
+ validate_initial_callback_url
116
+ end
117
+
118
+ def validate_signature_parameters
119
+ raise SmartIdRuby::Errors::RequestSetupError, "Value for 'rpChallenge' cannot be empty" if blank?(@rp_challenge)
120
+
121
+ begin
122
+ Base64.strict_decode64(@rp_challenge)
123
+ rescue ArgumentError
124
+ raise SmartIdRuby::Errors::RequestSetupError, "Value for 'rpChallenge' must be Base64-encoded string"
125
+ end
126
+
127
+ unless @rp_challenge.length.between?(RP_CHALLENGE_MIN_LENGTH, RP_CHALLENGE_MAX_LENGTH)
128
+ raise SmartIdRuby::Errors::RequestSetupError,
129
+ "Value for 'rpChallenge' must have length between #{RP_CHALLENGE_MIN_LENGTH} and #{RP_CHALLENGE_MAX_LENGTH} characters"
130
+ end
131
+ if @signature_algorithm.nil?
132
+ raise SmartIdRuby::Errors::RequestSetupError, "Value for 'signatureAlgorithm' must be set"
133
+ end
134
+
135
+ if @hash_algorithm.nil?
136
+ raise SmartIdRuby::Errors::RequestSetupError, "Value for 'hashAlgorithm' must be set"
137
+ end
138
+ end
139
+
140
+ def validate_interactions
141
+ normalized_interactions = normalize_interactions(@interactions)
142
+ if normalized_interactions.empty?
143
+ raise SmartIdRuby::Errors::RequestSetupError, "Value for 'interactions' cannot be empty"
144
+ end
145
+
146
+ interaction_types = normalized_interactions.map { |interaction| interaction[:type] }
147
+ if interaction_types.any?(&:nil?)
148
+ raise SmartIdRuby::Errors::RequestSetupError, "Each interaction must include a 'type' value"
149
+ end
150
+
151
+ if interaction_types.uniq.length != interaction_types.length
152
+ raise SmartIdRuby::Errors::RequestSetupError, "Value for 'interactions' cannot contain duplicate types"
153
+ end
154
+ end
155
+
156
+ def validate_initial_callback_url
157
+ return if blank?(@initial_callback_url)
158
+ return if INITIAL_CALLBACK_URL_PATTERN.match?(@initial_callback_url)
159
+
160
+ raise SmartIdRuby::Errors::RequestSetupError,
161
+ "Value for 'initialCallbackUrl' must match pattern ^https://[^|]+$ and must not contain unencoded vertical bars"
162
+ end
163
+
164
+ def create_authentication_request
165
+ {
166
+ relyingPartyUUID: relying_party_uuid,
167
+ relyingPartyName: relying_party_name,
168
+ certificateLevel: @certificate_level&.to_s,
169
+ signatureProtocol: "ACSP_V2",
170
+ signatureProtocolParameters: {
171
+ rpChallenge: @rp_challenge,
172
+ signatureAlgorithm: @signature_algorithm.to_s,
173
+ signatureAlgorithmParameters: {
174
+ hashAlgorithm: @hash_algorithm.to_s
175
+ }
176
+ },
177
+ interactions: encode_interactions(@interactions),
178
+ requestProperties: request_properties,
179
+ capabilities: @capabilities,
180
+ initialCallbackUrl: @initial_callback_url
181
+ }.compact
182
+ end
183
+
184
+ def request_properties
185
+ request_properties_for_share_md(@share_md_client_ip_address)
186
+ end
187
+
188
+ def validate_response_parameters(response)
189
+ if blank?(fetch_value(response, :sessionID))
190
+ raise SmartIdRuby::Errors::UnprocessableResponseError,
191
+ "Device link authentication session initialisation response field 'sessionID' is missing or empty"
192
+ end
193
+ if blank?(fetch_value(response, :sessionToken))
194
+ raise SmartIdRuby::Errors::UnprocessableResponseError,
195
+ "Device link authentication session initialisation response field 'sessionToken' is missing or empty"
196
+ end
197
+ if blank?(fetch_value(response, :sessionSecret))
198
+ raise SmartIdRuby::Errors::UnprocessableResponseError,
199
+ "Device link authentication session initialisation response field 'sessionSecret' is missing or empty"
200
+ end
201
+ if blank?(fetch_value(response, :deviceLinkBase))
202
+ raise SmartIdRuby::Errors::UnprocessableResponseError,
203
+ "Device link authentication session initialisation response field 'deviceLinkBase' is missing or empty"
204
+ end
205
+ end
206
+ end
207
+ end
208
+ end
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SmartIdRuby
4
+ module Flows
5
+ # Builds device link certificate choice session requests.
6
+ class DeviceLinkCertificateChoiceSessionRequestBuilder < BaseBuilder
7
+ INITIAL_CALLBACK_URL_PATTERN = %r{\Ahttps://[^|]+\z}
8
+ NONCE_MAX_LENGTH = 30
9
+
10
+ def initialize(connector)
11
+ super(connector)
12
+ @certificate_level = nil
13
+ @nonce = nil
14
+ @capabilities = nil
15
+ @share_md_client_ip_address = nil
16
+ @initial_callback_url = nil
17
+ end
18
+
19
+ def with_certificate_level(certificate_level)
20
+ @certificate_level = certificate_level
21
+ self
22
+ end
23
+
24
+ def with_nonce(nonce)
25
+ @nonce = nonce
26
+ self
27
+ end
28
+
29
+ def with_capabilities(*capabilities)
30
+ @capabilities = normalize_capabilities(capabilities)
31
+ self
32
+ end
33
+
34
+ def with_share_md_client_ip_address(share_md_client_ip_address)
35
+ @share_md_client_ip_address = share_md_client_ip_address
36
+ self
37
+ end
38
+
39
+ def with_initial_callback_url(initial_callback_url)
40
+ @initial_callback_url = initial_callback_url
41
+ self
42
+ end
43
+
44
+ def init_certificate_choice
45
+ validate_request_parameters
46
+ request = create_certificate_request
47
+ response = connector.init_device_link_certificate_choice(request)
48
+ validate_response_parameters(response)
49
+ SmartIdRuby::Models::DeviceLinkSessionResponse.from_h(response)
50
+ end
51
+
52
+ private
53
+
54
+ def validate_request_parameters
55
+ if blank?(relying_party_uuid)
56
+ raise SmartIdRuby::Errors::RequestSetupError, "Value for 'relyingPartyUUID' cannot be empty"
57
+ end
58
+ if blank?(relying_party_name)
59
+ raise SmartIdRuby::Errors::RequestSetupError, "Value for 'relyingPartyName' cannot be empty"
60
+ end
61
+ if !@nonce.nil? && (@nonce.empty? || @nonce.length > NONCE_MAX_LENGTH)
62
+ raise SmartIdRuby::Errors::RequestSetupError, "Value for 'nonce' must have length between 1 and 30 characters"
63
+ end
64
+
65
+ validate_initial_callback_url
66
+ end
67
+
68
+ def create_certificate_request
69
+ {
70
+ relyingPartyUUID: relying_party_uuid,
71
+ relyingPartyName: relying_party_name,
72
+ certificateLevel: @certificate_level&.to_s,
73
+ nonce: @nonce,
74
+ capabilities: @capabilities,
75
+ requestProperties: request_properties,
76
+ initialCallbackUrl: @initial_callback_url
77
+ }.compact
78
+ end
79
+
80
+ def request_properties
81
+ request_properties_for_share_md(@share_md_client_ip_address)
82
+ end
83
+
84
+ def validate_initial_callback_url
85
+ return if blank?(@initial_callback_url)
86
+ return if INITIAL_CALLBACK_URL_PATTERN.match?(@initial_callback_url)
87
+
88
+ raise SmartIdRuby::Errors::RequestSetupError,
89
+ "Value for 'initialCallbackUrl' must match pattern ^https://[^|]+$ and must not contain unencoded vertical bars"
90
+ end
91
+
92
+ def validate_response_parameters(response)
93
+ if blank?(fetch_value(response, :sessionID))
94
+ raise SmartIdRuby::Errors::UnprocessableResponseError,
95
+ "Device link certificate choice session initialisation response field 'sessionID' is missing or empty"
96
+ end
97
+ if blank?(fetch_value(response, :sessionToken))
98
+ raise SmartIdRuby::Errors::UnprocessableResponseError,
99
+ "Device link certificate choice session initialisation response field 'sessionToken' is missing or empty"
100
+ end
101
+ if blank?(fetch_value(response, :sessionSecret))
102
+ raise SmartIdRuby::Errors::UnprocessableResponseError,
103
+ "Device link certificate choice session initialisation response field 'sessionSecret' is missing or empty"
104
+ end
105
+ if blank?(fetch_value(response, :deviceLinkBase))
106
+ raise SmartIdRuby::Errors::UnprocessableResponseError,
107
+ "Device link certificate choice session initialisation response field 'deviceLinkBase' is missing or empty"
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end