howler-api 4.0.0.dev982__tar.gz → 4.0.0.dev1003__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.
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/PKG-INFO +1 -1
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/api/v1/search.py +0 -29
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/api/v1/tool.py +42 -15
- howler_api-4.0.0.dev1003/howler/common/net.py +128 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/datastore/collection.py +250 -19
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/datastore/howler_store.py +2 -1
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/datastore/store.py +12 -3
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/config.py +50 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/pyproject.toml +1 -1
- howler_api-4.0.0.dev982/howler/common/net.py +0 -79
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/README.md +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/__init__.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/actions/__init__.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/actions/add_label.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/actions/add_to_bundle.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/actions/change_field.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/actions/demote.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/actions/example_plugin.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/actions/prioritization.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/actions/promote.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/actions/remove_from_bundle.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/actions/remove_label.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/actions/transition.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/api/__init__.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/api/base.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/api/socket.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/api/v1/__init__.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/api/v1/action.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/api/v1/analytic.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/api/v1/auth.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/api/v1/clue.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/api/v1/configs.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/api/v1/dossier.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/api/v1/help.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/api/v1/hit.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/api/v1/notebook.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/api/v1/overview.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/api/v1/template.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/api/v1/user.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/api/v1/utils/__init__.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/api/v1/utils/etag.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/api/v1/view.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/app.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/common/README.md +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/common/__init__.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/common/classification.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/common/classification.yml +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/common/exceptions.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/common/loader.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/common/logging/__init__.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/common/logging/audit.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/common/logging/format.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/common/net_static.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/common/random_user.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/common/swagger.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/config.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/cronjobs/__init__.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/cronjobs/action_queue_worker.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/cronjobs/retention.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/cronjobs/rules.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/cronjobs/view_cleanup.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/datastore/README.md +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/datastore/__init__.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/datastore/bulk.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/datastore/constants.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/datastore/exceptions.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/datastore/migrations/fix_process.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/datastore/operations.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/datastore/schemas.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/datastore/support/__init__.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/datastore/support/build.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/datastore/support/schemas.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/datastore/types.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/error.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/external/README.md +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/external/__init__.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/external/generate_mitre.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/external/generate_sigma_rules.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/external/generate_tlds.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/external/reindex_data.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/external/wipe_databases.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/gunicorn_config.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/healthz.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/helper/__init__.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/helper/azure.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/helper/discover.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/helper/hit.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/helper/oauth.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/helper/search.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/helper/workflow.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/helper/ws.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/README.md +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/__init__.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/base.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/charter.txt +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/helper.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/howler_enum.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/__init__.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/action.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/analytic.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/assemblyline.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/aws.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/azure.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/cbs.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/clue.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/dossier.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/ecs/__init__.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/ecs/agent.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/ecs/autonomous_system.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/ecs/client.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/ecs/cloud.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/ecs/code_signature.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/ecs/container.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/ecs/dns.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/ecs/egress.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/ecs/elf.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/ecs/email.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/ecs/error.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/ecs/event.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/ecs/faas.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/ecs/file.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/ecs/geo.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/ecs/group.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/ecs/hash.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/ecs/host.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/ecs/http.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/ecs/ingress.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/ecs/interface.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/ecs/network.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/ecs/observer.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/ecs/organization.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/ecs/os.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/ecs/pe.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/ecs/process.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/ecs/registry.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/ecs/related.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/ecs/rule.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/ecs/server.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/ecs/threat.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/ecs/tls.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/ecs/url.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/ecs/user.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/ecs/user_agent.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/ecs/vulnerability.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/gcp.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/hit.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/howler_data.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/lead.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/localized_label.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/overview.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/pivot.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/template.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/user.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/models/view.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/random_data.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/odm/randomizer.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/patched.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/plugins/__init__.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/plugins/config.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/remote/__init__.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/remote/datatypes/README.md +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/remote/datatypes/__init__.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/remote/datatypes/counters.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/remote/datatypes/events.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/remote/datatypes/hash.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/remote/datatypes/lock.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/remote/datatypes/queues/__init__.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/remote/datatypes/queues/comms.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/remote/datatypes/queues/multi.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/remote/datatypes/queues/named.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/remote/datatypes/queues/priority.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/remote/datatypes/set.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/remote/datatypes/user_quota_tracker.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/security/__init__.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/security/socket.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/security/utils.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/services/__init__.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/services/action_service.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/services/analytic_service.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/services/auth_service.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/services/config_service.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/services/dossier_service.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/services/event_service.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/services/hit_service.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/services/jwt_service.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/services/lucene_service.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/services/notebook_service.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/services/overview_service.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/services/template_service.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/services/user_service.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/telemetry.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/utils/__init__.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/utils/annotations.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/utils/chunk.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/utils/compat.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/utils/constants.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/utils/dict_utils.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/utils/isotime.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/utils/list_utils.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/utils/lucene.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/utils/path.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/utils/socket_utils.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/utils/str_utils.py +0 -0
- {howler_api-4.0.0.dev982 → howler_api-4.0.0.dev1003}/howler/utils/uid.py +0 -0
|
@@ -78,7 +78,6 @@ def search(index, **kwargs):
|
|
|
78
78
|
sort => How to sort the results (not available in deep paging)
|
|
79
79
|
fl => List of fields to return
|
|
80
80
|
timeout => Maximum execution time (ms)
|
|
81
|
-
use_archive => Allow access to the datastore achive (Default: False)
|
|
82
81
|
track_total_hits => Track the total number of query matches, instead of stopping at 10000 (Default: False)
|
|
83
82
|
metadata => A list of additional features to be added to the result alongside the raw results
|
|
84
83
|
|
|
@@ -118,18 +117,9 @@ def search(index, **kwargs):
|
|
|
118
117
|
"track_total_hits",
|
|
119
118
|
]
|
|
120
119
|
multi_fields = ["filters", "metadata"]
|
|
121
|
-
boolean_fields = ["use_archive"]
|
|
122
120
|
|
|
123
121
|
params, req_data = generate_params(request, fields, multi_fields)
|
|
124
122
|
|
|
125
|
-
params.update(
|
|
126
|
-
{
|
|
127
|
-
k: str(req_data.get(k, "false")).lower() in ["true", ""]
|
|
128
|
-
for k in boolean_fields
|
|
129
|
-
if req_data.get(k, None) is not None
|
|
130
|
-
}
|
|
131
|
-
)
|
|
132
|
-
|
|
133
123
|
if has_access_control(index):
|
|
134
124
|
params.update({"access_control": user["access_control"]})
|
|
135
125
|
|
|
@@ -350,18 +340,9 @@ def sigma_search(index, **kwargs):
|
|
|
350
340
|
"track_total_hits",
|
|
351
341
|
]
|
|
352
342
|
multi_fields = ["filters"]
|
|
353
|
-
boolean_fields = ["use_archive"]
|
|
354
343
|
|
|
355
344
|
params, req_data = generate_params(request, fields, multi_fields)
|
|
356
345
|
|
|
357
|
-
params.update(
|
|
358
|
-
{
|
|
359
|
-
k: str(req_data.get(k, "false")).lower() in ["true", ""]
|
|
360
|
-
for k in boolean_fields
|
|
361
|
-
if req_data.get(k, None) is not None
|
|
362
|
-
}
|
|
363
|
-
)
|
|
364
|
-
|
|
365
346
|
if has_access_control(index):
|
|
366
347
|
params.update({"access_control": user["access_control"]})
|
|
367
348
|
|
|
@@ -520,7 +501,6 @@ def count(index, **kwargs):
|
|
|
520
501
|
Optional Arguments:
|
|
521
502
|
filters => List of additional filter queries limit the data
|
|
522
503
|
timeout => Maximum execution time (ms)
|
|
523
|
-
use_archive => Allow access to the datastore achive (Default: False)
|
|
524
504
|
|
|
525
505
|
Data Block:
|
|
526
506
|
# Note that the data block is for POST requests only!
|
|
@@ -543,15 +523,6 @@ def count(index, **kwargs):
|
|
|
543
523
|
|
|
544
524
|
params, req_data = generate_params(request, [], [])
|
|
545
525
|
|
|
546
|
-
boolean_fields = ["use_archive"]
|
|
547
|
-
params.update(
|
|
548
|
-
{
|
|
549
|
-
k: str(req_data.get(k, "false")).lower() in ["true", ""]
|
|
550
|
-
for k in boolean_fields
|
|
551
|
-
if req_data.get(k, None) is not None
|
|
552
|
-
}
|
|
553
|
-
)
|
|
554
|
-
|
|
555
526
|
if has_access_control(index):
|
|
556
527
|
params.update({"access_control": user["access_control"]})
|
|
557
528
|
|
|
@@ -59,6 +59,9 @@ def create_one_or_many_hits(tool_name: str, user: User, **kwargs): # noqa: C901
|
|
|
59
59
|
{'id': None, 'error': "Error message"},
|
|
60
60
|
]
|
|
61
61
|
}
|
|
62
|
+
|
|
63
|
+
.. deprecated::
|
|
64
|
+
Use POST /api/v1/hit/ directly with pre-mapped hit data instead.
|
|
62
65
|
"""
|
|
63
66
|
data = request.json
|
|
64
67
|
if not isinstance(data, dict):
|
|
@@ -74,7 +77,10 @@ def create_one_or_many_hits(tool_name: str, user: User, **kwargs): # noqa: C901
|
|
|
74
77
|
|
|
75
78
|
if not isinstance(hits, list):
|
|
76
79
|
return bad_request(err="Invalid: 'hits' field is missing or invalid.")
|
|
77
|
-
warnings = [
|
|
80
|
+
warnings = [
|
|
81
|
+
"This endpoint is deprecated and will be removed in a future version. "
|
|
82
|
+
"Use POST /api/v1/hit/ directly with pre-mapped hit data instead."
|
|
83
|
+
]
|
|
78
84
|
# Validate field_map targets
|
|
79
85
|
hit_fields = Hit.flat_fields()
|
|
80
86
|
for targets in field_map.values():
|
|
@@ -157,27 +163,48 @@ def create_one_or_many_hits(tool_name: str, user: User, **kwargs): # noqa: C901
|
|
|
157
163
|
logger.warning(e)
|
|
158
164
|
|
|
159
165
|
out.append({"id": None, "error": str(e)})
|
|
166
|
+
|
|
167
|
+
# Deduplicate by hash: skip hits whose hash already exists in the datastore
|
|
168
|
+
if odms:
|
|
169
|
+
hashes = [odm.howler.hash for odm in odms]
|
|
170
|
+
existing_hashes: dict[str, int] = datastore().hit.facet(
|
|
171
|
+
"howler.hash",
|
|
172
|
+
query=f"howler.hash:({' OR '.join(hashes)})",
|
|
173
|
+
rows=len(hashes),
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
deduplicated_odms = []
|
|
177
|
+
for odm in odms:
|
|
178
|
+
if odm.howler.hash in existing_hashes:
|
|
179
|
+
logger.warning("Hit with hash %s already exists in the DB, skipping", odm.howler.hash)
|
|
180
|
+
warnings.append(f"Hit with hash {odm.howler.hash} already exists in the DB and was skipped.")
|
|
181
|
+
out[:] = [entry for entry in out if entry["id"] != odm.howler.id]
|
|
182
|
+
else:
|
|
183
|
+
deduplicated_odms.append(odm)
|
|
184
|
+
|
|
185
|
+
odms = deduplicated_odms
|
|
186
|
+
|
|
160
187
|
# If there are any errors...
|
|
161
188
|
if any([obj["error"] for obj in out]):
|
|
162
189
|
return bad_request(out, warnings=warnings, err="No valid hits were provided")
|
|
163
|
-
else:
|
|
164
|
-
for odm in odms:
|
|
165
|
-
if bundle_hit is not None:
|
|
166
|
-
bundle_hit.howler.hits.append(odm.howler.id)
|
|
167
|
-
bundle_hit.howler.bundle_size += 1
|
|
168
|
-
odm.howler.bundles.append(bundle_hit.howler.id)
|
|
169
190
|
|
|
170
|
-
|
|
191
|
+
for odm in odms:
|
|
192
|
+
if bundle_hit is not None:
|
|
193
|
+
bundle_hit.howler.hits.append(odm.howler.id)
|
|
194
|
+
bundle_hit.howler.bundle_size += 1
|
|
195
|
+
odm.howler.bundles.append(bundle_hit.howler.id)
|
|
196
|
+
|
|
197
|
+
hit_service.create_hit(odm.howler.id, odm, user=user.uname)
|
|
171
198
|
|
|
172
|
-
|
|
199
|
+
analytic_service.save_from_hit(odm, user)
|
|
173
200
|
|
|
174
|
-
|
|
175
|
-
|
|
201
|
+
if bundle_hit:
|
|
202
|
+
hit_service.create_hit(bundle_hit.howler.id, bundle_hit, user=user.uname)
|
|
176
203
|
|
|
177
|
-
|
|
204
|
+
analytic_service.save_from_hit(bundle_hit, user)
|
|
178
205
|
|
|
179
|
-
|
|
206
|
+
datastore().hit.commit()
|
|
180
207
|
|
|
181
|
-
|
|
208
|
+
action_service.enqueue_action_execution([entry["id"] for entry in out], trigger="create", user=user)
|
|
182
209
|
|
|
183
|
-
|
|
210
|
+
return created(out, warnings=warnings)
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import socket
|
|
2
|
+
import uuid
|
|
3
|
+
from ipaddress import IPv4Network, ip_address
|
|
4
|
+
from typing import Union
|
|
5
|
+
|
|
6
|
+
from howler.common.net_static import TLDS_ALPHA_BY_DOMAIN
|
|
7
|
+
|
|
8
|
+
# IANA Special-Use Domain Names Registry
|
|
9
|
+
# https://www.iana.org/assignments/special-use-domain-names/special-use-domain-names.xhtml
|
|
10
|
+
IANA_SPECIAL_USE_TLDS = {
|
|
11
|
+
"LOCALHOST", # RFC 6761 - loopback address
|
|
12
|
+
"TEST", # RFC 6761 - testing
|
|
13
|
+
"EXAMPLE", # RFC 6761 - documentation examples
|
|
14
|
+
"INVALID", # RFC 6761 - invalid domain names
|
|
15
|
+
"LOCAL", # RFC 6762 - mDNS/Bonjour local network names
|
|
16
|
+
"ONION", # RFC 7686 - Tor hidden services
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
# Common private network suffixes used in enterprise environments
|
|
20
|
+
# These are NOT IANA-registered but are widely used organizational conventions
|
|
21
|
+
PRIVATE_NETWORK_SUFFIXES = {
|
|
22
|
+
"INTERNAL",
|
|
23
|
+
"LAN",
|
|
24
|
+
"HOME",
|
|
25
|
+
"CORP",
|
|
26
|
+
"LOCALDOMAIN",
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def is_valid_port(value: Union[int, str, float]) -> bool:
|
|
31
|
+
"Check if a port is valid"
|
|
32
|
+
try:
|
|
33
|
+
if 1 <= int(value) <= 65535:
|
|
34
|
+
return True
|
|
35
|
+
except ValueError:
|
|
36
|
+
pass
|
|
37
|
+
|
|
38
|
+
return False
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def is_valid_domain(
|
|
42
|
+
domain: str,
|
|
43
|
+
allow_special_use_tlds: bool = True,
|
|
44
|
+
allow_private_suffixes: bool = True,
|
|
45
|
+
) -> bool:
|
|
46
|
+
"""Check if a domain is valid.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
domain: The domain to validate.
|
|
50
|
+
allow_special_use_tlds: If True, accepts IANA special-use TLDs
|
|
51
|
+
(.localhost, .local, .onion, .test, .example, .invalid).
|
|
52
|
+
Set to False to reject these domains.
|
|
53
|
+
Defaults to True for backward compatibility.
|
|
54
|
+
allow_private_suffixes: If True, accepts common private network suffixes
|
|
55
|
+
(.internal, .lan, .home, .corp, .localdomain).
|
|
56
|
+
Set to False to reject these domains.
|
|
57
|
+
Defaults to True for backward compatibility.
|
|
58
|
+
|
|
59
|
+
Note:
|
|
60
|
+
To validate public internet domains only (e.g., for SSRF protection),
|
|
61
|
+
set both allow_special_use_tlds=False and allow_private_suffixes=False.
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
True if the domain has a valid TLD, False otherwise.
|
|
65
|
+
"""
|
|
66
|
+
if "@" in domain:
|
|
67
|
+
return False
|
|
68
|
+
|
|
69
|
+
if "." in domain:
|
|
70
|
+
tld = domain.split(".")[-1].upper()
|
|
71
|
+
if tld in TLDS_ALPHA_BY_DOMAIN:
|
|
72
|
+
return True
|
|
73
|
+
if allow_special_use_tlds and tld in IANA_SPECIAL_USE_TLDS:
|
|
74
|
+
return True
|
|
75
|
+
if allow_private_suffixes and tld in PRIVATE_NETWORK_SUFFIXES:
|
|
76
|
+
return True
|
|
77
|
+
|
|
78
|
+
return False
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def is_valid_ip(ip: str) -> bool:
|
|
82
|
+
"Check if an ip is valid"
|
|
83
|
+
parts = ip.split(".")
|
|
84
|
+
if len(parts) == 4:
|
|
85
|
+
for p in parts:
|
|
86
|
+
try:
|
|
87
|
+
if not (0 <= int(p) <= 255):
|
|
88
|
+
return False
|
|
89
|
+
except ValueError:
|
|
90
|
+
return False
|
|
91
|
+
|
|
92
|
+
if int(parts[0]) == 0:
|
|
93
|
+
return False
|
|
94
|
+
|
|
95
|
+
if int(parts[3]) == 0:
|
|
96
|
+
return False
|
|
97
|
+
|
|
98
|
+
return True
|
|
99
|
+
|
|
100
|
+
return False
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def is_ip_in_network(ip: str, network: IPv4Network) -> bool:
|
|
104
|
+
"Check if an ip is in a given network"
|
|
105
|
+
if not is_valid_ip(ip):
|
|
106
|
+
return False
|
|
107
|
+
|
|
108
|
+
return ip_address(ip) in network
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def is_valid_email(email: str) -> bool:
|
|
112
|
+
"Check if an email is valid"
|
|
113
|
+
parts = email.split("@")
|
|
114
|
+
if len(parts) == 2:
|
|
115
|
+
if is_valid_domain(parts[1]):
|
|
116
|
+
return True
|
|
117
|
+
|
|
118
|
+
return False
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def get_hostname() -> str:
|
|
122
|
+
"Get the hostname of the computer howler is running on"
|
|
123
|
+
return socket.gethostname()
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def get_mac_address() -> str:
|
|
127
|
+
"Get the mac address of the computer howler is running on"
|
|
128
|
+
return "".join(["{0:02x}".format((uuid.getnode() >> i) & 0xFF) for i in range(0, 8 * 6, 8)][::-1]).upper()
|