django-nativemojo 0.1.10__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.
Files changed (194) hide show
  1. django_nativemojo-0.1.10.dist-info/LICENSE +19 -0
  2. django_nativemojo-0.1.10.dist-info/METADATA +96 -0
  3. django_nativemojo-0.1.10.dist-info/NOTICE +8 -0
  4. django_nativemojo-0.1.10.dist-info/RECORD +194 -0
  5. django_nativemojo-0.1.10.dist-info/WHEEL +4 -0
  6. mojo/__init__.py +3 -0
  7. mojo/apps/account/__init__.py +1 -0
  8. mojo/apps/account/admin.py +91 -0
  9. mojo/apps/account/apps.py +16 -0
  10. mojo/apps/account/migrations/0001_initial.py +77 -0
  11. mojo/apps/account/migrations/0002_user_is_email_verified_user_is_phone_verified.py +23 -0
  12. mojo/apps/account/migrations/0003_group_mojo_secrets_user_mojo_secrets.py +23 -0
  13. mojo/apps/account/migrations/__init__.py +0 -0
  14. mojo/apps/account/models/__init__.py +3 -0
  15. mojo/apps/account/models/group.py +98 -0
  16. mojo/apps/account/models/member.py +95 -0
  17. mojo/apps/account/models/pkey.py +18 -0
  18. mojo/apps/account/models/user.py +211 -0
  19. mojo/apps/account/rest/__init__.py +3 -0
  20. mojo/apps/account/rest/group.py +25 -0
  21. mojo/apps/account/rest/user.py +47 -0
  22. mojo/apps/account/utils/__init__.py +0 -0
  23. mojo/apps/account/utils/jwtoken.py +72 -0
  24. mojo/apps/account/utils/passkeys.py +54 -0
  25. mojo/apps/fileman/README.md +549 -0
  26. mojo/apps/fileman/__init__.py +0 -0
  27. mojo/apps/fileman/apps.py +15 -0
  28. mojo/apps/fileman/backends/__init__.py +117 -0
  29. mojo/apps/fileman/backends/base.py +319 -0
  30. mojo/apps/fileman/backends/filesystem.py +397 -0
  31. mojo/apps/fileman/backends/s3.py +398 -0
  32. mojo/apps/fileman/examples/configurations.py +378 -0
  33. mojo/apps/fileman/examples/usage_example.py +665 -0
  34. mojo/apps/fileman/management/__init__.py +1 -0
  35. mojo/apps/fileman/management/commands/__init__.py +1 -0
  36. mojo/apps/fileman/management/commands/cleanup_expired_uploads.py +222 -0
  37. mojo/apps/fileman/models/__init__.py +7 -0
  38. mojo/apps/fileman/models/file.py +292 -0
  39. mojo/apps/fileman/models/manager.py +227 -0
  40. mojo/apps/fileman/models/render.py +0 -0
  41. mojo/apps/fileman/rest/__init__ +0 -0
  42. mojo/apps/fileman/rest/__init__.py +23 -0
  43. mojo/apps/fileman/rest/fileman.py +13 -0
  44. mojo/apps/fileman/rest/upload.py +92 -0
  45. mojo/apps/fileman/utils/__init__.py +19 -0
  46. mojo/apps/fileman/utils/upload.py +616 -0
  47. mojo/apps/incident/__init__.py +1 -0
  48. mojo/apps/incident/handlers/__init__.py +3 -0
  49. mojo/apps/incident/handlers/event_handlers.py +142 -0
  50. mojo/apps/incident/migrations/0001_initial.py +83 -0
  51. mojo/apps/incident/migrations/0002_rename_bundle_ruleset_bundle_minutes_event_hostname_and_more.py +44 -0
  52. mojo/apps/incident/migrations/0003_alter_event_model_id.py +18 -0
  53. mojo/apps/incident/migrations/0004_alter_incident_model_id.py +18 -0
  54. mojo/apps/incident/migrations/__init__.py +0 -0
  55. mojo/apps/incident/models/__init__.py +3 -0
  56. mojo/apps/incident/models/event.py +135 -0
  57. mojo/apps/incident/models/incident.py +33 -0
  58. mojo/apps/incident/models/rule.py +247 -0
  59. mojo/apps/incident/parsers/__init__.py +0 -0
  60. mojo/apps/incident/parsers/ossec/__init__.py +1 -0
  61. mojo/apps/incident/parsers/ossec/core.py +82 -0
  62. mojo/apps/incident/parsers/ossec/parsed.py +23 -0
  63. mojo/apps/incident/parsers/ossec/rules.py +124 -0
  64. mojo/apps/incident/parsers/ossec/utils.py +169 -0
  65. mojo/apps/incident/reporter.py +42 -0
  66. mojo/apps/incident/rest/__init__.py +2 -0
  67. mojo/apps/incident/rest/event.py +23 -0
  68. mojo/apps/incident/rest/ossec.py +22 -0
  69. mojo/apps/logit/__init__.py +0 -0
  70. mojo/apps/logit/admin.py +37 -0
  71. mojo/apps/logit/migrations/0001_initial.py +32 -0
  72. mojo/apps/logit/migrations/0002_log_duid_log_payload_log_username.py +28 -0
  73. mojo/apps/logit/migrations/0003_log_level.py +18 -0
  74. mojo/apps/logit/migrations/__init__.py +0 -0
  75. mojo/apps/logit/models/__init__.py +1 -0
  76. mojo/apps/logit/models/log.py +57 -0
  77. mojo/apps/logit/rest.py +9 -0
  78. mojo/apps/metrics/README.md +79 -0
  79. mojo/apps/metrics/__init__.py +12 -0
  80. mojo/apps/metrics/redis_metrics.py +331 -0
  81. mojo/apps/metrics/rest/__init__.py +1 -0
  82. mojo/apps/metrics/rest/base.py +152 -0
  83. mojo/apps/metrics/rest/db.py +0 -0
  84. mojo/apps/metrics/utils.py +227 -0
  85. mojo/apps/notify/README.md +91 -0
  86. mojo/apps/notify/README_NOTIFICATIONS.md +566 -0
  87. mojo/apps/notify/__init__.py +0 -0
  88. mojo/apps/notify/admin.py +52 -0
  89. mojo/apps/notify/handlers/__init__.py +0 -0
  90. mojo/apps/notify/handlers/example_handlers.py +516 -0
  91. mojo/apps/notify/handlers/ses/__init__.py +25 -0
  92. mojo/apps/notify/handlers/ses/bounce.py +0 -0
  93. mojo/apps/notify/handlers/ses/complaint.py +25 -0
  94. mojo/apps/notify/handlers/ses/message.py +86 -0
  95. mojo/apps/notify/management/__init__.py +0 -0
  96. mojo/apps/notify/management/commands/__init__.py +1 -0
  97. mojo/apps/notify/management/commands/process_notifications.py +370 -0
  98. mojo/apps/notify/mod +0 -0
  99. mojo/apps/notify/models/__init__.py +12 -0
  100. mojo/apps/notify/models/account.py +128 -0
  101. mojo/apps/notify/models/attachment.py +24 -0
  102. mojo/apps/notify/models/bounce.py +68 -0
  103. mojo/apps/notify/models/complaint.py +40 -0
  104. mojo/apps/notify/models/inbox.py +113 -0
  105. mojo/apps/notify/models/inbox_message.py +173 -0
  106. mojo/apps/notify/models/outbox.py +129 -0
  107. mojo/apps/notify/models/outbox_message.py +288 -0
  108. mojo/apps/notify/models/template.py +30 -0
  109. mojo/apps/notify/providers/__init__.py +0 -0
  110. mojo/apps/notify/providers/aws.py +73 -0
  111. mojo/apps/notify/rest/__init__.py +0 -0
  112. mojo/apps/notify/rest/ses.py +0 -0
  113. mojo/apps/notify/utils/__init__.py +2 -0
  114. mojo/apps/notify/utils/notifications.py +404 -0
  115. mojo/apps/notify/utils/parsing.py +202 -0
  116. mojo/apps/notify/utils/render.py +144 -0
  117. mojo/apps/tasks/README.md +118 -0
  118. mojo/apps/tasks/__init__.py +11 -0
  119. mojo/apps/tasks/manager.py +489 -0
  120. mojo/apps/tasks/rest/__init__.py +2 -0
  121. mojo/apps/tasks/rest/hooks.py +0 -0
  122. mojo/apps/tasks/rest/tasks.py +62 -0
  123. mojo/apps/tasks/runner.py +174 -0
  124. mojo/apps/tasks/tq_handlers.py +14 -0
  125. mojo/decorators/__init__.py +3 -0
  126. mojo/decorators/auth.py +25 -0
  127. mojo/decorators/cron.py +31 -0
  128. mojo/decorators/http.py +132 -0
  129. mojo/decorators/validate.py +14 -0
  130. mojo/errors.py +88 -0
  131. mojo/helpers/__init__.py +0 -0
  132. mojo/helpers/aws/__init__.py +0 -0
  133. mojo/helpers/aws/client.py +8 -0
  134. mojo/helpers/aws/s3.py +268 -0
  135. mojo/helpers/aws/setup_email.py +0 -0
  136. mojo/helpers/cron.py +79 -0
  137. mojo/helpers/crypto/__init__.py +4 -0
  138. mojo/helpers/crypto/aes.py +60 -0
  139. mojo/helpers/crypto/hash.py +59 -0
  140. mojo/helpers/crypto/privpub/__init__.py +1 -0
  141. mojo/helpers/crypto/privpub/hybrid.py +97 -0
  142. mojo/helpers/crypto/privpub/rsa.py +104 -0
  143. mojo/helpers/crypto/sign.py +36 -0
  144. mojo/helpers/crypto/too.l.py +25 -0
  145. mojo/helpers/crypto/utils.py +26 -0
  146. mojo/helpers/daemon.py +94 -0
  147. mojo/helpers/dates.py +69 -0
  148. mojo/helpers/dns/__init__.py +0 -0
  149. mojo/helpers/dns/godaddy.py +62 -0
  150. mojo/helpers/filetypes.py +128 -0
  151. mojo/helpers/logit.py +310 -0
  152. mojo/helpers/modules.py +95 -0
  153. mojo/helpers/paths.py +63 -0
  154. mojo/helpers/redis.py +10 -0
  155. mojo/helpers/request.py +89 -0
  156. mojo/helpers/request_parser.py +269 -0
  157. mojo/helpers/response.py +14 -0
  158. mojo/helpers/settings.py +146 -0
  159. mojo/helpers/sysinfo.py +140 -0
  160. mojo/helpers/ua.py +0 -0
  161. mojo/middleware/__init__.py +0 -0
  162. mojo/middleware/auth.py +26 -0
  163. mojo/middleware/logging.py +55 -0
  164. mojo/middleware/mojo.py +21 -0
  165. mojo/migrations/0001_initial.py +32 -0
  166. mojo/migrations/__init__.py +0 -0
  167. mojo/models/__init__.py +2 -0
  168. mojo/models/meta.py +262 -0
  169. mojo/models/rest.py +538 -0
  170. mojo/models/secrets.py +59 -0
  171. mojo/rest/__init__.py +1 -0
  172. mojo/rest/info.py +26 -0
  173. mojo/serializers/__init__.py +0 -0
  174. mojo/serializers/models.py +165 -0
  175. mojo/serializers/openapi.py +188 -0
  176. mojo/urls.py +38 -0
  177. mojo/ws4redis/README.md +174 -0
  178. mojo/ws4redis/__init__.py +2 -0
  179. mojo/ws4redis/client.py +283 -0
  180. mojo/ws4redis/connection.py +327 -0
  181. mojo/ws4redis/exceptions.py +32 -0
  182. mojo/ws4redis/redis.py +183 -0
  183. mojo/ws4redis/servers/__init__.py +0 -0
  184. mojo/ws4redis/servers/base.py +86 -0
  185. mojo/ws4redis/servers/django.py +171 -0
  186. mojo/ws4redis/servers/uwsgi.py +63 -0
  187. mojo/ws4redis/settings.py +45 -0
  188. mojo/ws4redis/utf8validator.py +128 -0
  189. mojo/ws4redis/websocket.py +403 -0
  190. testit/__init__.py +0 -0
  191. testit/client.py +147 -0
  192. testit/faker.py +20 -0
  193. testit/helpers.py +198 -0
  194. testit/runner.py +262 -0
