mirror of
https://github.com/binaricat/Netcatty.git
synced 2026-10-09 15:58:34 +00:00
5918f91132
Enhances keyboard-interactive (2FA/MFA) authentication by implementing a queue-based system, allowing multiple concurrent requests to be processed sequentially. Previously, password prompts during keyboard-interactive authentication were auto-filled if a saved password was available. This change removes the auto-fill behavior to prevent issues with custom or ambiguous prompt texts, instead providing a user-initiated "Use saved password" option in the UI. Increases the connection timeout to 120 seconds to provide ample time for users to complete 2FA challenges. A new UI indicator shows when additional 2FA requests are pending. Also, refines SSH authentication logic to strictly respect explicit password authentication, preventing unintended attempts to use private keys when password authentication is selected.
91 lines
2.2 KiB
TypeScript
91 lines
2.2 KiB
TypeScript
import type { Host, Identity, SSHKey } from "./models";
|
|
|
|
export type HostAuthMethod = "password" | "key" | "certificate";
|
|
|
|
export type HostAuthOverride = {
|
|
authMethod?: HostAuthMethod;
|
|
username?: string;
|
|
password?: string;
|
|
keyId?: string;
|
|
passphrase?: string;
|
|
};
|
|
|
|
export type ResolvedHostAuth = {
|
|
identity?: Identity;
|
|
authMethod: HostAuthMethod;
|
|
username: string;
|
|
password?: string;
|
|
keyId?: string;
|
|
key?: SSHKey;
|
|
passphrase?: string;
|
|
};
|
|
|
|
const inferAuthMethod = (opts: {
|
|
explicit?: HostAuthMethod;
|
|
keyId?: string;
|
|
password?: string;
|
|
hostAuthMethod?: HostAuthMethod;
|
|
key?: SSHKey;
|
|
}): HostAuthMethod => {
|
|
if (opts.explicit) return opts.explicit;
|
|
if (opts.keyId) {
|
|
if (opts.hostAuthMethod === "key" || opts.hostAuthMethod === "certificate") {
|
|
return opts.hostAuthMethod;
|
|
}
|
|
return opts.key?.certificate ? "certificate" : "key";
|
|
}
|
|
if (opts.hostAuthMethod) return opts.hostAuthMethod;
|
|
if (opts.password) return "password";
|
|
return "password";
|
|
};
|
|
|
|
export const resolveHostAuth = (args: {
|
|
host: Host;
|
|
keys: SSHKey[];
|
|
identities?: Identity[];
|
|
override?: HostAuthOverride | null;
|
|
}): ResolvedHostAuth => {
|
|
const { host, keys, identities = [], override } = args;
|
|
|
|
const identity = host.identityId
|
|
? identities.find((i) => i.id === host.identityId)
|
|
: undefined;
|
|
|
|
const username =
|
|
override?.username?.trim() ||
|
|
identity?.username?.trim() ||
|
|
host.username?.trim() ||
|
|
"";
|
|
|
|
// Don't load key when explicit password auth is requested
|
|
// This ensures user's auth method selection is strictly respected
|
|
const keyId = override?.authMethod === 'password'
|
|
? undefined
|
|
: (override?.keyId || identity?.keyId || host.identityFileId || undefined);
|
|
|
|
|
|
const key = keyId ? keys.find((k) => k.id === keyId) : undefined;
|
|
|
|
const password = override?.password ?? identity?.password ?? host.password;
|
|
|
|
const authMethod = inferAuthMethod({
|
|
explicit: override?.authMethod,
|
|
hostAuthMethod: (identity?.authMethod || host.authMethod) as HostAuthMethod | undefined,
|
|
keyId,
|
|
password,
|
|
key,
|
|
});
|
|
|
|
const passphrase = override?.passphrase || key?.passphrase || undefined;
|
|
|
|
return {
|
|
identity,
|
|
authMethod,
|
|
username,
|
|
password,
|
|
keyId,
|
|
key,
|
|
passphrase,
|
|
};
|
|
};
|