speakeasy_ruby_sdk 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +201 -0
- data/README.md +184 -0
- data/lib/speakeasy_ruby_sdk/config.rb +60 -0
- data/lib/speakeasy_ruby_sdk/har_builder.rb +242 -0
- data/lib/speakeasy_ruby_sdk/http_transaction.rb +122 -0
- data/lib/speakeasy_ruby_sdk/masker.rb +166 -0
- data/lib/speakeasy_ruby_sdk/time.rb +42 -0
- data/lib/speakeasy_ruby_sdk/url_utils.rb +24 -0
- data/lib/speakeasy_ruby_sdk/version.rb +3 -0
- data/lib/speakeasy_ruby_sdk.rb +112 -0
- data/test/bulk_test.rb +176 -0
- data/test/http_test.rb +32 -0
- data/test/masker_test.rb +124 -0
- data/test/testdata/captures_basic_request_and_no_response_body_input.json +15 -0
- data/test/testdata/captures_basic_request_and_no_response_body_output.json +61 -0
- data/test/testdata/captures_basic_request_and_response_input.json +21 -0
- data/test/testdata/captures_basic_request_and_response_output.json +70 -0
- data/test/testdata/captures_basic_request_and_response_with_different_content_types_input.json +22 -0
- data/test/testdata/captures_basic_request_and_response_with_different_content_types_output.json +74 -0
- data/test/testdata/captures_basic_request_and_response_with_no_response_header_set_input.json +21 -0
- data/test/testdata/captures_basic_request_and_response_with_no_response_header_set_output.json +70 -0
- data/test/testdata/captures_basic_request_with_nano_precision_input.json +23 -0
- data/test/testdata/captures_basic_request_with_nano_precision_output.json +70 -0
- data/test/testdata/captures_cookies_input.json +35 -0
- data/test/testdata/captures_cookies_output.json +165 -0
- data/test/testdata/captures_masked_request_response_input.json +73 -0
- data/test/testdata/captures_masked_request_response_output.json +156 -0
- data/test/testdata/captures_no_response_body_when_not_modified_input.json +17 -0
- data/test/testdata/captures_no_response_body_when_not_modified_output.json +60 -0
- data/test/testdata/captures_post_request_with_body_input.json +24 -0
- data/test/testdata/captures_post_request_with_body_output.json +81 -0
- data/test/testdata/captures_query_params_input.json +21 -0
- data/test/testdata/captures_query_params_output.json +75 -0
- data/test/testdata/captures_redirect_input.json +22 -0
- data/test/testdata/captures_redirect_output.json +74 -0
- data/test/testdata/drops_request_and_response_bodies_when_request_body_too_large_input.json +24 -0
- data/test/testdata/drops_request_and_response_bodies_when_request_body_too_large_output.json +81 -0
- data/test/testdata/drops_response_body_when_too_large_input.json +24 -0
- data/test/testdata/drops_response_body_when_too_large_output.json +81 -0
- metadata +240 -0
@@ -0,0 +1,112 @@
|
|
1
|
+
require_relative 'speakeasy_ruby_sdk/version'
|
2
|
+
require_relative 'speakeasy_ruby_sdk/config'
|
3
|
+
require_relative 'speakeasy_ruby_sdk/url_utils'
|
4
|
+
require_relative 'speakeasy_ruby_sdk/masker'
|
5
|
+
require_relative 'speakeasy_ruby_sdk/http_transaction'
|
6
|
+
require_relative 'speakeasy_ruby_sdk/har_builder'
|
7
|
+
require_relative 'speakeasy_ruby_sdk/time'
|
8
|
+
|
9
|
+
require "delegate"
|
10
|
+
|
11
|
+
require 'speakeasy_pb'
|
12
|
+
include Ingest
|
13
|
+
include Embedaccesstoken
|
14
|
+
|
15
|
+
module SpeakeasyRubySdk
|
16
|
+
class RouteWrapper < SimpleDelegator
|
17
|
+
def path
|
18
|
+
super.spec.to_s
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class Middleware
|
23
|
+
attr_accessor :ingest_client
|
24
|
+
attr_reader :config
|
25
|
+
|
26
|
+
def initialize(app, config=nil)
|
27
|
+
@config = Config.default.merge config
|
28
|
+
validation_errors = @config.validate
|
29
|
+
if validation_errors.length > 0
|
30
|
+
raise Exception.new validation_errors
|
31
|
+
end
|
32
|
+
@app = app
|
33
|
+
@masker = SpeakeasyRubySdk::Masker.new @config
|
34
|
+
credentials = GRPC::Core::ChannelCredentials.new()
|
35
|
+
@ingest_client = Ingest::IngestService::Stub.new(@config.ingestion_server_url, credentials)
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
def call(env)
|
40
|
+
if env.include? 'time_utils'
|
41
|
+
time_utils = env['time_utils']
|
42
|
+
else
|
43
|
+
time_utils = TimeUtils.new
|
44
|
+
end
|
45
|
+
|
46
|
+
status, response_headers, response_body = @app.call(env)
|
47
|
+
|
48
|
+
## If we are not in test, record the end time after calling the app
|
49
|
+
if !env.include? 'time_utils'
|
50
|
+
time_utils.set_end_time
|
51
|
+
end
|
52
|
+
|
53
|
+
http_transaction = HttpTransaction.new time_utils, env, status, response_headers, response_body, @masker
|
54
|
+
|
55
|
+
path_hint = ''
|
56
|
+
# todo - support other frameworks than rails
|
57
|
+
if @config.routes
|
58
|
+
req = ActionDispatch::Request.new(env)
|
59
|
+
found_route = nil
|
60
|
+
@config.routes.router.recognize(req) do |route, params|
|
61
|
+
found_route = route
|
62
|
+
end
|
63
|
+
if ! found_route.nil?
|
64
|
+
path_hint = RouteWrapper.new(found_route).path
|
65
|
+
end
|
66
|
+
end
|
67
|
+
if ! env[:path_hint].nil?
|
68
|
+
path_hint = env[:path_hint]
|
69
|
+
end
|
70
|
+
|
71
|
+
har_builder = HarBuilder.new @config
|
72
|
+
har = har_builder.construct_har http_transaction
|
73
|
+
|
74
|
+
request = Ingest::IngestRequest.new
|
75
|
+
request.api_id = @config.api_id
|
76
|
+
request.path_hint = path_hint
|
77
|
+
request.version_id = @config.version_id
|
78
|
+
if env.include? :customer_id
|
79
|
+
request.customer_id = env[:customer_id].to_s
|
80
|
+
end
|
81
|
+
request.har = har
|
82
|
+
|
83
|
+
metadata = {"x-api-key": @config.api_key}
|
84
|
+
response = @ingest_client.ingest(request, metadata: metadata)
|
85
|
+
|
86
|
+
[status, response_headers, response_body]
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.get_embedded_access_token key, operator, value, config=nil
|
91
|
+
if config.nil?
|
92
|
+
working_config = Middleware::Config.default
|
93
|
+
else
|
94
|
+
working_config = Middleware::Config.default.merge config
|
95
|
+
end
|
96
|
+
|
97
|
+
credentials = GRPC::Core::ChannelCredentials.new()
|
98
|
+
embed_client = Embedaccesstoken::EmbedAccessTokenService::Stub.new(working_config.ingestion_server_url, credentials)
|
99
|
+
request = Embedaccesstoken::EmbedAccessTokenRequest.new
|
100
|
+
|
101
|
+
filter = Embedaccesstoken::EmbedAccessTokenRequest::Filter.new
|
102
|
+
filter.key = key
|
103
|
+
filter.operator = operator
|
104
|
+
filter.value = value
|
105
|
+
|
106
|
+
request.filters.push filter
|
107
|
+
|
108
|
+
metadata = {"x-api-key": working_config.api_key}
|
109
|
+
response = embed_client.get(request, metadata: metadata)
|
110
|
+
|
111
|
+
end
|
112
|
+
end
|
data/test/bulk_test.rb
ADDED
@@ -0,0 +1,176 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'rack/test'
|
3
|
+
require 'json'
|
4
|
+
require 'ostruct'
|
5
|
+
require 'spy'
|
6
|
+
require 'timecop'
|
7
|
+
require_relative '../lib/speakeasy_ruby_sdk'
|
8
|
+
|
9
|
+
require 'speakeasy_pb'
|
10
|
+
include Ingest
|
11
|
+
|
12
|
+
def add_http_prefix header_dict
|
13
|
+
modified_headers = {}
|
14
|
+
for k, v in header_dict
|
15
|
+
modified_headers["HTTP_#{k}"] = v
|
16
|
+
end
|
17
|
+
modified_headers
|
18
|
+
end
|
19
|
+
|
20
|
+
def header_to_dict headers
|
21
|
+
modified_headers = {}
|
22
|
+
for d in headers
|
23
|
+
key = d['key']
|
24
|
+
if d['values'].length > 1
|
25
|
+
modified_headers[key] = d['values']
|
26
|
+
else
|
27
|
+
modified_headers[key] = d['values'][0]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
modified_headers
|
31
|
+
end
|
32
|
+
|
33
|
+
class BulkTest < Test::Unit::TestCase
|
34
|
+
include Rack::Test::Methods
|
35
|
+
|
36
|
+
def test_bulk
|
37
|
+
file_pairs = []
|
38
|
+
## Find all test files, and pair input and outputs
|
39
|
+
Dir.foreach("./test/testdata") do |file_name|
|
40
|
+
if file_name == "." || file_name == ".."
|
41
|
+
next
|
42
|
+
end
|
43
|
+
infile = nil
|
44
|
+
outfile = nil
|
45
|
+
if file_name.end_with?("input.json")
|
46
|
+
prefix_name = file_name.slice(0..-11)
|
47
|
+
output_filename = "#{prefix_name}output.json"
|
48
|
+
pair = OpenStruct.new
|
49
|
+
pair.infile = "./test/testdata/#{file_name}"
|
50
|
+
pair.outfile = "./test/testdata/#{output_filename}"
|
51
|
+
file_pairs << pair
|
52
|
+
end
|
53
|
+
end
|
54
|
+
for pair in file_pairs
|
55
|
+
input = JSON.parse(File.read(pair.infile))
|
56
|
+
puts "Testing #{pair.infile}, #{pair.outfile}"
|
57
|
+
config = {api_id: '123', version_id: '1.0'}
|
58
|
+
|
59
|
+
## Parse Masking Inputs
|
60
|
+
masking = []
|
61
|
+
if input['args'].include? 'query_string_masks'
|
62
|
+
for k, v in input['args']['query_string_masks']
|
63
|
+
masking << SpeakeasyRubySdk::MaskConfig.new(:query_params, [k], [v])
|
64
|
+
end
|
65
|
+
end
|
66
|
+
if input['args'].include? 'request_header_masks'
|
67
|
+
for k, v in input['args']['request_header_masks']
|
68
|
+
masking << SpeakeasyRubySdk::MaskConfig.new(:request_headers, [k], [v])
|
69
|
+
end
|
70
|
+
end
|
71
|
+
if input['args'].include? 'request_cookie_masks'
|
72
|
+
for k, v in input['args']['request_cookie_masks']
|
73
|
+
masking << SpeakeasyRubySdk::MaskConfig.new(:request_cookies, [k], [v])
|
74
|
+
end
|
75
|
+
end
|
76
|
+
if input['args'].include? 'request_field_masks_string'
|
77
|
+
for k, v in input['args']['request_field_masks_string']
|
78
|
+
masking << SpeakeasyRubySdk::MaskConfig.new(:request_body_string, [k], [v])
|
79
|
+
end
|
80
|
+
end
|
81
|
+
if input['args'].include? 'request_field_masks_number'
|
82
|
+
for k, v in input['args']['request_field_masks_number']
|
83
|
+
masking << SpeakeasyRubySdk::MaskConfig.new(:request_body_number, [k], [v])
|
84
|
+
end
|
85
|
+
end
|
86
|
+
if input['args'].include? 'response_header_masks'
|
87
|
+
for k, v in input['args']['response_header_masks']
|
88
|
+
masking << SpeakeasyRubySdk::MaskConfig.new(:response_headers, [k], [v])
|
89
|
+
end
|
90
|
+
end
|
91
|
+
if input['args'].include? 'response_cookie_masks'
|
92
|
+
for k, v in input['args']['response_cookie_masks']
|
93
|
+
masking << SpeakeasyRubySdk::MaskConfig.new(:response_cookies, [k], [v])
|
94
|
+
end
|
95
|
+
end
|
96
|
+
if input['args'].include? 'response_field_masks_string'
|
97
|
+
for k, v in input['args']['response_field_masks_string']
|
98
|
+
masking << SpeakeasyRubySdk::MaskConfig.new(:response_body_string, [k], [v])
|
99
|
+
end
|
100
|
+
end
|
101
|
+
if input['args'].include? 'response_field_masks_number'
|
102
|
+
for k, v in input['args']['response_field_masks_number']
|
103
|
+
masking << SpeakeasyRubySdk::MaskConfig.new(:response_body_number, [k], [v])
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
config[:masking] = masking
|
108
|
+
|
109
|
+
|
110
|
+
if input['fields'].include? 'max_capture_size'
|
111
|
+
config[:max_capture_size] = input['fields']['max_capture_size']
|
112
|
+
end
|
113
|
+
|
114
|
+
response_status = input['args']['response_status']
|
115
|
+
|
116
|
+
if input['args'].include? 'response_headers'
|
117
|
+
input['args']['response_headers'] = header_to_dict(input['args']['response_headers'])
|
118
|
+
else
|
119
|
+
input['args']['response_headers'] = {}
|
120
|
+
end
|
121
|
+
|
122
|
+
def simple_app input
|
123
|
+
->(_env) { [input['args']['response_status'], input['args']['response_headers'], input['args']['response_body']]}
|
124
|
+
end
|
125
|
+
|
126
|
+
opts = {
|
127
|
+
"SERVER_PROTOCOL" => 'HTTP/1.1'
|
128
|
+
}
|
129
|
+
if input['args'].include? 'method'
|
130
|
+
opts[:method] = input['args']['method']
|
131
|
+
end
|
132
|
+
if input['args'].include? 'headers'
|
133
|
+
opts = opts.merge add_http_prefix(header_to_dict(input['args']['headers']))
|
134
|
+
end
|
135
|
+
|
136
|
+
if input['args'].include? 'request_start_time'
|
137
|
+
start_time = Time.parse(input['args']['request_start_time'])
|
138
|
+
else
|
139
|
+
start_time = Time.utc(2020, 1, 1, 0, 0, 0)
|
140
|
+
end
|
141
|
+
|
142
|
+
if input['args'].include? 'elapsed_time'
|
143
|
+
elapsed_time = input['args']['elapsed_time']
|
144
|
+
else
|
145
|
+
elapsed_time = 1
|
146
|
+
end
|
147
|
+
|
148
|
+
opts['time_utils'] = SpeakeasyRubySdk::TimeUtils.new(start_time, elapsed_time)
|
149
|
+
|
150
|
+
## override Time.now for the cookie maxTime handling
|
151
|
+
Timecop.freeze(2020, 1, 1, 0, 0, 0)
|
152
|
+
|
153
|
+
if input['args'].include? 'body'
|
154
|
+
rack_input = StringIO.open(input['args']['body'])
|
155
|
+
opts[:input] = rack_input
|
156
|
+
end
|
157
|
+
request = Rack::MockRequest.env_for(input['args']['url'], opts)
|
158
|
+
|
159
|
+
subject = SpeakeasyRubySdk::Middleware.new(simple_app(input), config)
|
160
|
+
subject.ingest_client = Spy.mock(Ingest::IngestService::Stub)
|
161
|
+
|
162
|
+
spy = Spy.on(subject.ingest_client, :ingest).and_return(nil)
|
163
|
+
|
164
|
+
status, _headers, _response = subject.call(request)
|
165
|
+
|
166
|
+
har = JSON.parse(spy.calls.first.args[0].har)
|
167
|
+
output = JSON.parse(File.read(pair.outfile))
|
168
|
+
|
169
|
+
assert_equal(har, output)
|
170
|
+
|
171
|
+
## reset time mock
|
172
|
+
Timecop.return
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
data/test/http_test.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'rack/test'
|
3
|
+
require 'json'
|
4
|
+
require_relative '../lib/speakeasy_ruby_sdk'
|
5
|
+
|
6
|
+
class BasicHttpTest < Test::Unit::TestCase
|
7
|
+
include Rack::Test::Methods
|
8
|
+
|
9
|
+
def simple_app
|
10
|
+
->(_env) { [200, { 'content-type' => 'text/javascript' }, ActionDispatch::Response::RackBody.new(['All responses are OK'])] }
|
11
|
+
end
|
12
|
+
|
13
|
+
def fuller_app
|
14
|
+
->(_env) { [200, {"X-Frame-Options"=>"SAMEORIGIN", "X-XSS-Protection"=>"0", "X-Content-Type-Options"=>"nosniff", "X-Download-Options"=>"noopen", "X-Permitted-Cross-Domain-Policies"=>"none", "Referrer-Policy"=>"strict-origin-when-cross-origin", "Content-Type"=>"application/json; charset=utf-8"}, ActionDispatch::Response::RackBody.new]}
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_response_is_unchanged
|
18
|
+
request = Rack::MockRequest.env_for('/', method: :get)
|
19
|
+
|
20
|
+
subject = SpeakeasyRubySdk::Middleware.new(simple_app)
|
21
|
+
status, _headers, _response = subject.call(request)
|
22
|
+
assert_equal status, 200
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_full_request
|
26
|
+
request = Rack::MockRequest.env_for('/', method: :get)
|
27
|
+
subject = SpeakeasyRubySdk::Middleware.new(fuller_app)
|
28
|
+
status, _headers, _response = subject.call(request)
|
29
|
+
assert_equal status, 200
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
data/test/masker_test.rb
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'rack/test'
|
3
|
+
require 'json'
|
4
|
+
require_relative '../lib/speakeasy_ruby_sdk'
|
5
|
+
|
6
|
+
class MaskerTest < Test::Unit::TestCase
|
7
|
+
include Rack::Test::Methods
|
8
|
+
|
9
|
+
def self.init_masker config
|
10
|
+
config = SpeakeasyRubySdk::Middleware::Config.default.merge config
|
11
|
+
SpeakeasyRubySdk::Masker.new config
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_mask_query_param_simple
|
15
|
+
masker_config = {
|
16
|
+
routes: nil,
|
17
|
+
masking: [SpeakeasyRubySdk::MaskConfig.new(:query_params, 'carrot')]
|
18
|
+
}
|
19
|
+
masker = MaskerTest::init_masker(masker_config)
|
20
|
+
|
21
|
+
query_params = {'carrot': 'stick', 'parsnip': 'triangular'}
|
22
|
+
|
23
|
+
masked_params = masker.mask_query_params '', query_params
|
24
|
+
|
25
|
+
assert_equal(SpeakeasyRubySdk::Masker::SIMPLE_MASK, masked_params[:carrot])
|
26
|
+
assert_equal(query_params[:parsnip], masked_params[:parsnip]) # Should be unchanged
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_mask_query_param_multiple_attrs
|
30
|
+
masker_config = {
|
31
|
+
routes: nil,
|
32
|
+
masking: [SpeakeasyRubySdk::MaskConfig.new(:query_params, ['carrot', 'parsnip', 'unknown'])]
|
33
|
+
}
|
34
|
+
masker = MaskerTest::init_masker(masker_config)
|
35
|
+
|
36
|
+
query_params = {'carrot': 'stick', 'parsnip': 'triangular'}
|
37
|
+
|
38
|
+
masked_params = masker.mask_query_params '', query_params
|
39
|
+
|
40
|
+
assert_equal(SpeakeasyRubySdk::Masker::SIMPLE_MASK, masked_params[:carrot])
|
41
|
+
assert_equal(SpeakeasyRubySdk::Masker::SIMPLE_MASK, masked_params[:parsnip])
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_mask_query_param_custom_mask
|
45
|
+
masker_config = {
|
46
|
+
routes: nil,
|
47
|
+
masking: [SpeakeasyRubySdk::MaskConfig.new(:query_params, ['carrot'], ['__MASK__'])]
|
48
|
+
}
|
49
|
+
masker = MaskerTest::init_masker(masker_config)
|
50
|
+
|
51
|
+
query_params = {'carrot': 'stick', 'parsnip': 'triangular'}
|
52
|
+
|
53
|
+
masked_params = masker.mask_query_params '', query_params
|
54
|
+
|
55
|
+
assert_equal("__MASK__", masked_params[:carrot])
|
56
|
+
assert_equal(query_params[:parsnip], masked_params[:parsnip]) # Should be unchanged
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
def test_mask_response_cookies_simple
|
61
|
+
masker_config = {
|
62
|
+
masking: [SpeakeasyRubySdk::MaskConfig.new(:response_cookies, ['magic'])]
|
63
|
+
}
|
64
|
+
masker = MaskerTest::init_masker(masker_config)
|
65
|
+
|
66
|
+
response_cookies = HTTP::Cookie.parse("magic=itsnotmagic; path=/; max-age=86400; SameSite=Lax", 'http://localhost:8000')
|
67
|
+
|
68
|
+
masked_cookies = masker.mask_response_cookies '', response_cookies
|
69
|
+
|
70
|
+
first_cookie = masked_cookies[0]
|
71
|
+
|
72
|
+
assert_equal(SpeakeasyRubySdk::Masker::SIMPLE_MASK, first_cookie.value)
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_mask_body_string_simple
|
77
|
+
masker_config = {
|
78
|
+
masking: [SpeakeasyRubySdk::MaskConfig.new(:request_body_string, ['sign_in'])]
|
79
|
+
}
|
80
|
+
masker = MaskerTest::init_masker(masker_config)
|
81
|
+
|
82
|
+
body = {'sign_in': 'wiley', 'nobody': 'somebody'}.to_json
|
83
|
+
|
84
|
+
masked_body = masker.mask_request_body('', body)
|
85
|
+
assert !masked_body.include?('wiley')
|
86
|
+
assert masked_body.include?('somebody')
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_mask_body_number_simple
|
90
|
+
masker_config = {
|
91
|
+
masking: [SpeakeasyRubySdk::MaskConfig.new(:request_body_number, ['sign_in'])]
|
92
|
+
}
|
93
|
+
masker = MaskerTest::init_masker(masker_config)
|
94
|
+
|
95
|
+
body = {
|
96
|
+
'sign_in': 5476,
|
97
|
+
'nobody': 'somebody'
|
98
|
+
}.to_json
|
99
|
+
masked_body = masker.mask_request_body('', body)
|
100
|
+
assert ! masked_body.include?('5476')
|
101
|
+
assert masked_body.include?('somebody')
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_mask_body_number_and_string
|
105
|
+
masker_config = {
|
106
|
+
masking: [
|
107
|
+
SpeakeasyRubySdk::MaskConfig.new(:request_body_number, ['attr1']),
|
108
|
+
SpeakeasyRubySdk::MaskConfig.new(:request_body_string, ['attr2']),
|
109
|
+
]
|
110
|
+
}
|
111
|
+
masker = MaskerTest::init_masker(masker_config)
|
112
|
+
|
113
|
+
body = {
|
114
|
+
'attr1': 5476,
|
115
|
+
'attr2': 'somebody',
|
116
|
+
'attr3': 'keep it'
|
117
|
+
}.to_json
|
118
|
+
|
119
|
+
masked_body = masker.mask_request_body('', body)
|
120
|
+
assert !masked_body.include?('5476')
|
121
|
+
assert !masked_body.include?('somebody')
|
122
|
+
assert masked_body.include?('keep it')
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
{
|
2
|
+
"name": "captures basic request and no response body",
|
3
|
+
"fields": {
|
4
|
+
"max_capture_size": 9437184
|
5
|
+
},
|
6
|
+
"args": {
|
7
|
+
"method": "GET",
|
8
|
+
"url": "http://test.com:8080/test",
|
9
|
+
"headers": [
|
10
|
+
{ "key": "Host", "values": ["test.com"] },
|
11
|
+
{ "key": "Accept-Encoding", "values": ["gzip, deflate"] },
|
12
|
+
{ "key": "Connection", "values": ["close"] }
|
13
|
+
]
|
14
|
+
}
|
15
|
+
}
|
@@ -0,0 +1,61 @@
|
|
1
|
+
{
|
2
|
+
"log": {
|
3
|
+
"version": "1.2",
|
4
|
+
"creator": {
|
5
|
+
"name": "SpeakeasyRubySdk",
|
6
|
+
"version": "0.0.1"
|
7
|
+
},
|
8
|
+
"entries": [
|
9
|
+
{
|
10
|
+
"startedDateTime": "2020-01-01T00:00:00.000000000Z",
|
11
|
+
"time": 1,
|
12
|
+
"request": {
|
13
|
+
"method": "GET",
|
14
|
+
"url": "http://test.com:8080/test",
|
15
|
+
"httpVersion": "HTTP/1.1",
|
16
|
+
"cookies": [],
|
17
|
+
"headers": [
|
18
|
+
{
|
19
|
+
"name": "accept-encoding",
|
20
|
+
"value": "gzip, deflate"
|
21
|
+
},
|
22
|
+
{
|
23
|
+
"name": "connection",
|
24
|
+
"value": "close"
|
25
|
+
},
|
26
|
+
{
|
27
|
+
"name": "host",
|
28
|
+
"value": "test.com"
|
29
|
+
}
|
30
|
+
],
|
31
|
+
"queryString": [],
|
32
|
+
"headersSize": 67,
|
33
|
+
"bodySize": -1
|
34
|
+
},
|
35
|
+
"response": {
|
36
|
+
"status": 200,
|
37
|
+
"statusText": "OK",
|
38
|
+
"httpVersion": "HTTP/1.1",
|
39
|
+
"cookies": [],
|
40
|
+
"headers": [],
|
41
|
+
"content": {
|
42
|
+
"size": -1,
|
43
|
+
"mimeType": "application/octet-stream"
|
44
|
+
},
|
45
|
+
"redirectURL": "",
|
46
|
+
"headersSize": 0,
|
47
|
+
"bodySize": -1
|
48
|
+
},
|
49
|
+
"cache": {},
|
50
|
+
"timings": {
|
51
|
+
"send": -1,
|
52
|
+
"wait": -1,
|
53
|
+
"receive": -1
|
54
|
+
},
|
55
|
+
"serverIPAddress": "test.com",
|
56
|
+
"connection": "8080"
|
57
|
+
}
|
58
|
+
],
|
59
|
+
"comment": "request capture for http://test.com:8080/test"
|
60
|
+
}
|
61
|
+
}
|
@@ -0,0 +1,21 @@
|
|
1
|
+
{
|
2
|
+
"name": "captures basic request and response",
|
3
|
+
"fields": {
|
4
|
+
"max_capture_size": 9437184
|
5
|
+
},
|
6
|
+
"args": {
|
7
|
+
"method": "GET",
|
8
|
+
"url": "http://test.com/test",
|
9
|
+
"response_status": 200,
|
10
|
+
"response_body": "test",
|
11
|
+
"headers": [
|
12
|
+
{ "key": "Host", "values": ["test.com"] },
|
13
|
+
{ "key": "Accept-Encoding", "values": ["gzip, deflate"] },
|
14
|
+
{ "key": "Connection", "values": ["close"] }
|
15
|
+
],
|
16
|
+
"response_headers": [
|
17
|
+
{ "key": "Content-Type", "values": ["text/html; charset=utf-8"] },
|
18
|
+
{ "key": "Content-Length", "values": ["4"] }
|
19
|
+
]
|
20
|
+
}
|
21
|
+
}
|
@@ -0,0 +1,70 @@
|
|
1
|
+
{
|
2
|
+
"log": {
|
3
|
+
"version": "1.2",
|
4
|
+
"creator": {
|
5
|
+
"name": "SpeakeasyRubySdk",
|
6
|
+
"version": "0.0.1"
|
7
|
+
},
|
8
|
+
"entries": [
|
9
|
+
{
|
10
|
+
"startedDateTime": "2020-01-01T00:00:00.000000000Z",
|
11
|
+
"time": 1,
|
12
|
+
"request": {
|
13
|
+
"method": "GET",
|
14
|
+
"url": "http://test.com/test",
|
15
|
+
"httpVersion": "HTTP/1.1",
|
16
|
+
"cookies": [],
|
17
|
+
"headers": [
|
18
|
+
{
|
19
|
+
"name": "accept-encoding",
|
20
|
+
"value": "gzip, deflate"
|
21
|
+
},
|
22
|
+
{
|
23
|
+
"name": "connection",
|
24
|
+
"value": "close"
|
25
|
+
},
|
26
|
+
{
|
27
|
+
"name": "host",
|
28
|
+
"value": "test.com"
|
29
|
+
}
|
30
|
+
],
|
31
|
+
"queryString": [],
|
32
|
+
"headersSize": 67,
|
33
|
+
"bodySize": -1
|
34
|
+
},
|
35
|
+
"response": {
|
36
|
+
"status": 200,
|
37
|
+
"statusText": "OK",
|
38
|
+
"httpVersion": "HTTP/1.1",
|
39
|
+
"cookies": [],
|
40
|
+
"headers": [
|
41
|
+
{
|
42
|
+
"name": "content-length",
|
43
|
+
"value": "4"
|
44
|
+
},
|
45
|
+
{
|
46
|
+
"name": "content-type",
|
47
|
+
"value": "text/html; charset=utf-8"
|
48
|
+
}
|
49
|
+
],
|
50
|
+
"content": {
|
51
|
+
"size": 4,
|
52
|
+
"mimeType": "text/html; charset=utf-8",
|
53
|
+
"text": "test"
|
54
|
+
},
|
55
|
+
"redirectURL": "",
|
56
|
+
"headersSize": 59,
|
57
|
+
"bodySize": 4
|
58
|
+
},
|
59
|
+
"cache": {},
|
60
|
+
"timings": {
|
61
|
+
"send": -1,
|
62
|
+
"wait": -1,
|
63
|
+
"receive": -1
|
64
|
+
},
|
65
|
+
"serverIPAddress": "test.com"
|
66
|
+
}
|
67
|
+
],
|
68
|
+
"comment": "request capture for http://test.com/test"
|
69
|
+
}
|
70
|
+
}
|
data/test/testdata/captures_basic_request_and_response_with_different_content_types_input.json
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
{
|
2
|
+
"name": "captures basic request and response with different content types",
|
3
|
+
"fields": {
|
4
|
+
"max_capture_size": 9437184
|
5
|
+
},
|
6
|
+
"args": {
|
7
|
+
"method": "GET",
|
8
|
+
"url": "http://test.com/test",
|
9
|
+
"headers": [
|
10
|
+
{ "key": "Content-Type", "values": ["application/json"] },
|
11
|
+
{ "key": "Host", "values": ["test.com"] },
|
12
|
+
{ "key": "Accept-Encoding", "values": ["gzip, deflate"] },
|
13
|
+
{ "key": "Connection", "values": ["close"] }
|
14
|
+
],
|
15
|
+
"response_status": -1,
|
16
|
+
"response_body": "test",
|
17
|
+
"response_headers": [
|
18
|
+
{ "key": "Content-Type", "values": ["text/plain; charset=utf-8"] },
|
19
|
+
{ "key": "Content-Length", "values": ["4"] }
|
20
|
+
]
|
21
|
+
}
|
22
|
+
}
|