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
@@ -0,0 +1,24 @@
1
+ from io import BytesIO
2
+ import requests
3
+
4
+ from mitmproxy.http import Response as MitmproxyResponse
5
+ from urllib3 import HTTPResponse
6
+
7
+ class PythonResponseAdapter():
8
+
9
+ def __init__(self, response: MitmproxyResponse):
10
+ self.__response = response
11
+
12
+ def adapt(self) -> requests.Response:
13
+ response = requests.Response()
14
+ response.status_code = self.__response.status_code
15
+ response.headers = self.__response.headers
16
+
17
+ response.raw = HTTPResponse(
18
+ body=BytesIO(self.__response.raw_content),
19
+ decode_content=False,
20
+ headers=self.__response.headers,
21
+ preload_content=False
22
+ )
23
+
24
+ return response
@@ -0,0 +1,2 @@
1
+ from .request import PythonRequestAdapterFactory
2
+ from .response import PythonResponseAdapterFactory
@@ -0,0 +1,18 @@
1
+ import pdb
2
+ import requests
3
+
4
+ from urllib.parse import parse_qs, urlparse
5
+
6
+ from .mitmproxy_adapter import MitmproxyRequestAdapter
7
+ from .stoobly_adapter import StooblyRequestAdapter
8
+
9
+ class PythonRequestAdapterFactory():
10
+
11
+ def __init__(self, request: requests.Request):
12
+ self.__request = request
13
+
14
+ def mitmproxy_request(self, http_version: str = 'HTTP/1.1'):
15
+ return MitmproxyRequestAdapter(http_version, self.__request).adapt()
16
+
17
+ def stoobly_request(self):
18
+ return StooblyRequestAdapter(self.__request).adapt()
@@ -0,0 +1,53 @@
1
+ import pdb
2
+ import requests
3
+
4
+ from mitmproxy.http import Headers, Request as MitmproxyRequest
5
+ from urllib.parse import urlparse
6
+
7
+ class MitmproxyRequestAdapter():
8
+
9
+ def __init__(self, http_version, request: requests.Request):
10
+ self.__http_version = http_version
11
+ self.__request = request
12
+
13
+ @property
14
+ def url(self):
15
+ parsed_url = urlparse(self.__request.url)
16
+
17
+ if not parsed_url.netloc:
18
+ parsed_url = parsed_url._replace(netloc=parsed_url.path, path='')
19
+
20
+ if not parsed_url.scheme:
21
+ parsed_url = parsed_url._replace(scheme='https')
22
+
23
+ return parsed_url.geturl()
24
+
25
+ @property
26
+ def headers(self):
27
+ return Headers(**self.__decode_dict(self.__request.headers))
28
+
29
+ @property
30
+ def data(self):
31
+ _data = self.__request.data
32
+
33
+ # If no data is provided to python requests.Request, it is sent to []
34
+ if _data == []:
35
+ return b''
36
+
37
+ return _data
38
+
39
+ def adapt(self):
40
+ request = MitmproxyRequest.make(
41
+ self.__request.method,
42
+ self.url,
43
+ self.data,
44
+ self.headers,
45
+ )
46
+ request.http_version = self.__http_version
47
+ return request
48
+
49
+ def __decode_dict(self, d):
50
+ new_d = {}
51
+ for k, v in d.items():
52
+ new_d[k.decode() if isinstance(k, bytes) else k] = v.decode() if isinstance(v, bytes) else v
53
+ return new_d
@@ -0,0 +1,49 @@
1
+ import pdb
2
+ import requests
3
+
4
+ from urllib.parse import parse_qs, urlparse
5
+
6
+ class StooblyRequestAdapter():
7
+
8
+ def __init__(self, request: requests.Request):
9
+ self.__request = request
10
+
11
+ def adapt(self):
12
+ parsed_url = urlparse(self.__request.url)
13
+
14
+ return {
15
+ 'body': self.__request.data,
16
+ 'headers': self.adapt_headers(),
17
+ 'method': self.__request.method,
18
+ 'path': parsed_url.path,
19
+ 'query_params': self.adapt_query_params(parsed_url.query),
20
+ 'url': self.__request.url,
21
+ }
22
+
23
+ def adapt_query_params(self, query = None):
24
+ if not query:
25
+ parsed_url = urlparse(self.__request.url)
26
+ query = parsed_url.query
27
+
28
+ _query_params = parse_qs(query)
29
+
30
+ query_params = []
31
+ for k, v in _query_params.items():
32
+ for param in v:
33
+ query_params.append({
34
+ 'name': k,
35
+ 'value': param,
36
+ })
37
+
38
+ return query_params
39
+
40
+ def adapt_headers(self):
41
+ headers = []
42
+
43
+ for k, v in self.__request.headers.items():
44
+ headers.append({
45
+ 'name': k,
46
+ 'value': v
47
+ })
48
+
49
+ return headers
@@ -0,0 +1,13 @@
1
+ import http
2
+ import pdb
3
+ import requests
4
+
5
+ from .mitmproxy_adapter import MitmproxyResponseAdapter
6
+
7
+ class PythonResponseAdapterFactory():
8
+
9
+ def __init__(self, response: requests.Response):
10
+ self.__response = response
11
+
12
+ def mitmproxy_response(self):
13
+ return MitmproxyResponseAdapter(self.__response).adapt()
@@ -1,13 +1,21 @@
1
- from time import time
1
+ import pdb
2
2
  import requests
