howler-api 4.0.0.dev1121__tar.gz → 4.0.0.dev1141__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 (223) hide show
  1. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/PKG-INFO +1 -1
  2. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/api/v2/case.py +4 -2
  3. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/api/v2/search.py +3 -10
  4. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/case.py +8 -0
  5. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/services/case_service.py +27 -0
  6. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/services/search_service.py +14 -5
  7. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/pyproject.toml +1 -1
  8. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/README.md +0 -0
  9. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/__init__.py +0 -0
  10. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/actions/__init__.py +0 -0
  11. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/actions/add_label.py +0 -0
  12. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/actions/add_to_bundle.py +0 -0
  13. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/actions/add_to_case.py +0 -0
  14. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/actions/change_field.py +0 -0
  15. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/actions/demote.py +0 -0
  16. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/actions/example_plugin.py +0 -0
  17. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/actions/prioritization.py +0 -0
  18. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/actions/promote.py +0 -0
  19. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/actions/remove_from_bundle.py +0 -0
  20. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/actions/remove_label.py +0 -0
  21. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/actions/transition.py +0 -0
  22. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/api/__init__.py +0 -0
  23. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/api/base.py +0 -0
  24. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/api/socket.py +0 -0
  25. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/api/v1/__init__.py +0 -0
  26. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/api/v1/action.py +0 -0
  27. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/api/v1/analytic.py +0 -0
  28. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/api/v1/auth.py +0 -0
  29. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/api/v1/clue.py +0 -0
  30. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/api/v1/configs.py +0 -0
  31. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/api/v1/dossier.py +0 -0
  32. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/api/v1/help.py +0 -0
  33. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/api/v1/hit.py +0 -0
  34. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/api/v1/notebook.py +0 -0
  35. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/api/v1/overview.py +0 -0
  36. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/api/v1/search.py +0 -0
  37. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/api/v1/template.py +0 -0
  38. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/api/v1/tool.py +0 -0
  39. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/api/v1/user.py +0 -0
  40. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/api/v1/utils/__init__.py +0 -0
  41. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/api/v1/utils/etag.py +0 -0
  42. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/api/v1/utils/params.py +0 -0
  43. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/api/v1/view.py +0 -0
  44. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/api/v2/__init__.py +0 -0
  45. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/api/v2/fuzzy.py +0 -0
  46. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/api/v2/ingest.py +0 -0
  47. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/app.py +0 -0
  48. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/common/README.md +0 -0
  49. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/common/__init__.py +0 -0
  50. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/common/classification.py +0 -0
  51. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/common/classification.yml +0 -0
  52. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/common/exceptions.py +0 -0
  53. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/common/loader.py +0 -0
  54. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/common/logging/__init__.py +0 -0
  55. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/common/logging/audit.py +0 -0
  56. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/common/logging/format.py +0 -0
  57. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/common/net.py +0 -0
  58. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/common/net_static.py +0 -0
  59. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/common/random_user.py +0 -0
  60. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/common/swagger.py +0 -0
  61. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/config.py +0 -0
  62. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/cronjobs/__init__.py +0 -0
  63. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/cronjobs/action_queue_worker.py +0 -0
  64. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/cronjobs/correlation.py +0 -0
  65. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/cronjobs/retention.py +0 -0
  66. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/cronjobs/view_cleanup.py +0 -0
  67. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/datastore/README.md +0 -0
  68. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/datastore/__init__.py +0 -0
  69. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/datastore/bulk.py +0 -0
  70. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/datastore/collection.py +0 -0
  71. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/datastore/constants.py +0 -0
  72. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/datastore/exceptions.py +0 -0
  73. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/datastore/howler_store.py +0 -0
  74. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/datastore/migrations/fix_process.py +0 -0
  75. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/datastore/operations.py +0 -0
  76. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/datastore/schemas.py +0 -0
  77. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/datastore/store.py +0 -0
  78. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/datastore/support/__init__.py +0 -0
  79. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/datastore/support/build.py +0 -0
  80. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/datastore/support/schemas.py +0 -0
  81. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/datastore/types.py +0 -0
  82. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/error.py +0 -0
  83. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/external/README.md +0 -0
  84. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/external/__init__.py +0 -0
  85. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/external/generate_mitre.py +0 -0
  86. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/external/generate_sigma_rules.py +0 -0
  87. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/external/generate_tlds.py +0 -0
  88. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/external/reindex_data.py +0 -0
  89. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/external/wipe_databases.py +0 -0
  90. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/gunicorn_config.py +0 -0
  91. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/healthz.py +0 -0
  92. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/helper/__init__.py +0 -0
  93. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/helper/azure.py +0 -0
  94. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/helper/discover.py +0 -0
  95. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/helper/hit.py +0 -0
  96. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/helper/oauth.py +0 -0
  97. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/helper/search.py +0 -0
  98. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/helper/workflow.py +0 -0
  99. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/helper/ws.py +0 -0
  100. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/README.md +0 -0
  101. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/__init__.py +0 -0
  102. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/base.py +0 -0
  103. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/charter.txt +0 -0
  104. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/constants.py +0 -0
  105. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/helper.py +0 -0
  106. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/howler_enum.py +0 -0
  107. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/mixins.py +0 -0
  108. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/__init__.py +0 -0
  109. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/action.py +0 -0
  110. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/analytic.py +0 -0
  111. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/assemblyline.py +0 -0
  112. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/aws.py +0 -0
  113. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/azure.py +0 -0
  114. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/cbs.py +0 -0
  115. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/clue.py +0 -0
  116. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/config.py +0 -0
  117. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/dossier.py +0 -0
  118. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/ecs/__init__.py +0 -0
  119. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/ecs/agent.py +0 -0
  120. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/ecs/autonomous_system.py +0 -0
  121. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/ecs/client.py +0 -0
  122. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/ecs/cloud.py +0 -0
  123. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/ecs/code_signature.py +0 -0
  124. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/ecs/container.py +0 -0
  125. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/ecs/dns.py +0 -0
  126. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/ecs/egress.py +0 -0
  127. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/ecs/elf.py +0 -0
  128. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/ecs/email.py +0 -0
  129. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/ecs/error.py +0 -0
  130. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/ecs/event.py +0 -0
  131. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/ecs/faas.py +0 -0
  132. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/ecs/file.py +0 -0
  133. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/ecs/geo.py +0 -0
  134. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/ecs/group.py +0 -0
  135. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/ecs/hash.py +0 -0
  136. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/ecs/host.py +0 -0
  137. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/ecs/http.py +0 -0
  138. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/ecs/ingress.py +0 -0
  139. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/ecs/interface.py +0 -0
  140. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/ecs/network.py +0 -0
  141. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/ecs/observer.py +0 -0
  142. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/ecs/organization.py +0 -0
  143. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/ecs/os.py +0 -0
  144. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/ecs/pe.py +0 -0
  145. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/ecs/process.py +0 -0
  146. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/ecs/registry.py +0 -0
  147. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/ecs/related.py +0 -0
  148. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/ecs/rule.py +0 -0
  149. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/ecs/server.py +0 -0
  150. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/ecs/threat.py +0 -0
  151. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/ecs/tls.py +0 -0
  152. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/ecs/url.py +0 -0
  153. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/ecs/user.py +0 -0
  154. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/ecs/user_agent.py +0 -0
  155. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/ecs/vulnerability.py +0 -0
  156. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/event.py +0 -0
  157. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/gcp.py +0 -0
  158. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/hit.py +0 -0
  159. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/howler_data.py +0 -0
  160. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/lead.py +0 -0
  161. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/localized_label.py +0 -0
  162. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/overview.py +0 -0
  163. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/pivot.py +0 -0
  164. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/record.py +0 -0
  165. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/template.py +0 -0
  166. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/user.py +0 -0
  167. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/models/view.py +0 -0
  168. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/random_data.py +0 -0
  169. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/odm/randomizer.py +0 -0
  170. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/patched.py +0 -0
  171. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/plugins/__init__.py +0 -0
  172. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/plugins/config.py +0 -0
  173. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/remote/__init__.py +0 -0
  174. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/remote/datatypes/README.md +0 -0
  175. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/remote/datatypes/__init__.py +0 -0
  176. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/remote/datatypes/counters.py +0 -0
  177. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/remote/datatypes/events.py +0 -0
  178. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/remote/datatypes/hash.py +0 -0
  179. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/remote/datatypes/lock.py +0 -0
  180. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/remote/datatypes/queues/__init__.py +0 -0
  181. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/remote/datatypes/queues/comms.py +0 -0
  182. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/remote/datatypes/queues/multi.py +0 -0
  183. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/remote/datatypes/queues/named.py +0 -0
  184. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/remote/datatypes/queues/priority.py +0 -0
  185. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/remote/datatypes/set.py +0 -0
  186. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/remote/datatypes/user_quota_tracker.py +0 -0
  187. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/security/__init__.py +0 -0
  188. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/security/socket.py +0 -0
  189. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/security/utils.py +0 -0
  190. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/services/__init__.py +0 -0
  191. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/services/action_service.py +0 -0
  192. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/services/analytic_service.py +0 -0
  193. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/services/auth_service.py +0 -0
  194. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/services/bundle_compat_service.py +0 -0
  195. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/services/comms_service.py +0 -0
  196. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/services/config_service.py +0 -0
  197. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/services/correlation_service.py +0 -0
  198. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/services/docs_service.py +0 -0
  199. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/services/dossier_service.py +0 -0
  200. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/services/event_service.py +0 -0
  201. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/services/fuzzy_service.py +0 -0
  202. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/services/hit_service.py +0 -0
  203. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/services/jwt_service.py +0 -0
  204. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/services/lucene_service.py +0 -0
  205. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/services/notebook_service.py +0 -0
  206. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/services/overview_service.py +0 -0
  207. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/services/template_service.py +0 -0
  208. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/services/user_service.py +0 -0
  209. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/services/viewer_service.py +0 -0
  210. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/telemetry.py +0 -0
  211. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/utils/__init__.py +0 -0
  212. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/utils/annotations.py +0 -0
  213. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/utils/chunk.py +0 -0
  214. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/utils/compat.py +0 -0
  215. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/utils/constants.py +0 -0
  216. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/utils/dict_utils.py +0 -0
  217. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/utils/isotime.py +0 -0
  218. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/utils/list_utils.py +0 -0
  219. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/utils/lucene.py +0 -0
  220. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/utils/path.py +0 -0
  221. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/utils/socket_utils.py +0 -0
  222. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/howler/utils/str_utils.py +0 -0
  223. {howler_api-4.0.0.dev1121 → howler_api-4.0.0.dev1141}/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.dev1121
