tanker-core 2.30.0 → 2.30.1.alpha.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3f4f72b76b69cec6b590fb140b06e8d7ae2a1a80bf5460683ea4adb4fcba8ea6
4
- data.tar.gz: d2e0dda686b6d71ae27714c7a1dd904f65e2a78c76622511e52033fc278fd213
3
+ metadata.gz: f965af6640e6603ed8c76ceb3b9af8c02a70ac767e7c4db364df13fca40caf08
4
+ data.tar.gz: 2cad737772cb42913f419eb7e619082acef770b3477b65dcc7f35293bffcc41d
5
5
  SHA512:
6
- metadata.gz: 26082b813a8874586abd5e149dc2f60db53b96b3ddaf5d426b21865d6457e23155fa35ea757723127678e3075dddc27dbd883829153e34f8b25ccaf5c6760c43
7
- data.tar.gz: 585fff8b0fa829e199747f3bbfe4b9110d5c2171fda2029d628f3ee306789d4991d28c3309912a778851cc614d961345f3d31082d95a8b09b36e76b1dde2b7d3
6
+ metadata.gz: 20b15f5fba9ea29c1f94b23be2a8d629e9b965730f9587aa377bdcc81c1631492a5c9821fea634be2938122a05e820dfadec5af0e4097e8152d2359e7989d247
7
+ data.tar.gz: 7b168937a393fc0a2d300f06454533cb738048b09aba2e04e41a4b5280cce4362f114e6c92b164f9deb637efee4f14118ae4735051ec5e455c1b908a29c5900d
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'ffi'
4
- require 'tanker/core/verification'
5
- require 'tanker/c_tanker/c_string'
6
4
 
7
5
  module Tanker
8
6
  module CTanker
@@ -15,11 +13,5 @@ module Tanker
15
13
  :put_cache_values, :pointer,
16
14
  :find_cache_values, :pointer
17
15
  end
18
-
19
- class CHttpOptions < FFI::Struct
20
- layout :send_request, :pointer,
21
- :cancel_request, :pointer,
22
- :data, :pointer
23
- end
24
16
  end
25
17
  end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ffi'
4
+
5
+ module Tanker
6
+ module CTanker
7
+ class CHttpRequest < FFI::Struct
8
+ layout :method, :string,
9
+ :url, :string,
10
+ :instance_id, :string,
11
+ :authorization, :string,
12
+ :body, :pointer,
13
+ :body_size, :int32
14
+ end
15
+
16
+ class CHttpResponse < FFI::Struct
17
+ def self.new_ok(status_code:, content_type:, body:)
18
+ new nil, status_code, content_type, body
19
+ end
20
+
21
+ def self.new_error(msg)
22
+ new msg, nil, nil, nil
23
+ end
24
+
25
+ def initialize(error_msg, status_code, content_type, body)
26
+ super()
27
+
28
+ if error_msg
29
+ @error_msg = CTanker.new_cstring(error_msg)
30
+ self[:error_msg] = @error_msg
31
+ else
32
+ @content_type = CTanker.new_cstring content_type
33
+ @body = FFI::MemoryPointer.from_string(body)
34
+
35
+ self[:error_msg] = nil
36
+ self[:content_type] = @content_type
37
+ self[:body] = @body
38
+ self[:body_size] = body.bytesize
39
+ self[:status_code] = status_code
40
+ end
41
+ end
42
+
43
+ layout :error_msg, :pointer,
44
+ :content_type, :pointer,
45
+ :body, :pointer,
46
+ :body_size, :int64,
47
+ :status_code, :int32
48
+ end
49
+
50
+ typedef :pointer, :http_request_handle
51
+
52
+ callback :http_send_request, [CHttpRequest, :pointer], :http_request_handle
53
+ callback :http_cancel_request, [CHttpRequest, :http_request_handle, :pointer], :void
54
+
55
+ class CHttpOptions < FFI::Struct
56
+ layout :send_request, :http_send_request,
57
+ :cancel_request, :http_cancel_request,
58
+ :data, :pointer
59
+
60
+ def initialize(send_request, cancel_request)
61
+ super()
62
+
63
+ self[:send_request] = send_request
64
+ self[:cancel_request] = cancel_request
65
+ self[:data] = nil
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ffi'
4
+
5
+ module FFI::Library
6
+ # Marking a function blocking releases the global Ruby lock.
7
+ # This is required for every function that could invoke a callback (including log handler) in another thread
8
+ def blocking_attach_function(func, args, returns = nil)
9
+ attach_function func, args, returns, blocking: true
10
+ end
11
+ end
12
+
13
+ module Tanker
14
+ module CTanker
15
+ extend FFI::Library
16
+ ffi_lib get_path('ctanker')
17
+ end
18
+
19
+ private_constant :CTanker
20
+ end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'ffi'
4
+ require_relative 'c_tanker/init'
4
5
  require_relative 'core/options'
