feat(auth): add credential mode (credentials/token) support
Introduces a credential mode for stored credentials and wire it to per-remote URL resolution and operation flows. The UI, storage, and remote interactions now track and persist the mode, enabling token based auth alongside username/password credentials. - Remote URL resolution now considers direction (pull/push) and mode - Credential dialog, saving, and keychain handling updated to pass and respect the mode - Unique askpass scripts generated per invocation to avoid clashes
This commit is contained in:
Notes:
Christoph Brandau
2026-08-13 22:48:24 +02:00
git note test
@@ -1,4 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { untrack } from "svelte";
|
||||
import {
|
||||
AlertCircle,
|
||||
Download,
|
||||
@@ -17,7 +18,9 @@
|
||||
action: "push" | "pull" | "fetch" | "clone";
|
||||
error: string;
|
||||
isBusy: boolean;
|
||||
onSubmit: (username: string, password: string, save: boolean) => void;
|
||||
initialUsername?: string;
|
||||
initialMode?: Mode;
|
||||
onSubmit: (username: string, password: string, save: boolean, mode: Mode) => void;
|
||||
onCancel: () => void;
|
||||
}
|
||||
|
||||
@@ -25,14 +28,16 @@
|
||||
action,
|
||||
error = "",
|
||||
isBusy = false,
|
||||
initialUsername = "",
|
||||
initialMode = "credentials",
|
||||
onSubmit,
|
||||
onCancel,
|
||||
}: Props = $props();
|
||||
|
||||
type Mode = "credentials" | "token";
|
||||
|
||||
let mode = $state<Mode>("credentials");
|
||||
let username = $state("");
|
||||
let mode = $state<Mode>(untrack(() => initialMode));
|
||||
let username = $state(untrack(() => initialUsername === "oauth2" ? "" : initialUsername));
|
||||
let password = $state("");
|
||||
let showPassword = $state(false);
|
||||
let saveSession = $state(true);
|
||||
@@ -40,7 +45,7 @@
|
||||
let canSubmit = $derived(
|
||||
!isBusy &&
|
||||
password.trim().length > 0 &&
|
||||
(mode === "token" || username.trim().length > 0),
|
||||
username.trim().length > 0,
|
||||
);
|
||||
let actionLabel = $derived(action === "push" ? "Push" : action === "fetch" ? "Fetch" : action === "clone" ? "Clone" : "Pull");
|
||||
let actionTitle = $derived(
|
||||
@@ -61,7 +66,7 @@
|
||||
function handleSubmit(e: SubmitEvent) {
|
||||
e.preventDefault();
|
||||
if (!canSubmit) return;
|
||||
onSubmit(mode === "token" ? "oauth2" : username, password, saveSession);
|
||||
onSubmit(username.trim(), password, saveSession, mode);
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -92,7 +97,7 @@
|
||||
|
||||
<div class="cred-security-note">
|
||||
<ShieldCheck size={14} aria-hidden="true" />
|
||||
<span>When saved, the token is stored encrypted in the operating system's keychain — never in plain text.</span>
|
||||
<span>When saved, the credentials are stored encrypted in the operating system's keychain — never in plain text.</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -116,27 +121,25 @@
|
||||
aria-pressed={mode === "token"}
|
||||
>
|
||||
<Key size={13} aria-hidden="true" />
|
||||
Token
|
||||
Access token
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="cred-fields">
|
||||
{#if mode === "credentials"}
|
||||
<div class="cred-field">
|
||||
<label class="cred-field-label" for="cred-username">Username</label>
|
||||
<div class="cred-input">
|
||||
<User size={15} class="cred-field-icon" aria-hidden="true" />
|
||||
<input
|
||||
id="cred-username"
|
||||
type="text"
|
||||
bind:value={username}
|
||||
placeholder="e.g. my-github-username"
|
||||
autocomplete="username"
|
||||
disabled={isBusy}
|
||||
/>
|
||||
</div>
|
||||
<div class="cred-field">
|
||||
<label class="cred-field-label" for="cred-username">Username</label>
|
||||
<div class="cred-input">
|
||||
<User size={15} class="cred-field-icon" aria-hidden="true" />
|
||||
<input
|
||||
id="cred-username"
|
||||
type="text"
|
||||
bind:value={username}
|
||||
placeholder="Your account username"
|
||||
autocomplete="username"
|
||||
disabled={isBusy}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="cred-field">
|
||||
<label class="cred-field-label" for="cred-password">
|
||||
@@ -174,7 +177,7 @@
|
||||
{#if mode === "token"}
|
||||
<div class="cred-token-hint">
|
||||
<Key size={13} aria-hidden="true" />
|
||||
<span>Username is automatically set to <code>oauth2</code>. This works with GitHub, GitLab, and Bitbucket.</span>
|
||||
<span>Use your normal account username. The access token is sent as the password, as required by Gitea and most Git providers.</span>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
|
||||
+4
-4
@@ -373,16 +373,16 @@ export function push(path: string, username?: string, password?: string, forceWi
|
||||
return invoke<GitStatus>("push", { path, username: username ?? null, password: password ?? null, forceWithLease, remote: remote || null });
|
||||
}
|
||||
|
||||
export function getRemoteUrl(path: string): Promise<string | null> {
|
||||
return invoke<string | null>("get_remote_url", { path });
|
||||
export function getRemoteUrl(path: string, remote?: string, push = false): Promise<string | null> {
|
||||
return invoke<string | null>("get_remote_url", { path, remote: remote || null, push });
|
||||
}
|
||||
|
||||
export function credLoad(key: string): Promise<StoredCredential | null> {
|
||||
return invoke<StoredCredential | null>("cred_load", { key });
|
||||
}
|
||||
|
||||
export function credSave(key: string, username: string, password: string): Promise<void> {
|
||||
return invoke<void>("cred_save", { key, username, password });
|
||||
export function credSave(key: string, username: string, password: string, mode: "credentials" | "token" = "credentials"): Promise<void> {
|
||||
return invoke<void>("cred_save", { key, username, password, mode });
|
||||
}
|
||||
|
||||
export function credDelete(key: string): Promise<void> {
|
||||
|
||||
@@ -310,4 +310,5 @@ export interface ReflogEntry {
|
||||
export interface StoredCredential {
|
||||
username: string;
|
||||
password: string;
|
||||
mode?: "credentials" | "token";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user