howler-api 4.1.0.dev1560__tar.gz → 4.1.0.dev1573__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.1.0.dev1560 → howler_api-4.1.0.dev1573}/PKG-INFO +1 -1
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/actions/add_to_bundle.py +8 -2
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/actions/add_to_case.py +28 -7
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/api/socket.py +39 -5
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/api/v1/hit.py +160 -103
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/api/v1/search.py +20 -31
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/api/v1/tool.py +3 -4
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/api/v1/user.py +5 -6
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/api/v1/utils/etag.py +30 -17
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/api/v2/case.py +98 -43
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/api/v2/ingest.py +68 -20
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/common/classification.py +4 -1
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/datastore/collection.py +142 -93
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/security/socket.py +4 -4
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/security/utils.py +94 -3
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/services/bundle_compat_service.py +38 -30
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/services/case_service.py +238 -148
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/services/correlation_service.py +19 -23
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/services/event_service.py +81 -2
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/services/hit_service.py +52 -6
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/services/user_service.py +5 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/utils/socket_utils.py +14 -5
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/pyproject.toml +1 -1
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/README.md +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/__init__.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/actions/__init__.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/actions/add_label.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/actions/change_field.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/actions/demote.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/actions/example_plugin.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/actions/prioritization.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/actions/promote.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/actions/remove_from_bundle.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/actions/remove_label.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/actions/transition.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/api/__init__.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/api/base.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/api/v1/__init__.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/api/v1/action.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/api/v1/analytic.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/api/v1/auth.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/api/v1/clue.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/api/v1/configs.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/api/v1/dossier.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/api/v1/help.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/api/v1/notebook.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/api/v1/overview.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/api/v1/template.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/api/v1/utils/__init__.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/api/v1/utils/params.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/api/v1/view.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/api/v2/__init__.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/api/v2/fuzzy.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/api/v2/search.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/app.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/common/README.md +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/common/__init__.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/common/classification.yml +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/common/exceptions.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/common/loader.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/common/logging/__init__.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/common/logging/audit.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/common/logging/format.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/common/net.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/common/net_static.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/common/random_user.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/common/swagger.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/config.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/cronjobs/__init__.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/cronjobs/action_queue_worker.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/cronjobs/correlation.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/cronjobs/retention.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/cronjobs/view_cleanup.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/datastore/README.md +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/datastore/__init__.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/datastore/bulk.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/datastore/constants.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/datastore/exceptions.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/datastore/howler_store.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/datastore/migrations/fix_process.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/datastore/operations.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/datastore/schemas.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/datastore/store.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/datastore/support/__init__.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/datastore/support/build.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/datastore/support/schemas.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/datastore/types.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/datastore/utils.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/error.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/external/README.md +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/external/__init__.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/external/check_duplicates.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/external/generate_mitre.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/external/generate_sigma_rules.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/external/generate_tlds.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/external/reindex_data.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/external/wipe_databases.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/gunicorn_config.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/healthz.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/helper/__init__.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/helper/azure.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/helper/discover.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/helper/hit.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/helper/oauth.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/helper/search.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/helper/workflow.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/helper/ws.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/README.md +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/__init__.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/base.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/charter.txt +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/constants.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/helper.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/howler_enum.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/mixins.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/__init__.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/action.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/analytic.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/assemblyline.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/aws.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/azure.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/case.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/cbs.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/clue.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/config.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/dossier.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/ecs/__init__.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/ecs/agent.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/ecs/autonomous_system.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/ecs/client.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/ecs/cloud.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/ecs/code_signature.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/ecs/container.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/ecs/dns.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/ecs/egress.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/ecs/elf.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/ecs/email.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/ecs/error.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/ecs/event.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/ecs/faas.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/ecs/file.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/ecs/geo.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/ecs/group.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/ecs/hash.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/ecs/host.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/ecs/http.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/ecs/ingress.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/ecs/interface.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/ecs/network.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/ecs/observer.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/ecs/organization.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/ecs/os.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/ecs/pe.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/ecs/process.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/ecs/registry.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/ecs/related.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/ecs/rule.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/ecs/server.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/ecs/threat.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/ecs/tls.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/ecs/url.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/ecs/user.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/ecs/user_agent.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/ecs/vulnerability.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/event.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/gcp.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/hit.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/howler_data.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/lead.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/localized_label.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/overview.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/pivot.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/record.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/template.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/user.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/models/view.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/random_data.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/odm/randomizer.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/patched.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/plugins/__init__.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/plugins/config.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/remote/__init__.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/remote/datatypes/README.md +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/remote/datatypes/__init__.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/remote/datatypes/counters.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/remote/datatypes/events.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/remote/datatypes/hash.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/remote/datatypes/lock.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/remote/datatypes/queues/__init__.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/remote/datatypes/queues/comms.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/remote/datatypes/queues/multi.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/remote/datatypes/queues/named.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/remote/datatypes/queues/priority.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/remote/datatypes/set.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/remote/datatypes/user_quota_tracker.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/security/__init__.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/security/login.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/services/__init__.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/services/action_service.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/services/analytic_service.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/services/auth_service.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/services/comms_service.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/services/config_service.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/services/docs_service.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/services/dossier_service.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/services/fuzzy_service.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/services/jwt_service.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/services/lucene_service.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/services/notebook_service.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/services/overview_service.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/services/search_service.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/services/template_service.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/services/viewer_service.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/telemetry.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/utils/__init__.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/utils/annotations.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/utils/chunk.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/utils/compat.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/utils/constants.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/utils/dict_utils.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/utils/indexes.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/utils/isotime.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/utils/list_utils.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/utils/lucene.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/utils/net_utils.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/utils/path.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/utils/str_utils.py +0 -0
- {howler_api-4.1.0.dev1560 → howler_api-4.1.0.dev1573}/howler/utils/uid.py +0 -0
|
@@ -8,7 +8,7 @@ from howler.common.loader import datastore
|
|
|
8
8
|
from howler.odm.models.action import VALID_TRIGGERS
|
|
9
9
|
from howler.odm.models.case import CaseItemTypes
|
|
10
10
|
from howler.odm.models.user import User
|
|
11
|
-
from howler.services import bundle_compat_service, case_service
|
|
11
|
+
from howler.services import bundle_compat_service, case_service, comms_service
|
|
12
12
|
from howler.utils.str_utils import sanitize_lucene_query
|
|
13
13
|
|
|
14
14
|
OPERATION_ID = "add_to_bundle"
|
|
@@ -70,7 +70,8 @@ def execute(query: str, bundle_id: Optional[str] = None, user: Optional[User] =
|
|
|
70
70
|
)
|
|
71
71
|
return report
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
original_item_count = len(case.items)
|
|
74
|
+
folder = case_service.get_parent_from_path(case, "hits", create_if_missing=True, user=user)
|
|
74
75
|
|
|
75
76
|
added = []
|
|
76
77
|
skipped = []
|
|
@@ -83,11 +84,16 @@ def execute(query: str, bundle_id: Optional[str] = None, user: Optional[User] =
|
|
|
83
84
|
item_name=name,
|
|
84
85
|
item_value=hit.howler.id,
|
|
85
86
|
item_parent=folder.id if folder else None,
|
|
87
|
+
user=user,
|
|
86
88
|
)
|
|
87
89
|
added.append(hit.howler.id)
|
|
88
90
|
except Exception: # pragma: no cover
|
|
89
91
|
skipped.append(hit.howler.id)
|
|
90
92
|
|
|
93
|
+
if len(case.items) != original_item_count:
|
|
94
|
+
case.save(refresh="wait_for")
|
|
95
|
+
comms_service.emit("cases", {"case": case.as_primitives()})
|
|
96
|
+
|
|
91
97
|
if skipped:
|
|
92
98
|
report.append(
|
|
93
99
|
{
|
|
@@ -1,19 +1,23 @@
|
|
|
1
|
-
from typing import Optional
|
|
2
|
-
|
|
3
1
|
import chevron
|
|
4
2
|
|
|
5
3
|
from howler.common.exceptions import InvalidDataException, NotFoundException
|
|
6
4
|
from howler.common.loader import datastore
|
|
5
|
+
from howler.common.logging import get_logger
|
|
6
|
+
from howler.datastore.exceptions import DataStoreException, VersionConflictException
|
|
7
7
|
from howler.odm.models.action import VALID_TRIGGERS
|
|
8
|
-
from howler.
|
|
8
|
+
from howler.odm.models.user import User
|
|
9
|
+
from howler.services import case_service, comms_service
|
|
10
|
+
|
|
11
|
+
logger = get_logger(__file__)
|
|
9
12
|
|
|
10
13
|
OPERATION_ID = "add_to_case"
|
|
11
14
|
|
|
12
15
|
|
|
13
16
|
def execute( # noqa: C901
|
|
14
17
|
query: str,
|
|
15
|
-
case_id:
|
|
18
|
+
case_id: str | None = None,
|
|
16
19
|
destination: str = "related/{{howler.analytic}} ({{howler.id}})",
|
|
20
|
+
user: User | None = None,
|
|
17
21
|
**kwargs,
|
|
18
22
|
):
|
|
19
23
|
"""Add matching alerts to a given case.
|
|
@@ -37,8 +41,8 @@ def execute( # noqa: C901
|
|
|
37
41
|
|
|
38
42
|
ds = datastore()
|
|
39
43
|
|
|
40
|
-
case =
|
|
41
|
-
if case
|
|
44
|
+
case, version = case_service.get_case(case_id, as_odm=True, version=True, user=user)
|
|
45
|
+
if not case:
|
|
42
46
|
return [
|
|
43
47
|
{
|
|
44
48
|
"query": query,
|
|
@@ -63,6 +67,7 @@ def execute( # noqa: C901
|
|
|
63
67
|
report = []
|
|
64
68
|
skipped = []
|
|
65
69
|
added = []
|
|
70
|
+
original_item_count = len(case.items)
|
|
66
71
|
|
|
67
72
|
for hit in hits:
|
|
68
73
|
rendered_destination = chevron.render(destination, hit.as_primitives())
|
|
@@ -73,7 +78,7 @@ def execute( # noqa: C901
|
|
|
73
78
|
name = rendered_destination
|
|
74
79
|
|
|
75
80
|
try:
|
|
76
|
-
parent = case_service.get_parent_from_path(case, item_path, create_if_missing=True)
|
|
81
|
+
parent = case_service.get_parent_from_path(case, item_path, create_if_missing=True, user=user)
|
|
77
82
|
|
|
78
83
|
case_service.append_case_item(
|
|
79
84
|
case,
|
|
@@ -81,6 +86,7 @@ def execute( # noqa: C901
|
|
|
81
86
|
item_value=hit.howler.id,
|
|
82
87
|
item_name=name,
|
|
83
88
|
item_parent=parent.id if parent else None,
|
|
89
|
+
user=user,
|
|
84
90
|
)
|
|
85
91
|
added.append(hit.howler.id)
|
|
86
92
|
except InvalidDataException as e:
|
|
@@ -90,6 +96,21 @@ def execute( # noqa: C901
|
|
|
90
96
|
except Exception as e: # pragma: no cover
|
|
91
97
|
skipped.append(f"{hit.howler.id}: {e}")
|
|
92
98
|
|
|
99
|
+
if len(case.items) != original_item_count:
|
|
100
|
+
try:
|
|
101
|
+
case.save(refresh="wait_for", version=version)
|
|
102
|
+
except (DataStoreException, VersionConflictException):
|
|
103
|
+
logger.exception("Exception on save:")
|
|
104
|
+
return [
|
|
105
|
+
{
|
|
106
|
+
"query": query,
|
|
107
|
+
"outcome": "error",
|
|
108
|
+
"title": "Case update failed",
|
|
109
|
+
"message": "There was a datastore error or version conflict when updating the case.",
|
|
110
|
+
}
|
|
111
|
+
]
|
|
112
|
+
comms_service.emit("cases", {"case": case.as_primitives()})
|
|
113
|
+
|
|
93
114
|
if added:
|
|
94
115
|
report.append(
|
|
95
116
|
{
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
"""Websocket and inter-pod communication API endpoints."""
|
|
2
|
+
|
|
1
3
|
import base64
|
|
2
4
|
import json
|
|
3
5
|
import os
|
|
@@ -11,8 +13,11 @@ import howler.services.viewer_service as viewer_service
|
|
|
11
13
|
from howler.api import ok, unauthorized
|
|
12
14
|
from howler.common.logging import get_logger
|
|
13
15
|
from howler.helper.ws import ConnectionClosed, Server
|
|
16
|
+
from howler.odm.models.user import User
|
|
14
17
|
from howler.security.login import api_login
|
|
15
18
|
from howler.security.socket import websocket_auth, ws_response
|
|
19
|
+
from howler.security.utils import is_classification_accessible
|
|
20
|
+
from howler.services import case_service
|
|
16
21
|
from howler.utils.socket_utils import check_action
|
|
17
22
|
|
|
18
23
|
HWL_INTERPOD_COMMS_SECRET = os.getenv("HWL_INTERPOD_COMMS_SECRET", "secret")
|
|
@@ -70,7 +75,7 @@ def get_viewers(entity_id: str, **kwargs): # pragma: no cover
|
|
|
70
75
|
@tracer.start_as_current_span(f"{__name__}.connect")
|
|
71
76
|
@socket_api.route("/connect", websocket=True) # type: ignore
|
|
72
77
|
@websocket_auth(required_priv=["R"])
|
|
73
|
-
def connect(ws: Server, *args: Any, ws_id: str, **kwargs): # noqa: C901
|
|
78
|
+
def connect(ws: Server, *args: Any, ws_id: str, user: User | None = None, **kwargs): # noqa: C901
|
|
74
79
|
"""Connect to the server to monitor for updates via websocket
|
|
75
80
|
|
|
76
81
|
Variables:
|
|
@@ -86,22 +91,39 @@ def connect(ws: Server, *args: Any, ws_id: str, **kwargs): # noqa: C901
|
|
|
86
91
|
outstanding_actions: list[tuple[str, str, bool]] = []
|
|
87
92
|
|
|
88
93
|
def send_hit(data: dict[str, Any]):
|
|
94
|
+
"""Send an access-controlled hit update to the websocket client."""
|
|
95
|
+
if user and user.classification:
|
|
96
|
+
if not is_classification_accessible(user, data["hit"].get("classification")):
|
|
97
|
+
return
|
|
98
|
+
|
|
89
99
|
logger.debug("Sending hit update: %s", data["hit"]["howler"]["id"])
|
|
90
100
|
ws.send(ws_response("hits", data))
|
|
91
101
|
|
|
92
102
|
def send_broadcast(data: dict[str, str]):
|
|
103
|
+
"""Send a broadcast event to the websocket client."""
|
|
93
104
|
logger.debug("Sending broadcast: %s", data)
|
|
94
105
|
ws.send(ws_response("broadcast", {"event": data}))
|
|
95
106
|
|
|
96
107
|
def send_action(data: dict[str, str]):
|
|
108
|
+
"""Send an action update to the websocket client."""
|
|
97
109
|
logger.debug("Sending action: %s", data)
|
|
98
110
|
ws.send(ws_response("action", data))
|
|
99
111
|
|
|
100
112
|
def send_case(data: dict[str, Any]): # pragma: no cover
|
|
101
|
-
|
|
102
|
-
|
|
113
|
+
"""Send an access-controlled case update to the websocket client."""
|
|
114
|
+
case_data = data.get("case", {})
|
|
115
|
+
|
|
116
|
+
if user and user.classification:
|
|
117
|
+
if not is_classification_accessible(user, case_data.get("classification")):
|
|
118
|
+
return
|
|
119
|
+
|
|
120
|
+
case_service.filter_case_items_by_classification(case_data, user.classification)
|
|
121
|
+
|
|
122
|
+
logger.debug("Sending case update: %s", case_data.get("case_id"))
|
|
123
|
+
ws.send(ws_response("cases", {**data, "case": case_data}))
|
|
103
124
|
|
|
104
125
|
def send_viewers_update(data: dict[str, Any]): # pragma: no cover
|
|
126
|
+
"""Send a viewer-presence update to the websocket client."""
|
|
105
127
|
logger.debug("Sending viewers update: %s", data.get("id", "unknown"))
|
|
106
128
|
ws.send(ws_response("viewers_update", data))
|
|
107
129
|
|
|
@@ -135,7 +157,12 @@ def connect(ws: Server, *args: Any, ws_id: str, **kwargs): # noqa: C901
|
|
|
135
157
|
return
|
|
136
158
|
|
|
137
159
|
outstanding_actions = check_action(
|
|
138
|
-
obj["id"],
|
|
160
|
+
obj["id"],
|
|
161
|
+
obj["action"],
|
|
162
|
+
obj["broadcast"],
|
|
163
|
+
outstanding_actions=outstanding_actions,
|
|
164
|
+
user=user,
|
|
165
|
+
**kwargs,
|
|
139
166
|
)
|
|
140
167
|
logger.debug("%s: Outstanding actions count=%s", ws_id, len(outstanding_actions))
|
|
141
168
|
else:
|
|
@@ -154,5 +181,12 @@ def connect(ws: Server, *args: Any, ws_id: str, **kwargs): # noqa: C901
|
|
|
154
181
|
comms_service.off("viewers_update", send_viewers_update)
|
|
155
182
|
|
|
156
183
|
for id, action, broadcast in outstanding_actions:
|
|
157
|
-
outstanding_actions = check_action(
|
|
184
|
+
outstanding_actions = check_action(
|
|
185
|
+
id,
|
|
186
|
+
action,
|
|
187
|
+
broadcast,
|
|
188
|
+
outstanding_actions=outstanding_actions,
|
|
189
|
+
user=user,
|
|
190
|
+
**kwargs,
|
|
191
|
+
)
|
|
158
192
|
logger.info("%s: WS connect handler finished", ws_id)
|