howler-api 3.2.0.dev438__tar.gz → 3.2.0.dev467__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 (199) hide show
  1. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/PKG-INFO +1 -1
  2. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/actions/prioritization.py +2 -2
  3. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/actions/transition.py +2 -2
  4. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/api/__init__.py +9 -2
  5. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/api/socket.py +1 -1
  6. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/api/v1/__init__.py +1 -1
  7. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/api/v1/action.py +2 -2
  8. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/api/v1/analytic.py +15 -24
  9. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/api/v1/auth.py +11 -9
  10. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/api/v1/clue.py +3 -3
  11. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/api/v1/configs.py +1 -1
  12. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/api/v1/dossier.py +1 -1
  13. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/api/v1/help.py +1 -1
  14. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/api/v1/hit.py +28 -27
  15. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/api/v1/notebook.py +1 -1
  16. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/api/v1/overview.py +1 -1
  17. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/api/v1/search.py +7 -8
  18. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/api/v1/template.py +1 -1
  19. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/api/v1/tool.py +3 -3
  20. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/api/v1/user.py +11 -11
  21. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/api/v1/view.py +7 -5
  22. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/common/classification.py +2 -1
  23. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/common/logging/__init__.py +2 -2
  24. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/common/swagger.py +2 -1
  25. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/datastore/bulk.py +11 -11
  26. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/datastore/collection.py +120 -18
  27. howler_api-3.2.0.dev467/howler/datastore/types.py +11 -0
  28. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/error.py +1 -1
  29. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/helper/hit.py +2 -2
  30. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/helper/oauth.py +6 -4
  31. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/base.py +3 -3
  32. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/helper.py +1 -1
  33. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/howler_data.py +3 -3
  34. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/user.py +11 -11
  35. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/random_data.py +1 -1
  36. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/security/__init__.py +5 -4
  37. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/security/socket.py +23 -19
  38. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/security/utils.py +2 -2
  39. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/services/analytic_service.py +33 -5
  40. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/services/auth_service.py +6 -5
  41. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/services/dossier_service.py +33 -5
  42. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/services/hit_service.py +75 -16
  43. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/services/jwt_service.py +5 -5
  44. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/services/lucene_service.py +3 -1
  45. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/services/template_service.py +16 -4
  46. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/services/user_service.py +26 -6
  47. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/utils/lucene.py +1 -1
  48. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/pyproject.toml +8 -3
  49. howler_api-3.2.0.dev438/howler/datastore/types.py +0 -22
  50. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/README.md +0 -0
  51. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/__init__.py +0 -0
  52. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/actions/__init__.py +0 -0
  53. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/actions/add_label.py +0 -0
  54. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/actions/add_to_bundle.py +0 -0
  55. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/actions/change_field.py +0 -0
  56. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/actions/demote.py +0 -0
  57. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/actions/example_plugin.py +0 -0
  58. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/actions/promote.py +0 -0
  59. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/actions/remove_from_bundle.py +0 -0
  60. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/actions/remove_label.py +0 -0
  61. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/api/base.py +0 -0
  62. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/api/v1/utils/__init__.py +0 -0
  63. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/api/v1/utils/etag.py +0 -0
  64. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/app.py +0 -0
  65. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/common/README.md +0 -0
  66. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/common/__init__.py +0 -0
  67. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/common/classification.yml +0 -0
  68. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/common/exceptions.py +0 -0
  69. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/common/loader.py +0 -0
  70. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/common/logging/audit.py +0 -0
  71. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/common/logging/format.py +0 -0
  72. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/common/net.py +0 -0
  73. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/common/net_static.py +0 -0
  74. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/common/random_user.py +0 -0
  75. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/config.py +0 -0
  76. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/cronjobs/__init__.py +0 -0
  77. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/cronjobs/retention.py +0 -0
  78. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/cronjobs/rules.py +0 -0
  79. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/cronjobs/view_cleanup.py +0 -0
  80. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/datastore/README.md +0 -0
  81. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/datastore/__init__.py +0 -0
  82. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/datastore/constants.py +0 -0
  83. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/datastore/exceptions.py +0 -0
  84. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/datastore/howler_store.py +0 -0
  85. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/datastore/migrations/fix_process.py +0 -0
  86. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/datastore/operations.py +0 -0
  87. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/datastore/schemas.py +0 -0
  88. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/datastore/store.py +0 -0
  89. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/datastore/support/__init__.py +0 -0
  90. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/datastore/support/build.py +0 -0
  91. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/datastore/support/schemas.py +0 -0
  92. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/external/__init__.py +0 -0
  93. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/external/generate_mitre.py +0 -0
  94. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/external/generate_sigma_rules.py +0 -0
  95. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/external/generate_tlds.py +0 -0
  96. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/external/reindex_data.py +0 -0
  97. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/external/wipe_databases.py +0 -0
  98. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/gunicorn_config.py +0 -0
  99. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/healthz.py +0 -0
  100. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/helper/__init__.py +0 -0
  101. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/helper/azure.py +0 -0
  102. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/helper/discover.py +0 -0
  103. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/helper/search.py +0 -0
  104. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/helper/workflow.py +0 -0
  105. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/helper/ws.py +0 -0
  106. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/README.md +0 -0
  107. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/__init__.py +0 -0
  108. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/charter.txt +0 -0
  109. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/howler_enum.py +0 -0
  110. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/__init__.py +0 -0
  111. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/action.py +0 -0
  112. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/analytic.py +0 -0
  113. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/assemblyline.py +0 -0
  114. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/aws.py +0 -0
  115. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/azure.py +0 -0
  116. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/cbs.py +0 -0
  117. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/clue.py +0 -0
  118. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/config.py +0 -0
  119. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/dossier.py +0 -0
  120. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/ecs/__init__.py +0 -0
  121. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/ecs/agent.py +0 -0
  122. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/ecs/autonomous_system.py +0 -0
  123. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/ecs/client.py +0 -0
  124. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/ecs/cloud.py +0 -0
  125. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/ecs/code_signature.py +0 -0
  126. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/ecs/container.py +0 -0
  127. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/ecs/dns.py +0 -0
  128. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/ecs/egress.py +0 -0
  129. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/ecs/elf.py +0 -0
  130. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/ecs/email.py +0 -0
  131. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/ecs/error.py +0 -0
  132. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/ecs/event.py +0 -0
  133. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/ecs/faas.py +0 -0
  134. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/ecs/file.py +0 -0
  135. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/ecs/geo.py +0 -0
  136. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/ecs/group.py +0 -0
  137. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/ecs/hash.py +0 -0
  138. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/ecs/host.py +0 -0
  139. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/ecs/http.py +0 -0
  140. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/ecs/ingress.py +0 -0
  141. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/ecs/interface.py +0 -0
  142. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/ecs/network.py +0 -0
  143. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/ecs/observer.py +0 -0
  144. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/ecs/organization.py +0 -0
  145. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/ecs/os.py +0 -0
  146. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/ecs/pe.py +0 -0
  147. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/ecs/process.py +0 -0
  148. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/ecs/registry.py +0 -0
  149. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/ecs/related.py +0 -0
  150. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/ecs/rule.py +0 -0
  151. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/ecs/server.py +0 -0
  152. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/ecs/threat.py +0 -0
  153. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/ecs/tls.py +0 -0
  154. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/ecs/url.py +0 -0
  155. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/ecs/user.py +0 -0
  156. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/ecs/user_agent.py +0 -0
  157. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/ecs/vulnerability.py +0 -0
  158. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/gcp.py +0 -0
  159. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/hit.py +0 -0
  160. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/lead.py +0 -0
  161. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/localized_label.py +0 -0
  162. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/overview.py +0 -0
  163. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/pivot.py +0 -0
  164. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/template.py +0 -0
  165. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/models/view.py +0 -0
  166. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/odm/randomizer.py +0 -0
  167. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/patched.py +0 -0
  168. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/plugins/__init__.py +0 -0
  169. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/plugins/config.py +0 -0
  170. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/remote/__init__.py +0 -0
  171. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/remote/datatypes/README.md +0 -0
  172. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/remote/datatypes/__init__.py +0 -0
  173. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/remote/datatypes/counters.py +0 -0
  174. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/remote/datatypes/events.py +0 -0
  175. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/remote/datatypes/hash.py +0 -0
  176. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/remote/datatypes/lock.py +0 -0
  177. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/remote/datatypes/queues/__init__.py +0 -0
  178. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/remote/datatypes/queues/comms.py +0 -0
  179. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/remote/datatypes/queues/multi.py +0 -0
  180. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/remote/datatypes/queues/named.py +0 -0
  181. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/remote/datatypes/queues/priority.py +0 -0
  182. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/remote/datatypes/set.py +0 -0
  183. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/remote/datatypes/user_quota_tracker.py +0 -0
  184. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/services/__init__.py +0 -0
  185. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/services/action_service.py +0 -0
  186. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/services/config_service.py +0 -0
  187. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/services/event_service.py +0 -0
  188. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/services/notebook_service.py +0 -0
  189. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/services/overview_service.py +0 -0
  190. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/utils/__init__.py +0 -0
  191. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/utils/annotations.py +0 -0
  192. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/utils/chunk.py +0 -0
  193. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/utils/dict_utils.py +0 -0
  194. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/utils/isotime.py +0 -0
  195. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/utils/list_utils.py +0 -0
  196. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/utils/path.py +0 -0
  197. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/utils/socket_utils.py +0 -0
  198. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/utils/str_utils.py +0 -0
  199. {howler_api-3.2.0.dev438 → howler_api-3.2.0.dev467}/howler/utils/uid.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: howler-api