@@ -0,0 +1,142 @@
1
+ """
2
+ Event handlers for incident processing.
3
+
4
+ This module contains handlers for processing incident events based on different
5
+ handler types (task, email, notify). These handlers are used by the RuleSet.run_handler
6
+ method to handle events that match rule criteria.
7
+ """
8
+
9
+ class TaskHandler:
10
+ """
11
+ Handler for executing tasks based on events.
12
+
13
+ This handler executes a named task with the given parameters
14
+ when an event matches rule criteria.
15
+
16
+ Attributes:
17
+ handler_name (str): The name of the task to execute.
18
+ params (dict): Parameters to pass to the task.
19
+ """
20
+
21
+ def __init__(self, handler_name, **params):
22
+ """
23
+ Initialize a TaskHandler with a task name and parameters.
24
+
25
+ Args:
26
+ handler_name (str): The name of the task to execute.
27
+ **params: Parameters to pass to the task.
28
+ """
29
+ self.handler_name = handler_name
30
+ self.params = params
31
+
32
+ def run(self, event):
33
+ """
34
+ Execute the task for the given event.
35
+
36
+ Args:
37
+ event (Event): The event that triggered this handler.
38
+
39
+ Returns:
40
+ bool: True if the task was executed successfully, False otherwise.
41
+ """
42
+ # TODO: Implement actual task execution logic
43
+ # For example, using Celery to execute tasks asynchronously
44
+ try:
45
+ # Example implementation:
46
+ # from mojo.tasks import execute_task
47
+ # result = execute_task.delay(self.handler_name, event=event, **self.params)
48
+ # return result.successful()
49
+ return True
50
+ except Exception as e:
51
+ # Log the error
52
+ # logger.error(f"Error executing task {self.handler_name}: {e}")
53
+ return False
54
+
55
+
56
+ class EmailHandler:
57
+ """
58
+ Handler for sending email notifications based on events.
59
+
60
+ This handler sends an email to the specified recipient
61
+ when an event matches rule criteria.
62
+
63
+ Attributes:
64
+ recipient (str): The email address to send notifications to.
65
+ """
66
+
67
+ def __init__(self, recipient):
68
+ """
69
+ Initialize an EmailHandler with a recipient.
70
+
71
+ Args:
72
+ recipient (str): The email address to send notifications to.
73
+ """
74
+ self.recipient = recipient
75
+
76
+ def run(self, event):
77
+ """
78
+ Send an email notification for the given event.
79
+
80
+ Args:
81
+ event (Event): The event that triggered this handler.
82
+
83
+ Returns:
84
+ bool: True if the email was sent successfully, False otherwise.
85
+ """
86
+ # TODO: Implement actual email sending logic
87
+ try:
88
+ # Example implementation:
89
+ # from mojo.helpers.mail import send_mail
90
+ # subject = f"Incident Alert: {event.name}"
91
+ # body = f"An incident has been detected:\n\n{event.details}\n\nMetadata: {event.metadata}"
92
+ # result = send_mail(subject, body, [self.recipient])
93
+ # return result
94
+ return True
95
+ except Exception as e:
96
+ # Log the error
97
+ # logger.error(f"Error sending email to {self.recipient}: {e}")
98
+ return False
99
+
100
+
101
+ class NotifyHandler:
102
+ """
103
+ Handler for sending notifications through various channels based on events.
104
+
105
+ This handler can send notifications through multiple channels (SMS, push, etc.)
106
+ when an event matches rule criteria.
107
+
108
+ Attributes:
109
+ recipient (str): The recipient identifier (can be a username, user ID, etc.).
110
+ """
111
+
112
+ def __init__(self, recipient):
113
+ """
114
+ Initialize a NotifyHandler with a recipient.
115
+
116
+ Args:
117
+ recipient (str): The recipient identifier.
118
+ """
119
+ self.recipient = recipient
120
+
121
+ def run(self, event):
122
+ """
123
+ Send a notification for the given event.
124
+
125
+ Args:
126
+ event (Event): The event that triggered this handler.
127
+
128
+ Returns:
129
+ bool: True if the notification was sent successfully, False otherwise.
130
+ """
131
+ # TODO: Implement actual notification logic
132
+ try:
133
+ # Example implementation:
134
+ # from mojo.helpers.notifications import send_notification
135
+ # message = f"Incident Alert: {event.name}\n{event.details}"
136
+ # result = send_notification(self.recipient, message, metadata=event.metadata)
137
+ # return result
138
+ return True
139
+ except Exception as e:
140
+ # Log the error
141
+ # logger.error(f"Error sending notification to {self.recipient}: {e}")
142
+ return False
@@ -0,0 +1,83 @@
1
+ # Generated by Django 4.2.21 on 2025-06-04 02:22
2
+
3
+ from django.db import migrations, models
4
+ import django.db.models.deletion
5
+ import mojo.models.rest
6
+
7
+
8
+ class Migration(migrations.Migration):
9
+
10
+ initial = True
11
+
12
+ dependencies = [
13
+ ]
14
+
15
+ operations = [
16
+ migrations.CreateModel(
17
+ name='Incident',
18
+ fields=[
19
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
20
+ ('created', models.DateTimeField(auto_now_add=True, db_index=True)),
21
+ ('priority', models.IntegerField(db_index=True, default=0)),
22
+ ('state', models.IntegerField(db_index=True, default=0)),
23
+ ('category', models.CharField(db_index=True, max_length=124)),
24
+ ('title', models.TextField(default=None, null=True)),
25
+ ('details', models.TextField(default=None, null=True)),
26
+ ('model_name', models.TextField(db_index=True, default=None, null=True)),
27
+ ('model_id', models.IntegerField(db_index=True, default=0)),
28
+ ('source_ip', models.CharField(blank=True, db_index=True, default=None, max_length=16, null=True)),
29
+ ('metadata', models.JSONField(blank=True, default=dict)),
30
+ ],
31
+ bases=(models.Model, mojo.models.rest.MojoModel),
32
+ ),
33
+ migrations.CreateModel(
34
+ name='RuleSet',
35
+ fields=[
36
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
37
+ ('created', models.DateTimeField(auto_now_add=True)),
38
+ ('modified', models.DateTimeField(auto_now=True)),
39
+ ('priority', models.IntegerField(db_index=True, default=0)),
40
+ ('category', models.CharField(db_index=True, max_length=124)),
41
+ ('name', models.TextField(default=None, null=True)),
42
+ ('bundle', models.IntegerField(default=0)),
43
+ ('bundle_by', models.IntegerField(default=3)),
44
+ ('match_by', models.IntegerField(default=0)),
45
+ ('handler', models.TextField(default=None, null=True)),
46
+ ('metadata', models.JSONField(blank=True, default=dict)),
47
+ ],
48
+ bases=(models.Model, mojo.models.rest.MojoModel),
49
+ ),
50
+ migrations.CreateModel(
51
+ name='Rule',
52
+ fields=[
53
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
54
+ ('created', models.DateTimeField(auto_now_add=True)),
55
+ ('modified', models.DateTimeField(auto_now=True)),
56
+ ('name', models.TextField(default=None, null=True)),
57
+ ('index', models.IntegerField(db_index=True, default=0)),
58
+ ('comparator', models.CharField(default='==', max_length=32)),
59
+ ('field_name', models.CharField(default=None, max_length=124, null=True)),
60
+ ('value', models.CharField(default='', max_length=124)),
61
+ ('value_type', models.CharField(default='int', max_length=10)),
62
+ ('is_required', models.IntegerField(default=0)),
63
+ ('parent', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='rules', to='incident.ruleset')),
64
+ ],
65
+ bases=(models.Model, mojo.models.rest.MojoModel),
66
+ ),
67
+ migrations.CreateModel(
68
+ name='Event',
69
+ fields=[
70
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
71
+ ('created', models.DateTimeField(auto_now_add=True, db_index=True)),
72
+ ('level', models.IntegerField(db_index=True, default=0)),
73
+ ('category', models.CharField(db_index=True, max_length=124)),
74
+ ('title', models.TextField(default=None, null=True)),
75
+ ('details', models.TextField(default=None, null=True)),
76
+ ('model_name', models.TextField(db_index=True, default=None, null=True)),
77
+ ('model_id', models.IntegerField(db_index=True, default=0)),
78
+ ('metadata', models.JSONField(blank=True, default=dict)),
79
+ ('incident', models.ForeignKey(default=None, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='events', to='incident.incident')),
80
+ ],
81
+ bases=(models.Model, mojo.models.rest.MojoModel),
82
+ ),
83
+ ]
@@ -0,0 +1,44 @@
1
+ # Generated by Django 4.2.21 on 2025-06-04 13:42
2
+
3
+ from django.db import migrations, models
4
+ import django.db.models.deletion
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+
9
+ dependencies = [
10
+ ('incident', '0001_initial'),
11
+ ]
12
+
13
+ operations = [
14
+ migrations.RenameField(
15
+ model_name='ruleset',
16
+ old_name='bundle',
17
+ new_name='bundle_minutes',
18
+ ),
19
+ migrations.AddField(
20
+ model_name='event',
21
+ name='hostname',
22
+ field=models.CharField(db_index=True, default=None, max_length=16, null=True),
23
+ ),
24
+ migrations.AddField(
25
+ model_name='event',
26
+ name='source_ip',
27
+ field=models.CharField(db_index=True, default=None, max_length=16, null=True),
28
+ ),
29
+ migrations.AddField(
30
+ model_name='incident',
31
+ name='hostname',
32
+ field=models.CharField(db_index=True, default=None, max_length=16, null=True),
33
+ ),
34
+ migrations.AddField(
35
+ model_name='incident',
36
+ name='rule_set',
37
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='incidents', to='incident.ruleset'),
38
+ ),
39
+ migrations.AlterField(
40
+ model_name='incident',
41
+ name='source_ip',
42
+ field=models.CharField(db_index=True, default=None, max_length=16, null=True),
43
+ ),
44
+ ]
@@ -0,0 +1,18 @@
1
+ # Generated by Django 4.2.21 on 2025-06-04 14:30
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ('incident', '0002_rename_bundle_ruleset_bundle_minutes_event_hostname_and_more'),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AlterField(
14
+ model_name='event',
15
+ name='model_id',
16
+ field=models.IntegerField(db_index=True, default=None, null=True),
17
+ ),
18
+ ]
@@ -0,0 +1,18 @@
1
+ # Generated by Django 4.2.21 on 2025-06-04 17:22
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ('incident', '0003_alter_event_model_id'),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AlterField(
14
+ model_name='incident',
15
+ name='model_id',
16
+ field=models.IntegerField(db_index=True, default=None, null=True),
17
+ ),
18
+ ]
File without changes
@@ -0,0 +1,3 @@
1
+ from .event import Event
2
+ from .rule import RuleSet, Rule
3
+ from .incident import Incident
@@ -0,0 +1,135 @@
1
+ from mojo.apps.metrics import record
2
+ from django.db import models
3
+ from mojo.models import MojoModel
4
+ from mojo.helpers import dates
5
+ from mojo.helpers.settings import settings
6
+ from mojo.apps import metrics
7
+
8
+
9
+ INCIDENT_LEVEL_THRESHOLD = settings.get('INCIDENT_LEVEL_THRESHOLD', 7)
10
+
11
+ class Event(models.Model, MojoModel):
12
+ """
13
+ Event model.
14
+
15
+ Level 0–3: Informational or low importance
16
+ Level 4–7: Warning or potential issue
17
+ Level 8–15: Increasing severity, with Level 15 being critical
18
+ """
19
+ created = models.DateTimeField(auto_now_add=True, editable=False, db_index=True)
20
+
21
+ level = models.IntegerField(default=0, db_index=True)
22
+ category = models.CharField(max_length=124, db_index=True)
23
+ source_ip = models.CharField(max_length=16, null=True, default=None, db_index=True)
24
+ hostname = models.CharField(max_length=16, null=True, default=None, db_index=True)
25
+
26
+ title = models.TextField(default=None, null=True)
27
+ details = models.TextField(default=None, null=True)
28
+
29
+ model_name = models.TextField(default=None, null=True, db_index=True)
30
+ model_id = models.IntegerField(default=None, null=True, db_index=True)
31
+
32
+ incident = models.ForeignKey("incident.Incident", null=True, related_name="events",
33
+ default=None, on_delete=models.CASCADE)
34
+
35
+ # JSON-based metadata field
36
+ metadata = models.JSONField(default=dict, blank=True)
37
+
38
+ class RestMeta:
39
+ SEARCH_FIELDS = ["details"]
40
+ VIEW_PERMS = ["view_incidents"]
41
+ CREATE_PERMS = None
42
+
43
+ def sync_metadata(self):
44
+ # Gather all field values into the metadata
45
+ field_values = {
46
+ 'level': self.level,
47
+ 'category': self.category,
48
+ 'source_ip': self.source_ip,
49
+ 'title': self.title,
50
+ 'details': self.details,
51
+ 'model_name': self.model_name,
52
+ 'model_id': self.model_id }
53
+ # Update the metadata with these values
54
+ self.metadata.update(field_values)
55
+
56
+ def publish(self):
57
+ from mojo.apps.incident.models import RuleSet
58
+ # Find the RuleSet by category
59
+ self.record_event_metrics()
60
+ rule_set = RuleSet.check_by_category(self.category, self)
61
+
62
+ if rule_set or self.level >= INCIDENT_LEVEL_THRESHOLD:
63
+ incident, created = self.get_or_create_incident(rule_set)
64
+ self.link_to_incident(incident)
65
+ if rule_set and created:
66
+ rule_set.run_handler(self, incident)
67
+
68
+ def record_event_metrics(self):
69
+ if settings.INCIDENT_EVENT_METRICS:
70
+ metrics.record('incident_events', account="incident",
71
+ min_granularity=settings.get("INCIDENT_METRICS_MIN_GRANULARITY", "hours"))
72
+
73
+ def record_incident_metrics(self):
74
+ if settings.INCIDENT_EVENT_METRICS:
75
+ metrics.record('incidents', account="incident",
76
+ min_granularity=settings.get("INCIDENT_METRICS_MIN_GRANULARITY", "hours"))
77
+
78
+ def get_or_create_incident(self, rule_set=None):
79
+ """
80
+ Gets or creates an incident based on the event's level and rule set bundle criteria.
81
+ """
82
+ from mojo.apps.incident.models import Incident
83
+
84
+ incident = None
85
+ created = False
86
+ if rule_set is not None and rule_set.bundle_by > 0:
87
+ bundle_criteria = self.determine_bundle_criteria(rule_set)
88
+ incident = Incident.objects.filter(**bundle_criteria).first()
89
+
90
+ if not incident:
91
+ # Create a new incident if none found
92
+ created = True
93
+ incident = Incident(
94
+ priority=self.level,
95
+ state=0,
96
+ category=self.category,
97
+ title=self.title,
98
+ details=self.details,
99
+ hostname=self.hostname,
100
+ model_name=self.model_name,
101
+ model_id=self.model_id,
102
+ source_ip=self.source_ip
103
+ )
104
+ incident.metadata.update(self.metadata)
105
+ incident.save()
106
+ self.record_incident_metrics()
107
+
108
+ return incident, created
109
+
110
+ def determine_bundle_criteria(self, rule_set):
111
+ """
112
+ Determines the bundle criteria based on the rule set configuration.
113
+ """
114
+ bundle_criteria = {
115
+ "category": self.category
116
+ }
117
+ if rule_set.bundle_minutes:
118
+ bundle_criteria['created__gte'] = dates.subtract(minutes=rule_set.bundle_minutes)
119
+ if rule_set.bundle_by in [1, 5, 6, 9]: # hostname or hostname and others
120
+ bundle_criteria['hostname'] = self.hostname
121
+ if rule_set.bundle_by in [2, 3, 5, 6, 7, 8]: # model and combinations
122
+ bundle_criteria['model_name'] = self.model_name
123
+ if rule_set.bundle_by in [3, 6, 8]: # model_id where applicable
124
+ bundle_criteria['model_id'] = self.model_id
125
+ if rule_set.bundle_by in [4, 7, 8, 9]: # source_ip and combinations
126
+ bundle_criteria['source_ip'] = self.source_ip
127
+
128
+ return bundle_criteria
129
+
130
+ def link_to_incident(self, incident):
131
+ """
132
+ Links the event to an incident and saves the event.
133
+ """
134
+ self.incident = incident
135
+ self.save()
@@ -0,0 +1,33 @@
1
+ from django.db import models
2
+ from mojo.models import MojoModel
3
+
4
+
5
+ class Incident(models.Model, MojoModel):
6
+ """
7
+ Incident model.
8
+ """
9
+ created = models.DateTimeField(auto_now_add=True, editable=False, db_index=True)
10
+
11
+ priority = models.IntegerField(default=0, db_index=True)
12
+ state = models.IntegerField(default=0, db_index=True)
13
+ category = models.CharField(max_length=124, db_index=True)
14
+ title = models.TextField(default=None, null=True)
15
+ details = models.TextField(default=None, null=True)
16
+
17
+ model_name = models.TextField(default=None, null=True, db_index=True)
18
+ model_id = models.IntegerField(default=None, null=True, db_index=True)
19
+
20
+ # the
21
+ source_ip = models.CharField(max_length=16, null=True, default=None, db_index=True)
22
+ hostname = models.CharField(max_length=16, null=True, default=None, db_index=True)
23
+
24
+ # JSON-based metadata field
25
+ metadata = models.JSONField(default=dict, blank=True)
26
+
27
+ rule_set = models.ForeignKey("incident.Ruleset", on_delete=models.SET_NULL,
28
+ null=True, blank=True, related_name="incidents")
29
+
30
+ class RestMeta:
31
+ SEARCH_FIELDS = ["details"]
32
+ VIEW_PERMS = ["view_incidents"]
33
+ CREATE_PERMS = None