From 4688c41b9bd3b8185539f38a13caaeff653ef163 Mon Sep 17 00:00:00 2001 From: Deroino <117969239+Deroino@users.noreply.github.com> Date: Thu, 13 Nov 2025 10:37:19 +0800 Subject: [PATCH] feat(account-management): add upload and download cookie file buttons MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add '上传Cookie文件' and '下载Cookie文件' buttons to account management page - Implement frontend functionality for cookie file upload and download - Add backend API endpoints for handling cookie file operations: - /uploadCookie: Handle cookie file upload with validation - /downloadCookie: Handle secure cookie file download - Implement security measures to prevent path traversal attacks - Add proper error handling and user feedback - Maintain existing functionality while adding new features --- sau_backend.py | 121 +++++++++++++++++++ sau_frontend/src/views/AccountManagement.vue | 83 ++++++++++++- 2 files changed, 203 insertions(+), 1 deletion(-) diff --git a/sau_backend.py b/sau_backend.py index 480bbfc..1b41512 100644 --- a/sau_backend.py +++ b/sau_backend.py @@ -476,6 +476,127 @@ def postVideoBatch(): "data": None }), 200 +# Cookie文件上传API +@app.route('/uploadCookie', methods=['POST']) +def upload_cookie(): + try: + if 'file' not in request.files: + return jsonify({ + "code": 500, + "msg": "没有找到Cookie文件", + "data": None + }), 400 + + file = request.files['file'] + if file.filename == '': + return jsonify({ + "code": 500, + "msg": "Cookie文件名不能为空", + "data": None + }), 400 + + if not file.filename.endswith('.json'): + return jsonify({ + "code": 500, + "msg": "Cookie文件必须是JSON格式", + "data": None + }), 400 + + # 获取账号信息 + account_id = request.form.get('id') + platform = request.form.get('platform') + + if not account_id or not platform: + return jsonify({ + "code": 500, + "msg": "缺少账号ID或平台信息", + "data": None + }), 400 + + # 从数据库获取账号的文件路径 + with sqlite3.connect(Path(BASE_DIR / "db" / "database.db")) as conn: + conn.row_factory = sqlite3.Row + cursor = conn.cursor() + cursor.execute('SELECT filePath FROM user_info WHERE id = ?', (account_id,)) + result = cursor.fetchone() + + if not result: + return jsonify({ + "code": 500, + "msg": "账号不存在", + "data": None + }), 404 + + # 保存上传的Cookie文件到对应路径 + cookie_file_path = Path(BASE_DIR / "cookiesFile" / result['filePath']) + cookie_file_path.parent.mkdir(parents=True, exist_ok=True) + + file.save(str(cookie_file_path)) + + # 更新数据库中的账号信息(可选,比如更新更新时间) + # 这里可以根据需要添加额外的处理逻辑 + + return jsonify({ + "code": 200, + "msg": "Cookie文件上传成功", + "data": None + }), 200 + + except Exception as e: + print(f"上传Cookie文件时出错: {str(e)}") + return jsonify({ + "code": 500, + "msg": f"上传Cookie文件失败: {str(e)}", + "data": None + }), 500 + + +# Cookie文件下载API +@app.route('/downloadCookie', methods=['GET']) +def download_cookie(): + try: + file_path = request.args.get('filePath') + if not file_path: + return jsonify({ + "code": 500, + "msg": "缺少文件路径参数", + "data": None + }), 400 + + # 验证文件路径的安全性,防止路径遍历攻击 + cookie_file_path = Path(BASE_DIR / "cookiesFile" / file_path).resolve() + base_path = Path(BASE_DIR / "cookiesFile").resolve() + + if not cookie_file_path.is_relative_to(base_path): + return jsonify({ + "code": 500, + "msg": "非法文件路径", + "data": None + }), 400 + + if not cookie_file_path.exists(): + return jsonify({ + "code": 500, + "msg": "Cookie文件不存在", + "data": None + }), 404 + + # 返回文件 + return send_from_directory( + directory=str(cookie_file_path.parent), + path=cookie_file_path.name, + as_attachment=True + ) + + except Exception as e: + print(f"下载Cookie文件时出错: {str(e)}") + return jsonify({ + "code": 500, + "msg": f"下载Cookie文件失败: {str(e)}", + "data": None + }), 500 + + # 包装函数:在线程中运行异步函数 def run_async_function(type,id,status_queue): match type: diff --git a/sau_frontend/src/views/AccountManagement.vue b/sau_frontend/src/views/AccountManagement.vue index a5938b8..a6c6a4b 100644 --- a/sau_frontend/src/views/AccountManagement.vue +++ b/sau_frontend/src/views/AccountManagement.vue @@ -57,6 +57,8 @@ @@ -120,6 +122,8 @@ @@ -183,6 +187,8 @@ @@ -246,6 +252,8 @@ @@ -309,6 +317,8 @@ @@ -547,7 +557,7 @@ const handleDelete = (row) => { try { // 调用API删除账号 const response = await accountApi.deleteAccount(row.id) - + if (response.code === 200) { // 从状态管理中删除账号 accountStore.deleteAccount(row.id) @@ -568,6 +578,77 @@ const handleDelete = (row) => { }) } +// 下载Cookie文件 +const handleDownloadCookie = (row) => { + // 从后端获取Cookie文件 + const baseUrl = import.meta.env.VITE_API_BASE_URL || 'http://localhost:5409' + const downloadUrl = `${baseUrl}/downloadCookie?filePath=${encodeURIComponent(row.filePath)}` + + // 创建一个隐藏的链接来触发下载 + const link = document.createElement('a') + link.href = downloadUrl + link.download = `${row.name}_cookie.json` + link.target = '_blank' + link.style.display = 'none' + document.body.appendChild(link) + link.click() + document.body.removeChild(link) +} + +// 上传Cookie文件 +const handleUploadCookie = (row) => { + // 创建一个隐藏的文件输入框 + const input = document.createElement('input') + input.type = 'file' + input.accept = '.json' + input.style.display = 'none' + document.body.appendChild(input) + + input.onchange = async (event) => { + const file = event.target.files[0] + if (!file) return + + // 检查文件类型 + if (!file.name.endsWith('.json')) { + ElMessage.error('请选择JSON格式的Cookie文件') + document.body.removeChild(input) + return + } + + try { + // 创建FormData对象 + const formData = new FormData() + formData.append('file', file) + formData.append('id', row.id) + formData.append('platform', row.platform) + + // 发送上传请求 + const baseUrl = import.meta.env.VITE_API_BASE_URL || 'http://localhost:5409' + const response = await fetch(`${baseUrl}/uploadCookie`, { + method: 'POST', + body: formData + }) + + const result = await response.json() + + if (result.code === 200) { + ElMessage.success('Cookie文件上传成功') + // 刷新账号列表以显示更新 + fetchAccounts() + } else { + ElMessage.error(result.msg || 'Cookie文件上传失败') + } + } catch (error) { + console.error('上传Cookie文件失败:', error) + ElMessage.error('Cookie文件上传失败') + } finally { + document.body.removeChild(input) + } + } + + input.click() +} + // SSE事件源对象 let eventSource = null