tshield 0.13.5.0 → 0.14.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ab5c5057fe81ae295f572912c6955ce0ea0bd9be6b42fb515a7832fe3451459a
4
- data.tar.gz: 9c785dc23adb245fdfcc416698c551f7a45eaa32b5892a2cabea708f16fa2859
3
+ metadata.gz: 83eb12f572bdfd5f6fade21d83ee7d4883253aa9e42cad7fe0e9feac380d7ae6
4
+ data.tar.gz: c1718a13671ee6899321dcda86c6d6dbaad23c1389cc24c0b6ea3b684024c725
5
5
  SHA512:
6
- metadata.gz: 58fd33ddf9e466af5882e6522612b2b0fa05c95f728578fe50b014dca0777357bf5ccfa17605a86309c5742cb828dd2e52eb9bb2839096f594e1e75fef80e81b
7
- data.tar.gz: f085f1dcc7a3d861da1b28a0d07f3338f03dd5b27cdd234c283cecf0bce8a0dc66f26193755ea8f5b442cbf4953fb2bd4ce295f90257b76121ac7fdbcbdd38b0
6
+ metadata.gz: 003b70dbe21e80655ebfe6eae9e0260137a3f6e3e478200c04eefbc238ae72d8d172b62c4d980a934fd56a08eb7d2ad59d93b4d762a3c019e88d3e2e6cc39d46
7
+ data.tar.gz: 6c4ada87361e89edff1b8fe7353389861c3748986631ad9693d01f148c71fb2dbe06547b318d94c3247dc584081c047fc915f5d1d014d6026172b8cf406b5753
@@ -29,10 +29,7 @@ module TShield
29
29
  # generated directory
30
30
  #
31
31
  attr_reader :request
32
- attr_reader :domains
33
- attr_reader :tcp_servers
34
- attr_reader :session_path
35
- attr_reader :windows_compatibility
32
+ attr_reader :domains, :tcp_servers, :session_path, :windows_compatibility
36
33
 
37
34
  def initialize(attributes)
38
35
  attributes.each { |key, value| instance_variable_set("@#{key}", value) }
@@ -106,6 +103,7 @@ module TShield
106
103
 
107
104
  def send_header_content_type(domain)
108
105
  return domains[domain]['send_header_content_type'] != false if domains[domain]
106
+
109
107
  true
110
108
  end
111
109
 
@@ -140,6 +138,5 @@ module TShield
140
138
  def get_delay(domain, path)
141
139
  ((domains[domain] || {})['delay'] || {})[path] || 0
142
140
  end
143
-
144
141
  end
145
142
  end
@@ -114,7 +114,6 @@ module TShield
114
114
  logger.info("Response with delay of #{delay_in_seconds} seconds")
115
115
  sleep delay_in_seconds
116
116
  end
117
-
118
117
  end
119
118
  end
120
119
  end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TShield
4
+ # Increment counter for sessions requests
5
+ class GrpcCounter
6
+ def initialize
7
+ @requests = {}
8
+ end
9
+
10
+ def add(hexdigest)
11
+ count = @requests.fetch(hexdigest, 0)
12
+ count += 1
13
+ @requests[hexdigest] = count
14
+ end
15
+
16
+ def current(hexdigest)
17
+ @requests.fetch(hexdigest, 0)
18
+ end
19
+
20
+ def to_json(options = {})
21
+ @requests.to_json(options)
22
+ end
23
+ end
24
+ end
@@ -5,79 +5,127 @@ require 'tshield/sessions'
5
5
 
6
6
  module TShield
7
7
  module Grpc
8
+ # Grpc vcr module
8
9
  module VCR
10
+ # Path file to save Grpc request/response
11
+ class FilePath
12
+ attr_reader :path, :count
13
+
14
+ def initialize(path, count)
15
+ @path = path
16
+ @count = count
17
+ end
18
+ end
19
+
9
20
  def initialize
10
21
  @configuration = TShield::Configuration.singleton
