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.
Files changed (227) hide show
  1. stoobly_agent/__init__.py +2 -1
  2. stoobly_agent/app/api/bodies_controller.py +2 -2
  3. stoobly_agent/app/api/requests_controller.py +51 -29
  4. stoobly_agent/app/api/simple_http_request_handler.py +1 -1
  5. stoobly_agent/app/cli/ca_cert_installer.py +16 -5
  6. stoobly_agent/app/cli/config_cli.py +225 -135
  7. stoobly_agent/app/cli/dev_tools_cli.py +3 -1
  8. stoobly_agent/app/cli/helpers/__init__.py +2 -1
  9. stoobly_agent/app/cli/helpers/context.py +7 -0
  10. stoobly_agent/app/cli/helpers/handle_mock_service.py +14 -0
  11. stoobly_agent/app/cli/helpers/print_service.py +8 -0
  12. stoobly_agent/app/cli/helpers/scenario_facade.py +10 -28
  13. stoobly_agent/app/cli/intercept.py +46 -2
  14. stoobly_agent/app/cli/main_group.py +8 -9
  15. stoobly_agent/app/cli/project_cli.py +10 -27
  16. stoobly_agent/app/cli/request_cli.py +14 -18
  17. stoobly_agent/app/cli/scenario_cli.py +94 -87
  18. stoobly_agent/app/models/adapters/mitmproxy/__init__.py +2 -0
  19. stoobly_agent/app/models/adapters/mitmproxy/request/__init__.py +12 -0
  20. stoobly_agent/app/models/adapters/mitmproxy/request/python_adapter.py +16 -0
  21. stoobly_agent/app/models/adapters/mitmproxy/response/__init__.py +12 -0
  22. stoobly_agent/app/models/adapters/mitmproxy/response/python_adapter.py +24 -0
  23. stoobly_agent/app/models/adapters/python/__init__.py +2 -0
  24. stoobly_agent/app/models/adapters/python/request/__init__.py +18 -0
  25. stoobly_agent/app/models/adapters/python/request/mitmproxy_adapter.py +53 -0
  26. stoobly_agent/app/models/adapters/python/request/stoobly_adapter.py +49 -0
  27. stoobly_agent/app/models/adapters/python/response/__init__.py +13 -0
  28. stoobly_agent/app/models/adapters/{mitmproxy_response_adapter.py → python/response/mitmproxy_adapter.py} +15 -7
  29. stoobly_agent/app/models/adapters/raw_http_request_adapter.py +19 -12
  30. stoobly_agent/app/models/adapters/raw_http_response_adapter.py +22 -12
  31. stoobly_agent/app/models/adapters/stoobly/request/__init__.py +11 -0
  32. stoobly_agent/app/models/adapters/stoobly/request/mitmproxy_adapter.py +32 -0
  33. stoobly_agent/app/models/body_model.py +2 -2
  34. stoobly_agent/app/models/factories/__init__.py +0 -0
  35. stoobly_agent/app/models/factories/resource/__init__.py +0 -0
  36. stoobly_agent/app/models/{adapters/body_adapter_factory.py → factories/resource/body.py} +1 -1
  37. stoobly_agent/app/models/{adapters/header_adapter_factory.py → factories/resource/header.py} +1 -1
  38. stoobly_agent/app/models/factories/resource/local_db/__init__.py +0 -0
  39. stoobly_agent/app/models/{adapters → factories/resource}/local_db/header_adapter.py +2 -2
  40. stoobly_agent/app/models/{adapters → factories/resource}/local_db/replayed_response_adapter.py +1 -2
  41. stoobly_agent/app/models/{adapters → factories/resource}/local_db/request_adapter.py +15 -8
  42. stoobly_agent/app/models/{adapters → factories/resource}/local_db/scenario_adapter.py +13 -7
  43. stoobly_agent/app/models/{adapters/query_param_adapter_factory.py → factories/resource/query_param.py} +1 -1
  44. stoobly_agent/app/models/{adapters/replayed_response_adapter_factory.py → factories/resource/replayed_response.py} +1 -1
  45. stoobly_agent/app/models/{adapters/request_adapter_factory.py → factories/resource/request.py} +2 -2
  46. stoobly_agent/app/models/{adapters/response_adapter_factory.py → factories/resource/response.py} +1 -1
  47. stoobly_agent/app/models/{adapters/response_header_adapter_factory.py → factories/resource/response_header.py} +1 -1
  48. stoobly_agent/app/models/{adapters/scenario_adapter_factory.py → factories/resource/scenario.py} +2 -2
  49. stoobly_agent/app/models/factories/resource/stoobly/__init__.py +0 -0
  50. stoobly_agent/app/models/{adapters/stoobly_request_adapter.py → factories/resource/stoobly/request_adapter.py} +1 -2
  51. stoobly_agent/app/models/{adapters/stoobly_scenario_adapter.py → factories/resource/stoobly/scenario_adapter.py} +1 -2
  52. stoobly_agent/app/models/header_model.py +2 -2
  53. stoobly_agent/app/models/query_param_model.py +2 -2
  54. stoobly_agent/app/models/replayed_response_model.py +2 -2
  55. stoobly_agent/app/models/request_model.py +4 -5
  56. stoobly_agent/app/models/response_header_model.py +2 -2
  57. stoobly_agent/app/models/response_model.py +2 -2
  58. stoobly_agent/app/models/scenario_model.py +4 -4
  59. stoobly_agent/app/models/schemas/request.py +8 -1
  60. stoobly_agent/app/models/types/__init__.py +6 -0
  61. stoobly_agent/app/proxy/__init__.py +0 -5
  62. stoobly_agent/app/proxy/handle_mock_service.py +0 -3
  63. stoobly_agent/app/proxy/handle_test_service.py +1 -1
  64. stoobly_agent/app/proxy/intercept_handler.py +0 -1
  65. stoobly_agent/app/proxy/mitmproxy/flow_mock.py +35 -0
  66. stoobly_agent/app/proxy/mitmproxy/request_facade.py +11 -2
  67. stoobly_agent/app/proxy/mock/hashed_request_decorator.py +2 -2
  68. stoobly_agent/app/proxy/replay/replay_request_service.py +58 -40
  69. stoobly_agent/app/proxy/simulate_intercept_service.py +30 -0
  70. stoobly_agent/app/proxy/test/__init__.py +1 -0
  71. stoobly_agent/app/proxy/test/context.py +2 -1
  72. stoobly_agent/app/proxy/test/context_abc.py +155 -0
  73. stoobly_agent/app/proxy/test/matchers/context.py +1 -1
  74. stoobly_agent/app/proxy/test/matchers/contract.py +1 -1
  75. stoobly_agent/app/proxy/test/matchers/custom.py +1 -1
  76. stoobly_agent/app/proxy/test/matchers/diff.py +1 -1
  77. stoobly_agent/app/proxy/test/matchers/fuzzy.py +1 -1
  78. stoobly_agent/app/proxy/test/test_service.py +1 -1
  79. stoobly_agent/app/proxy/upload/joined_request.py +0 -1
  80. stoobly_agent/app/proxy/upload/proxy_request.py +4 -1
  81. stoobly_agent/app/proxy/upload/request_string.py +1 -1
  82. stoobly_agent/app/settings/constants/mode.py +3 -0
  83. stoobly_agent/app/settings/data_settings.py +3 -1
  84. stoobly_agent/cli.py +89 -11
  85. stoobly_agent/config/constants/env_vars.py +2 -1
  86. stoobly_agent/config/data_dir.py +29 -8
  87. stoobly_agent/config/settings.yml.sample +1 -1
  88. stoobly_agent/db/migrations/2022_12_12_092437_align_requests.py +4 -4
  89. stoobly_agent/lib/api/api.py +4 -4
  90. stoobly_agent/lib/api/keys/organization_key.py +2 -0
  91. stoobly_agent/lib/api/keys/project_key.py +13 -0
  92. stoobly_agent/lib/api/keys/resource_key.py +5 -3
  93. stoobly_agent/lib/api/scenarios_resource.py +4 -12
  94. stoobly_agent/lib/api/stoobly_api.py +9 -5
  95. stoobly_agent/lib/orm/__init__.py +1 -1
  96. stoobly_agent/lib/orm/migrate_service.py +28 -13
  97. stoobly_agent/lib/orm/replayed_response.py +3 -3
  98. stoobly_agent/lib/orm/request.py +25 -5
  99. stoobly_agent/lib/orm/transformers/orm_to_stoobly_request_transformer.py +15 -24
  100. stoobly_agent/mock.py +94 -0
  101. stoobly_agent/public/{2-es2015.3d54569af612a07a2e06.js → 1-es2015.37917aa26708d8f35d36.js} +1 -1
  102. stoobly_agent/public/{2-es5.3d54569af612a07a2e06.js → 1-es5.37917aa26708d8f35d36.js} +1 -1
  103. stoobly_agent/public/10-es2015.e9556b0d0f0e92fb548b.js +1 -0
  104. stoobly_agent/public/10-es5.e9556b0d0f0e92fb548b.js +1 -0
  105. stoobly_agent/public/11-es2015.bc6212fccbe72a623f81.js +1 -0
  106. stoobly_agent/public/11-es5.bc6212fccbe72a623f81.js +1 -0
  107. stoobly_agent/public/{13-es2015.76b6c147b0c46f995cd7.js → 12-es2015.d0768894ddffd6efa5e5.js} +1 -1
  108. stoobly_agent/public/{13-es5.76b6c147b0c46f995cd7.js → 12-es5.d0768894ddffd6efa5e5.js} +1 -1
  109. stoobly_agent/public/13-es2015.8a044490a76fd298162d.js +1 -0
  110. stoobly_agent/public/13-es5.8a044490a76fd298162d.js +1 -0
  111. stoobly_agent/public/{15-es2015.60c3b41c385f5bdedb7b.js → 14-es2015.1cd1a021e51ca0e62e1c.js} +1 -1
  112. stoobly_agent/public/{15-es5.60c3b41c385f5bdedb7b.js → 14-es5.1cd1a021e51ca0e62e1c.js} +1 -1
  113. stoobly_agent/public/{16-es2015.5d395009a77978db4405.js → 15-es2015.587781d19864ff0eb4f5.js} +1 -1
  114. stoobly_agent/public/{16-es5.5d395009a77978db4405.js → 15-es5.587781d19864ff0eb4f5.js} +1 -1
  115. stoobly_agent/public/16-es2015.ec6a175b1f9578203cd8.js +1 -0
  116. stoobly_agent/public/16-es5.ec6a175b1f9578203cd8.js +1 -0
  117. stoobly_agent/public/17-es2015.ad9c4756c96a15bd29d7.js +1 -0
  118. stoobly_agent/public/17-es5.ad9c4756c96a15bd29d7.js +1 -0
  119. stoobly_agent/public/{19-es2015.517f68e08f4c582dae66.js → 18-es2015.8583df0f8eccb3e47c0b.js} +1 -1
  120. stoobly_agent/public/{19-es5.517f68e08f4c582dae66.js → 18-es5.8583df0f8eccb3e47c0b.js} +1 -1
  121. stoobly_agent/public/{20-es2015.473486aabfa4d4a6431b.js → 19-es2015.d0225852a844dc03a09f.js} +1 -1
  122. stoobly_agent/public/{20-es5.473486aabfa4d4a6431b.js → 19-es5.d0225852a844dc03a09f.js} +1 -1
  123. stoobly_agent/public/{3-es5.1dad290844ea619e4c16.js → 2-es2015.8f184ac63348ba447b1f.js} +1 -1
  124. stoobly_agent/public/{3-es2015.1dad290844ea619e4c16.js → 2-es5.8f184ac63348ba447b1f.js} +1 -1
  125. stoobly_agent/public/{21-es2015.56aa10803cc1348a55a3.js → 20-es2015.f7c107847935264d58aa.js} +1 -1
  126. stoobly_agent/public/{21-es5.56aa10803cc1348a55a3.js → 20-es5.f7c107847935264d58aa.js} +1 -1
  127. stoobly_agent/public/{22-es2015.46d81010003b2a50eeab.js → 21-es2015.dd358e1edaf3d32dd2c0.js} +1 -1
  128. stoobly_agent/public/{22-es5.46d81010003b2a50eeab.js → 21-es5.dd358e1edaf3d32dd2c0.js} +1 -1
  129. stoobly_agent/public/26-es2015.6332c32f1b7c8c288f2f.js +1 -0
  130. stoobly_agent/public/26-es5.6332c32f1b7c8c288f2f.js +1 -0
  131. stoobly_agent/public/27-es2015.af505e744b0c869a93d1.js +1 -0
  132. stoobly_agent/public/27-es5.af505e744b0c869a93d1.js +1 -0
  133. stoobly_agent/public/28-es2015.7c7c0f64e4af29d2e4d4.js +1 -0
  134. stoobly_agent/public/28-es5.7c7c0f64e4af29d2e4d4.js +1 -0
  135. stoobly_agent/public/32-es2015.2ab8267be7275dee9059.js +1 -0
  136. stoobly_agent/public/32-es5.2ab8267be7275dee9059.js +1 -0
  137. stoobly_agent/public/{34-es2015.ef24f6f7630620a38b19.js → 33-es2015.5b575f3a87c6c2c6b93b.js} +1 -1
  138. stoobly_agent/public/{34-es5.ef24f6f7630620a38b19.js → 33-es5.5b575f3a87c6c2c6b93b.js} +1 -1
  139. stoobly_agent/public/{35-es2015.0667e742725cc828f59f.js → 34-es2015.6a1160649c718cdb9338.js} +1 -1
  140. stoobly_agent/public/{35-es5.0667e742725cc828f59f.js → 34-es5.6a1160649c718cdb9338.js} +1 -1
  141. stoobly_agent/public/35-es2015.1b9dc7a46a6d5296c3ae.js +1 -0
  142. stoobly_agent/public/35-es5.1b9dc7a46a6d5296c3ae.js +1 -0
  143. stoobly_agent/public/{37-es2015.50d0c2d3fe4d0a74fc8f.js → 36-es2015.2fc9151fe6a5ff2bff31.js} +1 -1
  144. stoobly_agent/public/{37-es5.50d0c2d3fe4d0a74fc8f.js → 36-es5.2fc9151fe6a5ff2bff31.js} +1 -1
  145. stoobly_agent/public/{38-es2015.c14bde0b8d0cc14e915e.js → 37-es2015.ac7108c3625fd6e1d981.js} +1 -1
  146. stoobly_agent/public/{38-es5.c14bde0b8d0cc14e915e.js → 37-es5.ac7108c3625fd6e1d981.js} +1 -1
  147. stoobly_agent/public/38-es2015.9c183b14373c0e449932.js +1 -0
  148. stoobly_agent/public/38-es5.9c183b14373c0e449932.js +1 -0
  149. stoobly_agent/public/39-es2015.4624cdeb29fe9850b216.js +1 -0
  150. stoobly_agent/public/39-es5.4624cdeb29fe9850b216.js +1 -0
  151. stoobly_agent/public/40-es2015.24d981230c0c8f369cde.js +1 -0
  152. stoobly_agent/public/40-es5.24d981230c0c8f369cde.js +1 -0
  153. stoobly_agent/public/{46-es2015.abc7e4fd207d54277fcb.js → 45-es2015.c76937ed45d460bcd36f.js} +1 -1
  154. stoobly_agent/public/{46-es5.abc7e4fd207d54277fcb.js → 45-es5.c76937ed45d460bcd36f.js} +1 -1
  155. stoobly_agent/public/6-es2015.53acc5d2ca7f48ef857f.js +1 -0
  156. stoobly_agent/public/6-es5.53acc5d2ca7f48ef857f.js +1 -0
  157. stoobly_agent/public/7-es2015.1c6b3d315d50ccd228cb.js +1 -0
  158. stoobly_agent/public/7-es5.1c6b3d315d50ccd228cb.js +1 -0
  159. stoobly_agent/public/{9-es2015.ef0f7cb32f5fadb085d0.js → 8-es2015.0fe7492f7b61eb4699b6.js} +1 -1
  160. stoobly_agent/public/{9-es5.ef0f7cb32f5fadb085d0.js → 8-es5.0fe7492f7b61eb4699b6.js} +1 -1
  161. stoobly_agent/public/common-es2015.86f70de6df2c705a87f6.js +1 -0
  162. stoobly_agent/public/common-es5.86f70de6df2c705a87f6.js +1 -0
  163. stoobly_agent/public/dashboard.agent-alpha-0.22.3.tar.gz +0 -0
  164. stoobly_agent/public/index.html +1 -1
  165. stoobly_agent/public/main-es2015.aceb967cb4cccc0bc521.js +1 -0
  166. stoobly_agent/public/main-es5.aceb967cb4cccc0bc521.js +1 -0
  167. stoobly_agent/public/{polyfills-es2015.2b40b2ecdf98a9210572.js → polyfills-es2015.580f7a6e775c2c348c9d.js} +1 -1
  168. stoobly_agent/public/{polyfills-es5.d9fb2eee68607c3f7f64.js → polyfills-es5.4c3461a071d35be3dd81.js} +1 -1
  169. stoobly_agent/public/runtime-es2015.49eaebd2913fa7fe2b97.js +1 -0
  170. stoobly_agent/public/runtime-es5.49eaebd2913fa7fe2b97.js +1 -0
  171. stoobly_agent/test/test_helper.py +4 -5
  172. {stoobly_agent-0.21.0.dist-info → stoobly_agent-0.22.3.dist-info}/METADATA +1 -1
  173. {stoobly_agent-0.21.0.dist-info → stoobly_agent-0.22.3.dist-info}/RECORD +186 -168
  174. {stoobly_agent-0.21.0.dist-info → stoobly_agent-0.22.3.dist-info}/WHEEL +1 -1
  175. stoobly_agent/app/models/adapters/mitmproxy_request_adapter.py +0 -60
  176. stoobly_agent/app/models/adapters/types/__init__.py +0 -3
  177. stoobly_agent/public/11-es2015.b85bdc528bab0ee542fe.js +0 -1
  178. stoobly_agent/public/11-es5.b85bdc528bab0ee542fe.js +0 -1
  179. stoobly_agent/public/12-es2015.72399d40488de533bb97.js +0 -1
  180. stoobly_agent/public/12-es5.72399d40488de533bb97.js +0 -1
  181. stoobly_agent/public/14-es2015.7cedfd0829bd7a64677a.js +0 -1
  182. stoobly_agent/public/14-es5.7cedfd0829bd7a64677a.js +0 -1
  183. stoobly_agent/public/17-es2015.f6f28ba9f681063632a8.js +0 -1
  184. stoobly_agent/public/17-es5.f6f28ba9f681063632a8.js +0 -1
  185. stoobly_agent/public/18-es2015.b0cd6822ebd1090b0d60.js +0 -1
  186. stoobly_agent/public/18-es5.b0cd6822ebd1090b0d60.js +0 -1
  187. stoobly_agent/public/27-es2015.4635450ff709f7868796.js +0 -1
  188. stoobly_agent/public/27-es5.4635450ff709f7868796.js +0 -1
  189. stoobly_agent/public/28-es2015.1b29b35529772ab108f1.js +0 -1
  190. stoobly_agent/public/28-es5.1b29b35529772ab108f1.js +0 -1
  191. stoobly_agent/public/32-es2015.862b67803e6242451976.js +0 -1
  192. stoobly_agent/public/32-es5.862b67803e6242451976.js +0 -1
  193. stoobly_agent/public/33-es2015.4ff4325d1aec37e1b43c.js +0 -1
  194. stoobly_agent/public/33-es5.4ff4325d1aec37e1b43c.js +0 -1
  195. stoobly_agent/public/36-es2015.cd370fdf8990019d0c8e.js +0 -1
  196. stoobly_agent/public/36-es5.cd370fdf8990019d0c8e.js +0 -1
  197. stoobly_agent/public/39-es2015.4ec5fc16202c4759eac4.js +0 -1
  198. stoobly_agent/public/39-es5.4ec5fc16202c4759eac4.js +0 -1
  199. stoobly_agent/public/40-es2015.25287ce77b40050f3471.js +0 -1
  200. stoobly_agent/public/40-es5.25287ce77b40050f3471.js +0 -1
  201. stoobly_agent/public/45-es2015.fd110741ac0fbaada177.js +0 -1
  202. stoobly_agent/public/45-es5.fd110741ac0fbaada177.js +0 -1
  203. stoobly_agent/public/6-es2015.7219d596e3545ebaed3a.js +0 -1
  204. stoobly_agent/public/6-es5.7219d596e3545ebaed3a.js +0 -1
  205. stoobly_agent/public/7-es2015.98b085349ebd9d246060.js +0 -1
  206. stoobly_agent/public/7-es5.98b085349ebd9d246060.js +0 -1
  207. stoobly_agent/public/8-es2015.335fd5c122ad083aec65.js +0 -1
  208. stoobly_agent/public/8-es5.335fd5c122ad083aec65.js +0 -1
  209. stoobly_agent/public/common-es2015.81f870bf87411a04446d.js +0 -1
  210. stoobly_agent/public/common-es5.81f870bf87411a04446d.js +0 -1
  211. stoobly_agent/public/dashboard.agent-alpha-0.21.0.tar.gz +0 -0
  212. stoobly_agent/public/main-es2015.575c1d17fc866d3a6649.js +0 -1
  213. stoobly_agent/public/main-es5.575c1d17fc866d3a6649.js +0 -1
  214. stoobly_agent/public/runtime-es2015.8915d042dc9b55368999.js +0 -1
  215. stoobly_agent/public/runtime-es5.8915d042dc9b55368999.js +0 -1
  216. /stoobly_agent/app/models/adapters/{local_db → stoobly}/__init__.py +0 -0
  217. /stoobly_agent/app/models/{adapters → factories/resource}/local_db/body_adapter.py +0 -0
  218. /stoobly_agent/app/models/{adapters → factories/resource}/local_db/query_param_adapter.py +0 -0
  219. /stoobly_agent/app/models/{adapters → factories/resource}/local_db/response_adapter.py +0 -0
  220. /stoobly_agent/app/models/{adapters → factories/resource}/local_db/response_header_adapter.py +0 -0
  221. /stoobly_agent/app/models/{adapters/types → types}/replayed_response.py +0 -0
  222. /stoobly_agent/app/models/{adapters/types → types}/request_create_params.py +0 -0
  223. /stoobly_agent/app/models/{adapters/types → types}/request_show_params.py +0 -0
  224. /stoobly_agent/app/models/{adapters/types → types}/scenario_create_params.py +0 -0
  225. {stoobly_agent-0.21.0.dist-info → stoobly_agent-0.22.3.dist-info}/LICENSE +0 -0
  226. {stoobly_agent-0.21.0.dist-info → stoobly_agent-0.22.3.dist-info}/entry_points.txt +0 -0
  227. {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 = HeaderAdapterFactory(self.settings.remote).local_db()
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 .adapters.query_param_adapter_factory import QueryParamAdapterFactory
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 = QueryParamAdapterFactory(self.settings.remote).local_db()
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 = ReplayedResponseAdapterFactory(self.settings.remote).local_db()
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 .adapters.request_adapter_factory import RequestAdapterFactory
12
- from .adapters.types import RequestCreateParams, RequestShowParams
11
+ from .factories.resource.request import RequestResourceFactory
13
12
  from .model import Model
14
- from .types.requests_model_index import RequestsModelIndex
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 = RequestAdapterFactory(self.settings.remote).local_db()
21
+ self.adapter = RequestResourceFactory(self.settings.remote).local_db()
23
22
 
24
23
  def as_remote(self):
25
- self.adapter = RequestAdapterFactory(self.settings.remote).stoobly()
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 .adapters.response_header_adapter_factory import ResponseHeaderAdapterFactory
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 = ResponseHeaderAdapterFactory(self.settings.remote).local_db()
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 = ResponseAdapterFactory(self.settings.remote).local_db()
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 .adapters.scenario_adapter_factory import ScenarioAdapterFactory
11
- from .adapters.types import ScenarioCreateParams
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 = ScenarioAdapterFactory(self.settings.remote).local_db()
20
+ self.adapter = ScenarioResourceFactory(self.settings.remote).local_db()
21
21
 
22
22
  def as_remote(self):
23
- self.adapter = ScenarioAdapterFactory(self.settings.remote).stoobly()
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
- return base64.b64decode(encoded_body)
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]):
@@ -0,0 +1,6 @@
1
+ from .replayed_response import *
2
+ from .request_components import *
3
+ from .request_create_params import *
4
+ from .request_show_params import *
5
+ from .requests_model_index import *
6
+ from .scenario_create_params import *
@@ -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.context import TestContext
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
 
