perf: some risk example file path

pull/15272/head
ibuler 2025-07-30 14:49:12 +08:00 committed by Bryan
parent 1406437d4e
commit 4e33b5b478
17 changed files with 83 additions and 62 deletions

View File

@ -5,7 +5,7 @@ from django.utils.translation import gettext_lazy as _
from common.db.fields import JSONManyToManyField from common.db.fields import JSONManyToManyField
from common.db.models import JMSBaseModel from common.db.models import JMSBaseModel
from common.utils import contains_ip from common.utils import contains_ip
from common.utils.time_period import contains_time_period from common.utils.timezone import contains_time_period
from orgs.mixins.models import OrgModelMixin, OrgManager from orgs.mixins.models import OrgModelMixin, OrgManager
from ..const import ActionChoices from ..const import ActionChoices

View File

@ -10,10 +10,12 @@ from django.core.files.storage import default_storage
from django.db import transaction from django.db import transaction
from django.utils import timezone from django.utils import timezone
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.utils._os import safe_join
from common.const.crontab import CRONTAB_AT_AM_TWO from common.const.crontab import CRONTAB_AT_AM_TWO
from common.storage.ftp_file import FTPFileStorageHandler from common.storage.ftp_file import FTPFileStorageHandler
from common.utils import get_log_keep_day, get_logger from common.utils import get_log_keep_day, get_logger
from common.utils.safe import safe_run_cmd
from ops.celery.decorator import register_as_period_task from ops.celery.decorator import register_as_period_task
from ops.models import CeleryTaskExecution from ops.models import CeleryTaskExecution
from orgs.utils import tmp_to_root_org from orgs.utils import tmp_to_root_org
@ -57,14 +59,12 @@ def clean_ftp_log_period():
now = timezone.now() now = timezone.now()
days = get_log_keep_day('FTP_LOG_KEEP_DAYS') days = get_log_keep_day('FTP_LOG_KEEP_DAYS')
expired_day = now - datetime.timedelta(days=days) expired_day = now - datetime.timedelta(days=days)
file_store_dir = os.path.join(default_storage.base_location, FTPLog.upload_to) file_store_dir = safe_join(default_storage.base_location, FTPLog.upload_to)
FTPLog.objects.filter(date_start__lt=expired_day).delete() FTPLog.objects.filter(date_start__lt=expired_day).delete()
command = "find %s -mtime +%s -type f -exec rm -f {} \\;" % ( command = "find %s -mtime +%s -type f -exec rm -f {} \\;"
file_store_dir, days safe_run_cmd(command, (file_store_dir, days))
) command = "find %s -type d -empty -delete;"
subprocess.call(command, shell=True) safe_run_cmd(command, (file_store_dir,))
command = "find %s -type d -empty -delete;" % file_store_dir
subprocess.call(command, shell=True)
logger.info("Clean FTP file done") logger.info("Clean FTP file done")
@ -76,12 +76,11 @@ def clean_celery_tasks_period():
tasks.delete() tasks.delete()
tasks = CeleryTaskExecution.objects.filter(date_start__isnull=True) tasks = CeleryTaskExecution.objects.filter(date_start__isnull=True)
tasks.delete() tasks.delete()
command = "find %s -mtime +%s -name '*.log' -type f -exec rm -f {} \\;" % ( command = "find %s -mtime +%s -name '*.log' -type f -exec rm -f {} \\;"
settings.CELERY_LOG_DIR, expire_days safe_run_cmd(command, (settings.CELERY_LOG_DIR, expire_days))
) celery_log_path = safe_join(settings.LOG_DIR, 'celery.log')
subprocess.call(command, shell=True) command = "echo > {}".format(celery_log_path)
command = "echo > {}".format(os.path.join(settings.LOG_DIR, 'celery.log')) safe_run_cmd(command, (celery_log_path,))
subprocess.call(command, shell=True)
def batch_delete(queryset, batch_size=3000): def batch_delete(queryset, batch_size=3000):
@ -119,15 +118,15 @@ def clean_expired_session_period():
expired_sessions = Session.objects.filter(date_start__lt=expire_date) expired_sessions = Session.objects.filter(date_start__lt=expire_date)
timestamp = expire_date.timestamp() timestamp = expire_date.timestamp()
expired_commands = Command.objects.filter(timestamp__lt=timestamp) expired_commands = Command.objects.filter(timestamp__lt=timestamp)
replay_dir = os.path.join(default_storage.base_location, 'replay') replay_dir = safe_join(default_storage.base_location, 'replay')
batch_delete(expired_sessions) batch_delete(expired_sessions)
logger.info("Clean session item done") logger.info("Clean session item done")
batch_delete(expired_commands) batch_delete(expired_commands)
logger.info("Clean session command done") logger.info("Clean session command done")
remove_files_by_days(replay_dir, days) remove_files_by_days(replay_dir, days)
command = "find %s -type d -empty -delete;" % replay_dir command = "find %s -type d -empty -delete;"
subprocess.call(command, shell=True) safe_run_cmd(command, (replay_dir,))
logger.info("Clean session replay done") logger.info("Clean session replay done")

