From a079821976a4240f8009612ee34f1567409c04f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=86=B0=E8=8B=B7=E6=99=B6?= <2749332490@qq.com> Date: Mon, 17 Mar 2025 23:12:23 +0800 Subject: [PATCH] fix: fix SSL certificateverification error during GitHub plugin installation. - Create a custom SSL context using certifi for proper HTTPS certificate verification, meow - Add the ssl parameter to aiohttp requests to prevent download failure due to missing root certificates, meow - Improve error messages and enhance the overall plugin installation process, meow! --- pkg/plugin/installers/github.py | 55 ++++++++++----------------------- 1 file changed, 17 insertions(+), 38 deletions(-) diff --git a/pkg/plugin/installers/github.py b/pkg/plugin/installers/github.py index 45439579..039ff196 100644 --- a/pkg/plugin/installers/github.py +++ b/pkg/plugin/installers/github.py @@ -4,6 +4,8 @@ import re import os import shutil import zipfile +import ssl +import certifi import aiohttp import aiofiles @@ -21,44 +23,39 @@ class GitHubRepoInstaller(installer.PluginInstaller): def get_github_plugin_repo_label(self, repo_url: str) -> list[str]: """获取username, repo""" - - # 提取 username/repo , 正则表达式 repo = re.findall( r"(?:https?://github\.com/|git@github\.com:)([^/]+/[^/]+?)(?:\.git|/|$)", repo_url, ) - - if len(repo) > 0: # github + if len(repo) > 0: return repo[0].split("/") else: return None - + async def download_plugin_source_code(self, repo_url: str, target_path: str, task_context: taskmgr.TaskContext = taskmgr.TaskContext.placeholder()) -> str: """下载插件源码(全异步)""" - - # 提取 username/repo , 正则表达式 repo = self.get_github_plugin_repo_label(repo_url) - - target_path += repo[1] - if repo is None: raise errors.PluginInstallerError('仅支持GitHub仓库地址') + target_path += repo[1] self.ap.logger.debug("正在下载源码...") task_context.trace("下载源码...", "download-plugin-source-code") zipball_url = f"https://api.github.com/repos/{'/'.join(repo)}/zipball/HEAD" - zip_resp: bytes = None + + # 创建自定义SSL上下文,使用certifi提供的根证书 + ssl_context = ssl.create_default_context(cafile=certifi.where()) async with aiohttp.ClientSession(trust_env=True) as session: async with session.get( url=zipball_url, - timeout=aiohttp.ClientTimeout(total=300) + timeout=aiohttp.ClientTimeout(total=300), + ssl=ssl_context # 使用自定义SSL上下文来验证证书 ) as resp: if resp.status != 200: - raise errors.PluginInstallerError(f"下载源码失败: {resp.text}") - + raise errors.PluginInstallerError(f"下载源码失败: {await resp.text()}") zip_resp = await resp.read() if await aiofiles_os.path.exists("temp/" + target_path): @@ -80,15 +77,11 @@ class GitHubRepoInstaller(installer.PluginInstaller): await aiofiles_os.remove("temp/" + target_path + "/source.zip") import glob - unzip_dir = glob.glob("temp/" + target_path + "/*")[0] - await aioshutil.copytree(unzip_dir, target_path + "/") - await aioshutil.rmtree(unzip_dir) self.ap.logger.debug("源码下载完成。") - return repo[1] async def install_requirements(self, path: str): @@ -100,20 +93,14 @@ class GitHubRepoInstaller(installer.PluginInstaller): plugin_source: str, task_context: taskmgr.TaskContext = taskmgr.TaskContext.placeholder(), ): - """安装插件 - """ + """安装插件""" task_context.trace("下载插件源码...", "install-plugin") - repo_label = await self.download_plugin_source_code(plugin_source, "plugins/", task_context) - task_context.trace("安装插件依赖...", "install-plugin") - await self.install_requirements("plugins/" + repo_label) - task_context.trace("完成.", "install-plugin") - await self.ap.plugin_mgr.setting.record_installed_plugin_source( - "plugins/"+repo_label+'/', plugin_source + "plugins/" + repo_label + '/', plugin_source ) async def uninstall_plugin( @@ -121,10 +108,8 @@ class GitHubRepoInstaller(installer.PluginInstaller): plugin_name: str, task_context: taskmgr.TaskContext = taskmgr.TaskContext.placeholder(), ): - """卸载插件 - """ + """卸载插件""" plugin_container = self.ap.plugin_mgr.get_plugin_by_name(plugin_name) - if plugin_container is None: raise errors.PluginInstallerError('插件不存在或未成功加载') else: @@ -135,24 +120,18 @@ class GitHubRepoInstaller(installer.PluginInstaller): async def update_plugin( self, plugin_name: str, - plugin_source: str=None, + plugin_source: str = None, task_context: taskmgr.TaskContext = taskmgr.TaskContext.placeholder(), ): - """更新插件 - """ + """更新插件""" task_context.trace("更新插件...", "update-plugin") - plugin_container = self.ap.plugin_mgr.get_plugin_by_name(plugin_name) - if plugin_container is None: raise errors.PluginInstallerError('插件不存在或未成功加载') else: if plugin_container.plugin_source: plugin_source = plugin_container.plugin_source - task_context.trace("转交安装任务.", "update-plugin") - await self.install_plugin(plugin_source, task_context) - else: - raise errors.PluginInstallerError('插件无源码信息,无法更新') + raise errors.PluginInstallerError('插件无源码信息,无法更新') \ No newline at end of file