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
stoobly_agent/__init__.py
CHANGED
@@ -1 +1,2 @@
|
|
1
|
-
|
1
|
+
COMMAND = 'stoobly-agent'
|
2
|
+
VERSION = '0.22.3'
|
@@ -41,12 +41,12 @@ class BodiesController:
|
|
41
41
|
|
42
42
|
accepted_headers = ['content-encoding', 'content-length', 'content-type']
|
43
43
|
for header, val in request.headers.items():
|
44
|
-
decoded_header = header.
|
44
|
+
decoded_header = header.lower()
|
45
45
|
|
46
46
|
if decoded_header not in accepted_headers:
|
47
47
|
continue
|
48
48
|
|
49
|
-
headers[decoded_header] = val
|
49
|
+
headers[decoded_header] = val
|
50
50
|
|
51
51
|
context.render(
|
52
52
|
data = request.data,
|
@@ -1,4 +1,6 @@
|
|
1
|
+
import json
|
1
2
|
import pdb
|
3
|
+
import requests
|
2
4
|
|
3
5
|
from datetime import datetime
|
4
6
|
from time import time
|
@@ -7,15 +9,15 @@ from urllib.parse import urlparse
|
|
7
9
|
from stoobly_agent.app.api.simple_http_request_handler import SimpleHTTPRequestHandler
|
8
10
|
from stoobly_agent.app.cli.helpers.context import ReplayContext
|
9
11
|
from stoobly_agent.app.models.adapters.joined_request_adapter import JoinedRequestAdapter
|
10
|
-
from stoobly_agent.app.models.adapters.
|
11
|
-
from stoobly_agent.app.models.adapters.mitmproxy_response_adapter import MitmproxyResponseAdapter
|
12
|
+
from stoobly_agent.app.models.adapters.python import PythonRequestAdapterFactory, PythonResponseAdapterFactory
|
12
13
|
from stoobly_agent.app.models.adapters.raw_http_request_adapter import RawHttpRequestAdapter
|
13
14
|
from stoobly_agent.app.models.adapters.raw_http_response_adapter import RawHttpResponseAdapter
|
14
15
|
from stoobly_agent.app.models.request_model import RequestModel
|
15
16
|
from stoobly_agent.app.models.schemas.request import Request
|
16
|
-
from stoobly_agent.app.proxy.replay.replay_request_service import
|
17
|
+
from stoobly_agent.app.proxy.replay.replay_request_service import replay
|
17
18
|
from stoobly_agent.app.proxy.upload.upload_request_service import upload_staged_request
|
18
19
|
from stoobly_agent.app.settings import Settings
|
20
|
+
from stoobly_agent.config.constants import mode
|
19
21
|
from stoobly_agent.lib.orm.replayed_response import ReplayedResponse
|
20
22
|
from stoobly_agent.lib.orm.request import Request as OrmRequest
|
21
23
|
|
@@ -52,8 +54,8 @@ class RequestsController:
|
|
52
54
|
request_adapter = RawHttpRequestAdapter(joined_request.request_string.get())
|
53
55
|
response_adapter = RawHttpResponseAdapter(joined_request.response_string.get())
|
54
56
|
|
55
|
-
mitmproxy_request =
|
56
|
-
mitmproxy_response =
|
57
|
+
mitmproxy_request = PythonRequestAdapterFactory(request_adapter.to_request()).mitmproxy_request(request_adapter.protocol)
|
58
|
+
mitmproxy_response = PythonResponseAdapterFactory(response_adapter.to_response()).mitmproxy_response()
|
57
59
|
|
58
60
|
class MitmproxyFlowMock():
|
59
61
|
def __init__(self, request, response):
|
@@ -66,6 +68,7 @@ class RequestsController:
|
|
66
68
|
request = request_model.create(**{
|
67
69
|
'flow': mitmproxy_flow_mock,
|
68
70
|
'joined_request': joined_request,
|
71
|
+
'scenario_id': body_params.get('scenario_id'),
|
69
72
|
})
|
70
73
|
|
71
74
|
if not request:
|
@@ -201,29 +204,21 @@ class RequestsController:
|
|
201
204
|
return context.bad_request(f"Could not find request {request_id}")
|
202
205
|
|
203
206
|
replay_context = ReplayContext(Request(request_response))
|
204
|
-
|
205
|
-
now = time()
|
206
|
-
res = replay_with_rewrite(replay_context)
|
207
|
-
received_at = time()
|
208
|
-
|
209
|
-
replayed_response = ReplayedResponse()
|
210
|
-
replayed_response.request_id = request_id
|
211
|
-
replayed_response.with_python_response(res)
|
212
|
-
replayed_response.latency = (received_at - now) * 1000 # ms
|
213
|
-
replayed_response.save()
|
214
|
-
|
215
|
-
context.render(
|
216
|
-
data = res.raw.data,
|
217
|
-
headers = res.headers,
|
218
|
-
status = res.status_code
|
219
|
-
)
|
207
|
+
self.__replay(context, replay_context)
|
220
208
|
|
221
209
|
# PUT /requests/send
|
222
210
|
def send(self, context: SimpleHTTPRequestHandler):
|
211
|
+
headers = []
|
212
|
+
|
213
|
+
try:
|
214
|
+
headers = json.load(context.params.get('headers'))
|
215
|
+
except Exception as e:
|
216
|
+
pass
|
217
|
+
|
223
218
|
url = urlparse(context.params.get('url'))
|
224
219
|
request_response = {
|
225
220
|
'body': context.params.get('body'),
|
226
|
-
'headers':
|
221
|
+
'headers': headers,
|
227
222
|
'method': context.params.get('method'),
|
228
223
|
'path': url.path,
|
229
224
|
'password': url.password,
|
@@ -234,16 +229,43 @@ class RequestsController:
|
|
234
229
|
}
|
235
230
|
|
236
231
|
replay_context = ReplayContext(Request(request_response))
|
237
|
-
|
232
|
+
self.__send(context, replay_context)
|
233
|
+
|
234
|
+
def export(self, context: SimpleHTTPRequestHandler):
|
235
|
+
context.parse_path_params({
|
236
|
+
'id': 1
|
237
|
+
})
|
238
|
+
request_id = int(context.params.get('id'))
|
239
|
+
|
240
|
+
def __request_model(self, context: SimpleHTTPRequestHandler):
|
241
|
+
request_model = RequestModel(Settings.instance())
|
242
|
+
request_model.as_remote() if context.headers.get('access-token') else request_model.as_local()
|
243
|
+
return request_model
|
244
|
+
|
245
|
+
def __replay(self, context: SimpleHTTPRequestHandler, replay_context: ReplayContext):
|
246
|
+
save = bool(context.params.get('save'))
|
247
|
+
callback = self.__create_replayed_response if save else None
|
248
|
+
|
249
|
+
self.__send(context, replay_context, callback)
|
250
|
+
|
251
|
+
def __send(self, context: SimpleHTTPRequestHandler, replay_context: ReplayContext, callback = None):
|
252
|
+
now = time()
|
253
|
+
res = replay(replay_context, { 'mode': mode.REPLAY })
|
254
|
+
received_at = time()
|
255
|
+
|
256
|
+
if callback:
|
257
|
+
callback(context, res, int((received_at - now) * 1000))
|
238
258
|
|
239
259
|
context.render(
|
240
|
-
data = res.raw.data,
|
260
|
+
data = res.raw.data if hasattr(res, 'raw') else res.content,
|
241
261
|
headers = res.headers,
|
242
262
|
status = res.status_code
|
243
263
|
)
|
244
264
|
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
265
|
+
def __create_replayed_response(self, context: SimpleHTTPRequestHandler, res: requests.Response, latency: int):
|
266
|
+
request_id = int(context.params.get('id'))
|
267
|
+
replayed_response = ReplayedResponse()
|
268
|
+
replayed_response.request_id = request_id
|
269
|
+
replayed_response.with_python_response(res)
|
270
|
+
replayed_response.latency = latency # ms
|
271
|
+
replayed_response.save()
|
@@ -62,7 +62,7 @@ class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):
|
|
62
62
|
headers = self.filter_headers(kwargs.get('headers'), {
|
63
63
|
'TRANSFER-ENCODING': 'CHUNKED',
|
64
64
|
})
|
65
|
-
headers['Content-Length'] = len(body)
|
65
|
+
headers['Content-Length'] = str(len(body))
|
66
66
|
|
67
67
|
self.enable_cors(headers)
|
68
68
|
self.render_headers(headers)
|
@@ -7,19 +7,22 @@ class CACertInstaller():
|
|
7
7
|
home_dir = os.path.expanduser('~')
|
8
8
|
self.mitmproxy_certs_dir = os.path.join(home_dir, '.mitmproxy')
|
9
9
|
self.pem_file_name = 'mitmproxy-ca-cert.pem'
|
10
|
+
self.cer_file_name = 'mitmproxy-ca-cert.cer'
|
10
11
|
self.crt_file_name = 'mitmproxy-ca-cert.crt'
|
11
12
|
|
13
|
+
@property
|
14
|
+
def mitm_crt_absolute_path(self):
|
15
|
+
return os.path.join(self.mitmproxy_certs_dir, self.crt_file_name)
|
16
|
+
|
12
17
|
# https://askubuntu.com/a/94861
|
13
18
|
def handle_debian(self):
|
14
19
|
extra_ca_certs_dir = '/usr/local/share/ca-certificates/extra'
|
15
|
-
|
16
|
-
mitm_crt_absolute_path = os.path.join(self.mitmproxy_certs_dir, self.crt_file_name)
|
20
|
+
mitm_cer_absolute_path = os.path.join(self.mitmproxy_certs_dir, self.cer_file_name)
|
17
21
|
extra_crt_absolute_path = os.path.join(extra_ca_certs_dir, self.crt_file_name)
|
18
22
|
|
19
23
|
subprocess.run(f"sudo mkdir -p {extra_ca_certs_dir}".split(), check=True)
|
20
|
-
subprocess.run(f"
|
21
|
-
subprocess.run(
|
22
|
-
subprocess.run('sudo update-ca-certificates'.split(), check=True)
|
24
|
+
subprocess.run(f"sudo cp {mitm_cer_absolute_path} {extra_crt_absolute_path}".split(), check=True)
|
25
|
+
subprocess.run("sudo update-ca-certificates".split(), check=True)
|
23
26
|
|
24
27
|
# https://www.dssw.co.uk/reference/security.html
|
25
28
|
def handle_darwin(self):
|
@@ -27,3 +30,11 @@ class CACertInstaller():
|
|
27
30
|
mitm_pem_absolute_path = os.path.join(self.mitmproxy_certs_dir, self.pem_file_name)
|
28
31
|
|
29
32
|
subprocess.run(f"sudo security add-trusted-cert -d -p ssl -p basic -k {system_keychain_path} {mitm_pem_absolute_path}".split(), check=True)
|
33
|
+
|
34
|
+
def handle_rhel(self):
|
35
|
+
ca_trust_dir = '/etc/pki/ca-trust/source/anchors'
|
36
|
+
mitm_cer_absolute_path = os.path.join(self.mitmproxy_certs_dir, self.cer_file_name)
|
37
|
+
ca_trust_crt_absolute_path = os.path.join(ca_trust_dir, self.crt_file_name)
|
38
|
+
|
39
|
+
subprocess.run(f"sudo cp {mitm_cer_absolute_path} {ca_trust_crt_absolute_path}".split(), check=True)
|
40
|
+
subprocess.run("sudo update-ca-trust extract".split(), check=True)
|
@@ -12,6 +12,8 @@ from stoobly_agent.config.constants import mode
|
|
12
12
|
from stoobly_agent.lib.api.keys import ProjectKey, ScenarioKey
|
13
13
|
from stoobly_agent.lib.logger import Logger
|
14
14
|
|
15
|
+
from .helpers import ProjectFacade, ScenarioFacade
|
16
|
+
from .helpers.print_service import print_projects, print_scenarios, select_print_options
|
15
17
|
from .helpers.validations import *
|
16
18
|
|
17
19
|
@click.group(
|
@@ -42,170 +44,234 @@ def dump(**kwargs):
|
|
42
44
|
else:
|
43
45
|
print(output)
|
44
46
|
|
45
|
-
|
46
|
-
if is_remote:
|
47
|
-
@click.group(
|
48
|
-
help="Manage active scenario."
|
49
|
-
)
|
50
|
-
@click.pass_context
|
51
|
-
def scenario(ctx):
|
52
|
-
pass
|
47
|
+
### Scenario
|
53
48
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
49
|
+
@click.group(
|
50
|
+
help="Manage active scenario"
|
51
|
+
)
|
52
|
+
@click.pass_context
|
53
|
+
def scenario(ctx):
|
54
|
+
pass
|
60
55
|
|
61
|
-
|
62
|
-
|
56
|
+
@scenario.command(
|
57
|
+
help="Describe scenario"
|
58
|
+
)
|
59
|
+
@click.option('--select', multiple=True, help='Select column(s) to display.')
|
60
|
+
@click.option('--without-headers', is_flag=True, default=False, help='Disable printing column headers.')
|
61
|
+
def show(**kwargs):
|
62
|
+
settings = Settings.instance()
|
63
|
+
print_options = select_print_options(kwargs)
|
63
64
|
|
64
|
-
|
65
|
-
|
66
|
-
project_key = ProjectKey(project_key)
|
65
|
+
project_key = __project_key(settings)
|
66
|
+
data_rule = settings.proxy.data.data_rules(project_key.id)
|
67
67
|
|
68
|
-
|
69
|
-
|
68
|
+
if not data_rule.scenario_key or len(data_rule.scenario_key) == 0:
|
69
|
+
return
|
70
70
|
|
71
|
-
|
72
|
-
data_rule.scenario_key = kwargs['scenario_key']
|
73
|
-
settings.commit()
|
71
|
+
kwargs['key'] = data_rule.scenario_key
|
74
72
|
|
75
|
-
print("Scenario updated!")
|
76
73
|
|
77
|
-
|
78
|
-
|
79
|
-
)
|
80
|
-
@click.pass_context
|
81
|
-
def project(ctx):
|
82
|
-
pass
|
74
|
+
scenario_key = resolve_scenario_key_and_validate(kwargs, settings)
|
75
|
+
scenario = ScenarioFacade(settings)
|
83
76
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
def set(**kwargs):
|
89
|
-
settings = Settings.instance()
|
77
|
+
try:
|
78
|
+
scenario_response = scenario.show(scenario_key)
|
79
|
+
except AssertionError as e:
|
80
|
+
return print(e, file=sys.stderr)
|
90
81
|
|
91
|
-
|
92
|
-
validate_project_key(project_key)
|
93
|
-
_project_key = ProjectKey(project_key)
|
82
|
+
print_scenarios([scenario_response], **print_options)
|
94
83
|
|
95
|
-
|
96
|
-
|
84
|
+
@scenario.command(
|
85
|
+
help="Set active scenario."
|
86
|
+
)
|
87
|
+
@click.argument('scenario_key')
|
88
|
+
def set(**kwargs):
|
89
|
+
validate_scenario_key(kwargs['scenario_key'])
|
90
|
+
scenario_key = ScenarioKey(kwargs['scenario_key'])
|
97
91
|
|
98
|
-
|
99
|
-
|
100
|
-
scenario_key = ScenarioKey(scenario_key)
|
92
|
+
settings = Settings.instance()
|
93
|
+
project_key = __project_key(settings)
|
101
94
|
|
102
|
-
|
103
|
-
|
104
|
-
print("Current scenario does not belong to current project, unsetting current scenario.\n")
|
95
|
+
if scenario_key.project_id != project_key.id:
|
96
|
+
return print("Please provide a scenario that belongs to the current project.\n")
|
105
97
|
|
106
|
-
|
107
|
-
|
98
|
+
data_rule = settings.proxy.data.data_rules(project_key.id)
|
99
|
+
data_rule.scenario_key = kwargs['scenario_key']
|
100
|
+
settings.commit()
|
108
101
|
|
109
|
-
|
102
|
+
print("Scenario updated!")
|
110
103
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
pass
|
104
|
+
@scenario.command(
|
105
|
+
help="Clear active scenario."
|
106
|
+
)
|
107
|
+
def clear(**kwargs):
|
108
|
+
settings = Settings.instance()
|
117
109
|
|
118
|
-
|
119
|
-
|
120
|
-
)
|
121
|
-
|
122
|
-
|
123
|
-
|
110
|
+
project_key = __project_key(settings)
|
111
|
+
|
112
|
+
data_rule = settings.proxy.data.data_rules(project_key.id)
|
113
|
+
data_rule.scenario_key = ''
|
114
|
+
settings.commit()
|
115
|
+
|
116
|
+
print("Scenario cleared!")
|
117
|
+
|
118
|
+
### Rewrite
|
119
|
+
|
120
|
+
@click.group(
|
121
|
+
help="Manage rewrite rules"
|
122
|
+
)
|
123
|
+
@click.pass_context
|
124
|
+
def rewrite(ctx):
|
125
|
+
pass
|
126
|
+
|
127
|
+
@rewrite.command(
|
128
|
+
help="Set rewrite rule."
|
129
|
+
)
|
130
|
+
@click.option(
|
131
|
+
'--method',
|
132
|
+
multiple=True,
|
133
|
+
required=True,
|
134
|
+
type=click.Choice(['GET', 'POST', 'DELETE', 'OPTIONS', 'PUT']),
|
135
|
+
help='HTTP methods.'
|
136
|
+
)
|
137
|
+
@click.option(
|
138
|
+
'--mode',
|
139
|
+
multiple=True,
|
140
|
+
required=True,
|
141
|
+
type=click.Choice([mode.MOCK, mode.RECORD, mode.REPLAY, mode.TEST])
|
142
|
+
)
|
143
|
+
@click.option('--name', required=True, help='Name of the request component.')
|
144
|
+
@click.option('--pattern', required=True, help='URLs pattern.')
|
145
|
+
@click.option('--project_key', help='Project to add rewrite rule to.')
|
146
|
+
@click.option(
|
147
|
+
'--type',
|
148
|
+
required=True,
|
149
|
+
type=click.Choice([request_component.BODY_PARAM, request_component.HEADER, request_component.QUERY_PARAM]),
|
150
|
+
help='Request component type.'
|
151
|
+
)
|
152
|
+
@click.option('--value', required=True, help='Rewrite value.')
|
153
|
+
def set(**kwargs):
|
154
|
+
settings = Settings.instance()
|
155
|
+
project_key_str = resolve_project_key_and_validate(kwargs, settings)
|
156
|
+
project_key = ProjectKey(project_key_str)
|
157
|
+
|
158
|
+
methods = list(kwargs['method'])
|
159
|
+
modes = list(kwargs['mode'])
|
160
|
+
|
161
|
+
rewrite_rules = settings.proxy.rewrite.rewrite_rules(project_key.id)
|
162
|
+
|
163
|
+
rewrite_rule_filter = lambda rule: rule.pattern == kwargs['pattern'] and rule.methods == methods
|
164
|
+
filtered_rewrite_rules: List[RewriteRule] = list(filter(rewrite_rule_filter, rewrite_rules))
|
165
|
+
|
166
|
+
if len(filtered_rewrite_rules) == 0:
|
167
|
+
rewrite_rule = RewriteRule({
|
168
|
+
'methods': methods,
|
169
|
+
'pattern': kwargs['pattern'],
|
170
|
+
'parameter_rules': [__select_parameter_rule(kwargs)]
|
171
|
+
})
|
172
|
+
rewrite_rules.append(rewrite_rule)
|
173
|
+
settings.proxy.rewrite.set_rewrite_rules(project_key.id, rewrite_rules)
|
174
|
+
else:
|
175
|
+
parameter_rule_filter = lambda rule: rule.name == kwargs['name'] and rule.type == kwargs['type'] and rule.modes == modes
|
176
|
+
for rewrite_rule in filtered_rewrite_rules:
|
177
|
+
parameter_rules = rewrite_rule.parameter_rules
|
178
|
+
filtered_parameter_rules: List[ParameterRule] = list(filter(parameter_rule_filter, parameter_rules))
|
179
|
+
parameter_rule_dict = __select_parameter_rule(kwargs)
|
180
|
+
|
181
|
+
if len(filtered_parameter_rules) == 0:
|
182
|
+
parameter_rule = ParameterRule(parameter_rule_dict)
|
183
|
+
parameter_rules.append(parameter_rule)
|
184
|
+
rewrite_rule.parameter_rules = parameter_rules
|
185
|
+
else:
|
186
|
+
for parameter_rule in filtered_parameter_rules:
|
187
|
+
parameter_rule.update(parameter_rule_dict)
|
188
|
+
|
189
|
+
settings.commit()
|
190
|
+
|
191
|
+
Logger.instance().debug(f"Rewrite {kwargs['name']} -> {kwargs['value']} set!")
|
192
|
+
|
193
|
+
### API Key
|
194
|
+
|
195
|
+
@click.group(
|
196
|
+
help="Manage API key"
|
197
|
+
)
|
198
|
+
@click.pass_context
|
199
|
+
def api_key(ctx):
|
200
|
+
pass
|
124
201
|
|
125
|
-
|
126
|
-
|
202
|
+
@api_key.command(
|
203
|
+
help="Set API Key"
|
204
|
+
)
|
205
|
+
@click.argument('api_key')
|
206
|
+
def set(**kwargs):
|
207
|
+
settings = Settings.instance()
|
208
|
+
|
209
|
+
api_key = kwargs['api_key']
|
210
|
+
settings.remote.api_key = api_key
|
127
211
|
|
128
|
-
|
212
|
+
settings.commit()
|
129
213
|
|
130
|
-
|
214
|
+
print("API Key updated!")
|
131
215
|
|
216
|
+
is_remote = Settings.instance().cli.features.remote
|
217
|
+
if is_remote:
|
132
218
|
@click.group(
|
133
|
-
help="Manage
|
219
|
+
help="Manage active project"
|
134
220
|
)
|
135
221
|
@click.pass_context
|
136
|
-
def
|
222
|
+
def project(ctx):
|
137
223
|
pass
|
138
224
|
|
139
|
-
@
|
140
|
-
help="
|
141
|
-
)
|
142
|
-
@click.option(
|
143
|
-
'--method',
|
144
|
-
multiple=True,
|
145
|
-
required=True,
|
146
|
-
type=click.Choice(['GET', 'POST', 'DELETE', 'OPTIONS', 'PUT']),
|
147
|
-
help='HTTP methods.'
|
225
|
+
@project.command(
|
226
|
+
help="Use local project."
|
148
227
|
)
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
228
|
+
def local(**kwargs):
|
229
|
+
project_key = ProjectKey.local_key
|
230
|
+
__set_project_key(project_key)
|
231
|
+
|
232
|
+
print("Using local project!")
|
233
|
+
|
234
|
+
@project.command(
|
235
|
+
help="Describe project."
|
154
236
|
)
|
155
|
-
@click.option('--
|
156
|
-
@click.option('--
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
237
|
+
@click.option('--select', multiple=True, help='Select column(s) to display.')
|
238
|
+
@click.option('--without-headers', is_flag=True, default=False, help='Disable printing column headers.')
|
239
|
+
def show(**kwargs):
|
240
|
+
settings = Settings.instance()
|
241
|
+
print_options = select_print_options(kwargs)
|
242
|
+
|
243
|
+
project_key = __project_key(settings)
|
244
|
+
if project_key.is_local:
|
245
|
+
return print('Using local project')
|
246
|
+
|
247
|
+
kwargs['project_key'] = project_key.raw
|
248
|
+
|
249
|
+
project_key = resolve_project_key_and_validate(kwargs, settings)
|
250
|
+
project = ProjectFacade(settings)
|
251
|
+
|
252
|
+
try:
|
253
|
+
project_response = project.show(project_key)
|
254
|
+
except AssertionError as e:
|
255
|
+
return print(e, file=sys.stderr)
|
256
|
+
|
257
|
+
print_projects([project_response], **print_options)
|
258
|
+
|
259
|
+
@project.command(
|
260
|
+
help="Set active project."
|
163
261
|
)
|
164
|
-
@click.
|
262
|
+
@click.argument('project_key')
|
165
263
|
def set(**kwargs):
|
166
|
-
|
167
|
-
|
168
|
-
project_key
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
rewrite_rules = settings.proxy.rewrite.rewrite_rules(project_key.id)
|
174
|
-
|
175
|
-
rewrite_rule_filter = lambda rule: rule.pattern == kwargs['pattern'] and rule.methods == methods
|
176
|
-
filtered_rewrite_rules: List[RewriteRule] = list(filter(rewrite_rule_filter, rewrite_rules))
|
177
|
-
|
178
|
-
if len(filtered_rewrite_rules) == 0:
|
179
|
-
rewrite_rule = RewriteRule({
|
180
|
-
'methods': methods,
|
181
|
-
'pattern': kwargs['pattern'],
|
182
|
-
'parameter_rules': [__select_parameter_rule(kwargs)]
|
183
|
-
})
|
184
|
-
rewrite_rules.append(rewrite_rule)
|
185
|
-
settings.proxy.rewrite.set_rewrite_rules(project_key.id, rewrite_rules)
|
186
|
-
else:
|
187
|
-
parameter_rule_filter = lambda rule: rule.name == kwargs['name'] and rule.type == kwargs['type'] and rule.modes == modes
|
188
|
-
for rewrite_rule in filtered_rewrite_rules:
|
189
|
-
parameter_rules = rewrite_rule.parameter_rules
|
190
|
-
filtered_parameter_rules: List[ParameterRule] = list(filter(parameter_rule_filter, parameter_rules))
|
191
|
-
parameter_rule_dict = __select_parameter_rule(kwargs)
|
192
|
-
|
193
|
-
if len(filtered_parameter_rules) == 0:
|
194
|
-
parameter_rule = ParameterRule(parameter_rule_dict)
|
195
|
-
parameter_rules.append(parameter_rule)
|
196
|
-
rewrite_rule.parameter_rules = parameter_rules
|
197
|
-
else:
|
198
|
-
for parameter_rule in filtered_parameter_rules:
|
199
|
-
parameter_rule.update(parameter_rule_dict)
|
200
|
-
|
201
|
-
settings.commit()
|
202
|
-
|
203
|
-
Logger.instance().debug(f"Rewrite {kwargs['name']} -> {kwargs['value']} set!")
|
204
|
-
|
205
|
-
config.add_command(api_key)
|
264
|
+
project_key = kwargs['project_key']
|
265
|
+
|
266
|
+
__set_project_key(project_key)
|
267
|
+
|
268
|
+
print("Project updated!")
|
269
|
+
|
206
270
|
config.add_command(project)
|
207
|
-
|
208
|
-
|
271
|
+
|
272
|
+
config.add_command(api_key)
|
273
|
+
config.add_command(rewrite)
|
274
|
+
config.add_command(scenario)
|
209
275
|
|
210
276
|
def __select_parameter_rule(kwargs):
|
211
277
|
return {
|
@@ -213,4 +279,28 @@ def __select_parameter_rule(kwargs):
|
|
213
279
|
'name': kwargs['name'],
|
214
280
|
'value': kwargs['value'],
|
215
281
|
'type': kwargs['type'],
|
216
|
-
}
|
282
|
+
}
|
283
|
+
|
284
|
+
def __project_key(settings):
|
285
|
+
project_key = settings.proxy.intercept.project_key
|
286
|
+
validate_project_key(project_key)
|
287
|
+
return ProjectKey(project_key)
|
288
|
+
|
289
|
+
def __set_project_key(project_key: str):
|
290
|
+
settings = Settings.instance()
|
291
|
+
validate_project_key(project_key)
|
292
|
+
_project_key = ProjectKey(project_key)
|
293
|
+
|
294
|
+
data_rule = settings.proxy.data.data_rules(_project_key.id)
|
295
|
+
scenario_key = data_rule.scenario_key
|
296
|
+
|
297
|
+
if scenario_key:
|
298
|
+
validate_scenario_key(scenario_key)
|
299
|
+
scenario_key = ScenarioKey(scenario_key)
|
300
|
+
|
301
|
+
if project_key.id != scenario_key.project_id:
|
302
|
+
data_rule.scenario_key = None
|
303
|
+
print("Current scenario does not belong to current project, unsetting current scenario.\n")
|
304
|
+
|
305
|
+
settings.proxy.intercept.project_key = project_key
|
306
|
+
settings.commit()
|
@@ -1,5 +1,7 @@
|
|
1
1
|
import click
|
2
2
|
import pdb
|
3
|
+
|
4
|
+
from stoobly_agent import VERSION
|
3
5
|
from stoobly_agent.app.proxy.replay.body_parser_service import decode_response
|
4
6
|
from stoobly_agent.app.models.adapters.raw_http_response_adapter import RawHttpResponseAdapter
|
5
7
|
from stoobly_agent.lib.orm.migrate_service import migrate as database_migrate, rollback as database_rollback
|
@@ -26,7 +28,7 @@ def debug(**kwargs):
|
|
26
28
|
|
27
29
|
@dev_tools.command()
|
28
30
|
def migrate():
|
29
|
-
database_migrate()
|
31
|
+
database_migrate(VERSION)
|
30
32
|
|
31
33
|
@dev_tools.command()
|
32
34
|
def rollback():
|
@@ -1,6 +1,8 @@
|
|
1
|
+
import pdb
|
1
2
|
import requests
|
2
3
|
import time
|
3
4
|
|
5
|
+
from stoobly_agent.app.models.adapters.python import PythonRequestAdapterFactory
|
4
6
|
from stoobly_agent.app.models.schemas.request import Request
|
5
7
|
|
6
8
|
class ReplayContext():
|
@@ -14,6 +16,11 @@ class ReplayContext():
|
|
14
16
|
|
15
17
|
self.__sequence = None
|
16
18
|
|
19
|
+
@classmethod
|
20
|
+
def from_python_request(cls, request: requests.Request):
|
21
|
+
stoobly_request = PythonRequestAdapterFactory(request).stoobly_request()
|
22
|
+
return cls(Request(stoobly_request))
|
23
|
+
|
17
24
|
@property
|
18
25
|
def end_time(self):
|
19
26
|
return self.__end_time
|
@@ -0,0 +1,14 @@
|
|
1
|
+
import requests
|
2
|
+
|
3
|
+
from stoobly_agent.app.models.adapters.python import PythonResponseAdapterFactory
|
4
|
+
from stoobly_agent.app.proxy.mitmproxy.response_facade import MitmproxyResponseFacade
|
5
|
+
from stoobly_agent.app.proxy.upload.response_string import ResponseString
|
6
|
+
|
7
|
+
RAW_FORMAT = 'raw'
|
8
|
+
|
9
|
+
def print_raw_response(response: requests.Response):
|
10
|
+
mitmproxy_response = PythonResponseAdapterFactory(response).mitmproxy_response()
|
11
|
+
facade = MitmproxyResponseFacade(mitmproxy_response)
|
12
|
+
response_string = ResponseString(facade, None)
|
13
|
+
|
14
|
+
print(response_string.get().decode())
|