重构git凭证托管,改为操作系统托管

This commit is contained in:
xintaofei
2026-03-21 18:00:05 +08:00
parent 44f812c8d2
commit 450b081e88
13 changed files with 180 additions and 19 deletions

View File

@@ -13,6 +13,7 @@ import {
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog"
import { saveAccountToken } from "@/lib/tauri"
import type { GitHubAccount } from "@/lib/types"
interface AddGitAccountDialogProps {
@@ -52,7 +53,7 @@ export function AddGitAccountDialog({
[onOpenChange, resetForm]
)
const handleSubmit = useCallback(() => {
const handleSubmit = useCallback(async () => {
const trimmedUrl = serverUrl.trim()
const trimmedUser = username.trim()
const trimmedPass = password.trim()
@@ -74,13 +75,19 @@ export function AddGitAccountDialog({
id: crypto.randomUUID(),
server_url: trimmedUrl,
username: trimmedUser,
token: trimmedPass,
scopes: [],
avatar_url: null,
is_default: isFirstAccount,
created_at: new Date().toISOString(),
}
try {
await saveAccountToken(account.id, trimmedPass)
} catch {
setError(t("gitAccount.passwordRequired"))
return
}
onAccountAdded(account)
handleOpenChange(false)
}, [

View File

@@ -14,7 +14,7 @@ import {
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog"
import { validateGitHubToken } from "@/lib/tauri"
import { validateGitHubToken, saveAccountToken } from "@/lib/tauri"
import type { GitHubAccount } from "@/lib/types"
interface AddGitHubAccountDialogProps {
@@ -94,13 +94,13 @@ export function AddGitHubAccountDialog({
id: crypto.randomUUID(),
server_url: serverUrl.trim() || "https://github.com",
username: result.username ?? "unknown",
token: trimmedToken,
scopes: result.scopes,
avatar_url: result.avatar_url,
is_default: isFirstAccount,
created_at: new Date().toISOString(),
}
await saveAccountToken(account.id, trimmedToken)
onAccountAdded(account)
handleOpenChange(false)
} catch (err) {

View File

@@ -33,6 +33,8 @@ import {
getGitHubAccounts,
updateGitHubAccounts,
validateGitHubToken,
getAccountToken,
deleteAccountToken,
} from "@/lib/tauri"
import type {
GitDetectResult,
@@ -260,10 +262,15 @@ export function VersionControlSettings() {
async (account: GitHubAccount) => {
setTestingAccountId(account.id)
try {
const token = await getAccountToken(account.id)
if (!token) {
toast.error(t("connectionFailed", { message: "Token not found" }))
return
}
if (isGitHubAccount(account)) {
const result = await validateGitHubToken(
account.server_url,
account.token
token
)
if (result.success) {
toast.success(t("connectionSuccess"))
@@ -276,7 +283,7 @@ export function VersionControlSettings() {
}
} else {
// For non-GitHub accounts we can't validate via API,
// just confirm the account is stored.
// just confirm the token exists in keyring.
toast.success(t("connectionSuccess"))
}
} catch (err) {
@@ -315,6 +322,7 @@ export function VersionControlSettings() {
accounts: accounts.accounts.filter((a) => a.id !== removeTarget.id),
}
try {
await deleteAccountToken(removeTarget.id)
const saved = await updateGitHubAccounts(updated)
setAccounts(saved)
toast.success(t("removeSuccess"))

View File

@@ -36,6 +36,7 @@ import {
validateGitHubToken,
getGitHubAccounts,
updateGitHubAccounts,
saveAccountToken,
} from "@/lib/tauri"
// ---------------------------------------------------------------------------
@@ -146,14 +147,15 @@ async function saveGenericAccount(
(a) => a.username === creds.username && extractHost(a.server_url) === host
)
if (!isDuplicate) {
const newId = crypto.randomUUID()
await saveAccountToken(newId, creds.password)
await updateGitHubAccounts({
accounts: [
...existing.accounts,
{
id: crypto.randomUUID(),
id: newId,
server_url: serverUrl,
username: creds.username,
token: creds.password,
scopes: [],
avatar_url: null,
is_default: existing.accounts.length === 0,
@@ -284,12 +286,12 @@ export function GitCredentialProvider({ children }: { children: ReactNode }) {
id: crypto.randomUUID(),
server_url: serverUrl,
username: result.username ?? "unknown",
token: trimmedToken,
scopes: result.scopes,
avatar_url: result.avatar_url,
is_default: existing.accounts.length === 0,
created_at: new Date().toISOString(),
}
await saveAccountToken(newAccount.id, trimmedToken)
await updateGitHubAccounts({
accounts: [...existing.accounts, newAccount],
})

View File

@@ -344,6 +344,25 @@ export async function updateGitHubAccounts(
return invoke("update_github_accounts", { settings })
}
export async function saveAccountToken(
accountId: string,
token: string
): Promise<void> {
return invoke("save_account_token", { accountId, token })
}
export async function getAccountToken(
accountId: string
): Promise<string | null> {
return invoke("get_account_token", { accountId })
}
export async function deleteAccountToken(
accountId: string
): Promise<void> {
return invoke("delete_account_token", { accountId })
}
export async function mcpScanLocal(): Promise<LocalMcpServer[]> {
return invoke("mcp_scan_local")
}

View File

@@ -544,7 +544,6 @@ export interface GitHubAccount {
id: string
server_url: string
username: string
token: string
scopes: string[]
avatar_url: string | null
is_default: boolean