Better auth key support and fix to dockerfile for mongoDB.
This commit is contained in:
@@ -19,30 +19,72 @@ import { useState, useEffect } from 'react';
|
||||
import Visibility from '@mui/icons-material/Visibility';
|
||||
import VisibilityOff from '@mui/icons-material/VisibilityOff';
|
||||
|
||||
const NoAuthenticationModal = ({ isHidden, form, setForm, setIsNoAuthHidden, handleAuthSubmit }) => {
|
||||
const NoAuthenticationModal = ({ isHidden, setIsHidden, onAuthenticate }) => {
|
||||
const [form, setForm] = useState({
|
||||
authMethod: 'Select Auth',
|
||||
password: '',
|
||||
privateKey: '',
|
||||
keyType: '',
|
||||
passphrase: ''
|
||||
});
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
const [showPassphrase, setShowPassphrase] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!form.authMethod) {
|
||||
setForm(prev => ({
|
||||
...prev,
|
||||
authMethod: 'Select Auth'
|
||||
}));
|
||||
}
|
||||
}, []);
|
||||
|
||||
const isFormValid = () => {
|
||||
if (!form.authMethod || form.authMethod === 'Select Auth') return false;
|
||||
if (form.authMethod === 'rsaKey' && !form.rsaKey) return false;
|
||||
if (form.authMethod === 'password' && !form.password) return false;
|
||||
return true;
|
||||
const handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
onAuthenticate({
|
||||
authMethod: form.authMethod,
|
||||
password: form.password,
|
||||
privateKey: form.privateKey,
|
||||
keyType: form.keyType,
|
||||
passphrase: form.passphrase
|
||||
});
|
||||
setIsHidden(true);
|
||||
};
|
||||
|
||||
const handleSubmit = (event) => {
|
||||
event.preventDefault();
|
||||
if (isFormValid()) {
|
||||
handleAuthSubmit(form);
|
||||
setForm({ authMethod: 'Select Auth', password: '', rsaKey: '' });
|
||||
const handleFileChange = (e) => {
|
||||
const file = e.target.files[0];
|
||||
const supportedKeyTypes = {
|
||||
'id_rsa': 'RSA',
|
||||
'id_ed25519': 'ED25519',
|
||||
'id_ecdsa': 'ECDSA',
|
||||
'id_dsa': 'DSA',
|
||||
'.pem': 'PEM',
|
||||
'.key': 'KEY',
|
||||
'.ppk': 'PPK'
|
||||
};
|
||||
|
||||
const isValidKeyFile = Object.keys(supportedKeyTypes).some(ext =>
|
||||
file.name.toLowerCase().includes(ext) || file.name.endsWith('.pub')
|
||||
);
|
||||
|
||||
if (isValidKeyFile) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (event) => {
|
||||
const keyContent = event.target.result;
|
||||
let keyType = 'UNKNOWN';
|
||||
|
||||
// Detect key type from content
|
||||
if (keyContent.includes('BEGIN RSA PRIVATE KEY') || keyContent.includes('BEGIN RSA PUBLIC KEY')) {
|
||||
keyType = 'RSA';
|
||||
} else if (keyContent.includes('BEGIN OPENSSH PRIVATE KEY') && keyContent.includes('ssh-ed25519')) {
|
||||
keyType = 'ED25519';
|
||||
} else if (keyContent.includes('BEGIN EC PRIVATE KEY') || keyContent.includes('BEGIN EC PUBLIC KEY')) {
|
||||
keyType = 'ECDSA';
|
||||
} else if (keyContent.includes('BEGIN DSA PRIVATE KEY')) {
|
||||
keyType = 'DSA';
|
||||
}
|
||||
|
||||
setForm({
|
||||
...form,
|
||||
privateKey: keyContent,
|
||||
keyType: keyType,
|
||||
authMethod: 'key'
|
||||
});
|
||||
};
|
||||
reader.readAsText(file);
|
||||
} else {
|
||||
alert('Please upload a valid SSH key file (RSA, ED25519, ECDSA, DSA, PEM, or PPK format).');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -50,31 +92,12 @@ const NoAuthenticationModal = ({ isHidden, form, setForm, setIsNoAuthHidden, han
|
||||
<CssVarsProvider theme={theme}>
|
||||
<Modal
|
||||
open={!isHidden}
|
||||
onClose={(e, reason) => {
|
||||
if (reason !== 'backdropClick') {
|
||||
setIsNoAuthHidden(true);
|
||||
}
|
||||
}}
|
||||
sx={{
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
onClose={() => setIsHidden(true)}
|
||||
>
|
||||
<ModalDialog
|
||||
layout="center"
|
||||
sx={{
|
||||
backgroundColor: theme.palette.general.tertiary,
|
||||
borderColor: theme.palette.general.secondary,
|
||||
backgroundColor: theme.palette.general.secondary,
|
||||
color: theme.palette.text.primary,
|
||||
padding: 3,
|
||||
borderRadius: 10,
|
||||
maxWidth: '500px',
|
||||
width: '100%',
|
||||
maxHeight: '80vh',
|
||||
overflow: 'auto',
|
||||
boxSizing: 'border-box',
|
||||
mx: 2,
|
||||
}}
|
||||
>
|
||||
<DialogTitle sx={{ mb: 2 }}>Authentication Required</DialogTitle>
|
||||
@@ -84,8 +107,15 @@ const NoAuthenticationModal = ({ isHidden, form, setForm, setIsNoAuthHidden, han
|
||||
<FormControl error={!form.authMethod || form.authMethod === 'Select Auth'}>
|
||||
<FormLabel>Authentication Method</FormLabel>
|
||||
<Select
|
||||
value={form.authMethod || 'Select Auth'}
|
||||
onChange={(e, val) => setForm(prev => ({ ...prev, authMethod: val, password: '', rsaKey: '' }))}
|
||||
value={form.authMethod}
|
||||
onChange={(e, val) => setForm(prev => ({
|
||||
...prev,
|
||||
authMethod: val,
|
||||
password: '',
|
||||
privateKey: '',
|
||||
keyType: '',
|
||||
passphrase: ''
|
||||
}))}
|
||||
sx={{
|
||||
backgroundColor: theme.palette.general.primary,
|
||||
color: theme.palette.text.primary,
|
||||
@@ -93,77 +123,76 @@ const NoAuthenticationModal = ({ isHidden, form, setForm, setIsNoAuthHidden, han
|
||||
>
|
||||
<Option value="Select Auth" disabled>Select Auth</Option>
|
||||
<Option value="password">Password</Option>
|
||||
<Option value="rsaKey">Public Key</Option>
|
||||
<Option value="key">SSH Key</Option>
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
{form.authMethod === 'password' && (
|
||||
<FormControl error={!form.password}>
|
||||
<FormLabel>Password</FormLabel>
|
||||
<div style={{ display: 'flex', alignItems: 'center' }}>
|
||||
<Input
|
||||
type={showPassword ? 'text' : 'password'}
|
||||
value={form.password || ''}
|
||||
onChange={(e) => setForm(prev => ({ ...prev, password: e.target.value }))}
|
||||
sx={{
|
||||
backgroundColor: theme.palette.general.primary,
|
||||
color: theme.palette.text.primary,
|
||||
flex: 1
|
||||
}}
|
||||
/>
|
||||
<IconButton
|
||||
onClick={() => setShowPassword(!showPassword)}
|
||||
sx={{
|
||||
color: theme.palette.text.primary,
|
||||
marginLeft: 1
|
||||
}}
|
||||
>
|
||||
{showPassword ? <VisibilityOff /> : <Visibility />}
|
||||
</IconButton>
|
||||
</div>
|
||||
<Input
|
||||
type={showPassword ? "text" : "password"}
|
||||
value={form.password}
|
||||
onChange={(e) => setForm({ ...form, password: e.target.value })}
|
||||
endDecorator={
|
||||
<IconButton onClick={() => setShowPassword(!showPassword)}>
|
||||
{showPassword ? <VisibilityOff /> : <Visibility />}
|
||||
</IconButton>
|
||||
}
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
|
||||
{form.authMethod === 'rsaKey' && (
|
||||
<FormControl error={!form.rsaKey}>
|
||||
<FormLabel>Public Key</FormLabel>
|
||||
<Button
|
||||
component="label"
|
||||
sx={{
|
||||
backgroundColor: theme.palette.general.primary,
|
||||
color: theme.palette.text.primary,
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
height: '40px',
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.general.disabled,
|
||||
},
|
||||
}}
|
||||
>
|
||||
{form.rsaKey ? 'Change Public Key File' : 'Upload Public Key File'}
|
||||
<Input
|
||||
type="file"
|
||||
onChange={(e) => {
|
||||
const file = e.target.files[0];
|
||||
if (file) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (event) => {
|
||||
setForm({ ...form, rsaKey: event.target.result });
|
||||
};
|
||||
reader.readAsText(file);
|
||||
}
|
||||
{form.authMethod === 'key' && (
|
||||
<Stack spacing={2}>
|
||||
<FormControl error={!form.privateKey}>
|
||||
<FormLabel>SSH Key</FormLabel>
|
||||
<Button
|
||||
component="label"
|
||||
sx={{
|
||||
backgroundColor: theme.palette.general.primary,
|
||||
color: theme.palette.text.primary,
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
height: '40px',
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.general.disabled,
|
||||
},
|
||||
}}
|
||||
sx={{ display: 'none' }}
|
||||
/>
|
||||
</Button>
|
||||
</FormControl>
|
||||
>
|
||||
{form.privateKey ? `Change ${form.keyType || 'SSH'} Key File` : 'Upload SSH Key File'}
|
||||
<Input
|
||||
type="file"
|
||||
onChange={handleFileChange}
|
||||
sx={{ display: 'none' }}
|
||||
/>
|
||||
</Button>
|
||||
</FormControl>
|
||||
{form.privateKey && (
|
||||
<FormControl>
|
||||
<FormLabel>Key Passphrase (optional)</FormLabel>
|
||||
<Input
|
||||
type={showPassphrase ? "text" : "password"}
|
||||
value={form.passphrase || ''}
|
||||
onChange={(e) => setForm(prev => ({ ...prev, passphrase: e.target.value }))}
|
||||
endDecorator={
|
||||
<IconButton onClick={() => setShowPassphrase(!showPassphrase)}>
|
||||
{showPassphrase ? <VisibilityOff /> : <Visibility />}
|
||||
</IconButton>
|
||||
}
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
</Stack>
|
||||
)}
|
||||
|
||||
<Button
|
||||
type="submit"
|
||||
disabled={!isFormValid()}
|
||||
disabled={!form.authMethod || form.authMethod === 'Select Auth' ||
|
||||
(form.authMethod === 'password' && !form.password) ||
|
||||
(form.authMethod === 'key' && !form.privateKey)}
|
||||
sx={{
|
||||
backgroundColor: theme.palette.general.primary,
|
||||
color: theme.palette.text.primary,
|
||||
@@ -174,8 +203,6 @@ const NoAuthenticationModal = ({ isHidden, form, setForm, setIsNoAuthHidden, han
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.1)',
|
||||
color: 'rgba(255, 255, 255, 0.3)',
|
||||
},
|
||||
marginTop: 2,
|
||||
height: '40px',
|
||||
}}
|
||||
>
|
||||
Connect
|
||||
@@ -191,10 +218,8 @@ const NoAuthenticationModal = ({ isHidden, form, setForm, setIsNoAuthHidden, han
|
||||
|
||||
NoAuthenticationModal.propTypes = {
|
||||
isHidden: PropTypes.bool.isRequired,
|
||||
form: PropTypes.object.isRequired,
|
||||
setForm: PropTypes.func.isRequired,
|
||||
setIsNoAuthHidden: PropTypes.func.isRequired,
|
||||
handleAuthSubmit: PropTypes.func.isRequired,
|
||||
setIsHidden: PropTypes.func.isRequired,
|
||||
onAuthenticate: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default NoAuthenticationModal;
|
||||
Reference in New Issue
Block a user