diff --git a/api/controllers/console/app/app.py b/api/controllers/console/app/app.py index e1467d7381..8cc3cf98c2 100644 --- a/api/controllers/console/app/app.py +++ b/api/controllers/console/app/app.py @@ -168,6 +168,22 @@ class AppImportFromUrlApi(Resource): return app, 201 +class AppImportFromUrlDependenciesCheckApi(Resource): + @setup_required + @login_required + @account_initialization_required + def post(self): + parser = reqparse.RequestParser() + parser.add_argument("url", type=str, required=True, nullable=False, location="json") + args = parser.parse_args() + + leaked_dependencies = AppDslService.check_dependencies_from_url( + tenant_id=current_user.current_tenant_id, url=args["url"], account=current_user + ) + + return jsonable_encoder({"leaked": leaked_dependencies}), 200 + + class AppApi(Resource): @setup_required @login_required @@ -391,6 +407,7 @@ api.add_resource(AppListApi, "/apps") api.add_resource(AppImportDependenciesCheckApi, "/apps/import/dependencies/check") api.add_resource(AppImportApi, "/apps/import") api.add_resource(AppImportFromUrlApi, "/apps/import/url") +api.add_resource(AppImportFromUrlDependenciesCheckApi, "/apps/import/url/dependencies/check") api.add_resource(AppApi, "/apps/") api.add_resource(AppCopyApi, "/apps//copy") api.add_resource(AppExportApi, "/apps//export") diff --git a/api/services/app_dsl_service/service.py b/api/services/app_dsl_service/service.py index a1ebd98d59..5fed40f2f5 100644 --- a/api/services/app_dsl_service/service.py +++ b/api/services/app_dsl_service/service.py @@ -37,6 +37,7 @@ from .exc import ( logger = logging.getLogger(__name__) current_dsl_version = "0.1.3" +dsl_max_size = 10 * 1024 * 1024 # 10MB class AppDslService: @@ -49,12 +50,11 @@ class AppDslService: :param args: request args :param account: Account instance """ - max_size = 10 * 1024 * 1024 # 10MB response = ssrf_proxy.get(url.strip(), follow_redirects=True, timeout=(10, 10)) response.raise_for_status() content = response.content - if len(content) > max_size: + if len(content) > dsl_max_size: raise FileSizeLimitExceededError("File size exceeds the limit of 10MB") if not content: @@ -67,6 +67,25 @@ class AppDslService: return cls.import_and_create_new_app(tenant_id, data, args, account) + @classmethod + def check_dependencies_from_url(cls, tenant_id: str, url: str, account: Account) -> list[PluginDependency]: + """ + Check dependencies from url + """ + response = ssrf_proxy.get(url.strip(), follow_redirects=True, timeout=(10, 10)) + response.raise_for_status() + content = response.content + + if len(content) > dsl_max_size: + raise FileSizeLimitExceededError("File size exceeds the limit of 10MB") + + try: + data = content.decode("utf-8") + except UnicodeDecodeError as e: + raise ContentDecodingError(f"Error decoding content: {e}") + + return cls.check_dependencies(tenant_id, data, account) + @classmethod def check_dependencies(cls, tenant_id: str, data: str, account: Account) -> list[PluginDependency]: """