howler-api 4.0.0.dev1019__tar.gz → 4.0.0.dev1020__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.dev1019 → howler_api-4.0.0.dev1020}/PKG-INFO +1 -1
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/api/v1/action.py +21 -11
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/api/v1/analytic.py +30 -11
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/api/v1/dossier.py +25 -9
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/api/v1/hit.py +94 -25
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/api/v1/overview.py +19 -6
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/api/v1/template.py +19 -6
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/api/v1/tool.py +2 -2
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/api/v1/user.py +25 -5
- howler_api-4.0.0.dev1020/howler/api/v1/utils/params.py +71 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/api/v1/view.py +19 -10
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/common/exceptions.py +4 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/datastore/collection.py +18 -11
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/random_data.py +2 -2
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/services/analytic_service.py +44 -17
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/services/dossier_service.py +6 -10
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/services/hit_service.py +16 -14
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/services/user_service.py +2 -2
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/pyproject.toml +1 -1
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/README.md +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/__init__.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/actions/__init__.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/actions/add_label.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/actions/add_to_bundle.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/actions/change_field.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/actions/demote.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/actions/example_plugin.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/actions/prioritization.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/actions/promote.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/actions/remove_from_bundle.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/actions/remove_label.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/actions/transition.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/api/__init__.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/api/base.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/api/socket.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/api/v1/__init__.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/api/v1/auth.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/api/v1/clue.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/api/v1/configs.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/api/v1/help.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/api/v1/notebook.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/api/v1/search.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/api/v1/utils/__init__.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/api/v1/utils/etag.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/app.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/common/README.md +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/common/__init__.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/common/classification.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/common/classification.yml +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/common/loader.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/common/logging/__init__.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/common/logging/audit.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/common/logging/format.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/common/net.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/common/net_static.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/common/random_user.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/common/swagger.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/config.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/cronjobs/__init__.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/cronjobs/action_queue_worker.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/cronjobs/retention.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/cronjobs/rules.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/cronjobs/view_cleanup.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/datastore/README.md +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/datastore/__init__.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/datastore/bulk.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/datastore/constants.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/datastore/exceptions.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/datastore/howler_store.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/datastore/migrations/fix_process.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/datastore/operations.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/datastore/schemas.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/datastore/store.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/datastore/support/__init__.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/datastore/support/build.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/datastore/support/schemas.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/datastore/types.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/error.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/external/README.md +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/external/__init__.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/external/generate_mitre.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/external/generate_sigma_rules.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/external/generate_tlds.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/external/reindex_data.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/external/wipe_databases.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/gunicorn_config.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/healthz.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/helper/__init__.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/helper/azure.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/helper/discover.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/helper/hit.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/helper/oauth.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/helper/search.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/helper/workflow.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/helper/ws.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/README.md +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/__init__.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/base.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/charter.txt +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/helper.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/howler_enum.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/__init__.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/action.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/analytic.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/assemblyline.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/aws.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/azure.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/cbs.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/clue.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/config.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/dossier.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/__init__.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/agent.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/autonomous_system.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/client.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/cloud.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/code_signature.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/container.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/dns.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/egress.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/elf.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/email.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/error.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/event.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/faas.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/file.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/geo.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/group.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/hash.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/host.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/http.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/ingress.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/interface.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/network.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/observer.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/organization.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/os.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/pe.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/process.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/registry.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/related.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/rule.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/server.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/threat.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/tls.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/url.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/user.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/user_agent.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/ecs/vulnerability.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/gcp.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/hit.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/howler_data.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/lead.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/localized_label.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/overview.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/pivot.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/template.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/user.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/models/view.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/odm/randomizer.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/patched.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/plugins/__init__.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/plugins/config.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/remote/__init__.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/remote/datatypes/README.md +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/remote/datatypes/__init__.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/remote/datatypes/counters.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/remote/datatypes/events.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/remote/datatypes/hash.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/remote/datatypes/lock.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/remote/datatypes/queues/__init__.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/remote/datatypes/queues/comms.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/remote/datatypes/queues/multi.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/remote/datatypes/queues/named.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/remote/datatypes/queues/priority.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/remote/datatypes/set.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/remote/datatypes/user_quota_tracker.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/security/__init__.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/security/socket.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/security/utils.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/services/__init__.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/services/action_service.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/services/auth_service.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/services/config_service.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/services/event_service.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/services/jwt_service.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/services/lucene_service.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/services/notebook_service.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/services/overview_service.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/services/template_service.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/telemetry.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/utils/__init__.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/utils/annotations.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/utils/chunk.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/utils/compat.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/utils/constants.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/utils/dict_utils.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/utils/isotime.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/utils/list_utils.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/utils/lucene.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/utils/path.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/utils/socket_utils.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/utils/str_utils.py +0 -0
- {howler_api-4.0.0.dev1019 → howler_api-4.0.0.dev1020}/howler/utils/uid.py +0 -0
|
@@ -4,6 +4,7 @@ from flask import Response, request
|
|
|
4
4
|
|
|
5
5
|
import howler.actions as actions
|
|
6
6
|
from howler.api import bad_request, created, forbidden, internal_error, make_subapi_blueprint, no_content, not_found, ok
|
|
7
|
+
from howler.api.v1.utils.params import parse_parameters, parse_refresh
|
|
7
8
|
from howler.common.exceptions import HowlerException
|
|
8
9
|
from howler.common.loader import datastore
|
|
9
10
|
from howler.common.logging.audit import audit
|
|
@@ -48,14 +49,16 @@ def get_actions(**_) -> Response:
|
|
|
48
49
|
@generate_swagger_docs()
|
|
49
50
|
@action_api.route("/", methods=["POST"])
|
|
50
51
|
@api_login(audit=False, check_xsrf_token=False, required_type=["admin", "automation_basic", "automation_advanced"])
|
|
51
|
-
|
|
52
|
+
@parse_parameters(refresh=parse_refresh)
|
|
53
|
+
def add_action(user: User, **kwargs) -> Response:
|
|
52
54
|
"""Create a new action
|
|
53
55
|
|
|
54
56
|
Variables:
|
|
55
57
|
None
|
|
56
58
|
|
|
57
59
|
Optional Arguments:
|
|
58
|
-
|
|
60
|
+
refresh => ('true' | 'false' | 'wait_for') Whether to refresh the datastore before returning.
|
|
61
|
+
'wait_for' will wait for the change to be visible in search.
|
|
59
62
|
|
|
60
63
|
Data Block:
|
|
61
64
|
{
|
|
@@ -79,6 +82,8 @@ def add_action(user: User, **_) -> Response:
|
|
|
79
82
|
if new_action is None:
|
|
80
83
|
return bad_request(err="You must specify an action")
|
|
81
84
|
|
|
85
|
+
refresh = kwargs.get("refresh")
|
|
86
|
+
|
|
82
87
|
if error := action_service.validate_action(new_action):
|
|
83
88
|
return error
|
|
84
89
|
|
|
@@ -88,8 +93,7 @@ def add_action(user: User, **_) -> Response:
|
|
|
88
93
|
action_obj = Action(new_action)
|
|
89
94
|
|
|
90
95
|
ds = datastore()
|
|
91
|
-
ds.action.save(action_obj.action_id, action_obj)
|
|
92
|
-
ds.action.commit()
|
|
96
|
+
ds.action.save(action_obj.action_id, action_obj, refresh=refresh)
|
|
93
97
|
except HowlerException as e:
|
|
94
98
|
return bad_request(err=str(e))
|
|
95
99
|
|
|
@@ -103,14 +107,16 @@ def add_action(user: User, **_) -> Response:
|
|
|
103
107
|
check_xsrf_token=False,
|
|
104
108
|
required_type=["admin", "automation_basic", "automation_advanced"],
|
|
105
109
|
)
|
|
106
|
-
|
|
110
|
+
@parse_parameters(refresh=parse_refresh)
|
|
111
|
+
def update_action(id: str, user: User, **kwargs) -> Response:
|
|
107
112
|
"""Update an existing action
|
|
108
113
|
|
|
109
114
|
Variables:
|
|
110
115
|
id => id of the aciton to update
|
|
111
116
|
|
|
112
117
|
Optional Arguments:
|
|
113
|
-
|
|
118
|
+
refresh => ('true' | 'false' | 'wait_for') Whether to refresh the datastore before returning.
|
|
119
|
+
'wait_for' will wait for the change to be visible in search.
|
|
114
120
|
|
|
115
121
|
Data Block:
|
|
116
122
|
{
|
|
@@ -133,6 +139,8 @@ def update_action(id: str, user: User, **_) -> Response:
|
|
|
133
139
|
if not isinstance(updated_action, dict):
|
|
134
140
|
return bad_request(err="Incorrect data structure!")
|
|
135
141
|
|
|
142
|
+
refresh = kwargs.get("refresh")
|
|
143
|
+
|
|
136
144
|
ds = datastore()
|
|
137
145
|
|
|
138
146
|
existing_action = ds.action.get(id, as_obj=False)
|
|
@@ -158,8 +166,7 @@ def update_action(id: str, user: User, **_) -> Response:
|
|
|
158
166
|
action_obj = Action(updated_action)
|
|
159
167
|
action_obj.action_id = id
|
|
160
168
|
|
|
161
|
-
ds.action.save(action_obj.action_id, action_obj)
|
|
162
|
-
ds.action.commit()
|
|
169
|
+
ds.action.save(action_obj.action_id, action_obj, refresh=refresh)
|
|
163
170
|
except HowlerException as e:
|
|
164
171
|
return bad_request(err=str(e))
|
|
165
172
|
|
|
@@ -169,6 +176,7 @@ def update_action(id: str, user: User, **_) -> Response:
|
|
|
169
176
|
@generate_swagger_docs()
|
|
170
177
|
@action_api.route("/<id>", methods=["DELETE"])
|
|
171
178
|
@api_login(audit=True, check_xsrf_token=False, required_type=["admin", "automation_basic", "automation_advanced"])
|
|
179
|
+
@parse_parameters(refresh=parse_refresh)
|
|
172
180
|
def delete_action(id: str, user: User, **kwargs) -> Response:
|
|
173
181
|
"""Delete an existing action
|
|
174
182
|
|
|
@@ -176,11 +184,14 @@ def delete_action(id: str, user: User, **kwargs) -> Response:
|
|
|
176
184
|
id => The id of the action to delete
|
|
177
185
|
|
|
178
186
|
Optional Arguments:
|
|
179
|
-
|
|
187
|
+
refresh => ('true' | 'false' | 'wait_for') Whether to refresh the datastore before returning.
|
|
188
|
+
'wait_for' will wait for the change to be visible in search.
|
|
180
189
|
|
|
181
190
|
Result Example:
|
|
182
191
|
None
|
|
183
192
|
"""
|
|
193
|
+
refresh = kwargs.get("refresh")
|
|
194
|
+
|
|
184
195
|
ds = datastore()
|
|
185
196
|
|
|
186
197
|
result = ds.action.search(f"action_id:{id}", rows=1)
|
|
@@ -194,8 +205,7 @@ def delete_action(id: str, user: User, **kwargs) -> Response:
|
|
|
194
205
|
return forbidden(err="You do not have the permissions necessary to delete this action.")
|
|
195
206
|
|
|
196
207
|
try:
|
|
197
|
-
ds.action.delete(id)
|
|
198
|
-
ds.action.commit()
|
|
208
|
+
ds.action.delete(id, refresh=refresh)
|
|
199
209
|
|
|
200
210
|
return no_content()
|
|
201
211
|
except HowlerException as e:
|
|
@@ -11,6 +11,7 @@ from howler.api import (
|
|
|
11
11
|
not_found,
|
|
12
12
|
ok,
|
|
13
13
|
)
|
|
14
|
+
from howler.api.v1.utils.params import parse_parameters, parse_refresh
|
|
14
15
|
from howler.common.exceptions import HowlerException
|
|
15
16
|
from howler.common.loader import datastore
|
|
16
17
|
from howler.common.logging import get_logger
|
|
@@ -83,6 +84,7 @@ def get_analytic(id, **kwargs):
|
|
|
83
84
|
@generate_swagger_docs()
|
|
84
85
|
@analytic_api.route("/<id>", methods=["PUT"])
|
|
85
86
|
@api_login(required_priv=["R", "W"])
|
|
87
|
+
@parse_parameters(refresh=parse_refresh)
|
|
86
88
|
def update_analytic(id: str, user: User, **kwargs):
|
|
87
89
|
"""Update an analytic
|
|
88
90
|
|
|
@@ -90,7 +92,8 @@ def update_analytic(id: str, user: User, **kwargs):
|
|
|
90
92
|
id => The id of the analytic to modify
|
|
91
93
|
|
|
92
94
|
Optional Arguments:
|
|
93
|
-
|
|
95
|
+
refresh => ('true' | 'false' | 'wait_for') Whether to refresh the datastore before returning.
|
|
96
|
+
'wait_for' will wait for the change to be visible in search.
|
|
94
97
|
|
|
95
98
|
Data Block:
|
|
96
99
|
{
|
|
@@ -102,6 +105,8 @@ def update_analytic(id: str, user: User, **kwargs):
|
|
|
102
105
|
...analytic # The updated analytic data
|
|
103
106
|
}
|
|
104
107
|
"""
|
|
108
|
+
refresh = kwargs.get("refresh")
|
|
109
|
+
|
|
105
110
|
storage = datastore()
|
|
106
111
|
|
|
107
112
|
if not storage.analytic.exists(id):
|
|
@@ -135,7 +140,7 @@ def update_analytic(id: str, user: User, **kwargs):
|
|
|
135
140
|
existing_analytic.rule = new_data.get("rule", existing_analytic.rule)
|
|
136
141
|
existing_analytic.rule_crontab = new_data.get("rule_crontab", existing_analytic.rule_crontab)
|
|
137
142
|
|
|
138
|
-
storage.analytic.save(existing_analytic.analytic_id, existing_analytic)
|
|
143
|
+
storage.analytic.save(existing_analytic.analytic_id, existing_analytic, refresh=refresh)
|
|
139
144
|
|
|
140
145
|
if updated_rule:
|
|
141
146
|
# The registration process automatically deletes and resets the rule cronjob
|
|
@@ -149,6 +154,7 @@ def update_analytic(id: str, user: User, **kwargs):
|
|
|
149
154
|
@generate_swagger_docs()
|
|
150
155
|
@analytic_api.route("/rules", methods=["POST"])
|
|
151
156
|
@api_login(required_priv=["R", "W"])
|
|
157
|
+
@parse_parameters(refresh=parse_refresh)
|
|
152
158
|
def create_rule(user: User, **kwargs):
|
|
153
159
|
"""Create a rule analytic
|
|
154
160
|
|
|
@@ -156,7 +162,8 @@ def create_rule(user: User, **kwargs):
|
|
|
156
162
|
None
|
|
157
163
|
|
|
158
164
|
Optional Arguments:
|
|
159
|
-
|
|
165
|
+
refresh => ('true' | 'false' | 'wait_for') Whether to refresh the datastore before returning.
|
|
166
|
+
'wait_for' will wait for the change to be visible in search.
|
|
160
167
|
|
|
161
168
|
Data Block:
|
|
162
169
|
{
|
|
@@ -169,6 +176,8 @@ def create_rule(user: User, **kwargs):
|
|
|
169
176
|
...analytic # The created analytic rule
|
|
170
177
|
}
|
|
171
178
|
"""
|
|
179
|
+
refresh = kwargs.get("refresh")
|
|
180
|
+
|
|
172
181
|
storage = datastore()
|
|
173
182
|
|
|
174
183
|
new_data: Optional[dict[str, Any]] = request.json
|
|
@@ -215,12 +224,12 @@ def create_rule(user: User, **kwargs):
|
|
|
215
224
|
)
|
|
216
225
|
|
|
217
226
|
try:
|
|
218
|
-
storage.analytic.save(new_analytic.analytic_id, new_analytic)
|
|
219
|
-
|
|
220
|
-
|
|
227
|
+
storage.analytic.save(new_analytic.analytic_id, new_analytic, refresh=refresh)
|
|
228
|
+
|
|
229
|
+
# note that passing a rule will only register that rule without querying for all existing rules
|
|
221
230
|
register_rules(new_analytic)
|
|
222
231
|
|
|
223
|
-
storage.template.save(new_template.template_id, new_template)
|
|
232
|
+
storage.template.save(new_template.template_id, new_template, refresh=refresh)
|
|
224
233
|
|
|
225
234
|
return ok(new_analytic)
|
|
226
235
|
except HowlerException as e:
|
|
@@ -230,6 +239,7 @@ def create_rule(user: User, **kwargs):
|
|
|
230
239
|
@generate_swagger_docs()
|
|
231
240
|
@analytic_api.route("/<id>", methods=["DELETE"])
|
|
232
241
|
@api_login(audit=False, required_priv=["W"])
|
|
242
|
+
@parse_parameters(refresh=parse_refresh)
|
|
233
243
|
def delete_rule(id: str, user: User, **kwargs):
|
|
234
244
|
"""Delete a rule
|
|
235
245
|
|
|
@@ -237,7 +247,8 @@ def delete_rule(id: str, user: User, **kwargs):
|
|
|
237
247
|
id => id of the analytic whose comments we are deleting
|
|
238
248
|
|
|
239
249
|
Optional Arguments:
|
|
240
|
-
|
|
250
|
+
refresh => ('true' | 'false' | 'wait_for') Whether to refresh the datastore before returning.
|
|
251
|
+
'wait_for' will wait for the change to be visible in search.
|
|
241
252
|
|
|
242
253
|
Data Block:
|
|
243
254
|
[
|
|
@@ -248,6 +259,8 @@ def delete_rule(id: str, user: User, **kwargs):
|
|
|
248
259
|
{
|
|
249
260
|
}
|
|
250
261
|
"""
|
|
262
|
+
refresh = kwargs.get("refresh")
|
|
263
|
+
|
|
251
264
|
if not analytic_service.does_analytic_exist(id):
|
|
252
265
|
return not_found(err=f"Analytic {id} does not exist")
|
|
253
266
|
|
|
@@ -260,7 +273,7 @@ def delete_rule(id: str, user: User, **kwargs):
|
|
|
260
273
|
return forbidden(err="You cannot delete this analytic.")
|
|
261
274
|
|
|
262
275
|
try:
|
|
263
|
-
datastore().analytic.delete(analytic.analytic_id)
|
|
276
|
+
datastore().analytic.delete(analytic.analytic_id, refresh=refresh)
|
|
264
277
|
except DataStoreException as e:
|
|
265
278
|
return bad_request(err=str(e))
|
|
266
279
|
|
|
@@ -517,6 +530,7 @@ def delete_comments(id: str, user: User, **kwargs):
|
|
|
517
530
|
@generate_swagger_docs()
|
|
518
531
|
@analytic_api.route("/<id>/owner", methods=["POST"])
|
|
519
532
|
@api_login(required_priv=["W"])
|
|
533
|
+
@parse_parameters(refresh=parse_refresh)
|
|
520
534
|
def set_analytic_owner(id: str, user: dict[str, Any], **kwargs):
|
|
521
535
|
"""Set the analytic's owner
|
|
522
536
|
|
|
@@ -526,6 +540,10 @@ def set_analytic_owner(id: str, user: dict[str, Any], **kwargs):
|
|
|
526
540
|
Arguments:
|
|
527
541
|
None
|
|
528
542
|
|
|
543
|
+
Optional Arguments:
|
|
544
|
+
refresh => ('true' | 'false' | 'wait_for') Whether to refresh the datastore before returning.
|
|
545
|
+
'wait_for' will wait for the change to be visible in search.
|
|
546
|
+
|
|
529
547
|
Data Block:
|
|
530
548
|
{
|
|
531
549
|
"username": "admin" # The username to set the owner as
|
|
@@ -536,6 +554,8 @@ def set_analytic_owner(id: str, user: dict[str, Any], **kwargs):
|
|
|
536
554
|
...analytic # The claimed analytic
|
|
537
555
|
}
|
|
538
556
|
"""
|
|
557
|
+
refresh = kwargs.get("refresh")
|
|
558
|
+
|
|
539
559
|
if not analytic_service.does_analytic_exist(id):
|
|
540
560
|
return not_found(err=f"Analytic {id} does not exist")
|
|
541
561
|
|
|
@@ -548,8 +568,7 @@ def set_analytic_owner(id: str, user: dict[str, Any], **kwargs):
|
|
|
548
568
|
analytic.owner = data["username"]
|
|
549
569
|
|
|
550
570
|
ds = datastore()
|
|
551
|
-
ds.analytic.save(analytic.analytic_id, analytic)
|
|
552
|
-
ds.analytic.commit()
|
|
571
|
+
ds.analytic.save(analytic.analytic_id, analytic, refresh=refresh)
|
|
553
572
|
|
|
554
573
|
return ok(analytic)
|
|
555
574
|
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
from flask import request
|
|
2
2
|
|
|
3
3
|
from howler.api import bad_request, created, forbidden, internal_error, make_subapi_blueprint, no_content, not_found, ok
|
|
4
|
-
from howler.
|
|
4
|
+
from howler.api.v1.utils.params import parse_parameters, parse_refresh
|
|
5
|
+
from howler.common.exceptions import (
|
|
6
|
+
ForbiddenException,
|
|
7
|
+
HowlerException,
|
|
8
|
+
InvalidDataException,
|
|
9
|
+
NotFoundException,
|
|
10
|
+
)
|
|
5
11
|
from howler.common.loader import datastore
|
|
6
12
|
from howler.common.logging import get_logger
|
|
7
13
|
from howler.common.swagger import generate_swagger_docs
|
|
@@ -49,6 +55,7 @@ def get_dossiers(user: User, **kwargs):
|
|
|
49
55
|
@generate_swagger_docs()
|
|
50
56
|
@dossier_api.route("/", methods=["POST"])
|
|
51
57
|
@api_login(required_priv=["R", "W"])
|
|
58
|
+
@parse_parameters(refresh=parse_refresh)
|
|
52
59
|
def create_dossier(**kwargs):
|
|
53
60
|
"""Create a new dossier
|
|
54
61
|
|
|
@@ -56,7 +63,8 @@ def create_dossier(**kwargs):
|
|
|
56
63
|
None
|
|
57
64
|
|
|
58
65
|
Optional Arguments:
|
|
59
|
-
|
|
66
|
+
refresh => ('true' | 'false' | 'wait_for') Whether to refresh the datastore before returning.
|
|
67
|
+
'wait_for' will wait for the change to be visible in search.
|
|
60
68
|
|
|
61
69
|
Data Block:
|
|
62
70
|
{
|
|
@@ -72,8 +80,10 @@ def create_dossier(**kwargs):
|
|
|
72
80
|
"""
|
|
73
81
|
dossier_data = request.json
|
|
74
82
|
|
|
83
|
+
refresh = kwargs.get("refresh")
|
|
84
|
+
|
|
75
85
|
try:
|
|
76
|
-
return created(dossier_service.create_dossier(dossier_data, username=kwargs["user"]["uname"]))
|
|
86
|
+
return created(dossier_service.create_dossier(dossier_data, username=kwargs["user"]["uname"], refresh=refresh))
|
|
77
87
|
except InvalidDataException as e:
|
|
78
88
|
return bad_request(err=str(e))
|
|
79
89
|
except HowlerException:
|
|
@@ -147,6 +157,7 @@ def get_dossier_for_hit(id: str, user: User, **kwargs):
|
|
|
147
157
|
@generate_swagger_docs()
|
|
148
158
|
@dossier_api.route("/<id>", methods=["DELETE"])
|
|
149
159
|
@api_login(required_priv=["W"])
|
|
160
|
+
@parse_parameters(refresh=parse_refresh)
|
|
150
161
|
def delete_dossier(id: str, user: User, **kwargs):
|
|
151
162
|
"""Delete a dossier
|
|
152
163
|
|
|
@@ -154,7 +165,8 @@ def delete_dossier(id: str, user: User, **kwargs):
|
|
|
154
165
|
id => The id of the dossier to delete
|
|
155
166
|
|
|
156
167
|
Optional Arguments:
|
|
157
|
-
|
|
168
|
+
refresh => ('true' | 'false' | 'wait_for') Whether to refresh the datastore before returning.
|
|
169
|
+
'wait_for' will wait for the change to be visible in search.
|
|
158
170
|
|
|
159
171
|
Data Block:
|
|
160
172
|
None
|
|
@@ -164,6 +176,8 @@ def delete_dossier(id: str, user: User, **kwargs):
|
|
|
164
176
|
"success": true # Did the deletion succeed?
|
|
165
177
|
}
|
|
166
178
|
"""
|
|
179
|
+
refresh = kwargs.get("refresh")
|
|
180
|
+
|
|
167
181
|
storage = datastore()
|
|
168
182
|
|
|
169
183
|
existing_dossier: Dossier = storage.dossier.get_if_exists(id)
|
|
@@ -173,9 +187,7 @@ def delete_dossier(id: str, user: User, **kwargs):
|
|
|
173
187
|
if existing_dossier.owner != user.uname and "admin" not in user.type:
|
|
174
188
|
return forbidden(err="You cannot delete a dossier unless you are an administrator, or the owner.")
|
|
175
189
|
|
|
176
|
-
success = storage.dossier.delete(id)
|
|
177
|
-
|
|
178
|
-
storage.dossier.commit()
|
|
190
|
+
success = storage.dossier.delete(id, refresh=refresh)
|
|
179
191
|
|
|
180
192
|
return no_content({"success": success})
|
|
181
193
|
|
|
@@ -183,6 +195,7 @@ def delete_dossier(id: str, user: User, **kwargs):
|
|
|
183
195
|
@generate_swagger_docs()
|
|
184
196
|
@dossier_api.route("/<id>", methods=["PUT"])
|
|
185
197
|
@api_login(required_priv=["R", "W"])
|
|
198
|
+
@parse_parameters(refresh=parse_refresh)
|
|
186
199
|
def update_dossier(id: str, user: User, **kwargs):
|
|
187
200
|
"""Update a dossier
|
|
188
201
|
|
|
@@ -190,7 +203,8 @@ def update_dossier(id: str, user: User, **kwargs):
|
|
|
190
203
|
id => The id of the dossier to modify
|
|
191
204
|
|
|
192
205
|
Optional Arguments:
|
|
193
|
-
|
|
206
|
+
refresh => ('true' | 'false' | 'wait_for') Whether to refresh the datastore before returning.
|
|
207
|
+
'wait_for' will wait for the change to be visible in search.
|
|
194
208
|
|
|
195
209
|
Data Block:
|
|
196
210
|
{
|
|
@@ -207,8 +221,10 @@ def update_dossier(id: str, user: User, **kwargs):
|
|
|
207
221
|
if not isinstance(new_data, dict):
|
|
208
222
|
return bad_request(err="Invalid data format")
|
|
209
223
|
|
|
224
|
+
refresh = kwargs.get("refresh")
|
|
225
|
+
|
|
210
226
|
try:
|
|
211
|
-
updated_dossier = dossier_service.update_dossier(id, new_data, user)
|
|
227
|
+
updated_dossier = dossier_service.update_dossier(id, new_data, user, refresh=refresh)
|
|
212
228
|
|
|
213
229
|
return ok(updated_dossier)
|
|
214
230
|
except ForbiddenException as e:
|