3
+ Version: 4.0.0.dev1141
4
4
  Summary: Howler - API server
5
5
  License: MIT
6
6
  Keywords: howler,alerting,gc,canada,cse-cst,cse,cst,cyber,cccs
@@ -63,7 +63,7 @@ def create_case(user: User, **kwargs):
63
63
  @generate_swagger_docs()
64
64
  @case_api.route("/<id>", methods=["GET"])
65
65
  @api_login(audit=True, required_priv=["R"])
66
- def get_case(id: str, **kwargs):
66
+ def get_case(id: str, user: User, **kwargs):
67
67
  """Get a case.
68
68
 
69
69
  Variables:
@@ -77,11 +77,13 @@ def get_case(id: str, **kwargs):
77
77
  ...case # The requested case, if it exists
78
78
  }
79
79
  """
80
- case = datastore().case.get_if_exists(key=id, as_obj=False)
80
+ case = datastore().case.get(id, as_obj=False)
81
81
 
82
82
  if not case:
83
83
  return not_found(err="Case %s does not exist" % id)
84
84
 
85
+ case_service.filter_case_items_by_classification(case, user.classification)
86
+
85
87
  return ok(case)
86
88
 
87
89
 
@@ -12,6 +12,7 @@ from howler.common.logging import get_logger
12
12
  from howler.common.swagger import generate_swagger_docs