@@ -28,7 +28,6 @@ LOG_ID = 'InterceptHandler'
28
28
 
29
29
  def request(flow: MitmproxyHTTPFlow):
30
30
  request: MitmproxyRequest = flow.request
31
-
32
31
  intercept_settings = InterceptSettings(Settings.instance(), request)
33
32
 
34
33
  active_mode = intercept_settings.mode
@@ -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().debug(f"{bcolors.OKCYAN}Rewriting{bcolors.ENDC} {rewrite.name} => {rewrite.value}")
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]):
@@ -86,8 +86,8 @@ class HashedRequestDecorator:
86
86
  def body_text_hash(self):
87
87
  text = self.request.body
88
88
 
89
- if len(text) == 0:
90
- return text
89
+ if not text or len(text) == 0:
90
+ return ''
91
91
 
92
92
  return self.__hash(text)
93
93
 
@@ -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' in options:
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' in options:
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' in options:
64
+ if options.get('mode'):
66
65
  __handle_mode_option(options['mode'], request, headers)
67
66
 
68
- if 'project_key' in options:
67
+ if options.get('project_key'):
69
68
  headers[custom_headers.PROJECT_KEY] = options['project_key']
70
69
 
71
- if 'report_key' in options:
70
+ if options.get('report_key'):
72
71
  headers[custom_headers.REPORT_KEY] = options['report_key']
