Skip to content

case_handler models

case_handler.models

Status

Bases: TextChoices

Enumeration of possible case statuses.

TODO = ('To Do', _('To Do')) class-attribute instance-attribute

ONGOING = ('On Going', _('On Going')) class-attribute instance-attribute

CHALLENGED = ('Challenged', _('Challenged')) class-attribute instance-attribute

DONE = ('Done', _('Done')) class-attribute instance-attribute

Result

Bases: TextChoices

Enumeration of possible case result statuses.

SAFE = ('Safe', _('Safe')) class-attribute instance-attribute

INCONCLUSIVE = ('Inconclusive', _('Inconclusive')) class-attribute instance-attribute

UNCHALLENGED = ('Unchallenged', _('Unchallenged')) class-attribute instance-attribute

ALLOW_LISTED = ('AllowListed', _('AllowListed')) class-attribute instance-attribute

FAILURE = ('Failure', _('Failure')) class-attribute instance-attribute

SUSPICIOUS = ('Suspicious', _('Suspicious')) class-attribute instance-attribute

DANGEROUS = ('Dangerous', _('Dangerous')) class-attribute instance-attribute

ProposedVerdict

Bases: TextChoices

SAFE = ('Safe', _('Safe')) class-attribute instance-attribute

DANGEROUS = ('Dangerous', _('Dangerous')) class-attribute instance-attribute

Case

Bases: Model

Main incident investigation case, storing scores, analyst decisions and AI predictions.

description = models.TextField() class-attribute instance-attribute

reporter = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=(models.CASCADE), related_name='cases', db_index=True) class-attribute instance-attribute

analysis_done = models.PositiveIntegerField(default=0) class-attribute instance-attribute

status = models.CharField(max_length=20, choices=(Status.choices), default=(Status.TODO), verbose_name='Status', db_index=True) class-attribute instance-attribute

results = models.CharField(max_length=20, choices=(Result.choices), default=(Result.INCONCLUSIVE), verbose_name='Results', db_index=True) class-attribute instance-attribute

final_score = models.FloatField(default=0) class-attribute instance-attribute

final_confidence = models.FloatField(default=0) class-attribute instance-attribute

score = models.FloatField(default=0) class-attribute instance-attribute

confidence = models.FloatField(default=0) class-attribute instance-attribute

results_ai = models.CharField(max_length=20, default='Suspicious', verbose_name='ResultsAI') class-attribute instance-attribute

score_ai = models.FloatField(default=0) class-attribute instance-attribute

confidence_ai = models.FloatField(default=0) class-attribute instance-attribute

category_ai = models.CharField(max_length=20, default='Uncategorized', verbose_name='Category AI', db_index=True) class-attribute instance-attribute

fileOrMail = models.ForeignKey('CaseHasFileOrMail', on_delete=(models.CASCADE), related_name='cases', null=True, blank=True, db_index=True) class-attribute instance-attribute

nonFileIocs = models.ForeignKey('CaseHasNonFileIocs', on_delete=(models.CASCADE), related_name='cases', null=True, blank=True, db_index=True) class-attribute instance-attribute

is_challenged = models.BooleanField(default=False) class-attribute instance-attribute

is_challengeable = models.BooleanField(default=True) class-attribute instance-attribute

challenged_result = models.CharField(max_length=20, choices=(Result.choices), default=(Result.UNCHALLENGED), verbose_name='Challenged Result') class-attribute instance-attribute

creation_date = models.DateTimeField(auto_now_add=True, db_index=True) class-attribute instance-attribute

last_update = models.DateTimeField(auto_now=True) class-attribute instance-attribute

last_update_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=(models.CASCADE), related_name='cases_last_update_by', null=True, blank=True, db_index=True) class-attribute instance-attribute

lifecycle_state = models.CharField(max_length=20, choices=(LifecycleState.choices), default=(LifecycleState.CREATED), db_index=True, verbose_name='Lifecycle State') class-attribute instance-attribute

finalized_at = models.DateTimeField(null=True, blank=True, verbose_name='Finalized At') class-attribute instance-attribute

dispatched_at = models.DateTimeField(null=True, blank=True, verbose_name='Dispatched At') class-attribute instance-attribute

kpi_counted = models.BooleanField(default=False, verbose_name='KPI Counted') class-attribute instance-attribute

challenge_proposed_result = models.CharField(max_length=20, choices=(ProposedVerdict.choices), blank=True, default='', verbose_name='Challenge Proposed Result') class-attribute instance-attribute

challenge_reason = models.TextField(blank=True, default='', verbose_name='Challenge Reason') class-attribute instance-attribute

reporter_context = models.TextField(blank=True, default='', verbose_name='Reporter Context') class-attribute instance-attribute

thehive_alert_id = models.CharField(max_length=64, blank=True, default='', verbose_name='TheHive Alert ID') class-attribute instance-attribute

is_allowlisted = models.BooleanField(default=False, verbose_name='Is Allowlisted') class-attribute instance-attribute

is_denylisted = models.BooleanField(default=False, verbose_name='Is Denylisted') class-attribute instance-attribute

list_reason = models.TextField(blank=True, default='', verbose_name='Allow/Deny List Reason') class-attribute instance-attribute

Meta

ordering = ['-creation_date'] class-attribute instance-attribute

was_published_recently()

Check if the case was created in the last 24 hours.

CaseChallengeToken

Bases: Model

case = models.ForeignKey(Case, on_delete=(models.CASCADE), related_name='challenge_tokens', db_index=True) class-attribute instance-attribute