13
13
  from howler.datastore.exceptions import SearchException
14
14
  from howler.helper.search import get_collection, has_access_control
15
+ from howler.odm.models.user import User
15
16
  from howler.security import api_login
16
17
  from howler.services import hit_service, lucene_service, search_service
17
18
 
@@ -51,7 +52,7 @@ def generate_params(request: Request, fields: list[str], multi_fields: list[str]
51
52
  @generate_swagger_docs()
52
53
  @search_api.route("/<indexes>", methods=["GET", "POST"])
53
54
  @api_login(required_priv=["R"])
54
- def search(indexes: str, **kwargs):
55
+ def search(indexes: str, user: User, **kwargs):
55
56
  """Search through specified index for a given query. Uses lucene search syntax for query.
56
57
 
57
58
  Variables:
@@ -91,8 +92,6 @@ def search(indexes: str, **kwargs):
91
92
  "next_deep_paging_id": "asX3f...342", # ID to pass back for the next page during deep paging
92
93
  "items": []} # List of results
93
94
  """
94
- user = kwargs["user"]
95
-
96
95
  index_list = indexes.split(",")
97
96
 
98
97
  fields = [
@@ -117,12 +116,6 @@ def search(indexes: str, **kwargs):
117
116
  }
118
117
  )
119
118
 
