From 9a682f100922f89ce3dd44bab46ab203fc7eee72 Mon Sep 17 00:00:00 2001 From: GareArc Date: Thu, 5 Mar 2026 01:16:45 -0800 Subject: [PATCH] fix: use LicenseStatus enum instead of raw strings and tighten path prefix matching Replace raw license status strings with LicenseStatus enum values in app_factory.py and enterprise_service.py to prevent silent mismatches. Use trailing-slash prefixes ('/console/api/', '/api/') to avoid false matches on unrelated paths like /api-docs. --- api/app_factory.py | 10 +++++----- api/services/enterprise/base.py | 5 +---- api/services/enterprise/enterprise_service.py | 8 +++++--- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/api/app_factory.py b/api/app_factory.py index 09ee1ee6ee..efefa7a455 100644 --- a/api/app_factory.py +++ b/api/app_factory.py @@ -11,6 +11,7 @@ from controllers.console.error import UnauthorizedAndForceLogout from core.logging.context import init_request_context from dify_app import DifyApp from services.enterprise.enterprise_service import EnterpriseService +from services.feature_service import LicenseStatus logger = logging.getLogger(__name__) @@ -38,8 +39,8 @@ def create_flask_app_with_configs() -> DifyApp: # When license expires, block all API access except bootstrap endpoints needed # for the frontend to load the license expiration page without infinite reloads. if dify_config.ENTERPRISE_ENABLED: - is_console_api = request.path.startswith("/console/api") - is_webapp_api = request.path.startswith("/api") and not is_console_api + is_console_api = request.path.startswith("/console/api/") + is_webapp_api = request.path.startswith("/api/") and not is_console_api if is_console_api or is_webapp_api: if is_console_api: @@ -70,14 +71,13 @@ def create_flask_app_with_configs() -> DifyApp: try: # Check license status with caching (10 min TTL) license_status = EnterpriseService.get_cached_license_status() - if license_status in ["inactive", "expired", "lost"]: + if license_status in (LicenseStatus.INACTIVE, LicenseStatus.EXPIRED, LicenseStatus.LOST): # Cookie clearing is handled by register_external_error_handlers # in libs/external_api.py which detects the error code and calls # build_force_logout_cookie_headers(). Frontend then checks # code === 'unauthorized_and_force_logout' and calls location.reload(). raise UnauthorizedAndForceLogout( - f"Enterprise license is {license_status}. " - "Please contact your administrator." + f"Enterprise license is {license_status}. Please contact your administrator." ) except UnauthorizedAndForceLogout: raise diff --git a/api/services/enterprise/base.py b/api/services/enterprise/base.py index 86cca34cf2..cc29ecfdc4 100644 --- a/api/services/enterprise/base.py +++ b/api/services/enterprise/base.py @@ -101,10 +101,7 @@ class BaseRequest: # {"message": "..."} # {"detail": "..."} error_message = ( - error_data.get("message") - or error_data.get("error") - or error_data.get("detail") - or error_message + error_data.get("message") or error_data.get("error") or error_data.get("detail") or error_message ) except Exception: # If JSON parsing fails, use the default message diff --git a/api/services/enterprise/enterprise_service.py b/api/services/enterprise/enterprise_service.py index c2d89283a6..8e1da916e6 100644 --- a/api/services/enterprise/enterprise_service.py +++ b/api/services/enterprise/enterprise_service.py @@ -258,9 +258,11 @@ class EnterpriseService: info = cls.get_info() license_info = info.get("License") if license_info: - status = license_info.get("status", "inactive") + from services.feature_service import LicenseStatus + + status = license_info.get("status", LicenseStatus.INACTIVE) # Only cache valid statuses so license updates are picked up immediately - if status in ("active", "expiring"): + if status in (LicenseStatus.ACTIVE, LicenseStatus.EXPIRING): try: redis_client.setex(LICENSE_STATUS_CACHE_KEY, LICENSE_STATUS_CACHE_TTL, status) except Exception: @@ -269,4 +271,4 @@ class EnterpriseService: except Exception: logger.exception("Failed to get enterprise license status") - return None \ No newline at end of file + return None