howler-api 4.0.0.dev1019__tar.gz → 4.0.0.dev1020__tar.gz

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 (204) hide show
  1. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/PKG-INFO +1 -1
  2. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/api/v1/action.py +21 -11
  3. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/api/v1/analytic.py +30 -11
  4. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/api/v1/dossier.py +25 -9
  5. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/api/v1/hit.py +94 -25
  6. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/api/v1/overview.py +19 -6
  7. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/api/v1/template.py +19 -6
  8. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/api/v1/tool.py +2 -2
  9. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/api/v1/user.py +25 -5
  10. howler_api-4.0.0.dev1020/howler/api/v1/utils/params.py +71 -0
  11. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/api/v1/view.py +19 -10
  12. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/common/exceptions.py +4 -0
  13. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/datastore/collection.py +18 -11
  14. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/random_data.py +2 -2
  15. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/services/analytic_service.py +44 -17
  16. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/services/dossier_service.py +6 -10
  17. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/services/hit_service.py +16 -14
  18. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/services/user_service.py +2 -2
  19. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/pyproject.toml +1 -1
  20. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/README.md +0 -0
  21. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/__init__.py +0 -0
  22. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/actions/__init__.py +0 -0
  23. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/actions/add_label.py +0 -0
  24. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/actions/add_to_bundle.py +0 -0
  25. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/actions/change_field.py +0 -0
  26. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/actions/demote.py +0 -0
  27. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/actions/example_plugin.py +0 -0
  28. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/actions/prioritization.py +0 -0
  29. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/actions/promote.py +0 -0
  30. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/actions/remove_from_bundle.py +0 -0
  31. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/actions/remove_label.py +0 -0
  32. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/actions/transition.py +0 -0
  33. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/api/__init__.py +0 -0
  34. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/api/base.py +0 -0
  35. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/api/socket.py +0 -0
  36. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/api/v1/__init__.py +0 -0
  37. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/api/v1/auth.py +0 -0
  38. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/api/v1/clue.py +0 -0
  39. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/api/v1/configs.py +0 -0
  40. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/api/v1/help.py +0 -0
  41. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/api/v1/notebook.py +0 -0
  42. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/api/v1/search.py +0 -0
  43. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/api/v1/utils/__init__.py +0 -0
  44. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/api/v1/utils/etag.py +0 -0
  45. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/app.py +0 -0
  46. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/common/README.md +0 -0
  47. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/common/__init__.py +0 -0
  48. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/common/classification.py +0 -0
  49. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/common/classification.yml +0 -0
  50. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/common/loader.py +0 -0
  51. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/common/logging/__init__.py +0 -0
  52. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/common/logging/audit.py +0 -0
  53. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/common/logging/format.py +0 -0
  54. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/common/net.py +0 -0
  55. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/common/net_static.py +0 -0
  56. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/common/random_user.py +0 -0
  57. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/common/swagger.py +0 -0
  58. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/config.py +0 -0
  59. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/cronjobs/__init__.py +0 -0
  60. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/cronjobs/action_queue_worker.py +0 -0
  61. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/cronjobs/retention.py +0 -0
  62. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/cronjobs/rules.py +0 -0
  63. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/cronjobs/view_cleanup.py +0 -0
  64. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/datastore/README.md +0 -0
  65. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/datastore/__init__.py +0 -0
  66. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/datastore/bulk.py +0 -0
  67. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/datastore/constants.py +0 -0
  68. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/datastore/exceptions.py +0 -0
  69. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/datastore/howler_store.py +0 -0
  70. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/datastore/migrations/fix_process.py +0 -0
  71. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/datastore/operations.py +0 -0
  72. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/datastore/schemas.py +0 -0
  73. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/datastore/store.py +0 -0
  74. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/datastore/support/__init__.py +0 -0
  75. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/datastore/support/build.py +0 -0
  76. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/datastore/support/schemas.py +0 -0
  77. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/datastore/types.py +0 -0
  78. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/error.py +0 -0
  79. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/external/README.md +0 -0
  80. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/external/__init__.py +0 -0
  81. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/external/generate_mitre.py +0 -0
  82. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/external/generate_sigma_rules.py +0 -0
  83. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/external/generate_tlds.py +0 -0
  84. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/external/reindex_data.py +0 -0
  85. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/external/wipe_databases.py +0 -0
  86. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/gunicorn_config.py +0 -0
  87. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/healthz.py +0 -0
  88. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/helper/__init__.py +0 -0
  89. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/helper/azure.py +0 -0
  90. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/helper/discover.py +0 -0
  91. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/helper/hit.py +0 -0
  92. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/helper/oauth.py +0 -0
  93. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/helper/search.py +0 -0
  94. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/helper/workflow.py +0 -0
  95. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/helper/ws.py +0 -0
  96. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/README.md +0 -0
  97. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/__init__.py +0 -0
  98. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/base.py +0 -0
  99. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/charter.txt +0 -0
  100. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/helper.py +0 -0
  101. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/howler_enum.py +0 -0
  102. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/__init__.py +0 -0
  103. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/action.py +0 -0
  104. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/analytic.py +0 -0
  105. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/assemblyline.py +0 -0
  106. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/aws.py +0 -0
  107. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/azure.py +0 -0
  108. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/cbs.py +0 -0
  109. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/clue.py +0 -0
  110. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/config.py +0 -0
  111. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/dossier.py +0 -0
  112. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/__init__.py +0 -0
  113. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/agent.py +0 -0
  114. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/autonomous_system.py +0 -0
  115. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/client.py +0 -0
  116. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/cloud.py +0 -0
  117. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/code_signature.py +0 -0
  118. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/container.py +0 -0
  119. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/dns.py +0 -0
  120. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/egress.py +0 -0
  121. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/elf.py +0 -0
  122. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/email.py +0 -0
  123. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/error.py +0 -0
  124. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/event.py +0 -0
  125. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/faas.py +0 -0
  126. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/file.py +0 -0
  127. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/geo.py +0 -0
  128. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/group.py +0 -0
  129. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/hash.py +0 -0
  130. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/host.py +0 -0
  131. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/http.py +0 -0
  132. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/ingress.py +0 -0
  133. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/interface.py +0 -0
  134. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/network.py +0 -0
  135. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/observer.py +0 -0
  136. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/organization.py +0 -0
  137. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/os.py +0 -0
  138. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/pe.py +0 -0
  139. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/process.py +0 -0
  140. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/registry.py +0 -0
  141. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/related.py +0 -0
  142. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/rule.py +0 -0
  143. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/server.py +0 -0
  144. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/threat.py +0 -0
  145. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/tls.py +0 -0
  146. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/url.py +0 -0
  147. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/user.py +0 -0
  148. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/user_agent.py +0 -0
  149. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/vulnerability.py +0 -0
  150. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/gcp.py +0 -0
  151. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/hit.py +0 -0
  152. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/howler_data.py +0 -0
  153. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/lead.py +0 -0
  154. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/localized_label.py +0 -0
  155. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/overview.py +0 -0
  156. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/pivot.py +0 -0
  157. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/template.py +0 -0
  158. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/user.py +0 -0
  159. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/view.py +0 -0
  160. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/randomizer.py +0 -0
  161. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/patched.py +0 -0
  162. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/plugins/__init__.py +0 -0
  163. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/plugins/config.py +0 -0
  164. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/remote/__init__.py +0 -0
  165. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/remote/datatypes/README.md +0 -0
  166. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/remote/datatypes/__init__.py +0 -0
  167. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/remote/datatypes/counters.py +0 -0
  168. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/remote/datatypes/events.py +0 -0
  169. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/remote/datatypes/hash.py +0 -0
  170. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/remote/datatypes/lock.py +0 -0
  171. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/remote/datatypes/queues/__init__.py +0 -0
  172. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/remote/datatypes/queues/comms.py +0 -0
  173. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/remote/datatypes/queues/multi.py +0 -0
  174. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/remote/datatypes/queues/named.py +0 -0
  175. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/remote/datatypes/queues/priority.py +0 -0
  176. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/remote/datatypes/set.py +0 -0
  177. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/remote/datatypes/user_quota_tracker.py +0 -0
  178. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/security/__init__.py +0 -0
  179. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/security/socket.py +0 -0
  180. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/security/utils.py +0 -0
  181. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/services/__init__.py +0 -0
  182. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/services/action_service.py +0 -0
  183. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/services/auth_service.py +0 -0
  184. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/services/config_service.py +0 -0
  185. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/services/event_service.py +0 -0
  186. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/services/jwt_service.py +0 -0
  187. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/services/lucene_service.py +0 -0
  188. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/services/notebook_service.py +0 -0
  189. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/services/overview_service.py +0 -0
  190. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/services/template_service.py +0 -0
  191. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/telemetry.py +0 -0
  192. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/utils/__init__.py +0 -0
  193. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/utils/annotations.py +0 -0
  194. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/utils/chunk.py +0 -0
  195. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/utils/compat.py +0 -0
  196. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/utils/constants.py +0 -0
  197. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/utils/dict_utils.py +0 -0
  198. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/utils/isotime.py +0 -0
  199. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/utils/list_utils.py +0 -0
  200. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/utils/lucene.py +0 -0
  201. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/utils/path.py +0 -0
  202. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/utils/socket_utils.py +0 -0
  203. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/utils/str_utils.py +0 -0
  204. {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/utils/uid.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: howler-api
3
- Version: 4.0.0.dev1019
3
+ Version: 4.0.0.dev1020
4
4
  Summary: Howler - API server
5
5
  License: MIT
6
6
  Keywords: howler,alerting,gc,canada,cse-cst,cse,cst,cyber,cccs
@@ -4,6 +4,7 @@ from flask import Response, request
4
4
 
5
5
  import howler.actions as actions
6
6
  from howler.api import bad_request, created, forbidden, internal_error, make_subapi_blueprint, no_content, not_found, ok
7
+ from howler.api.v1.utils.params import parse_parameters, parse_refresh
7
8
  from howler.common.exceptions import HowlerException
8
9
  from howler.common.loader import datastore
9
10
  from howler.common.logging.audit import audit
@@ -48,14 +49,16 @@ def get_actions(**_) -> Response:
48
49
  @generate_swagger_docs()
49
50
  @action_api.route("/", methods=["POST"])
50
51
  @api_login(audit=False, check_xsrf_token=False, required_type=["admin", "automation_basic", "automation_advanced"])
51
- def add_action(user: User, **_) -> Response:
52
+ @parse_parameters(refresh=parse_refresh)
53
+ def add_action(user: User, **kwargs) -> Response:
52
54
  """Create a new action
53
55
 
54
56
  Variables:
55
57
  None
56
58
 
57
59
  Optional Arguments:
58
- None
60
+ refresh => ('true' | 'false' | 'wait_for') Whether to refresh the datastore before returning.
61
+ 'wait_for' will wait for the change to be visible in search.
59
62
 
60
63
  Data Block:
61
64
  {
@@ -79,6 +82,8 @@ def add_action(user: User, **_) -> Response:
79
82
  if new_action is None:
80
83
  return bad_request(err="You must specify an action")
81
84
 
85
+ refresh = kwargs.get("refresh")
86
+
82
87
  if error := action_service.validate_action(new_action):
83
88
  return error
84
89
 
@@ -88,8 +93,7 @@ def add_action(user: User, **_) -> Response:
88
93
  action_obj = Action(new_action)
89
94
 
90
95
  ds = datastore()
91
- ds.action.save(action_obj.action_id, action_obj)
92
- ds.action.commit()
96
+ ds.action.save(action_obj.action_id, action_obj, refresh=refresh)
93
97
  except HowlerException as e:
94
98
  return bad_request(err=str(e))
95
99
 
@@ -103,14 +107,16 @@ def add_action(user: User, **_) -> Response:
103
107
  check_xsrf_token=False,
104
108
  required_type=["admin", "automation_basic", "automation_advanced"],
105
109
  )
106
- def update_action(id: str, user: User, **_) -> Response:
110
+ @parse_parameters(refresh=parse_refresh)
111
+ def update_action(id: str, user: User, **kwargs) -> Response:
107
112
  """Update an existing action
108
113
 
109
114
  Variables:
110
115
  id => id of the aciton to update
111
116
 
112
117
  Optional Arguments:
113
- None
118
+ refresh => ('true' | 'false' | 'wait_for') Whether to refresh the datastore before returning.
119
+ 'wait_for' will wait for the change to be visible in search.
114
120
 
115
121
  Data Block:
116
122
  {
@@ -133,6 +139,8 @@ def update_action(id: str, user: User, **_) -> Response:
133
139
  if not isinstance(updated_action, dict):
134
140
  return bad_request(err="Incorrect data structure!")
135
141
 
142
+ refresh = kwargs.get("refresh")
143
+
136
144
  ds = datastore()
137
145
 
138
146
  existing_action = ds.action.get(id, as_obj=False)
@@ -158,8 +166,7 @@ def update_action(id: str, user: User, **_) -> Response:
158
166
  action_obj = Action(updated_action)
159
167
  action_obj.action_id = id
160
168
 
161
- ds.action.save(action_obj.action_id, action_obj)
162
- ds.action.commit()
169
+ ds.action.save(action_obj.action_id, action_obj, refresh=refresh)
163
170
  except HowlerException as e:
164
171
  return bad_request(err=str(e))
165
172
 
@@ -169,6 +176,7 @@ def update_action(id: str, user: User, **_) -> Response:
169
176
  @generate_swagger_docs()
170
177
  @action_api.route("/<id>", methods=["DELETE"])
171
178
  @api_login(audit=True, check_xsrf_token=False, required_type=["admin", "automation_basic", "automation_advanced"])
179
+ @parse_parameters(refresh=parse_refresh)
172
180
  def delete_action(id: str, user: User, **kwargs) -> Response:
173
181
  """Delete an existing action
174
182
 
@@ -176,11 +184,14 @@ def delete_action(id: str, user: User, **kwargs) -> Response:
176
184
  id => The id of the action to delete
177
185
 
178
186
  Optional Arguments:
179
- None
187
+ refresh => ('true' | 'false' | 'wait_for') Whether to refresh the datastore before returning.
188
+ 'wait_for' will wait for the change to be visible in search.
180
189
 
181
190
  Result Example:
182
191
  None
183
192
  """
193
+ refresh = kwargs.get("refresh")
194
+
184
195
  ds = datastore()
185
196
 
186
197
  result = ds.action.search(f"action_id:{id}", rows=1)
@@ -194,8 +205,7 @@ def delete_action(id: str, user: User, **kwargs) -> Response:
194
205
  return forbidden(err="You do not have the permissions necessary to delete this action.")
195
206
 
196
207
  try:
197
- ds.action.delete(id)
198
- ds.action.commit()
208
+ ds.action.delete(id, refresh=refresh)
199
209
 
200
210
  return no_content()
201
211
  except HowlerException as e:
@@ -11,6 +11,7 @@ from howler.api import (
11
11
  not_found,
12
12
  ok,
13
13
  )
14
+ from howler.api.v1.utils.params import parse_parameters, parse_refresh
14
15
  from howler.common.exceptions import HowlerException
15
16
  from howler.common.loader import datastore
16
17
  from howler.common.logging import get_logger
@@ -83,6 +84,7 @@ def get_analytic(id, **kwargs):
83
84
  @generate_swagger_docs()
84
85
  @analytic_api.route("/<id>", methods=["PUT"])
85
86
  @api_login(required_priv=["R", "W"])
87
+ @parse_parameters(refresh=parse_refresh)
86
88
  def update_analytic(id: str, user: User, **kwargs):
87
89
  """Update an analytic
88
90
 
@@ -90,7 +92,8 @@ def update_analytic(id: str, user: User, **kwargs):
90
92
  id => The id of the analytic to modify
91
93
 
92
94
  Optional Arguments:
93
- None
95
+ refresh => ('true' | 'false' | 'wait_for') Whether to refresh the datastore before returning.
96
+ 'wait_for' will wait for the change to be visible in search.
94
97
 
95
98
  Data Block:
96
99
  {
@@ -102,6 +105,8 @@ def update_analytic(id: str, user: User, **kwargs):
102
105
  ...analytic # The updated analytic data
103
106
  }
104
107
  """
108
+ refresh = kwargs.get("refresh")
109
+
105
110
  storage = datastore()
106
111
 
107
112
  if not storage.analytic.exists(id):
@@ -135,7 +140,7 @@ def update_analytic(id: str, user: User, **kwargs):
135
140
  existing_analytic.rule = new_data.get("rule", existing_analytic.rule)
136
141
  existing_analytic.rule_crontab = new_data.get("rule_crontab", existing_analytic.rule_crontab)
137
142
 
138
- storage.analytic.save(existing_analytic.analytic_id, existing_analytic)
143
+ storage.analytic.save(existing_analytic.analytic_id, existing_analytic, refresh=refresh)
139
144
 
140
145
  if updated_rule:
141
146
  # The registration process automatically deletes and resets the rule cronjob
@@ -149,6 +154,7 @@ def update_analytic(id: str, user: User, **kwargs):
149
154
  @generate_swagger_docs()
150
155
  @analytic_api.route("/rules", methods=["POST"])
151
156
  @api_login(required_priv=["R", "W"])
157
+ @parse_parameters(refresh=parse_refresh)
152
158
  def create_rule(user: User, **kwargs):
153
159
  """Create a rule analytic
154
160
 
@@ -156,7 +162,8 @@ def create_rule(user: User, **kwargs):
156
162
  None
157
163
 
158
164
  Optional Arguments:
159
- None
165
+ refresh => ('true' | 'false' | 'wait_for') Whether to refresh the datastore before returning.
166
+ 'wait_for' will wait for the change to be visible in search.
160
167
 
161
168
  Data Block:
162
169
  {
@@ -169,6 +176,8 @@ def create_rule(user: User, **kwargs):
169
176
  ...analytic # The created analytic rule
170
177
  }
171
178
  """
179
+ refresh = kwargs.get("refresh")
180
+
172
181
  storage = datastore()
173
182
 
174
183
  new_data: Optional[dict[str, Any]] = request.json
@@ -215,12 +224,12 @@ def create_rule(user: User, **kwargs):
215
224
  )
216
225
 
217
226
  try:
218
- storage.analytic.save(new_analytic.analytic_id, new_analytic)
219
- # Have to commit so the analytic is available during registration
220
- storage.analytic.commit()
227
+ storage.analytic.save(new_analytic.analytic_id, new_analytic, refresh=refresh)
228
+
229
+ # note that passing a rule will only register that rule without querying for all existing rules
221
230
  register_rules(new_analytic)
222
231
 
223
- storage.template.save(new_template.template_id, new_template)
232
+ storage.template.save(new_template.template_id, new_template, refresh=refresh)
224
233
 
225
234
  return ok(new_analytic)
226
235
  except HowlerException as e:
@@ -230,6 +239,7 @@ def create_rule(user: User, **kwargs):
230
239
  @generate_swagger_docs()
231
240
  @analytic_api.route("/<id>", methods=["DELETE"])
232
241
  @api_login(audit=False, required_priv=["W"])
242
+ @parse_parameters(refresh=parse_refresh)
233
243
  def delete_rule(id: str, user: User, **kwargs):
234
244
  """Delete a rule
235
245
 
@@ -237,7 +247,8 @@ def delete_rule(id: str, user: User, **kwargs):
237
247
  id => id of the analytic whose comments we are deleting
238
248
 
239
249
  Optional Arguments:
240
- None
250
+ refresh => ('true' | 'false' | 'wait_for') Whether to refresh the datastore before returning.
251
+ 'wait_for' will wait for the change to be visible in search.
241
252
 
242
253
  Data Block:
243
254
  [
@@ -248,6 +259,8 @@ def delete_rule(id: str, user: User, **kwargs):
248
259
  {
249
260
  }
250
261
  """
262
+ refresh = kwargs.get("refresh")
263
+
251
264
  if not analytic_service.does_analytic_exist(id):
252
265
  return not_found(err=f"Analytic {id} does not exist")
253
266
 
@@ -260,7 +273,7 @@ def delete_rule(id: str, user: User, **kwargs):
260
273
  return forbidden(err="You cannot delete this analytic.")
261
274
 
262
275
  try:
263
- datastore().analytic.delete(analytic.analytic_id)
276
+ datastore().analytic.delete(analytic.analytic_id, refresh=refresh)
264
277
  except DataStoreException as e:
265
278
  return bad_request(err=str(e))
266
279
 
@@ -517,6 +530,7 @@ def delete_comments(id: str, user: User, **kwargs):
517
530
  @generate_swagger_docs()
518
531
  @analytic_api.route("/<id>/owner", methods=["POST"])
519
532
  @api_login(required_priv=["W"])
533
+ @parse_parameters(refresh=parse_refresh)
520
534
  def set_analytic_owner(id: str, user: dict[str, Any], **kwargs):
521
535
  """Set the analytic's owner
522
536
 
@@ -526,6 +540,10 @@ def set_analytic_owner(id: str, user: dict[str, Any], **kwargs):
526
540
  Arguments:
527
541
  None
528
542
 
543
+ Optional Arguments:
544
+ refresh => ('true' | 'false' | 'wait_for') Whether to refresh the datastore before returning.
545
+ 'wait_for' will wait for the change to be visible in search.
546
+
529
547
  Data Block:
530
548
  {
531
549
  "username": "admin" # The username to set the owner as
@@ -536,6 +554,8 @@ def set_analytic_owner(id: str, user: dict[str, Any], **kwargs):
536
554
  ...analytic # The claimed analytic
537
555
  }
538
556
  """
557
+ refresh = kwargs.get("refresh")
558
+
539
559
  if not analytic_service.does_analytic_exist(id):
540
560
  return not_found(err=f"Analytic {id} does not exist")
541
561
 
@@ -548,8 +568,7 @@ def set_analytic_owner(id: str, user: dict[str, Any], **kwargs):
548
568
  analytic.owner = data["username"]
549
569
 
550
570
  ds = datastore()
551
- ds.analytic.save(analytic.analytic_id, analytic)
552
- ds.analytic.commit()
571
+ ds.analytic.save(analytic.analytic_id, analytic, refresh=refresh)
553
572
 
554
573
  return ok(analytic)
555
574
 
@@ -1,7 +1,13 @@
1
1
  from flask import request
2
2
 
3
3
  from howler.api import bad_request, created, forbidden, internal_error, make_subapi_blueprint, no_content, not_found, ok
4
- from howler.common.exceptions import ForbiddenException, HowlerException, InvalidDataException, NotFoundException
4
+ from howler.api.v1.utils.params import parse_parameters, parse_refresh
5
+ from howler.common.exceptions import (
6
+ ForbiddenException,
7
+ HowlerException,
8
+ InvalidDataException,
9
+ NotFoundException,
10
+ )
5
11
  from howler.common.loader import datastore
6
12
  from howler.common.logging import get_logger
7
13
  from howler.common.swagger import generate_swagger_docs
@@ -49,6 +55,7 @@ def get_dossiers(user: User, **kwargs):
49
55
  @generate_swagger_docs()
50
56
  @dossier_api.route("/", methods=["POST"])
51
57
  @api_login(required_priv=["R", "W"])
58
+ @parse_parameters(refresh=parse_refresh)
52
59
  def create_dossier(**kwargs):
53
60
  """Create a new dossier
54
61
 
@@ -56,7 +63,8 @@ def create_dossier(**kwargs):
56
63
  None
57
64
 
58
65
  Optional Arguments:
59
- None
66
+ refresh => ('true' | 'false' | 'wait_for') Whether to refresh the datastore before returning.
67
+ 'wait_for' will wait for the change to be visible in search.
60
68
 
61
69
  Data Block:
62
70
  {
@@ -72,8 +80,10 @@ def create_dossier(**kwargs):
72
80
  """
73
81
  dossier_data = request.json
74
82
 
83
+ refresh = kwargs.get("refresh")
84
+
75
85
  try:
76
- return created(dossier_service.create_dossier(dossier_data, username=kwargs["user"]["uname"]))
86
+ return created(dossier_service.create_dossier(dossier_data, username=kwargs["user"]["uname"], refresh=refresh))
77
87
  except InvalidDataException as e:
78
88
  return bad_request(err=str(e))
79
89
  except HowlerException:
@@ -147,6 +157,7 @@ def get_dossier_for_hit(id: str, user: User, **kwargs):
147
157
  @generate_swagger_docs()
148
158
  @dossier_api.route("/<id>", methods=["DELETE"])
149
159
  @api_login(required_priv=["W"])
160
+ @parse_parameters(refresh=parse_refresh)
150
161
  def delete_dossier(id: str, user: User, **kwargs):
151
162
  """Delete a dossier
152
163
 
@@ -154,7 +165,8 @@ def delete_dossier(id: str, user: User, **kwargs):
154
165
  id => The id of the dossier to delete
155
166
 
156
167
  Optional Arguments:
157
- None
168
+ refresh => ('true' | 'false' | 'wait_for') Whether to refresh the datastore before returning.
169
+ 'wait_for' will wait for the change to be visible in search.
158
170
 
159
171
  Data Block:
160
172
  None
@@ -164,6 +176,8 @@ def delete_dossier(id: str, user: User, **kwargs):
164
176
  "success": true # Did the deletion succeed?
165
177
  }
166
178
  """
179
+ refresh = kwargs.get("refresh")
180
+
167
181
  storage = datastore()
168
182
 
169
183
  existing_dossier: Dossier = storage.dossier.get_if_exists(id)
@@ -173,9 +187,7 @@ def delete_dossier(id: str, user: User, **kwargs):
173
187
  if existing_dossier.owner != user.uname and "admin" not in user.type:
174
188
  return forbidden(err="You cannot delete a dossier unless you are an administrator, or the owner.")
175
189
 
176
- success = storage.dossier.delete(id)
177
-
178
- storage.dossier.commit()
190
+ success = storage.dossier.delete(id, refresh=refresh)
179
191
 
180
192
  return no_content({"success": success})
181
193
 
@@ -183,6 +195,7 @@ def delete_dossier(id: str, user: User, **kwargs):
183
195
  @generate_swagger_docs()
184
196
  @dossier_api.route("/<id>", methods=["PUT"])
185
197
  @api_login(required_priv=["R", "W"])
198
+ @parse_parameters(refresh=parse_refresh)
186
199
  def update_dossier(id: str, user: User, **kwargs):
187
200
  """Update a dossier
188
201
 
@@ -190,7 +203,8 @@ def update_dossier(id: str, user: User, **kwargs):
190
203
  id => The id of the dossier to modify
191
204
 
192
205
  Optional Arguments:
193
- None
206
+ refresh => ('true' | 'false' | 'wait_for') Whether to refresh the datastore before returning.
207
+ 'wait_for' will wait for the change to be visible in search.
194
208
 
195
209
  Data Block:
196
210
  {
@@ -207,8 +221,10 @@ def update_dossier(id: str, user: User, **kwargs):
207
221
  if not isinstance(new_data, dict):
208
222
  return bad_request(err="Invalid data format")
209
223
 
224
+ refresh = kwargs.get("refresh")
225
+
210
226
  try:
211
- updated_dossier = dossier_service.update_dossier(id, new_data, user)
227
+ updated_dossier = dossier_service.update_dossier(id, new_data, user, refresh=refresh)
212
228
 
213
229
  return ok(updated_dossier)
214
230
  except ForbiddenException as e: