perf: check account engine

pull/14833/head
feng 2025-01-21 17:04:27 +08:00 committed by feng626
parent 01ac001f84
commit ef0df85a15
5 changed files with 88 additions and 80 deletions

View File

@ -138,47 +138,16 @@ class CheckAccountEngineViewSet(JMSModelViewSet):
search_fields = ("name",) search_fields = ("name",)
serializer_class = serializers.CheckAccountEngineSerializer serializer_class = serializers.CheckAccountEngineSerializer
@staticmethod perm_model = CheckAccountEngine
def get_default_engines():
data = [
{
"id": "00000000-0000-0000-0000-000000000001",
"slug": "check_gathered_account",
"name": "检查发现的账号",
"comment": "基于自动发现的账号结果进行检查分析,检查 用户组、公钥、sudoers 等信息",
},
{
"id": "00000000-0000-0000-0000-000000000002",
"slug": "check_account_secret",
"name": "检查账号密码强弱",
"comment": "基于账号密码的安全性进行检查分析, 检查密码强度、泄露等信息",
},
{
"id": "00000000-0000-0000-0000-000000000003",
"slug": "check_account_repeat",
"name": "检查账号密码是否重复",
"comment": "检查账号是否与其它账号相同"
},
{
"id": "00000000-0000-0000-0000-000000000004",
"slug": "check_account_leak",
"name": "检查账号密码是否是常见密码",
"comment": "检查账号密码是否是常见泄露的密码"
},
]
return data
def init_if_need(self):
data = self.get_default_engines()
model_cls = CheckAccountEngine
if model_cls.objects.count() == 4:
return
for item in data:
model_cls.objects.update_or_create(defaults=item, id=item["id"])
def get_queryset(self): def get_queryset(self):
# return self.get_default_engines() return CheckAccountEngine.get_default_engines()
self.init_if_need()
return CheckAccountEngine.objects.all() def filter_queryset(self, queryset: list):
search = self.request.GET.get('search')
if search is not None:
queryset = [
item for item in queryset
if search in item['name']
]
return queryset

View File

@ -6,28 +6,7 @@ import django.db.models.deletion
from django.db import migrations, models from django.db import migrations, models
def init_account_check_engine(apps, schema_editor):
data = [
{
'id': '00000000-0000-0000-0000-000000000001',
'slug': 'check_gathered_account',
'name': '检查发现的账号',
'comment': '基于自动发现的账号结果进行检查分析,检查 用户组、公钥、sudoers 等信息'
},
{
'id': '00000000-0000-0000-0000-000000000002',
'slug': 'check_account_secret',
'name': '检查账号密码强弱',
'comment': '基于账号密码的安全性进行检查分析, 检查密码强度、泄露等信息'
}
]
model_cls = apps.get_model('accounts', 'CheckAccountEngine')
for item in data:
model_cls.objects.create(**item)
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
("assets", "0007_baseautomation_date_last_run_and_more"), ("assets", "0007_baseautomation_date_last_run_and_more"),
( (
@ -139,5 +118,4 @@ class Migration(migrations.Migration):
verbose_name="Engines", verbose_name="Engines",
), ),
), ),
migrations.RunPython(init_account_check_engine),
] ]

View File

@ -0,0 +1,26 @@
# Generated by Django 4.1.13 on 2025-01-21 08:41
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('accounts', '0027_accountrisk_gathered_account'),
]
operations = [
migrations.RemoveField(
model_name='checkaccountengine',
name='is_active',
),
migrations.RemoveField(
model_name='checkaccountautomation',
name='engines',
),
migrations.AddField(
model_name='checkaccountautomation',
name='engines',
field=models.JSONField(default=list, verbose_name='Engines'),
),
]

View File

