From cbc7f7c9c5cade774a56dcf6d30c840ec6541f31 Mon Sep 17 00:00:00 2001 From: yml2213 Date: Sun, 6 Sep 2026 14:00:24 +0800 Subject: [PATCH] =?UTF-8?q?fix(huya):=20=E4=BC=98=E5=8C=96=E8=B4=A6?= =?UTF-8?q?=E5=8F=B7=E5=AF=86=E7=A0=81=E5=AF=BC=E5=85=A5=E4=BA=A4=E4=BA=92?= =?UTF-8?q?=E5=B9=B6=E5=B0=86=E5=AF=BC=E5=85=A5=E7=B1=BB=E5=9E=8B=E4=B8=A5?= =?UTF-8?q?=E6=A0=BC=E9=99=90=E5=88=B6=E4=B8=BA=E5=9B=9B=E6=AE=B5=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 交互优化:将账号标签选择器移至弹窗顶部,避免下拉列表向下展开时遮挡底部的'确定'/'导入'按钮 - 格式限制:严格限制仅允许'账号----密码----手机号----接码链接'四段格式导入 - 前后端校验:前端逐行校验格式并提示具体错误行号,后端限制 require_four_segments=True 兜底 --- tests/test_huya_sms_url.py | 17 +++++ web/backend/routers/huya.py | 13 +++- web/backend/services/huya_service.py | 27 +++++-- web/frontend/src/pages/HuyaAccountsPage.tsx | 82 +++++++++++++++------ 4 files changed, 110 insertions(+), 29 deletions(-) diff --git a/tests/test_huya_sms_url.py b/tests/test_huya_sms_url.py index 6dcebdf..382f543 100644 --- a/tests/test_huya_sms_url.py +++ b/tests/test_huya_sms_url.py @@ -76,6 +76,23 @@ def test_import_password_accounts_persists_sms_url(): assert added_account.tag == "测试接码" +def test_import_password_accounts_strictly_four_segments(): + """测试账号密码导入默认严格限制仅允许四段格式。""" + mock_db = MagicMock() + mock_db.query().filter().first.return_value = None + + # 两段、三段会被跳过;仅四段有效行会被导入 + text = ( + "user1----pass1\n" + "user2----pass2----13800138000\n" + "user3----pass3----+14504409332----http://194.163.45.144/api/get_sms?key=xxx\n" + "user4----pass4----not_a_url\n" + ) + created, skipped = import_huya_password_accounts(mock_db, text, tag="四段测试") + assert created == 1 + assert skipped == 3 + + def test_solver_strategy_with_and_without_sms_url(): """测试在遇到 sms_auth2 时,有接码链接不抛异常,无接码链接抛出短信异常。""" url = "https://aq.huya.com/p/safe_auth/sms_auth2.html?param=xyz&mobile=14504409332" diff --git a/web/backend/routers/huya.py b/web/backend/routers/huya.py index acdca4c..de8e9c7 100644 --- a/web/backend/routers/huya.py +++ b/web/backend/routers/huya.py @@ -693,11 +693,18 @@ def import_password_accounts( db: Session = Depends(get_db), current: User = Depends(get_current_user), ): - """导入虎牙账号密码,只入库不立即登录。""" + """导入虎牙账号密码,只入库不立即登录(仅允许四段格式)。""" _require_huya_perm(current, "huya:import") - count, skipped = import_huya_password_accounts(db, req.text, req.tag) + count, skipped = import_huya_password_accounts( + db, req.text, req.tag, require_four_segments=True + ) + if count == 0 and skipped > 0: + raise HTTPException( + status_code=400, + detail="导入失败:当前仅允许四段格式(账号----密码----手机号----接码链接)", + ) return { - "message": f"导入/更新 {count} 个虎牙账号,跳过 {skipped} 条", + "message": f"成功导入/更新 {count} 个虎牙账号,跳过 {skipped} 条", "success": True, "count": count, "skipped": skipped, diff --git a/web/backend/services/huya_service.py b/web/backend/services/huya_service.py index 97a62a7..e577681 100644 --- a/web/backend/services/huya_service.py +++ b/web/backend/services/huya_service.py @@ -136,8 +136,13 @@ def _looks_like_url(value: str) -> bool: return parsed.scheme in {"http", "https"} and bool(parsed.netloc) -def split_huya_password_line(line: str) -> HuyaPasswordLine | None: - """拆分虎牙账号密码行,兼容账号----密码----手机号----验证码链接。""" +def split_huya_password_line( + line: str, require_four_segments: bool = False +) -> HuyaPasswordLine | None: + """拆分虎牙账号密码行,兼容账号----密码----手机号----验证码链接。 + + 若 require_four_segments 为 True,则严格限制必须包含手机号和有效接码链接。 + """ raw = (line or "").strip() if not raw or raw.startswith("#"): return None @@ -174,6 +179,10 @@ def split_huya_password_line(line: str) -> HuyaPasswordLine | None: cookie = "----".join(extra) if not username or not password: return None + if require_four_segments and ( + not phone or not sms_url or not _looks_like_url(sms_url) + ): + return None return HuyaPasswordLine( username=username, password=password, @@ -184,15 +193,23 @@ def split_huya_password_line(line: str) -> HuyaPasswordLine | None: def import_huya_password_accounts( - db: Session, text: str, tag: str = "" + db: Session, + text: str, + tag: str = "", + require_four_segments: bool = True, ) -> tuple[int, int]: - """导入虎牙账号密码,返回 (导入/更新数, 跳过数)。""" + """导入虎牙账号密码,返回 (导入/更新数, 跳过数)。 + + 默认仅允许四段格式(账号----密码----手机号----接码链接)。 + """ created_or_updated = 0 skipped = 0 tag = (tag or "").strip() for line in (text or "").splitlines(): - parsed = split_huya_password_line(line) + parsed = split_huya_password_line( + line, require_four_segments=require_four_segments + ) if not parsed: if line.strip(): skipped += 1 diff --git a/web/frontend/src/pages/HuyaAccountsPage.tsx b/web/frontend/src/pages/HuyaAccountsPage.tsx index f825e8f..fbf6939 100644 --- a/web/frontend/src/pages/HuyaAccountsPage.tsx +++ b/web/frontend/src/pages/HuyaAccountsPage.tsx @@ -278,10 +278,36 @@ export default function HuyaAccountsPage() { }; const handleImportPasswordAccounts = async () => { - if (!passwordImportText.trim()) { + const rawLines = passwordImportText + .split('\n') + .map((l) => l.trim()) + .filter((l) => l && !l.startsWith('#')); + if (rawLines.length === 0) { message.warning('请先粘贴虎牙账号密码'); return; } + const invalidLines: number[] = []; + rawLines.forEach((line, idx) => { + const parts = line.includes('----') + ? line.split('----').map((p) => p.trim()) + : line.split(/\s+/).map((p) => p.trim()); + if ( + parts.length < 4 || + !parts[0] || + !parts[1] || + !parts[2] || + !parts[3] || + !/^https?:\/\//i.test(parts[3]) + ) { + invalidLines.push(idx + 1); + } + }); + if (invalidLines.length > 0) { + message.error( + `格式错误:仅允许四段格式(账号----密码----手机号----接码链接)。第 ${invalidLines.slice(0, 5).join('、')}${invalidLines.length > 5 ? ` 等共 ${invalidLines.length}` : ''} 行不符合要求` + ); + return; + } setPasswordImporting(true); try { const tag = passwordImportTag.length > 0 ? passwordImportTag[passwordImportTag.length - 1].trim() : ''; @@ -946,27 +972,41 @@ export default function HuyaAccountsPage() { closable={!passwordImporting} width={720} > - -