View File

@ -0,0 +1,9 @@
import re
import subprocess
import shlex
def safe_run_cmd(cmd_str, cmd_args=(), shell=True):
cmd_args = [shlex.quote(arg) for arg in cmd_args]
cmd = cmd_str % tuple(cmd_args)
return subprocess.run(cmd, shell=shell)

View File

@ -1,24 +0,0 @@
from common.utils.timezone import local_now
def contains_time_period(time_periods, ctime=None):
"""
time_periods: [{"id": 1, "value": "00:00~07:30、10:00~13:00"}, {"id": 2, "value": "00:00~00:00"}]
"""
if not time_periods:
return None
if ctime is None:
ctime = local_now()
current_time = ctime.strftime('%H:%M')
today_time_period = next(filter(lambda x: str(x['id']) == local_now().strftime("%w"), time_periods))
today_time_period = today_time_period['value']
if not today_time_period:
return False
for time in today_time_period.split(''):
start, end = time.split('~')
end = "24:00" if end == "00:00" else end
if start <= current_time <= end:
return True
return False

View File

@ -57,6 +57,29 @@ def is_date_more_than(d1, d2, threshold='1d'):
return d1 - d2 > delta return d1 - d2 > delta
def contains_time_period(time_periods, ctime=None):
"""
time_periods: [{"id": 1, "value": "00:00~07:30、10:00~13:00"}, {"id": 2, "value": "00:00~00:00"}]
"""
if not time_periods:
return None
if ctime is None:
ctime = local_now()
current_time = ctime.strftime('%H:%M')
today_time_period = next(filter(lambda x: str(x['id']) == local_now().strftime("%w"), time_periods))
today_time_period = today_time_period['value']
if not today_time_period:
return False
for time in today_time_period.split(''):
start, end = time.split('~')
end = "24:00" if end == "00:00" else end
if start <= current_time <= end:
return True
return False
_rest_dt_field = DateTimeField() _rest_dt_field = DateTimeField()
dt_parser = _rest_dt_field.to_internal_value dt_parser = _rest_dt_field.to_internal_value
dt_formatter = _rest_dt_field.to_representation dt_formatter = _rest_dt_field.to_representation

View File

@ -616,7 +616,7 @@
"Gateway": "Gateway", "Gateway": "Gateway",
"GatewayCreate": "Create gateway", "GatewayCreate": "Create gateway",
"GatewayList": "Gateways", "GatewayList": "Gateways",
"GatewayPlatformHelpText": "Only platforms with names starting with Gateway can be used as gateways.", "GatewayPlatformHelpText": "Only platforms with names starting with 'Gateway' can be used as gateways.",
"GatewayUpdate": "Update the gateway", "GatewayUpdate": "Update the gateway",
"General": "General", "General": "General",
"GeneralAccounts": "General accounts", "GeneralAccounts": "General accounts",
@ -1560,4 +1560,4 @@
"userId": "User ID", "userId": "User ID",
"userName": "User name", "userName": "User name",
"EmailHelpText": "Please click the 'Submit' button to save the current configuration before clicking 'Test Connection' to ensure the settings take effect." "EmailHelpText": "Please click the 'Submit' button to save the current configuration before clicking 'Test Connection' to ensure the settings take effect."
} }

