Skip to content

Commit 1cebfb9

Browse files
committed
fix: CSP blocking inline onclick - use addEventListener instead; fix cloudLogin/Register return types
1 parent 330ed71 commit 1cebfb9

8 files changed

Lines changed: 137 additions & 10 deletions

File tree

_check_db.sh

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#!/bin/bash
2+
cd /opt/testpilot/app
3+
source venv/bin/activate
4+
python3 -c "
5+
from src.auth.database import engine
6+
from sqlalchemy import text
7+
with engine.connect() as conn:
8+
r = conn.execute(text('SHOW TABLES'))
9+
tables = [row[0] for row in r]
10+
print('Tables:', tables)
11+
print('Count:', len(tables))
12+
"

_db_check2.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#!/usr/bin/env python3
2+
import sys, os
3+
sys.path.insert(0, '/opt/testpilot/app')
4+
os.chdir('/opt/testpilot/app')
5+
from src.auth.database import engine
6+
from sqlalchemy import text, inspect
7+
8+
with engine.connect() as conn:
9+
r = conn.execute(text('SHOW TABLES'))
10+
tables = sorted([row[0] for row in r])
11+
print('=== 数据库中的表 (%d个) ===' % len(tables))
12+
for t in tables:
13+
print(' ', t)
14+
15+
print()
16+
print('=== 检查关键表是否存在 ===')
17+
required = ['users','api_keys','credit_transactions','shared_experiences',
18+
'experience_votes','user_badges','user_profiles','teams','team_members',
19+
'projects','debug_snapshots','usage_records',
20+
'login_attempts','refresh_tokens','email_verifications']
21+
insp = inspect(engine)
22+
existing = insp.get_table_names()
23+
for t in required:
24+
status = '✅' if t in existing else '❌ 缺失!'
25+
print(f' {status} {t}')

_test_auth.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
"""临时测试脚本:验证注册/登录/JWT 在 MySQL RDS 上工作正常"""
2+
import traceback
3+
import sys
4+
5+
try:
6+
from dotenv import load_dotenv
7+
load_dotenv()
8+
print("1. dotenv loaded")
9+
10+
from src.auth.database import get_db
11+
print("2. database imported")
12+
13+
from src.auth.service import register_user, authenticate_user, create_access_token
14+
print("3. service imported")
15+
16+
db = next(get_db())
17+
print("4. db session OK")
18+
19+
# 注册(已存在则跳过)
20+
try:
21+
user = register_user(db, "test@testpilot.com", "testuser", "Test123456")
22+
print(f"5. 注册成功: id={user.id}, username={user.username}, role={user.role}")
23+
except ValueError as e:
24+
print(f"5. 注册跳过(已存在): {e}")
25+
26+
# 用户名登录
27+
u = authenticate_user(db, "testuser", "Test123456")
28+
status = "成功" if u else "失败"
29+
print(f"6. 用户名登录: {status}")
30+
31+
# 邮箱登录
32+
u2 = authenticate_user(db, "test@testpilot.com", "Test123456")
33+
status2 = "成功" if u2 else "失败"
34+
print(f"7. 邮箱登录: {status2}")
35+
36+
# 错误密码
37+
u3 = authenticate_user(db, "testuser", "wrongpass")
38+
status3 = "正确拒绝" if not u3 else "未拒绝!"
39+
print(f"8. 错误密码: {status3}")
40+
41+
# JWT
42+
if u:
43+
token = create_access_token(u.id, u.username, u.role)
44+
print(f"9. JWT: {token[:60]}...")
45+
46+
# MySQL 持久化验证
47+
from sqlalchemy import text
48+
row = db.execute(text("SELECT id, email, username, role FROM users WHERE username='testuser'")).fetchone()
49+
print(f"10. MySQL 持久化: {row}")
50+
51+
db.close()
52+
print("\nALL PASSED!")
53+
54+
except Exception:
55+
traceback.print_exc()
56+
sys.exit(1)

deploy_package.zip

343 KB
Binary file not shown.