3
- Version: 3.2.0.dev438
3
+ Version: 3.2.0.dev467
4
4
  Summary: Howler - API server
5
5
  License: MIT
6
6
  Keywords: howler,alerting,gc,canada,cse-cst,cse,cst,cyber,cccs
@@ -10,7 +10,7 @@ OPERATION_ID = "prioritization"
10
10
  VALID_FIELDS = ["reliability", "severity", "volume", "confidence", "score"]
11
11
 
12
12
 
13
- def execute(query: str, field: str = "score", value: str = "0.0", **kwargs):
13
+ def execute(query: str, field: str = "score", value: str | float = "0.0", **kwargs):
14
14
  """Change one of the priorization fields of a hit
15
15
 
16
16
  Args:
@@ -34,7 +34,7 @@ def execute(query: str, field: str = "score", value: str = "0.0", **kwargs):
34
34
  report = []
35
35
 
36
36
  try:
37
- value: float = float(value)
37
+ value = float(value)
38
38
 
39
39
  datastore().hit.update_by_query(
40
40
  query,
@@ -1,5 +1,5 @@
1
1
  import inspect
2
- from typing import Optional
2
+ from typing import Optional, cast
3
3
 
4
4
  from howler.common.exceptions import InvalidDataException, NotFoundException
5
5
  from howler.common.loader import datastore
@@ -115,7 +115,7 @@ def execute(
115
115
  try:
116
116
  hit_service.transition_hit(
117
117
  hit_id,
118
- HitStatusTransition[transition],
118
+ cast(HitStatusTransition, HitStatusTransition[transition]),
119
119
  user,
120
120
  **kwargs,
121
121
  )
@@ -28,8 +28,15 @@ def make_subapi_blueprint(name, api_version=1):
28
28
 
29
29
 
30
30
  def _make_api_response(
31
- data: Any, err: Union[str, Exception] = "", warnings: list[str] = [], status_code: int = 200, cookies: Any = None
31
+ data: Any,
32
+ err: Union[str, Exception] = "",
33
+ warnings: list[str] | None = None,
34
+ status_code: int = 200,
35
+ cookies: Any = None,
32
36
  ) -> Response:
37
+ if not warnings:
38
+ warnings = []
39
+
33
40
  quota_user = flsk_session.pop("quota_user", None)
34
41
  quota_set = flsk_session.pop("quota_set", False)
35
42
  if quota_user and quota_set and not request.path.startswith("/api/v1/clue"):
@@ -100,7 +107,7 @@ def not_modified(data=DEFAULT_DATA[True], cookies=None):
100
107
  return _make_api_response(data, status_code=304, cookies=cookies)
101
108
 
102
109
 
103
- def bad_request(data=DEFAULT_DATA[False], err="", cookies=None, warnings=None):
110
+ def bad_request(data: Any = DEFAULT_DATA[False], err: str = "", cookies: Any = None, warnings: list[str] | None = None):
104
111
  """Returns response with status code ies"""
105
112
  return _make_api_response(data, err, status_code=400, cookies=cookies, warnings=warnings)
106
113
 
@@ -46,7 +46,7 @@ def emit(event: str):
46
46
  return ok()
47
47
 
48
48
 
49
- @socket_api.route("/connect", websocket=True)
49
+ @socket_api.route("/connect", websocket=True) # type: ignore
50
50
  @websocket_auth(required_priv=["R"])
51
51
  def connect(ws: Server, *args: Any, ws_id: str, **kwargs):
52
52
  """Connect to the server to monitor for updates via websocket
