howler-api 3.2.0.dev561__tar.gz → 3.2.0.dev576__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.dev561 → howler_api-3.2.0.dev576}/PKG-INFO +1 -1
  2. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/datastore/types.py +7 -1
  3. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/config.py +6 -0
  4. howler_api-3.2.0.dev576/howler/remote/datatypes/__init__.py +157 -0
  5. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/remote/datatypes/events.py +8 -8
  6. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/remote/datatypes/hash.py +5 -3
  7. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/remote/datatypes/lock.py +3 -1
  8. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/remote/datatypes/queues/multi.py +2 -1
  9. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/remote/datatypes/queues/named.py +2 -2
  10. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/remote/datatypes/queues/priority.py +2 -2
  11. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/remote/datatypes/set.py +2 -1
  12. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/remote/datatypes/user_quota_tracker.py +3 -1
  13. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/pyproject.toml +2 -2
  14. howler_api-3.2.0.dev561/howler/remote/datatypes/__init__.py +0 -98
  15. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/README.md +0 -0
  16. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/__init__.py +0 -0
  17. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/actions/__init__.py +0 -0
  18. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/actions/add_label.py +0 -0
  19. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/actions/add_to_bundle.py +0 -0
  20. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/actions/change_field.py +0 -0
  21. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/actions/demote.py +0 -0
  22. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/actions/example_plugin.py +0 -0
  23. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/actions/prioritization.py +0 -0
  24. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/actions/promote.py +0 -0
  25. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/actions/remove_from_bundle.py +0 -0
  26. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/actions/remove_label.py +0 -0
  27. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/actions/transition.py +0 -0
  28. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/api/__init__.py +0 -0
  29. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/api/base.py +0 -0
  30. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/api/socket.py +0 -0
  31. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/api/v1/__init__.py +0 -0
  32. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/api/v1/action.py +0 -0
  33. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/api/v1/analytic.py +0 -0
  34. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/api/v1/auth.py +0 -0
  35. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/api/v1/clue.py +0 -0
  36. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/api/v1/configs.py +0 -0
  37. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/api/v1/dossier.py +0 -0
  38. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/api/v1/help.py +0 -0
  39. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/api/v1/hit.py +0 -0
  40. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/api/v1/notebook.py +0 -0
  41. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/api/v1/overview.py +0 -0
  42. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/api/v1/search.py +0 -0
  43. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/api/v1/template.py +0 -0
  44. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/api/v1/tool.py +0 -0
  45. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/api/v1/user.py +0 -0
  46. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/api/v1/utils/__init__.py +0 -0
  47. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/api/v1/utils/etag.py +0 -0
  48. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/api/v1/view.py +0 -0
  49. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/app.py +0 -0
  50. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/common/README.md +0 -0
  51. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/common/__init__.py +0 -0
  52. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/common/classification.py +0 -0
  53. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/common/classification.yml +0 -0
  54. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/common/exceptions.py +0 -0
  55. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/common/loader.py +0 -0
  56. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/common/logging/__init__.py +0 -0
  57. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/common/logging/audit.py +0 -0
  58. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/common/logging/format.py +0 -0
  59. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/common/net.py +0 -0
  60. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/common/net_static.py +0 -0
  61. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/common/random_user.py +0 -0
  62. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/common/swagger.py +0 -0
  63. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/config.py +0 -0
  64. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/cronjobs/__init__.py +0 -0
  65. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/cronjobs/retention.py +0 -0
  66. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/cronjobs/rules.py +0 -0
  67. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/cronjobs/view_cleanup.py +0 -0
  68. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/datastore/README.md +0 -0
  69. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/datastore/__init__.py +0 -0
  70. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/datastore/bulk.py +0 -0
  71. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/datastore/collection.py +0 -0
  72. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/datastore/constants.py +0 -0
  73. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/datastore/exceptions.py +0 -0
  74. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/datastore/howler_store.py +0 -0
  75. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/datastore/migrations/fix_process.py +0 -0
  76. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/datastore/operations.py +0 -0
  77. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/datastore/schemas.py +0 -0
  78. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/datastore/store.py +0 -0
  79. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/datastore/support/__init__.py +0 -0
  80. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/datastore/support/build.py +0 -0
  81. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/datastore/support/schemas.py +0 -0
  82. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/error.py +0 -0
  83. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/external/__init__.py +0 -0
  84. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/external/generate_mitre.py +0 -0
  85. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/external/generate_sigma_rules.py +0 -0
  86. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/external/generate_tlds.py +0 -0
  87. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/external/reindex_data.py +0 -0
  88. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/external/wipe_databases.py +0 -0
  89. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/gunicorn_config.py +0 -0
  90. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/healthz.py +0 -0
  91. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/helper/__init__.py +0 -0
  92. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/helper/azure.py +0 -0
  93. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/helper/discover.py +0 -0
  94. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/helper/hit.py +0 -0
  95. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/helper/oauth.py +0 -0
  96. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/helper/search.py +0 -0
  97. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/helper/workflow.py +0 -0
  98. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/helper/ws.py +0 -0
  99. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/README.md +0 -0
  100. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/__init__.py +0 -0
  101. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/base.py +0 -0
  102. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/charter.txt +0 -0
  103. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/helper.py +0 -0
  104. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/howler_enum.py +0 -0
  105. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/__init__.py +0 -0
  106. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/action.py +0 -0
  107. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/analytic.py +0 -0
  108. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/assemblyline.py +0 -0
  109. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/aws.py +0 -0
  110. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/azure.py +0 -0
  111. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/cbs.py +0 -0
  112. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/clue.py +0 -0
  113. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/dossier.py +0 -0
  114. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/ecs/__init__.py +0 -0
  115. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/ecs/agent.py +0 -0
  116. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/ecs/autonomous_system.py +0 -0
  117. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/ecs/client.py +0 -0
  118. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/ecs/cloud.py +0 -0
  119. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/ecs/code_signature.py +0 -0
  120. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/ecs/container.py +0 -0
  121. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/ecs/dns.py +0 -0
  122. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/ecs/egress.py +0 -0
  123. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/ecs/elf.py +0 -0
  124. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/ecs/email.py +0 -0
  125. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/ecs/error.py +0 -0
  126. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/ecs/event.py +0 -0
  127. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/ecs/faas.py +0 -0
  128. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/ecs/file.py +0 -0
  129. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/ecs/geo.py +0 -0
  130. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/ecs/group.py +0 -0
  131. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/ecs/hash.py +0 -0
  132. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/ecs/host.py +0 -0
  133. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/ecs/http.py +0 -0
  134. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/ecs/ingress.py +0 -0
  135. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/ecs/interface.py +0 -0
  136. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/ecs/network.py +0 -0
  137. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/ecs/observer.py +0 -0
  138. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/ecs/organization.py +0 -0
  139. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/ecs/os.py +0 -0
  140. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/ecs/pe.py +0 -0
  141. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/ecs/process.py +0 -0
  142. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/ecs/registry.py +0 -0
  143. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/ecs/related.py +0 -0
  144. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/ecs/rule.py +0 -0
  145. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/ecs/server.py +0 -0
  146. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/ecs/threat.py +0 -0
  147. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/ecs/tls.py +0 -0
  148. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/ecs/url.py +0 -0
  149. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/ecs/user.py +0 -0
  150. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/ecs/user_agent.py +0 -0
  151. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/ecs/vulnerability.py +0 -0
  152. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/gcp.py +0 -0
  153. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/hit.py +0 -0
  154. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/howler_data.py +0 -0
  155. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/lead.py +0 -0
  156. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/localized_label.py +0 -0
  157. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/overview.py +0 -0
  158. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/pivot.py +0 -0
  159. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/template.py +0 -0
  160. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/user.py +0 -0
  161. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/models/view.py +0 -0
  162. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/random_data.py +0 -0
  163. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/odm/randomizer.py +0 -0
  164. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/patched.py +0 -0
  165. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/plugins/__init__.py +0 -0
  166. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/plugins/config.py +0 -0
  167. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/remote/__init__.py +0 -0
  168. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/remote/datatypes/README.md +0 -0
  169. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/remote/datatypes/counters.py +0 -0
  170. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/remote/datatypes/queues/__init__.py +0 -0
  171. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/remote/datatypes/queues/comms.py +0 -0
  172. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/security/__init__.py +0 -0
  173. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/security/socket.py +0 -0
  174. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/security/utils.py +0 -0
  175. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/services/__init__.py +0 -0
  176. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/services/action_service.py +0 -0
  177. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/services/analytic_service.py +0 -0
  178. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/services/auth_service.py +0 -0
  179. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/services/config_service.py +0 -0
  180. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/services/dossier_service.py +0 -0
  181. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/services/event_service.py +0 -0
  182. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/services/hit_service.py +0 -0
  183. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/services/jwt_service.py +0 -0
  184. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/services/lucene_service.py +0 -0
  185. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/services/notebook_service.py +0 -0
  186. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/services/overview_service.py +0 -0
  187. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/services/template_service.py +0 -0
  188. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/services/user_service.py +0 -0
  189. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/utils/__init__.py +0 -0
  190. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/utils/annotations.py +0 -0
  191. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/utils/chunk.py +0 -0
  192. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/utils/dict_utils.py +0 -0
  193. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/utils/isotime.py +0 -0
  194. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/utils/list_utils.py +0 -0
  195. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/utils/lucene.py +0 -0
  196. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/utils/path.py +0 -0
  197. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/utils/socket_utils.py +0 -0
  198. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/howler/utils/str_utils.py +0 -0
  199. {howler_api-3.2.0.dev561 → howler_api-3.2.0.dev576}/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.dev561