extension/esbuild.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ esbuild.build({
1515
}).then(() => {
1616
// 自动同步到所有已安装的 IDE 扩展目录(开发便利)
1717
const home = process.env.USERPROFILE || "";
18-
const extName = "testpilot-ai.testpilot-ai-1.3.0";
18+
const extName = "wenzhouxinzao.testpilot-ai-1.3.0";
1919
const ideDirs = [
2020
path.join(home, ".vscode", "extensions", extName),
21-
path.join(home, ".trae", "extensions", extName),
21+
path.join(home, ".trae-cn", "extensions", extName),
2222
path.join(home, ".cursor", "extensions", extName),
2323
path.join(home, ".windsurf", "extensions", extName),
2424
path.join(home, ".vscodium", "extensions", extName),

extension/src/engineClient.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -446,8 +446,9 @@ export class EngineClient {
446446
/** 云端登录 */
447447
async cloudLogin(emailOrUsername: string, password: string): Promise<{
448448
access_token: string;
449+
refresh_token?: string;
449450
token_type: string;
450-
user: { id: number; email: string; username: string; role: string };
451+
user: { id: number; email: string; username: string; role: string; plan?: string; credits?: number };
451452
}> {
452453
return this._cloudPost("/auth/login", {
453454
email_or_username: emailOrUsername,
@@ -458,8 +459,9 @@ export class EngineClient {
458459
/** 云端注册 */
459460
async cloudRegister(email: string, username: string, password: string): Promise<{
460461
access_token: string;
462+
refresh_token?: string;
461463
token_type: string;
462-
user: { id: number; email: string; username: string; role: string };
464+
user: { id: number; email: string; username: string; role: string; plan?: string; credits?: number };
463465
}> {
464466
return this._cloudPost("/auth/register", { email, username, password });
465467
}

extension/src/sidebarProvider.ts

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1679,7 +1679,7 @@ ${commonRules}`;
16791679
<div class="sdrop-section">个性化设置</div>
16801680
<div class="sdrop-item" id="settingsThemeRow">
16811681
<span>🌓 界面主题</span>
1682-
<label class="toggle-switch" onclick="event.stopPropagation()">
1682+
<label class="toggle-switch" id="themeToggleLabel">
16831683
<input type="checkbox" id="themeToggle" />
16841684
<span class="toggle-slider"></span>
16851685
</label>
@@ -1695,24 +1695,24 @@ ${commonRules}`;
16951695
<span class="badge-soon">即将推出</span>
16961696
</div>
16971697
<div class="sdrop-divider"></div>
1698-
<div class="sdrop-item" id="settingsAuthRow" onclick="toggleSettingsAuth()">
1698+
<div class="sdrop-item" id="settingsAuthRow">
16991699
<span id="settingsAuthLabel">🔑 账户登录</span>
17001700
<span id="settingsAuthArrow" style="font-size:10px;color:var(--muted)">▾</span>
17011701
</div>
17021702
<div id="settingsAuthPanel" class="sdrop-auth-panel">
17031703
<div id="authError" class="auth-error"></div>
17041704
<input id="authUser" type="text" placeholder="用户名或邮箱" autocomplete="username" />
1705-
<input id="authPass" type="password" placeholder="密码" autocomplete="current-password" onkeydown="if(event.key==='Enter')doAuth()" />
1705+
<input id="authPass" type="password" placeholder="密码" autocomplete="current-password" />
17061706
<div style="display:flex;gap:6px;margin-top:4px">
1707-
<button class="sdrop-login-btn" onclick="doAuth()">登录</button>
1708-
<button class="sdrop-register-btn" onclick="openRegister()">前往注册 ↗</button>
1707+
<button class="sdrop-login-btn" id="authLoginBtn">登录</button>
1708+
<button class="sdrop-register-btn" id="authRegisterBtn">前往注册 ↗</button>
17091709
</div>
17101710
</div>
17111711
<div id="settingsUserRow" class="sdrop-user-row" style="display:none">
17121712
<div style="display:flex;align-items:center;justify-content:space-between">
17131713
<span style="color:var(--success);font-weight:600">👤 <span id="authUsername"></span>
17141714
<span style="color:var(--muted)" id="authPlan"></span></span>
1715-
<button onclick="doLogout()" style="background:none;border:none;color:var(--muted);cursor:pointer;font-size:11px;text-decoration:underline">退出</button>
1715+
<button id="authLogoutBtn" style="background:none;border:none;color:var(--muted);cursor:pointer;font-size:11px;text-decoration:underline">退出</button>
17161716
</div>
17171717
<div id="authCredits" style="font-size:11px;color:var(--muted);margin-top:2px"></div>
17181718
</div>
@@ -1956,6 +1956,19 @@ ${commonRules}`;
19561956
vscode.postMessage({ command: 'logout' });
19571957
}
19581958
1959+
// ── 认证相关事件绑定(CSP 禁止内联 onclick,必须用 addEventListener) ──
1960+
const settingsAuthRow = document.getElementById('settingsAuthRow');
1961+
if (settingsAuthRow) settingsAuthRow.addEventListener('click', toggleSettingsAuth);
1962+
if (authPass) authPass.addEventListener('keydown', (e) => { if (e.key === 'Enter') doAuth(); });
1963+
const authLoginBtn = document.getElementById('authLoginBtn');
1964+
if (authLoginBtn) authLoginBtn.addEventListener('click', doAuth);
1965+
const authRegisterBtn = document.getElementById('authRegisterBtn');
1966+
if (authRegisterBtn) authRegisterBtn.addEventListener('click', openRegister);
1967+
const authLogoutBtn = document.getElementById('authLogoutBtn');
1968+
if (authLogoutBtn) authLogoutBtn.addEventListener('click', doLogout);
1969+
const themeToggleLabel = document.getElementById('themeToggleLabel');
1970+
if (themeToggleLabel) themeToggleLabel.addEventListener('click', (e) => e.stopPropagation());
1971+
19591972
function setAuthState(loggedIn, user) {
19601973
const authPanel = document.getElementById('settingsAuthPanel');
19611974
const userRow = document.getElementById('settingsUserRow');

开发备忘录.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
- **注册改为跳官网**:点击「前往注册」→ `openExternal` 打开 `https://testpilotai.pages.dev/register`,不再内嵌注册表单
3636
- **修复引擎未连接日志反复打印**`extension.ts` 新增 `retainContextWhenHidden: true`,防止 WebView 被销毁/重建导致 `hasLoggedDisconnected` 变量重置
3737
- **修复 TRAE 显示旧版**:TRAE 扩展目录中存在两个版本(`testpilot-ai.testpilot-ai-1.2.9` 旧 publisher + `wenzhouxinzao.testpilot-ai-1.3.0`),将旧版目录 rename 为 `.bak`,安装新版
38+
- **修复 VS Code 双插件问题(2026-03-25)**:VS Code 扩展目录同时存在三个版本(`testpilot-ai.testpilot-ai-1.2.0``testpilot-ai.testpilot-ai-1.2.9` 旧 publisher + `wenzhouxinzao.testpilot-ai-1.3.0` 新 publisher),直接 `Remove-Item -Recurse -Force` 删除两个旧版目录,只保留新版。**根本原因:publisher 从 `testpilot-ai` 改成 `wenzhouxinzao` 后,VS Code 将其视为两个完全不同的插件。代码无需改动,只需删除旧目录。**
39+
- **修复账户登录点击无反应(2026-03-25)**:CSP 策略(`script-src 'nonce-xxx'`)阻止了所有内联 `onclick="..."` / `onkeydown="..."` 属性调用,导致设置菜单里的「账户登录」行及登录按钮/注册按钮/退出按钮/密码框回车键全部失效。修复:删除6处内联事件属性,给各元素加 id,在 nonce 脚本块里统一用 `addEventListener` 绑定。同步修复 `cloudLogin/cloudRegister` 返回类型缺少 `refresh_token?/plan?/credits?` 字段的 TypeScript 错误。
3840
- **服务器 alembic 分支冲突修复**`stamp f03fbc681fc5` 跳过重复建表,再 `upgrade 3f8a9b2c1d47` 建 3 个安全表(login_attempts/refresh_tokens/email_verifications)
3941

4042
---
@@ -87,6 +89,23 @@ npx @vscode/vsce package --no-yarn
8789
--install-extension testpilot-ai-1.3.0.vsix --force
8890
```
8991

92+
**⚠️ 双Publisher问题说明(必读):**
93+
> 历史上 publisher 从 `testpilot-ai` 改为 `wenzhouxinzao`,导致 VS Code / TRAE / Windsurf 将新旧版本视为**两个完全不同的插件**,搜索和安装时会出现两个。
94+
> 当前正确 publisher:**`wenzhouxinzao`**,旧 publisher `testpilot-ai` 的目录均需删除。
95+
96+
**VS Code 清理旧版(⚠️ 重要):**
97+
- VS Code 扩展目录(Windows):`%USERPROFILE%\.vscode\extensions\`
98+
- 若存在旧版目录(`testpilot-ai.testpilot-ai-*`),需删除:
99+
```powershell
100+
cd "$env:USERPROFILE\.vscode\extensions"
101+
# 查看当前 testpilot 相关目录
102+
Get-ChildItem | Where-Object { $_.Name -like "*testpilot*" }
103+
# 删除所有旧 publisher 版本(保留 wenzhouxinzao.* 开头的)
104+
Remove-Item -Recurse -Force testpilot-ai.testpilot-ai-1.2.0
105+
Remove-Item -Recurse -Force testpilot-ai.testpilot-ai-1.2.9
106+
```
107+
- 删除后重启 VS Code 即可,无需重新安装新版
108+
90109
**TRAE 注意事项(⚠️ 重要):**
91110
- TRAE 扩展目录(Windows):`C:\Users\%USERNAME%\.trae-cn\extensions\`
92111
- 目录名格式:`{publisher}.{extensionName}-{version}`,publisher 不同 = 完全不同的插件

0 commit comments

Comments
 (0)