11
22
  end
23
+
12
24
  def handler_in_vcr_mode(method_name, request, parameters, options)
13
25
  parameters.peer =~ /ipv6:\[(.+?)\]|ipv4:(.+?):/
14
26
  peer = Regexp.last_match(1) || Regexp.last_match(2)
15
27
 
16
28
  TShield.logger.info("request from #{parameters.peer}")
17
29
  @session = TShield::Sessions.current(peer)
30
+ @digest = hexdigest(request)
31
+ counter = @session ? request_count.current(@digest) : 0
18
32
 
19
33
  TShield.logger.info("grpc using session #{@session || 'default'}")
20
34
  module_name = options['module']
21
35
 
22
- path = create_destiny(module_name, method_name, request)
23
- save_request(path, request)
24
- response = saved_response(path)
25
- if response
26
- TShield.logger.info("returning saved response for request #{request.to_json} saved into #{hexdigest(request)}")
27
- return response
36
+ path = create_destiny(module_name, method_name)
37
+ @file_path = FilePath.new(path, counter)
38
+ save_request(request)
39
+ response = {}
40
+ saved_error
41
+ begin
42
+ response = saved_response
43
+ if response
44
+ TShield.logger.info("returning saved response for request #{request.to_json} saved into #{@digest}")
45
+ request_count.add(@digest) if @session
46
+ return response
47
+ end
48
+
49
+ response = send_request(request, module_name, options, method_name)
50
+ save_response(response)
51
+ rescue GRPC::BadStatus => e
52
+ save_error({ code: e.code, details: e.details })
53
+ raise e
28
54
  end
55
+ request_count.add(@digest) if @session
56
+ response
57
+ end
29
58
 
59
+ def send_request(request, module_name, options, method_name)
30
60
  TShield.logger.info("calling server to get response for #{request.to_json}")
31
61
  client_class = Object.const_get("#{module_name}::Stub")
32
62
  client_instance = client_class.new(options['hostname'], :this_channel_is_insecure)
33
- response = client_instance.send(method_name, request)
34
- save_response(path, response)
35
- response
63
+ client_instance.send(method_name, request)
64
+ end
65
+
66
+ def request_count
67
+ @session[:grpc_counter]
36
68
  end
37
69
 
38
70
  def encode_colon(value)
39
- value.gsub(':','%3a')
71
+ value.gsub(':', '%3a')
40
72
  end
41
73
 
42
- def saved_response(path)
43
- response_file = File.join(path, 'response')
74
+ def saved_response
75
+ response_file = File.join(@file_path.path, "#{@file_path.count}.response")
44
76
  return false unless File.exist? response_file
45
77
 
46
78
  content = JSON.parse File.open(response_file).read
47
- response_class = File.open(File.join(path, 'response_class')).read.strip
79
+ response_class = File.open(File.join(@file_path.path, "#{@file_path.count}.response_class")).read.strip
48
80
  Kernel.const_get(response_class).new(content)
49
81
  end
50
82
 
51
- def save_request(path, request)
52
- file = File.open(File.join(path, 'original_request'), 'w')
83
+ def saved_error
84
+ error_file = File.join(@file_path.path, "#{@file_path.count}.error")
85
+ return false unless File.exist? error_file
86
+
87
+ request_count.add(@digest) if @session
88
+ content = JSON.parse File.open(error_file).read
89
+ grpc_error = GRPC::BadStatus.new(content['code'], content['details'])
90
+ raise grpc_error
91
+ end
92
+
93
+ def save_request(request)
94
+ file = File.open(File.join(@file_path.path, "#{@file_path.count}.original_request"), 'w')
53
95
  file.puts request.to_json
54
96
  file.close
55
97
  end
56
98
 