3
+ Version: 3.2.0.dev576
4
4
  Summary: Howler - API server
5
5
  License: MIT
6
6
  Keywords: howler,alerting,gc,canada,cse-cst,cse,cst,cyber,cccs
@@ -1,4 +1,10 @@
1
- from typing import Generic, NotRequired, TypedDict, TypeVar
1
+ import sys
2
+ from typing import Generic, TypedDict, TypeVar
3
+
4
+ if sys.version_info >= (3, 11):
5
+ from typing import NotRequired
6
+ else:
7
+ from typing_extensions import NotRequired
2
8
 
3
9
  SearchResultType = TypeVar("SearchResultType")
4
10
 
@@ -28,6 +28,12 @@ class RedisServer(BaseModel):
28
28
 
29
29
  host: str = Field(description="Hostname of Redis instance")
30
30
  port: int = Field(description="Port of Redis instance")
31
+ password: Optional[str] = Field(description="Password for Redis instance", default=None)
32
+ tls_enabled: bool = Field(default=False, description="Enable TLS for Redis connection")
33
+ tls_ca_cert: Optional[str] = Field(
34
+ description="Path to CA Certificate (PEM) to validate Redis instance certificate when using TLS", default=None
35
+ )
36
+ is_cluster: bool = Field(default=False, description="Is this Redis instance a cluster?")
31
37
 
