stoobly-agent 0.29.2__py3-none-any.whl → 0.30.1__py3-none-any.whl

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 (33) hide show
  1. stoobly_agent/__init__.py +1 -1
  2. stoobly_agent/app/cli/config_cli.py +64 -14
  3. stoobly_agent/app/cli/helpers/openapi_endpoint_adapter.py +79 -8
  4. stoobly_agent/app/proxy/handle_mock_service.py +1 -1
  5. stoobly_agent/app/proxy/handle_replay_service.py +2 -1
  6. stoobly_agent/app/proxy/intercept_settings.py +20 -16
  7. stoobly_agent/app/proxy/mitmproxy/request_facade.py +41 -35
  8. stoobly_agent/app/proxy/mitmproxy/response_facade.py +0 -11
  9. stoobly_agent/app/proxy/record/join_request_service.py +1 -1
  10. stoobly_agent/app/proxy/replay/rewrite_params_service.py +1 -1
  11. stoobly_agent/app/settings/rewrite_rule.py +13 -0
  12. stoobly_agent/app/settings/types/__init__.py +1 -6
  13. stoobly_agent/app/settings/types/proxy_settings.py +6 -0
  14. stoobly_agent/app/settings/url_rule.py +33 -0
  15. stoobly_agent/config/schema.yml +7 -1
  16. stoobly_agent/lib/orm/request.py +8 -4
  17. stoobly_agent/public/18-es2015.46d337c47cb41abec8ad.js +1 -0
  18. stoobly_agent/public/18-es5.46d337c47cb41abec8ad.js +1 -0
  19. stoobly_agent/public/dashboard.agent-alpha-0.30.0.tar.gz +0 -0
  20. stoobly_agent/public/index.html +1 -1
  21. stoobly_agent/public/runtime-es2015.3a15c6ce90c8f8cce796.js +1 -0
  22. stoobly_agent/public/runtime-es5.3a15c6ce90c8f8cce796.js +1 -0
  23. {stoobly_agent-0.29.2.dist-info → stoobly_agent-0.30.1.dist-info}/METADATA +1 -1
  24. {stoobly_agent-0.29.2.dist-info → stoobly_agent-0.30.1.dist-info}/RECORD +28 -27
  25. stoobly_agent/public/18-es2015.750ef954bde422debcb6.js +0 -1
  26. stoobly_agent/public/18-es5.750ef954bde422debcb6.js +0 -1
  27. stoobly_agent/public/dashboard.agent-alpha-0.29.0.tar.gz +0 -0
  28. stoobly_agent/public/runtime-es2015.b392473c492ce4cf1cb5.js +0 -1
  29. stoobly_agent/public/runtime-es5.b392473c492ce4cf1cb5.js +0 -1
  30. {stoobly_agent-0.29.2.dist-info → stoobly_agent-0.30.1.dist-info}/LICENSE +0 -0
  31. {stoobly_agent-0.29.2.dist-info → stoobly_agent-0.30.1.dist-info}/WHEEL +0 -0
  32. {stoobly_agent-0.29.2.dist-info → stoobly_agent-0.30.1.dist-info}/entry_points.txt +0 -0
  33. {stoobly_agent-0.29.2.dist-info → stoobly_agent-0.30.1.dist-info}/top_level.txt +0 -0
stoobly_agent/__init__.py CHANGED
@@ -1,2 +1,2 @@
1
1
  COMMAND = 'stoobly-agent'
2
- VERSION = '0.29.2'
2
+ VERSION = '0.30.1'
@@ -8,7 +8,7 @@ from stoobly_agent.app.settings import Settings
8
8
  from stoobly_agent.app.settings.constants import firewall_action, request_component
9
9
  from stoobly_agent.app.settings.firewall_rule import FirewallRule
10
10
  from stoobly_agent.app.settings.match_rule import MatchRule
11
- from stoobly_agent.app.settings.rewrite_rule import ParameterRule, RewriteRule
11
+ from stoobly_agent.app.settings.rewrite_rule import ParameterRule, RewriteRule, UrlRule
12
12
  from stoobly_agent.config.constants import mode
13
13
  from stoobly_agent.config.data_dir import DataDir
14
14
  from stoobly_agent.lib.api.keys import ProjectKey, ScenarioKey
