mirror of
https://github.com/l0ng-ai/openidea.git
synced 2026-11-08 08:52:12 +00:00
Git no longer asks for the HTTPS user name and password on every fetch, pull and push. The password prompt offers "Remember for this host"; the credential is saved in the app's secret store (next to the saved SSH passwords, never in git's global configuration) only after the git command that used it succeeds, and a stored credential the server rejects is forgotten so the next command asks again. Settings › Version Control › Git lists saved credentials and forgets them. Each git child gets its own id, passed to the askpass helper, so concurrent commands never save or forget each other's credentials. ide-vcs reports command completion through an observer installed at start-up instead of depending on ide-ssh. Credentials are keyed by scheme, host and port, and only git's authentication errors (Authentication failed, HTTP 401/403 responses, invalid username or password) forget a stored credential. Fixes #272 Co-authored-by: a-rookie-of-C-language <[email protected]>
48 lines
1.6 KiB
TypeScript
48 lines
1.6 KiB
TypeScript
/**
|
|
* Credential prompts of `ssh` / `git` child processes (backend askpass), shown
|
|
* one at a time; prompts arriving meanwhile wait in order.
|
|
*/
|
|
import { create } from "zustand";
|
|
import { commands, type AskpassKind } from "@/platform/ipc";
|
|
|
|
export interface AskpassPrompt {
|
|
id: number;
|
|
prompt: string;
|
|
kind: AskpassKind;
|
|
/** The dialog offers "Remember" (git HTTPS passwords). */
|
|
remember: boolean;
|
|
}
|
|
|
|
export const useAskpass = create<{ queue: AskpassPrompt[] }>(() => ({ queue: [] }));
|
|
|
|
export function enqueueAskpass(p: AskpassPrompt) {
|
|
useAskpass.setState((s) => (s.queue.some((q) => q.id === p.id) ? s : { queue: [...s.queue, p] }));
|
|
}
|
|
|
|
/** Drops prompt `id` (answered in another window, or the process gave up). */
|
|
export function dropAskpass(id: number) {
|
|
useAskpass.setState((s) => (s.queue.some((q) => q.id === id) ? { queue: s.queue.filter((q) => q.id !== id) } : s));
|
|
}
|
|
|
|
/** The answer sent back: the typed text, `yes` / `no` for a confirmation, null when cancelled. */
|
|
export function askpassAnswer(
|
|
kind: AskpassKind,
|
|
choice: { text: string } | { confirm: boolean } | null,
|
|
): string | null {
|
|
if (choice === null) return null;
|
|
if ("confirm" in choice) return kind === "confirm" ? (choice.confirm ? "yes" : "no") : null;
|
|
return kind === "confirm" ? null : choice.text;
|
|
}
|
|
|
|
export function answerAskpass(
|
|
p: AskpassPrompt,
|
|
answer: string | null,
|
|
remember: boolean,
|
|
send = commands.sshAskpassAnswer,
|
|
) {
|
|
dropAskpass(p.id);
|
|
// The backend ties `remember` to this prompt; the git command saves it only
|
|
// on success and drops it again when authentication fails.
|
|
void send(p.id, answer, remember).catch(() => {});
|
|
}
|