120
- # NOTE: This means index searches must be either ALL access controlled or none of them havbe access control.
121
- # Otherwise, the access control requirements on one index will cause the other index to return no items.
122
- # This is pretty reasonable constraint, as all the relevant, searchable items support classifications.
123
- if has_access_control(index_list):
124
- params["access_control"] = user["access_control"]
125
-
126
119
  params["sort"] = [entry for entry in params.get("sort", "").split(",") if entry] or search_service.DEFAULT_SORT
127
120
 
128
121
  query = req_data.get("query", None)
@@ -130,7 +123,7 @@ def search(indexes: str, **kwargs):
130
123
  return bad_request(err="There was no search query.")
131
124
 
132
125
  metadata = params.pop("metadata", [])
133
- result = search_service.search(indexes, query, access_control=params.pop("access_control", None), **params)
126
+ result = search_service.search(indexes, query, user=user, **params)
134
127
 
135
128
  if metadata and any(idx in index_list for idx in ["hit"]):
136
129
  hit_service.augment_metadata(result["items"], metadata, user)
@@ -79,6 +79,14 @@ class CaseItem(odm.Model):
79
79
  type: str = odm.Enum(values=CaseItemTypes, description="Type of case item.")
80
80
  value: str = odm.Keyword(description="String reference value for the item (ID, URL, or token).")
81
81
  visible: bool = odm.Boolean(default=True, description="Whether the item is visible/accessible in the frontend.")
82
+ classification: Optional[str] = odm.Optional(
83
+ odm.Classification(
84
+ is_user_classification=False,
85
+ copyto="__text__",
86
+ default=CLASSIFICATION.UNRESTRICTED,
87
+ description="Classification of the related record. Automatically populated for hit and event items.",
88
+ )
89
+ )
82
90
 
83
91
 
84
92
  @odm.model(index=True, store=True, description="Rule used to place/query data into case paths.")
@@ -12,6 +12,7 @@ from prometheus_client import Counter
12
12
  from howler.common.exceptions import HowlerValueError, InvalidDataException, NotFoundException
13
13
  from howler.common.loader import APP_NAME, datastore
14
14
  from howler.common.logging import get_logger
15
+ from howler.config import CLASSIFICATION
15
16
  from howler.datastore.exceptions import DataStoreException
16
17
  from howler.odm.models.case import Case, CaseItem, CaseItemTypes, CaseLog, CaseRule
17
18
  from howler.odm.models.ecs.related import Related
@@ -150,6 +151,28 @@ def delete_cases(case_ids: set[str]) -> bool:
150
151
  return ds.case.delete_by_query(f"case_id:({' OR '.join(case_ids)})")
151
152
 
152
153
 
154
+ def filter_case_items_by_classification(_case: dict, user_classification: str):
155
+ """Remove items from a case dict that exceed the user's classification.
156
+
157
+ Items without a ``classification`` value are always included. Items with a
158
+ classification are only included when ``CLASSIFICATION.is_accessible``
159
+ confirms the requesting user can see them.
160
+
161
+ Args:
162
+ case: Raw case dict (as returned by ``as_obj=False`` datastore calls).
163
+ user_classification: The requesting user's maximum classification string.
164
+ """
165
+ if "items" not in _case:
166
+ return
167
+
168
+ _case["items"] = [
169
+ item
170
+ for item in _case["items"]
171
+ if item.get("classification") is None
172
+ or CLASSIFICATION.is_accessible(user_classification, item["classification"])
173
+ ]
174
+
175
+
153
176
  def get_last_resolved_time(case: Case) -> datetime | None:
