mirror of https://github.com/jumpserver/jumpserver
perf: 修改命令command input 长度问题 (#7996)
* perf: 修改命令command input max_length 1024 * perf: 修改命令command input 长度问题 * perf: 修改命令command input 长度问题 * perf: 修改命令command input 长度问题 * perf: 修改命令command input 长度问题 Co-authored-by: Jiangjie.Bai <bugatti_it@163.com>pull/7999/head
parent
54d1996507
commit
e7af037513
|
@ -338,3 +338,24 @@ def get_file_by_arch(dir, filename):
|
|||
settings.BASE_DIR, dir, platform_name, arch, filename
|
||||
)
|
||||
return file_path
|
||||
|
||||
|
||||
def pretty_string(data: str, max_length=128, ellipsis_str='...'):
|
||||
"""
|
||||
params:
|
||||
data: abcdefgh
|
||||
max_length: 7
|
||||
ellipsis_str: ...
|
||||
return:
|
||||
ab...gh
|
||||
"""
|
||||
if len(data) < max_length:
|
||||
return data
|
||||
remain_length = max_length - len(ellipsis_str)
|
||||
half = remain_length // 2
|
||||
if half <= 1:
|
||||
return data[:max_length]
|
||||
start = data[:half]
|
||||
end = data[-half:]
|
||||
data = f'{start}{ellipsis_str}{end}'
|
||||
return data
|
||||
|
|
|
@ -14,7 +14,7 @@ from terminal.filters import CommandFilter
|
|||
from orgs.utils import current_org
|
||||
from common.drf.api import JMSBulkModelViewSet
|
||||
from common.utils import get_logger
|
||||
from terminal.serializers import InsecureCommandAlertSerializer
|
||||
from terminal.backends.command.serializers import InsecureCommandAlertSerializer
|
||||
from terminal.exceptions import StorageInvalid
|
||||
from ..backends import (
|
||||
get_command_storage, get_multi_command_storage,
|
||||
|
|
|
@ -4,6 +4,7 @@ import datetime
|
|||
from django.db import transaction
|
||||
from django.utils import timezone
|
||||
from django.db.utils import OperationalError
|
||||
from common.utils.common import pretty_string
|
||||
|
||||
from .base import CommandBase
|
||||
|
||||
|
@ -32,9 +33,11 @@ class CommandStore(CommandBase):
|
|||
"""
|
||||
_commands = []
|
||||
for c in commands:
|
||||
cmd_input = pretty_string(c['input'])
|
||||
cmd_output = pretty_string(c['output'], max_length=1024)
|
||||
_commands.append(self.model(
|
||||
user=c["user"], asset=c["asset"], system_user=c["system_user"],
|
||||
input=c["input"], output=c["output"], session=c["session"],
|
||||
input=cmd_input, output=cmd_output, session=c["session"],
|
||||
risk_level=c.get("risk_level", 0), org_id=c["org_id"],
|
||||
timestamp=c["timestamp"]
|
||||
))
|
||||
|
|
|
@ -4,27 +4,19 @@ from rest_framework import serializers
|
|||
|
||||
from .models import AbstractSessionCommand
|
||||
|
||||
__all__ = ['SessionCommandSerializer', 'InsecureCommandAlertSerializer']
|
||||
|
||||
class SessionCommandSerializer(serializers.Serializer):
|
||||
"""使用这个类作为基础Command Log Serializer类, 用来序列化"""
|
||||
|
||||
id = serializers.UUIDField(read_only=True)
|
||||
class SimpleSessionCommandSerializer(serializers.Serializer):
|
||||
""" 简单Session命令序列类, 用来提取公共字段 """
|
||||
user = serializers.CharField(label=_("User")) # 限制 64 字符,见 validate_user
|
||||
asset = serializers.CharField(max_length=128, label=_("Asset"))
|
||||
system_user = serializers.CharField(max_length=64, label=_("System user"))
|
||||
input = serializers.CharField(max_length=128, label=_("Command"))
|
||||
output = serializers.CharField(max_length=1024, allow_blank=True, label=_("Output"))
|
||||
input = serializers.CharField(max_length=2048, label=_("Command"))
|
||||
session = serializers.CharField(max_length=36, label=_("Session ID"))
|
||||
risk_level = serializers.ChoiceField(required=False, label=_("Risk level"), choices=AbstractSessionCommand.RISK_LEVEL_CHOICES)
|
||||
risk_level_display = serializers.SerializerMethodField(label=_('Risk level display'))
|
||||
risk_level = serializers.ChoiceField(
|
||||
required=False, label=_("Risk level"), choices=AbstractSessionCommand.RISK_LEVEL_CHOICES
|
||||
)
|
||||
org_id = serializers.CharField(max_length=36, required=False, default='', allow_null=True, allow_blank=True)
|
||||
timestamp = serializers.IntegerField(label=_('Timestamp'))
|
||||
remote_addr = serializers.CharField(read_only=True, label=_('Remote Address'))
|
||||
|
||||
@staticmethod
|
||||
def get_risk_level_display(obj):
|
||||
risk_mapper = dict(AbstractSessionCommand.RISK_LEVEL_CHOICES)
|
||||
return risk_mapper.get(obj.risk_level)
|
||||
|
||||
def validate_user(self, value):
|
||||
if len(value) > 64:
|
||||
|
@ -32,9 +24,21 @@ class SessionCommandSerializer(serializers.Serializer):
|
|||
return value
|
||||
|
||||
|
||||
class InsecureCommandAlertSerializer(serializers.Serializer):
|
||||
input = serializers.CharField()
|
||||
asset = serializers.CharField()
|
||||
user = serializers.CharField()
|
||||
risk_level = serializers.IntegerField()
|
||||
session = serializers.UUIDField()
|
||||
class InsecureCommandAlertSerializer(SimpleSessionCommandSerializer):
|
||||
pass
|
||||
|
||||
|
||||
class SessionCommandSerializer(SimpleSessionCommandSerializer):
|
||||
"""使用这个类作为基础Command Log Serializer类, 用来序列化"""
|
||||
|
||||
id = serializers.UUIDField(read_only=True)
|
||||
system_user = serializers.CharField(max_length=64, label=_("System user"))
|
||||
output = serializers.CharField(max_length=2048, allow_blank=True, label=_("Output"))
|
||||
risk_level_display = serializers.SerializerMethodField(label=_('Risk level display'))
|
||||
timestamp = serializers.IntegerField(label=_('Timestamp'))
|
||||
remote_addr = serializers.CharField(read_only=True, label=_('Remote Address'))
|
||||
|
||||
@staticmethod
|
||||
def get_risk_level_display(obj):
|
||||
risk_mapper = dict(AbstractSessionCommand.RISK_LEVEL_CHOICES)
|
||||
return risk_mapper.get(obj.risk_level)
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
import time
|
||||
|
||||
from django.db import models
|
||||
from django.db.models.signals import post_save
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
@ -18,6 +20,33 @@ class CommandManager(models.Manager):
|
|||
class Command(AbstractSessionCommand):
|
||||
objects = CommandManager()
|
||||
|
||||
@classmethod
|
||||
def generate_fake(cls, count=100, org=None):
|
||||
import uuid
|
||||
import datetime
|
||||
from orgs.models import Organization
|
||||
from common.utils import random_string
|
||||
|
||||
if not org:
|
||||
org = Organization.default()
|
||||
|
||||
d = datetime.datetime.now() - datetime.timedelta(days=1)
|
||||
commands = [
|
||||
cls(**{
|
||||
'user': random_string(6),
|
||||
'asset': random_string(10),
|
||||
'system_user': random_string(6),
|
||||
'session': str(uuid.uuid4()),
|
||||
'input': random_string(16),
|
||||
'output': random_string(64),
|
||||
'timestamp': int(d.timestamp()),
|
||||
'org_id': str(org.id)
|
||||
})
|
||||
for i in range(count)
|
||||
]
|
||||
cls.objects.bulk_create(commands)
|
||||
print(f'Create {len(commands)} commands of org ({org})')
|
||||
|
||||
class Meta:
|
||||
db_table = "terminal_command"
|
||||
ordering = ('-timestamp',)
|
||||
|
|
|
@ -3,5 +3,4 @@
|
|||
from .terminal import *
|
||||
from .session import *
|
||||
from .storage import *
|
||||
from .command import *
|
||||
from .sharing import *
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
# ~*~ coding: utf-8 ~*~
|
||||
from rest_framework import serializers
|
||||
|
||||
|
||||
class InsecureCommandAlertSerializer(serializers.Serializer):
|
||||
input = serializers.CharField()
|
||||
asset = serializers.CharField()
|
||||
user = serializers.CharField()
|
||||
risk_level = serializers.IntegerField()
|
||||
session = serializers.UUIDField()
|
||||
org_id = serializers.CharField()
|
|
@ -4,7 +4,7 @@ from django.utils.translation import ugettext_lazy as _
|
|||
from common.drf.serializers import BulkModelSerializer, AdaptedBulkListSerializer
|
||||
from common.utils import is_uuid
|
||||
from users.serializers import ServiceAccountSerializer
|
||||
from common.utils import get_request_ip
|
||||
from common.utils import get_request_ip, pretty_string
|
||||
from .. import const
|
||||
|
||||
from ..models import (
|
||||
|
@ -111,12 +111,11 @@ class TerminalRegistrationSerializer(serializers.ModelSerializer):
|
|||
valid = super().is_valid(raise_exception=raise_exception)
|
||||
if not valid:
|
||||
return valid
|
||||
name = self.validated_data.get('name')
|
||||
if len(name) > 128:
|
||||
self.validated_data['comment'] = name
|
||||
name = '{}...{}'.format(name[:32], name[-32:])
|
||||
self.validated_data['name'] = name
|
||||
|
||||
raw_name = self.validated_data.get('name')
|
||||
name = pretty_string(raw_name)
|
||||
self.validated_data['name'] = name
|
||||
if len(raw_name) > 128:
|
||||
self.validated_data['comment'] = raw_name
|
||||
data = {'name': name}
|
||||
kwargs = {'data': data}
|
||||
if self.instance and self.instance.user:
|
||||
|
|
|
@ -401,10 +401,12 @@ class RoleMixin:
|
|||
def is_staff(self, value):
|
||||
pass
|
||||
|
||||
service_account_email_suffix = '@local.domain'
|
||||
|
||||
@classmethod
|
||||
def create_service_account(cls, name, comment):
|
||||
def create_service_account(cls, name, email, comment):
|
||||
app = cls.objects.create(
|
||||
username=name, name=name, email='{}@local.domain'.format(name),
|
||||
username=name, name=name, email=email,
|
||||
comment=comment, is_first_login=False,
|
||||
created_by='System', is_service_account=True,
|
||||
)
|
||||
|
|
|
@ -6,6 +6,7 @@ from rest_framework import serializers
|
|||
|
||||
from common.mixins import CommonBulkSerializerMixin
|
||||
from common.validators import PhoneValidator
|
||||
from common.utils import pretty_string
|
||||
from rbac.builtin import BuiltinRole
|
||||
from rbac.permissions import RBACPermission
|
||||
from rbac.models import OrgRoleBinding, SystemRoleBinding, Role
|
||||
|
@ -268,7 +269,9 @@ class ServiceAccountSerializer(serializers.ModelSerializer):
|
|||
|
||||
def get_email(self):
|
||||
name = self.initial_data.get('name')
|
||||
return '{}@serviceaccount.local'.format(name)
|
||||
name_max_length = 128 - len(User.service_account_email_suffix)
|
||||
name = pretty_string(name, max_length=name_max_length, ellipsis_str='-')
|
||||
return '{}{}'.format(name, User.service_account_email_suffix)
|
||||
|
||||
def validate_name(self, name):
|
||||
email = self.get_email()
|
||||
|
@ -283,6 +286,7 @@ class ServiceAccountSerializer(serializers.ModelSerializer):
|
|||
|
||||
def create(self, validated_data):
|
||||
name = validated_data['name']
|
||||
email = self.get_email()
|
||||
comment = validated_data.get('comment', '')
|
||||
user, ak = User.create_service_account(name, comment)
|
||||
user, ak = User.create_service_account(name, email, comment)
|
||||
return user
|
||||
|
|
|
@ -11,7 +11,7 @@ from django.conf import settings
|
|||
from django.core.cache import cache
|
||||
|
||||
from common.tasks import send_mail_async
|
||||
from common.utils import reverse, get_object_or_none, ip
|
||||
from common.utils import reverse, get_object_or_none, ip, pretty_string
|
||||
from .models import User
|
||||
|
||||
logger = logging.getLogger('jumpserver')
|
||||
|
@ -229,12 +229,14 @@ class LoginIpBlockUtil(BlockGlobalIpUtilBase):
|
|||
BLOCK_KEY_TMPL = "_LOGIN_BLOCK_{}"
|
||||
|
||||
|
||||
def construct_user_email(username, email):
|
||||
if '@' not in email:
|
||||
if '@' in username:
|
||||
email = username
|
||||
else:
|
||||
email = '{}@{}'.format(username, settings.EMAIL_SUFFIX)
|
||||
def construct_user_email(username, email, email_suffix=''):
|
||||
if '@' in email:
|
||||
return email
|
||||
if '@' in username:
|
||||
return username
|
||||
if not email_suffix:
|
||||
email_suffix = settings.EMAIL_SUFFIX
|
||||
email = f'{username}@{email_suffix}'
|
||||
return email
|
||||
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ django.setup()
|
|||
from resources.assets import AssetsGenerator, NodesGenerator, SystemUsersGenerator, AdminUsersGenerator
|
||||
from resources.users import UserGroupGenerator, UserGenerator
|
||||
from resources.perms import AssetPermissionGenerator
|
||||
from resources.terminal import CommandGenerator
|
||||
# from resources.system import StatGenerator
|
||||
|
||||
|
||||
|
@ -26,6 +27,7 @@ resource_generator_mapper = {
|
|||
'user': UserGenerator,
|
||||
'user_group': UserGroupGenerator,
|
||||
'asset_permission': AssetPermissionGenerator,
|
||||
'command': CommandGenerator,
|
||||
# 'stat': StatGenerator
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
from .base import FakeDataGenerator
|
||||
from terminal.models import Command
|
||||
|
||||
|
||||
class CommandGenerator(FakeDataGenerator):
|
||||
resource = 'command'
|
||||
|
||||
def do_generate(self, batch, batch_size):
|
||||
Command.generate_fake(len(batch), self.org)
|
||||
|
Loading…
Reference in New Issue