57
- def save_response(path, response)
58
- file = File.open(File.join(path, 'response'), 'w')
99
+ def save_error(error)
100
+ file = File.open(File.join(@file_path.path, "#{@file_path.count}.error"), 'w')
101
+ file.puts error.to_json
102
+ file.close
103
+ request_count.add(@digest) if @session
104
+ end
105
+
106
+ def save_response(response)
107
+ file = File.open(File.join(@file_path.path, "#{@file_path.count}.response"), 'w')
59
108
  file.puts response.to_json
60
109
  file.close
61
110
 
62
- response_class = File.open(File.join(path, 'response_class'), 'w')
111
+ response_class = File.open(File.join(@file_path.path, "#{@file_path.count}.response_class"), 'w')
63
112
  response_class.puts response.class.to_s
64
113
  response_class.close
65
114
  end
66
115
 
67
- def complete_path(module_name, method_name, request)
116
+ def complete_path(module_name, method_name)
68
117
  @session_name = (@session || {})[:name]
69
118
  module_name = @configuration.windows_compatibility? ? encode_colon(module_name) : module_name
70
- path = ['requests', 'grpc', @session_name, module_name, method_name.to_s, hexdigest(request)].compact
71
- path
119
+ ['requests', @session_name, module_name, method_name.to_s, @digest].compact
72
120
  end
73
121
 
74
- def create_destiny(module_name, method_name, request)
122
+ def create_destiny(module_name, method_name)
75
123
  current_path = []
76
124
 
77
- path = complete_path(module_name, method_name, request)
125
+ path = complete_path(module_name, method_name)
78
126
  TShield.logger.info("using path #{path}")
79
- path.each do |path|
80
- current_path << path
127
+ path.each do |inner_path|
128
+ current_path << inner_path
81
129
  destiny = File.join current_path
82
130
  Dir.mkdir destiny unless File.exist? destiny
83
131
  end
data/lib/tshield/grpc.rb CHANGED
@@ -4,7 +4,6 @@ require 'grpc'
4
4
 
5
5
  require 'tshield/configuration'
6
6
  require 'tshield/grpc/vcr'
7
-
8
7
  module TShield
9
8
  module Grpc
10
9
  module RequestHandler
@@ -14,6 +13,7 @@ module TShield
14
13
  handler_in_vcr_mode(method_name, request, parameters, options)
15
14
  end
16
15
  end
16
+
17
17
  def self.run!
18
18
  @configuration = TShield::Configuration.singleton.grpc
19
19
 
@@ -41,6 +41,7 @@ module TShield
41
41
  handlers = []
42
42
  number_of_handlers = 0
43
43
  services.each do |file, options|
44
+
44
45
  require file
45
46
 
46
47
  base = Object.const_get("#{options['module']}::Service")
@@ -55,8 +56,7 @@ module TShield
55
56
  def self.build_handler(base, descriptions, number_of_handlers, options)
56
57
  handler = Class.new(base) do
57
58
  class << self
58
- attr_writer :options
59
- attr_reader :options
59
+ attr_accessor :options
60
60
  end
61
61
  descriptions.each do |service_name, description|
62
62
  puts description
@@ -5,6 +5,6 @@ require 'logger'
5
5
  # Logger instance for application
6
6
  module TShield
7
7
  def self.logger
8
- @logger ||= Logger.new(STDOUT)
8
+ @logger ||= Logger.new($stdout)
9
9
  end
10
10
  end
@@ -79,7 +79,6 @@ module TShield
79
79
  end
80
80
 
81
81
  def apply_set_cookie_header_values(raw_response, headers = {})
82
-
83
82
  headers_clone = headers.clone
84
83
 
85
84
  field = raw_response.get_fields('Set-Cookie')
@@ -98,6 +97,7 @@ module TShield
98
97
 
99
98
  raw_response.headers.each do |k, v|
100
99
  next if k == 'set-cookie'
100
+
101
101
  headers[k] = v unless configuration.not_save_headers(domain).include? k
102
102
  end
103
103
 
@@ -156,9 +156,10 @@ module TShield
156
156
  end
157
157
 
158
158
  def encode_for_windows_dir(directory)