5
6
  require_relative 'sharing_options'
6
7
  require_relative 'encryption_options'
@@ -12,19 +13,8 @@ require_relative 'c_tanker/c_verification_method'
12
13
  require_relative 'c_tanker/c_log_record'
13
14
  require_relative 'c_tanker/c_device_info'
14
15
 
15
- module FFI::Library
16
- # Marking a function blocking releases the global Ruby lock.
17
- # This is required for every function that could invoke a callback (including log handler) in another thread
18
- def blocking_attach_function(func, args, returns = nil)
19
- attach_function func, args, returns, blocking: true
20
- end
21
- end
22
-
23
16
  module Tanker
24
17
  module CTanker
25
- extend FFI::Library
26
- ffi_lib get_path('ctanker')
27
-
28
18
  typedef :pointer, :session_pointer
29
19
  typedef :pointer, :enc_sess_pointer
30
20
  typedef :pointer, :stream_pointer
@@ -99,6 +89,8 @@ module Tanker
99
89
 
100
90
  blocking_attach_function :tanker_set_log_handler, [:log_handler_callback], :void
101
91
 
92
+ blocking_attach_function :tanker_http_handle_response, [CHttpRequest, CHttpResponse], :void
93
+
102
94
  blocking_attach_function :tanker_prehash_password, [:string], CFuture
103
95
 
104
96
  blocking_attach_function :tanker_free_buffer, [:pointer], :void
@@ -28,9 +28,9 @@ module Tanker
28
28
  decrypted_size = CTanker.tanker_decrypted_size(inbuf, data.bytesize).get.address
29
29
  outbuf = FFI::MemoryPointer.new(:char, decrypted_size)
30
30
 
31
- clear_size = CTanker.tanker_decrypt(@ctanker, outbuf, inbuf, data.bytesize).get.address
31
+ CTanker.tanker_decrypt(@ctanker, outbuf, inbuf, data.bytesize).get
32
32
 
33
- outbuf.read_string clear_size
33
+ outbuf.read_string decrypted_size
34
34
  end
35
35
 
36
36
  def decrypt_utf8(data)