3
3
 
4
4
  from mitmproxy.http import Headers, Response as MitmproxyResponse
5
+ from time import time
6
+
7
+ from stoobly_agent.app.models.adapters.raw_http_request_adapter import DEFAULT_HTTP_VERSION
5
8
 
6
9
  class MitmproxyResponseAdapter():
7
10
 
8
- def __init__(self, http_version, response: requests.Response):
11
+ def __init__(self, response: requests.Response):
9
12
  self.__timestamp_start = time()
10
- self.__http_version = http_version
13
+
14
+ if hasattr(response, 'raw'):
15
+ self.__http_version = f"HTTP/{response.raw.version / 10.0}"
16
+ else:
17
+ self.__http_version = DEFAULT_HTTP_VERSION
18
+
11
19
  self.__latency = 0 # Seconds
12
20
  self.__response = response
13
21
 
@@ -41,11 +49,11 @@ class MitmproxyResponseAdapter():
41
49
 
42
50
  def adapt(self):
43
51
  body = b''
44
-
45
- try:
46
- body = self.__response.raw.data
47
- except:
52
+
53
+ if self.__response._content_consumed or not hasattr(self.__response, 'raw'):
48
54
  body = self.__response.content
55
+ else:
56
+ body = self.__response.raw.data
49
57
 
