Adds support for certificate-based SSH authentication

Extends authentication logic and UI to recognize and handle
certificate-based keys alongside password and regular key methods.
Improves key selection UX by auto-switching to the appropriate
auth method based on the selected key type. Enables broader
SSH authentication compatibility.
This commit is contained in:
LAPTOP-O016UC3M\Qi Chen
2025-12-15 17:31:24 +08:00
parent 47888dff3a
commit be4e97ae69
2 changed files with 26 additions and 11 deletions
+18 -7
View File
@@ -218,7 +218,7 @@ const TerminalComponent: React.FC<TerminalProps> = ({
// Pending connection credentials (set after auth dialog submit)
const pendingAuthRef = useRef<{
authMethod: "password" | "key";
authMethod: "password" | "key" | "certificate";
username: string;
password?: string;
keyId?: string;
@@ -722,7 +722,9 @@ const TerminalComponent: React.FC<TerminalProps> = ({
// SSH connection (default)
// Check if host needs authentication info
const hasPassword = host.authMethod === "password" && host.password;
const hasKey = host.authMethod === "key" && host.identityFileId;
const hasKey =
(host.authMethod === "key" || host.authMethod === "certificate") &&
host.identityFileId;
const hasPendingAuth = pendingAuthRef.current;
if (!hasPassword && !hasKey && !hasPendingAuth && !host.username) {
@@ -1114,7 +1116,7 @@ const TerminalComponent: React.FC<TerminalProps> = ({
: undefined;
// Prepare jump host chain configuration
const jumpHosts = resolvedChainHosts.map((jumpHost) => {
const jumpHosts = resolvedChainHosts.map<NetcattyJumpHost>((jumpHost) => {
const jumpKey = jumpHost.identityFileId
? keys.find((k) => k.id === jumpHost.identityFileId)
: undefined;
@@ -1674,7 +1676,7 @@ const TerminalComponent: React.FC<TerminalProps> = ({
const isAuthValid = () => {
if (!authUsername.trim()) return false;
if (authMethod === "password") return authPassword.trim().length > 0;
if (authMethod === "key") return !!authKeyId;
if (authMethod === "key" || authMethod === "certificate") return !!authKeyId;
return false;
};
@@ -1686,8 +1688,14 @@ const TerminalComponent: React.FC<TerminalProps> = ({
authMethod,
username: authUsername,
password: authMethod === "password" ? authPassword : undefined,
keyId: authMethod === "key" ? (authKeyId ?? undefined) : undefined,
passphrase: authMethod === "key" ? authPassphrase || undefined : undefined,
keyId:
authMethod === "key" || authMethod === "certificate"
? (authKeyId ?? undefined)
: undefined,
passphrase:
authMethod === "key" || authMethod === "certificate"
? authPassphrase || undefined
: undefined,
};
// Save credentials to host if requested
@@ -1697,7 +1705,10 @@ const TerminalComponent: React.FC<TerminalProps> = ({
username: authUsername,
authMethod: authMethod,
password: authMethod === "password" ? authPassword : undefined,
identityFileId: authMethod === "key" ? (authKeyId ?? undefined) : undefined,
identityFileId:
authMethod === "key" || authMethod === "certificate"
? (authKeyId ?? undefined)
: undefined,
};
onUpdateHost(updatedHost);
}
+8 -4
View File
@@ -11,7 +11,7 @@ import { Input } from '../ui/input';
import { Label } from '../ui/label';
import { Popover, PopoverContent, PopoverTrigger } from '../ui/popover';
export type TerminalAuthMethod = 'password' | 'key';
export type TerminalAuthMethod = 'password' | 'key' | 'certificate';
export interface TerminalAuthDialogProps {
authMethod: TerminalAuthMethod;
@@ -64,8 +64,11 @@ export const TerminalAuthDialog: React.FC<TerminalAuthDialogProps> = ({
}
};
// Show all keys (both regular keys and certificates) when in key mode
const selectableKeys = keys.filter((k) => k.category === 'key' || Boolean(k.certificate?.trim()));
// Show all keys (both regular keys and certificates) in the single key picker.
const selectableKeys = React.useMemo(
() => keys.filter((k) => k.category === 'key' || Boolean(k.certificate?.trim())),
[keys],
);
const [keyDropdownOpen, setKeyDropdownOpen] = React.useState(false);
@@ -90,7 +93,7 @@ export const TerminalAuthDialog: React.FC<TerminalAuthDialogProps> = ({
<button
className={cn(
"flex-1 flex items-center justify-center gap-2 py-2 text-sm font-medium rounded-md transition-all",
authMethod === 'key'
authMethod === 'key' || authMethod === 'certificate'
? "bg-primary text-primary-foreground shadow-sm"
: "text-muted-foreground hover:text-foreground hover:bg-secondary"
)}
@@ -205,6 +208,7 @@ export const TerminalAuthDialog: React.FC<TerminalAuthDialogProps> = ({
)}
onClick={() => {
setAuthKeyId(key.id);
setAuthMethod(key.certificate?.trim() ? 'certificate' : 'key');
setAuthPassphrase(key.passphrase || '');
setKeyDropdownOpen(false);
}}