@@ -0,0 +1,155 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'faraday'
4
+
5
+ module Tanker
6
+ module Http
7
+ class HttpRequest
8
+ @@mutex = Mutex.new # rubocop:disable Style/ClassVars I have no idea why you don't like class vars
9
+ @@current_request_id = 0 # rubocop:disable Style/ClassVars
10
+ # Hash(id => request)
11
+ @@running_requests = {} # rubocop:disable Style/ClassVars
12
+
13
+ attr_reader :id
14
+ attr_reader :method
15
+ attr_reader :url
16
+ attr_reader :instance_id
17
+ attr_reader :authorization
18
+ attr_reader :body
19
+ attr_reader :crequest
20
+
21
+ def self.method_str_to_symbol(method)
22
+ case method
23
+ when 'GET' then :get
24
+ when 'POST' then :post
25
+ when 'PATCH' then :patch
26
+ when 'PUT' then :put
27
+ when 'DELETE' then :delete
28
+ else raise "unknown HTTP method #{method}"
29
+ end
30
+ end
31
+
32
+ def initialize(crequest:)
33
+ @@mutex.synchronize do
34
+ @@current_request_id += 1 # rubocop:disable Style/ClassVars
35
+ @id = @@current_request_id
36
+ @@running_requests[@id] = self
37
+ end
38
+
39
+ @method = self.class.method_str_to_symbol crequest[:method]
40
+ @url = crequest[:url]
41
+ @instance_id = crequest[:instance_id]
42
+ @authorization = crequest[:authorization]
43
+ @body = crequest[:body].read_string_length(crequest[:body_size])
44
+
45
+ # Keep the crequest because we need its address to answer to Tanker
46
+ @crequest = crequest
47
+ end
48
+
49
+ # Since Ruby's HTTP libraries are not asynchronous, they do not support cancelation either.
50
+ # When a request is canceled, we let it run until the end, and then we discard its result.
51
+ def self.cancel(id)
52
+ @@mutex.synchronize do
53
+ @@running_requests.delete id
54
+ end
55
+ end
56
+
57
+ def complete_if_not_canceled(&block)
58
+ @@mutex.synchronize do
59
+ unless @@running_requests.delete @id
60
+ # Request has been canceled, don't call Tanker back
61
+ return
62
+ end
63
+
64
+ block.call
65
+ end
66
+ end
67
+ end
68
+
69
+ module ThreadPool
70
+ THREAD_POOL_SIZE = 4
71
+
72
+ def self.thread_loop
73
+ loop do
74
+ work = @queue.pop
75
+ work.call
76
+ end
77
+ end
78
+
79
+ def self.push(proc)
80
+ @queue << proc
81
+ end
82
+
83
+ # Queue is a concurrent queue in Ruby
84
+ @queue = Queue.new
85
+ @http_thread_pool = THREAD_POOL_SIZE.times do
86
+ Thread.new do
87
+ thread_loop
88
+ end
89
+ end
90
+ end
91
+
92
+ class Client
93
+ attr_reader :tanker_http_options
94
+
95
+ def initialize(sdk_type, sdk_version)
96
+ @sdk_type = sdk_type
97
+ @sdk_version = sdk_version
98
+
99
+ # This could be a proc, but for some reason, ffi gives the wrong type
100
+ # for crequest if we don't specify it explicitly here
101
+ @c_send_request = FFI::Function.new(:pointer, [CTanker::CHttpRequest.by_ref, :pointer]) do |crequest, cdata|
102
+ next send_request crequest, cdata
103
+ rescue Exception => e # rubocop:disable Lint/RescueException I do want to rescue all exceptions
104
+ cresponse = CTanker::CHttpResponse.new_error e.message
105
+ CTanker.tanker_http_handle_response(crequest, cresponse)
106
+ end
107
+ @c_cancel_request = proc do |crequest, request_id, cdata|
108
+ cancel_request crequest, request_id, cdata
109
+ rescue Exception => e # rubocop:disable Lint/RescueException I do want to rescue all exceptions
110
+ # This is not recoverable and won't be logged by FFI, let's do our best and log it here just before we crash
111
+ puts "fatal error when canceling HTTP request:\n#{e.full_message}"
112
+ raise
113
+ end
114
+
115
+ @tanker_http_options = CTanker::CHttpOptions.new @c_send_request, @c_cancel_request
116
+ end
117
+
118
+ def process_request(request)
119
+ fresponse = Faraday.run_request(request.method, request.url, request.body, {
120
+ 'X-Tanker-SdkType' => @sdk_type,
121
+ 'X-Tanker-SdkVersion' => @sdk_version,
122
+ 'Authorization' => request.authorization,
123
+ 'X-Tanker-Instanceid' => request.instance_id
124
+ }.compact)
125
+
126
+ request.complete_if_not_canceled do
127
+ cresponse = CTanker::CHttpResponse.new_ok status_code: fresponse.status,
128
+ content_type: fresponse.headers['content-type'],
129
+ body: fresponse.body
130
+ CTanker.tanker_http_handle_response(request.crequest, cresponse)
131
+ end
132
+ rescue Exception => e # rubocop:disable Lint/RescueException I do want to rescue all exceptions
133
+ # NOTE: when debugging, you might want to uncomment this to print a full backtrace
134
+ # puts "HTTP request error:\n#{e.full_message}"
135
+ cresponse = CTanker::CHttpResponse.new_error e.message
136
+ CTanker.tanker_http_handle_response(request.crequest, cresponse)
137
+ end
138
+
139
+ def send_request(crequest, _cdata)
140
+ request = HttpRequest.new crequest: crequest
141
+ ThreadPool.push(proc do
142
+ process_request request
143
+ end)
144
+ FFI::Pointer.new :void, request.id
145
+ end
146
+
147
+ def cancel_request(_crequest, prequest_id, _cdata)
148
+ request_id = prequest_id.to_i
149
+ HttpRequest.cancel(request_id)
150
+ end
151
+ end
152
+ end
153
+
154
+ private_constant :Http
155
+ end
@@ -31,6 +31,9 @@ module Tanker
31
31
  # Do not spam the console of our users.
