-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdatastructures.py
290 lines (225 loc) · 7.75 KB
/
datastructures.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
from dataclasses import dataclass, field
from typing import Any, Union
from helperfunctions import *
import os, sys, math, datetime, time
@dataclass()
class Time:
"""
Class to represent a specific time value.
Will initialize itself to instantiation time if no values given.
:hour: (int) hour value
:minute: (int) minute value
:second: (int) optional seconds value
:return: None.
"""
hour: int = -1
minute: int = -1
second: int = None
def __post_init__(self, *args, **kwargs) -> None:
# Sets default values to instantiation time if not passed in
if self.hour == -1 or self.minute == -1:
# checks if the minute or hour was not set
pass
else:
# if both were set, return b/c no change required
return
# if at least one was not set, set them both to instantiation time
temp = time.localtime()
self.hour = temp[3]
self.minute = temp[4]
# Never add a seconds value if it was not passed in
# self._second = temp[5]
def set_time(self, *args, **kwargs) -> None:
# TODO: time setter to make user prompting easier
pass
def pretty_print(self, *args, **kwargs) -> str:
hour, min = prt_conv_hlpr(self.hour), prt_conv_hlpr(self.minute)
if self.second:
return f"{hour}:{min}:{self.second}"
else:
return f"{hour}:{min}"
def __str__(self, *args, **kwargs) -> str:
return self.pretty_print()
@dataclass()
class Date:
year: int = -1
month: int = -1
day: int = -1
def __post_init__(self, *args, **kwargs) -> None:
temp = time.localtime()
# TODO: Finish this. Need to move more stuff before spending more time here.
if self.year == -1 or self.month == -1 or self.day == -1:
# check if values passed in. If not, set to instantiation date.
pass
else:
if self.year == temp[0] and self.month == temp[0] and self.day == temp[0]:
# Catches if date agrees with current date
# If so, returns as date is likely correct.
return
elif (self.year + 1 == temp[0] or self.year - 1 == temp[0]) and (
self.month == 1 or self.month == 12
):
# Checks to see if the year is off by 1 around New Year's
# Goal: prevent issues around 01jan.
pass
else:
# Check for wildly incorrect year
# if caught, replaces with current year.
self.year = temp[0]
# TODO: Checks on month and day.
self.year = temp[0]
self.month = temp[1]
self.day = temp[2]
def _pp_day_conversion(self, *args, **kwargs) -> str:
if self.day >= 10:
return str(self.day)
else:
return "0" + str(self.day)
def __str__(self, *args, **kwargs) -> str:
return self._pretty_print(args, kwargs)
def _pretty_print(self, *args, **kwargs) -> str:
# returns a date in format "daymonthyear" formatted like "02apr2022".
return (
f"{self._pp_day_conversion()}{month_num_to_ltr_conv(self.month)}{self.year}"
)
@dataclass()
class Source:
source: str = "sysmon"
def __post_init__(self, *args, **kwargs) -> None:
self._source = self.source.strip().lower()
def __str__(self, *args, **kwargs) -> str:
return self._prettyprint(args, kwargs)
def _prettyprint(self, *args, **kwargs) -> str:
return f"{self.source}"
@dataclass()
class Signal:
name: str = ""
source: Source = None
details: list = None
def __post_init__(self, *args, **kwargs):
self.details = list()
def add_details(self, *args, **kwargs) -> None:
# pass in the additional details via *args
# TODO: Make this better??? It seems too simple
for item in args:
self.details.append(str(item))
def _prettyprint(self, *args, **kwargs) -> str:
description = ""
for line in self.details:
description += f"{line}\n\t"
return f"{self.name.capitalize()}\nSource: {self.source}\n\y{description}\n"
def __str__(self, *args, **kwargs) -> str:
return self._prettyprint(args, kwargs)
@dataclass()
class Entity:
name: str = ""
_set: bool = None
def __post_init__(self, *args, **kwargs) -> None:
if self.name == "":
self._set = False
def set_name(self, name, *args, **kwargs) -> None:
self.name = str(name)
def prettyprint(self, *args, **kwargs) -> str:
return str(self.name)
def __str__(self, *args, **kwargs) -> str:
return self.prettyprint()
@dataclass()
class Object:
name: str
@property
def set_name(self, nm, *args, **kwargs) -> None:
self.name = nm
def prettyprint(self, *args, **kwargs) -> str:
return self.name
def __str__(self, *args, **kwargs) -> str:
return self.prettyprint()
@dataclass()
class Host(Object):
pass
@dataclass()
class User(Object):
pass
@dataclass()
class CloseCode:
# Close Code class, only option is the code.
# Sumo Logic uses "False Positive", "resolved", "No Action", "Duplicate".
code: str
def _prettyprint(self):
return f"{self.code}"
def __str__(self):
return self._prettyprint()
@dataclass()
class Duplicate(CloseCode):
dupe: str
def _prettyprint(self):
return f"{self.code} of {self.dupe}"
@dataclass()
class Insight:
number: int = 0
_host: Host = None
_user: User = None
_entity: Entity = None
_date: Date = None
_time: Time = None
_activity_time: Time = None
_signals: list = None
_close_code: CloseCode = None
"""
:number: Insight number
:host: Relevant host
:user: Relevant user
:entity: What entity the insight triggered on. Can be host, IP, user, etc.
"""
# TODO: Timing. Was kwarg-based, now something else is necessary.
def __post_init__(self, *args, **kwargs):
self.signals = list()
# TODO: what else needs to be initialized?
@property
def set_host(self, host: str, *args, **kwargs) -> None:
self._host = Host(host)
@property
def get_host(self, *args, **kwargs):
return str(self._host)
@property
def set_user(self, user: str, *args, **kwargs) -> None:
self._user = User(user)
@property
def get_user(self, *args, **kwargs):
return str(self._user)
@property
def set_entity(self, entity: str, *args, **kwargs) -> None:
self._entity = Entity(entity)
@property
def set_date(self, year=-1, month=-1, day=-1, *args, **kwargs) -> None:
self._date = Date(year, month, day)
@property
def get_date(self, *args, **kwargs) -> str:
return str(self._date)
@property
def set_time(self, hour=-1, minute=-1, second=None, *args, **kwargs) -> None:
self._time = Time(hour, minute, second)
@property
def get_time(self, *args, **kwargs) -> str:
return str(self._time)
@property
def set_act_time(self, hour=-1, minute=-1, second=None, *args, **kwargs) -> None:
self._activity_time = Time(hour, minute, second)
@property
def get_act_time(self, *args, **kwargs) -> str:
return str(self._activity_time)
@property
def add_signal(self, sig: Signal, *args, **kwargs) -> None:
"""
:sig: Signal object
:return: None
"""
self._signals.append(sig)
@property
def get_signals(self, *args, **kwargs) -> str:
# TODO: Fix this, it definitely does not work
ret = ""
for sig in self._signals:
ret += f"{sig}\n"
return ret
def _prettyprint(self, *args, **kwargs):
pass