mirror of
https://github.com/binaricat/Netcatty.git
synced 2026-10-09 15:58:34 +00:00
b8c221d112
Reorder and normalize import statements, group icon imports, and add missing utility imports (cn). Fix export/newline formatting and minor type import tweaks. Add ESLint scripts to package.json and update the lockfile.
162 lines
5.5 KiB
TypeScript
162 lines
5.5 KiB
TypeScript
/**
|
|
* Import Key Panel - Import existing SSH key
|
|
*/
|
|
|
|
import { Upload } from 'lucide-react';
|
|
import React,{ useCallback,useRef } from 'react';
|
|
import { SSHKey } from '../../types';
|
|
import { Button } from '../ui/button';
|
|
import { Input } from '../ui/input';
|
|
import { Label } from '../ui/label';
|
|
import { Textarea } from '../ui/textarea';
|
|
import { detectKeyType } from './utils';
|
|
|
|
interface ImportKeyPanelProps {
|
|
draftKey: Partial<SSHKey>;
|
|
setDraftKey: (key: Partial<SSHKey>) => void;
|
|
onImport: () => void;
|
|
}
|
|
|
|
export const ImportKeyPanel: React.FC<ImportKeyPanelProps> = ({
|
|
draftKey,
|
|
setDraftKey,
|
|
onImport,
|
|
}) => {
|
|
const fileInputRef = useRef<HTMLInputElement>(null);
|
|
|
|
const handleFileImport = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
|
|
const file = event.target.files?.[0];
|
|
if (!file) return;
|
|
|
|
const reader = new FileReader();
|
|
reader.onload = (e) => {
|
|
const content = e.target?.result as string;
|
|
if (content) {
|
|
const detectedType = detectKeyType(content);
|
|
const label = file.name.replace(/\.(pem|key|pub|ppk)$/i, '');
|
|
|
|
setDraftKey({
|
|
...draftKey,
|
|
privateKey: content,
|
|
label: draftKey.label || label,
|
|
type: detectedType,
|
|
});
|
|
}
|
|
};
|
|
reader.readAsText(file);
|
|
event.target.value = '';
|
|
}, [draftKey, setDraftKey]);
|
|
|
|
const handleDrop = useCallback((event: React.DragEvent<HTMLDivElement>) => {
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
|
|
const file = event.dataTransfer.files?.[0];
|
|
if (!file) return;
|
|
|
|
const reader = new FileReader();
|
|
reader.onload = (e) => {
|
|
const content = e.target?.result as string;
|
|
if (content) {
|
|
const detectedType = detectKeyType(content);
|
|
const label = file.name.replace(/\.(pem|key|pub|ppk)$/i, '');
|
|
|
|
setDraftKey({
|
|
...draftKey,
|
|
privateKey: content,
|
|
label: draftKey.label || label,
|
|
type: detectedType,
|
|
});
|
|
}
|
|
};
|
|
reader.readAsText(file);
|
|
}, [draftKey, setDraftKey]);
|
|
|
|
const handleDragOver = useCallback((event: React.DragEvent<HTMLDivElement>) => {
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
}, []);
|
|
|
|
return (
|
|
<>
|
|
<input
|
|
ref={fileInputRef}
|
|
type="file"
|
|
accept=".pem,.key,.pub,.ppk,*"
|
|
className="hidden"
|
|
onChange={handleFileImport}
|
|
/>
|
|
|
|
<div className="space-y-2">
|
|
<Label>Label</Label>
|
|
<Input
|
|
value={draftKey.label || ''}
|
|
onChange={e => setDraftKey({ ...draftKey, label: e.target.value })}
|
|
placeholder="Key label"
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label>Private key *</Label>
|
|
<Textarea
|
|
value={draftKey.privateKey || ''}
|
|
onChange={e => setDraftKey({ ...draftKey, privateKey: e.target.value })}
|
|
placeholder="-----BEGIN OPENSSH PRIVATE KEY-----"
|
|
className="min-h-[120px] font-mono text-xs"
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label>Public key</Label>
|
|
<Textarea
|
|
value={draftKey.publicKey || ''}
|
|
onChange={e => setDraftKey({ ...draftKey, publicKey: e.target.value })}
|
|
placeholder="ssh-ed25519 AAAAC3... user@host"
|
|
className="min-h-[80px] font-mono text-xs"
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label className="flex items-center gap-2">
|
|
Certificate
|
|
<span className="text-[10px] px-2 py-0.5 rounded-full bg-muted text-muted-foreground">
|
|
Optional
|
|
</span>
|
|
</Label>
|
|
<Textarea
|
|
value={draftKey.certificate || ''}
|
|
onChange={e => setDraftKey({ ...draftKey, certificate: e.target.value })}
|
|
placeholder="Paste certificate..."
|
|
className="min-h-[80px] font-mono text-xs"
|
|
/>
|
|
</div>
|
|
|
|
<div
|
|
className="border border-dashed border-border/80 rounded-xl p-4 text-center space-y-2 bg-background/60 transition-colors hover:border-primary/50"
|
|
onDrop={handleDrop}
|
|
onDragOver={handleDragOver}
|
|
>
|
|
<div className="flex items-center justify-center gap-2 text-muted-foreground">
|
|
<Upload size={16} />
|
|
<span className="text-sm">Drag and drop a private key file to import</span>
|
|
</div>
|
|
<Button
|
|
variant="secondary"
|
|
className="w-full"
|
|
onClick={() => fileInputRef.current?.click()}
|
|
>
|
|
Import from key file
|
|
</Button>
|
|
</div>
|
|
|
|
<Button
|
|
className="w-full h-11"
|
|
onClick={onImport}
|
|
disabled={!draftKey.label?.trim() || !draftKey.privateKey?.trim()}
|
|
>
|
|
Save Key
|
|
</Button>
|
|
</>
|
|
);
|
|
};
|