mirror of
https://github.com/binaricat/Netcatty.git
synced 2026-10-09 15:58:34 +00:00
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:
+18
-7
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}}
|
||||
|
||||
Reference in New Issue
Block a user