@@ -7,7 +7,7 @@ from howler.security import api_login
7
7
 
8
8
  API_PREFIX = "/api/v1"
9
9
  apiv1 = Blueprint("apiv1", __name__, url_prefix=API_PREFIX)
10
- apiv1._doc = "Api Documentation Version 1" # type: ignore[attr-defined]
10
+ apiv1._doc = "Api Documentation Version 1" # type: ignore[attr-defined] # type: ignore
11
11
 
12
12
 
13
13
  @apiv1.route("/")
@@ -18,7 +18,7 @@ SUB_API = "action"
18
18
  classification_definition = CLASSIFICATION.get_parsed_classification_definition()
19
19
 
20
20
  action_api = make_subapi_blueprint(SUB_API, api_version=1)
21
- action_api._doc = "Endpoints relating to bulk actions and automation"
21
+ action_api._doc = "Endpoints relating to bulk actions and automation" # type: ignore
22
22
 
23
23
 
24
24
  @generate_swagger_docs()
@@ -240,7 +240,7 @@ def execute_action(id: str, **kwargs) -> Response:
240
240
  current_user: User | None = kwargs.get("user", None)
241
241
 
242
242
  for operation in action.operations:
243
- op_data = json.loads(operation["data_json"])
243
+ op_data = json.loads(operation.data_json) if operation.data_json else {}
244
244
 
245
245
  query = execute_req.get("query", action.query) or action.query
246
246
 
@@ -27,7 +27,7 @@ from howler.services import analytic_service, user_service
27
27
  MAX_COMMENT_LEN = 5000
28
28
  SUB_API = "analytic"
29
29
  analytic_api = make_subapi_blueprint(SUB_API, api_version=1)
30
- analytic_api._doc = "Manage the analytics that create hits"
30
+ analytic_api._doc = "Manage the analytics that create hits" # type: ignore
31
31
 
32
32
  logger = get_logger(__file__)
33
33
 
@@ -75,7 +75,7 @@ def get_analytic(id, **kwargs):
75
75
  if not analytic_service.does_analytic_exist(id):
76
76
  return not_found(err="Analytic does not exist")
77
77
 
78
- return ok(analytic_service.get_analytic(id, as_obj=False))
78
+ return ok(analytic_service.get_analytic(id, as_odm=False))
79
79
  except ValueError as e:
80
80
  return bad_request(err=str(e))
81
81
 
@@ -251,7 +251,7 @@ def delete_rule(id: str, user: User, **kwargs):
251
251
  if not analytic_service.does_analytic_exist(id):
