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.
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/PKG-INFO +1 -1
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/api/v1/auth.py +2 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/config.py +4 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/services/auth_service.py +97 -1
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/pyproject.toml +1 -1
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/README.md +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/__init__.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/actions/__init__.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/actions/add_label.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/actions/add_to_bundle.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/actions/change_field.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/actions/demote.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/actions/example_plugin.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/actions/prioritization.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/actions/promote.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/actions/remove_from_bundle.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/actions/remove_label.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/actions/transition.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/api/__init__.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/api/base.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/api/socket.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/api/v1/__init__.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/api/v1/action.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/api/v1/analytic.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/api/v1/clue.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/api/v1/configs.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/api/v1/dossier.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/api/v1/help.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/api/v1/hit.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/api/v1/notebook.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/api/v1/overview.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/api/v1/search.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/api/v1/template.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/api/v1/tool.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/api/v1/user.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/api/v1/utils/__init__.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/api/v1/utils/etag.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/api/v1/view.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/app.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/common/README.md +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/common/__init__.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/common/classification.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/common/classification.yml +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/common/exceptions.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/common/loader.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/common/logging/__init__.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/common/logging/audit.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/common/logging/format.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/common/net.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/common/net_static.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/common/random_user.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/common/swagger.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/config.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/cronjobs/__init__.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/cronjobs/retention.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/cronjobs/rules.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/cronjobs/view_cleanup.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/datastore/README.md +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/datastore/__init__.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/datastore/bulk.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/datastore/collection.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/datastore/constants.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/datastore/exceptions.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/datastore/howler_store.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/datastore/migrations/fix_process.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/datastore/operations.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/datastore/schemas.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/datastore/store.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/datastore/support/__init__.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/datastore/support/build.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/datastore/support/schemas.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/datastore/types.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/error.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/external/__init__.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/external/generate_mitre.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/external/generate_sigma_rules.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/external/generate_tlds.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/external/reindex_data.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/external/wipe_databases.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/gunicorn_config.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/healthz.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/helper/__init__.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/helper/azure.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/helper/discover.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/helper/hit.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/helper/oauth.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/helper/search.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/helper/workflow.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/helper/ws.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/README.md +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/__init__.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/base.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/charter.txt +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/helper.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/howler_enum.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/__init__.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/action.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/analytic.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/assemblyline.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/aws.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/azure.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/cbs.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/clue.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/dossier.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/__init__.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/agent.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/autonomous_system.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/client.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/cloud.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/code_signature.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/container.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/dns.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/egress.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/elf.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/email.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/error.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/event.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/faas.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/file.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/geo.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/group.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/hash.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/host.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/http.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/ingress.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/interface.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/network.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/observer.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/organization.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/os.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/pe.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/process.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/registry.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/related.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/rule.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/server.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/threat.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/tls.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/url.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/user.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/user_agent.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/vulnerability.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/gcp.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/hit.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/howler_data.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/lead.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/localized_label.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/overview.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/pivot.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/template.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/user.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/view.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/random_data.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/randomizer.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/patched.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/plugins/__init__.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/plugins/config.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/remote/__init__.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/remote/datatypes/README.md +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/remote/datatypes/__init__.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/remote/datatypes/counters.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/remote/datatypes/events.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/remote/datatypes/hash.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/remote/datatypes/lock.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/remote/datatypes/queues/__init__.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/remote/datatypes/queues/comms.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/remote/datatypes/queues/multi.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/remote/datatypes/queues/named.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/remote/datatypes/queues/priority.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/remote/datatypes/set.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/remote/datatypes/user_quota_tracker.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/security/__init__.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/security/socket.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/security/utils.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/services/__init__.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/services/action_service.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/services/analytic_service.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/services/config_service.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/services/dossier_service.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/services/event_service.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/services/hit_service.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/services/jwt_service.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/services/lucene_service.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/services/notebook_service.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/services/overview_service.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/services/template_service.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/services/user_service.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/utils/__init__.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/utils/annotations.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/utils/chunk.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/utils/dict_utils.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/utils/isotime.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/utils/list_utils.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/utils/lucene.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/utils/path.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/utils/socket_utils.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/utils/str_utils.py +0 -0
- {howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/utils/uid.py +0 -0
|
@@ -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.
|
|
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>",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/datastore/migrations/fix_process.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/odm/models/ecs/autonomous_system.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/remote/datatypes/queues/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/remote/datatypes/queues/priority.py
RENAMED
|
File without changes
|
|
File without changes
|
{howler_api-3.2.0.dev532 → howler_api-3.2.0.dev554}/howler/remote/datatypes/user_quota_tracker.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|