32
38
 
33
39
  class Redis(BaseModel):
@@ -0,0 +1,157 @@
1
+ #!/usr/bin/env python
2
+
3
+ import json
4
+ import logging
5
+ import time
6
+ from datetime import datetime
7
+ from pathlib import Path
8
+
9
+ import redis
10
+ from packaging.version import parse
11
+
12
+ from howler.common import loader
13
+ from howler.odm.models.config import config
14
+ from howler.utils.uid import get_random_id
15
+
16
+ # Add a version warning if redis python client is < 2.10.0. Older versions
17
+ # have a connection bug that can manifest with the dispatcher.
18
+ if parse(redis.__version__) <= parse("2.10.0"):
19
+ import warnings
20
+
21
+ warnings.warn(
22
+ "%s works best with redis > 2.10.0. You're running"
23
+ " redis %s. You should upgrade." % (__name__, redis.__version__)
24
+ )
25
+
26
+
27
+ log = logging.getLogger(f"{loader.APP_NAME}.queue")
28
+ pool: dict[tuple[str, str, bool], redis.BlockingConnectionPool] = {}
29
+
30
+
31
+ def now_as_iso():
32
+ s = datetime.utcfromtimestamp(time.time()).isoformat()
33
+ return f"{s}Z"
34
+
35
+
36
+ def reply_queue_name(prefix=None, suffix=None):
37
+ if prefix:
38
+ components = [prefix]
39
+ else:
40
+ components = []
41
+
42
+ components.append(get_random_id())
43
+
44
+ if suffix:
45
+ components.append(str(suffix))
46
+
47
+ return "-".join(components)
48
+
49
+
50
+ def retry_call(func, *args, **kw):
51
+ maximum = 2
52
+ exponent = -7
53
+
54
+ while True:
55
+ try:
56
+ ret_val = func(*args, **kw)
57
+
58
+ if exponent != -7:
59
+ log.info("Reconnected to Redis!")
60
+
61
+ return ret_val
62
+ except (redis.ConnectionError, ConnectionResetError) as ce:
63
+ log.warning(f"No connection to Redis, reconnecting... [{ce}]")
64
+ time.sleep(2**exponent)
65
+ exponent = exponent + 1 if exponent < maximum else exponent
66
+
67
+
68
+ def get_client(
69
+ host: str | redis.Redis | redis.StrictRedis | redis.RedisCluster | None, port: int | None, private: bool = False
70
+ ):
71
+ """
72
+ Get Redis instance.
73
+
74
+ Args:
75
+ host: Redis host, defaults to nonpersistent host
76
+ port: Redis port, defaults to nonpersistent port
77
+ private: If true then use standard connection, otherwise use a Pool
78
+
79
+ Returns:
80
+ Redis instance
81
+ """
82
+ # In case a structure is passed a client as host
83
+ if isinstance(host, (redis.Redis, redis.StrictRedis, redis.RedisCluster)):
84
+ return host
85
+
86
+ if not host or not port:
87
+ host = host or config.core.redis.nonpersistent.host
88
+ port = int(port or config.core.redis.nonpersistent.port)
89
+
90
+ extra_conn_config: dict[str, str | bool | int] = {}
91
+ host_config = None
92
+
93
+ if host == config.core.redis.nonpersistent.host and port == config.core.redis.nonpersistent.port:
94
+ host_config = config.core.redis.nonpersistent
95
+ else:
96
+ host_config = config.core.redis.persistent
97
+
98
+ if host_config.password:
99
+ extra_conn_config["username"] = "default"
100
+ extra_conn_config["password"] = host_config.password
101
+
102
+ if host_config.tls_enabled:
103
+ extra_conn_config["ssl"] = True
104
+ extra_conn_config["ssl_cert_reqs"] = "required"
105
+
106
+ if host_config.tls_ca_cert:
107
+ if not Path(host_config.tls_ca_cert).exists():
108
+ raise FileNotFoundError(f"Redis TLS CA cert or path '{host_config.tls_ca_cert}' not found.")
109
+
110
+ if Path(host_config.tls_ca_cert).is_file():
111
+ extra_conn_config["ssl_ca_certs"] = host_config.tls_ca_cert
112
+ else:
113
+ extra_conn_config["ssl_ca_path"] = host_config.tls_ca_cert
114
+
115
+ if host_config.is_cluster is True:
116
+ return redis.RedisCluster(host=host, port=port, **extra_conn_config) # type: ignore
117
+
118
+ if private:
119
+ return redis.StrictRedis(host=host, port=port, **extra_conn_config) # type: ignore
120
+ else:
121
+ return redis.StrictRedis(connection_pool=get_pool(host, port, **extra_conn_config))
122
+
123
+
124
+ def get_pool(host, port, **kwargs):
125
+ """
126
+ Get Redis connection pool
127
+ Args:
128
+ host: Redis host
129
+ port: Redis port
130
+ **kwargs: Extra parameters to pass to pool connection class
131
+
132
+ Returns:
133
+ Redis BlockingConnectionPool
134
+ """
135
+ key = (host, str(port), kwargs.get("ssl", False))
136
+ connection_pool = pool.get(key, None)
137
+
138
+ if not connection_pool:
139
+ if "ssl" in kwargs and kwargs["ssl"]:
140
+ # SSLConnection class doesn't accept 'ssl' parameter as it implicitly uses SSL
141
+ kwargs.pop("ssl")
142
+ connection_pool = redis.BlockingConnectionPool(
143
+ host=host, port=port, max_connections=200, connection_class=redis.SSLConnection, **kwargs
144
+ )
145
+ else:
146
+ connection_pool = redis.BlockingConnectionPool(host=host, port=port, max_connections=200, **kwargs)
147
+ pool[key] = connection_pool
148
+
149
+ return connection_pool
150
+
151
+
152
+ def decode(data):
153
+ try:
154
+ return json.loads(data)
155
+ except ValueError:
156
+ log.warning("Invalid data on queue: %s", str(data))
157
+ return None
@@ -8,7 +8,7 @@ from howler.common.logging import get_logger
8
8
  from howler.remote.datatypes import get_client, retry_call
9
9
 
10
10
  if TYPE_CHECKING:
11
- from redis import Redis
11
+ pass
12
12
 
13
13
 
14
14
  logger = get_logger(__name__)
@@ -21,12 +21,12 @@ class EventSender(Generic[MessageType]):
21
21
  def __init__(
22
22
  self,
23
23
  prefix: str,
24
- host=None,
25
- port=None,
26
- private=None,
24
+ host: str | None = None,
25
+ port: int | None = None,
26
+ private: bool | None = None,
27
27
  serializer: Callable[[MessageType], str] = json.dumps,
28
28
  ):
29
- self.client: Redis[Any] = get_client(host, port, private)
29
+ self.client = get_client(host, port, bool(private))
30
30
  self.prefix = prefix.lower()
31
31
  if not self.prefix.endswith("."):
32
32
  self.prefix += "."
@@ -40,12 +40,12 @@ class EventSender(Generic[MessageType]):
40
40
  class EventWatcher(Generic[MessageType]):
41
41
  def __init__(
42
42
  self,
43
- host=None,
44
- port=None,
43
+ host: str | None = None,
44
+ port: int | None = None,
45
45
  private=None,
46
46
  deserializer: Callable[[str], MessageType] = json.loads,
47
47
  ):
48
- client: Redis[Any] = get_client(host, port, private)
48
+ client = get_client(host, port, bool(private))
49
49
  self.pubsub = retry_call(client.pubsub)
50
50
  self.worker: Optional[threading.Thread] = None
51
51
  self.deserializer = deserializer
@@ -2,7 +2,9 @@ from __future__ import annotations
2
2
 
3
3
  import json
4
4
  import time
5
- from typing import TYPE_CHECKING, Generic, Optional, TypeVar, Union
5
+ from typing import TYPE_CHECKING, Any, Generic, Optional, TypeVar
6
+
7
+ from redis import RedisCluster
6
8
 
7
9
  from howler.common.exceptions import HowlerValueError
8
10
  from howler.remote.datatypes import get_client, retry_call
@@ -71,10 +73,10 @@ class Hash(Generic[T]):
71
73
  def __init__(
72
74
  self,
73
75
  name: str,
74
- host: Optional[Union[str, Redis]] = None,
76
+ host: str | Redis[Any] | RedisCluster[Any] | None = None,
75
77
  port: Optional[int] = None,
76
78
  ):
77
- self.c = get_client(host, port, False)
79
+ self.c: Any = get_client(host, port, False)
78
80
  self.name = name
79
81
  self._pop = self.c.register_script(h_pop_script)
80
82
  self._limited_add = self.c.register_script(_limited_add)
@@ -1,3 +1,5 @@
1
+ from typing import Any
2
+
1
3
  from howler.remote.datatypes import get_client, retry_call
2
4
  from howler.utils.uid import get_random_id
3
5
 
@@ -27,7 +29,7 @@ end
27
29
  class Lock(object):
28
30
  def __init__(self, name, timeout, host=None, port=None):
29
31
  self.uuid = get_random_id()
30
- self.c = get_client(host, port, False)
32
+ self.c: Any = get_client(host, port, False)
31
33
  self.lock_release = "-".join(("lock", str(timeout), name, "released"))
32
34
  self.lock_holder = "-".join(("lock", str(timeout), name, "holder"))
33
35
  self.timeout = timeout
@@ -1,11 +1,12 @@
1
1
  import json
2
+ from typing import Any
2
3
 
3
4
  from howler.remote.datatypes import get_client, retry_call
4
5
 
5
6
 
6
7
  class MultiQueue(object):
7
8
  def __init__(self, host=None, port=None, private=False):
8
- self.c = get_client(host, port, private)
9
+ self.c: Any = get_client(host, port, private)
9
10
 
10
11
  def delete(self, name):
11
12
  retry_call(self.c.delete, name)
@@ -1,6 +1,6 @@
1
1
  import json
2
2
  import time
3
- from typing import Generic, Optional, TypeVar
3
+ from typing import Any, Generic, Optional, TypeVar
4
4
 
5
5
  from howler.common.exceptions import HowlerTypeError
6
6
  from howler.remote.datatypes import get_client, retry_call
@@ -10,7 +10,7 @@ T = TypeVar("T")
10
10
 
11
11
  class NamedQueue(Generic[T]):
12
12
  def __init__(self, name: str, host=None, port=None, private: bool = False, ttl: int = 0):
13
- self.c = get_client(host, port, private)
13
+ self.c: Any = get_client(host, port, private)
14
14
  self.name: str = name
15
15
  self.ttl: int = ttl
16
16
  self.last_expire_time: float = 0
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import json
4
4
  import time
5
- from typing import Generic, Optional, TypeVar, Union
5
+ from typing import Any, Generic, Optional, TypeVar, Union
6
6
 
7
7
  from howler.common.exceptions import HowlerTypeError
8
8
  from howler.remote.datatypes import decode, get_client, retry_call
@@ -36,7 +36,7 @@ T = TypeVar("T")
36
36
 
37
37
  class PriorityQueue(Generic[T]):
38
38
  def __init__(self, name, host=None, port=None, private=False):
39
- self.c = get_client(host, port, private)
39
+ self.c: Any = get_client(host, port, private)
40
40
  self._deque_range = self.c.register_script(pq_dequeue_range_script)
41
41
  self.name = name
42
42
 
@@ -1,5 +1,6 @@
1
1
  import json
2
2
  import time
3
+ from typing import Any
3
4
 
4
5
  from howler.remote.datatypes import get_client, retry_call
5
6
 
@@ -26,7 +27,7 @@ return false
26
27
 
27
28
  class Set(object):
28
29
  def __init__(self, name, host=None, port=None):
29
- self.c = get_client(host, port, False)
30
+ self.c: Any = get_client(host, port, False)
30
31
  self.name = name
31
32
  self._drop_card = self.c.register_script(_drop_card_script)
32
33
  self._limited_add = self.c.register_script(_limited_add)
@@ -1,3 +1,5 @@
1
+ from typing import Any
2
+
1
3
  import redis
2
4
 
3
5
  from howler.remote.datatypes import get_client, retry_call
@@ -22,7 +24,7 @@ end
22
24
 
23
25
  class UserQuotaTracker(object):
24
26
  def __init__(self, prefix, timeout=120, redis=None, host=None, port=None, private=False):
25
- self.c = redis or get_client(host, port, private)
27
+ self.c: Any = redis or get_client(host, port, private)
26
28
  self.bs = self.c.register_script(begin_script)
27
29
  self.prefix = prefix
28
30
  self.timeout = timeout
@@ -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.dev561"
155
+ version = "3.2.0.dev576"
156
156
  description = "Howler - API server"
157
157
  authors = [
158
158
  "Canadian Centre for Cyber Security <howler@cyber.gc.ca>",
@@ -240,7 +240,7 @@ mypy = "^1.6.1"
240
240
  pytest = "^8.1.1"
241
241
  retrying = "^1.3.4"
242
242
  pyftpdlib = "^1.5.9"
243
- pyopenssl = "^24.1.0"
243
+ pyopenssl = ">=24.1,<27.0"
244
244
  diff-cover = "^9.2.4"
245
245
  pytest-cov = "^4.1.0"
246
246
  mock = "^5.1.0"
@@ -1,98 +0,0 @@
1
- #!/usr/bin/env python
2
-
3
- import json
4
- import logging
5
- import time
6
- from datetime import datetime
7
-
8
- import redis
9
- from packaging.version import parse
10
-
11
- from howler.common import loader
12
- from howler.odm.models.config import config
13
- from howler.utils.uid import get_random_id
14
-
15
- # Add a version warning if redis python client is < 2.10.0. Older versions
16
- # have a connection bug that can manifest with the dispatcher.
17
- if parse(redis.__version__) <= parse("2.10.0"):
18
- import warnings
19
-
20
- warnings.warn(
21
- "%s works best with redis > 2.10.0. You're running"
22
- " redis %s. You should upgrade." % (__name__, redis.__version__)
23
- )
24
-
25
-
26
- log = logging.getLogger(f"{loader.APP_NAME}.queue")
27
- pool: dict[tuple[str, str], redis.BlockingConnectionPool] = {}
28
-
29
-
30
- def now_as_iso():
31
- s = datetime.utcfromtimestamp(time.time()).isoformat()
32
- return f"{s}Z"
33
-
34
-
35
- def reply_queue_name(prefix=None, suffix=None):
36
- if prefix:
37
- components = [prefix]
38
- else:
39
- components = []
40
-
41
- components.append(get_random_id())
42
-
43
- if suffix:
44
- components.append(str(suffix))
45
-
46
- return "-".join(components)
47
-
48
-
49
- def retry_call(func, *args, **kw):
50
- maximum = 2
51
- exponent = -7
52
-
53
- while True:
54
- try:
55
- ret_val = func(*args, **kw)
56
-
57
- if exponent != -7:
58
- log.info("Reconnected to Redis!")
59
-
60
- return ret_val
61
- except (redis.ConnectionError, ConnectionResetError) as ce:
62
- log.warning(f"No connection to Redis, reconnecting... [{ce}]")
63
- time.sleep(2**exponent)
64
- exponent = exponent + 1 if exponent < maximum else exponent
65
-
66
-
67
- def get_client(host, port, private):
68
- # In case a structure is passed a client as host
69
- if isinstance(host, (redis.Redis, redis.StrictRedis)):
70
- return host
71
-
72
- if not host or not port:
73
- host = host or config.core.redis.nonpersistent.host
74
- port = int(port or config.core.redis.nonpersistent.port)
75
-
76
- if private:
77
- return redis.StrictRedis(host=host, port=port)
78
- else:
79
- return redis.StrictRedis(connection_pool=get_pool(host, port))
80
-
81
-
82
- def get_pool(host, port):
83
- key = (host, port)
84
-
85
- connection_pool = pool.get(key, None)
86
- if not connection_pool:
87
- connection_pool = redis.BlockingConnectionPool(host=host, port=port, max_connections=200)
88
- pool[key] = connection_pool
89
-
90
- return connection_pool
91
-
92
-
93
- def decode(data):
94
- try:
95
- return json.loads(data)
96
- except ValueError:
97
- log.warning("Invalid data on queue: %s", str(data))
98
- return None