Started syncing back new detection changes. Unsure how to optimize this for now.

This commit is contained in:
Frikky
2024-08-16 00:42:30 +02:00
parent 7d8a52cfff
commit e8a2107524
10 changed files with 237 additions and 349 deletions
+1 -1
View File
@@ -299,7 +299,7 @@ const AppGrid = (props) => {
useEffect(() => {
var baseurl = globalUrl;
fetch(baseurl + "/api/v1/getinfo", {
fetch(baseurl + "/api/v1/me", {
credentials: "include",
headers: {
'Content-Type': 'application/json',
@@ -9,12 +9,12 @@ import {
import EditIcon from "@mui/icons-material/Edit";
import { toast } from "react-toastify";
import ShuffleCodeEditor from "../components/ShuffleCodeEditor1.jsx";
import theme from '../theme.jsx';
const RuleCard = ({ ruleName, description, file_id, globalUrl, folderDisabled, isTenzirActive, ...otherProps }) => {
const [openCodeEditor, setOpenCodeEditor] = React.useState(false);
const [fileData, setFileData] = React.useState("");
const [isEnabled, setIsEnabled] = React.useState(otherProps.is_enabled);
const isCloud = ["localhost:3002", "shuffler.io"].includes(window.location.host);
const handleSwitchChange = (event) => {
@@ -50,7 +50,7 @@ const RuleCard = ({ ruleName, description, file_id, globalUrl, folderDisabled, i
})
.then((responseJson) => {
if (responseJson.success === true) {
toast("Successfully updated file");
toast("Successfully updated rule");
}
})
.catch((error) => {
@@ -59,7 +59,10 @@ const RuleCard = ({ ruleName, description, file_id, globalUrl, folderDisabled, i
};
return (
<Card variant="outlined" sx={{ mb: 2 }}>
<Card style={{
borderRadius: theme.palette.borderRadius,
minHeight: 100,
}}>
<CardContent>
<div
style={{
@@ -67,8 +70,10 @@ const RuleCard = ({ ruleName, description, file_id, globalUrl, folderDisabled, i
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 16,
color: "white",
}}
>
<h1> HELO</h1>
<Typography variant="h6">{ruleName}</Typography>
<div style={{ display: 'flex', alignItems: 'center' }}>
<IconButton onClick={() => openEditBar(file_id, setOpenCodeEditor, setFileData, globalUrl)}>
-264
View File
@@ -124,8 +124,6 @@ const useStyles = makeStyles((theme) => ({
const Header = (props) => {
const {
globalUrl,
setNotifications,
notifications,
isLoaded,
isLoggedIn,
removeCookie,
@@ -230,71 +228,6 @@ const Header = (props) => {
? window.location.pathname
: "";
const clearNotifications = () => {
// Don't really care about the logout
toast("Clearing notifications")
fetch(`${globalUrl}/api/v1/notifications/clear`, {
credentials: "include",
method: "GET",
headers: {
"Content-Type": "application/json",
},
})
.then(function (response) {
if (response.status !== 200) {
console.log("Error in response");
}
return response.json();
})
.then(function (responseJson) {
if (responseJson.success === true) {
setNotifications([]);
handleClose();
} else {
toast("Failed dismissing notifications. Please try again later.");
}
})
.catch((error) => {
console.log("error in notification dismissal: ", error);
//removeCookie("session_token", {path: "/"})
});
};
const dismissNotification = (alert_id) => {
// Don't really care about the logout
fetch(`${globalUrl}/api/v1/notifications/${alert_id}/markasread`, {
credentials: "include",
method: "GET",
headers: {
"Content-Type": "application/json",
},
})
.then(function (response) {
if (response.status !== 200) {
console.log("Error in response");
}
return response.json();
})
.then(function (responseJson) {
if (responseJson.success === true) {
const newNotifications = notifications.filter(
(data) => data.id !== alert_id
);
console.log("NEW NOTIFICATIONS: ", newNotifications);
setNotifications(newNotifications);
} else {
toast("Failed dismissing notification. Please try again later.");
}
})
.catch((error) => {
console.log("error in notification dismissal: ", error);
//removeCookie("session_token", {path: "/"})
});
};
// DEBUG HERE
const handleClickLogout = () => {
console.log("SHOULD LOG OUT");
@@ -337,202 +270,6 @@ const Header = (props) => {
const imagesize = 22;
const boxColor = "#86c142";
const NotificationItem = (props) => {
const { data } = props
var image = "";
var orgName = "";
var orgId = "";
if (userdata.orgs !== undefined) {
const foundOrg = userdata.orgs.find((org) => org.id === data["org_id"]);
if (foundOrg !== undefined && foundOrg !== null) {
//position: "absolute", bottom: 5, right: -5,
const imageStyle = {
width: imagesize,
height: imagesize,
pointerEvents: "none",
marginLeft:
data.creator_org !== undefined && data.creator_org.length > 0
? 20
: 0,
borderRadius: 10,
border:
foundOrg.id === userdata.active_org.id
? `3px solid ${boxColor}`
: null,
cursor: "pointer",
marginRight: 10,
}
image =
foundOrg.image === "" ? (
<img
alt={foundOrg.name}
src={theme.palette.defaultImage}
style={imageStyle}
/>
) : (
<img
alt={foundOrg.name}
src={foundOrg.image}
style={imageStyle}
onClick={() => { }}
/>
);
orgName = foundOrg.name;
orgId = foundOrg.id;
}
}
return (
<Paper
style={{
backgroundColor: theme.palette.surfaceColor,
width: notificationWidth,
padding: 25,
borderBottom: "1px solid rgba(255,255,255,0.4)",
}}
>
{data.reference_url !== undefined && data.reference_url !== null && data.reference_url.length > 0 ?
<Link to={data.reference_url} style={{ color: "#f86a3e", textDecoration: "none", }}>
<Typography variant="body1">
{data.title} ({data.amount})
</Typography >
</Link>
:
<Typography variant="body1" color="textSecondary">
{data.title}
</Typography >
}
{data.image !== undefined && data.image !== null && data.image.length > 0 ?
<img alt={data.title} src={data.image} style={{ height: 100, width: 100, }} />
:
null
}
<Typography variant="body2" style={{ marginTop: 10, maxHeight: 200, overflowX: "hidden", overflowY: "auto", }}>
{data.description}
</Typography >
<div style={{ display: "flex" }}>
{data.read === false ? (
<Button
color="primary"
variant="outlined"
style={{ marginTop: 15 }}
onClick={() => {
dismissNotification(data.id);
}}
>
Dismiss
</Button>
) : null}
<Tooltip title={`Org "${orgName}"`} placement="bottom">
<div
style={{ cursor: "pointer", marginLeft: 10, marginTop: 20 }}
onClick={() => { }}
>
{image}
</div>
</Tooltip>
</div>
</Paper>
);
};
const notificationMenu = (
<span style={{}}>
<IconButton
color="primary"
style={{}}
aria-controls="simple-menu"
aria-haspopup="true"
onClick={(event) => {
setAnchorEl(event.currentTarget);
}}
>
{/*<Badge badgeContent={notifications.filter((n) => n.read === false).length} color="primary">*/}
<NotificationsIcon
color="secondary"
style={{ height: 30, width: 30 }}
alt="Your username here"
src=""
/>
</IconButton>
<Menu
id="simple-menu"
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
style={{
zIndex: 10002,
maxHeight: "80vh",
overflowX: "hidden",
overflowY: "auto",
}}
PaperProps={{
style: {
backgroundColor: theme.palette.surfaceColor,
},
}}
onClose={() => {
handleClose();
}}
>
<Paper
style={{
backgroundColor: theme.palette.surfaceColor,
width: notificationWidth,
padding: 25,
borderBottom: "3px solid rgba(255,255,255,0.4)",
}}
>
<div style={{ display: "flex", marginBottom: 5 }}>
<Typography variant="body1" style={{ flex: 1, }}>
Notifications ({notifications.filter((data) => !data.read).length})
</Typography>
<ButtonGroup style={{ height: 40, flex: 1, }}>
{notifications.length > 1 ? (
<Button
color="primary"
variant="outlined"
disabled={notifications.filter((data) => !data.read).length === 0}
onClick={() => {
clearNotifications();
}}
>
Flush
</Button>
) : null}
<Button
color="primary"
variant="contained"
onClick={() => {
navigate("/admin?tab=organization&admin_tab=priorities")
}}
>
Explore
</Button>
</ButtonGroup>
</div>
<Typography variant="body2" color="textSecondary" style={{ marginTop: 5, }}>
Notifications generated made by Shuffle to help you discover issues or
improvements. <a href="/docs/organizations#notifications" target="_blank" rel="noopener noreferrer" style={{ color: "#f86a3e", textDecoration: "none", }}>
Learn more</a>
</Typography>
</Paper>
{notifications.map((data, index) => {
if (data.read) {
return null
}
return <NotificationItem data={data} key={index} />;
})}
</Menu>
</span>
);
const handleClickChangeOrg = (orgId) => {
// Don't really care about the logout
//name: org.name,
@@ -689,7 +426,6 @@ const Header = (props) => {
</MenuItem>
</Link>
{/*notificationMenu*/}
<Divider style={{ marginTop: 10, marginBottom: 10, }} />
<Link to="/docs" style={hrefStyle}>
<MenuItem
@@ -977,7 +977,11 @@ const CodeEditor = (props) => {
}}
PaperComponent={PaperComponent}
PaperProps={{
onClick: () => setActiveDialog("codeeditor"),
onClick: () => {
if (setActiveDialog !== undefined) {
setActiveDialog("codeeditor")
}
},
style: {
// zIndex: 12501,
pointerEvents: "auto",
+3 -1
View File
@@ -18,11 +18,13 @@ const theme = createTheme(adaptV4Theme({
secondary: "rgba(255,255,255,0.7)",
},
type: "dark",
inputColor: "rgba(39,41,45,1)",
//inputColor: "#383B40",
inputColor: "rgba(39,41,45,1)",
surfaceColor: "#27292d",
platformColor: "#1c1c1d",
backgroundColor: "#1a1a1a",
green: "#5cc879",
borderRadius: 10,
defaultBorder: "1px solid rgba(255,255,255,0.3)",
+4
View File
@@ -1533,6 +1533,8 @@ const Apps = (props) => {
const [hover, setHover] = React.useState(false);
const makeFancy = text?.includes("Generate")
return (
<Paper
onMouseEnter={() => setHover(true)}
@@ -1551,6 +1553,8 @@ const Apps = (props) => {
maxHeight: 150,
borderRadius: theme.palette.borderRadius,
//borderImage: makeFancy ? "linear-gradient(45deg, red, orange, yellow, green, blue, indigo, violet) 1" : null,
}}
>
{icon}
+46 -34
View File
@@ -6,10 +6,13 @@ import {
Switch,
Typography,
Button,
CircularProgress,
Paper,
} from "@mui/material";
import { toast } from "react-toastify";
import RuleCard from "./RuleCard";
import CircularProgress from "@material-ui/core/CircularProgress";
import theme from '../theme.jsx';
import DetectionRuleCard from "../components/DetectionRuleCard.jsx";
const handleDirectoryChange = (folderDisabled, setFolderDisabled, globalUrl, isTenzirActive) => {
@@ -17,8 +20,9 @@ const handleDirectoryChange = (folderDisabled, setFolderDisabled, globalUrl, isT
toast("connect to siem first for global enable/disable to work");
return;
}
const action = folderDisabled ? "enable_folder" : "disable_folder";
const url = `${globalUrl}/api/v1/files/detection/${action}`;
const url = `${globalUrl}/api/v1/detection/${action}`;
fetch(url, {
method: "PUT",
@@ -43,13 +47,8 @@ const handleDirectoryChange = (folderDisabled, setFolderDisabled, globalUrl, isT
});
};
const Detection = ({
globalUrl,
ruleInfo,
folderDisabled,
setFolderDisabled,
isTenzirActive,
}) => {
const Detection = (props) => {
const { globalUrl, ruleInfo, folderDisabled, setFolderDisabled, isTenzirActive } = props;
const [searchQuery, setSearchQuery] = useState("");
const [loading, setLoading] = useState(false);
@@ -94,8 +93,16 @@ const Detection = ({
);
return (
<Container sx={{ mt: 4 }}>
<Box sx={{ border: "1px solid #ccc", borderRadius: 2, p: 3 }}>
<Container>
<Paper
style={{
marginTop: 50,
width: "100%",
padding: 50,
backgroundColor: theme.palette.backgroundColor,
borderRadius: theme.palette.borderRadius,
}}
>
<Box
sx={{
display: "flex",
@@ -108,13 +115,14 @@ const Detection = ({
Sigma Detection Rules
</Typography>
<Button
variant="contained"
onClick={handleConnectClick}
disabled={loading} // Disable the button while loading
style={{ backgroundColor: isTenzirActive ? "green" : "red"}}
>
{loading ? <CircularProgress size={24} /> : isTenzirActive ? "Connected to siem" : "Connect to siem"}
</Button>
variant="contained"
onClick={handleConnectClick}
disabled={loading} // Disable the button while loading
color={isTenzirActive ? "primary" : "secondary"}
style={{ }}
>
{loading ? <CircularProgress size={24} /> : isTenzirActive ? "Connected to siem" : "Connect to siem"}
</Button>
</Box>
<Box
sx={{
@@ -172,25 +180,29 @@ const Detection = ({
height: "500px",
width: "100%",
overflowY: "auto",
border: "1px solid #ddd",
p: 1,
}}
>
{filteredRules?.length > 0 &&
filteredRules.map((card) => (
<RuleCard
key={card.file_id}
ruleName={card.title}
description={card.description}
file_id={card.file_id}
globalUrl={globalUrl}
folderDisabled={folderDisabled}
isTenzirActive={isTenzirActive}
{...card}
/>
))}
{filteredRules?.length > 0 ?
filteredRules.map((card) => {
console.log("RULE CARD: ", card);
return (
<DetectionRuleCard
key={card.file_id}
ruleName={card.title}
description={card.description}
file_id={card.file_id}
globalUrl={globalUrl}
folderDisabled={folderDisabled}
isTenzirActive={isTenzirActive}
{...card}
/>
)
})
: null }
</Box>
</Box>
</Paper>
</Container>
);
};
+162
View File
@@ -0,0 +1,162 @@
import React, { useState, useEffect } from "react";
import { Container, CircularProgress, Typography } from "@mui/material";
import { toast } from "react-toastify";
import Detection from "../views/Detection";
const DetectionDashBoard = (props) => {
const { globalUrl } = props;
const [ruleInfo, setRuleInfo] = useState(null);
const [, setSelectedRule] = useState(null);
const [, setFileData] = useState("");
const [isTenzirActive, setIsTenzirActive] = useState(false);
const [folderDisabled, setFolderDisabled] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [importAttempts, setImportAttempts] = useState(0);
const maxImportAttempts = 2;
useEffect(() => {
const fetchTimeout = setTimeout(() => {
fetchSigmaInfo();
}, 1000); // Delay by 1 second
return () => clearTimeout(fetchTimeout);
}, [globalUrl]);
useEffect(() => {
if (ruleInfo && ruleInfo.length === 0 && importAttempts < maxImportAttempts) {
importSigmaFromUrl();
}
}, [ruleInfo]);
const openEditBar = (rule) => {
setSelectedRule(rule);
fetchFileContent(rule.file_id);
};
const handleSave = (updatedContent) => {
toast("This will be saved");
};
const fetchFileContent = (file_id) => {
setFileData("");
fetch(`${globalUrl}/api/v1/files/${file_id}/content`, {
method: "GET",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
credentials: "include",
})
.then((response) => {
if (response.status !== 200) {
console.log("Status not 200 for file :O!");
return "";
}
return response.text();
})
.then((respdata) => {
if (respdata.length === 0) {
toast("Failed getting file. Is it deleted?");
return;
}
setFileData(respdata);
})
.catch((error) => {
toast(error.toString());
});
};
const fetchSigmaInfo = () => {
const url = `${globalUrl}/api/v1/files/detection/sigma_rules`;
setIsLoading(true);
fetch(url, {
method: "GET",
credentials: "include",
headers: {
"Content-Type": "application/json",
},
})
.then((response) => response.json())
.then((responseJson) => {
if (responseJson["success"] === false) {
toast("Failed to get sigma rules");
} else {
setRuleInfo(responseJson.sigma_info || []);
setFolderDisabled(responseJson.folder_disabled);
setIsTenzirActive(responseJson.is_tenzir_active);
}
setIsLoading(false);
})
.catch((error) => {
setIsLoading(false);
console.log("Error in getting sigma files: ", error);
toast("An error occurred while fetching sigma rules");
setRuleInfo([]);
});
};
const importSigmaFromUrl = () => {
setIsLoading(true);
setImportAttempts((prevAttempts) => prevAttempts + 1);
const url = "https://github.com/satti-hari-krishna-reddy/shuffle_sigma";
const folder = "sigma";
const parsedData = {
url: url,
path: folder,
field_3: "main",
};
toast(`Getting files from url ${url}. This may take a while if the repository is large. Please wait...`);
fetch(`${globalUrl}/api/v1/files/download_remote_enhanced`, {
method: "POST",
mode: "cors",
headers: {
Accept: "application/json",
},
body: JSON.stringify(parsedData),
credentials: "include",
})
.then((response) => response.json())
.then((responseJson) => {
if (responseJson.success) {
toast("Successfully loaded files from " + url);
fetchSigmaInfo(); // Fetch again after successful import
} else {
toast(responseJson.reason ? `Failed loading: ${responseJson.reason}` : "Failed loading");
}
setIsLoading(false);
})
.catch((error) => {
toast(error.toString());
setIsLoading(false);
});
};
if (isLoading && (!ruleInfo || ruleInfo.length === 0)) {
return (
<Container style={{ display: "flex", justifyContent: "center", alignItems: "center", height: "100vh" }}>
<div>
<CircularProgress />
<Typography variant="h6" style={{ marginTop: 20 }}>Downloading rules, please wait...</Typography>
</div>
</Container>
);
}
return (
<Container style={{ display: "flex" }}>
<Detection
globalUrl={globalUrl}
ruleInfo={ruleInfo}
folderDisabled={folderDisabled}
setFolderDisabled={setFolderDisabled}
isTenzirActive={isTenzirActive}
/>
</Container>
);
};
export default DetectionDashBoard;
+1 -1
View File
@@ -183,7 +183,7 @@ const LoginDialog = (props) => {
if (responseJson.tutorials === undefined || responseJson.tutorials === null || !responseJson.tutorials.includes("welcome")) {
console.log("RUN Welcome!!")
window.location.pathname = "/welcome"
window.location.pathname = "/welcome?tab=2"
return
}