32
32
  self.class.set_log_handler { |_| } unless self.class.test_and_set_log_handler == 1 # rubocop:disable Lint/EmptyBlock
33
33
 
34
+ @http_client = Http::Client.new options.sdk_type, VERSION
35
+ options[:http_options] = @http_client.tanker_http_options
36
+
34
37
  @ctanker = CTanker.tanker_create(options).get
35
38
  @freed = false
36
39
  ctanker_addr = @ctanker.address
@@ -2,7 +2,8 @@
2
2
 
3
3
  require 'ffi'
4
4
  require 'tanker/c_tanker/c_string'
5
- require 'tanker/c_tanker/c_backends'
5
+ require 'tanker/c_tanker/c_datastore'
6
+ require 'tanker/c_tanker/c_http'
6
7
 
7
8
  module Tanker
8
9
  # Options that can be given when opening a Tanker session
@@ -20,22 +21,25 @@ module Tanker
20
21
  SDK_TYPE = 'client-ruby'
21
22
  SDK_VERSION = CTanker.new_cstring Core::VERSION
22
23
 
24
+ attr_reader :sdk_type
25
+
23
26
  def initialize(app_id:, url: nil, sdk_type: SDK_TYPE, persistent_path: nil, cache_path: nil)
24
27
  super()
25
28
 
26
29
  # NOTE: Instance variables are required to keep the CStrings alive
27
- @app_id = CTanker.new_cstring app_id
28
- @url = CTanker.new_cstring url
29
- @persistent_path = CTanker.new_cstring persistent_path
30
- @cache_path = CTanker.new_cstring cache_path
31
- @sdk_type = CTanker.new_cstring sdk_type
30
+ @c_app_id = CTanker.new_cstring app_id
31
+ @c_url = CTanker.new_cstring url
32
+ @c_persistent_path = CTanker.new_cstring persistent_path
33
+ @c_cache_path = CTanker.new_cstring cache_path
34
+ @sdk_type = sdk_type
35
+ @c_sdk_type = CTanker.new_cstring sdk_type
32
36
 
33
37
  self[:version] = 4
34
- self[:app_id] = @app_id
35
- self[:url] = @url
36
- self[:persistent_path] = @persistent_path
37
- self[:cache_path] = @cache_path
38
- self[:sdk_type] = @sdk_type
38
+ self[:app_id] = @c_app_id
39
+ self[:url] = @c_url
40
+ self[:persistent_path] = @c_persistent_path
41
+ self[:cache_path] = @c_cache_path
42
+ self[:sdk_type] = @c_sdk_type
39
43
  self[:sdk_version] = SDK_VERSION
40
44
  end
41
45
  end