@@ -146,6 +146,7 @@ def rewrite(ctx):
146
146
  @rewrite.command(
147
147
  help="Set rewrite rule."
148
148
  )
149
+ @click.option('--host', help='Request URL host.')
149
150
  @click.option(
150
151
  '--method',
151
152
  multiple=True,
@@ -159,17 +160,30 @@ def rewrite(ctx):
159
160
  required=True,
160
161
  type=click.Choice([mode.MOCK, mode.RECORD, mode.REPLAY] + ([mode.TEST] if is_remote else []))
161
162
  )
162
- @click.option('--name', required=True, help='Name of the request component.')
163
+ @click.option('--name', help='Name of the request component.')
163
164
  @click.option('--pattern', required=True, help='URLs pattern.')
165
+ @click.option('--port', help='Request URL port.')
164
166
  @click.option('--project-key', help='Project to add rewrite rule to.')
165
167
  @click.option(
166
168
  '--type',
167
- required=True,
168
169
  type=click.Choice([request_component.BODY_PARAM, request_component.HEADER, request_component.QUERY_PARAM]),
169
170
  help='Request component type.'
170
171
  )
171
- @click.option('--value', required=True, help='Rewrite value.')
172
+ @click.option('--value', help='Rewrite value.')
172
173
  def set(**kwargs):
174
+ if kwargs['name'] or kwargs['value'] or kwargs['type']:
175
+ if kwargs['name'] == None:
176
+ print("Error: missing option '--name'", file=sys.stderr)
177
+ sys.exit(1)
178
+
179
+ if kwargs['value'] == None:
180
+ print("Error: missing option '--value'", file=sys.stderr)
181
+ sys.exit(1)
182
+
183
+ if kwargs['type'] == None:
184
+ print("Error: missing option '--type'", file=sys.stderr)
185
+ sys.exit(1)
186
+
173
187
  settings = Settings.instance()
174
188
  project_key_str = resolve_project_key_and_validate(kwargs, settings)
175
189
  project_key = ProjectKey(project_key_str)
@@ -183,27 +197,50 @@ def set(**kwargs):
183
197
  filtered_rewrite_rules: List[RewriteRule] = list(filter(rewrite_rule_filter, rewrite_rules))
184
198
 
185
199
  if len(filtered_rewrite_rules) == 0:
200
+ parameter_rules = list(filter(lambda r: r != None, [__select_parameter_rule(kwargs)]))
201
+ url_rules = list(filter(lambda r: r != None , [__select_url_rule(kwargs)]))
186
202
  rewrite_rule = RewriteRule({
187
203
  'methods': methods,
188
204
  'pattern': kwargs['pattern'],
189
- 'parameter_rules': [__select_parameter_rule(kwargs)]
205
+ 'parameter_rules': parameter_rules,
206
+ 'url_rules': url_rules,
190
207
  })
191
208
  rewrite_rules.append(rewrite_rule)
192
209
  settings.proxy.rewrite.set_rewrite_rules(project_key.id, rewrite_rules)
193
210
  else:
194
211
  parameter_rule_filter = lambda rule: rule.name == kwargs['name'] and rule.type == kwargs['type'] and rule.modes == modes
212
+ url_rule_filter = lambda rule: rule.host == kwargs['host'] and rule.modes == modes
213
+
195
214
  for rewrite_rule in filtered_rewrite_rules:
196
- parameter_rules = rewrite_rule.parameter_rules
197
- filtered_parameter_rules: List[ParameterRule] = list(filter(parameter_rule_filter, parameter_rules))
215
+ # Parameter rules
198
216
  parameter_rule_dict = __select_parameter_rule(kwargs)
199
217
 