252
252
  return not_found(err=f"Analytic {id} does not exist")
253
253
 
254
- analytic: Analytic = analytic_service.get_analytic(id, as_obj=True)
254
+ analytic = analytic_service.get_analytic(id, as_odm=True)
255
255
 
256
256
  if not analytic.rule:
257
257
  return bad_request(err="This is not a rule analytic, and cannot be deleted.")
@@ -304,7 +304,7 @@ def add_comment(id: str, user: dict[str, Any], **kwargs):
304
304
  if not analytic_service.does_analytic_exist(id):
305
305
  return not_found(err="Analytic %s does not exist" % id)
306
306
 
307
- analytic: Analytic = analytic_service.get_analytic(id, as_obj=True)
307
+ analytic = analytic_service.get_analytic(id, as_odm=True)
308
308
 
309
309
  try:
310
310
  analytic.comment.append(
@@ -321,8 +321,6 @@ def add_comment(id: str, user: dict[str, Any], **kwargs):
321
321
  except DataStoreException as e:
322
322
  return bad_request(err=str(e))
323
323
 
324
- analytic = analytic_service.get_analytic(id)
325
-
326
324
  return ok(analytic)
327
325
 
328
326
 
@@ -363,7 +361,7 @@ def edit_comment(id: str, comment_id: str, user: dict[str, Any], **kwargs):
363
361
  if len(comment_data) > MAX_COMMENT_LEN:
364
362
  return bad_request(err="Comment is too long.")
365
363
 
366
- analytic: Analytic = analytic_service.get_analytic(id, as_obj=True)
364
+ analytic = analytic_service.get_analytic(id, as_odm=True)
367
365
 
368
366
  comment: Optional[Comment] = next((c for c in analytic.comment if c.id == comment_id), None)
369
367
 
@@ -420,14 +418,11 @@ def react_comment(id: str, comment_id: str, user: dict[str, Any], **kwargs):
420
418
  if not analytic_service.does_analytic_exist(id):
421
419
  return not_found(err=f"Analytic {id} does not exist")
422
420
 
423
- analytic: Analytic = analytic_service.get_analytic(id, as_obj=True)
421
+ analytic = analytic_service.get_analytic(id, as_odm=True)
424
422
 
425
423
  for comment in analytic.comment:
426
424
  if comment.id == comment_id:
427
- comment["reactions"] = {
428
- **comment.get("reactions", {}),
429
- user["uname"]: react_data,
430
- }
425
+ comment.reactions[user["uname"]] = react_data
431
426
 
432
427
  datastore().analytic.save(analytic.analytic_id, analytic)
433
428
 
@@ -455,11 +450,11 @@ def remove_react_comment(id: str, comment_id: str, user: dict[str, Any], **kwarg
455
450
  if not analytic_service.does_analytic_exist(id):
456
451
  return not_found(err=f"Analytic {id} does not exist")
457
452
 
458
- analytic: Analytic = analytic_service.get_analytic(id, as_obj=True)
453
+ analytic = analytic_service.get_analytic(id, as_odm=True)
459
454
 
460
455
  for comment in analytic.comment:
461
456
  if comment.id == comment_id:
462
- reactions = comment.get("reactions", {})
457
+ reactions = comment.reactions
463
458
  reactions.pop(user["uname"], None)
464
459
  comment["reactions"] = {**reactions}
465
460
 
@@ -497,7 +492,7 @@ def delete_comments(id: str, user: User, **kwargs):
497
492
  if len(comment_ids) == 0:
498
493
  return bad_request(err="Supply at least one comment to delete.")
499
494
 
500
- analytic: Analytic = analytic_service.get_analytic(id, as_obj=True)
495
+ analytic = analytic_service.get_analytic(id, as_odm=True)
501
496
 
502
497
  new_comments = []
503
498
  for comment in analytic.comment:
@@ -548,7 +543,7 @@ def set_analytic_owner(id: str, user: dict[str, Any], **kwargs):
548
543
  if not user_service.get_user(data["username"]):
549
544
  return not_found(err=f"User {data['username']} does not exist")
550
545
 
551
- analytic: Analytic = analytic_service.get_analytic(id, as_obj=True)
546
+ analytic = analytic_service.get_analytic(id, as_odm=True)
552
547
 
553
548
  analytic.owner = data["username"]
554
549
 
@@ -588,7 +583,7 @@ def set_as_favourite(id, **kwargs):
588
583
  try:
589
584
  current_user = storage.user.get_if_exists(kwargs["user"]["uname"])
590
585
 
591
- current_user["favourite_analytics"] = list(set(current_user.get("favourite_analytics", []) + [id]))
586
+ current_user.favourite_analytics.append(id)
592
587
 
593
588
  storage.user.save(current_user["uname"], current_user)
594
589
 
@@ -622,9 +617,7 @@ def remove_as_favourite(id, **kwargs):
622
617
  try:
623
618
  current_user = storage.user.get_if_exists(kwargs["user"]["uname"])
624
619
 
625
- current_user["favourite_analytics"] = list(
626
- filter(lambda f: f != id, current_user.get("favourite_analytics", []))
627
- )
620
+ current_user["favourite_analytics"] = list(filter(lambda f: f != id, current_user.favourite_analytics))
628
621
 
629
622
  storage.user.save(current_user["uname"], current_user)
630
623
 
@@ -674,7 +667,7 @@ def add_notebook(id: str, user: dict[str, Any], **kwargs):
674
667
  if not analytic_service.does_analytic_exist(id):
675
668
  return not_found(err="Analytic %s does not exist" % id)
676
669
 
677
- analytic: Analytic = analytic_service.get_analytic(id, as_obj=True)
670
+ analytic = analytic_service.get_analytic(id, as_odm=True)
678
671
 
679
672
  try:
680
673
  analytic.notebooks.append(
@@ -692,8 +685,6 @@ def add_notebook(id: str, user: dict[str, Any], **kwargs):
692
685
  except DataStoreException as e:
693
686
  return bad_request(err=str(e))
694
687
 
695
- analytic = analytic_service.get_analytic(id)
696
-
697
688
  return ok(analytic)
698
689
 
699
690
 
@@ -726,7 +717,7 @@ def delete_notebook(id: str, user: User, **kwargs):
726
717
  if len(notebook_ids) == 0:
727
718
  return bad_request(err="A notebook id is necessary for deletion.")
728
719
 
729
- analytic: Analytic = analytic_service.get_analytic(id, as_obj=True)
720
+ analytic = analytic_service.get_analytic(id, as_odm=True)
730
721
 
731
722
  new_notebooks = []
732
723
  for notebook in analytic.notebooks:
@@ -30,7 +30,7 @@ from howler.common.loader import datastore
30
30
  from howler.common.logging import get_logger
31
31
  from howler.common.swagger import generate_swagger_docs
32
32
  from howler.config import config
33
- from howler.odm.models.user import User
33
+ from howler.odm.models.user import ApiKey, User
34
34
  from howler.security import api_login
35
35
  from howler.security.utils import generate_random_secret
36
36
  from howler.services import jwt_service
@@ -41,7 +41,7 @@ logger = get_logger(__file__)
41
41
 
42
42
  SUB_API = "auth"
43
43
  auth_api = make_subapi_blueprint(SUB_API, api_version=1)
44
- auth_api._doc = "Allow user to authenticate to the web server"
44
+ auth_api._doc = "Allow user to authenticate to the web server" # type: ignore
45
45
 
46
46
  logger = get_logger(__file__)
47
47
 
@@ -117,6 +117,7 @@ def add_apikey(**kwargs): # noqa: C901
117
117
  )
118
118
  max_expiry = datetime.fromtimestamp(data["exp"])
119
119
 
120
+ expiry = None
120
121
  if expiry_date:
121
122
  try:
122
123
  expiry = datetime.fromisoformat(expiry_date.replace("Z", ""))
@@ -136,10 +137,10 @@ def add_apikey(**kwargs): # noqa: C901
136
137
  "acl": privs,
137
138
  }
138
139
 
139
- if expiry_date:
140
+ if expiry:
140
141
  new_key["expiry_date"] = expiry.isoformat()
141
142
 
142
- user_data.apikeys[key_name] = new_key
143
+ user_data.apikeys[key_name] = ApiKey(new_key)
143
144
  except HowlerException as e:
144
145
  return bad_request(err=e.message)
145
146
 
@@ -235,8 +236,8 @@ def login(**_): # noqa: C901
235
236
  apikey = data.get("apikey", None)
236
237
 
237
238
  # These variables are what will eventually be returned, if authentication is successful
238
- logged_in_uname = None
239
- access_token = None
239
+ logged_in_uname: str | None = None
240
+ access_token: str | None = None
240
241
  refresh_token = data.get("refresh_token", None)
241
242
  priv: Optional[list[str]] = []
242
243
 
@@ -316,7 +317,7 @@ def login(**_): # noqa: C901
316
317
  token_data, oauth_provider, skip_setup=False, access_token=access_token
317
318
  )