50
58
  return MitmproxyResponse(
51
59
  self.__http_version,
@@ -1,5 +1,8 @@
1
+ import pdb
1
2
  import requests
2
3
 
4
+ from typing import Union
5
+
3
6
  CRLF = b'\r\n'
4
7
  DEFAULT_HTTP_VERSION = b'HTTP/1.1'
5
8
 
@@ -14,29 +17,33 @@ class RawHttpRequestAdapter():
14
17
  colon_ind = req_lines[ind].find(b':')
15
18
  header_key = req_lines[ind][:colon_ind]
16
19
  header_value = req_lines[ind][colon_ind + 1:]
17
- self.headers[header_key] = header_value
20
+ self.headers[self.__decode(header_key)] = self.__decode(header_value).strip()
18
21
  ind += 1
19
22
  ind += 1
20
23
  data_lines = req_lines[ind:] if ind < len(req_lines) else None
21
24
  self.body = CRLF.join(data_lines)
22
25
 
26
+ def to_request(self):
27
+ req = requests.Request(
28
+ method=self.method,
29
+ url=self.url,
30
+ headers=self.headers,
31
+ data=self.body
32
+ )
33
+
34
+ return req
35
+
23
36
  def __parse_request_line(self, request_line):
24
37
  request_parts = request_line.split(b' ')
25
- self.method = request_parts[0]
26
- self.url = request_parts[1]
27
- self.protocol = request_parts[2] if len(request_parts) > 2 else DEFAULT_HTTP_VERSION
38
+ self.method = self.__decode(request_parts[0])
39
+ self.url = self.__decode(request_parts[1])
40
+ self.protocol = self.__decode(request_parts[2]) if len(request_parts) > 2 else DEFAULT_HTTP_VERSION
28
41
 
29
42
  def __str__(self):
30
43
  headers = CRLF.join(f'{key}: {self.headers[key]}' for key in self.headers)
31
44
  return f'{self.method} {self.url} {self.protocol}{CRLF}' \
32
45
  f'{headers}{CRLF}{CRLF}{self.body}'
33
46
 
34
- def to_request(self):
35
- req = requests.Request(
36
- method=self.method,
37
- url=self.url,
38
- headers=self.headers,
39
- data=self.body
40
- )
41
47
 
42
- return req
48
+ def __decode(self, s: Union[bytes, str]) -> str:
49
+ return s if isinstance(s, str) else s.decode()
@@ -6,6 +6,7 @@ from io import BytesIO
6
6
  from mitmproxy.net import encoding
7
7
  from requests.structures import CaseInsensitiveDict
8
8
  from typing import Union
9
+ from urllib3 import HTTPResponse
9
10
 
10
11
  from stoobly_agent.app.proxy.mitmproxy.response import Response
11
12
  from stoobly_agent.lib.orm.utils.response_parse_handler import Response as ResponseDict, ResponseParseHandler
@@ -17,28 +18,36 @@ class RawHttpResponseAdapter():
17
18
 
18
19
  def __init__(self, req_text):
19
20
  self.__req_text = req_text
20
-
21
- def to_response(self):
22
21
  req_lines = self.__req_text.split(CRLF)
22
+
23
23
  self.__parse_response_line(req_lines[0])
24
+
24
25
  ind = 1
25
- headers = CaseInsensitiveDict()
26
+ self.headers = CaseInsensitiveDict()
26
27
  while ind < len(req_lines) and len(req_lines[ind]) > 0:
27
28
  colon_ind = req_lines[ind].find(b':')
28
29
  header_key = req_lines[ind][:colon_ind]
29
30
  header_value = req_lines[ind][colon_ind + 1:]
30
- headers[self.__decode(header_key)] = self.__decode(header_value).strip()
31
+ self.headers[self.__decode(header_key)] = self.__decode(header_value).strip()
31
32
  ind += 1
32
33
  ind += 1
34
+
33
35
  data_lines = req_lines[ind:] if ind < len(req_lines) else None
36
+ self.body = CRLF.join(data_lines)
34
37
 
38
+ def to_response(self):
35
39
  response = requests.Response()
36
40
  response.status_code = self.status
37
- response.headers = headers
41
+ response.headers = self.headers
42
+
43
+ response.raw = HTTPResponse(
44
+ body=BytesIO(self.body),
45
+ decode_content=False,
46
+ headers=self.headers,
47
+ preload_content=False
48
+ )
38
49
 
39
- content_encoding = response.headers.get('content-encoding')
40
- body = CRLF.join(data_lines)
41
- response.raw = self.__decode_body(body, content_encoding)
50
+ #response.raw = self.__decode_body(self.body, content_encoding)
42
51
 
43
52
  return response
44
53
 
@@ -67,12 +76,13 @@ class RawHttpResponseAdapter():
67
76
 
68
77
  def __parse_response_line(self, response_line):
69
78
  response_parts = response_line.split(b' ')
70
- self.protocol = response_parts[0] if len(response_parts) > 2 else DEFAULT_HTTP_VERSION
71
- self.status = response_parts[1]
79
+ self.protocol = self.__decode(response_parts[0]) if len(response_parts) > 2 else DEFAULT_HTTP_VERSION
80
+ self.status = int(self.__decode(response_parts[1]))
81
+ self.reason = self.__decode(response_parts[2]) if len(response_parts) > 2 else ''
72
82
 
73
83
  def __str__(self):
74
84
  headers = CRLF.join(f'{key}: {self.headers[key]}' for key in self.headers)
75
- return f'{self.method} {self.url} {self.protocol}{CRLF}' \
85
+ return f'{self.protocol} {self.status} {self.reason}{CRLF}' \
76
86
  f'{headers}{CRLF}{CRLF}{self.body}'
77
87
 
78
88
  def __new_parser(self, response_dict):
@@ -81,7 +91,7 @@ class RawHttpResponseAdapter():
81
91
  parser.feed_data(memoryview(self.__req_text))
82
92
  return parser
83
93
 
84
- def __decode(self, s: Union[bytes, str]):
94
+ def __decode(self, s: Union[bytes, str]) -> str:
85
95
  return s if isinstance(s, str) else s.decode()
86
96
 
87
97
  def __decode_body(self, body: bytes, content_encoding):
@@ -0,0 +1,11 @@
1
+ from lib.api.interfaces.requests import RequestShowResponse
2
+
3
+ from .mitmproxy_adapter import MitmproxyRequestAdapter
4
+
5
+ class StooblyRequestAdapterFactory():
6
+
7
+ def __init__(self, request: RequestShowResponse):
8
+ self.__request = request
9
+
10
+ def mitmproxy_request(self):
11
+ return MitmproxyRequestAdapter(self.__request)
@@ -0,0 +1,32 @@
1
+ import pdb
2
+ import requests
3
+
4
+ from mitmproxy.http import Headers, Request as MitmproxyRequest
5
+
6
+ from stoobly_agent.app.models.schemas.request import Request
7
+
8
+ class MitmproxyRequestAdapter():
9
+
10
+ def __init__(self, request: Request):
11
+ self.__http_version = 'HTTP/1.1'
12
+ self.__request = request
13
+
14
+ @property
15
+ def headers(self):
16
+ return Headers(**self.__decode_dict(self.__request.headers))
17
+
18
+ def adapt(self):
19
+ request = MitmproxyRequest.make(
20
+ self.__request.method,
21
+ self.__request.url,
22
+ self.__request.body,
23
+ self.headers,
24
+ )
25
+ request.http_version = self.__http_version
26
+ return request
27
+
28
+ def __decode_dict(self, d):
29
+ new_d = {}
30
+ for k, v in d.items():
31
+ new_d[k.decode() if isinstance(k, bytes) else k] = v.decode() if isinstance(v, bytes) else v
32
+ return new_d
@@ -1,10 +1,10 @@
1
1
  import pdb
2
2
  import requests
3
3
 
4
- from stoobly_agent.app.models.adapters.body_adapter_factory import BodyAdapterFactory
5
4
  from stoobly_agent.app.settings import Settings
6
5
  from stoobly_agent.lib.logger import Logger
7
6
 
7
+ from .factories.resource.body import BodyResourceFactory
8
8
  from .model import Model
9
9
 
10
10
  class BodyModel(Model):
@@ -13,7 +13,7 @@ class BodyModel(Model):
13
13
  super().__init__(settings)
14
14
 
15
15
  def as_local(self):
16
- self.adapter = BodyAdapterFactory(self.settings.remote).local_db()
16
+ self.adapter = BodyResourceFactory(self.settings.remote).local_db()
17
17
 
18
18
  def as_remote(self):
19
19
  # 'Not yet supported.'
File without changes
@@ -3,7 +3,7 @@ from stoobly_agent.lib.orm.request import Request
3
3
 
4
4
  from .local_db.body_adapter import LocalDBBodyAdapter
5
5
 
6
- class BodyAdapterFactory():
6
+ class BodyResourceFactory():
7
7
 
8
8
  def __init__(self, settings: RemoteSettings):
9
9
  self.__remote_settings = settings
@@ -3,7 +3,7 @@ from stoobly_agent.lib.orm.request import Request
3
3
 
4
4
  from .local_db.header_adapter import LocalDBHeaderAdapter
5
5
 
6
- class HeaderAdapterFactory():
6
+ class HeaderResourceFactory():
7
7
 
8
8
  def __init__(self, settings: RemoteSettings):
9
9
  self.__remote_settings = settings
@@ -24,8 +24,8 @@ class LocalDBHeaderAdapter():
24
24
  headers = []
25
25
  for key, val in request.headers.items():
26
26
  headers.append({
27
- 'name': key.decode(),
28
- 'value': val.decode(),
27
+ 'name': key,
28
+ 'value': val,
29
29
  })
30
30
 
31
31
  return headers
@@ -1,14 +1,13 @@
1
1
  import pdb
2
2
  import requests
3
3
 
4
+ from stoobly_agent.app.models.types import ReplayedResponseIndexQueryParams
4
5
  from stoobly_agent.lib.api.interfaces.requests import RequestShowResponse
5
6
  from stoobly_agent.lib.orm.replayed_response import ReplayedResponse
6
7
  from stoobly_agent.lib.orm.transformers.orm_to_requests_response_transformer import ORMToRequestsResponseTransformer
7
8
  from stoobly_agent.lib.orm.transformers.orm_to_stoobly_request_transformer import ORMToStooblyRequestTransformer
8
9
  from stoobly_agent.lib.orm.utils.response_parse_handler import Response
9
10
 
10
- from ..types.replayed_response import ReplayedResponseIndexQueryParams
11
-
12
11
  class LocalDBReplayedResponseAdapter():
13
12
  __replayed_response_orm = None
14
13
 
@@ -3,13 +3,12 @@ from urllib.parse import urlparse
3
3
  import requests
4
4
 
5
5
  from mitmproxy.http import HTTPFlow as MitmproxyHTTPFlow, Request as MitmproxyRequest
6
- from typing import List
7
6
 
7
+ from stoobly_agent.app.models.types import RequestCreateParams, RequestShowParams
8
8
  from stoobly_agent.app.proxy.mock.custom_not_found_response_builder import CustomNotFoundResponseBuilder
9
9
  from stoobly_agent.app.proxy.mock.hashed_request_decorator import HashedRequestDecorator
10
10
  from stoobly_agent.app.proxy.mitmproxy.request_facade import MitmproxyRequestFacade
11
11
  from stoobly_agent.app.proxy.upload.joined_request import JoinedRequest
12
-
13
12
  from stoobly_agent.lib.orm import ORM
14
13
  from stoobly_agent.lib.orm.request import Request
15
14
  from stoobly_agent.lib.orm.response import Response
@@ -19,8 +18,6 @@ from stoobly_agent.lib.orm.types.response_columns import ResponseColumns
19
18
  from stoobly_agent.lib.orm.transformers import ORMToRequestsResponseTransformer, ORMToStooblyResponseTransformer
20
19
  from stoobly_agent.lib.api.interfaces import RequestsIndexQueryParams, RequestsIndexResponse, RequestShowResponse
21
20
 
22
- from ..types import RequestCreateParams, RequestShowParams
23
-
24
21
  class LocalDBRequestAdapter():
25
22
  __request_orm = None
26
23
  __response_orm = None
@@ -73,14 +70,23 @@ class LocalDBRequestAdapter():
73
70
  def show(self, request_id: str, **options: RequestShowParams) -> RequestShowResponse:
74
71
  request = self.__request_orm.find(request_id)
75
72
 
73
+ if not request:
74
+ return CustomNotFoundResponseBuilder().build()
75
+
76
76
  return ORMToStooblyRequestTransformer(request, options).transform()
77
77
 
78
78
  def response(self, **query_params: RequestColumns) -> requests.Response:
79
- request_columns = { **query_params }
80
- self.__filter_request_response_columns(request_columns)
79
+ request = None
80
+
81
+ if not query_params.get('request_id'):
82
+ request_columns = { **query_params }
81
83
 
82
- # Find most recent matching record
83
- request = self.__request_orm.where_for(**request_columns).get().last()
84
+ self.__filter_request_response_columns(request_columns)
85
+
86
+ # Find most recent matching record
87
+ request = self.__request_orm.where_for(**request_columns).get().last()
88
+ else:
89
+ request = self.__request_orm.find(query_params.get('request_id'))
84
90
 
85
91
  if not request:
86
92
  return CustomNotFoundResponseBuilder().build()
@@ -107,6 +113,7 @@ class LocalDBRequestAdapter():
107
113
 
108
114
  if scenario_id:
109
115
  requests = requests.where('scenario_id', int(scenario_id))
116
+ sort_order = query_params.get('sort_order') or 'asc'
110
117
 
111
118
  if starred:
112
119
  requests = requests.where('starred', starred)
@@ -1,13 +1,11 @@
1
1
  import pdb
2
2
 
3
- from stoobly_agent.app.models.adapters.types.scenario_create_params import ScenarioCreateParams
3
+ from stoobly_agent.app.models.types import ScenarioCreateParams
4
4
  from stoobly_agent.lib.api.interfaces import ScenariosIndexQueryParams, ScenariosIndexResponse, ScenarioShowResponse
5
5
  from stoobly_agent.lib.api.keys.scenario_key import ScenarioKey
6
6
  from stoobly_agent.lib.orm import ORM
7
7
  from stoobly_agent.lib.orm.scenario import Scenario
8
8
 
9
- from ..types import ScenarioCreateParams
10
-
11
9
  class LocalDBScenarioAdapter():
12
10
  __scenario_orm = None
13
11
 
@@ -30,13 +28,21 @@ class LocalDBScenarioAdapter():
30
28
  sort_by = query_params.get('sort_by') or 'id'
31
29
  sort_order = query_params.get('sort_order') or 'desc'
32
30
 
33
- is_deleted = query_params.get('filter') == 'is_deleted'
34
- starred = query_params.get('filter') == 'starred'
31
+ filter = query_params.get('filter')
32
+ is_deleted = filter == 'is_deleted'
35
33
 
36
34
  scenarios = Scenario.where('is_deleted', is_deleted)
37
35
 
38
- if starred:
39
- scenarios = scenarios.where('starred', starred)
36
+ if filter == 'starred':
37
+ scenarios = scenarios.where('starred', True)
38
+ elif filter == 'high_priority':
39
+ scenarios = scenarios.where('priority', 3)
40
+ elif filter == 'medium_priority':
41
+ scenarios = scenarios.where('priority', 2)
42
+ elif filter == 'low_priority':
43
+ scenarios = scenarios.where('priority', 1)
44
+ elif filter == 'none_priority':
45
+ scenarios = scenarios.where('priority', 0)
40
46
 
41
47
  if query:
42
48
  scenarios = self.__search(scenarios, query)
@@ -3,7 +3,7 @@ from stoobly_agent.lib.orm.request import Request
3
3
 
4
4
  from .local_db.query_param_adapter import LocalDBQueryParamAdapter
5
5
 
6
- class QueryParamAdapterFactory():
6
+ class QueryParamResourceFactory():
7
7
 
8
8
  def __init__(self, settings: RemoteSettings):
9
9
  self.__remote_settings = settings
@@ -3,7 +3,7 @@ from stoobly_agent.lib.orm.replayed_response import ReplayedResponse
3
3
 
4
4
  from .local_db.replayed_response_adapter import LocalDBReplayedResponseAdapter
5
5
 
6
- class ReplayedResponseAdapterFactory():
6
+ class ReplayedResponseResourceFactory():
7
7
 
8
8
  def __init__(self, settings: RemoteSettings):
9
9
  self.__remote_settings = settings
@@ -3,9 +3,9 @@ from stoobly_agent.lib.api.requests_resource import RequestsResource
3
3
  from stoobly_agent.app.settings import RemoteSettings
4
4
 
5
5
  from .local_db.request_adapter import LocalDBRequestAdapter
6
- from .stoobly_request_adapter import StooblyRequestAdapter
6
+ from .stoobly.request_adapter import StooblyRequestAdapter
7
7
 
8
- class RequestAdapterFactory():
8
+ class RequestResourceFactory():
9
9
 
10
10
  def __init__(self, settings: RemoteSettings):
11
11
  self.__remote_settings = settings
@@ -3,7 +3,7 @@ from stoobly_agent.lib.orm.request import Request
3
3
 
4
4
  from .local_db.response_adapter import LocalDBResponseAdapter
5
5
 
6
- class ResponseAdapterFactory():
6
+ class ResponseResourceFactory():
7
7
 
8
8
  def __init__(self, settings: RemoteSettings):
9
9
  self.__remote_settings = settings
@@ -3,7 +3,7 @@ from stoobly_agent.lib.orm.request import Request
3
3
 
4
4
  from .local_db.response_header_adapter import LocalDBResponseHeaderAdapter
5
5
 
6
- class ResponseHeaderAdapterFactory():
6
+ class ResponseHeaderResourceFactory():
7
7
 
8
8
  def __init__(self, settings: RemoteSettings):
9
9
  self.__remote_settings = settings
@@ -3,9 +3,9 @@ from stoobly_agent.lib.api.scenarios_resource import ScenariosResource
3
3
  from stoobly_agent.app.settings import RemoteSettings
4
4
 
5
5
  from .local_db.scenario_adapter import LocalDBScenarioAdapter
6
- from .stoobly_scenario_adapter import StooblyScenarioAdapter
6
+ from .stoobly.scenario_adapter import StooblyScenarioAdapter
7
7
 
8
- class ScenarioAdapterFactory():
8
+ class ScenarioResourceFactory():
9
9
 
10
10
  def __init__(self, settings: RemoteSettings):
11
11
  self.__remote_settings = settings
@@ -1,11 +1,10 @@
1
1
  import pdb
2
2
  import requests
3
3
 
4
+ from stoobly_agent.app.models.types import RequestCreateParams, RequestShowParams
4
5
  from stoobly_agent.lib.api.requests_resource import RequestsResource
5
6
  from stoobly_agent.lib.api.interfaces import RequestShowResponse, RequestsIndexResponse
6
7
 
7
- from .types import RequestCreateParams, RequestShowParams
8
-
9
8
  class StooblyRequestAdapter():
10
9
 
11
10
  def __init__(self, __api: RequestsResource):
@@ -1,10 +1,9 @@
1
1
  import pdb
2
2
 
3
+ from stoobly_agent.app.models.types import ScenarioCreateParams
3
4
  from stoobly_agent.lib.api.scenarios_resource import ScenariosResource
4
5
  from stoobly_agent.lib.api.interfaces.scenarios import ScenarioShowResponse, ScenariosIndexResponse
5
6
 
6
- from .types import ScenarioCreateParams
7
-
8
7
  class StooblyScenarioAdapter():
9
8
 
10
9
  def __init__(self, __api: ScenariosResource):