73
72
 
74
- if 'request_origin' in options:
73
+ if options.get('request_origin'):
75
74
  headers[custom_headers.REQUEST_ORIGIN] = options['request_origin']
76
75
 
77
- if 'scenario_key' in options:
76
+ if options.get('scenario_key'):
78
77
  headers[custom_headers.SCENARIO_KEY] = options['scenario_key']
79
78
 
80
- if 'test_filter' in options:
79
+ if options.get('test_filter'):
81
80
  headers[custom_headers.TEST_FILTER] = options['test_filter']
82
81
 
83
- if 'test_strategy' in options:
82
+ if options.get('test_strategy'):
84
83
  headers[custom_headers.TEST_STRATEGY] = options['test_strategy']
85
84
 
86
- method = request.method
87
- handler = getattr(requests, method.lower())
88
- cookies = __get_cookies(request.headers)
89
-
90
- # Set proxy env vars to ensure request gets sent to proxy
91
- res: requests.Response = Api().with_proxy(lambda: handler(
92
- request.url,
93
- allow_redirects = True,
94
- cookies = cookies,
95
- data=request.body,
96
- headers=headers,
97
- #params=request.query_params, # Do not send query params, they should be a part of the URL
98
- stream = True,
99
- verify = not MitmproxyConfig.instance().get('ssl_insecure')
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
- headers[custom_headers.MOCK_REQUEST_ID] = str(request.id)
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
- return SimpleCookie(headers.get('Cookie'))
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()
@@ -1,2 +1,3 @@
1
1
  from .context import TestContext
2
+ from .context_abc import TestContextABC
2
3
  from .context_response import TestContextResponse
@@ -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