Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Container manager #40

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<link rel="icon" type="image/svg+xml" href="/public/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Honeybrain Dashboard</title>
</head>
Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"@mui/icons-material": "^5.11.16",
"@mui/material": "^5.13.2",
"@mui/styles": "^5.13.2",
"@mui/system": "^5.14.15",
"@protobuf-ts/grpcweb-transport": "^2.9.0",
"@protobuf-ts/plugin": "^2.9.0",
"@types/react-router-dom": "^5.3.3",
Expand All @@ -30,10 +31,12 @@
"react-router-dom": "^5.3.4",
"react-toastify": "^9.1.3",
"reactjs-popup": "^2.0.5",
"swiper": "6.8.4",
"vite": "^4.3.2",
"web-vitals": "^2.1.4"
},
"devDependencies": {
"@types/node": "^20.8.5",
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11",
"@vitejs/plugin-react": "^4.0.0",
Expand Down
3 changes: 0 additions & 3 deletions src/components/LanguageSwitcher.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@ const LanguageSwitcher = () => {
<Box
display="flex"
alignItems="center"
paddingRight={2}
marginRight={2}
borderRight={1}
borderColor="grey.500"
>
<ToggleButtonGroup
Expand Down
125 changes: 103 additions & 22 deletions src/components/Navbar.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { AppBar, Toolbar, Typography, Button } from '@mui/material';
import { useHistory } from 'react-router-dom';
import { AppBar, Toolbar, Typography, Button, IconButton, Box, Tooltip, Avatar, Menu, MenuItem, Divider, ListItemIcon } from '@mui/material';
import '../styles.css';
import { makeStyles } from '@mui/styles';

import { Settings, Logout } from '@mui/icons-material';
import React, { useContext } from 'react';
import AuthContext from "@contexts/AuthContext";
import { Link } from 'react-router-dom';
Expand All @@ -23,35 +24,115 @@ const useStyles = makeStyles({


const Navbar = () => {

const { isLoggedIn, logout } = useContext(AuthContext);
const { t } = useTranslation();
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
const open = Boolean(anchorEl);
const history = useHistory();

const handleClick = (event: React.MouseEvent<HTMLElement>) => {
setAnchorEl(event.currentTarget);
};

const handleClose = () => {
setAnchorEl(null);
};

const handleLogout = () => {
logout();
};

const handleRoutes = (path) => {
history.push(path);
}

const classes = useStyles();

return (
<AppBar position="static">
<Toolbar>
<Typography variant="h6" className={classes.title}>
{t('navbar.dashboard')}
</Typography>
<LanguageSwitcher />
{!isLoggedIn && (
<>
<Button component={Link} to="/login" color="inherit" className={classes.navButton}>{t('navbar.login')}</Button>
</>
)}
{isLoggedIn && (
<>
<Button component={Link} to="/" color="inherit" className={classes.navButton}>{t('navbar.home')}</Button>
<Button component={Link} to="/profile" color="inherit" className={classes.navButton}>{t('navbar.profile')}</Button>
<Button color="inherit" onClick={handleLogout} className={classes.navButton}>{t('navbar.logout')}</Button>
</>
)}
</Toolbar>
</AppBar>
<React.Fragment>
<AppBar position="static">
<Toolbar>
<Typography variant="h6" className={classes.title}>
{t('navbar.dashboard')}
</Typography>
{!isLoggedIn && (
<>
<Button component={Link} to="/login" color="inherit" className={classes.navButton}>{t('navbar.login')}</Button>
</>
)}
{isLoggedIn && (
<>
<Box sx={{ display: 'flex', alignItems: 'center', textAlign: 'center' }}>
<Button component={Link} to="/" color="inherit" className={classes.navButton}>{t('navbar.home')}</Button>
<Tooltip title="Account settings">
<IconButton
onClick={handleClick}
size="small"
sx={{ ml: 2 }}
aria-controls={open ? 'account-menu' : undefined}
aria-haspopup="true"
aria-expanded={open ? 'true' : undefined}>
<Avatar sx={{ width: 32, height: 32 }}>M</Avatar>
</IconButton>
</Tooltip>
</Box>
<Menu
anchorEl={anchorEl}
id="account-menu"
open={open}
onClose={handleClose}
onClick={handleClose}
PaperProps={{
elevation: 0,
sx: {
overflow: 'visible',
filter: 'drop-shadow(0px 2px 8px rgba(0,0,0,0.32))',
mt: 1.5,
'& .MuiAvatar-root': {
width: 32,
height: 32,
ml: -0.5,
mr: 1,
},
'&:before': {
content: '""',
display: 'block',
position: 'absolute',
top: 0,
right: 14,
width: 10,
height: 10,
bgcolor: 'background.paper',
transform: 'translateY(-50%) rotate(45deg)',
zIndex: 0,
},
},
}}
transformOrigin={{ horizontal: 'right', vertical: 'top' }}
anchorOrigin={{ horizontal: 'right', vertical: 'bottom' }}>
<MenuItem onClick={()=>handleRoutes('/profile')}>
<Avatar />
{t('navbar.profile')}
</MenuItem>
<Divider />
<MenuItem onClick={handleClose}>
<LanguageSwitcher />
<div style={{ margin: '10px' }}>{t('navbar.language')}</div>
</MenuItem>
<Divider />
<MenuItem onClick={handleLogout}>
<ListItemIcon>
<Logout fontSize="small" />
</ListItemIcon>
{t('navbar.logout')}
</MenuItem>
</Menu>
</>
)}
</Toolbar>
</AppBar>
</React.Fragment>
);
};

Expand Down
110 changes: 101 additions & 9 deletions src/components/dashboard/ContainerManager.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,101 @@
import React, { useState, useEffect, useContext } from 'react';
import { Grid, Typography, Card, CardContent, Box } from '@mui/material';
import React, { useState, useEffect, useContext, useRef } from 'react';
import { Grid, Typography, Card, CardContent, Box, Button, Dialog, DialogTitle, DialogContent, DialogActions, DialogContentText } from '@mui/material';
import ErrorIcon from '@mui/icons-material/Error';
import CheckCircleIcon from '@mui/icons-material/CheckCircle';
import PauseCircleIcon from '@mui/icons-material/PauseCircle';
import AuthContext from "@contexts/AuthContext";
import HelpModal from "@components/HelpModal";
import useContainersRPC from '@hooks/backend/honeypotService/useContainersRPC';
import { useTranslation } from 'react-i18next';
import Carousel from '@components/Carousel';

export interface ConfirmationDialogRawProps {
id: string;
keepMounted: boolean;
open: boolean;
onClose: (value?: string) => void;
}

let _status: any = null;
let _IP: any = null;

function ConfirmationDialogRaw(props: ConfirmationDialogRawProps) {
const { onClose, open, ...other } = props;

const handleCancel = () => {
onClose('no');
};

const handleOk = () => {
onClose('yes');
};

return (
<Dialog
sx={{ '& .MuiDialog-paper': { width: '80%', maxHeight: 435 } }}
maxWidth="xs"
open={open}
{...other}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">Change container state ?</DialogTitle>
<DialogContent dividers>
<DialogContentText id="alert-dialog-description">
if you accept, you could damage the viability and security of the honeypot.
</DialogContentText>
</DialogContent>
<DialogActions>
<Button autoFocus onClick={handleCancel}>Cancel</Button>
<Button onClick={handleOk}>Continue</Button>
</DialogActions>
</Dialog>
);
}

const ContainerManager: React.FC = () => {
const { containers } = useContainersRPC();
const { token } = useContext(AuthContext);
const { t } = useTranslation();
const [elementsActifs, setElementsActifs] = useState<string[]>([]);
const [open, setOpen] = useState(false);

const handleClickOpen = (elementId: string, status: string) => {
setOpen(true);
_IP = elementId,
_status = status
};

const handleClose = (newValue?: string) => {
setOpen(false);
if (newValue === 'yes')
toggleElement(_IP, _status)
};

const getContainerStatus = (status: string) => {
const getContainerStatus = (status: string, ip: string) => {
if (status.startsWith('running')) {
return <CheckCircleIcon color="success" />;
if (elementsActifs.includes(ip)) {
return <PauseCircleIcon color="warning" />;
} else {
return <CheckCircleIcon color="success" />;
}
} else {
return <ErrorIcon color="error" />;
}
};

const toggleElement = (elementId: string, status: string) => {
if (status.startsWith('running')) {
if (elementsActifs.includes(elementId)) {
setElementsActifs(elementsActifs.filter((id) => id !== elementId));
} else {
setElementsActifs([...elementsActifs, elementId]);
}
}
};

return (
<>
<Grid container direction="column">
<Grid item>
<Grid container justifyContent="space-between" alignItems="center" mb={2}>
Expand All @@ -42,28 +117,45 @@ const ContainerManager: React.FC = () => {
marginBottom: '16px', // Add a margin to each child
},
}}
>
{containers && containers.map((container, index) => (
<Card variant="outlined" key={index}>
>
{containers && containers.map((container, index) => (
<>
<Card variant="outlined" key={index}
aria-controls="menu-dialog"
onClick={() => handleClickOpen(container.ip, container.status)}
style={{
backgroundColor: elementsActifs.includes(container.ip) ? 'lightyellow' : 'lightblue',
cursor: 'pointer',
marginBottom: '16px',
}}>
<CardContent>
<Box
sx={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'flex-start',
}}
>
>
<Typography variant="h6">{container.name}</Typography>
{getContainerStatus(container.status)}
{getContainerStatus(container.status, container.ip)}
</Box>
<Typography variant="body2" color="text.secondary">{t('containerManager.status')}: {container.status}</Typography>
<Typography variant="body2" color="text.secondary">{t('containerManager.ip')}: {container.ip.split('/')[0]}</Typography>
</CardContent>
</Card>
</>
))}
<ConfirmationDialogRaw
id="menu-dialog"
keepMounted
open={open}
onClose={handleClose}
/>
</Box>
</Grid>
</Grid>
<Carousel/>
</>
);
};

Expand Down
9 changes: 7 additions & 2 deletions src/components/dashboard/UsersManagement.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react';
import React, { useState, useEffect, useContext } from 'react';
import {
Typography, TextField, Button, Grid, List, ListItem, ListItemText, Box, Select, MenuItem, Card, CardContent, Snackbar, Alert, IconButton
} from '@mui/material';
Expand All @@ -7,6 +7,7 @@ import useInviteUserRPC from '@hooks/backend/userService/useInviteUserRPC';
import useChangeRightsRPC from '@hooks/backend/userService/useChangeRightsRPC';
import useDeleteUserRPC from '@hooks/backend/userService/useDeleteUserRPC';
import DeleteIcon from '@mui/icons-material/Delete';
import AuthContext from "@contexts/AuthContext";

interface User {
email: string;
Expand All @@ -23,6 +24,7 @@ const UsersManagement: React.FC = () => {
const [open, setOpen] = React.useState(false);
const [alertText, setAlertText] = React.useState('');
const [alertSeverity, setAlertSeverity] = useState<'success' | 'error'>('success');
const { rights} = useContext(AuthContext);

const { getUsers } = useGetUsersRPC();
const { inviteUser } = useInviteUserRPC();
Expand Down Expand Up @@ -119,6 +121,7 @@ const UsersManagement: React.FC = () => {
}, []);

return (
(rights ? <>
<Grid container direction="column" spacing={2}>
<Grid item>
<Typography variant="h4">
Expand Down Expand Up @@ -194,8 +197,10 @@ const UsersManagement: React.FC = () => {
</Alert>
</Snackbar>
</Grid>
</>
: <></>
)
);

};

export default UsersManagement;
Loading