mirror of
https://github.com/wahyd4/links.git
synced 2026-08-09 05:06:16 +10:00
85 lines
3.0 KiB
Python
85 lines
3.0 KiB
Python
from django.db import models
|
|
|
|
from .fields import EncryptedCharField
|
|
|
|
|
|
class ScanProfile(models.Model):
|
|
INTERVAL_CHOICES = [
|
|
(1, 'Every 1 day'),
|
|
(3, 'Every 3 days'),
|
|
(7, 'Every 7 days'),
|
|
(30, 'Every 30 days'),
|
|
]
|
|
SEVERITY_CHOICES = [
|
|
('warning', 'Warning and above'),
|
|
('critical', 'Critical only'),
|
|
]
|
|
|
|
name = models.CharField(max_length=200)
|
|
enabled = models.BooleanField(default=True)
|
|
schedule_interval = models.IntegerField(choices=INTERVAL_CHOICES, default=7)
|
|
gateway_ip = models.GenericIPAddressField(help_text='e.g. 192.168.1.1')
|
|
public_ip = models.GenericIPAddressField(help_text='Your public/WAN IP address')
|
|
network_cidr = models.CharField(max_length=50, blank=True, help_text='e.g. 192.168.1.0/24')
|
|
auth_provider_host = models.CharField(max_length=255, blank=True, help_text='e.g. pass.junv.cc')
|
|
domains = models.JSONField(default=list, blank=True, help_text='List of public hostnames to check')
|
|
cameras = models.JSONField(default=list, blank=True, help_text='List of camera IPs to probe')
|
|
telegram_bot_token = EncryptedCharField(blank=True)
|
|
telegram_chat_id = EncryptedCharField(blank=True)
|
|
notify_on_severity = models.CharField(max_length=20, choices=SEVERITY_CHOICES, default='critical')
|
|
last_run_at = models.DateTimeField(null=True, blank=True)
|
|
created_at = models.DateTimeField(auto_now_add=True)
|
|
|
|
def __str__(self):
|
|
return self.name
|
|
|
|
|
|
class ScanRun(models.Model):
|
|
STATUS_CHOICES = [
|
|
('pending', 'Pending'),
|
|
('running', 'Running'),
|
|
('success', 'Success'),
|
|
('failed', 'Failed'),
|
|
]
|
|
|
|
profile = models.ForeignKey(ScanProfile, on_delete=models.CASCADE, related_name='runs')
|
|
started_at = models.DateTimeField(auto_now_add=True)
|
|
finished_at = models.DateTimeField(null=True, blank=True)
|
|
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='pending')
|
|
summary = models.JSONField(default=dict)
|
|
triggered_by = models.CharField(max_length=20, default='manual')
|
|
|
|
class Meta:
|
|
ordering = ['-started_at']
|
|
|
|
def __str__(self):
|
|
return f'{self.profile.name} run #{self.pk} ({self.status})'
|
|
|
|
@property
|
|
def duration_seconds(self):
|
|
if self.finished_at and self.started_at:
|
|
return int((self.finished_at - self.started_at).total_seconds())
|
|
return None
|
|
|
|
|
|
class ScanFinding(models.Model):
|
|
SEVERITY_CHOICES = [
|
|
('ok', 'OK'),
|
|
('info', 'Info'),
|
|
('warning', 'Warning'),
|
|
('critical', 'Critical'),
|
|
]
|
|
|
|
run = models.ForeignKey(ScanRun, on_delete=models.CASCADE, related_name='findings')
|
|
check_name = models.CharField(max_length=100)
|
|
severity = models.CharField(max_length=20, choices=SEVERITY_CHOICES)
|
|
title = models.CharField(max_length=255)
|
|
detail = models.TextField()
|
|
raw = models.JSONField(default=dict)
|
|
|
|
class Meta:
|
|
ordering = ['severity', 'check_name']
|
|
|
|
def __str__(self):
|
|
return f'[{self.severity.upper()}] {self.title}'
|