stoobly-agent 0.21.0__py3-none-any.whl → 0.22.3__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.
- stoobly_agent/__init__.py +2 -1
- stoobly_agent/app/api/bodies_controller.py +2 -2
- stoobly_agent/app/api/requests_controller.py +51 -29
- stoobly_agent/app/api/simple_http_request_handler.py +1 -1
- stoobly_agent/app/cli/ca_cert_installer.py +16 -5
- stoobly_agent/app/cli/config_cli.py +225 -135
- stoobly_agent/app/cli/dev_tools_cli.py +3 -1
- stoobly_agent/app/cli/helpers/__init__.py +2 -1
- stoobly_agent/app/cli/helpers/context.py +7 -0
- stoobly_agent/app/cli/helpers/handle_mock_service.py +14 -0
- stoobly_agent/app/cli/helpers/print_service.py +8 -0
- stoobly_agent/app/cli/helpers/scenario_facade.py +10 -28
- stoobly_agent/app/cli/intercept.py +46 -2
- stoobly_agent/app/cli/main_group.py +8 -9
- stoobly_agent/app/cli/project_cli.py +10 -27
- stoobly_agent/app/cli/request_cli.py +14 -18
- stoobly_agent/app/cli/scenario_cli.py +94 -87
- stoobly_agent/app/models/adapters/mitmproxy/__init__.py +2 -0
- stoobly_agent/app/models/adapters/mitmproxy/request/__init__.py +12 -0
- stoobly_agent/app/models/adapters/mitmproxy/request/python_adapter.py +16 -0
- stoobly_agent/app/models/adapters/mitmproxy/response/__init__.py +12 -0
- stoobly_agent/app/models/adapters/mitmproxy/response/python_adapter.py +24 -0
- stoobly_agent/app/models/adapters/python/__init__.py +2 -0
- stoobly_agent/app/models/adapters/python/request/__init__.py +18 -0
- stoobly_agent/app/models/adapters/python/request/mitmproxy_adapter.py +53 -0
- stoobly_agent/app/models/adapters/python/request/stoobly_adapter.py +49 -0
- stoobly_agent/app/models/adapters/python/response/__init__.py +13 -0
- stoobly_agent/app/models/adapters/{mitmproxy_response_adapter.py → python/response/mitmproxy_adapter.py} +15 -7
- stoobly_agent/app/models/adapters/raw_http_request_adapter.py +19 -12
- stoobly_agent/app/models/adapters/raw_http_response_adapter.py +22 -12
- stoobly_agent/app/models/adapters/stoobly/request/__init__.py +11 -0
- stoobly_agent/app/models/adapters/stoobly/request/mitmproxy_adapter.py +32 -0
- stoobly_agent/app/models/body_model.py +2 -2
- stoobly_agent/app/models/factories/__init__.py +0 -0
- stoobly_agent/app/models/factories/resource/__init__.py +0 -0
- stoobly_agent/app/models/{adapters/body_adapter_factory.py → factories/resource/body.py} +1 -1
- stoobly_agent/app/models/{adapters/header_adapter_factory.py → factories/resource/header.py} +1 -1
- stoobly_agent/app/models/factories/resource/local_db/__init__.py +0 -0
- stoobly_agent/app/models/{adapters → factories/resource}/local_db/header_adapter.py +2 -2
- stoobly_agent/app/models/{adapters → factories/resource}/local_db/replayed_response_adapter.py +1 -2
- stoobly_agent/app/models/{adapters → factories/resource}/local_db/request_adapter.py +15 -8
- stoobly_agent/app/models/{adapters → factories/resource}/local_db/scenario_adapter.py +13 -7
- stoobly_agent/app/models/{adapters/query_param_adapter_factory.py → factories/resource/query_param.py} +1 -1
- stoobly_agent/app/models/{adapters/replayed_response_adapter_factory.py → factories/resource/replayed_response.py} +1 -1
- stoobly_agent/app/models/{adapters/request_adapter_factory.py → factories/resource/request.py} +2 -2
- stoobly_agent/app/models/{adapters/response_adapter_factory.py → factories/resource/response.py} +1 -1
- stoobly_agent/app/models/{adapters/response_header_adapter_factory.py → factories/resource/response_header.py} +1 -1
- stoobly_agent/app/models/{adapters/scenario_adapter_factory.py → factories/resource/scenario.py} +2 -2
- stoobly_agent/app/models/factories/resource/stoobly/__init__.py +0 -0
- stoobly_agent/app/models/{adapters/stoobly_request_adapter.py → factories/resource/stoobly/request_adapter.py} +1 -2
- stoobly_agent/app/models/{adapters/stoobly_scenario_adapter.py → factories/resource/stoobly/scenario_adapter.py} +1 -2
- stoobly_agent/app/models/header_model.py +2 -2
- stoobly_agent/app/models/query_param_model.py +2 -2
- stoobly_agent/app/models/replayed_response_model.py +2 -2
- stoobly_agent/app/models/request_model.py +4 -5
- stoobly_agent/app/models/response_header_model.py +2 -2
- stoobly_agent/app/models/response_model.py +2 -2
- stoobly_agent/app/models/scenario_model.py +4 -4
- stoobly_agent/app/models/schemas/request.py +8 -1
- stoobly_agent/app/models/types/__init__.py +6 -0
- stoobly_agent/app/proxy/__init__.py +0 -5
- stoobly_agent/app/proxy/handle_mock_service.py +0 -3
- stoobly_agent/app/proxy/handle_test_service.py +1 -1
- stoobly_agent/app/proxy/intercept_handler.py +0 -1
- stoobly_agent/app/proxy/mitmproxy/flow_mock.py +35 -0
- stoobly_agent/app/proxy/mitmproxy/request_facade.py +11 -2
- stoobly_agent/app/proxy/mock/hashed_request_decorator.py +2 -2
- stoobly_agent/app/proxy/replay/replay_request_service.py +58 -40
- stoobly_agent/app/proxy/simulate_intercept_service.py +30 -0
- stoobly_agent/app/proxy/test/__init__.py +1 -0
- stoobly_agent/app/proxy/test/context.py +2 -1
- stoobly_agent/app/proxy/test/context_abc.py +155 -0
- stoobly_agent/app/proxy/test/matchers/context.py +1 -1
- stoobly_agent/app/proxy/test/matchers/contract.py +1 -1
- stoobly_agent/app/proxy/test/matchers/custom.py +1 -1
- stoobly_agent/app/proxy/test/matchers/diff.py +1 -1
- stoobly_agent/app/proxy/test/matchers/fuzzy.py +1 -1
- stoobly_agent/app/proxy/test/test_service.py +1 -1
- stoobly_agent/app/proxy/upload/joined_request.py +0 -1
- stoobly_agent/app/proxy/upload/proxy_request.py +4 -1
- stoobly_agent/app/proxy/upload/request_string.py +1 -1
- stoobly_agent/app/settings/constants/mode.py +3 -0
- stoobly_agent/app/settings/data_settings.py +3 -1
- stoobly_agent/cli.py +89 -11
- stoobly_agent/config/constants/env_vars.py +2 -1
- stoobly_agent/config/data_dir.py +29 -8
- stoobly_agent/config/settings.yml.sample +1 -1
- stoobly_agent/db/migrations/2022_12_12_092437_align_requests.py +4 -4
- stoobly_agent/lib/api/api.py +4 -4
- stoobly_agent/lib/api/keys/organization_key.py +2 -0
- stoobly_agent/lib/api/keys/project_key.py +13 -0
- stoobly_agent/lib/api/keys/resource_key.py +5 -3
- stoobly_agent/lib/api/scenarios_resource.py +4 -12
- stoobly_agent/lib/api/stoobly_api.py +9 -5
- stoobly_agent/lib/orm/__init__.py +1 -1
- stoobly_agent/lib/orm/migrate_service.py +28 -13
- stoobly_agent/lib/orm/replayed_response.py +3 -3
- stoobly_agent/lib/orm/request.py +25 -5
- stoobly_agent/lib/orm/transformers/orm_to_stoobly_request_transformer.py +15 -24
- stoobly_agent/mock.py +94 -0
- stoobly_agent/public/{2-es2015.3d54569af612a07a2e06.js → 1-es2015.37917aa26708d8f35d36.js} +1 -1
- stoobly_agent/public/{2-es5.3d54569af612a07a2e06.js → 1-es5.37917aa26708d8f35d36.js} +1 -1
- stoobly_agent/public/10-es2015.e9556b0d0f0e92fb548b.js +1 -0
- stoobly_agent/public/10-es5.e9556b0d0f0e92fb548b.js +1 -0
- stoobly_agent/public/11-es2015.bc6212fccbe72a623f81.js +1 -0
- stoobly_agent/public/11-es5.bc6212fccbe72a623f81.js +1 -0
- stoobly_agent/public/{13-es2015.76b6c147b0c46f995cd7.js → 12-es2015.d0768894ddffd6efa5e5.js} +1 -1
- stoobly_agent/public/{13-es5.76b6c147b0c46f995cd7.js → 12-es5.d0768894ddffd6efa5e5.js} +1 -1
- stoobly_agent/public/13-es2015.8a044490a76fd298162d.js +1 -0
- stoobly_agent/public/13-es5.8a044490a76fd298162d.js +1 -0
- stoobly_agent/public/{15-es2015.60c3b41c385f5bdedb7b.js → 14-es2015.1cd1a021e51ca0e62e1c.js} +1 -1
- stoobly_agent/public/{15-es5.60c3b41c385f5bdedb7b.js → 14-es5.1cd1a021e51ca0e62e1c.js} +1 -1
- stoobly_agent/public/{16-es2015.5d395009a77978db4405.js → 15-es2015.587781d19864ff0eb4f5.js} +1 -1
- stoobly_agent/public/{16-es5.5d395009a77978db4405.js → 15-es5.587781d19864ff0eb4f5.js} +1 -1
- stoobly_agent/public/16-es2015.ec6a175b1f9578203cd8.js +1 -0
- stoobly_agent/public/16-es5.ec6a175b1f9578203cd8.js +1 -0
- stoobly_agent/public/17-es2015.ad9c4756c96a15bd29d7.js +1 -0
- stoobly_agent/public/17-es5.ad9c4756c96a15bd29d7.js +1 -0
- stoobly_agent/public/{19-es2015.517f68e08f4c582dae66.js → 18-es2015.8583df0f8eccb3e47c0b.js} +1 -1
- stoobly_agent/public/{19-es5.517f68e08f4c582dae66.js → 18-es5.8583df0f8eccb3e47c0b.js} +1 -1
- stoobly_agent/public/{20-es2015.473486aabfa4d4a6431b.js → 19-es2015.d0225852a844dc03a09f.js} +1 -1
- stoobly_agent/public/{20-es5.473486aabfa4d4a6431b.js → 19-es5.d0225852a844dc03a09f.js} +1 -1
- stoobly_agent/public/{3-es5.1dad290844ea619e4c16.js → 2-es2015.8f184ac63348ba447b1f.js} +1 -1
- stoobly_agent/public/{3-es2015.1dad290844ea619e4c16.js → 2-es5.8f184ac63348ba447b1f.js} +1 -1
- stoobly_agent/public/{21-es2015.56aa10803cc1348a55a3.js → 20-es2015.f7c107847935264d58aa.js} +1 -1
- stoobly_agent/public/{21-es5.56aa10803cc1348a55a3.js → 20-es5.f7c107847935264d58aa.js} +1 -1
- stoobly_agent/public/{22-es2015.46d81010003b2a50eeab.js → 21-es2015.dd358e1edaf3d32dd2c0.js} +1 -1
- stoobly_agent/public/{22-es5.46d81010003b2a50eeab.js → 21-es5.dd358e1edaf3d32dd2c0.js} +1 -1
- stoobly_agent/public/26-es2015.6332c32f1b7c8c288f2f.js +1 -0
- stoobly_agent/public/26-es5.6332c32f1b7c8c288f2f.js +1 -0
- stoobly_agent/public/27-es2015.af505e744b0c869a93d1.js +1 -0
- stoobly_agent/public/27-es5.af505e744b0c869a93d1.js +1 -0
- stoobly_agent/public/28-es2015.7c7c0f64e4af29d2e4d4.js +1 -0
- stoobly_agent/public/28-es5.7c7c0f64e4af29d2e4d4.js +1 -0
- stoobly_agent/public/32-es2015.2ab8267be7275dee9059.js +1 -0
- stoobly_agent/public/32-es5.2ab8267be7275dee9059.js +1 -0
- stoobly_agent/public/{34-es2015.ef24f6f7630620a38b19.js → 33-es2015.5b575f3a87c6c2c6b93b.js} +1 -1
- stoobly_agent/public/{34-es5.ef24f6f7630620a38b19.js → 33-es5.5b575f3a87c6c2c6b93b.js} +1 -1
- stoobly_agent/public/{35-es2015.0667e742725cc828f59f.js → 34-es2015.6a1160649c718cdb9338.js} +1 -1
- stoobly_agent/public/{35-es5.0667e742725cc828f59f.js → 34-es5.6a1160649c718cdb9338.js} +1 -1
- stoobly_agent/public/35-es2015.1b9dc7a46a6d5296c3ae.js +1 -0
- stoobly_agent/public/35-es5.1b9dc7a46a6d5296c3ae.js +1 -0
- stoobly_agent/public/{37-es2015.50d0c2d3fe4d0a74fc8f.js → 36-es2015.2fc9151fe6a5ff2bff31.js} +1 -1
- stoobly_agent/public/{37-es5.50d0c2d3fe4d0a74fc8f.js → 36-es5.2fc9151fe6a5ff2bff31.js} +1 -1
- stoobly_agent/public/{38-es2015.c14bde0b8d0cc14e915e.js → 37-es2015.ac7108c3625fd6e1d981.js} +1 -1
- stoobly_agent/public/{38-es5.c14bde0b8d0cc14e915e.js → 37-es5.ac7108c3625fd6e1d981.js} +1 -1
- stoobly_agent/public/38-es2015.9c183b14373c0e449932.js +1 -0
- stoobly_agent/public/38-es5.9c183b14373c0e449932.js +1 -0
- stoobly_agent/public/39-es2015.4624cdeb29fe9850b216.js +1 -0
- stoobly_agent/public/39-es5.4624cdeb29fe9850b216.js +1 -0
- stoobly_agent/public/40-es2015.24d981230c0c8f369cde.js +1 -0
- stoobly_agent/public/40-es5.24d981230c0c8f369cde.js +1 -0
- stoobly_agent/public/{46-es2015.abc7e4fd207d54277fcb.js → 45-es2015.c76937ed45d460bcd36f.js} +1 -1
- stoobly_agent/public/{46-es5.abc7e4fd207d54277fcb.js → 45-es5.c76937ed45d460bcd36f.js} +1 -1
- stoobly_agent/public/6-es2015.53acc5d2ca7f48ef857f.js +1 -0
- stoobly_agent/public/6-es5.53acc5d2ca7f48ef857f.js +1 -0
- stoobly_agent/public/7-es2015.1c6b3d315d50ccd228cb.js +1 -0
- stoobly_agent/public/7-es5.1c6b3d315d50ccd228cb.js +1 -0
- stoobly_agent/public/{9-es2015.ef0f7cb32f5fadb085d0.js → 8-es2015.0fe7492f7b61eb4699b6.js} +1 -1
- stoobly_agent/public/{9-es5.ef0f7cb32f5fadb085d0.js → 8-es5.0fe7492f7b61eb4699b6.js} +1 -1
- stoobly_agent/public/common-es2015.86f70de6df2c705a87f6.js +1 -0
- stoobly_agent/public/common-es5.86f70de6df2c705a87f6.js +1 -0
- stoobly_agent/public/dashboard.agent-alpha-0.22.3.tar.gz +0 -0
- stoobly_agent/public/index.html +1 -1
- stoobly_agent/public/main-es2015.aceb967cb4cccc0bc521.js +1 -0
- stoobly_agent/public/main-es5.aceb967cb4cccc0bc521.js +1 -0
- stoobly_agent/public/{polyfills-es2015.2b40b2ecdf98a9210572.js → polyfills-es2015.580f7a6e775c2c348c9d.js} +1 -1
- stoobly_agent/public/{polyfills-es5.d9fb2eee68607c3f7f64.js → polyfills-es5.4c3461a071d35be3dd81.js} +1 -1
- stoobly_agent/public/runtime-es2015.49eaebd2913fa7fe2b97.js +1 -0
- stoobly_agent/public/runtime-es5.49eaebd2913fa7fe2b97.js +1 -0
- stoobly_agent/test/test_helper.py +4 -5
- {stoobly_agent-0.21.0.dist-info → stoobly_agent-0.22.3.dist-info}/METADATA +1 -1
- {stoobly_agent-0.21.0.dist-info → stoobly_agent-0.22.3.dist-info}/RECORD +186 -168
- {stoobly_agent-0.21.0.dist-info → stoobly_agent-0.22.3.dist-info}/WHEEL +1 -1
- stoobly_agent/app/models/adapters/mitmproxy_request_adapter.py +0 -60
- stoobly_agent/app/models/adapters/types/__init__.py +0 -3
- stoobly_agent/public/11-es2015.b85bdc528bab0ee542fe.js +0 -1
- stoobly_agent/public/11-es5.b85bdc528bab0ee542fe.js +0 -1
- stoobly_agent/public/12-es2015.72399d40488de533bb97.js +0 -1
- stoobly_agent/public/12-es5.72399d40488de533bb97.js +0 -1
- stoobly_agent/public/14-es2015.7cedfd0829bd7a64677a.js +0 -1
- stoobly_agent/public/14-es5.7cedfd0829bd7a64677a.js +0 -1
- stoobly_agent/public/17-es2015.f6f28ba9f681063632a8.js +0 -1
- stoobly_agent/public/17-es5.f6f28ba9f681063632a8.js +0 -1
- stoobly_agent/public/18-es2015.b0cd6822ebd1090b0d60.js +0 -1
- stoobly_agent/public/18-es5.b0cd6822ebd1090b0d60.js +0 -1
- stoobly_agent/public/27-es2015.4635450ff709f7868796.js +0 -1
- stoobly_agent/public/27-es5.4635450ff709f7868796.js +0 -1
- stoobly_agent/public/28-es2015.1b29b35529772ab108f1.js +0 -1
- stoobly_agent/public/28-es5.1b29b35529772ab108f1.js +0 -1
- stoobly_agent/public/32-es2015.862b67803e6242451976.js +0 -1
- stoobly_agent/public/32-es5.862b67803e6242451976.js +0 -1
- stoobly_agent/public/33-es2015.4ff4325d1aec37e1b43c.js +0 -1
- stoobly_agent/public/33-es5.4ff4325d1aec37e1b43c.js +0 -1
- stoobly_agent/public/36-es2015.cd370fdf8990019d0c8e.js +0 -1
- stoobly_agent/public/36-es5.cd370fdf8990019d0c8e.js +0 -1
- stoobly_agent/public/39-es2015.4ec5fc16202c4759eac4.js +0 -1
- stoobly_agent/public/39-es5.4ec5fc16202c4759eac4.js +0 -1
- stoobly_agent/public/40-es2015.25287ce77b40050f3471.js +0 -1
- stoobly_agent/public/40-es5.25287ce77b40050f3471.js +0 -1
- stoobly_agent/public/45-es2015.fd110741ac0fbaada177.js +0 -1
- stoobly_agent/public/45-es5.fd110741ac0fbaada177.js +0 -1
- stoobly_agent/public/6-es2015.7219d596e3545ebaed3a.js +0 -1
- stoobly_agent/public/6-es5.7219d596e3545ebaed3a.js +0 -1
- stoobly_agent/public/7-es2015.98b085349ebd9d246060.js +0 -1
- stoobly_agent/public/7-es5.98b085349ebd9d246060.js +0 -1
- stoobly_agent/public/8-es2015.335fd5c122ad083aec65.js +0 -1
- stoobly_agent/public/8-es5.335fd5c122ad083aec65.js +0 -1
- stoobly_agent/public/common-es2015.81f870bf87411a04446d.js +0 -1
- stoobly_agent/public/common-es5.81f870bf87411a04446d.js +0 -1
- stoobly_agent/public/dashboard.agent-alpha-0.21.0.tar.gz +0 -0
- stoobly_agent/public/main-es2015.575c1d17fc866d3a6649.js +0 -1
- stoobly_agent/public/main-es5.575c1d17fc866d3a6649.js +0 -1
- stoobly_agent/public/runtime-es2015.8915d042dc9b55368999.js +0 -1
- stoobly_agent/public/runtime-es5.8915d042dc9b55368999.js +0 -1
- /stoobly_agent/app/models/adapters/{local_db → stoobly}/__init__.py +0 -0
- /stoobly_agent/app/models/{adapters → factories/resource}/local_db/body_adapter.py +0 -0
- /stoobly_agent/app/models/{adapters → factories/resource}/local_db/query_param_adapter.py +0 -0
- /stoobly_agent/app/models/{adapters → factories/resource}/local_db/response_adapter.py +0 -0
- /stoobly_agent/app/models/{adapters → factories/resource}/local_db/response_header_adapter.py +0 -0
- /stoobly_agent/app/models/{adapters/types → types}/replayed_response.py +0 -0
- /stoobly_agent/app/models/{adapters/types → types}/request_create_params.py +0 -0
- /stoobly_agent/app/models/{adapters/types → types}/request_show_params.py +0 -0
- /stoobly_agent/app/models/{adapters/types → types}/scenario_create_params.py +0 -0
- {stoobly_agent-0.21.0.dist-info → stoobly_agent-0.22.3.dist-info}/LICENSE +0 -0
- {stoobly_agent-0.21.0.dist-info → stoobly_agent-0.22.3.dist-info}/entry_points.txt +0 -0
- {stoobly_agent-0.21.0.dist-info → stoobly_agent-0.22.3.dist-info}/top_level.txt +0 -0
@@ -2,12 +2,12 @@ import pdb
|
|
2
2
|
import requests
|
3
3
|
|
4
4
|
from typing import Union
|
5
|
-
from stoobly_agent.app.models.adapters.header_adapter_factory import HeaderAdapterFactory
|
6
5
|
|
7
6
|
from stoobly_agent.app.models.types.request_components import HeaderIndexResponse
|
8
7
|
from stoobly_agent.app.settings import Settings
|
9
8
|
from stoobly_agent.lib.logger import Logger
|
10
9
|
|
10
|
+
from .factories.resource.header import HeaderResourceFactory
|
11
11
|
from .model import Model
|
12
12
|
|
13
13
|
class HeaderModel(Model):
|
@@ -16,7 +16,7 @@ class HeaderModel(Model):
|
|
16
16
|
super().__init__(settings)
|
17
17
|
|
18
18
|
def as_local(self):
|
19
|
-
self.adapter =
|
19
|
+
self.adapter = HeaderResourceFactory(self.settings.remote).local_db()
|
20
20
|
|
21
21
|
def as_remote(self):
|
22
22
|
# raise('Not yet supported.')
|
@@ -7,7 +7,7 @@ from stoobly_agent.app.models.types.request_components import QueryParamIndexRes
|
|
7
7
|
from stoobly_agent.app.settings import Settings
|
8
8
|
from stoobly_agent.lib.logger import Logger
|
9
9
|
|
10
|
-
from .
|
10
|
+
from .factories.resource.query_param import QueryParamResourceFactory
|
11
11
|
from .model import Model
|
12
12
|
|
13
13
|
class QueryParamModel(Model):
|
@@ -16,7 +16,7 @@ class QueryParamModel(Model):
|
|
16
16
|
super().__init__(settings)
|
17
17
|
|
18
18
|
def as_local(self):
|
19
|
-
self.adapter =
|
19
|
+
self.adapter = QueryParamResourceFactory(self.settings.remote).local_db()
|
20
20
|
|
21
21
|
def as_remote(self):
|
22
22
|
#raise('Not yet supported.')
|
@@ -1,10 +1,10 @@
|
|
1
1
|
import pdb
|
2
2
|
import requests
|
3
3
|
|
4
|
-
from stoobly_agent.app.models.adapters.replayed_response_adapter_factory import ReplayedResponseAdapterFactory
|
5
4
|
from stoobly_agent.app.settings import Settings
|
6
5
|
from stoobly_agent.lib.logger import Logger
|
7
6
|
|
7
|
+
from .factories.resource.replayed_response import ReplayedResponseResourceFactory
|
8
8
|
from .model import Model
|
9
9
|
|
10
10
|
class ReplayedResponseModel(Model):
|
@@ -13,7 +13,7 @@ class ReplayedResponseModel(Model):
|
|
13
13
|
super().__init__(settings)
|
14
14
|
|
15
15
|
def as_local(self):
|
16
|
-
self.adapter =
|
16
|
+
self.adapter = ReplayedResponseResourceFactory(self.settings.remote).local_db()
|
17
17
|
|
18
18
|
def as_remote(self):
|
19
19
|
# raise('Not yet supported.')
|
@@ -8,10 +8,9 @@ from stoobly_agent.app.settings import Settings
|
|
8
8
|
from stoobly_agent.lib.api.interfaces import RequestShowResponse
|
9
9
|
from stoobly_agent.lib.logger import Logger
|
10
10
|
|
11
|
-
from .
|
12
|
-
from .adapters.types import RequestCreateParams, RequestShowParams
|
11
|
+
from .factories.resource.request import RequestResourceFactory
|
13
12
|
from .model import Model
|
14
|
-
from .types
|
13
|
+
from .types import RequestCreateParams, RequestShowParams, RequestsModelIndex
|
15
14
|
|
16
15
|
class RequestModel(Model):
|
17
16
|
|
@@ -19,10 +18,10 @@ class RequestModel(Model):
|
|
19
18
|
super().__init__(settings)
|
20
19
|
|
21
20
|
def as_local(self):
|
22
|
-
self.adapter =
|
21
|
+
self.adapter = RequestResourceFactory(self.settings.remote).local_db()
|
23
22
|
|
24
23
|
def as_remote(self):
|
25
|
-
self.adapter =
|
24
|
+
self.adapter = RequestResourceFactory(self.settings.remote).stoobly()
|
26
25
|
|
27
26
|
def create(self, **body_params: RequestCreateParams) -> Union[RequestsModelIndex, None]:
|
28
27
|
try:
|
@@ -7,7 +7,7 @@ from stoobly_agent.app.models.types.request_components import ResponseHeaderInde
|
|
7
7
|
from stoobly_agent.app.settings import Settings
|
8
8
|
from stoobly_agent.lib.logger import Logger
|
9
9
|
|
10
|
-
from .
|
10
|
+
from .factories.resource.response_header import ResponseHeaderResourceFactory
|
11
11
|
from .model import Model
|
12
12
|
|
13
13
|
class ResponseHeaderModel(Model):
|
@@ -16,7 +16,7 @@ class ResponseHeaderModel(Model):
|
|
16
16
|
super().__init__(settings)
|
17
17
|
|
18
18
|
def as_local(self):
|
19
|
-
self.adapter =
|
19
|
+
self.adapter = ResponseHeaderResourceFactory(self.settings.remote).local_db()
|
20
20
|
|
21
21
|
def as_remote(self):
|
22
22
|
# raise('Not yet supported.')
|
@@ -1,10 +1,10 @@
|
|
1
1
|
import pdb
|
2
2
|
import requests
|
3
3
|
|
4
|
-
from stoobly_agent.app.models.adapters.response_adapter_factory import ResponseAdapterFactory
|
5
4
|
from stoobly_agent.app.settings import Settings
|
6
5
|
from stoobly_agent.lib.logger import Logger
|
7
6
|
|
7
|
+
from .factories.resource.response import ResponseResourceFactory
|
8
8
|
from .model import Model
|
9
9
|
|
10
10
|
class ResponseModel(Model):
|
@@ -13,7 +13,7 @@ class ResponseModel(Model):
|
|
13
13
|
super().__init__(settings)
|
14
14
|
|
15
15
|
def as_local(self):
|
16
|
-
self.adapter =
|
16
|
+
self.adapter = ResponseResourceFactory(self.settings.remote).local_db()
|
17
17
|
|
18
18
|
def as_remote(self):
|
19
19
|
# raise('Not yet supported.')
|
@@ -7,8 +7,8 @@ from stoobly_agent.lib.logger import Logger
|
|
7
7
|
from stoobly_agent.lib.api.interfaces.scenarios import ScenarioShowResponse, ScenariosIndexResponse
|
8
8
|
from stoobly_agent.app.settings import Settings
|
9
9
|
|
10
|
-
from .
|
11
|
-
from .
|
10
|
+
from .types import ScenarioCreateParams
|
11
|
+
from .factories.resource.scenario import ScenarioResourceFactory
|
12
12
|
from .model import Model
|
13
13
|
|
14
14
|
class ScenarioModel(Model):
|
@@ -17,10 +17,10 @@ class ScenarioModel(Model):
|
|
17
17
|
super().__init__(settings)
|
18
18
|
|
19
19
|
def as_local(self):
|
20
|
-
self.adapter =
|
20
|
+
self.adapter = ScenarioResourceFactory(self.settings.remote).local_db()
|
21
21
|
|
22
22
|
def as_remote(self):
|
23
|
-
self.adapter =
|
23
|
+
self.adapter = ScenarioResourceFactory(self.settings.remote).stoobly()
|
24
24
|
|
25
25
|
def create(self, **body_params: ScenarioCreateParams) -> Union[ScenarioShowResponse, None]:
|
26
26
|
try:
|
@@ -96,6 +96,10 @@ class Request():
|
|
96
96
|
def headers(self, v: MultiDict):
|
97
97
|
self.__set_dict('headers', v)
|
98
98
|
|
99
|
+
@property
|
100
|
+
def query(self) -> str:
|
101
|
+
return urlencode(self.query_params)
|
102
|
+
|
99
103
|
@property
|
100
104
|
def query_params(self) -> MultiDict:
|
101
105
|
query_params = MultiDict()
|
@@ -115,7 +119,10 @@ class Request():
|
|
115
119
|
if not encoded_body:
|
116
120
|
return ''
|
117
121
|
|
118
|
-
|
122
|
+
try:
|
123
|
+
return base64.b64decode(encoded_body)
|
124
|
+
except Exception as e:
|
125
|
+
return encoded_body
|
119
126
|
|
120
127
|
@body.setter
|
121
128
|
def body(self, v: Union[bytes, str]):
|
@@ -83,10 +83,6 @@ def __commit_options(options: dict):
|
|
83
83
|
if options.get('proxy_host') and options.get('proxy_port'):
|
84
84
|
settings.proxy.url = f"http://{options.get('proxy_host')}:{options.get('proxy_port')}"
|
85
85
|
|
86
|
-
if options.get('intercept_mode'):
|
87
|
-
settings.proxy.intercept.mode = options['intercept_mode']
|
88
|
-
settings.proxy.intercept.active = True
|
89
|
-
|
90
86
|
settings.ui.active = not options.get('headless')
|
91
87
|
|
92
88
|
settings.commit()
|
@@ -112,7 +108,6 @@ def __filter_options(options):
|
|
112
108
|
if 'ui_port' in options:
|
113
109
|
del options['ui_port']
|
114
110
|
|
115
|
-
del options['intercept_mode']
|
116
111
|
del options['log_level']
|
117
112
|
del options['proxy_host']
|
118
113
|
del options['proxy_mode']
|
@@ -2,15 +2,12 @@ import requests
|
|
2
2
|
import time
|
3
3
|
import pdb
|
4
4
|
|
5
|
-
from mitmproxy.http import HTTPFlow as MitmproxyHTTPFlow
|
6
5
|
from mitmproxy.http import Request as MitmproxyRequest
|
7
6
|
from typing import Callable, TypedDict
|
8
7
|
|
9
8
|
from stoobly_agent.app.models.request_model import RequestModel
|
10
|
-
from stoobly_agent.app.proxy.intercept_settings import InterceptSettings
|
11
9
|
from stoobly_agent.app.proxy.mitmproxy.request_facade import MitmproxyRequestFacade
|
12
10
|
from stoobly_agent.app.proxy.utils.rewrite_rules_to_ignored_components_service import rewrite_rules_to_ignored_components
|
13
|
-
from stoobly_agent.app.settings import intercept_settings
|
14
11
|
from stoobly_agent.config.constants import custom_headers, mock_policy
|
15
12
|
from stoobly_agent.lib.logger import Logger
|
16
13
|
|
@@ -13,7 +13,7 @@ from stoobly_agent.lib.logger import Logger
|
|
13
13
|
|
14
14
|
from .handle_mock_service import handle_request_mock_generic
|
15
15
|
from .mock.context import MockContext
|
16
|
-
from .test.
|
16
|
+
from .test.context_abc import TestContextABC as TestContext
|
17
17
|
from .test.test_service import test
|
18
18
|
from .upload.upload_test_service import inject_upload_test
|
19
19
|
|
@@ -0,0 +1,35 @@
|
|
1
|
+
import requests
|
2
|
+
|
3
|
+
from mitmproxy.http import Request as MitmproxyRequest, Response as MitmproxyResponse
|
4
|
+
from typing import Union
|
5
|
+
|
6
|
+
from stoobly_agent.app.models.adapters.python import PythonRequestAdapterFactory, PythonResponseAdapterFactory
|
7
|
+
from stoobly_agent.app.models.adapters.raw_http_request_adapter import DEFAULT_HTTP_VERSION
|
8
|
+
|
9
|
+
class MitmproxyFlowMock():
|
10
|
+
|
11
|
+
def __init__(self):
|
12
|
+
self.__request: MitmproxyRequest = None
|
13
|
+
self.__response: MitmproxyResponse = None
|
14
|
+
|
15
|
+
@property
|
16
|
+
def request(self):
|
17
|
+
return self.__request
|
18
|
+
|
19
|
+
@property
|
20
|
+
def response(self):
|
21
|
+
return self.__response
|
22
|
+
|
23
|
+
@request.setter
|
24
|
+
def request(self, _request: Union[MitmproxyRequest, requests.Request]):
|
25
|
+
if isinstance(_request, requests.Request):
|
26
|
+
self.__request = PythonRequestAdapterFactory(_request).mitmproxy_request(DEFAULT_HTTP_VERSION)
|
27
|
+
else:
|
28
|
+
self.__request = _request
|
29
|
+
|
30
|
+
@response.setter
|
31
|
+
def response(self, _response: Union[MitmproxyResponse, requests.Response]):
|
32
|
+
if isinstance(_response, requests.Response):
|
33
|
+
self.__response = PythonResponseAdapterFactory(_response).mitmproxy_response()
|
34
|
+
else:
|
35
|
+
self.__response = _response
|
@@ -5,6 +5,7 @@ from mitmproxy.http import Headers, Request as MitmproxyRequest
|
|
5
5
|
from mitmproxy.coretypes import multidict
|
6
6
|
from typing import Callable, List, Union
|
7
7
|
from urllib.parse import urlparse
|
8
|
+
import requests
|
8
9
|
|
9
10
|
from stoobly_agent.app.settings.constants import request_component
|
10
11
|
from stoobly_agent.app.settings.rewrite_rule import RewriteRule, ParameterRule
|
@@ -53,7 +54,7 @@ class MitmproxyRequestFacade(Request):
|
|
53
54
|
|
54
55
|
@property
|
55
56
|
def body(self):
|
56
|
-
content = self.request.raw_content
|
57
|
+
content = self.request.raw_content or ''
|
57
58
|
|
58
59
|
try:
|
59
60
|
if isinstance(content, bytes):
|
@@ -96,6 +97,14 @@ class MitmproxyRequestFacade(Request):
|
|
96
97
|
def rewrite_rules(self) -> List[ParameterRule]:
|
97
98
|
return self.__rewrite_rules
|
98
99
|
|
100
|
+
def to_python_request(self):
|
101
|
+
return requests.Request(
|
102
|
+
method=self.request.method,
|
103
|
+
url=self.request.url,
|
104
|
+
headers=self.request.headers,
|
105
|
+
data=self.request.content
|
106
|
+
)
|
107
|
+
|
99
108
|
def with_rewrite_rules(self, rules: List[RewriteRule]):
|
100
109
|
if type(rules) == list:
|
101
110
|
self.__rewrite_rules = self.select_parameter_rules(rules)
|
@@ -154,7 +163,7 @@ class MitmproxyRequestFacade(Request):
|
|
154
163
|
})
|
155
164
|
|
156
165
|
def __rewrite_handler(self, rewrite: ParameterRule) -> str:
|
157
|
-
Logger.instance().
|
166
|
+
Logger.instance().info(f"{bcolors.OKCYAN}Rewriting {rewrite.type.lower()}{bcolors.ENDC} {rewrite.name} => {rewrite.value}")
|
158
167
|
return rewrite.value
|
159
168
|
|
160
169
|
def __rewrite_headers(self, rewrites: List[ParameterRule]):
|
@@ -5,16 +5,17 @@ import requests
|
|
5
5
|
from http.cookies import SimpleCookie
|
6
6
|
from typing import Callable, TypedDict, Union
|
7
7
|
|
8
|
+
from stoobly_agent.app.cli.ca_cert_installer import CACertInstaller
|
8
9
|
from stoobly_agent.app.cli.helpers.context import ReplayContext
|
9
10
|
from stoobly_agent.app.models.schemas.request import Request
|
10
11
|
from stoobly_agent.app.proxy.intercept_settings import InterceptSettings
|
11
12
|
from stoobly_agent.app.proxy.mitmproxy.request_facade import MitmproxyRequestFacade
|
12
13
|
from stoobly_agent.app.proxy.replay.trace_context import TraceContext
|
14
|
+
from stoobly_agent.app.proxy.simulate_intercept_service import simulate_intercept
|
13
15
|
from stoobly_agent.app.settings import Settings
|
14
16
|
from stoobly_agent.config.constants import alias_resolve_strategy, custom_headers, request_origin, test_filter, test_strategy
|
15
17
|
from stoobly_agent.config.mitmproxy import MitmproxyConfig
|
16
|
-
from stoobly_agent.config.constants import mode
|
17
|
-
from stoobly_agent.lib.api.api import Api
|
18
|
+
from stoobly_agent.config.constants import mock_policy, mode
|
18
19
|
|
19
20
|
class ReplayRequestOptions(TypedDict):
|
20
21
|
alias_resolve_strategy: alias_resolve_strategy.AliasResolveStrategy
|
@@ -25,6 +26,7 @@ class ReplayRequestOptions(TypedDict):
|
|
25
26
|
before_replay: Union[Callable[[ReplayContext], None], None]
|
26
27
|
after_replay: Union[Callable[[ReplayContext], Union[requests.Response, None]], None]
|
27
28
|
project_key: Union[str, None]
|
29
|
+
proxies: dict
|
28
30
|
report_key: Union[str, None]
|
29
31
|
request_origin: Union[request_origin.CLI, None]
|
30
32
|
scenario_key: Union[str, None]
|
@@ -37,17 +39,14 @@ def replay_with_trace(context: ReplayContext, trace_context: TraceContext, optio
|
|
37
39
|
trace_context.alias_resolve_strategy = options.get('alias_resolve_strategy')
|
38
40
|
return trace_context.with_replay_context(context, lambda context: replay(context, options))
|
39
41
|
|
40
|
-
def replay_with_rewrite(context: ReplayContext) -> requests.Response:
|
41
|
-
return replay(context, {
|
42
|
-
'before_replay': __handle_before_replay
|
43
|
-
})
|
44
|
-
|
45
42
|
def replay(context: ReplayContext, options: ReplayRequestOptions) -> requests.Response:
|
46
43
|
if 'before_replay' in options and callable(options['before_replay']):
|
47
44
|
options['before_replay'](context)
|
48
45
|
|
49
46
|
request = context.request
|
50
47
|
headers = request.headers
|
48
|
+
method = request.method
|
49
|
+
cookies = __get_cookies(headers)
|
51
50
|
|
52
51
|
if options.get('host'):
|
53
52
|
request.host = options['host']
|
@@ -56,48 +55,70 @@ def replay(context: ReplayContext, options: ReplayRequestOptions) -> requests.Re
|
|
56
55
|
if options.get('scheme'):
|
57
56
|
request.scheme = options['scheme']
|
58
57
|
|
59
|
-
if 'alias_resolve_strategy'
|
58
|
+
if options.get('alias_resolve_strategy'):
|
60
59
|
headers[custom_headers.ALIAS_RESOLVE_STRATEGY] = options['alias_resolve_strategy']
|
61
60
|
|
62
|
-
if 'lifecycle_hooks_script_path'
|
61
|
+
if options.get('lifecycle_hooks_script_path'):
|
63
62
|
__handle_lifecycle_hooks_script_path(options['lifecycle_hooks_script_path'], headers)
|
64
63
|
|
65
|
-
if 'mode'
|
64
|
+
if options.get('mode'):
|
66
65
|
__handle_mode_option(options['mode'], request, headers)
|
67
66
|
|
68
|
-
if 'project_key'
|
67
|
+
if options.get('project_key'):
|
69
68
|
headers[custom_headers.PROJECT_KEY] = options['project_key']
|
70
69
|
|
71
|
-
if 'report_key'
|
70
|
+
if options.get('report_key'):
|
72
71
|
headers[custom_headers.REPORT_KEY] = options['report_key']
|
73
72
|
|
74
|
-
if 'request_origin'
|
73
|
+
if options.get('request_origin'):
|
75
74
|
headers[custom_headers.REQUEST_ORIGIN] = options['request_origin']
|
76
75
|
|
77
|
-
if 'scenario_key'
|
76
|
+
if options.get('scenario_key'):
|
78
77
|
headers[custom_headers.SCENARIO_KEY] = options['scenario_key']
|
79
78
|
|
80
|
-
if 'test_filter'
|
79
|
+
if options.get('test_filter'):
|
81
80
|
headers[custom_headers.TEST_FILTER] = options['test_filter']
|
82
81
|
|
83
|
-
if 'test_strategy'
|
82
|
+
if options.get('test_strategy'):
|
84
83
|
headers[custom_headers.TEST_STRATEGY] = options['test_strategy']
|
85
84
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
85
|
+
request_config = {
|
86
|
+
'allow_redirects': True,
|
87
|
+
'stream': True,
|
88
|
+
'verify': not MitmproxyConfig.instance().get('ssl_insecure')
|
89
|
+
}
|
90
|
+
request_dict = {
|
91
|
+
'cookies': cookies,
|
92
|
+
'data': request.body,
|
93
|
+
'headers': headers,
|
94
|
+
#'params': request.query_params, # Do not send query params, they should be a part of the URL
|
95
|
+
}
|
96
|
+
|
97
|
+
res: requests.Response = None
|
98
|
+
if not options.get('proxy'):
|
99
|
+
request = requests.Request(**{
|
100
|
+
**request_dict,
|
101
|
+
'method': method,
|
102
|
+
'url': request.url,
|
103
|
+
})
|
104
|
+
|
105
|
+
res = simulate_intercept(request, **request_config)
|
106
|
+
else:
|
107
|
+
settings = Settings.instance()
|
108
|
+
handler = getattr(requests, method.lower())
|
109
|
+
|
110
|
+
res = handler(
|
111
|
+
request.url,
|
112
|
+
**{
|
113
|
+
**request_config,
|
114
|
+
**request_dict,
|
115
|
+
'proxies': {
|
116
|
+
'http': settings.proxy.url,
|
117
|
+
'https': settings.proxy.url,
|
118
|
+
},
|
119
|
+
'verify': CACertInstaller().mitm_crt_absolute_path if request_config['verify'] else False,
|
120
|
+
}
|
121
|
+
)
|
101
122
|
|
102
123
|
if 'after_replay' in options and callable(options['after_replay']):
|
103
124
|
context.with_response(res)
|
@@ -119,18 +140,15 @@ def __handle_mode_option(_mode, request: Request, headers):
|
|
119
140
|
|
120
141
|
if _mode == mode.MOCK or _mode == mode.TEST:
|
121
142
|
# If mocking or testing, we already know which request to get response from
|
122
|
-
|
143
|
+
if request.id:
|
144
|
+
headers[custom_headers.MOCK_REQUEST_ID] = str(request.id)
|
145
|
+
|
146
|
+
headers[custom_headers.MOCK_POLICY] = mock_policy.ALL
|
123
147
|
elif _mode == mode.RECORD:
|
124
148
|
# If recording, then it's actually a replay and record
|
125
149
|
headers[custom_headers.PROXY_MODE] = mode.REPLAY
|
126
150
|
headers[custom_headers.RESPONSE_PROXY_MODE] = mode.RECORD
|
127
151
|
|
128
152
|
def __get_cookies(headers: Request.headers):
|
129
|
-
|
130
|
-
|
131
|
-
def __handle_before_replay(context: ReplayContext):
|
132
|
-
request = context.request
|
133
|
-
request_facade = MitmproxyRequestFacade(request)
|
134
|
-
intercept_settings = InterceptSettings(Settings.instance())
|
135
|
-
rewrite_rules = intercept_settings.replay_rewrite_rules
|
136
|
-
request_facade.with_rewrite_rules(rewrite_rules).rewrite()
|
153
|
+
cookies = SimpleCookie(headers.get('Cookie')).items()
|
154
|
+
return {k: v.value for k, v in cookies}
|
@@ -0,0 +1,30 @@
|
|
1
|
+
import pdb
|
2
|
+
import requests
|
3
|
+
|
4
|
+
from mitmproxy.http import Request as MitmproxyRequest
|
5
|
+
|
6
|
+
from stoobly_agent.app.proxy.mitmproxy.flow_mock import MitmproxyFlowMock
|
7
|
+
from stoobly_agent.app.models.adapters.mitmproxy import MitmproxyRequestAdapterFactory, MitmproxyResponseAdapterFactory
|
8
|
+
|
9
|
+
from .intercept_handler import request as handle_request, response as handle_response
|
10
|
+
|
11
|
+
def simulate_intercept(request: requests.Request, **config):
|
12
|
+
flow = MitmproxyFlowMock()
|
13
|
+
|
14
|
+
flow.request = request
|
15
|
+
|
16
|
+
handle_request(flow)
|
17
|
+
|
18
|
+
if not flow.response:
|
19
|
+
session = requests.Session()
|
20
|
+
prepared_request = __prepare_mitmproxy_request(flow.request)
|
21
|
+
res = session.send(prepared_request, **config)
|
22
|
+
flow.response = res
|
23
|
+
|
24
|
+
handle_response(flow)
|
25
|
+
|
26
|
+
return MitmproxyResponseAdapterFactory(flow.response).python_response()
|
27
|
+
|
28
|
+
def __prepare_mitmproxy_request(request: MitmproxyRequest) -> requests.Request:
|
29
|
+
_request = MitmproxyRequestAdapterFactory(request).python_request()
|
30
|
+
return _request.prepare()
|
@@ -20,10 +20,11 @@ from stoobly_agent.lib.api.interfaces.endpoints import EndpointShowResponse
|
|
20
20
|
from stoobly_agent.lib.orm.trace import Trace
|
21
21
|
|
22
22
|
from .context_response import TestContextResponse
|
23
|
+
from .context_abc import TestContextABC
|
23
24
|
|
24
25
|
FuzzyContent = Union[dict, list, str]
|
25
26
|
|
26
|
-
class TestContext():
|
27
|
+
class TestContext(TestContextABC):
|
27
28
|
def __init__(self, replay_context: ReplayContext, mock_context: MockContext):
|
28
29
|
self.__flow = mock_context.flow
|
29
30
|
self.__intercept_settings = mock_context.intercept_settings
|