From eee78556be51f19a097bd1b51045fea193471a6a Mon Sep 17 00:00:00 2001 From: frikky Date: Thu, 26 Jan 2023 15:50:19 +0100 Subject: [PATCH] Minor frontend changes in suggestion engine --- frontend/src/components/AppFramework.jsx | 223 ++++++++++++++---- .../src/components/SuggestedWorkflows.jsx | 5 +- frontend/src/components/UsecaseSearch.jsx | 8 +- frontend/src/components/WelcomeForm2.jsx | 9 +- 4 files changed, 192 insertions(+), 53 deletions(-) diff --git a/frontend/src/components/AppFramework.jsx b/frontend/src/components/AppFramework.jsx index 0d475b0d..39547697 100644 --- a/frontend/src/components/AppFramework.jsx +++ b/frontend/src/components/AppFramework.jsx @@ -21,6 +21,8 @@ import { CircularProgress, Tooltip, Dialog, + Chip, + Avatar, } from "@material-ui/core"; import { @@ -38,10 +40,25 @@ import * as cytoscape from "cytoscape"; cytoscape.use(edgehandles); -const svgSize = 23 +const svgSize = "40px" const parsedDatatypeImages = { - "Cases": encodeURI(`data:image/svg+xml;utf-8,`), + "SIEM": encodeURI(`data:image/svg+xml;utf-8,`), + + "CASES": encodeURI(`data:image/svg+xml;utf-8,`), + "EDR & AV": encodeURI(`data:image/svg+xml;utf-8,`), + + "INTEL": encodeURI(`data:image/svg+xml;utf-8,`), + + "COMMS": encodeURI(`data:image/svg+xml;utf-8,`), + + "NETWORK": encodeURI(`data:image/svg+xml;utf-8,`), + + "INTEL": encodeURI(`data:image/svg+xml;utf-8,`), + + "ASSETS": encodeURI(`data:image/svg+xml;utf-8,`), + + "IAM": encodeURI(`data:image/svg+xml;utf-8,`), } export const usecases = { @@ -541,6 +558,8 @@ const AppFramework = (props) => { const [usecaseType, setUsecaseType] = React.useState(0) const [selectedUsecase, setSelectedUsecase] = React.useState(selectedOption !== undefined ? selectedOption : "Phishing") + const [injectedApps, setInjectedApps] = React.useState([]) + const scale = size === undefined ? 1 : size > 5 ? 3 : size const alert = useAlert() @@ -549,7 +568,20 @@ const AppFramework = (props) => { console.log("Should check for next apps to load from App suggestion model") //fetch(globalUrl + "/api/v1/workflows/usecases", { //credentials: "include", + //cors: "no-cors", + const max_suggestions = 5 + const max_per_category = 2 + const priorities = { + "edr": 1, + "siem": 2, + "cases": 3, + "intel": 4, + "comms": 5, + } + + // Based on apps recommended from repo https://github.com/Shuffle/app-recommender + //fetch("http://localhost:8080/app_recommendations", { fetch("https://europe-west2-shuffler.cloudfunctions.net/app_recommendations", { method: "POST", headers: { @@ -557,7 +589,6 @@ const AppFramework = (props) => { Accept: "application/json", }, body: JSON.stringify(frameworkData), - cors: "no-cors", }) .then((response) => { //if (response.status !== 200) { @@ -567,20 +598,36 @@ const AppFramework = (props) => { return response.json(); }) .then((responseJson) => { - console.log("Response: ", responseJson) - //if (responseJson.success === false) { - // if (responseJson.reason !== undefined) { - // alert.error("Failed updating: " + responseJson.reason) - // } else { - // alert.error("Failed to update framework for your org.") - // } - //} else { - // alert.info("Updated usecase.") - //} + // Loop the response dict + var suggestions = [] + var suggestion_cnt = 0 + var category_count = {} + for (const [key, value] of Object.entries(responseJson)) { + if (suggestion_cnt >= max_suggestions) { + break + } + + if (category_count[key] === undefined) { + category_count[key] = 1 + } else { + category_count[key] += 1 + } + + if (category_count[key] > max_per_category) { + continue + } + + //console.log("Found: " + key + " with value of len: " + value.length) + + //suggestion_cnt += value.slice(0,1).length + suggestions.push(value.slice(0,1)) + } + + console.log("SUGG: ", suggestions) + setInjectedApps(suggestions) }) .catch((error) => { - //alert.error(error.toString()); - //setFrameworkLoaded(true) + console.log("Recommendation error: ", error); }) } @@ -1318,7 +1365,7 @@ const AppFramework = (props) => { const baselocationY = 50*scale const shiftmodifier = 3*scale //const svgSize = `${40*scale}px` - const svgSize = `${40}px` + //const svgSize = `${40}px` const fontSize = `${12*scale}px` const defaultSize = `${85*scale}px` @@ -1343,9 +1390,8 @@ const AppFramework = (props) => { margin_y: parsedFrameworkData.Cases.large_image === undefined ? `${19*scale}px` : `0px`, width: parsedFrameworkData.Cases.large_image === undefined ? iconSize : defaultSize, height: parsedFrameworkData.Cases.large_image === undefined ? iconSize : defaultSize, - large_image: parsedFrameworkData.Cases.large_image === undefined ? encodeURI(`data:image/svg+xml;utf-8, - - `) : parsedFrameworkData.Cases.large_image, + large_image: parsedFrameworkData.Cases.large_image === undefined ? parsedDatatypeImages["CASES"] : parsedFrameworkData.Cases.large_image, + label: securityFramework[0].text.toUpperCase(), id: securityFramework[0].text.toUpperCase(), animate: true, @@ -1372,9 +1418,8 @@ const AppFramework = (props) => { margin_y: parsedFrameworkData.IAM.large_image === undefined ? `${19*scale}px` : `0px`, width: parsedFrameworkData.IAM.large_image === undefined ? iconSize : defaultSize, height: parsedFrameworkData.IAM.large_image === undefined ? iconSize : defaultSize, - large_image: parsedFrameworkData.IAM.large_image === undefined ? encodeURI(`data:image/svg+xml;utf-8, - , - `) : parsedFrameworkData.IAM.large_image, + large_image: parsedFrameworkData.IAM.large_image === undefined ? parsedDatatypeImages["IAM"] : parsedFrameworkData.IAM.large_image, + label: securityFramework[3].text.toUpperCase(), id: securityFramework[3].text.toUpperCase(), animate: false, @@ -1401,9 +1446,8 @@ const AppFramework = (props) => { margin_y: parsedFrameworkData.Assets.large_image === undefined ? `${19*scale}px` : `0px`, width: parsedFrameworkData.Assets.large_image === undefined ? iconSize : defaultSize, height: parsedFrameworkData.Assets.large_image === undefined ? iconSize : defaultSize, - large_image: parsedFrameworkData.Assets.large_image === undefined ? encodeURI(`data:image/svg+xml;utf-8, - , - `) : parsedFrameworkData.Assets.large_image, + large_image: parsedFrameworkData.Assets.large_image === undefined ? parsedDatatypeImages["ASSETS"] : parsedFrameworkData.Assets.large_image, + label: securityFramework[2].text.toUpperCase(), id: securityFramework[2].text.toUpperCase(), animate: false, @@ -1430,9 +1474,8 @@ const AppFramework = (props) => { margin_y: parsedFrameworkData.Intel.large_image === undefined ? `${19*scale}px` : `0px`, width: parsedFrameworkData.Intel.large_image === undefined ? iconSize : defaultSize, height: parsedFrameworkData.Intel.large_image === undefined ? iconSize : defaultSize, - large_image: parsedFrameworkData.Intel.large_image === undefined ? encodeURI(`data:image/svg+xml;utf-8, - , - `): parsedFrameworkData.Intel.large_image, + large_image: parsedFrameworkData.Intel.large_image === undefined ? parsedDatatypeImages["INTEL"] : parsedFrameworkData.Intel.large_image, + label: securityFramework[4].text.toUpperCase(), id: securityFramework[4].text.toUpperCase(), animate: false, @@ -1459,9 +1502,8 @@ const AppFramework = (props) => { margin_y: parsedFrameworkData.Comms.large_image === undefined ? `${19*scale}px` : `0px`, width: parsedFrameworkData.Comms.large_image === undefined ? iconSize : defaultSize, height: parsedFrameworkData.Comms.large_image === undefined ? iconSize : defaultSize, - large_image: parsedFrameworkData.Comms.large_image === undefined ? encodeURI(`data:image/svg+xml;utf-8, - , - `) : parsedFrameworkData.Comms.large_image, + large_image: parsedFrameworkData.Comms.large_image === undefined ? parsedDatatypeImages["COMMS"] : parsedFrameworkData.Comms.large_image, + label: securityFramework[5].text.toUpperCase(), id: securityFramework[5].text.toUpperCase(), animate: false, @@ -1488,9 +1530,8 @@ const AppFramework = (props) => { margin_y: parsedFrameworkData["EDR & AV"].large_image === undefined ? `${19*scale}px` : `0px`, width: parsedFrameworkData["EDR & AV"].large_image === undefined ? iconSize : defaultSize, height: parsedFrameworkData["EDR & AV"].large_image === undefined ? iconSize : defaultSize, - large_image: parsedFrameworkData["EDR & AV"].large_image === undefined ? encodeURI(`data:image/svg+xml;utf-8, - , - `) : parsedFrameworkData["EDR & AV"].large_image, + large_image: parsedFrameworkData["EDR & AV"].large_image === undefined ? parsedDatatypeImages["EDR & AV"] : parsedFrameworkData["EDR & AV"].large_image, + label: securityFramework[7].text.toUpperCase(), id: securityFramework[7].text.toUpperCase(), animate: false, @@ -1517,9 +1558,7 @@ const AppFramework = (props) => { margin_y: parsedFrameworkData.Network.large_image === undefined ? `${19*scale}px` : `0px`, width: parsedFrameworkData.Network.large_image === undefined ? iconSize : defaultSize, height: parsedFrameworkData.Network.large_image === undefined ? iconSize : defaultSize, - large_image: parsedFrameworkData.Network.large_image === undefined ? encodeURI(`data:image/svg+xml;utf-8, - , - `) : parsedFrameworkData.Network.large_image, + large_image: parsedFrameworkData.Network.large_image === undefined ? parsedDatatypeImages["NETWORK"] : parsedFrameworkData.Network.large_image, label: securityFramework[6].text.toUpperCase(), id: securityFramework[6].text.toUpperCase(), animate: false, @@ -1546,9 +1585,7 @@ const AppFramework = (props) => { margin_y: parsedFrameworkData.SIEM.large_image === undefined ? `${19*scale}px` : `0px`, width: parsedFrameworkData.SIEM.large_image === undefined ? iconSize : defaultSize, height: parsedFrameworkData.SIEM.large_image === undefined ? iconSize : defaultSize, - large_image: parsedFrameworkData.SIEM.large_image === undefined ? encodeURI(`data:image/svg+xml;utf-8, - , - `) : parsedFrameworkData.SIEM.large_image, + large_image: parsedFrameworkData.SIEM.large_image === undefined ? parsedDatatypeImages["SIEM"] : parsedFrameworkData.SIEM.large_image, label: securityFramework[1].text.toUpperCase(), id: securityFramework[1].text.toUpperCase(), animate: false, @@ -1683,8 +1720,8 @@ const AppFramework = (props) => { const UsecaseHandler = (props) => { const { data, index, diff } = props - const leftImage = data.left_image !== undefined ? parsedDatatypeImages[data.left_image] : undefined - const rightImage = data.right_image !== undefined ? parsedDatatypeImages[data.right_image] : undefined + const leftImage = data.left_image !== undefined ? parsedDatatypeImages[data.left_image.toUpperCase()] : undefined + const rightImage = data.right_image !== undefined ? parsedDatatypeImages[data.right_image.toUpperCase()] : undefined if (leftImage === undefined) { console.log("LEFT MISSING: ", leftImage) @@ -1700,7 +1737,6 @@ const AppFramework = (props) => { const parsedLeftImage = const parsedLeftText =
{data.left_text}
- const svgSize = 20 var svgIcon = @@ -1837,6 +1873,16 @@ const AppFramework = (props) => { } ] + const getNodeName = (category) => { + if (category === "email") { + category = "COMMS" + } else if (category === "edr") { + category = "EDR & AV" + } + + return category.toUpperCase() + } + //autounselectify={true} var usecasediff = -100 const bgColor = color === undefined || color === null || color.length === 0 ? theme.palette.surfaceColor : color @@ -1856,6 +1902,94 @@ const AppFramework = (props) => { /> + {injectedApps.map((apps) => { + var categoryTop = 100 + var categoryLeft = 100 + + const category = apps[0].category + if (category === "edr") { + categoryTop = 355 + categoryLeft = 50 + } else if (category === "siem") { + categoryTop = 95 + categoryLeft = 50 + } else if (category === "cases") { + categoryTop = 65 + categoryLeft = 175 + } else if (category === "intel") { + categoryTop = 355 + categoryLeft = 315 + } else if (category === "comms") { + categoryTop = 415 + categoryLeft = 175 + } else if (category === "iam") { + categoryTop = 95 + categoryLeft = 315 + } else { + return null + } + + return ( +
+ {apps.map((app) => { + return ( + } + label={""} + variant="contained" + style={{}} + onClick={() => { + console.log("Add app to framework and remove category: ", app) + app.objectID = app.id + app.type = app.category + app.large_image = app.image_url + + const nodename = getNodeName(app.category) + + + const foundelement = cy.getElementById(nodename) + console.log("FOUND: ", foundelement) + if (foundelement !== undefined && foundelement !== null) { + foundelement.data("large_image", app.image_url) + foundelement.data("margin_x", "0px") + foundelement.data("margin_y", "0px") + foundelement.data("text_margin_y", `${60*scale}px`) + foundelement.data("width", `${85*scale}px`) + foundelement.data("height", `${85*scale}px`) + } + + if (setFrameworkData !== undefined) { + console.log("Setting frameworkdata") + // Find discoveryData.id + var keys = [] + for (const [key, value] of Object.entries(frameworkData)) { + if (key.toLowerCase() === app.category.toLowerCase()) { + keys.push(key) + } + } + + if (keys.length === 0) { + console.log("Failed to find: ", app.category, " IN ", frameworkData) + } else { + console.log("In else for keys: ", frameworkData, keys) + for (var key in keys) { + frameworkData[keys[key]] = app + } + + setFrameworkData(frameworkData) + showRecommendations(app.category, frameworkData) + } + } + + setFrameworkItem(app) + }} + /> + ) + })} +
+ ) + })} + {showOptions === false ? null :
{Object.keys(usecases).map((data, index) => { @@ -1959,7 +2093,8 @@ const AppFramework = (props) => { const foundelement = cy.getElementById(discoveryData.id) if (foundelement !== undefined && foundelement !== null) { console.log("element: ", foundelement) - foundelement.data("large_image", discoveryData.large_image) + console.log("DISC: ", discoveryData) + foundelement.data("large_image", parsedDatatypeImages[discoveryData.id.toUpperCase()]) foundelement.data("text_margin_y", "14px") foundelement.data("margin_x", "32px") foundelement.data("margin_y", "19x") diff --git a/frontend/src/components/SuggestedWorkflows.jsx b/frontend/src/components/SuggestedWorkflows.jsx index eac3dc3e..69349846 100644 --- a/frontend/src/components/SuggestedWorkflows.jsx +++ b/frontend/src/components/SuggestedWorkflows.jsx @@ -83,7 +83,6 @@ const SuggestedWorkflows = (props) => { dstimage = usecase.items[2].app } - console.log(srcimage, dstimage, usecase.items) if (srcimage === undefined || dstimage === undefined) { console.log("Error in src or dst: returning!") return null @@ -148,8 +147,6 @@ const SuggestedWorkflows = (props) => { finishedUsecases.push(usecaseSearch) setFinishedUsecases(finishedUsecases) - - setUsecaseSearch("") setUsecaseSearchType("") }} @@ -161,7 +158,7 @@ const SuggestedWorkflows = (props) => { minWidth: 450, padding: 50, overflow: "hidden", - zIndex: 10012, + zIndex: 10050, border: theme.palette.defaultBorder, }, }} diff --git a/frontend/src/components/UsecaseSearch.jsx b/frontend/src/components/UsecaseSearch.jsx index b71e9257..fb1c7449 100644 --- a/frontend/src/components/UsecaseSearch.jsx +++ b/frontend/src/components/UsecaseSearch.jsx @@ -1163,11 +1163,11 @@ const UsecaseSearch = (props) => { } if (changed) { - alert.error("Errors were found. Click them to sort sort them out or go to the next usecase.") + //alert.error("Errors were found. Click them to sort sort them out or go to the next usecase.") - setUpdate(Math.random()) - setIsUploading(false) - return + //setUpdate(Math.random()) + //setIsUploading(false) + //return } // Auto finding these during deploy diff --git a/frontend/src/components/WelcomeForm2.jsx b/frontend/src/components/WelcomeForm2.jsx index 18d8d1db..5c7a2163 100644 --- a/frontend/src/components/WelcomeForm2.jsx +++ b/frontend/src/components/WelcomeForm2.jsx @@ -615,7 +615,14 @@ const WelcomeForm = (props) => { {/*Find your integrations!*/}
-