@@ -76,7 +76,7 @@ module Tanker
76
76
  CTanker.tanker_create_oidc_nonce(@ctanker).get_string
77
77
  end
78
78
 
79
- def oidc_test_nonce=(nonce)
79
+ def _oidc_test_nonce=(nonce)
80
80
  CTanker.tanker_set_oidc_test_nonce(@ctanker, nonce).get
81
81
  end
82
82
 
@@ -166,7 +166,7 @@ module Tanker
166
166
  buffer.put_bytes(0, rbbuf)
167
167
  CTanker.tanker_stream_read_operation_finish(operation, rbbuf.size)
168
168
  end
169
- rescue StandardError => e
169
+ rescue Exception => e # rubocop:disable Lint/RescueException I do want to rescue all exceptions
170
170
  @mutex.synchronize do
171
171
  return if @closed
172
172
 
@@ -227,7 +227,7 @@ module Tanker
227
227
 
228
228
  @write.write(ffibuf.read_string(nb_read))
229
229
  end
230
- rescue StandardError => e
230
+ rescue Exception => e # rubocop:disable Lint/RescueException I do want to rescue all exceptions
231
231
  @error = @substream.error || e
232
232
  ensure
233
233
  @write.close
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Tanker
4
4
  class Core
5
- VERSION = '2.30.0'
5
+ VERSION = '2.30.1.alpha.1'
6
6
 
7
7
  def self.native_version
8
8
  CTanker.tanker_version_string
data/lib/tanker/core.rb CHANGED
@@ -5,6 +5,7 @@ require 'set'
5
5
  require_relative 'core/version'
6
6
  require_relative 'c_tanker'
7
7
  require_relative 'error'
8
+ require_relative 'core/http'
8
9
  require_relative 'core/session'
9
10
  require_relative 'core/verification'
10
11
  require_relative 'core/encryption'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tanker-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.30.0
4
+ version: 2.30.1.alpha.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tanker team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-05-03 00:00:00.000000000 Z
11
+ date: 2022-04-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi
@@ -140,20 +140,23 @@ files:
140
140
  - lib/tanker/admin/c_admin/c_app_descriptor.rb
141
141
  - lib/tanker/admin/c_admin/c_app_update_options.rb
142
142
  - lib/tanker/c_tanker.rb
143
- - lib/tanker/c_tanker/c_backends.rb
143
+ - lib/tanker/c_tanker/c_datastore.rb
144
144
  - lib/tanker/c_tanker/c_device_info.rb
145
145
  - lib/tanker/c_tanker/c_future.rb
146
+ - lib/tanker/c_tanker/c_http.rb
146
147
  - lib/tanker/c_tanker/c_lib.rb
147
148
  - lib/tanker/c_tanker/c_log_record.rb
148
149
  - lib/tanker/c_tanker/c_string.rb
149
150
  - lib/tanker/c_tanker/c_tanker_error.rb
150
151
  - lib/tanker/c_tanker/c_verification.rb
151
152
  - lib/tanker/c_tanker/c_verification_method.rb
153
+ - lib/tanker/c_tanker/init.rb
152
154
  - lib/tanker/core.rb
153
155
  - lib/tanker/core/attach_result.rb
154
156
  - lib/tanker/core/encryption.rb
155
157
  - lib/tanker/core/encryption_session.rb
156
158
  - lib/tanker/core/group.rb
159
+ - lib/tanker/core/http.rb
157
160
  - lib/tanker/core/init.rb
158
161
  - lib/tanker/core/log_record.rb
159
162
  - lib/tanker/core/options.rb
@@ -187,9 +190,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
187
190
  version: 2.6.0
188
191
  required_rubygems_version: !ruby/object:Gem::Requirement
189
192
  requirements:
190
- - - ">="
193
+ - - ">"
191
194
  - !ruby/object:Gem::Version
192
- version: '0'
195
+ version: 1.3.1
193
196
  requirements: []
194
197
  rubygems_version: 3.3.7
195
198
  signing_key: