feat(antigravity): 对齐 AM 客户端标识,前端 OAuth 增加 TOTP 支持

- User-Agent 改为 Electron 浏览器格式,新增 x-client-name/x-client-version/x-vscode-sessionid/x-goog-api-client header
- 移除 MODEL_ALIAS_MAP 别名映射,改为仅剥离 -online 后缀
- thinking 自动注入关键字新增 gemini-3.1-pro
- 新增定时 Antigravity UA 版本刷新任务(每 6 小时 + 启动时)
- 前端 OAuth 设备授权新增 TOTP 验证码生成(otpauth),Region 改为按钮选择
- SSO OIDC 轮询日志 authorization_pending/slow_down 降级为 debug
This commit is contained in:
fawney19
2026-02-24 01:52:53 +08:00
parent cd70c9148e
commit 7e447fe54e
11 changed files with 290 additions and 92 deletions

View File

@@ -0,0 +1,79 @@
import { ref, computed, onBeforeUnmount } from 'vue'
import { TOTP, Secret } from 'otpauth'
/**
* TOTP composable: 给定 secret 持续生成验证码并显示剩余秒数。
*/
export function useTotp() {
const secret = ref('')
const code = ref('')
const remaining = ref(0)
const error = ref('')
let timer: ReturnType<typeof setInterval> | null = null
let totp: TOTP | null = null
function parseSecret(raw: string): Secret | null {
const cleaned = raw.replace(/[\s-]/g, '')
if (!cleaned) return null
try {
return Secret.fromBase32(cleaned.toUpperCase())
} catch {
// 尝试 hex
}
try {
return Secret.fromHex(cleaned)
} catch {
return null
}
}
function generate(): void {
if (!totp) {
code.value = ''
remaining.value = 0
return
}
code.value = totp.generate()
const epoch = Math.floor(Date.now() / 1000)
remaining.value = totp.period - (epoch % totp.period)
}
function start(rawSecret: string): void {
stop()
error.value = ''
secret.value = rawSecret
const parsed = parseSecret(rawSecret)
if (!parsed) {
error.value = rawSecret.trim() ? 'Secret 格式无效' : ''
return
}
totp = new TOTP({ secret: parsed, digits: 6, period: 30 })
generate()
timer = setInterval(generate, 1000)
}
function stop(): void {
if (timer) {
clearInterval(timer)
timer = null
}
totp = null
code.value = ''
remaining.value = 0
error.value = ''
}
onBeforeUnmount(stop)
return {
secret,
code: computed(() => code.value),
remaining: computed(() => remaining.value),
error: computed(() => error.value),
start,
stop,
}
}