From da36c26178ef72bea4e3f73a001c17b1d6ff2897 Mon Sep 17 00:00:00 2001 From: feng <1304903146@qq.com> Date: Fri, 16 Jan 2026 18:33:19 +0800 Subject: [PATCH] perf: Adaptation vendor --- .../templates/authentication/login.html | 1 - apps/jumpserver/conf.py | 1 + apps/jumpserver/context_processor.py | 19 ++-- .../rewriting/storage/permissions.py | 6 ++ apps/jumpserver/settings/custom.py | 8 ++ apps/jumpserver/vendor.py | 92 +++++++++++++++++++ 6 files changed, 119 insertions(+), 8 deletions(-) create mode 100644 apps/jumpserver/vendor.py diff --git a/apps/authentication/templates/authentication/login.html b/apps/authentication/templates/authentication/login.html index e35e30876..bb7dc0e16 100644 --- a/apps/authentication/templates/authentication/login.html +++ b/apps/authentication/templates/authentication/login.html @@ -465,4 +465,3 @@ setInterval(checkHealth, 30 * 1000); - diff --git a/apps/jumpserver/conf.py b/apps/jumpserver/conf.py index c97bad8a6..6ed9a162a 100644 --- a/apps/jumpserver/conf.py +++ b/apps/jumpserver/conf.py @@ -740,6 +740,7 @@ class Config(dict): # oauth2_provider settings 'OAUTH2_PROVIDER_ACCESS_TOKEN_EXPIRE_SECONDS': 60 * 60, 'OAUTH2_PROVIDER_REFRESH_TOKEN_EXPIRE_SECONDS': 60 * 60 * 24 * 7, + 'VENDOR': 'jumpserver', } old_config_map = { diff --git a/apps/jumpserver/context_processor.py b/apps/jumpserver/context_processor.py index b9d195623..a37933419 100644 --- a/apps/jumpserver/context_processor.py +++ b/apps/jumpserver/context_processor.py @@ -6,17 +6,22 @@ from django.conf import settings from django.templatetags.static import static from django.utils.translation import gettext_lazy as _ +from jumpserver.vendor import get_vendor_value, is_default_vendor + default_interface = dict(( - ('logo_logout', static('img/logo.png')), - ('logo_index', static('img/logo_text_white.png')), - ('login_image', static('img/login_image.png')), - ('favicon', static('img/facio.ico')), - ('login_title', _('JumpServer - An open-source PAM')), - ('theme', 'classic_green'), + ('logo_logout', get_vendor_value('logo_logout')), + ('logo_index', get_vendor_value('logo_index')), + ('login_image', get_vendor_value('login_image')), + ('favicon', get_vendor_value('favicon')), + ('login_title', get_vendor_value('login_title', default=_('JumpServer - An open-source PAM'))), + ('theme', get_vendor_value('theme', default='classic_green')), ('theme_info', {}), - ('footer_content', ''), + ('footer_content', get_vendor_value('footer_content', default='')), )) +if not is_default_vendor(): + default_interface['theme_info'] = get_vendor_value('theme_info', default={}) + current_year = datetime.datetime.now().year default_context = { diff --git a/apps/jumpserver/rewriting/storage/permissions.py b/apps/jumpserver/rewriting/storage/permissions.py index 7eb0bc771..023918fd2 100644 --- a/apps/jumpserver/rewriting/storage/permissions.py +++ b/apps/jumpserver/rewriting/storage/permissions.py @@ -1,5 +1,7 @@ # ~*~ coding: utf-8 ~*~ +from django.conf import settings + path_perms_map = { 'xpack': 'none', 'settings': 'none', @@ -17,6 +19,10 @@ def allow_access(private_file): request_path = private_file.request.path path_list = str(request_path)[1:].split('/') path_base = path_list[1] if len(path_list) > 1 else None + if path_base not in path_perms_map and len(path_list) > 2: + vendor = path_list[1] + if vendor == settings.VENDOR: + path_base = path_list[2] path_perm = path_perms_map.get(path_base, None) if ".." in request_path: diff --git a/apps/jumpserver/settings/custom.py b/apps/jumpserver/settings/custom.py index a3990ff0d..1c553ced0 100644 --- a/apps/jumpserver/settings/custom.py +++ b/apps/jumpserver/settings/custom.py @@ -1,5 +1,8 @@ # -*- coding: utf-8 -*- # +from pathlib import Path + +from .base import TEMPLATES, STATIC_DIR from ..const import CONFIG # Storage settings @@ -267,3 +270,8 @@ TOOL_USER_ENABLED = CONFIG.TOOL_USER_ENABLED SUGGESTION_LIMIT = CONFIG.SUGGESTION_LIMIT MCP_ENABLED = CONFIG.MCP_ENABLED + +VENDOR = CONFIG.VENDOR +VENDOR_TEMPLATES_DIR = Path(STATIC_DIR) / VENDOR +if Path(VENDOR_TEMPLATES_DIR).is_dir(): + TEMPLATES[0]['DIRS'].insert(0, VENDOR_TEMPLATES_DIR) diff --git a/apps/jumpserver/vendor.py b/apps/jumpserver/vendor.py new file mode 100644 index 000000000..5f254ed0b --- /dev/null +++ b/apps/jumpserver/vendor.py @@ -0,0 +1,92 @@ +import json +from pathlib import Path + +from django.conf import settings +from django.contrib.staticfiles import finders +from django.templatetags.static import static + +DEFAULT_VENDOR = "jumpserver" +DEFAULT_LOGIN_TEMPLATE = "authentication/login.html" +DEFAULT_THEME = "classic_green" + +VENDOR_THEMES_DIR = settings.VENDOR_TEMPLATES_DIR / "themes" + + +def is_default_vendor() -> bool: + return settings.VENDOR == DEFAULT_VENDOR + + +def find_theme_path(theme_dirs, theme_name: str) -> Path | None: + filename = f"{theme_name}.json" + for d in theme_dirs: + p = d / filename + if p.is_file(): + return p + + +def _default_theme_dir() -> Path: + data_dir = Path(settings.BASE_DIR) + return data_dir / "xpack" / "plugins" / "interface" / "themes" + + +def _build_theme() -> str: + return DEFAULT_THEME if is_default_vendor() else settings.VENDOR + + +def _build_theme_info() -> dict: + default_theme_path = find_theme_path([_default_theme_dir()], DEFAULT_THEME) + + search_dirs = [_default_theme_dir()] if is_default_vendor() else [ + settings.VENDOR_TEMPLATES_DIR / 'themes', + _default_theme_dir(), + ] + theme_name = DEFAULT_THEME if is_default_vendor() else settings.VENDOR + + theme_path = find_theme_path(search_dirs, theme_name) or default_theme_path + return json.loads(theme_path.read_text(encoding="utf-8")) + + +def _build_vendor_info() -> dict: + if is_default_vendor(): + return {} + info_path = settings.VENDOR_TEMPLATES_DIR / "info.json" + if not info_path.exists(): + return {} + return json.loads(info_path.read_text(encoding="utf-8")) + + +def _build_vendor_info_value(key: str, default=None): + info = _build_vendor_info() + return info.get(key, default) + + +def _build_asset(filename: str) -> str: + if is_default_vendor(): + return static(filename) + + vendor_path = f"{settings.VENDOR}/{filename}" + if finders.find(vendor_path): + return static(vendor_path) + return static(filename) + + +VENDOR_BUILDERS = { + "theme": _build_theme, + "theme_info": _build_theme_info, + "logo_logout": lambda: _build_asset("img/logo.png"), + "logo_index": lambda: _build_asset("img/logo_text_white.png"), + "login_image": lambda: _build_asset("img/login_image.png"), + "favicon": lambda: _build_asset("img/facio.ico"), + "logo_white": lambda: _build_asset("img/logo_white.png"), + "logo_text_white": lambda: _build_asset("img/logo_text_white.png"), + "login_title": lambda: _build_vendor_info_value("login_title"), + "footer_content": lambda: _build_vendor_info_value("footer_content"), +} + + +def get_vendor_value(kind: str, default=None): + builder = VENDOR_BUILDERS.get(kind) + if not builder: + return default + value = builder() + return default if value is None else value