howler-api 3.2.0.dev532__tar.gz → 3.2.0.dev554__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.

Potentially problematic release.


This version of howler-api might be problematic. Click here for more details.

Files changed (198) hide show
  1. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/PKG-INFO +1 -1
  2. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/api/v1/auth.py +2 -0
  3. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/config.py +4 -0
  4. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/services/auth_service.py +97 -1
  5. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/pyproject.toml +1 -1
  6. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/README.md +0 -0
  7. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/__init__.py +0 -0
  8. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/actions/__init__.py +0 -0
  9. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/actions/add_label.py +0 -0
  10. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/actions/add_to_bundle.py +0 -0
  11. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/actions/change_field.py +0 -0
  12. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/actions/demote.py +0 -0
  13. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/actions/example_plugin.py +0 -0
  14. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/actions/prioritization.py +0 -0
  15. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/actions/promote.py +0 -0
  16. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/actions/remove_from_bundle.py +0 -0
  17. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/actions/remove_label.py +0 -0
  18. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/actions/transition.py +0 -0
  19. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/api/__init__.py +0 -0
  20. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/api/base.py +0 -0
  21. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/api/socket.py +0 -0
  22. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/api/v1/__init__.py +0 -0
  23. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/api/v1/action.py +0 -0
  24. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/api/v1/analytic.py +0 -0
  25. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/api/v1/clue.py +0 -0
  26. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/api/v1/configs.py +0 -0
  27. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/api/v1/dossier.py +0 -0
  28. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/api/v1/help.py +0 -0
  29. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/api/v1/hit.py +0 -0
  30. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/api/v1/notebook.py +0 -0
  31. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/api/v1/overview.py +0 -0
  32. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/api/v1/search.py +0 -0
  33. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/api/v1/template.py +0 -0
  34. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/api/v1/tool.py +0 -0
  35. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/api/v1/user.py +0 -0
  36. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/api/v1/utils/__init__.py +0 -0
  37. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/api/v1/utils/etag.py +0 -0
  38. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/api/v1/view.py +0 -0
  39. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/app.py +0 -0
  40. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/common/README.md +0 -0
  41. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/common/__init__.py +0 -0
  42. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/common/classification.py +0 -0
  43. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/common/classification.yml +0 -0
  44. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/common/exceptions.py +0 -0
  45. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/common/loader.py +0 -0
  46. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/common/logging/__init__.py +0 -0
  47. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/common/logging/audit.py +0 -0
  48. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/common/logging/format.py +0 -0
  49. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/common/net.py +0 -0
  50. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/common/net_static.py +0 -0
  51. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/common/random_user.py +0 -0
  52. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/common/swagger.py +0 -0
  53. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/config.py +0 -0
  54. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/cronjobs/__init__.py +0 -0
  55. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/cronjobs/retention.py +0 -0
  56. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/cronjobs/rules.py +0 -0
  57. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/cronjobs/view_cleanup.py +0 -0
  58. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/datastore/README.md +0 -0
  59. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/datastore/__init__.py +0 -0
  60. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/datastore/bulk.py +0 -0
  61. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/datastore/collection.py +0 -0
  62. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/datastore/constants.py +0 -0
  63. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/datastore/exceptions.py +0 -0
  64. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/datastore/howler_store.py +0 -0
  65. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/datastore/migrations/fix_process.py +0 -0
  66. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/datastore/operations.py +0 -0
  67. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/datastore/schemas.py +0 -0
  68. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/datastore/store.py +0 -0
  69. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/datastore/support/__init__.py +0 -0
  70. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/datastore/support/build.py +0 -0
  71. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/datastore/support/schemas.py +0 -0
  72. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/datastore/types.py +0 -0
  73. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/error.py +0 -0
  74. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/external/__init__.py +0 -0
  75. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/external/generate_mitre.py +0 -0
  76. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/external/generate_sigma_rules.py +0 -0
  77. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/external/generate_tlds.py +0 -0
  78. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/external/reindex_data.py +0 -0
  79. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/external/wipe_databases.py +0 -0
  80. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/gunicorn_config.py +0 -0
  81. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/healthz.py +0 -0
  82. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/helper/__init__.py +0 -0
  83. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/helper/azure.py +0 -0
  84. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/helper/discover.py +0 -0
  85. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/helper/hit.py +0 -0
  86. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/helper/oauth.py +0 -0
  87. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/helper/search.py +0 -0
  88. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/helper/workflow.py +0 -0
  89. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/helper/ws.py +0 -0
  90. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/README.md +0 -0
  91. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/__init__.py +0 -0
  92. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/base.py +0 -0
  93. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/charter.txt +0 -0
  94. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/helper.py +0 -0
  95. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/howler_enum.py +0 -0
  96. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/__init__.py +0 -0
  97. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/action.py +0 -0
  98. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/analytic.py +0 -0
  99. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/assemblyline.py +0 -0
  100. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/aws.py +0 -0
  101. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/azure.py +0 -0
  102. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/cbs.py +0 -0
  103. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/clue.py +0 -0
  104. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/dossier.py +0 -0
  105. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/__init__.py +0 -0
  106. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/agent.py +0 -0
  107. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/autonomous_system.py +0 -0
  108. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/client.py +0 -0
  109. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/cloud.py +0 -0
  110. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/code_signature.py +0 -0
  111. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/container.py +0 -0
  112. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/dns.py +0 -0
  113. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/egress.py +0 -0
  114. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/elf.py +0 -0
  115. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/email.py +0 -0
  116. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/error.py +0 -0
  117. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/event.py +0 -0
  118. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/faas.py +0 -0
  119. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/file.py +0 -0
  120. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/geo.py +0 -0
  121. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/group.py +0 -0
  122. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/hash.py +0 -0
  123. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/host.py +0 -0
  124. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/http.py +0 -0
  125. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/ingress.py +0 -0
  126. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/interface.py +0 -0
  127. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/network.py +0 -0
  128. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/observer.py +0 -0
  129. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/organization.py +0 -0
  130. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/os.py +0 -0
  131. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/pe.py +0 -0
  132. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/process.py +0 -0
  133. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/registry.py +0 -0
  134. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/related.py +0 -0
  135. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/rule.py +0 -0
  136. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/server.py +0 -0
  137. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/threat.py +0 -0
  138. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/tls.py +0 -0
  139. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/url.py +0 -0
  140. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/user.py +0 -0
  141. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/user_agent.py +0 -0
  142. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/vulnerability.py +0 -0
  143. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/gcp.py +0 -0
  144. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/hit.py +0 -0
  145. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/howler_data.py +0 -0
  146. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/lead.py +0 -0
  147. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/localized_label.py +0 -0
  148. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/overview.py +0 -0
  149. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/pivot.py +0 -0
  150. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/template.py +0 -0
  151. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/user.py +0 -0
  152. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/view.py +0 -0
  153. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/random_data.py +0 -0
  154. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/randomizer.py +0 -0
  155. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/patched.py +0 -0
  156. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/plugins/__init__.py +0 -0
  157. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/plugins/config.py +0 -0
  158. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/remote/__init__.py +0 -0
  159. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/remote/datatypes/README.md +0 -0
  160. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/remote/datatypes/__init__.py +0 -0
  161. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/remote/datatypes/counters.py +0 -0
  162. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/remote/datatypes/events.py +0 -0
  163. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/remote/datatypes/hash.py +0 -0
  164. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/remote/datatypes/lock.py +0 -0
  165. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/remote/datatypes/queues/__init__.py +0 -0
  166. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/remote/datatypes/queues/comms.py +0 -0
  167. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/remote/datatypes/queues/multi.py +0 -0
  168. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/remote/datatypes/queues/named.py +0 -0
  169. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/remote/datatypes/queues/priority.py +0 -0
  170. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/remote/datatypes/set.py +0 -0
  171. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/remote/datatypes/user_quota_tracker.py +0 -0
  172. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/security/__init__.py +0 -0
  173. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/security/socket.py +0 -0
  174. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/security/utils.py +0 -0
  175. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/services/__init__.py +0 -0
  176. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/services/action_service.py +0 -0
  177. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/services/analytic_service.py +0 -0
  178. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/services/config_service.py +0 -0
  179. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/services/dossier_service.py +0 -0
  180. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/services/event_service.py +0 -0
  181. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/services/hit_service.py +0 -0
  182. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/services/jwt_service.py +0 -0
  183. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/services/lucene_service.py +0 -0
  184. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/services/notebook_service.py +0 -0
  185. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/services/overview_service.py +0 -0
  186. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/services/template_service.py +0 -0
  187. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/services/user_service.py +0 -0
  188. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/utils/__init__.py +0 -0
  189. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/utils/annotations.py +0 -0
  190. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/utils/chunk.py +0 -0
  191. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/utils/dict_utils.py +0 -0
  192. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/utils/isotime.py +0 -0
  193. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/utils/list_utils.py +0 -0
  194. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/utils/lucene.py +0 -0
  195. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/utils/path.py +0 -0
  196. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/utils/socket_utils.py +0 -0
  197. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/utils/str_utils.py +0 -0
  198. {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/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.dev532
3
+ Version: 3.2.0.dev554
4
4
  Summary: Howler - API server
5
5
  License: MIT
6
6
  Keywords: howler,alerting,gc,canada,cse-cst,cse,cst,cyber,cccs
@@ -144,6 +144,7 @@ def add_apikey(**kwargs): # noqa: C901
144
144
  except HowlerException as e:
145
145
  return bad_request(err=e.message)
146
146
 
147
+ auth_service.invalidate_apikey_cache(user["uname"], key_name)
147
148
  storage.user.save(user["uname"], user_data)
148
149
 
149
150
  return ok({"apikey": f"{key_name}:{random_pass}"})
@@ -173,6 +174,7 @@ def delete_apikey(name, **kwargs):
173
174
  return not_found("Api key does not exist")
174
175
 
175
176
  user_data.apikeys.pop(name)
177
+ auth_service.invalidate_apikey_cache(user["uname"], name)
176
178
  storage.user.save(user["uname"], user_data)
177
179
 
178
180
  return no_content()
@@ -284,6 +284,10 @@ class Auth(BaseModel):
284
284
 
285
285
  allow_apikeys: bool = Field(default=True, description="Allow API keys?")
286
286
  allow_extended_apikeys: bool = Field(default=True, description="Allow extended API keys?")
287
+ hmac_secret_key: str = Field(
288
+ default=os.environ.get("HMAC_SECRET_KEY", "changeme"),
289
+ description="HMAC secret used in auth hash operations. Change this in production!",
290
+ )
287
291
  max_apikey_duration_amount: Optional[int] = Field(
288
292
  default=None, description="Amount of unit of maximum duration for API keys"
289
293
  )
@@ -1,5 +1,6 @@
1
1
  import base64
2
2
  import hashlib
3
+ import hmac
3
4
  from datetime import datetime
4
5
  from typing import Optional, Union
5
6
 
@@ -18,6 +19,7 @@ from howler.common.loader import datastore
18
19
  from howler.common.logging import get_logger
19
20
  from howler.config import config, redis
20
21
  from howler.odm.models.user import User
22
+ from howler.remote.datatypes import retry_call
21
23
  from howler.remote.datatypes.queues.named import NamedQueue
22
24
  from howler.remote.datatypes.set import ExpiringSet
23
25
  from howler.security.utils import generate_random_secret, verify_password
@@ -30,6 +32,93 @@ nonpersistent_config: dict[str, Union[str, int]] = {
30
32
  "ttl": config.auth.internal.failure_ttl,
31
33
  }
32
34
 
35
+ # TTL for the apikey verification cache (seconds)
36
+ _APIKEY_CACHE_TTL: int = 600 # 10 minutes
37
+
38
+ # Derive the HMAC key from the configured secret
39
+ _HMAC_KEY: bytes = hashlib.sha256(config.auth.hmac_secret_key.encode()).digest()
40
+
41
+
42
+ def _apikey_cache_key(username: str, key_name: str) -> str:
43
+ """Build the Redis key that identifies a cached apikey verification.
44
+
45
+ Args:
46
+ username (str): The authenticating username.
47
+ key_name (str): The name portion of the apikey.
48
+
49
+ Returns:
50
+ str: The Redis cache key.
51
+ """
52
+ return f"apikey_cache:{username}:{key_name}"
53
+
54
+
55
+ def _hash_secret(username: str, key_name: str, secret: str) -> str:
56
+ """Return an HMAC-SHA256 hex digest of an apikey secret.
57
+
58
+ Uses a derived HMAC key so that cached hashes are useless without
59
+ access to the application's configured secret.
60
+
61
+ Args:
62
+ username (str): The authenticating username.
63
+ key_name (str): The name portion of the apikey.
64
+ secret (str): The raw apikey secret.
65
+
66
+ Returns:
67
+ str: The HMAC hex digest.
68
+ """
69
+ return hmac.new(_HMAC_KEY, f"{username}:{key_name}:{secret}".encode(), hashlib.sha256).hexdigest()
70
+
71
+
72
+ def _is_apikey_cached(username: str, key_name: str, secret: str) -> bool:
73
+ """Check whether a previous bcrypt verification for this apikey is cached.
74
+
75
+ The Redis key identifies the apikey (username + key name) and the stored
76
+ value is the HMAC-SHA256 digest of the apikey secret (as computed by
77
+ :func:`_hash_secret` from the username, key name, and secret).
78
+
79
+ Args:
80
+ username (str): The authenticating username.
81
+ key_name (str): The name portion of the apikey.
82
+ secret (str): The raw apikey secret to compare against the cache.
83
+
84
+ Returns:
85
+ bool: True if the cache holds a matching hash for this secret.
86
+ """
87
+ raw = retry_call(redis.get, _apikey_cache_key(username, key_name))
88
+ if raw is None:
89
+ return False
90
+ cached_hash = raw.decode() if isinstance(raw, bytes) else raw
91
+ return hmac.compare_digest(cached_hash, _hash_secret(username, key_name, secret))
92
+
93
+
94
+ def _cache_apikey_verification(username: str, key_name: str, secret: str) -> None:
95
+ """Store a successful bcrypt verification in Redis.
96
+
97
+ Args:
98
+ username (str): The authenticating username.
99
+ key_name (str): The name portion of the apikey.
100
+ secret (str): The raw apikey secret whose hash will be stored.
101
+ """
102
+ retry_call(
103
+ redis.setex,
104
+ _apikey_cache_key(username, key_name),
105
+ _APIKEY_CACHE_TTL,
106
+ _hash_secret(username, key_name, secret),
107
+ )
108
+
109
+
110
+ def invalidate_apikey_cache(username: str, key_name: str) -> None:
111
+ """Remove a cached apikey verification from Redis.
112
+
113
+ Call this whenever an API key is created, modified, or deleted so that
114
+ stale cache entries do not allow authentication with an old secret.
115
+
116
+ Args:
117
+ username (str): The authenticating username.
118
+ key_name (str): The name portion of the apikey.
119
+ """
120
+ retry_call(redis.delete, _apikey_cache_key(username, key_name))
121
+
33
122
 
34
123
  def _get_token_store(user: str) -> ExpiringSet:
35
124
  """Get an expiring redis set in which to add a token
@@ -169,7 +258,7 @@ def bearer_auth(
169
258
 
170
259
 
171
260
  @capture_span(span_type="authentication")
172
- def validate_apikey(
261
+ def validate_apikey( # noqa: C901
173
262
  username: str, apikey: str, impersonator: Optional[User] = None
174
263
  ) -> tuple[Optional[User], Optional[list[str]]]:
175
264
  """This function identifies the user via the internal API key functionality.
@@ -214,8 +303,15 @@ def validate_apikey(
214
303
  + "Provide your credentials and supply it in the X-Impersonating header instead."
215
304
  )
216
305
 
306
+ # Check the cache to avoid the expensive bcrypt verification.
307
+ # Key = username:key_name, Value = HMAC-SHA256(username:key_name:secret) via _hash_secret
308
+ if _is_apikey_cached(username, name, apikey_password):
309
+ logger.debug("API key validated from cache for user %s", username)
310
+ return user_data, key.acl
311
+
217
312
  # If the key can be used for whichever purpose, actually validate the secret data
218
313
  if verify_password(apikey_password, key.password):
314
+ _cache_apikey_verification(username, name, apikey_password)
219
315
  return user_data, key.acl
220
316
  except ValueError:
221
317
  pass
@@ -152,7 +152,7 @@ suppress-none-returning = true
152
152
  [tool.poetry]
153
153
  package-mode = true
154
154
  name = "howler-api"
155
- version = "3.2.0.dev532"
155
+ version = "3.2.0.dev554"
156
156
  description = "Howler - API server"
157
157
  authors = [
158
158
  "Canadian Centre for Cyber Security <howler@cyber.gc.ca>",