View File

@ -1564,4 +1564,4 @@
"setVariable": "configurar parámetros", "setVariable": "configurar parámetros",
"userId": "ID de usuario", "userId": "ID de usuario",
"userName": "Nombre de usuario" "userName": "Nombre de usuario"
} }

View File

@ -1569,4 +1569,4 @@
"setVariable": "パラメータ設定", "setVariable": "パラメータ設定",
"userId": "ユーザーID", "userId": "ユーザーID",
"userName": "ユーザー名" "userName": "ユーザー名"
} }

View File

@ -1564,4 +1564,4 @@
"setVariable": "설정 매개변수", "setVariable": "설정 매개변수",
"userId": "사용자 ID", "userId": "사용자 ID",
"userName": "사용자명" "userName": "사용자명"
} }

View File

@ -1565,4 +1565,4 @@
"setVariable": "Parâmetros de configuração", "setVariable": "Parâmetros de configuração",
"userId": "ID do usuário", "userId": "ID do usuário",
"userName": "Usuário" "userName": "Usuário"
} }

View File

@ -1566,4 +1566,4 @@
"setVariable": "Задать переменную", "setVariable": "Задать переменную",
"userId": "ID пользователя", "userId": "ID пользователя",
"userName": "Имя пользовател" "userName": "Имя пользовател"
} }

View File

@ -580,6 +580,10 @@
"FaviconTip": "提示:网站图标(建议图片大小为: 16px*16px", "FaviconTip": "提示:网站图标(建议图片大小为: 16px*16px",
"Features": "功能设置", "Features": "功能设置",
"FeiShu": "飞书", "FeiShu": "飞书",
"PasskeySummary": "无密码生物识别认证",
"Common": "通用",
"SSO": "单点登录",
"IdP": "身份提供者",
"FeiShuOAuth": "飞书认证", "FeiShuOAuth": "飞书认证",
"FeiShuTest": "测试", "FeiShuTest": "测试",
"FieldRequiredError": "此字段是必填项", "FieldRequiredError": "此字段是必填项",
@ -1566,4 +1570,4 @@
"userName": "用户名", "userName": "用户名",
"EmailHelpText": "请点击'提交'按钮保存当前配置后,再点击'测试连接'以确保信息生效", "EmailHelpText": "请点击'提交'按钮保存当前配置后,再点击'测试连接'以确保信息生效",
"None": "无" "None": "无"
} }

View File

@ -1569,4 +1569,4 @@
"setVariable": "設置參數", "setVariable": "設置參數",
"userId": "用戶ID", "userId": "用戶ID",
"userName": "用戶名" "userName": "用戶名"
} }

View File