318
319
 
319
- logged_in_uname = cur_user["uname"]
320
+ logged_in_uname = cur_user.uname
320
321
 
321
322
  priv = ["R", "W", "E"]
322
323
 
@@ -336,7 +337,7 @@ def login(**_): # noqa: C901
336
337
  if not user_data:
337
338
  raise AuthenticationException("User does not exist, or authentication was invalid") # noqa: TRY301
338
339
 
339
- logged_in_uname = user_data["uname"]
340
+ logged_in_uname = user_data.uname
340
341
 
341
342
  else:
342
343
  raise AuthenticationException("Not enough information to proceed with authentication") # noqa: TRY301
@@ -366,9 +367,10 @@ def login(**_): # noqa: C901
366
367
 
367
368
  # Generate the token this user can use to authenticate from now on
368
369
 
370
+ app_token = None
369
371
  if access_token:
370
372
  app_token = access_token
371
- else:
373
+ elif logged_in_uname:
372
374
  app_token = f"{logged_in_uname}:{auth_service.create_token(logged_in_uname, typing.cast(list[str], priv))}"
373
375
 
374
376
  return ok(
@@ -2,8 +2,8 @@ import sys
2
2
  import time
3
3
  from typing import Callable, Optional
4
4
 
5
- import elasticapm
6
5
  import requests
6
+ from elasticapm.traces import capture_span
7
7
  from flask import request
8
8
 
9
9
  from howler.api import bad_gateway, make_subapi_blueprint, ok
@@ -16,7 +16,7 @@ from howler.security import api_login
16
16
 
17
17
  SUB_API = "clue"
18
18
  clue_api = make_subapi_blueprint(SUB_API, api_version=1)
19
- clue_api._doc = "Proxy enrichment requests to clue"
19
+ clue_api._doc = "Proxy enrichment requests to clue" # type: ignore
20
20
 
21
21
  logger = get_logger(__file__)
22
22
 
@@ -74,7 +74,7 @@ def proxy_to_clue(path, **kwargs):
74
74
  clue_token = get_token(auth_token)
75
75
 
76
76
  start = time.perf_counter()
77
- with elasticapm.capture_span("clue", span_type="http"):
77
+ with capture_span("clue", span_type="http"):
78
78
  if request.method.lower() == "get":
79
79
  response = requests.get(
80
80
  f"{config.core.clue.url}/{path}",
@@ -10,7 +10,7 @@ from howler.security.utils import get_disco_url
10
10
 
11
11
  SUB_API = "configs"
12
12
  config_api = make_subapi_blueprint(SUB_API, api_version=1)
13
- config_api._doc = "Read configuration data about the system"
13
+ config_api._doc = "Read configuration data about the system" # type: ignore
14
14
 
15
15
 
16
16
  @generate_swagger_docs()
@@ -12,7 +12,7 @@ from howler.services import dossier_service
12
12
 
13
13
  SUB_API = "dossier"
14
14
  dossier_api = make_subapi_blueprint(SUB_API, api_version=1)
15
- dossier_api._doc = "Manage the different dossiers created for filtering hits"
15
+ dossier_api._doc = "Manage the different dossiers created for filtering hits" # type: ignore
16
16
 
17
17
  logger = get_logger(__file__)
18
18
 
@@ -7,7 +7,7 @@ SUB_API = "help"
7
7
  classification_definition = CLASSIFICATION.get_parsed_classification_definition()
8
8
 
9
9
  help_api = make_subapi_blueprint(SUB_API, api_version=1)
10
- help_api._doc = "Provide information about the system configuration"
10
+ help_api._doc = "Provide information about the system configuration" # type: ignore
11
11
 
12
12
 
13
13
  @generate_swagger_docs()
@@ -36,7 +36,7 @@ MAX_COMMENT_LEN = 5000
36
36
 
37
37
  SUB_API = "hit"
38
38
  hit_api = make_subapi_blueprint(SUB_API, api_version=1)
39
- hit_api._doc = "Manage the different hits in the system"
39
+ hit_api._doc = "Manage the different hits in the system" # type: ignore
40
40
 
41
41
  FIELDS = Hit.flat_fields()
42
42
 
@@ -118,7 +118,7 @@ def create_hits(user: User, **kwargs):
118
118
  # Ensure all ids are consistent
119
119
  if odm.event is not None:
120
120
  odm.event.id = odm.howler.id
121
- hit_service.create_hit(odm.howler.id, odm, user=user["uname"])
121
+ hit_service.create_hit(odm.howler.id, odm, user=user.uname)
122
122
  analytic_service.save_from_hit(odm, user)
123
123
 
124
124
  datastore().hit.commit()
@@ -311,12 +311,15 @@ def overwrite_hit(id: str, server_version: str, **kwargs):
311
311
  return bad_request(err="The JSON payload must be a subset of a valid Hit object.")
312
312
 
313
313
  try:
314
- new_hit = merge(
315
- hit_service.flatten(hit.as_primitives(), odm=Hit),
316
- hit_service.flatten(new_fields),
317
- strategy=Strategy.REPLACE
318
- if bool(request.args.get("replace", False, type=lambda v: v.lower() == "true"))
319
- else Strategy.ADDITIVE,
314
+ new_hit = cast(
315
+ dict[str, Any],
316
+ merge(
317
+ hit_service.flatten(hit.as_primitives(), odm=Hit),
318
+ hit_service.flatten(new_fields),
319
+ strategy=Strategy.REPLACE
320
+ if bool(request.args.get("replace", False, type=lambda v: v.lower() == "true"))
321
+ else Strategy.ADDITIVE,
322
+ ),
320
323
  )
321
324
 
322
325
  new_hit, new_version = hit_service.save_hit(Hit(new_hit), server_version)
@@ -486,9 +489,9 @@ def get_assigned_hits(user, **kwargs):
486
489
  deep_paging_id=request.args.get("deep_paging_id", None),
487
490
  offset=request.args.get("offset", 0, type=int), # type: ignore[union-attr]
488
491
  rows=request.args.get("rows", None, type=int), # type: ignore[union-attr]
489
- sort=request.args.get("sort", None),
490
- fl=request.args.get("fl", None),
491
- timeout=request.args.get("timeout", None),
492
+ sort=request.args.get("sort", None, type=str),
493
+ fl=request.args.get("fl", None, type=str),
494
+ timeout=request.args.get("timeout", None, type=int),
492
495
  as_obj=False,
493
496
  )["items"]
494
497
 
@@ -554,7 +557,7 @@ def add_label(id, label_set, user, **kwargs):
554
557
  user=user,
555
558
  )
556
559
 
557
- hit, version = hit_service.get_hit(id, version=True)
560
+ hit, version = hit_service.get_hit(id, as_odm=False, version=True)
558
561
 
559
562
  return ok(hit), version
560
563
 
@@ -612,7 +615,7 @@ def remove_labels(id, label_set, user, **kwargs):
612
615
  user=user,
613
616
  )