159
- replace = [['<','%3c'],['>','%3e'],[':','%3a'],['"','%22'],['?','%3f'],[' ','%20'],['*','%2a'],['/','%2f']]
159
+ replace = [['<', '%3c'], ['>', '%3e'], [':', '%3a'], ['"', '%22'], ['?', '%3f'], [' ', '%20'], ['*', '%2a'],
160
+ ['/', '%2f']]
160
161
  replace.each do |value|
161
- directory = directory.gsub(value.first,value.last)
162
+ directory = directory.gsub(value.first, value.last)
162
163
  end
163
164
  directory
164
165
  end
@@ -171,7 +172,7 @@ module TShield
171
172
  else
172
173
  directory = url.gsub(%r{/}, '-').gsub(/^-/, '')
173
174
  end
174
- configuration.windows_compatibility? ? encode_for_windows_dir(directory) : directory
175
+ configuration.windows_compatibility? ? encode_for_windows_dir(directory) : directory
175
176
  end
176
177
  end
177
178
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'tshield/logger'
4
4
  require 'tshield/counter'
5
+ require 'tshield/grpc/grpc_counter'
5
6
  require 'tshield/errors'
6
7
 
7
8
  module TShield
@@ -14,6 +15,7 @@ module TShield
14
15
  sessions[normalize_ip(ip)] = {
15
16
  name: name,
16
17
  counter: TShield::Counter.new,
18
+ grpc_counter: TShield::GrpcCounter.new,
17
19
  secondary_sessions: []
18
20
  }
19
21
  end
@@ -4,8 +4,8 @@ module TShield
4
4
  # Control version of gem
5
5
  class Version
6
6
  MAJOR = 0
7
- MINOR = 13
8
- PATCH = 5
7
+ MINOR = 14
8
+ PATCH = 0
9
9
  PRE = 0
10
10
 
11
11
  class << self
@@ -67,7 +67,7 @@ describe TShield::Configuration do
67
67
 
68
68
  describe 'SO compatibility' do
69
69
  it 'should be compatible with windows when configuration is true' do
70
- allow(YAML).to receive(:safe_load).and_return({:windows_compatibility => true })
70
+ allow(YAML).to receive(:safe_load).and_return({ windows_compatibility: true })
71
71
  TShield::Configuration.clear
72
72
  @configuration = TShield::Configuration.singleton
73
73
 
@@ -75,7 +75,7 @@ describe TShield::Configuration do
75
75
  end
76
76
 
77
77
  it 'should be compatible with Unix when configuration is false' do
78
- allow(YAML).to receive(:safe_load).and_return({:windows_compatibility => false })
78
+ allow(YAML).to receive(:safe_load).and_return({ windows_compatibility: false })
79
79
  TShield::Configuration.clear
80
80
  @configuration = TShield::Configuration.singleton
81
81
 
@@ -89,7 +89,6 @@ describe TShield::Configuration do
89
89
 
90
90
  expect(@configuration.windows_compatibility?).to eq(false)
91
91
  end
92
-
93
92
  end
94
93
  end
95
94
  context 'on config not exist' do
@@ -73,7 +73,6 @@ describe TShield::Controllers::Requests do
73
73
  allow(@configuration).to receive(:get_domain_for).and_return('example.org')
74
74
  allow(@configuration).to receive(:get_delay).and_return(0)
75
75
 
76
-
77
76
  allow(TShield::Options).to receive_message_chain(:instance, :break?)
78
77
  @mock_logger = double
79
78
  @controller = MockController.new(@mock_logger)
@@ -100,15 +99,15 @@ describe TShield::Controllers::Requests do
100
99
  allow(matched_response).to receive(:body).and_return('')
101
100
  allow(@mock_logger).to receive(:info)
102
101
 