@ -1,9 +1,9 @@
# ~*~ coding: utf-8 ~*~ # ~*~ coding: utf-8 ~*~
path_perms_map = { path_perms_map = {
'xpack': '*', 'xpack': 'none',
'settings': '*', 'settings': 'none',
'img': '*', 'img': 'none',
'replay': 'terminal.view_sessionreplay', 'replay': 'terminal.view_sessionreplay',
'applets': 'terminal.view_applet', 'applets': 'terminal.view_applet',
'virtual_apps': 'terminal.view_virtualapp', 'virtual_apps': 'terminal.view_virtualapp',
@ -23,7 +23,8 @@ def allow_access(private_file):
return False return False
if not path_perm: if not path_perm:
return False return False
if path_perm == '*' or request.user.has_perms([path_perm]): if path_perm == 'none' or request.user.has_perms([path_perm]):
# 不需要权限检查,任何人都可以访问
return True return True
if path_perm == 'default': if path_perm == 'default':
return request.user.is_authenticated and request.user.is_staff return request.user.is_authenticated and request.user.is_staff

View File

@ -87,15 +87,23 @@ ALLOWED_DOMAINS.extend(DEBUG_HOST_PORTS)
# for host in ALLOWED_DOMAINS: # for host in ALLOWED_DOMAINS:
# print(' - ' + host.lstrip('.')) # print(' - ' + host.lstrip('.'))
ALLOWED_HOSTS = ['*'] ALLOWED_HOSTS = []
# https://docs.djangoproject.com/en/4.1/ref/settings/#std-setting-CSRF_TRUSTED_ORIGINS # https://docs.djangoproject.com/en/4.1/ref/settings/#std-setting-CSRF_TRUSTED_ORIGINS
CSRF_TRUSTED_ORIGINS = [] CSRF_TRUSTED_ORIGINS = []
for host_port in ALLOWED_DOMAINS: for host_port in ALLOWED_DOMAINS:
origin = host_port.strip('.') origin = host_port.strip('.')
if origin.startswith('http'):
CSRF_TRUSTED_ORIGINS.append(origin) if not origin:
continue continue
if origin.startswith('http'):
origin = origin.replace('http://', '').replace('https://', '')
host = origin.split(':')[0]
if host not in ALLOWED_HOSTS:
ALLOWED_HOSTS.append(host)
is_local_origin = origin.split(':')[0] in DEBUG_HOSTS is_local_origin = origin.split(':')[0] in DEBUG_HOSTS
for schema in ['https', 'http']: for schema in ['https', 'http']:
if is_local_origin and schema == 'https': if is_local_origin and schema == 'https':

View File

@ -16,10 +16,11 @@ class RBACBackend(JMSBaseAuthBackend):
return False return False
def has_perm(self, user_obj, perm, obj=None): def has_perm(self, user_obj, perm, obj=None):
# 扫描软件对 * 毕竟敏感,所以改成 none, 虽说这个 * 是我们自定义的标识
if perm == 'none':
return True
if not user_obj.is_active or not perm: if not user_obj.is_active or not perm:
raise PermissionDenied() raise PermissionDenied()
if perm == '*':
return True
if isinstance(perm, str): if isinstance(perm, str):
perm_set = set(i.strip() for i in perm.split('|')) perm_set = set(i.strip() for i in perm.split('|'))
elif isinstance(perm, (list, tuple, set)): elif isinstance(perm, (list, tuple, set)):

View File

@ -16,10 +16,10 @@ class RBACPermission(permissions.DjangoModelPermissions):
('bulk_update', '%(app_label)s.change_%(model_name)s'), ('bulk_update', '%(app_label)s.change_%(model_name)s'),
('partial_bulk_update', '%(app_label)s.change_%(model_name)s'), ('partial_bulk_update', '%(app_label)s.change_%(model_name)s'),
('bulk_destroy', '%(app_label)s.delete_%(model_name)s'), ('bulk_destroy', '%(app_label)s.delete_%(model_name)s'),
('render_to_json', '*'), ('render_to_json', 'none'),
('metadata', '*'), ('metadata', 'none'),
('GET', '%(app_label)s.view_%(model_name)s'), ('GET', '%(app_label)s.view_%(model_name)s'),
('OPTIONS', '*'), ('OPTIONS', 'none'),
('HEAD', '%(app_label)s.view_%(model_name)s'), ('HEAD', '%(app_label)s.view_%(model_name)s'),
('POST', '%(app_label)s.add_%(model_name)s'), ('POST', '%(app_label)s.add_%(model_name)s'),
('PUT', '%(app_label)s.change_%(model_name)s'), ('PUT', '%(app_label)s.change_%(model_name)s'),