614
617
 
615
- hit, version = hit_service.get_hit(id, version=True)
618
+ hit, version = hit_service.get_hit(id, as_odm=False, version=True)
616
619
 
617
620
  return ok(hit), version
618
621
 
@@ -672,7 +675,7 @@ def transition(id: str, user: User, **kwargs):
672
675
  except HowlerException as e:
673
676
  return internal_error(err=str(e))
674
677
 
675
- hit, version = hit_service.get_hit(id, version=True)
678
+ hit, version = hit_service.get_hit(id, as_odm=False, version=True)
676
679
  return ok(hit), version
677
680
 
678
681
 
@@ -759,7 +762,7 @@ def add_comment(id: str, user: dict[str, Any], **kwargs):
759
762
  except DataStoreException as e:
760
763
  return bad_request(err=str(e))
761
764
 
762
- hit, version = hit_service.get_hit(id, version=True)
765
+ hit, version = hit_service.get_hit(id, as_odm=False, version=True)
763
766
 
764
767
  return ok(hit), version
765
768
 
@@ -822,7 +825,7 @@ def edit_comment(id: str, comment_id: str, user: dict[str, Any], **kwargs):
822
825
  if line[:3] not in ("+++", "---", "@@ "):
823
826
  diff.append(line)
824
827
 
