mirror of https://github.com/jumpserver/jumpserver
perf: some risk example file path
parent
1406437d4e
commit
4e33b5b478
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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")
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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)
|
|
@ -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
|
|
|
@ -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
|
||||||
|
|
|
@ -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."
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1569,4 +1569,4 @@
|
||||||
"setVariable": "パラメータ設定",
|
"setVariable": "パラメータ設定",
|
||||||
"userId": "ユーザーID",
|
"userId": "ユーザーID",
|
||||||
"userName": "ユーザー名"
|
"userName": "ユーザー名"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1564,4 +1564,4 @@
|
||||||
"setVariable": "설정 매개변수",
|
"setVariable": "설정 매개변수",
|
||||||
"userId": "사용자 ID",
|
"userId": "사용자 ID",
|
||||||
"userName": "사용자명"
|
"userName": "사용자명"
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1566,4 +1566,4 @@
|
||||||
"setVariable": "Задать переменную",
|
"setVariable": "Задать переменную",
|
||||||
"userId": "ID пользователя",
|
"userId": "ID пользователя",
|
||||||
"userName": "Имя пользовател"
|
"userName": "Имя пользовател"
|
||||||
}
|
}
|
||||||
|
|
|
@ -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": "无"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1569,4 +1569,4 @@
|
||||||
"setVariable": "設置參數",
|
"setVariable": "設置參數",
|
||||||
"userId": "用戶ID",
|
"userId": "用戶ID",
|
||||||
"userName": "用戶名"
|
"userName": "用戶名"
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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':
|
||||||
|
|
|
@ -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)):
|
||||||
|
|
|
@ -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'),
|
||||||
|
|
Loading…
Reference in New Issue