token_hash = models.CharField(max_length=64, unique=True, db_index=True) class-attribute instance-attribute

expires_at = models.DateTimeField(db_index=True) class-attribute instance-attribute

used_at = models.DateTimeField(null=True, blank=True, db_index=True) class-attribute instance-attribute

created_at = models.DateTimeField(auto_now_add=True) class-attribute instance-attribute

Meta

indexes = [models.Index(fields=['case', 'expires_at'], name='cct_case_expires_idx'), models.Index(fields=['case', 'used_at'], name='cct_case_used_idx')] class-attribute instance-attribute

hash_token(token) staticmethod

issue_token(case, *, lifetime=None) classmethod

build_challenge_url(case_id, token, api_base) staticmethod

normalize_api_base(submissions_url) staticmethod

mark_used()

CaseComment

Bases: Model

case = models.ForeignKey(Case, on_delete=(models.CASCADE), related_name='comments', db_index=True) class-attribute instance-attribute

author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=(models.CASCADE), related_name='case_comments') class-attribute instance-attribute

body = models.TextField() class-attribute instance-attribute

is_internal = models.BooleanField(default=False, verbose_name='Internal (analyst-only)') class-attribute instance-attribute

created_at = models.DateTimeField(auto_now_add=True, db_index=True) class-attribute instance-attribute

Meta

ordering = ['-created_at'] class-attribute instance-attribute

CaseHasFileOrMail

Bases: Model

Association model for cases linked to either a file or an email (one-to-one per instance).

case = models.ForeignKey('Case', on_delete=(models.CASCADE), related_name='case_has_file_or_mail', db_index=True) class-attribute instance-attribute

file = models.ForeignKey(File, on_delete=(models.CASCADE), related_name='case_has_file_or_mail', null=True, blank=True, db_index=True) class-attribute instance-attribute

mail = models.ForeignKey(Mail, on_delete=(models.CASCADE), related_name='case_has_file_or_mail', null=True, blank=True, db_index=True) class-attribute instance-attribute

creation_date = models.DateTimeField(auto_now_add=True, db_index=True) class-attribute instance-attribute

last_update = models.DateTimeField(auto_now=True) class-attribute instance-attribute

Meta

ordering = ['-creation_date'] class-attribute instance-attribute

get_iocs()

Return the associated file or mail object in a dict.

CaseHasNonFileIocs

Bases: Model

Association model for cases linked to non-file IOCs: URLs, IPs, and hashes.

case = models.ForeignKey('Case', on_delete=(models.CASCADE), related_name='case_has_non_file_iocs', db_index=True) class-attribute instance-attribute

url = models.ForeignKey(URL, on_delete=(models.CASCADE), related_name='case_has_non_file_iocs', null=True, blank=True, db_index=True) class-attribute instance-attribute

ip = models.ForeignKey(IP, on_delete=(models.CASCADE), related_name='case_has_non_file_iocs', null=True, blank=True, db_index=True) class-attribute instance-attribute

hash = models.ForeignKey(Hash, on_delete=(models.CASCADE), related_name='case_has_non_file_iocs', null=True, blank=True, db_index=True) class-attribute instance-attribute

creation_date = models.DateTimeField(auto_now_add=True, db_index=True) class-attribute instance-attribute

last_update = models.DateTimeField(auto_now=True) class-attribute instance-attribute

Meta

ordering = ['-creation_date'] class-attribute instance-attribute

get_iocs()

Return the associated URL, IP, or hash as a dict.

CaseArtifact

Bases: Model

Per-(case, artifact) link replacing the old FileInCases / HashInCases / UrlInCases / IpInCases / MailInCases models. Exactly one of file, hash, url, ip, mail is populated per row; artifact_type matches the populated FK.

case = models.ForeignKey('Case', on_delete=(models.CASCADE), related_name='case_artifacts', db_index=True) class-attribute instance-attribute

artifact_type = models.CharField(max_length=10, choices=(ArtifactType.choices), db_index=True) class-attribute instance-attribute

file = models.ForeignKey(File, on_delete=(models.CASCADE), related_name='case_artifacts', null=True, blank=True, db_index=True) class-attribute instance-attribute

hash = models.ForeignKey(Hash, on_delete=(models.CASCADE), related_name='case_artifacts', null=True, blank=True, db_index=True) class-attribute instance-attribute

url = models.ForeignKey(URL, on_delete=(models.CASCADE), related_name='case_artifacts', null=True, blank=True, db_index=True) class-attribute instance-attribute

ip = models.ForeignKey(IP, on_delete=(models.CASCADE), related_name='case_artifacts', null=True, blank=True, db_index=True) class-attribute instance-attribute

mail = models.ForeignKey(Mail, on_delete=(models.CASCADE), related_name='case_artifacts', null=True, blank=True, db_index=True) class-attribute instance-attribute

creation_date = models.DateTimeField(auto_now_add=True, db_index=True) class-attribute instance-attribute

last_update = models.DateTimeField(auto_now=True) class-attribute instance-attribute

ArtifactType

Bases: TextChoices

FILE = ('file', 'File') class-attribute instance-attribute
HASH = ('hash', 'Hash') class-attribute instance-attribute
URL = ('url', 'URL') class-attribute instance-attribute
IP = ('ip', 'IP') class-attribute instance-attribute
MAIL = ('mail', 'Mail') class-attribute instance-attribute

Meta

ordering = ['-creation_date'] class-attribute instance-attribute