103
- expect(TShield::RequestVCR).to receive(:new).with("/",{
104
- call: 0,
105
- headers: {},
106
- ip: "0.0.0.0",
107
- method: "GET",
108
- raw_query: "a=b",
109
- secondary_sessions: nil,
110
- session: nil
111
- })
102
+ expect(TShield::RequestVCR).to receive(:new).with('/', {
103
+ call: 0,
104
+ headers: {},
105
+ ip: '0.0.0.0',
106
+ method: 'GET',
107
+ raw_query: 'a=b',
108
+ secondary_sessions: nil,
109
+ session: nil
110
+ })
112
111
  @controller.treat(params, request, nil)
113
112
  end
114
113
  end
@@ -135,16 +134,15 @@ describe TShield::Controllers::Requests do
135
134
  allow(matched_response).to receive(:body).and_return('')
136
135
  allow(@mock_logger).to receive(:info)
137
136
 
138
- expect(TShield::RequestVCR).to receive(:new).with("/",{
139
- call: 0,
140
- headers: {'Content-Type' => 'application/json'},
141
- ip: "0.0.0.0",
142
- method: "GET",
143
- raw_query: "a=b",
144
- secondary_sessions: nil,
145
- session: nil
146
- })
147
-
137
+ expect(TShield::RequestVCR).to receive(:new).with('/', {
138
+ call: 0,
139
+ headers: { 'Content-Type' => 'application/json' },
140
+ ip: '0.0.0.0',
141
+ method: 'GET',
142
+ raw_query: 'a=b',
143
+ secondary_sessions: nil,
144
+ session: nil
145
+ })
148
146
 
149
147
  @controller.treat(params, request, nil)
150
148
  end
@@ -107,9 +107,9 @@ describe TShield::RequestVCR do
107
107
 
108
108
  it 'should create response directory in windows standard' do
109
109
  allow(@configuration).to receive(:domains).and_return(
110
- 'example.org' => {
111
- 'skip_query_params' => []
112
- }
110
+ 'example.org' => {
111
+ 'skip_query_params' => []
112
+ }
113
113
  )
114
114
 
115
115
  allow(@configuration).to receive(:windows_compatibility?).and_return(true)
@@ -118,28 +118,28 @@ describe TShield::RequestVCR do
118
118
  file_double = double
119
119
 
120
120
  allow(File).to receive(:join)
121
- .with('./requests/example.org', '%3fparam=value')
122
- .and_return('./requests/example.org/%3fparam=value')
121
+ .with('./requests/example.org', '%3fparam=value')
122
+ .and_return('./requests/example.org/%3fparam=value')
123
123
  allow(File).to receive(:join)
124
- .with('./requests/example.org/%3fparam=value', 'get')
125
- .and_return('./requests/example.org/%3fparam=value/get')
124
+ .with('./requests/example.org/%3fparam=value', 'get')
125
+ .and_return('./requests/example.org/%3fparam=value/get')
126
126
  allow(File).to receive(:join)
127
- .with('./requests/example.org/%3fparam=value/get', '0')
128
- .and_return('./requests/example.org/%3fparam=value/get/0')
127
+ .with('./requests/example.org/%3fparam=value/get', '0')
128
+ .and_return('./requests/example.org/%3fparam=value/get/0')
129
129
 
130
130
  allow(file_double).to receive(:read).and_return('{}')
131
131
 
132
132
  expect(File).to receive('open')
133
- .with('./requests/example.org/%3fparam=value/get/0.content', 'w')
134
- .and_return(file_double)
133
+ .with('./requests/example.org/%3fparam=value/get/0.content', 'w')
134
+ .and_return(file_double)
135
135
 
136
136
  expect(File).to receive('open')
137
- .with('./requests/example.org/%3fparam=value/get/0.json', 'w')
138
- .and_return(file_double)
137
+ .with('./requests/example.org/%3fparam=value/get/0.json', 'w')
138
+ .and_return(file_double)
139
139
 
140
140
  expect(file_double).to receive(:write).ordered.with('this is the body')
141
141
  expect(file_double).to receive(:write)
