yoti 1.6.2 → 1.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +23 -224
- data/lib/yoti.rb +52 -1
- data/lib/yoti/activity_details.rb +1 -0
- data/lib/yoti/client.rb +13 -4
- data/lib/yoti/configuration.rb +7 -2
- data/lib/yoti/data_type/age_verification.rb +1 -1
- data/lib/yoti/data_type/base_profile.rb +1 -1
- data/lib/yoti/data_type/image.rb +4 -12
- data/lib/yoti/data_type/image_jpeg.rb +2 -0
- data/lib/yoti/data_type/image_png.rb +2 -0
- data/lib/yoti/data_type/media.rb +19 -0
- data/lib/yoti/data_type/signed_time_stamp.rb +1 -1
- data/lib/yoti/doc_scan/client.rb +187 -0
- data/lib/yoti/doc_scan/constants.rb +30 -0
- data/lib/yoti/doc_scan/errors.rb +81 -0
- data/lib/yoti/doc_scan/session/create/create_session_result.rb +50 -0
- data/lib/yoti/doc_scan/session/create/document_filter.rb +31 -0
- data/lib/yoti/doc_scan/session/create/document_restrictions_filter.rb +140 -0
- data/lib/yoti/doc_scan/session/create/notification_config.rb +142 -0
- data/lib/yoti/doc_scan/session/create/orthogonal_restrictions_filter.rb +150 -0
- data/lib/yoti/doc_scan/session/create/requested_check.rb +39 -0
- data/lib/yoti/doc_scan/session/create/requested_document_authenticity_check.rb +53 -0
- data/lib/yoti/doc_scan/session/create/requested_face_match_check.rb +95 -0
- data/lib/yoti/doc_scan/session/create/requested_liveness_check.rb +108 -0
- data/lib/yoti/doc_scan/session/create/requested_task.rb +39 -0
- data/lib/yoti/doc_scan/session/create/requested_text_extraction_task.rb +116 -0
- data/lib/yoti/doc_scan/session/create/required_document.rb +31 -0
- data/lib/yoti/doc_scan/session/create/required_id_document.rb +53 -0
- data/lib/yoti/doc_scan/session/create/sdk_config.rb +221 -0
- data/lib/yoti/doc_scan/session/create/session_specification.rb +203 -0
- data/lib/yoti/doc_scan/session/retrieve/authenticity_check_response.rb +12 -0
- data/lib/yoti/doc_scan/session/retrieve/breakdown_response.rb +38 -0
- data/lib/yoti/doc_scan/session/retrieve/check_response.rb +63 -0
- data/lib/yoti/doc_scan/session/retrieve/details_response.rb +28 -0
- data/lib/yoti/doc_scan/session/retrieve/document_fields_response.rb +21 -0
- data/lib/yoti/doc_scan/session/retrieve/document_id_photo_response.rb +21 -0
- data/lib/yoti/doc_scan/session/retrieve/face_map_response.rb +21 -0
- data/lib/yoti/doc_scan/session/retrieve/face_match_check_response.rb +12 -0
- data/lib/yoti/doc_scan/session/retrieve/frame_response.rb +21 -0
- data/lib/yoti/doc_scan/session/retrieve/generated_check_response.rb +28 -0
- data/lib/yoti/doc_scan/session/retrieve/generated_media.rb +28 -0
- data/lib/yoti/doc_scan/session/retrieve/generated_text_data_check_response.rb +12 -0
- data/lib/yoti/doc_scan/session/retrieve/get_session_result.rb +113 -0
- data/lib/yoti/doc_scan/session/retrieve/id_document_resource_response.rb +57 -0
- data/lib/yoti/doc_scan/session/retrieve/liveness_check_response.rb +12 -0
- data/lib/yoti/doc_scan/session/retrieve/liveness_resource_response.rb +24 -0
- data/lib/yoti/doc_scan/session/retrieve/media_response.rb +38 -0
- data/lib/yoti/doc_scan/session/retrieve/page_response.rb +27 -0
- data/lib/yoti/doc_scan/session/retrieve/recommendation_response.rb +34 -0
- data/lib/yoti/doc_scan/session/retrieve/report_response.rb +31 -0
- data/lib/yoti/doc_scan/session/retrieve/resource_container.rb +50 -0
- data/lib/yoti/doc_scan/session/retrieve/resource_response.rb +39 -0
- data/lib/yoti/doc_scan/session/retrieve/task_response.rb +87 -0
- data/lib/yoti/doc_scan/session/retrieve/text_data_check_response.rb +12 -0
- data/lib/yoti/doc_scan/session/retrieve/text_extraction_task_response.rb +18 -0
- data/lib/yoti/doc_scan/session/retrieve/zoom_liveness_resource_response.rb +33 -0
- data/lib/yoti/doc_scan/support/supported_documents.rb +60 -0
- data/lib/yoti/dynamic_share_service/extension/thirdparty_attribute_extension.rb +62 -11
- data/lib/yoti/dynamic_share_service/policy/dynamic_policy.rb +84 -22
- data/lib/yoti/dynamic_share_service/share_url.rb +28 -33
- data/lib/yoti/errors.rb +15 -2
- data/lib/yoti/http/aml_check_request.rb +12 -6
- data/lib/yoti/http/payloads/aml_address.rb +4 -0
- data/lib/yoti/http/payloads/aml_profile.rb +7 -1
- data/lib/yoti/http/profile_request.rb +11 -6
- data/lib/yoti/http/request.rb +221 -18
- data/lib/yoti/http/signed_request.rb +13 -4
- data/lib/yoti/protobuf/main.rb +1 -1
- data/lib/yoti/ssl.rb +2 -2
- data/lib/yoti/util/anchor_processor.rb +1 -1
- data/lib/yoti/util/validation.rb +41 -0
- data/lib/yoti/version.rb +1 -1
- data/yoti.gemspec +18 -9
- metadata +55 -68
- data/.gitignore +0 -39
- data/CONTRIBUTING.md +0 -127
- data/Guardfile +0 -11
- data/Rakefile +0 -49
- data/lib/yoti/sandbox.rb +0 -4
- data/lib/yoti/sandbox/anchor.rb +0 -49
- data/lib/yoti/sandbox/attribute.rb +0 -52
- data/lib/yoti/sandbox/profile.rb +0 -171
- data/lib/yoti/sandbox/sandbox_client.rb +0 -40
- data/login_flow.png +0 -0
- data/rubocop.yml +0 -57
- data/yardstick.yml +0 -9
@@ -7,6 +7,10 @@ module Yoti
|
|
7
7
|
# @return [String] the postcode required for USA, optional otherwise
|
8
8
|
attr_accessor :post_code
|
9
9
|
|
10
|
+
#
|
11
|
+
# @param [String] country
|
12
|
+
# @param [String] post_code
|
13
|
+
#
|
10
14
|
def initialize(country, post_code = nil)
|
11
15
|
raise AmlError, 'AmlAddress requires a country.' if country.to_s.empty?
|
12
16
|
|
@@ -1,6 +1,12 @@
|
|
1
1
|
module Yoti
|
2
2
|
# Manages the AML check Profile object
|
3
3
|
class AmlProfile
|
4
|
+
#
|
5
|
+
# @param [String] given_names
|
6
|
+
# @param [String] family_name
|
7
|
+
# @param [AmlAddress] aml_address
|
8
|
+
# @param [String] ssn
|
9
|
+
#
|
4
10
|
def initialize(given_names, family_name, aml_address, ssn = nil)
|
5
11
|
@given_names = given_names
|
6
12
|
@family_name = family_name
|
@@ -11,7 +17,7 @@ module Yoti
|
|
11
17
|
raise AmlError, 'Request for USA require a valid SSN and postcode.' if usa_invalid
|
12
18
|
end
|
13
19
|
|
14
|
-
# @return [
|
20
|
+
# @return [Hash] the AML check request body
|
15
21
|
def payload
|
16
22
|
{
|
17
23
|
given_names: @given_names,
|
@@ -1,6 +1,9 @@
|
|
1
1
|
module Yoti
|
2
2
|
# Manage the API's profile requests
|
3
3
|
class ProfileRequest
|
4
|
+
#
|
5
|
+
# @param [String] encrypted_connect_token
|
6
|
+
#
|
4
7
|
def initialize(encrypted_connect_token)
|
5
8
|
@encrypted_connect_token = encrypted_connect_token
|
6
9
|
@request = request
|
@@ -14,12 +17,14 @@ module Yoti
|
|
14
17
|
private
|
15
18
|
|
16
19
|
def request
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
Yoti::Request
|
21
|
+
.builder
|
22
|
+
.with_http_method('GET')
|
23
|
+
.with_base_url(Yoti.configuration.api_endpoint)
|
24
|
+
.with_endpoint("profile/#{Yoti::SSL.decrypt_token(@encrypted_connect_token)}")
|
25
|
+
.with_query_param('appId', Yoti.configuration.client_sdk_id)
|
26
|
+
.with_header('X-Yoti-Auth-Key', Yoti::SSL.auth_key_from_pem)
|
27
|
+
.build
|
23
28
|
end
|
24
29
|
end
|
25
30
|
end
|
data/lib/yoti/http/request.rb
CHANGED
@@ -1,9 +1,19 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
require 'cgi'
|
3
|
+
|
1
4
|
module Yoti
|
2
5
|
# Manage the API's HTTPS requests
|
3
6
|
class Request
|
7
|
+
# @deprecated will be removed in 2.0.0 - token is now provided with the endpoint
|
4
8
|
# @return [String] the URL token received from Yoti Connect
|
5
9
|
attr_accessor :encrypted_connect_token
|
6
10
|
|
11
|
+
# @return [String] the base URL
|
12
|
+
attr_writer :base_url
|
13
|
+
|
14
|
+
# @return [Hash] query params to add to the request
|
15
|
+
attr_accessor :query_params
|
16
|
+
|
7
17
|
# @return [String] the HTTP method used for the request
|
8
18
|
# The allowed methods are: GET, DELETE, POST, PUT, PATCH
|
9
19
|
attr_accessor :http_method
|
@@ -11,36 +21,93 @@ module Yoti
|
|
11
21
|
# @return [String] the API endpoint for the request
|
12
22
|
attr_accessor :endpoint
|
13
23
|
|
14
|
-
# @return [
|
24
|
+
# @return [#to_json,String] the body sent with the request
|
15
25
|
attr_accessor :payload
|
16
26
|
|
17
27
|
def initialize
|
18
28
|
@headers = {}
|
19
29
|
end
|
20
30
|
|
31
|
+
#
|
32
|
+
# @return [RequestBuilder]
|
33
|
+
#
|
34
|
+
def self.builder
|
35
|
+
RequestBuilder.new
|
36
|
+
end
|
37
|
+
|
38
|
+
#
|
21
39
|
# Adds a HTTP header to the request
|
40
|
+
#
|
41
|
+
# @param [String] header
|
42
|
+
# @param [String] value
|
43
|
+
#
|
22
44
|
def add_header(header, value)
|
23
45
|
@headers[header] = value
|
24
46
|
end
|
25
47
|
|
48
|
+
#
|
26
49
|
# Makes a HTTP request after signing the headers
|
27
|
-
#
|
28
|
-
|
50
|
+
#
|
51
|
+
# @return [HTTPResponse]
|
52
|
+
#
|
53
|
+
def execute
|
29
54
|
raise RequestError, 'The request requires a HTTP method.' unless @http_method
|
30
|
-
raise RequestError, 'The payload needs to be a hash.' unless @payload.to_s.empty? || @payload.is_a?(Hash)
|
31
55
|
|
32
|
-
|
56
|
+
http_res = Net::HTTP.start(uri.hostname, Yoti.configuration.api_port, use_ssl: https_uri?) do |http|
|
33
57
|
signed_request = SignedRequest.new(unsigned_request, path, @payload).sign
|
34
58
|
http.request(signed_request)
|
35
59
|
end
|
36
60
|
|
37
|
-
raise RequestError
|
61
|
+
raise RequestError.new("Unsuccessful Yoti API call: #{http_res.message}", http_res) unless response_is_success(http_res)
|
38
62
|
|
39
|
-
|
63
|
+
http_res
|
64
|
+
end
|
65
|
+
|
66
|
+
#
|
67
|
+
# Makes a HTTP request and returns the body after signing the headers
|
68
|
+
#
|
69
|
+
# @return [String]
|
70
|
+
#
|
71
|
+
def body
|
72
|
+
execute.body
|
73
|
+
end
|
74
|
+
|
75
|
+
#
|
76
|
+
# @return [String] the base URL
|
77
|
+
#
|
78
|
+
def base_url
|
79
|
+
@base_url ||= Yoti.configuration.api_endpoint
|
40
80
|
end
|
41
81
|
|
42
82
|
private
|
43
83
|
|
84
|
+
#
|
85
|
+
# @param [Net::HTTPResponse] http_res
|
86
|
+
#
|
87
|
+
# @return [Boolean]
|
88
|
+
#
|
89
|
+
def response_is_success(http_res)
|
90
|
+
http_res.code.to_i >= 200 && http_res.code.to_i < 300
|
91
|
+
end
|
92
|
+
|
93
|
+
#
|
94
|
+
# Adds payload to provided HTTP request
|
95
|
+
#
|
96
|
+
# @param [Net::HTTPRequest] http_req
|
97
|
+
#
|
98
|
+
def add_payload(http_req)
|
99
|
+
return if @payload.to_s.empty?
|
100
|
+
|
101
|
+
if @payload.is_a?(String)
|
102
|
+
http_req.body = @payload
|
103
|
+
elsif @payload.respond_to?(:to_json)
|
104
|
+
http_req.body = @payload.to_json
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
#
|
109
|
+
# @return [Net::HTTPRequest] the unsigned HTTP request
|
110
|
+
#
|
44
111
|
def unsigned_request
|
45
112
|
case @http_method
|
46
113
|
when 'GET'
|
@@ -49,13 +116,13 @@ module Yoti
|
|
49
116
|
http_req = Net::HTTP::Delete.new(uri)
|
50
117
|
when 'POST'
|
51
118
|
http_req = Net::HTTP::Post.new(uri)
|
52
|
-
http_req
|
119
|
+
add_payload(http_req)
|
53
120
|
when 'PUT'
|
54
121
|
http_req = Net::HTTP::Put.new(uri)
|
55
|
-
http_req
|
122
|
+
add_payload(http_req)
|
56
123
|
when 'PATCH'
|
57
124
|
http_req = Net::HTTP::Patch.new(uri)
|
58
|
-
http_req
|
125
|
+
add_payload(http_req)
|
59
126
|
else
|
60
127
|
raise RequestError, "Request method not allowed: #{@http_method}"
|
61
128
|
end
|
@@ -67,22 +134,27 @@ module Yoti
|
|
67
134
|
http_req
|
68
135
|
end
|
69
136
|
|
137
|
+
#
|
138
|
+
# @return [URI] the full request URI
|
139
|
+
#
|
70
140
|
def uri
|
71
|
-
@uri ||= URI(
|
141
|
+
@uri ||= URI(base_url + path)
|
72
142
|
end
|
73
143
|
|
144
|
+
#
|
145
|
+
# @return [String] the path with query string
|
146
|
+
#
|
74
147
|
def path
|
75
148
|
@path ||= begin
|
76
|
-
|
77
|
-
timestamp = Time.now.to_i
|
78
|
-
|
79
|
-
"/#{@endpoint}/#{token}"\
|
80
|
-
"?nonce=#{nonce}"\
|
81
|
-
"×tamp=#{timestamp}"\
|
82
|
-
"&appId=#{Yoti.configuration.client_sdk_id}"
|
149
|
+
"/#{@endpoint}/#{token}".chomp('/') + "?#{query_string}"
|
83
150
|
end
|
84
151
|
end
|
85
152
|
|
153
|
+
#
|
154
|
+
# @deprecated will be removed in 2.0.0 - token is now provided with the endpoint
|
155
|
+
#
|
156
|
+
# @return [String] the decrypted connect token
|
157
|
+
#
|
86
158
|
def token
|
87
159
|
return '' unless @encrypted_connect_token
|
88
160
|
|
@@ -92,5 +164,136 @@ module Yoti
|
|
92
164
|
def https_uri?
|
93
165
|
uri.scheme == 'https'
|
94
166
|
end
|
167
|
+
|
168
|
+
#
|
169
|
+
# Builds query string including nonce and timestamp
|
170
|
+
#
|
171
|
+
# @return [String]
|
172
|
+
#
|
173
|
+
def query_string
|
174
|
+
params = {
|
175
|
+
nonce: SecureRandom.uuid,
|
176
|
+
timestamp: Time.now.to_i
|
177
|
+
}
|
178
|
+
|
179
|
+
if @query_params.nil?
|
180
|
+
# @deprecated this default will be removed in 2.0.0
|
181
|
+
# Append appId when no custom query params are provided.
|
182
|
+
params.merge!(appId: Yoti.configuration.client_sdk_id)
|
183
|
+
else
|
184
|
+
Validation.assert_is_a(Hash, @query_params, 'query_params')
|
185
|
+
params.merge!(@query_params)
|
186
|
+
end
|
187
|
+
|
188
|
+
params.map do |k, v|
|
189
|
+
CGI.escape(k.to_s) + '=' + CGI.escape(v.to_s)
|
190
|
+
end.join('&')
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
#
|
195
|
+
# Builder for {Request}
|
196
|
+
#
|
197
|
+
class RequestBuilder
|
198
|
+
def initialize
|
199
|
+
@headers = {}
|
200
|
+
@query_params = {}
|
201
|
+
end
|
202
|
+
|
203
|
+
#
|
204
|
+
# Sets the base URL
|
205
|
+
#
|
206
|
+
# @param [String] base_url
|
207
|
+
#
|
208
|
+
# @return [self]
|
209
|
+
#
|
210
|
+
def with_base_url(base_url)
|
211
|
+
Validation.assert_is_a(String, base_url, 'base_url')
|
212
|
+
@base_url = base_url
|
213
|
+
self
|
214
|
+
end
|
215
|
+
|
216
|
+
#
|
217
|
+
# Adds a HTTP header to the request
|
218
|
+
#
|
219
|
+
# @param [String] header
|
220
|
+
# @param [String] value
|
221
|
+
#
|
222
|
+
# @return [self]
|
223
|
+
#
|
224
|
+
def with_header(header, value)
|
225
|
+
Validation.assert_is_a(String, header, 'header')
|
226
|
+
Validation.assert_is_a(String, value, 'value')
|
227
|
+
@headers[header] = value
|
228
|
+
self
|
229
|
+
end
|
230
|
+
|
231
|
+
#
|
232
|
+
# Adds a query parameter to the request
|
233
|
+
#
|
234
|
+
# @param [String] key
|
235
|
+
# @param [String] value
|
236
|
+
#
|
237
|
+
# @return [self]
|
238
|
+
#
|
239
|
+
def with_query_param(key, value)
|
240
|
+
Validation.assert_is_a(String, key, 'key')
|
241
|
+
Validation.assert_is_a(String, value, 'value')
|
242
|
+
@query_params[key] = value
|
243
|
+
self
|
244
|
+
end
|
245
|
+
|
246
|
+
#
|
247
|
+
# Sets the HTTP method
|
248
|
+
#
|
249
|
+
# @param [String] http_method
|
250
|
+
#
|
251
|
+
# @return [self]
|
252
|
+
#
|
253
|
+
def with_http_method(http_method)
|
254
|
+
Validation.assert_is_a(String, http_method, 'http_method')
|
255
|
+
@http_method = http_method
|
256
|
+
self
|
257
|
+
end
|
258
|
+
|
259
|
+
#
|
260
|
+
# Sets the API endpoint for the request
|
261
|
+
#
|
262
|
+
# @param [String] endpoint
|
263
|
+
#
|
264
|
+
# @return [self]
|
265
|
+
#
|
266
|
+
def with_endpoint(endpoint)
|
267
|
+
Validation.assert_is_a(String, endpoint, 'endpoint')
|
268
|
+
@endpoint = endpoint
|
269
|
+
self
|
270
|
+
end
|
271
|
+
|
272
|
+
#
|
273
|
+
# Sets the body sent with the request
|
274
|
+
#
|
275
|
+
# @param [#to_json,String] payload
|
276
|
+
#
|
277
|
+
# @return [self]
|
278
|
+
#
|
279
|
+
def with_payload(payload)
|
280
|
+
Validation.assert_respond_to(:to_json, payload, 'payload') unless payload.is_a?(String)
|
281
|
+
@payload = payload
|
282
|
+
self
|
283
|
+
end
|
284
|
+
|
285
|
+
#
|
286
|
+
# @return [Request]
|
287
|
+
#
|
288
|
+
def build
|
289
|
+
request = Request.new
|
290
|
+
request.base_url = @base_url
|
291
|
+
request.endpoint = @endpoint
|
292
|
+
request.query_params = @query_params
|
293
|
+
request.http_method = @http_method
|
294
|
+
request.payload = @payload
|
295
|
+
@headers.map { |k, v| request.add_header(k, v) }
|
296
|
+
request
|
297
|
+
end
|
95
298
|
end
|
96
299
|
end
|
@@ -3,6 +3,11 @@ require 'base64'
|
|
3
3
|
module Yoti
|
4
4
|
# Converts a basic Net::HTTP request into a Yoti Signed Request
|
5
5
|
class SignedRequest
|
6
|
+
#
|
7
|
+
# @param [Net::HTTPRequest] unsigned_request
|
8
|
+
# @param [String] path
|
9
|
+
# @param [#to_json,String] payload
|
10
|
+
#
|
6
11
|
def initialize(unsigned_request, path, payload = {})
|
7
12
|
@http_req = unsigned_request
|
8
13
|
@path = path
|
@@ -10,6 +15,9 @@ module Yoti
|
|
10
15
|
@auth_key = Yoti::SSL.auth_key_from_pem
|
11
16
|
end
|
12
17
|
|
18
|
+
#
|
19
|
+
# @return [Net::HTTPRequest]
|
20
|
+
#
|
13
21
|
def sign
|
14
22
|
@http_req['X-Yoti-Auth-Digest'] = message_signature
|
15
23
|
@http_req['X-Yoti-SDK'] = Yoti.configuration.sdk_identifier
|
@@ -20,18 +28,19 @@ module Yoti
|
|
20
28
|
private
|
21
29
|
|
22
30
|
def message_signature
|
23
|
-
@message_signature ||= Yoti::SSL.get_secure_signature("#{http_method}&#{@path}#{
|
31
|
+
@message_signature ||= Yoti::SSL.get_secure_signature("#{http_method}&#{@path}#{base64_payload}")
|
24
32
|
end
|
25
33
|
|
26
34
|
def http_method
|
27
35
|
@http_req.method
|
28
36
|
end
|
29
37
|
|
30
|
-
|
31
|
-
def payload_string
|
38
|
+
def base64_payload
|
32
39
|
return '' unless @payload
|
33
40
|
|
34
|
-
|
41
|
+
payload_string = @payload.is_a?(String) ? @payload : @payload.to_json
|
42
|
+
|
43
|
+
'&' + Base64.strict_encode64(payload_string)
|
35
44
|
end
|
36
45
|
end
|
37
46
|
end
|
data/lib/yoti/protobuf/main.rb
CHANGED
@@ -94,7 +94,7 @@ module Yoti
|
|
94
94
|
proto_multi_value = Yoti::Protobuf::Attrpubapi::MultiValue.decode(value)
|
95
95
|
items = []
|
96
96
|
proto_multi_value.values.each do |item|
|
97
|
-
items
|
97
|
+
items << value_based_on_content_type(item.data, item.content_type)
|
98
98
|
end
|
99
99
|
MultiValue.new(items)
|
100
100
|
end
|
data/lib/yoti/ssl.rb
CHANGED
@@ -32,7 +32,7 @@ module Yoti
|
|
32
32
|
end
|
33
33
|
|
34
34
|
# Extracts the public key from pem key, converts it to a DER base 64 encoded value
|
35
|
-
# @return [String] base 64 encoded
|
35
|
+
# @return [String] base 64 encoded authentication key
|
36
36
|
def auth_key_from_pem
|
37
37
|
public_key = private_key.public_key
|
38
38
|
Base64.strict_encode64(public_key.to_der)
|
@@ -48,7 +48,7 @@ module Yoti
|
|
48
48
|
|
49
49
|
# Uses the decrypted receipt key and the current user's iv to decode the text
|
50
50
|
# @param key [String] base 64 decoded key
|
51
|
-
# @param
|
51
|
+
# @param user_iv [String] base 64 decoded iv
|
52
52
|
# @param text [String] base 64 decoded cyphered text
|
53
53
|
# @return [String] base 64 decoded deciphered text
|
54
54
|
def decipher(key, user_iv, text)
|