200
- if len(filtered_parameter_rules) == 0:
201
- parameter_rule = ParameterRule(parameter_rule_dict)
202
- parameter_rules.append(parameter_rule)
203
- rewrite_rule.parameter_rules = parameter_rules
204
- else:
205
- for parameter_rule in filtered_parameter_rules:
206
- parameter_rule.update(parameter_rule_dict)
218
+ if parameter_rule_dict:
219
+ parameter_rules = rewrite_rule.parameter_rules
220
+ filtered_parameter_rules: List[ParameterRule] = list(filter(parameter_rule_filter, parameter_rules))
221
+
222
+ if len(filtered_parameter_rules) == 0:
223
+ parameter_rule = ParameterRule(parameter_rule_dict)
224
+ parameter_rules.append(parameter_rule)
225
+ rewrite_rule.parameter_rules = parameter_rules
226
+ else:
227
+ for parameter_rule in filtered_parameter_rules:
228
+ parameter_rule.update(parameter_rule_dict)
229
+
230
+ # URL rules
231
+ url_rule_dict = __select_url_rule(kwargs)
232
+
233
+ if url_rule_dict:
234
+ url_rules = rewrite_rule.url_rules
235
+ filtered_url_rules: List[UrlRule] = list(filter(url_rule_filter, url_rules))
236
+
237
+ if len(filtered_url_rules) == 0:
238
+ url_rule = UrlRule(url_rule_dict)
239
+ url_rules.append(url_rule)
240
+ rewrite_rule.url_rules = url_rules
241
+ else:
242
+ for url_rule in filtered_url_rules:
243
+ url_rule.update(url_rule_dict)
207
244
 
208
245
  settings.commit()
209
246
 
@@ -437,6 +474,9 @@ config.add_command(rewrite)
437
474
  config.add_command(scenario)
438
475
 
439
476
  def __select_parameter_rule(kwargs):
477
+ if kwargs['name'] == None or kwargs['value'] == None or kwargs['type'] == None:
478
+ return
479
+
440
480
  return {
441
481
  'modes': list(kwargs['mode']),
442
482
  'name': kwargs['name'],
@@ -444,6 +484,16 @@ def __select_parameter_rule(kwargs):
444
484
  'type': kwargs['type'],
445
485
  }
446
486
 
487
+ def __select_url_rule(kwargs):
488
+ if kwargs['host'] == None or kwargs['port'] == None:
489
+ return
490
+
491
+ return {
492
+ 'host': kwargs['host'],
493
+ 'modes': list(kwargs['mode']),
494
+ 'port': kwargs['port'],
495
+ }
496
+
447
497
  def __project_key(settings):
448
498
  project_key = settings.proxy.intercept.project_key
449
499
  validate_project_key(project_key)
@@ -1,13 +1,13 @@
1
1
  import copy
2
2
  from functools import reduce
3
3
  import itertools
4
- import pdb
5
4
  from pprint import pprint
6
5
  import re
7
6
  from typing import Dict, List, Union
8
7
  from urllib.parse import urlparse
9
8
 
10
9
  from openapi_core import Spec
10
+ import yaml
11
11
 