142
- .with("{\n \"status\": 200,\n \"headers\": {\n }\n}")
142
+ .with("{\n \"status\": 200,\n \"headers\": {\n }\n}")
143
143
  expect(file_double).to receive(:close)
144
144
  expect(file_double).to receive(:close)
145
145
 
@@ -148,7 +148,6 @@ describe TShield::RequestVCR do
148
148
  method: 'GET',
149
149
  call: 0
150
150
  end
151
-
152
151
  end
153
152
  end
154
153
 
@@ -161,7 +160,7 @@ describe TShield::RequestVCR do
161
160
  'this is the body'
162
161
  end
163
162
 
164
- def get_fields(field = "")
163
+ def get_fields(_field = '')
165
164
  []
166
165
  end
167
166
 
@@ -172,22 +171,19 @@ describe TShield::RequestVCR do
172
171
 
173
172
  class RawResponseCookiesMultipleValues
174
173
  def headers
175
- {'Set-Cookie' => ['FirstCookie=An Value', 'SecondCookie=An Value']}
174
+ { 'Set-Cookie' => ['FirstCookie=An Value', 'SecondCookie=An Value'] }
176
175
  end
177
176
 
178
177
  def body
179
178
  'this is the body'
180
179
  end
181
180
 
182
- def get_fields(field = "")
183
- self.headers[filed] unless self.headers.key?(field)
181
+ def get_fields(field = '')
182
+ headers[filed] unless headers.key?(field)
184
183
  end
185
184
 
186
185
  def code
187
186
  200
188
187
  end
189
188
  end
190
-
191
189
  end
192
-
193
-
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tshield
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.5.0
4
+ version: 0.14.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Diego Rubin
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2021-06-03 00:00:00.000000000 Z
12
+ date: 2021-10-18 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: grpc
@@ -415,6 +415,7 @@ files:
415
415
  - lib/tshield/errors.rb
416
416
  - lib/tshield/extensions/string_extensions.rb
417
417
  - lib/tshield/grpc.rb
418
+ - lib/tshield/grpc/grpc_counter.rb
418
419
  - lib/tshield/grpc/vcr.rb
419
420
  - lib/tshield/logger.rb
420
421
  - lib/tshield/matching/filters.rb
@@ -467,19 +468,19 @@ signing_key:
467
468
  specification_version: 4
468
469
  summary: Proxy for mocks API responses
469
470
  test_files:
470
- - spec/tshield/controllers/requests_spec.rb
471
+ - spec/spec_helper.rb
472
+ - spec/tshield/request_matching_spec.rb
473
+ - spec/tshield/sessions_spec.rb
474
+ - spec/tshield/request_vcr_spec.rb
471
475
  - spec/tshield/after_filter_spec.rb
472
- - spec/tshield/configuration_spec.rb
473
- - spec/tshield/fixtures/proto/test_services_pb.rb
476
+ - spec/tshield/grpc_spec.rb
477
+ - spec/tshield/options_spec.rb
474
478
  - spec/tshield/fixtures/config/tshield-without-grpc.yml
475
479
  - spec/tshield/fixtures/config/tshield-with-send-content-type-header_as_false.yml
476
- - spec/tshield/fixtures/config/tshield.yml
477
480
  - spec/tshield/fixtures/config/tshield-with-send-content-type-header.yml
481
+ - spec/tshield/fixtures/config/tshield.yml
482
+ - spec/tshield/fixtures/proto/test_services_pb.rb
478
483
  - spec/tshield/fixtures/matching/example.json
479
484
  - spec/tshield/fixtures/filters/example_filter.rb
480
- - spec/tshield/request_vcr_spec.rb
481
- - spec/tshield/sessions_spec.rb
482
- - spec/tshield/grpc_spec.rb
483
- - spec/tshield/options_spec.rb
484
- - spec/tshield/request_matching_spec.rb
485
- - spec/spec_helper.rb
485
+ - spec/tshield/controllers/requests_spec.rb
486
+ - spec/tshield/configuration_spec.rb