825
- (hit, version) = hit_service.update_hit(
828
+ (new_hit, version) = hit_service.update_hit(
826
829
  id,
827
830
  [
828
831
  hit_helper.list_remove("howler.comment", comment, silent=True),
@@ -834,7 +837,8 @@ def edit_comment(id: str, comment_id: str, user: dict[str, Any], **kwargs):
834
837
  ],
835
838
  user["uname"],
836
839
  )
837
- return ok(hit), version
840
+
841
+ return ok(new_hit), version
838
842
 
839
843
 
840
844
  @generate_swagger_docs()
@@ -889,13 +893,14 @@ def delete_comments(id: str, user: User, **kwargs):
889
893
  )
890
894
  for comment in comments
891
895
  ],
892
- user["uname"],
896
+ user.uname,
893
897
  )
894
898
 
895
899
  except DataStoreException as e:
896
900
  return bad_request(err=str(e))
897
- hit, version = hit_service.get_hit(id, version=True)
898
- return ok(hit), version
901
+
902
+ new_hit, version = hit_service.get_hit(id, as_odm=False, version=True)
903
+ return ok(new_hit), version
899
904
 
900
905
 
901
906
  @generate_swagger_docs()
@@ -1028,7 +1033,7 @@ def create_bundle(user: User, **kwargs):
1028
1033
  if hit_id not in odm.howler.hits:
1029
1034
  odm.howler.hits.append(hit_id)
1030
1035
 
1031
- hit_service.create_hit(odm.howler.id, odm, user=user["uname"])
1036
+ hit_service.create_hit(odm.howler.id, odm, user=user.uname)
1032
1037
  analytic_service.save_from_hit(odm, user)
1033
1038
 
1034
1039
  for hit_id in odm.howler.hits:
@@ -1039,9 +1044,7 @@ def create_bundle(user: User, **kwargs):
1039
1044
  err=f"You cannot specify a bundle as a child of another bundle - {child_hit.howler.id} is a bundle."
1040
1045
  )
1041
1046
 
1042
- new_bundle_list = child_hit.howler.get("bundles", [])
1043
- new_bundle_list.append(odm.howler.id)
1044
- child_hit.howler.bundles = new_bundle_list
1047
+ child_hit.howler.bundles.append(odm.howler.id)
1045
1048
  datastore().hit.save(child_hit.howler.id, child_hit)
1046
1049
 
1047
1050
  return created(odm)
@@ -1165,12 +1168,10 @@ def remove_bundle_children(id, **kwargs):
1165
1168
  for hit_id in hit_ids:
1166
1169
  child_hit: Hit = hit_service.get_hit(hit_id, as_odm=True)
1167
1170
 
1168
- new_bundle_list = child_hit.howler.get("bundles", [])
1169
1171
  try:
1170
- new_bundle_list.remove(bundle_hit.howler.id)
1172
+ child_hit.howler.bundles.remove(bundle_hit.howler.id)
1171
1173
  except ValueError:
1172
1174
  logger.warning("Bundle isn't included in child %s!", bundle_hit.howler.id)
1173
- child_hit.howler.bundles = new_bundle_list
1174
1175
 
1175
1176
  datastore().hit.save(child_hit.howler.id, child_hit)
1176
1177
 
@@ -7,7 +7,7 @@ from howler.services import notebook_service
7
7
 
8
8
  SUB_API = "notebook"
9
9
  notebook_api = make_subapi_blueprint(SUB_API, api_version=1)
10
- notebook_api._doc = "Get notebook information"
10
+ notebook_api._doc = "Get notebook information" # type: ignore
11
11
 