12
12
  from stoobly_agent.lib.api.interfaces.endpoints import (
13
13
  Alias,
@@ -23,17 +23,30 @@ class OpenApiEndpointAdapter():
23
23
  return
24
24
 
25
25
  def adapt_from_file(self, file_path) -> List[EndpointShowResponse]:
26
- spec = Spec.from_file_path(file_path)
26
+ spec = {}
27
+
28
+ with open(file_path, "r") as stream:
29
+ file_data: Dict = yaml.safe_load(stream)
30
+
31
+ if 'info' not in file_data:
32
+ self.__add_info(file_data)
33
+
34
+ missing_oauth2_scopes = self.__is_missing_oauth2_scopes(file_data)
35
+ if missing_oauth2_scopes:
36
+ self.__add_oauth2_default_scopes(file_data)
37
+
38
+ spec = Spec.from_dict(file_data)
39
+
27
40
  return self.adapt(spec)
28
41
 
29
42
  def adapt(self, spec: Spec) -> List[EndpointShowResponse]:
30
43
  endpoints = []
31
44
  endpoint_counter = 0
32
- components = spec.get("components")
45
+ components = spec.get("components", {})
33
46
  schemas = components.get("schemas", {})
34
47
  paths = spec.getkey('paths')
35
48
 
36
- servers_spec = spec / "servers"
49
+ servers_spec = spec.get("servers")
37
50
  servers = self.__evaluate_servers(servers_spec)
38
51
 
39
52
  for _, server in enumerate(servers):
@@ -177,12 +190,12 @@ class OpenApiEndpointAdapter():
177
190
  request_body = operation.get("requestBody", {})
178
191
  required_request_body = request_body.get("required")
179
192
  required_body_params = []
180
- param_properties = {}
181
193
  literal_body_params = {}
182
194
  request_body_array = False
183
195
 
184
196
  content = request_body.get("content", {})
185
197
  for mimetype, media_type in content.items():
198
+ param_properties = {}
186
199
  schema = media_type['schema']
187
200
 
188
201
  # If Spec Component reference, look it up in components
@@ -195,12 +208,10 @@ class OpenApiEndpointAdapter():
195
208
  schema_type = schema.get('type')
196
209
  if schema_type:
197
210
  if schema_type == 'object':
198
- param_properties = schema['properties']
211
+ param_properties = schema.get('properties', {})
199
212
  elif schema_type == 'array':
200
213
  request_body_array = True
201
214
  param_properties = {'tmp': schema['items']}
202
- else:
203
- param_properties = {}
204
215
 
205
216
  for property_key, property_value in param_properties.items():
206
217
  if property_key in required_body_params:
@@ -231,6 +242,66 @@ class OpenApiEndpointAdapter():
231
242
 
232
243
  return endpoints
233
244
 
245
+ def __add_info(self, file_data: Dict):
246
+ if 'info' in file_data:
247
+ return
248
+
249
+ file_data['info'] = {
250
+ 'version': '0.0.1',
251
+ 'title': ''
252
+ }
253
+
254
+ def __is_missing_oauth2_scopes(self, file_data: Dict):
255
+ is_missing = False
256
+ if 'components' in file_data:
257
+ components = file_data['components']
258
+
259
+ if 'securitySchemes' in components:
260
+ security_schemes = components['securitySchemes']
261
+
262
+ for scheme_name, scheme in security_schemes.items():
263
+ if scheme.get('type') == 'oauth2':
264
+ flows = scheme.get('flows')
265
+
266
+ if flows and flows.get('clientCredentials'):
267
+ scopes = flows.get('clientCredentials').get('scopes')
268
+
269
+ if scopes is None:
270
+ return True
271
+
272
+ break
273
+
274
+ return is_missing
275
+
276
+ def __add_oauth2_default_scopes(self, file_data: Dict):
277
+ if 'components' not in file_data:
278
+ return
279
+ components = file_data['components']
280
+
281
+ if 'securitySchemes' not in components:
282
+ return
283
+ security_schemes = components['securitySchemes']
284
+
285
+ oauth_security_scheme = {}
286
+ for scheme_name, scheme in security_schemes.items():
287
+ if scheme.get('type') == 'oauth2':
288
+ oauth_security_scheme = scheme
289
+ break
290
+
291
+ # If empty dict or None
292
+ if not oauth_security_scheme:
293
+ return
294
+
295
+ flows = oauth_security_scheme['flows']
296
+ if not flows:
297
+ return
298
+
299
+ client_credentials = flows['clientCredentials']
300
+ if not client_credentials:
301
+ return
302
+
303
+ client_credentials['scopes'] = {}
304
+
234
305
  def __get_most_recent_param(self, literal_params: dict):
235
306
  return list(literal_params)[-1] if literal_params else None
236
307
 
@@ -41,7 +41,7 @@ def handle_request_mock_generic(context: MockContext, **options: MockOptions):
41
41
  # Rewrite request with paramter rules for mock
42
42
  request: MitmproxyRequest = context.flow.request
43
43
  request_facade = MitmproxyRequestFacade(request)
44
- request_facade.with_rewrite_rules(rewrite_rules).rewrite()
44
+ request_facade.with_parameter_rules(rewrite_rules).with_url_rules(rewrite_rules).rewrite()
45
45
 
46
46
  __mock_hook(lifecycle_hooks.BEFORE_MOCK, context)
47
47
 
@@ -28,10 +28,11 @@ def __replay_request(replay_context: ReplayContext):
28
28
  """
29
29
  intercept_settings: InterceptSettings = replay_context.intercept_settings
30
30
  rewrite_rules = intercept_settings.rewrite_rules
31
+
31
32
  if len(rewrite_rules) > 0:
32
33
  request: MitmproxyRequest = replay_context.flow.request
33
34
  request_facade = MitmproxyRequestFacade(request)
34
- request_facade.with_rewrite_rules(rewrite_rules).rewrite()
35
+ request_facade.with_parameter_rules(rewrite_rules).with_url_rules(rewrite_rules).rewrite()
35
36
 
36
37
  __replay_hook(lifecycle_hooks.BEFORE_REPLAY, replay_context)
37
38
 
@@ -10,7 +10,7 @@ from stoobly_agent.app.settings.constants import firewall_action, intercept_mode
10
10
  from stoobly_agent.app.settings.rewrite_rule import RewriteRule
11
11
  from stoobly_agent.app.settings.firewall_rule import FirewallRule
12
12
  from stoobly_agent.app.settings import Settings
13
- from stoobly_agent.app.settings.types import IgnoreRule, MatchRule, RedactRule
13
+ from stoobly_agent.app.settings.types import IgnoreRule, MatchRule
14
14
  from stoobly_agent.config.constants import custom_headers, env_vars, mode, request_origin, test_filter
15
15
  from stoobly_agent.lib.api.keys.project_key import InvalidProjectKey, ProjectKey
16
16
  from stoobly_agent.lib.logger import Logger
@@ -154,11 +154,11 @@ class InterceptSettings:
154
154
  return self.__select_rewrite_rules(_mode)
155
155
 
156
156
  @property
157
- def record_rewrite_rules(self) -> List[RedactRule]:
157
+ def record_rewrite_rules(self) -> List[RewriteRule]:
158
158
  return self.__select_rewrite_rules(mode.RECORD)
159
159
 
160
160
  @property
161
- def mock_rewrite_rules(self) -> List[RedactRule]:
161
+ def mock_rewrite_rules(self) -> List[RewriteRule]:
162
162
  return self.__select_rewrite_rules(mode.MOCK)
163
163
 
164
164
  @property
@@ -210,21 +210,18 @@ class InterceptSettings:
210
210
 
211
211
  # Filter only parameters matching active intercept mode
212
212
  for rewrite_rule in self.__rewrite_rules:
213
- parameter_rules = self.__select_parameter_rules(rewrite_rule, mode)
214
-
215
- # If no parameters rules were found, then this filter rule is not applied
216
- if len(parameter_rules) == 0:
217
- continue
213
+ # If url rule applies, then update .url_rules with url_rule
214
+ url_rules = self.__select_url_rules(rewrite_rule)
218
215
 
219
- # Build a new RewriteRule object contain only parameter rules matching intercept mode
220
- rewrite_rule = RewriteRule({
221
- 'methods': rewrite_rule.methods,
222
- 'pattern': rewrite_rule.pattern,
223
- 'parameters_rules': [], # Has to be dict form, manually set it
224
- })
225
- rewrite_rule.parameter_rules = parameter_rules
216
+ # If parameters rules apply, then update .parameter_rules with applicable parameter_rules
217
+ parameter_rules = self.__select_parameter_rules(rewrite_rule, mode)
226
218
 
227
- rules.append(rewrite_rule)
219
+ if len(url_rules) > 0 or len(parameter_rules) > 0:
220
+ # Build a new RewriteRule object contain only parameter rules matching intercept mode
221
+ rewrite_rule = RewriteRule(rewrite_rule.to_dict())
222
+ rewrite_rule.url_rules = url_rules
223
+ rewrite_rule.parameter_rules = parameter_rules
224
+ rules.append(rewrite_rule)
228
225
 
229
226
  return rules
230
227
 
@@ -235,6 +232,13 @@ class InterceptSettings:
235
232
  rewrite_rule.parameter_rules or []
236
233
  ))
237
234
 
235
+ def __select_url_rules(self, rewrite_rule: RewriteRule, mode = None):
236
+ mode = mode or self.mode
237
+ return list(filter(
238
+ lambda url: mode in url.modes,
239
+ rewrite_rule.url_rules or []
240
+ ))
241
+
238
242
  def __initialize_lifecycle_hooks(self):
239
243
  script_path = self.lifecycle_hooks_path
240
244
 
@@ -8,7 +8,7 @@ from typing import Callable, List
8
8
  from urllib.parse import urlparse
9
9
 
10
10
  from stoobly_agent.app.settings.constants import request_component
11
- from stoobly_agent.app.settings.rewrite_rule import RewriteRule, ParameterRule
11
+ from stoobly_agent.app.settings.rewrite_rule import ParameterRule, RewriteRule, UrlRule
12
12
  from stoobly_agent.config.constants import custom_headers
13
13
  from stoobly_agent.lib.logger import Logger, bcolors
14
14
  from stoobly_agent.lib.utils import jmespath
@@ -29,8 +29,8 @@ class MitmproxyRequestFacade(Request):
29
29
  self.request = request
30
30
  self.uri = urlparse(self.request.url)
31
31
 
32
- self.__redact_rules: List[ParameterRule] = []
33
- self.__rewrite_rules: List[ParameterRule] = []
32
+ self.__url_rules: List[UrlRule] = []
33
+ self.__parameter_rules: List[ParameterRule] = []
34
34
 
35
35
  self.__body = MitmproxyRequestBodyFacade(request)
36
36
 
@@ -99,41 +99,42 @@ class MitmproxyRequestFacade(Request):
99
99
  return self.request.port
100
100
 
101
101
  @property
102
- def redact_rules(self) -> List[ParameterRule]:
103
- return self.__redact_rules
102
+ def url_rules(self) -> List[ParameterRule]:
103
+ return self.__url_rules
104
104
 
105
105
  @property
106
- def rewrite_rules(self) -> List[ParameterRule]:
107
- return self.__rewrite_rules
106
+ def parameter_rules(self) -> List[ParameterRule]:
107
+ return self.__parameter_rules
108
108
 
109
- def with_rewrite_rules(self, rules: List[RewriteRule]):
109
+ def with_parameter_rules(self, rules: List[RewriteRule]):
110
110
  if type(rules) == list:
111
- self.__rewrite_rules = self.select_parameter_rules(rules)
111
+ self.__parameter_rules = self.select_parameter_rules(rules)
112
112
  return self
113
113
 
114
- def with_redact_rules(self, rules: List[RewriteRule]):
114
+ def with_url_rules(self, rules: List[RewriteRule]):
115
115
  if type(rules) == list:
116
- self.__redact_rules = self.select_parameter_rules(rules)
116
+ self.__url_rules = self.select_url_rules(rules)
117
117
  return self
118
118
 
119
- def redact(self):
120
- redacts = self.__redact_rules
121
- if len(redacts) != 0:
122
- self.__redact_headers(redacts)
123
- self.__redact_query(redacts)
124
- self.__redact_content(redacts)
125
-
126
119
  def rewrite(self):
127
- rewrites = self.__rewrite_rules
120
+ rewrites = self.__parameter_rules
128
121
 
129
122
  if len(rewrites) != 0:
130
123
  self.__rewrite_headers(rewrites)
131
124
  self.__rewrite_query(rewrites)
132
125
  self.__rewrite_content(rewrites)
133
126
 
127
+ rewrites = self.__url_rules
128
+
129
+ if len(rewrites):
130
+ self.__rewrite_url(rewrites)
131
+
132
+ # Find all the rules that match request url and method
133
+ def select_rewrite_rules(self, rules: List[RewriteRule]) -> List[RewriteRule]:
134
+ return list(filter(self.__is_rewrite_rule_selected, rules or []))
135
+
134
136
  def select_parameter_rules(self, rules: List[RewriteRule]) -> List[ParameterRule]:
135
- # Find all the rules that match request url and method
136
- _rules = list(filter(self.__is_parameter_rule_selected, rules or []))
137
+ _rules = self.select_rewrite_rules(rules)
137
138
 
138
139
  if len(_rules) == 0:
139
140
  return []
@@ -142,7 +143,17 @@ class MitmproxyRequestFacade(Request):
142
143
 
143
144
  return [item for sublist in parameter_rules for item in sublist] # flatten list
144
145
 
145
- def __is_parameter_rule_selected(self, rewrite_rule: RewriteRule):
146
+ def select_url_rules(self, rules: List[RewriteRule]) -> List[UrlRule]:
147
+ _rules = self.select_rewrite_rules(rules)
148
+
149
+ if len(_rules) == 0:
150
+ return []
151
+
152
+ url_rules = list(map(lambda rule: rule.url_rules, _rules))
153
+
154
+ return [item for sublist in url_rules for item in sublist] # flatten list
155
+
156
+ def __is_rewrite_rule_selected(self, rewrite_rule: RewriteRule):
146
157
  pattern = rewrite_rule.pattern
147
158
 
148
159
  try:
@@ -168,6 +179,14 @@ class MitmproxyRequestFacade(Request):
168
179
  Logger.instance().info(f"{bcolors.OKCYAN}Rewriting {rewrite.type.lower()}{bcolors.ENDC} {rewrite.name} => {rewrite.value}")
169
180
  return rewrite.value
170
181
 
182
+ def __rewrite_url(self, rewrites: List[UrlRule]):
183
+ for rewrite in rewrites:
184
+ if rewrite.host:
185
+ self.request.host = rewrite.host
186
+
187
+ if rewrite.port:
188
+ self.request.port = int(rewrite.port)
189
+
171
190
  def __rewrite_headers(self, rewrites: List[ParameterRule]):
172
191
  self.__apply_headers(rewrites, self.__rewrite_handler)
173
192
 
@@ -177,19 +196,6 @@ class MitmproxyRequestFacade(Request):
177
196
  def __rewrite_content(self, rewrites: List[ParameterRule]):
178
197
  self.__apply_content(rewrites, self.__rewrite_handler)
179
198
 
180
- def __redact_handler(self, rewrite: ParameterRule) -> str:
181
- Logger.instance().debug(f"{bcolors.OKCYAN}Redacting{bcolors.ENDC} {rewrite.name}")
182
- return '[REDACTED]'
183
-
184
- def __redact_headers(self, redacts: List[ParameterRule]):
185
- self.__apply_headers(redacts, self.__redact_handler)
186
-
187
- def __redact_query(self, redacts: List[ParameterRule]):
188
- self.__apply_queries(redacts, self.__redact_handler)
189
-
190
- def __redact_content(self, redacts: List[ParameterRule]):
191
- self.__apply_content(redacts, self.__redact_handler)
192
-
193
199
  def __apply_headers(self, rewrites: List[ParameterRule], handler: Callable):
194
200
  rewrites = list(filter(lambda rewrite: rewrite.type == request_component.HEADER, rewrites))
195
201
  self.__apply_rewrites(self.request.headers, rewrites, handler)
@@ -11,7 +11,6 @@ class MitmproxyResponseFacade(Response):
11
11
  self.content = response.raw_content
12
12
 
13
13
  self.rewrite_rules = []
14
- self.rewrite_rules = []
15
14
 
16
15
  @property
17
16
  def code(self):
@@ -42,22 +41,12 @@ class MitmproxyResponseFacade(Response):
42
41
  self.response.headers['content-length'] = str(len(self.content))
43
42
 
44
43
 
45
- def with_redact_rules(self, rules: RewriteRule):
46
- if type(rules) == list:
47
- self.rewrite_rules = rules
48
-
49
- return self
50
-
51
44
  def with_rewrite_rules(self, rules: RewriteRule):
52
45
  if type(rules) == list:
53
46
  self.rewrite_rules = rules
54
47
 
55
48
  return self
56
49
 
57
- # TODO
58
- def redact(self):
59
- pass
60
-
61
50
  # TODO
62
51
  def rewrite(self):
63
52
  pass
@@ -26,7 +26,7 @@ def join_rewritten_request(flow: MitmproxyHTTPFlow, intercept_settings: Intercep
26
26
  response = MitmproxyResponseFacade(flow.response)
27
27
  rewrite_rules = intercept_settings.record_rewrite_rules
28
28
 
29
- request.with_rewrite_rules(rewrite_rules).rewrite()
29
+ request.with_parameter_rules(rewrite_rules).with_url_rules(rewrite_rules).rewrite()
30
30
  response.with_rewrite_rules(rewrite_rules).rewrite()
31
31
 
32
32
  return join_request(request, response, intercept_settings)
@@ -1,6 +1,6 @@
1
1
  import pdb
2
2
 
3
- from typing import Callable, Dict, List, TypedDict, Union
3
+ from typing import Dict, List, Union
4
4
 
5
5
  from stoobly_agent.app.proxy.replay.alias_context import AliasContext
6
6
  from stoobly_agent.app.proxy.replay.alias_resolver import AliasResolver
@@ -2,6 +2,7 @@ import pdb
2
2
 
3
3
  from .parameter_rule import ParameterRule
4
4
  from .types.proxy_settings import RewriteRule as IRewriteRule
5
+ from .url_rule import UrlRule
5
6
 
6
7
  class RewriteRule:
7
8
 
@@ -14,6 +15,9 @@ class RewriteRule:
14
15
  self.__raw_parameter_rules = self.__rewrite_rule.get('parameter_rules') or []
15
16
  self.__parameter_rules = list(map(lambda rule: ParameterRule(rule), self.__raw_parameter_rules))
16
17
 
18
+ self.__raw_url_rules = self.__rewrite_rule.get('url_rules') or []
19
+ self.__url_rules = list(map(lambda rule: UrlRule(rule), self.__raw_url_rules))
20
+
17
21
  @property
18
22
  def methods(self):
19
23
  return self.__methods
@@ -30,9 +34,18 @@ class RewriteRule:
30
34
  def parameter_rules(self, v):
31
35
  self.__parameter_rules = v
32
36
 
37
+ @property
38
+ def url_rules(self):
39
+ return self.__url_rules
40
+
41
+ @url_rules.setter
42
+ def url_rules(self, v):
43
+ self.__url_rules = v
44
+
33
45
  def to_dict(self):
34
46
  return {
35
47
  'methods': self.__methods,
36
48
  'pattern': self.__pattern,
37
49
  'parameter_rules': list(map(lambda parameter: parameter.to_dict(), self.__parameter_rules)),
50
+ 'url_rules': list(map(lambda url: url.to_dict(), self.__url_rules)),
38
51
  }
@@ -23,11 +23,6 @@ class IgnoreRule(TypedDict):
23
23
  method: str
24
24
  pattern: str
25
25
 
26
- class RedactRule(TypedDict):
27
- redacts: List[Redact]
28
- method: str
29
- pattern: str
30
-
31
26
  class RewriteRule(TypedDict):
32
27
  rewrites: List[Rewrite]
33
28
  method: str
@@ -97,4 +92,4 @@ Component = {
97
92
  'QueryParam': 'Query Param',
98
93
  }
99
94
  IProjectModeSettings = Union[IProjectMockSettings, IProjectRecordSettings, IProjectTestSettings]
100
- Rule = Union[IgnoreRule, RedactRule, RewriteRule]
95
+ Rule = Union[IgnoreRule, RewriteRule]
@@ -15,6 +15,11 @@ class ParameterRule(TypedDict):
15
15
  type: str
16
16
  value: str
17
17
 
18
+ class UrlRule(TypedDict):
19
+ host: str
20
+ modes: List[Mode]
21
+ port: str
22
+
18
23
  class DataRules(TypedDict):
19
24
  mock_policy: MockPolicy
20
25
  record_policy: RecordPolicy
@@ -30,6 +35,7 @@ class RewriteRule(TypedDict):
30
35
  methods: List[Method]
31
36
  pattern: str
32
37
  parameter_rules: List[ParameterRule]
38
+ url_rule: List[UrlRule]
33
39
 
34
40
  class FirewallRule(TypedDict):
35
41
  action: List[FirewallAction]
@@ -0,0 +1,33 @@
1
+ from typing import List
2
+
3
+ from .types.proxy_settings import UrlRule as IUrlRule
4
+
5
+ class UrlRule:
6
+
7
+ def __init__(self, url_rule: IUrlRule):
8
+ self.update(url_rule)
9
+
10
+ @property
11
+ def host(self):
12
+ return self.__host
13
+
14
+ @property
15
+ def modes(self):
16
+ return self.__modes
17
+
18
+ @property
19
+ def port(self):
20
+ return self.__port
21
+
22
+ def update(self, url_rule: IUrlRule):
23
+ self.__url_rule = url_rule
24
+ self.__host = self.__url_rule.get('host')
25
+ self.__modes = self.__url_rule.get('modes')
26
+ self.__port = self.__url_rule.get('port')
27
+
28
+ def to_dict(self):
29
+ return {
30
+ 'host': self.__host,
31
+ 'modes': self.__modes,
32
+ 'port': self.__port,
33
+ }