howler-api 3.0.0.dev374__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of howler-api might be problematic. Click here for more details.
- howler/__init__.py +0 -0
- howler/actions/__init__.py +168 -0
- howler/actions/add_label.py +111 -0
- howler/actions/add_to_bundle.py +159 -0
- howler/actions/change_field.py +76 -0
- howler/actions/demote.py +160 -0
- howler/actions/example_plugin.py +104 -0
- howler/actions/prioritization.py +93 -0
- howler/actions/promote.py +147 -0
- howler/actions/remove_from_bundle.py +133 -0
- howler/actions/remove_label.py +111 -0
- howler/actions/transition.py +200 -0
- howler/api/__init__.py +249 -0
- howler/api/base.py +88 -0
- howler/api/socket.py +114 -0
- howler/api/v1/__init__.py +97 -0
- howler/api/v1/action.py +372 -0
- howler/api/v1/analytic.py +748 -0
- howler/api/v1/auth.py +382 -0
- howler/api/v1/clue.py +99 -0
- howler/api/v1/configs.py +58 -0
- howler/api/v1/dossier.py +222 -0
- howler/api/v1/help.py +28 -0
- howler/api/v1/hit.py +1181 -0
- howler/api/v1/notebook.py +82 -0
- howler/api/v1/overview.py +191 -0
- howler/api/v1/search.py +788 -0
- howler/api/v1/template.py +206 -0
- howler/api/v1/tool.py +183 -0
- howler/api/v1/user.py +416 -0
- howler/api/v1/utils/__init__.py +0 -0
- howler/api/v1/utils/etag.py +84 -0
- howler/api/v1/view.py +288 -0
- howler/app.py +235 -0
- howler/common/README.md +125 -0
- howler/common/__init__.py +0 -0
- howler/common/classification.py +979 -0
- howler/common/classification.yml +107 -0
- howler/common/exceptions.py +167 -0
- howler/common/loader.py +154 -0
- howler/common/logging/__init__.py +241 -0
- howler/common/logging/audit.py +138 -0
- howler/common/logging/format.py +38 -0
- howler/common/net.py +79 -0
- howler/common/net_static.py +1494 -0
- howler/common/random_user.py +316 -0
- howler/common/swagger.py +117 -0
- howler/config.py +64 -0
- howler/cronjobs/__init__.py +29 -0
- howler/cronjobs/retention.py +61 -0
- howler/cronjobs/rules.py +274 -0
- howler/cronjobs/view_cleanup.py +88 -0
- howler/datastore/README.md +112 -0
- howler/datastore/__init__.py +0 -0
- howler/datastore/bulk.py +72 -0
- howler/datastore/collection.py +2342 -0
- howler/datastore/constants.py +119 -0
- howler/datastore/exceptions.py +41 -0
- howler/datastore/howler_store.py +105 -0
- howler/datastore/migrations/fix_process.py +41 -0
- howler/datastore/operations.py +130 -0
- howler/datastore/schemas.py +90 -0
- howler/datastore/store.py +231 -0
- howler/datastore/support/__init__.py +0 -0
- howler/datastore/support/build.py +215 -0
- howler/datastore/support/schemas.py +90 -0
- howler/datastore/types.py +22 -0
- howler/error.py +91 -0
- howler/external/__init__.py +0 -0
- howler/external/generate_mitre.py +96 -0
- howler/external/generate_sigma_rules.py +31 -0
- howler/external/generate_tlds.py +47 -0
- howler/external/reindex_data.py +66 -0
- howler/external/wipe_databases.py +58 -0
- howler/gunicorn_config.py +25 -0
- howler/healthz.py +47 -0
- howler/helper/__init__.py +0 -0
- howler/helper/azure.py +50 -0
- howler/helper/discover.py +59 -0
- howler/helper/hit.py +236 -0
- howler/helper/oauth.py +247 -0
- howler/helper/search.py +92 -0
- howler/helper/workflow.py +110 -0
- howler/helper/ws.py +378 -0
- howler/odm/README.md +102 -0
- howler/odm/__init__.py +1 -0
- howler/odm/base.py +1543 -0
- howler/odm/charter.txt +146 -0
- howler/odm/helper.py +416 -0
- howler/odm/howler_enum.py +25 -0
- howler/odm/models/__init__.py +0 -0
- howler/odm/models/action.py +33 -0
- howler/odm/models/analytic.py +90 -0
- howler/odm/models/assemblyline.py +48 -0
- howler/odm/models/aws.py +23 -0
- howler/odm/models/azure.py +16 -0
- howler/odm/models/cbs.py +44 -0
- howler/odm/models/config.py +558 -0
- howler/odm/models/dossier.py +33 -0
- howler/odm/models/ecs/__init__.py +0 -0
- howler/odm/models/ecs/agent.py +17 -0
- howler/odm/models/ecs/autonomous_system.py +16 -0
- howler/odm/models/ecs/client.py +149 -0
- howler/odm/models/ecs/cloud.py +141 -0
- howler/odm/models/ecs/code_signature.py +27 -0
- howler/odm/models/ecs/container.py +32 -0
- howler/odm/models/ecs/dns.py +62 -0
- howler/odm/models/ecs/egress.py +10 -0
- howler/odm/models/ecs/elf.py +74 -0
- howler/odm/models/ecs/email.py +122 -0
- howler/odm/models/ecs/error.py +14 -0
- howler/odm/models/ecs/event.py +140 -0
- howler/odm/models/ecs/faas.py +24 -0
- howler/odm/models/ecs/file.py +84 -0
- howler/odm/models/ecs/geo.py +30 -0
- howler/odm/models/ecs/group.py +18 -0
- howler/odm/models/ecs/hash.py +16 -0
- howler/odm/models/ecs/host.py +17 -0
- howler/odm/models/ecs/http.py +37 -0
- howler/odm/models/ecs/ingress.py +12 -0
- howler/odm/models/ecs/interface.py +21 -0
- howler/odm/models/ecs/network.py +30 -0
- howler/odm/models/ecs/observer.py +45 -0
- howler/odm/models/ecs/organization.py +12 -0
- howler/odm/models/ecs/os.py +21 -0
- howler/odm/models/ecs/pe.py +17 -0
- howler/odm/models/ecs/process.py +216 -0
- howler/odm/models/ecs/registry.py +26 -0
- howler/odm/models/ecs/related.py +45 -0
- howler/odm/models/ecs/rule.py +51 -0
- howler/odm/models/ecs/server.py +24 -0
- howler/odm/models/ecs/threat.py +247 -0
- howler/odm/models/ecs/tls.py +58 -0
- howler/odm/models/ecs/url.py +51 -0
- howler/odm/models/ecs/user.py +57 -0
- howler/odm/models/ecs/user_agent.py +20 -0
- howler/odm/models/ecs/vulnerability.py +41 -0
- howler/odm/models/gcp.py +16 -0
- howler/odm/models/hit.py +356 -0
- howler/odm/models/howler_data.py +328 -0
- howler/odm/models/lead.py +24 -0
- howler/odm/models/localized_label.py +13 -0
- howler/odm/models/overview.py +16 -0
- howler/odm/models/pivot.py +40 -0
- howler/odm/models/template.py +24 -0
- howler/odm/models/user.py +83 -0
- howler/odm/models/view.py +34 -0
- howler/odm/random_data.py +888 -0
- howler/odm/randomizer.py +609 -0
- howler/patched.py +5 -0
- howler/plugins/__init__.py +25 -0
- howler/plugins/config.py +123 -0
- howler/remote/__init__.py +0 -0
- howler/remote/datatypes/README.md +355 -0
- howler/remote/datatypes/__init__.py +98 -0
- howler/remote/datatypes/counters.py +63 -0
- howler/remote/datatypes/events.py +66 -0
- howler/remote/datatypes/hash.py +206 -0
- howler/remote/datatypes/lock.py +42 -0
- howler/remote/datatypes/queues/__init__.py +0 -0
- howler/remote/datatypes/queues/comms.py +59 -0
- howler/remote/datatypes/queues/multi.py +32 -0
- howler/remote/datatypes/queues/named.py +93 -0
- howler/remote/datatypes/queues/priority.py +215 -0
- howler/remote/datatypes/set.py +118 -0
- howler/remote/datatypes/user_quota_tracker.py +54 -0
- howler/security/__init__.py +253 -0
- howler/security/socket.py +108 -0
- howler/security/utils.py +185 -0
- howler/services/__init__.py +0 -0
- howler/services/action_service.py +111 -0
- howler/services/analytic_service.py +128 -0
- howler/services/auth_service.py +323 -0
- howler/services/config_service.py +128 -0
- howler/services/dossier_service.py +252 -0
- howler/services/event_service.py +93 -0
- howler/services/hit_service.py +893 -0
- howler/services/jwt_service.py +158 -0
- howler/services/lucene_service.py +286 -0
- howler/services/notebook_service.py +119 -0
- howler/services/overview_service.py +44 -0
- howler/services/template_service.py +45 -0
- howler/services/user_service.py +331 -0
- howler/utils/__init__.py +0 -0
- howler/utils/annotations.py +28 -0
- howler/utils/chunk.py +38 -0
- howler/utils/dict_utils.py +200 -0
- howler/utils/isotime.py +17 -0
- howler/utils/list_utils.py +11 -0
- howler/utils/lucene.py +77 -0
- howler/utils/path.py +27 -0
- howler/utils/socket_utils.py +61 -0
- howler/utils/str_utils.py +256 -0
- howler/utils/uid.py +47 -0
- howler_api-3.0.0.dev374.dist-info/METADATA +71 -0
- howler_api-3.0.0.dev374.dist-info/RECORD +198 -0
- howler_api-3.0.0.dev374.dist-info/WHEEL +4 -0
- howler_api-3.0.0.dev374.dist-info/entry_points.txt +8 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
from howler import odm
|
|
2
|
+
|
|
3
|
+
EVENT_CATEGORIES = [
|
|
4
|
+
"authentication",
|
|
5
|
+
"configuration",
|
|
6
|
+
"database",
|
|
7
|
+
"driver",
|
|
8
|
+
"email",
|
|
9
|
+
"file",
|
|
10
|
+
"host",
|
|
11
|
+
"iam",
|
|
12
|
+
"intrusion_detection",
|
|
13
|
+
"malware",
|
|
14
|
+
"network",
|
|
15
|
+
"package",
|
|
16
|
+
"process",
|
|
17
|
+
"registry",
|
|
18
|
+
"session",
|
|
19
|
+
"threat",
|
|
20
|
+
"web",
|
|
21
|
+
]
|
|
22
|
+
EVENT_KIND = [
|
|
23
|
+
"alert",
|
|
24
|
+
"enrichment",
|
|
25
|
+
"event",
|
|
26
|
+
"metric",
|
|
27
|
+
"state",
|
|
28
|
+
"pipeline_error",
|
|
29
|
+
"signal",
|
|
30
|
+
]
|
|
31
|
+
EVENT_TYPE = [
|
|
32
|
+
"access",
|
|
33
|
+
"admin",
|
|
34
|
+
"allowed",
|
|
35
|
+
"change",
|
|
36
|
+
"connection",
|
|
37
|
+
"creation",
|
|
38
|
+
"deletion",
|
|
39
|
+
"denied",
|
|
40
|
+
"end",
|
|
41
|
+
"error",
|
|
42
|
+
"group",
|
|
43
|
+
"indicator",
|
|
44
|
+
"info",
|
|
45
|
+
"installation",
|
|
46
|
+
"protocol",
|
|
47
|
+
"start",
|
|
48
|
+
"user",
|
|
49
|
+
]
|
|
50
|
+
EVENT_OUTCOME = ["failure", "success", "unknown"]
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@odm.model(
|
|
54
|
+
index=True,
|
|
55
|
+
store=True,
|
|
56
|
+
description="The event fields are used for context information about the log or metric event itself.",
|
|
57
|
+
)
|
|
58
|
+
class Event(odm.Model):
|
|
59
|
+
action = odm.Optional(odm.Keyword(description="The action captured by the event."))
|
|
60
|
+
category = odm.Optional(
|
|
61
|
+
odm.List(
|
|
62
|
+
odm.Enum(values=EVENT_CATEGORIES),
|
|
63
|
+
description='Represents the "big buckets" of ECS categories. For example, filtering on '
|
|
64
|
+
"event.category:process yields all events relating to process activity. This field is closely "
|
|
65
|
+
"related to event.type, which is used as a subcategory.",
|
|
66
|
+
)
|
|
67
|
+
)
|
|
68
|
+
code = odm.Optional(odm.Keyword(description="Identification code for this event, if one exists."))
|
|
69
|
+
count = odm.Integer(description="Count of events", optional=True)
|
|
70
|
+
created = odm.Optional(
|
|
71
|
+
odm.Date(description="Contains the date/time when the event was first read by an agent, or by your pipeline.")
|
|
72
|
+
)
|
|
73
|
+
dataset = odm.Optional(odm.Keyword(description="Name of the dataset."))
|
|
74
|
+
duration = odm.Optional(odm.Integer(description="Duration of the event in nanoseconds."))
|
|
75
|
+
end = odm.Optional(
|
|
76
|
+
odm.Date(description="Contains the date when the event ended or when the activity was last observed.")
|
|
77
|
+
)
|
|
78
|
+
hash = odm.Optional(
|
|
79
|
+
odm.Keyword(
|
|
80
|
+
description="Hash (perhaps logstash fingerprint) of raw field to be able to demonstrate log integrity."
|
|
81
|
+
)
|
|
82
|
+
)
|
|
83
|
+
id = odm.Optional(odm.Keyword(description="Unique ID to describe the event."))
|
|
84
|
+
ingested = odm.Date(
|
|
85
|
+
default="NOW",
|
|
86
|
+
description="Timestamp when an event arrived in the central data store.",
|
|
87
|
+
)
|
|
88
|
+
kind = odm.Optional(
|
|
89
|
+
odm.Enum(
|
|
90
|
+
values=EVENT_KIND,
|
|
91
|
+
description="Gives high-level information about what type of information the event "
|
|
92
|
+
"contains, without being specific to the contents of the event. ",
|
|
93
|
+
)
|
|
94
|
+
)
|
|
95
|
+
module = odm.Optional(odm.Keyword(description="Name of the module this data is coming from."))
|
|
96
|
+
original = odm.Optional(
|
|
97
|
+
odm.Keyword(
|
|
98
|
+
description="Raw text message of entire event. Used to demonstrate log integrity or where the "
|
|
99
|
+
"full log message (before splitting it up in multiple parts) may be required, e.g. for reindex."
|
|
100
|
+
)
|
|
101
|
+
)
|
|
102
|
+
outcome = odm.Optional(
|
|
103
|
+
odm.Enum(
|
|
104
|
+
values=EVENT_OUTCOME,
|
|
105
|
+
description="Simply denotes whether the event represents a success or "
|
|
106
|
+
"a failure from the perspective of the entity that produced the event.",
|
|
107
|
+
)
|
|
108
|
+
)
|
|
109
|
+
provider = odm.Optional(odm.Keyword(description="Source of the event."))
|
|
110
|
+
reason = odm.Optional(odm.Keyword(description="Reason why this event happened, according to the source."))
|
|
111
|
+
reference = odm.Optional(
|
|
112
|
+
odm.Keyword(description="Reference URL linking to additional information about this event.")
|
|
113
|
+
)
|
|
114
|
+
risk_score = odm.Optional(odm.Float(description="Risk score or priority of the event (e.g. security solutions)."))
|
|
115
|
+
risk_score_norm = odm.Optional(
|
|
116
|
+
odm.Float(description="Normalized risk score or priority of the event, on a scale of 0 to 100.")
|
|
117
|
+
)
|
|
118
|
+
sequence = odm.Optional(odm.Integer(description="Sequence number of the event."))
|
|
119
|
+
severity = odm.Optional(
|
|
120
|
+
odm.Integer(description="The numeric severity of the event according to your event source.")
|
|
121
|
+
)
|
|
122
|
+
start = odm.Optional(
|
|
123
|
+
odm.Date(description="Contains the date when the event started or when the activity was first observed.")
|
|
124
|
+
)
|
|
125
|
+
timezone = odm.Optional(
|
|
126
|
+
odm.Keyword(
|
|
127
|
+
description="This field should be populated when the event’s timestamp does not include timezone "
|
|
128
|
+
"information already (e.g. default Syslog timestamps)."
|
|
129
|
+
)
|
|
130
|
+
)
|
|
131
|
+
type = odm.Optional(
|
|
132
|
+
odm.List(
|
|
133
|
+
odm.Enum(values=EVENT_TYPE),
|
|
134
|
+
description='Represents a categorization "sub-bucket" that, when used along with the event.category '
|
|
135
|
+
"field values, enables filtering events down to a level appropriate for single visualization.",
|
|
136
|
+
)
|
|
137
|
+
)
|
|
138
|
+
url = odm.Optional(
|
|
139
|
+
odm.Keyword(description="URL linking to an external system to continue investigation of this event.")
|
|
140
|
+
)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from howler import odm
|
|
2
|
+
|
|
3
|
+
TRIGGER_TYPES = ["http", "pubsub", "datasource", "timer", "other"]
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@odm.model(index=True, store=True, description="Details about the function trigger.")
|
|
7
|
+
class Trigger(odm.Model):
|
|
8
|
+
request_id = odm.Optional(odm.Keyword(description="The ID of the trigger request , message, event, etc."))
|
|
9
|
+
type = odm.Optional(odm.Enum(values=TRIGGER_TYPES, description="The trigger for the function execution."))
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@odm.model(
|
|
13
|
+
index=True,
|
|
14
|
+
store=True,
|
|
15
|
+
description="The user fields describe information about the function as a "
|
|
16
|
+
"service (FaaS) that is relevant to the event.",
|
|
17
|
+
)
|
|
18
|
+
class FAAS(odm.Model):
|
|
19
|
+
coldstart = odm.Optional(odm.Boolean(description="Boolean value indicating a cold start of a function."))
|
|
20
|
+
execution = odm.Optional(odm.Keyword(description="The execution ID of the current function execution."))
|
|
21
|
+
id = odm.Optional(odm.Keyword(description="The unique identifier of a serverless function."))
|
|
22
|
+
name = odm.Optional(odm.Keyword(description="The name of a serverless function."))
|
|
23
|
+
trigger = odm.Optional(odm.Compound(Trigger, description="Details about the function trigger."))
|
|
24
|
+
version = odm.Optional(odm.Keyword(description="The version of a serverless function."))
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from howler import odm
|
|
4
|
+
from howler.odm.models.ecs.code_signature import CodeSignature
|
|
5
|
+
from howler.odm.models.ecs.elf import ELF
|
|
6
|
+
from howler.odm.models.ecs.hash import Hashes
|
|
7
|
+
from howler.odm.models.ecs.pe import PE
|
|
8
|
+
|
|
9
|
+
# from howler.odm.models.ecs.x509 import X509
|
|
10
|
+
|
|
11
|
+
FILE_TYPE = ["file", "dir", "symlink"]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@odm.model(
|
|
15
|
+
index=True,
|
|
16
|
+
store=True,
|
|
17
|
+
description="A file is defined as a set of information that has "
|
|
18
|
+
"been created on, or has existed on a filesystem.",
|
|
19
|
+
)
|
|
20
|
+
class File(odm.Model):
|
|
21
|
+
accessed: Optional[str] = odm.Optional(odm.Date(description="Last time the file was accessed."))
|
|
22
|
+
attributes: Optional[list[str]] = odm.Optional(odm.List(odm.Keyword(), description="Array of file attributes."))
|
|
23
|
+
created: Optional[str] = odm.Optional(odm.Date(description="File creation time."))
|
|
24
|
+
ctime: Optional[str] = odm.Optional(odm.Date(description="Last time the file attributes or metadata changed."))
|
|
25
|
+
device: Optional[str] = odm.Optional(odm.Keyword(description="Device that is the source of the file."))
|
|
26
|
+
directory: Optional[str] = odm.Optional(
|
|
27
|
+
odm.Keyword(
|
|
28
|
+
description="Directory where the file is located. It should include the drive letter, when appropriate."
|
|
29
|
+
)
|
|
30
|
+
)
|
|
31
|
+
drive_letter: Optional[str] = odm.Optional(
|
|
32
|
+
odm.Keyword(description="Drive letter where the file is located. This field is only relevant on Windows.")
|
|
33
|
+
)
|
|
34
|
+
extension: Optional[str] = odm.Optional(odm.Keyword(description="File extension, excluding the leading dot."))
|
|
35
|
+
fork_name: Optional[str] = odm.Optional(
|
|
36
|
+
odm.Keyword(description="A fork is additional data associated with a filesystem object.")
|
|
37
|
+
)
|
|
38
|
+
gid: Optional[str] = odm.Optional(odm.Keyword(description="Primary group ID (GID) of the file."))
|
|
39
|
+
group: Optional[str] = odm.Optional(odm.Keyword(description="Primary group name of the file."))
|
|
40
|
+
inode: Optional[str] = odm.Optional(odm.Keyword(description="Inode representing the file in the filesystem."))
|
|
41
|
+
mime_type: Optional[str] = odm.Optional(
|
|
42
|
+
odm.Keyword(
|
|
43
|
+
description="MIME type should identify the format of the file or stream of "
|
|
44
|
+
"bytes using IANA official types, where possible."
|
|
45
|
+
)
|
|
46
|
+
)
|
|
47
|
+
mode: Optional[str] = odm.Optional(odm.Keyword(description="Mode of the file in octal representation."))
|
|
48
|
+
mtime: Optional[str] = odm.Optional(odm.Date(description="Last time the file content was modified."))
|
|
49
|
+
name: Optional[str] = odm.Optional(
|
|
50
|
+
odm.Keyword(description="Name of the file including the extension, without the directory.")
|
|
51
|
+
)
|
|
52
|
+
owner: Optional[str] = odm.Optional(odm.Keyword(description="File owner’s username."))
|
|
53
|
+
path: Optional[str] = odm.Optional(
|
|
54
|
+
odm.Keyword(
|
|
55
|
+
description="Full path to the file, including the file name. "
|
|
56
|
+
"It should include the drive letter, when appropriate."
|
|
57
|
+
)
|
|
58
|
+
)
|
|
59
|
+
size: Optional[int] = odm.Integer(description="File size in bytes.", optional=True)
|
|
60
|
+
target_path: Optional[str] = odm.Optional(odm.Keyword(description="Target path for symlinks."))
|
|
61
|
+
type: Optional[str] = odm.Optional(odm.Enum(values=FILE_TYPE, description="File type (file, dir, or symlink)."))
|
|
62
|
+
uid: Optional[str] = odm.Optional(
|
|
63
|
+
odm.Keyword(description="The user ID (UID) or security identifier (SID) of the file owner.")
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
code_signature: Optional[CodeSignature] = odm.Optional(
|
|
67
|
+
odm.Compound(
|
|
68
|
+
CodeSignature,
|
|
69
|
+
description="These fields contain information about binary code signatures.",
|
|
70
|
+
)
|
|
71
|
+
)
|
|
72
|
+
elf: Optional[ELF] = odm.Optional(
|
|
73
|
+
odm.Compound(
|
|
74
|
+
ELF,
|
|
75
|
+
description="These fields contain Linux Executable Linkable Format (ELF) metadata.",
|
|
76
|
+
)
|
|
77
|
+
)
|
|
78
|
+
hash: Optional[Hashes] = odm.Optional(
|
|
79
|
+
odm.Compound(
|
|
80
|
+
Hashes,
|
|
81
|
+
description="These fields contain Windows Portable Executable (PE) metadata.",
|
|
82
|
+
)
|
|
83
|
+
)
|
|
84
|
+
pe: Optional[PE] = odm.Optional(odm.Compound(PE, description="Hashes, usually file hashes."))
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from howler import odm
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
@odm.model(index=True, store=True, description="Longitude and latitude.")
|
|
5
|
+
class GeoPoint(odm.Model):
|
|
6
|
+
lon = odm.Float(description="Longitude")
|
|
7
|
+
lat = odm.Float(description="Latitude")
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@odm.model(
|
|
11
|
+
index=True,
|
|
12
|
+
store=True,
|
|
13
|
+
description="Geo fields can carry data about a specific location related to an event.",
|
|
14
|
+
)
|
|
15
|
+
class Geo(odm.Model):
|
|
16
|
+
city_name = odm.Optional(odm.Keyword(description="City name."))
|
|
17
|
+
continent_code = odm.Optional(odm.Keyword(description="Two-letter code representing continent’s name."))
|
|
18
|
+
continent_name = odm.Optional(odm.Keyword(description="Name of the continent."))
|
|
19
|
+
country_iso_code = odm.Optional(odm.Keyword(description="Country ISO code."))
|
|
20
|
+
country_name = odm.Optional(odm.Keyword(description="Country name."))
|
|
21
|
+
location = odm.Optional(odm.Compound(GeoPoint, description="Longitude and latitude."))
|
|
22
|
+
name = odm.Optional(
|
|
23
|
+
odm.Keyword(
|
|
24
|
+
description="User-defined description of a location, at the level " "of granularity they care about."
|
|
25
|
+
)
|
|
26
|
+
)
|
|
27
|
+
postal_code = odm.Optional(odm.Keyword(description="Postal code associated with the location."))
|
|
28
|
+
region_iso_code = odm.Optional(odm.Keyword(description="Region ISO code."))
|
|
29
|
+
region_name = odm.Optional(odm.Keyword(description="Region name."))
|
|
30
|
+
timezone = odm.Optional(odm.Keyword(description="The time zone of the location, such as IANA time zone name."))
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from howler import odm
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
@odm.model(
|
|
5
|
+
index=True,
|
|
6
|
+
store=True,
|
|
7
|
+
description="The group fields are meant to represent groups that are relevant to the event.",
|
|
8
|
+
)
|
|
9
|
+
class Group(odm.Model):
|
|
10
|
+
domain = odm.Optional(odm.Keyword(description="Name of the directory the group is a member of."))
|
|
11
|
+
id = odm.Optional(odm.Keyword(description="Unique identifier for the group on the system/platform."))
|
|
12
|
+
name = odm.Optional(odm.Keyword(description="Name of the group."))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@odm.model(index=True, store=True, description="Shorter representation of a group.")
|
|
16
|
+
class ShortGroup(odm.Model):
|
|
17
|
+
id = odm.Optional(odm.Keyword(description="Unique identifier for the group on the system/platform."))
|
|
18
|
+
name = odm.Optional(odm.Keyword(description="Name of the group."))
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from howler import odm
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
@odm.model(
|
|
5
|
+
index=True,
|
|
6
|
+
store=True,
|
|
7
|
+
description="The hash fields represent different bitwise hash algorithms and their values.",
|
|
8
|
+
)
|
|
9
|
+
class Hashes(odm.Model):
|
|
10
|
+
md5 = odm.Optional(odm.MD5(description="MD5 hash."))
|
|
11
|
+
sha1 = odm.Optional(odm.SHA1(description="SHA1 hash."))
|
|
12
|
+
sha256 = odm.Optional(odm.SHA256(description="SHA256 hash."))
|
|
13
|
+
sha384 = odm.Optional(odm.ValidatedKeyword(r"^[a-f0-9]{96}$", description="SHA384 hash."))
|
|
14
|
+
sha512 = odm.Optional(odm.ValidatedKeyword(r"^[a-f0-9]{128}$", description="SHA512 hash."))
|
|
15
|
+
ssdeep = odm.Optional(odm.SSDeepHash(description="SSDEEP hash."))
|
|
16
|
+
tlsh = odm.Optional(odm.Keyword(description="TLSH hash."))
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from howler import odm
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@odm.model(
|
|
7
|
+
index=True,
|
|
8
|
+
store=True,
|
|
9
|
+
description=("A host is defined as a general computing instance."),
|
|
10
|
+
)
|
|
11
|
+
class Host(odm.Model):
|
|
12
|
+
id: Optional[str] = odm.Optional(odm.Keyword(description="Unique host id. Use Agent ID for HBS."))
|
|
13
|
+
ip: list[str] = odm.List(odm.IP(), default=[], description="Host ip addresses.")
|
|
14
|
+
mac: list[str] = odm.List(odm.Keyword(), default=[], description="Host MAC addresses.")
|
|
15
|
+
name: Optional[str] = odm.Optional(odm.Keyword(description="Name of the host."))
|
|
16
|
+
domain: Optional[str] = odm.Optional(odm.Keyword(description="Domain the host is a member of."))
|
|
17
|
+
type: Optional[str] = odm.Optional(odm.Keyword(description="As described by CSP."))
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from howler import odm
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
@odm.model(index=True, store=True, description="Defines the body of a request/response.")
|
|
5
|
+
class Body(odm.Model):
|
|
6
|
+
bytes = odm.Optional(odm.Integer(description="Size in bytes of the body."))
|
|
7
|
+
content = odm.Optional(odm.Keyword(description="The full HTTP body."))
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@odm.model(index=True, store=True, description="These fields can represent errors of any kind.")
|
|
11
|
+
class Request(odm.Model):
|
|
12
|
+
body = odm.Optional(odm.Compound(Body, description="Defines the body of a request"))
|
|
13
|
+
bytes = odm.Optional(odm.Integer(description="Total size in bytes of the request (body and headers)."))
|
|
14
|
+
id = odm.Optional(
|
|
15
|
+
odm.Keyword(
|
|
16
|
+
description="A unique identifier for each HTTP request to correlate logs between clients "
|
|
17
|
+
"and servers in transactions."
|
|
18
|
+
)
|
|
19
|
+
)
|
|
20
|
+
method = odm.Optional(odm.Keyword(description="HTTP request method."))
|
|
21
|
+
mime_type = odm.Optional(odm.Keyword(description="Mime type of the body of the request."))
|
|
22
|
+
referrer = odm.Optional(odm.Keyword(description="Referrer for this HTTP request."))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@odm.model(index=True, store=True, description="These fields can represent errors of any kind.")
|
|
26
|
+
class Response(odm.Model):
|
|
27
|
+
body = odm.Optional(odm.Compound(Body, description="Defines the body of a response"))
|
|
28
|
+
bytes = odm.Optional(odm.Integer(description="Total size in bytes of the request (body and headers)."))
|
|
29
|
+
mime_type = odm.Optional(odm.Keyword(description="Mime type of the body of the request."))
|
|
30
|
+
status_code = odm.Optional(odm.Integer(description="HTTP response status code."))
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@odm.model(index=True, store=True, description="These fields can represent errors of any kind.")
|
|
34
|
+
class HTTP(odm.Model):
|
|
35
|
+
request = odm.Optional(odm.Compound(Request, description="Request data."))
|
|
36
|
+
response = odm.Optional(odm.Compound(Response, description="Response data."))
|
|
37
|
+
version = odm.Optional(odm.Keyword(description="HTTP version."))
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from howler import odm
|
|
2
|
+
from howler.odm.models.ecs.interface import Interface
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@odm.model(
|
|
6
|
+
index=True,
|
|
7
|
+
store=True,
|
|
8
|
+
description="Holds information like interface number, name, vlan, and zone to classify ingress traffic",
|
|
9
|
+
)
|
|
10
|
+
class Ingress(odm.Model):
|
|
11
|
+
zone = odm.Optional(odm.Keyword(description="Network zone of incoming traffic as reported by observer"))
|
|
12
|
+
interface = odm.Optional(odm.Compound(Interface, description="Ingress Interface"))
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from howler import odm
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@odm.model(
|
|
7
|
+
index=True,
|
|
8
|
+
store=True,
|
|
9
|
+
description=(
|
|
10
|
+
"The interface fields are used to record ingress and egress interface information when reported by "
|
|
11
|
+
"an observer (e.g. firewall, router, load balancer) in the context of the observer handling a network "
|
|
12
|
+
"connection."
|
|
13
|
+
),
|
|
14
|
+
)
|
|
15
|
+
class Interface(odm.Model):
|
|
16
|
+
id: Optional[int] = odm.Integer(
|
|
17
|
+
description="Interface ID as reported by an observer (typically SNMP interface ID).", optional=True
|
|
18
|
+
)
|
|
19
|
+
name: Optional[str] = odm.Optional(
|
|
20
|
+
odm.Keyword(description="Name of interface"),
|
|
21
|
+
)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from howler import odm
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@odm.model(
|
|
7
|
+
index=True,
|
|
8
|
+
store=True,
|
|
9
|
+
description="The network is defined as the communication path over which a host or network event happens.",
|
|
10
|
+
)
|
|
11
|
+
class Network(odm.Model):
|
|
12
|
+
direction: Optional[str] = odm.Keyword(
|
|
13
|
+
description=(
|
|
14
|
+
"The direction of network traffic relative to the host it was collected on. "
|
|
15
|
+
'(values: "OUTBOUND", "INBOUND", "LISTENING", "UNKNOWN")'
|
|
16
|
+
),
|
|
17
|
+
optional=True,
|
|
18
|
+
)
|
|
19
|
+
protocol = odm.Optional(
|
|
20
|
+
odm.Keyword(
|
|
21
|
+
description="Application layer protocol in the OSI Model",
|
|
22
|
+
)
|
|
23
|
+
)
|
|
24
|
+
transport = odm.LowerKeyword(
|
|
25
|
+
description=(
|
|
26
|
+
"Transport layer protocol of the network traffic. "
|
|
27
|
+
'(values: "udp", "udp_listener", "tcp", "tcp_listener", "unknown")'
|
|
28
|
+
),
|
|
29
|
+
optional=True,
|
|
30
|
+
)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
from howler import odm
|
|
2
|
+
from howler.odm.models.ecs.egress import Egress
|
|
3
|
+
from howler.odm.models.ecs.ingress import Ingress
|
|
4
|
+
from howler.odm.models.ecs.interface import Interface
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@odm.model(
|
|
8
|
+
index=True,
|
|
9
|
+
store=True,
|
|
10
|
+
description=(
|
|
11
|
+
"Observer is defined as a special network, security, or application device used to detect, observe, "
|
|
12
|
+
"or create network, sercurity, or application event metrics"
|
|
13
|
+
),
|
|
14
|
+
)
|
|
15
|
+
class Observer(odm.Model):
|
|
16
|
+
egress = odm.Optional(
|
|
17
|
+
odm.Compound(
|
|
18
|
+
Egress,
|
|
19
|
+
description="Holds information like interface number, name, vlan, and zone to classify ingress traffic",
|
|
20
|
+
)
|
|
21
|
+
)
|
|
22
|
+
hostname = odm.Optional(odm.Keyword(description="Hostname of the observer"))
|
|
23
|
+
ingress = odm.Optional(
|
|
24
|
+
odm.Compound(
|
|
25
|
+
Ingress,
|
|
26
|
+
description="Holds information like interface number, name, vlan, and zone to classify ingress traffic",
|
|
27
|
+
)
|
|
28
|
+
)
|
|
29
|
+
interface = odm.Optional(
|
|
30
|
+
odm.Compound(
|
|
31
|
+
Interface,
|
|
32
|
+
description="Interface being observed",
|
|
33
|
+
)
|
|
34
|
+
)
|
|
35
|
+
ip = odm.List(odm.IP(description="IP addresses of the observer."), default=[])
|
|
36
|
+
mac = odm.List(
|
|
37
|
+
odm.Keyword(description="Mac addresses of the observer."),
|
|
38
|
+
default=[],
|
|
39
|
+
)
|
|
40
|
+
name = odm.Optional(odm.Keyword(description="Custom name of the observer"))
|
|
41
|
+
product = odm.Optional(odm.Keyword(description="Product name of the observer"))
|
|
42
|
+
serial_number = odm.Optional(odm.Keyword(description="Observer serial number"))
|
|
43
|
+
type = odm.Optional(odm.Keyword(description="Type of the observer the data is coming from"))
|
|
44
|
+
vendor = odm.Optional(odm.Keyword(description="Vendor name of the observer"))
|
|
45
|
+
version = odm.Optional(odm.Keyword(description="Observer version"))
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from howler import odm
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
@odm.model(
|
|
5
|
+
index=True,
|
|
6
|
+
store=True,
|
|
7
|
+
description="The organization fields enrich data with information "
|
|
8
|
+
"about the company or entity the data is associated with.",
|
|
9
|
+
)
|
|
10
|
+
class Organization(odm.Model):
|
|
11
|
+
id = odm.Optional(odm.Keyword(description="Unique identifier for the organization."))
|
|
12
|
+
name = odm.Keyword(description="Organization name.")
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from howler import odm
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
@odm.model(
|
|
5
|
+
index=True,
|
|
6
|
+
store=True,
|
|
7
|
+
description="The OS fields contain information about the operating system.",
|
|
8
|
+
)
|
|
9
|
+
class OS(odm.Model):
|
|
10
|
+
family = odm.Optional(odm.Keyword(description="OS family (such as redhat, debian, freebsd, windows)."))
|
|
11
|
+
full = odm.Optional(odm.Keyword(description="Operating system name, including the version or code name."))
|
|
12
|
+
kernel = odm.Optional(odm.Keyword(description="Operating system kernel version as a raw string."))
|
|
13
|
+
name = odm.Optional(odm.Keyword(description="Operating system name, without the version."))
|
|
14
|
+
platform = odm.Optional(odm.Keyword(description="Operating system platform (such centos, ubuntu, windows)."))
|
|
15
|
+
type = odm.Optional(
|
|
16
|
+
odm.Keyword(
|
|
17
|
+
description="Use the os.type field to categorize the operating "
|
|
18
|
+
"system into one of the broad commercial families."
|
|
19
|
+
)
|
|
20
|
+
)
|
|
21
|
+
version = odm.Optional(odm.Keyword(description="Operating system version as a raw string."))
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from howler import odm
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
@odm.model(
|
|
5
|
+
index=True,
|
|
6
|
+
store=True,
|
|
7
|
+
description="These fields contain Windows Portable Executable (PE) metadata.",
|
|
8
|
+
)
|
|
9
|
+
class PE(odm.Model):
|
|
10
|
+
architecture = odm.Optional(odm.Keyword(description="CPU architecture target for the file."))
|
|
11
|
+
company = odm.Optional(odm.Keyword(description="Internal company name of the file, provided at compile-time."))
|
|
12
|
+
description = odm.Optional(odm.Keyword(description="Internal description of the file, provided at compile-time."))
|
|
13
|
+
file_version = odm.Optional(odm.Keyword(description="Internal version of the file, provided at compile-time."))
|
|
14
|
+
imphash = odm.Optional(odm.Keyword(description="A hash of the imports in a PE file."))
|
|
15
|
+
original_file_name = odm.Optional(odm.Keyword(description="Internal name of the file, provided at compile-time."))
|
|
16
|
+
pehash = odm.Optional(odm.Keyword(description="A hash of the PE header and data from one or more PE sections."))
|
|
17
|
+
product = odm.Optional(odm.Keyword(description="Internal product name of the file, provided at compile-time."))
|