12
12
 
13
13
  @generate_swagger_docs()
@@ -21,7 +21,7 @@ from howler.utils.str_utils import sanitize_lucene_query
21
21
 
22
22
  SUB_API = "overview"
23
23
  overview_api = make_subapi_blueprint(SUB_API, api_version=1)
24
- overview_api._doc = "Manage the different overviews created for viewing hits"
24
+ overview_api._doc = "Manage the different overviews created for viewing hits" # type: ignore
25
25
 
26
26
  logger = get_logger(__file__)
27
27
 
@@ -1,10 +1,10 @@
1
1
  import re
2
2
  from copy import deepcopy
3
- from typing import Any, Union
3
+ from typing import Any
4
4
 
5
5
  from elasticsearch import BadRequestError
6
6
  from elasticsearch._sync.client.indices import IndicesClient
7
- from flask import request
7
+ from flask import Request, request
8
8
  from sigma.backends.elasticsearch import LuceneBackend
9
9
  from sigma.rule import SigmaRule
10
10
  from werkzeug.exceptions import BadRequest
@@ -21,12 +21,12 @@ from howler.services import hit_service, lucene_service
21
21
 
22
22
  SUB_API = "search"
23
23
  search_api = make_subapi_blueprint(SUB_API, api_version=1)
24
- search_api._doc = "Perform search queries"
24
+ search_api._doc = "Perform search queries" # type: ignore
25
25
 
26
26
  logger = get_logger(__file__)
27
27
 
28
28
 
29
- def generate_params(request, fields, multi_fields, params=None):
29
+ def generate_params(request: Request, fields: list[str], multi_fields: list[str], params: dict[str, Any] | None = None):
30
30
  """Generate a list of parameters, combining the request data and the query arguments"""
31
31
  # I hate you, python
32
32
  if params is None:
@@ -49,7 +49,7 @@ def generate_params(request, fields, multi_fields, params=None):
49
49
  params = {
50
50
  **params,
51
51
  **{k: req_data[k] for k in fields if k in req_data},
52
- **{k: req_data.getlist(k, None) for k in multi_fields if k in req_data},
52
+ **{k: req_data.getlist(k) for k in multi_fields if k in req_data},
53
53
  }
54
54
 
55
55
  return params, req_data
@@ -130,7 +130,6 @@ def search(index, **kwargs):
130
130
  if has_access_control(index):
131
131
  params.update({"access_control": user["access_control"]})
132
132
 
133
- params["as_obj"] = False
134
133
  params.update({"sort": (params.get("sort", None) or default_sort).split(",")})
135
134
 
136
135
  query = req_data.get("query", None)
@@ -139,7 +138,7 @@ def search(index, **kwargs):
139
138
 
140
139
  try:
141
140
  metadata = params.pop("metadata", [])
142
- result = collection().search(query, **params)
141
+ result = collection().search(query, as_obj=False, **params)
143
142
 
144
143
  if index == "hit" and len(metadata) > 0:
145
144
  hit_service.augment_metadata(result["items"], metadata, user)
@@ -703,7 +702,7 @@ def histogram(index, field, **kwargs):
703
702
 
704
703
  # Get fields default values
705
704
  field_info = collection().fields().get(field, None)
706
- params: dict[str, Union[str, int]] = {}
705
+ params: dict[str, Any] = {}
707
706
  if field_info is None:
708
707
  return bad_request(err=f"Field '{field}' is not a valid field in index: {index}")
709
708
  elif field_info["type"] == "integer":
@@ -22,7 +22,7 @@ from howler.utils.str_utils import sanitize_lucene_query
22
22
 
23
23
  SUB_API = "template"
24
24
  template_api = make_subapi_blueprint(SUB_API, api_version=1)
25
- template_api._doc = "Manage the different templates created for viewing hits"
25
+ template_api._doc = "Manage the different templates created for viewing hits" # type: ignore
26
26
 
27
27
  logger = get_logger(__file__)
28
28
 
@@ -20,7 +20,7 @@ from howler.utils.uid import get_random_id
20
20
 
21
21
  SUB_API = "tools"
22
22
  tool_api = make_subapi_blueprint(SUB_API, api_version=1)
23
- tool_api._doc = "Manage the tools"
23
+ tool_api._doc = "Manage the tools" # type: ignore
24
24
 
25
25
  logger = get_logger(__file__)
26
26
 
@@ -167,12 +167,12 @@ def create_one_or_many_hits(tool_name: str, user: User, **kwargs): # noqa: C901
167
167
  bundle_hit.howler.bundle_size += 1
168
168
  odm.howler.bundles.append(bundle_hit.howler.id)
169
169
 
170
- hit_service.create_hit(odm.howler.id, odm, user=user["uname"])
170
+ hit_service.create_hit(odm.howler.id, odm, user=user.uname)
171
171
 
172
172
  analytic_service.save_from_hit(odm, user)
173
173
 
174
174
  if bundle_hit:
175
- hit_service.create_hit(bundle_hit.howler.id, bundle_hit, user=user["uname"])
175
+ hit_service.create_hit(bundle_hit.howler.id, bundle_hit, user=user.uname)
176
176
 
177
177
  analytic_service.save_from_hit(bundle_hit, user)
178
178