@ -15,13 +15,13 @@ __all__ = ['CheckAccountAutomation', 'AccountRisk', 'RiskChoice', 'CheckAccountE
class CheckAccountAutomation(AccountBaseAutomation): class CheckAccountAutomation(AccountBaseAutomation):
engines = models.ManyToManyField('CheckAccountEngine', related_name='check_automations', verbose_name=_('Engines')) engines = models.JSONField(default=list, verbose_name=_('Engines'))
recipients = models.ManyToManyField('users.User', verbose_name=_("Recipient"), blank=True) recipients = models.ManyToManyField('users.User', verbose_name=_("Recipient"), blank=True)
def to_attr_json(self): def to_attr_json(self):
attr_json = super().to_attr_json() attr_json = super().to_attr_json()
attr_json.update({ attr_json.update({
'engines': [engine.slug for engine in self.engines.all()], 'engines': self.engines,
'recipients': [str(user.id) for user in self.recipients.all()] 'recipients': [str(user.id) for user in self.recipients.all()]
}) })
return attr_json return attr_json
@ -117,14 +117,43 @@ class AccountRisk(JMSOrgBaseModel):
class CheckAccountEngine(JMSBaseModel): class CheckAccountEngine(JMSBaseModel):
name = models.CharField(max_length=128, verbose_name=_('Name'), unique=True) name = models.CharField(max_length=128, verbose_name=_('Name'), unique=True)
slug = models.SlugField(max_length=128, verbose_name=_('Slug'), unique=True) # slug = models.SlugField(max_length=128, verbose_name=_('Slug'), unique=True)
is_active = models.BooleanField(default=True, verbose_name=_('Is active'))
def __str__(self): def __str__(self):
return self.name return self.name
def internals(self): @staticmethod
return [ def get_default_engines():
'check_gathered_account', data = [
'check_account_secret' {
"id": "00000000-0000-0000-0000-000000000001",
"slug": "check_gathered_account",
"name": _("Check the discovered accounts"),
"comment": _(
"Perform checks and analyses based on automatically discovered account results, "
"including user groups, public keys, sudoers, and other information"
)
},
{
"id": "00000000-0000-0000-0000-000000000002",
"slug": "check_account_secret",
"name": _("Check the strength of your account and password"),
"comment": _(
"Perform checks and analyses based on the security of account passwords, "
"including password strength, leakage, etc."
)
},
{
"id": "00000000-0000-0000-0000-000000000003",
"slug": "check_account_repeat",
"name": _("Check if the account and password are repeated"),
"comment": _("Check if the account is the same as other accounts")
},
{
"id": "00000000-0000-0000-0000-000000000004",
"slug": "check_account_leak",
"name": _("Check whether the account password is a common password"),
"comment": _("Check whether the account password is a commonly leaked password")
},
] ]
return data

View File

@ -10,12 +10,12 @@ from accounts.models import (
RiskChoice, RiskChoice,
CheckAccountEngine, CheckAccountEngine,
) )
from accounts.risk_handlers import TYPE_CHOICES
from assets.models import Asset from assets.models import Asset
from common.const import ConfirmOrIgnore from common.const import ConfirmOrIgnore
from common.serializers.fields import ObjectRelatedField, LabeledChoiceField from common.serializers.fields import ObjectRelatedField, LabeledChoiceField
from common.utils import get_logger from common.utils import get_logger
from .base import BaseAutomationSerializer from .base import BaseAutomationSerializer
from accounts.risk_handlers import TYPE_CHOICES
logger = get_logger(__file__) logger = get_logger(__file__)
@ -88,9 +88,9 @@ class CheckAccountAutomationSerializer(BaseAutomationSerializer):
model = CheckAccountAutomation model = CheckAccountAutomation
read_only_fields = BaseAutomationSerializer.Meta.read_only_fields read_only_fields = BaseAutomationSerializer.Meta.read_only_fields
fields = ( fields = (
BaseAutomationSerializer.Meta.fields BaseAutomationSerializer.Meta.fields
+ ["engines", "recipients"] + ["engines", "recipients"]
+ read_only_fields + read_only_fields
) )
extra_kwargs = BaseAutomationSerializer.Meta.extra_kwargs extra_kwargs = BaseAutomationSerializer.Meta.extra_kwargs
@ -98,12 +98,18 @@ class CheckAccountAutomationSerializer(BaseAutomationSerializer):
def model_type(self): def model_type(self):
return AutomationTypes.check_account return AutomationTypes.check_account
@staticmethod
def validate_engines(engines):
valid_slugs = {i['slug'] for i in CheckAccountEngine.get_default_engines()}
if not all(engine in valid_slugs for engine in engines):
raise serializers.ValidationError(_("Invalid engine id"))
return engines
class CheckAccountEngineSerializer(serializers.ModelSerializer): class CheckAccountEngineSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = CheckAccountEngine model = CheckAccountEngine
fields = ["id", "name", "slug", "is_active", "comment"] fields = ["id", "name", "slug", "comment"]
read_only_fields = ["slug"] read_only_fields = ["slug"]
extra_kwargs = {
"is_active": {"required": False},
}