154
177
  """Return the timestamp of the most recent resolution of a case.
155
178
 
@@ -389,6 +412,8 @@ def append_hit(case_id: str, item: CaseItem) -> Case:
389
412
  if hit is None:
390
413
  raise NotFoundException(f"Hit {item.value} not found, cannot be added to case")
391
414
 
415
+ item.classification = hit.classification
416
+
392
417
  _case.items.append(item)
393
418
 
394
419
  if not ds.case.save(_case.case_id, _case):
@@ -436,6 +461,8 @@ def append_event(case_id: str, item: CaseItem) -> Case:
436
461
  if event is None:
437
462
  raise NotFoundException(f"Event {item.value} not found, cannot be added to case")
438
463
 
464
+ item.classification = event.classification
465
+
439
466
  _case.items.append(item)
440
467
 
441
468
  if not ds.case.save(_case.case_id, _case):
@@ -9,6 +9,9 @@ from howler.common.loader import APP_NAME, datastore
9
9
  from howler.datastore.collection import parse_sort
10
10
  from howler.datastore.exceptions import SearchException, SearchRetryException
11
11
  from howler.datastore.types import SearchResult
12
+ from howler.helper.search import has_access_control
13
+ from howler.odm.models.user import User
14
+ from howler.services import case_service
12
15
 
13
16
  DEFAULT_OFFSET = 0
14
17
  DEFAULT_ROW_SIZE = 25
@@ -61,7 +64,7 @@ def _normalize_indexes(indexes: str | list[str]) -> str:
61
64
  return ",".join(normalized_indexes)
62
65
 
63
66
 
64
- def _format_items(hits: list[dict[str, Any]]) -> list[dict[str, Any]]:
67
+ def _format_items(hits: list[dict[str, Any]], user_classification: str | None) -> list[dict[str, Any]]:
65
68
  """Formats Elasticsearch search hits into a standardized item format.
66
69
 
67
70
  Extracts the _source content from each hit.
@@ -82,6 +85,9 @@ def _format_items(hits: list[dict[str, Any]]) -> list[dict[str, Any]]:
82
85
  if raw_index:
83
86
  source["__index"] = raw_index.replace(f"{APP_NAME}-", "").replace("_hot", "")
84
87
 
88
+ if source.get("__index") == "case" and user_classification:
89
+ case_service.filter_case_items_by_classification(source, user_classification)
90
+
85
91
  items.append(source)
86
92
 
87
93
  return items
@@ -99,7 +105,7 @@ def search( # noqa: C901
99
105
  timeout: int | None = None,
100
106
  track_total_hits: bool = False,
101
107
  metadata: list[str] | None = None,
102
- access_control: str | None = None,
108
+ user: User | None = None,
103
109
  ) -> SearchResult[dict[str, Any]]:
104
110
  """Search through specified index for a given query. Uses lucene search syntax for query.
105
111
 
@@ -137,8 +143,11 @@ def search( # noqa: C901
137
143
  else:
138
144
  parsed_filters = filters
139
145
 
140
- if access_control:
141
- parsed_filters.append(access_control)
146
+ # NOTE: This means index searches must be either ALL access controlled or none of them have access control.
147
+ # Otherwise, the access control requirements on one index will cause the other index to return no items.
148
+ # This is pretty reasonable constraint, as all the relevant, searchable items support classifications.
149
+ if user and user.access_control and has_access_control(indexes):
150
+ parsed_filters.append(user.access_control)
142
151
 
143
152
  if query is None:
144
153
  query = "id:*"
@@ -197,7 +206,7 @@ def search( # noqa: C901
197
206
  "offset": int(offset),
198
207
  "rows": len(hits),
199
208
  "total": int(total),
200
- "items": _format_items(hits),
209
+ "items": _format_items(hits, user.classification if user else None),
201
210
  }
202
211
 
203
212
  next_deep_paging_id = result.get("_scroll_id")
@@ -152,7 +152,7 @@ suppress-none-returning = true
152
152
  [tool.poetry]
153
153
  package-mode = true
154
154
  name = "howler-api"
155
- version = "4.0.0.dev1121"
155
+ version = "4.0.0.dev1141"
156
156
  description = "Howler - API server"
157
157
  authors = [
158
158
  "Canadian Centre for Cyber Security <howler@cyber.gc.ca>",