Fixed some frontend things for release and orborus is now better by default
This commit is contained in:
@@ -228,15 +228,16 @@ const parseCurl = (s) => {
|
||||
// Basically CRUD for each category + special
|
||||
export const appCategories = [
|
||||
{
|
||||
"name": "Communication",
|
||||
"name": "Communication",
|
||||
"color": "#FFC107",
|
||||
"icon": "communication",
|
||||
"action_labels": ["List Messages", "Send Message", "Get Message", "Search messages", "List Attachments", "Get Attachment", "Get Contact"],
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"name": "SIEM",
|
||||
"color": "#FFC107",
|
||||
"icon": "siem",
|
||||
"action_labels": ["Search", "List Alerts", "Close Alert", "Get Alert", "Create detection", "Add to lookup list",],
|
||||
"action_labels": ["Search", "List Alerts", "Close Alert", "Get Alert", "Create detection", "Add to lookup list", "Isolate endpoint",],
|
||||
}, {
|
||||
"name": "Eradication",
|
||||
"color": "#FFC107",
|
||||
|
||||
@@ -287,6 +287,7 @@ const Apps = (props) => {
|
||||
const [selectedAction, setSelectedAction] = React.useState({});
|
||||
const [searchBackend, setSearchBackend] = React.useState(false);
|
||||
const [searchableApps, setSearchableApps] = React.useState([]);
|
||||
const [publishModalOpen, setPublishModalOpen] = React.useState(false);
|
||||
|
||||
const [openApi, setOpenApi] = React.useState("");
|
||||
const [openApiData, setOpenApiData] = React.useState("");
|
||||
@@ -441,6 +442,7 @@ const Apps = (props) => {
|
||||
if (privateapps.length > 0) {
|
||||
if (selectedApp.id === undefined || selectedApp.id === null) {
|
||||
setSelectedApp(privateapps[0]);
|
||||
setSharingConfiguration(privateapps[0].sharing === true ? "public" : "you")
|
||||
}
|
||||
|
||||
if (
|
||||
@@ -646,6 +648,7 @@ const Apps = (props) => {
|
||||
if (selectedApp.id !== data.id) {
|
||||
data.name = newAppname;
|
||||
setSelectedApp(data);
|
||||
setSharingConfiguration(data.sharing === true ? "public" : "you")
|
||||
|
||||
if (
|
||||
data.actions !== undefined &&
|
||||
@@ -658,7 +661,7 @@ const Apps = (props) => {
|
||||
}
|
||||
|
||||
if (data.sharing) {
|
||||
setSharingConfiguration(isCloud ? "public" : "everyone");
|
||||
setSharingConfiguration("public");
|
||||
}
|
||||
}
|
||||
}}
|
||||
@@ -999,11 +1002,11 @@ const Apps = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
const userRoles = ["you", isCloud ? "public" : "everyone"];
|
||||
const userRoles = ["you", "public"];
|
||||
|
||||
// Admin in org or creator of app
|
||||
// FIXME: Missing check for if same creator account
|
||||
const canEditApp = userdata !== undefined && (userdata.admin === "true" || userdata.id === selectedApp.owner || selectedApp.owner === "" || (userdata.admin === "true" && userdata.active_org.id === selectedApp.reference_org)) || !selectedApp.generated
|
||||
// Admin in org or creator of app
|
||||
// FIXME: Missing check for if same creator account
|
||||
const canEditApp = userdata !== undefined && (userdata.admin === "true" || userdata.id === selectedApp.owner || selectedApp.owner === "" || (userdata.admin === "true" && userdata.active_org.id === selectedApp.reference_org)) || !selectedApp.generated
|
||||
|
||||
//fetch(globalUrl+"/api/v1/get_openapi/"+urlParams.get("id"),
|
||||
var baseInfo =
|
||||
@@ -1054,6 +1057,7 @@ const Apps = (props) => {
|
||||
console.log("New version: ", newversion);
|
||||
selectedApp.app_version = selectedApp.app_version;
|
||||
setSelectedApp(selectedApp);
|
||||
setSharingConfiguration(selectedApp.sharing === true ? "public" : "you")
|
||||
|
||||
if (newversion !== undefined && newversion !== null) {
|
||||
getApp(newversion.id, true);
|
||||
@@ -1156,17 +1160,22 @@ const Apps = (props) => {
|
||||
<Select
|
||||
value={sharingConfiguration}
|
||||
onChange={(event) => {
|
||||
toast("Changing sharing to " + event.target.value);
|
||||
|
||||
setSharingConfiguration(event.target.value);
|
||||
|
||||
if (event.target.value === "you") {
|
||||
toast("Changing sharing to " + event.target.value);
|
||||
updateAppField(selectedApp.id, "sharing", false);
|
||||
} else if (
|
||||
event.target.value === "everyone" ||
|
||||
event.target.value === "public"
|
||||
) {
|
||||
updateAppField(selectedApp.id, "sharing", true);
|
||||
|
||||
if (!isCloud) {
|
||||
setPublishModalOpen(true)
|
||||
} else {
|
||||
updateAppField(selectedApp.id, "sharing", true);
|
||||
}
|
||||
} else {
|
||||
console.log(
|
||||
"Can't handle value for sharing: ",
|
||||
@@ -2247,6 +2256,7 @@ const Apps = (props) => {
|
||||
setSelectedAction({});
|
||||
}
|
||||
setSelectedApp(responseJson);
|
||||
setSharingConfiguration(responseJson.sharing === true ? "public" : "you")
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
@@ -2282,6 +2292,7 @@ const Apps = (props) => {
|
||||
const data = {};
|
||||
data[fieldname] = fieldvalue;
|
||||
|
||||
|
||||
console.log("DATA: ", data);
|
||||
|
||||
fetch(globalUrl + "/api/v1/apps/" + app_id, {
|
||||
@@ -2305,8 +2316,8 @@ const Apps = (props) => {
|
||||
if (responseJson.reason !== undefined && responseJson.reason !== null) {
|
||||
toast("Error: "+responseJson.reason);
|
||||
} else {
|
||||
toast("Error updating app configuration");
|
||||
}
|
||||
toast("Error updating app configuration. Are you the owner of this app?");
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
@@ -2507,6 +2518,61 @@ const Apps = (props) => {
|
||||
setLoadAppsModalOpen(false);
|
||||
};
|
||||
|
||||
const publishModal = publishModalOpen ? (
|
||||
<Dialog
|
||||
open={publishModalOpen}
|
||||
onClose={() => {
|
||||
setPublishModalOpen(false);
|
||||
}}
|
||||
PaperProps={{
|
||||
style: {
|
||||
backgroundColor: theme.palette.surfaceColor,
|
||||
color: "white",
|
||||
minWidth: 500,
|
||||
padding: 50,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<DialogTitle style={{ marginBottom: 0 }}>
|
||||
<div style={{ textAlign: "center", color: "rgba(255,255,255,0.9)" }}>
|
||||
Are you sure you want to PUBLISH this app?
|
||||
</div>
|
||||
</DialogTitle>
|
||||
<DialogContent
|
||||
style={{ color: "rgba(255,255,255,0.65)", textAlign: "center" }}
|
||||
>
|
||||
<div>
|
||||
<Typography variant="body1" style={{ marginBottom: 20 }}>
|
||||
Before publishing, make sure to sanitize the App for anything you don't want public.
|
||||
</Typography>
|
||||
<Typography variant="body1" style={{ marginBottom: 20 }}>
|
||||
The published App is yours, and you can always change your public Apps after they are released.
|
||||
</Typography>
|
||||
</div>
|
||||
<Button
|
||||
variant="contained"
|
||||
style={{}}
|
||||
onClick={() => {
|
||||
updateAppField(selectedApp.id, "sharing", true);
|
||||
setPublishModalOpen(false);
|
||||
}}
|
||||
color="primary"
|
||||
>
|
||||
Yes
|
||||
</Button>
|
||||
<Button
|
||||
style={{}}
|
||||
onClick={() => {
|
||||
setPublishModalOpen(false);
|
||||
}}
|
||||
color="primary"
|
||||
>
|
||||
No
|
||||
</Button>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
) : null;
|
||||
|
||||
const deleteModal = deleteModalOpen ? (
|
||||
<Dialog
|
||||
open={deleteModalOpen}
|
||||
@@ -2937,6 +3003,7 @@ const Apps = (props) => {
|
||||
<div>
|
||||
{appView}
|
||||
{modalView}
|
||||
{publishModal}
|
||||
{generateAppView}
|
||||
{appsModalLoad}
|
||||
{deleteModal}
|
||||
|
||||
@@ -12,6 +12,7 @@ import WorkflowTemplatePopup from "../components/WorkflowTemplatePopup.jsx";
|
||||
//import { Line, Bar } from "react-chartjs-2";
|
||||
//import { useAlert
|
||||
import { ToastContainer, toast } from "react-toastify"
|
||||
import { parsedDatatypeImages } from "../components/AppFramework.jsx"
|
||||
|
||||
import {
|
||||
Autocomplete,
|
||||
@@ -159,12 +160,165 @@ const UsecaseListComponent = ({userdata, keys, isCloud, globalUrl, frameworkData
|
||||
return null
|
||||
}
|
||||
|
||||
const parseUsecase = (parsedUsecase, subcase) => {
|
||||
console.log("parseUsecase: ", parsedUsecase, subcase)
|
||||
const findSpecificApp = (framework, inputcategory) => {
|
||||
// Get the frameworkinfo for the org and fill in
|
||||
//
|
||||
if (framework === undefined || framework === null) {
|
||||
console.log("findSpecificApp: frameworkData is null")
|
||||
return null
|
||||
}
|
||||
|
||||
if (inputcategory === undefined || inputcategory === null) {
|
||||
console.log("findSpecificApp: category is null")
|
||||
return null
|
||||
}
|
||||
|
||||
const category = inputcategory.toLowerCase()
|
||||
|
||||
console.log("findSpecificApp: ", category, frameworkData)
|
||||
if (category === "edr" || category === "eradication" || category === "edr & av") {
|
||||
if (frameworkData["EDR & AV"] !== undefined && frameworkData["EDR & AV"].name !== undefined) {
|
||||
return frameworkData["EDR & AV"]
|
||||
}
|
||||
|
||||
return {
|
||||
name: "EDR :default",
|
||||
large_image: parsedDatatypeImages["EDR & AV"],
|
||||
count: 0,
|
||||
description: "",
|
||||
id: "",
|
||||
}
|
||||
} else if (category === "communication") {
|
||||
if (frameworkData["Comms"] !== undefined && frameworkData["Comms"].name !== undefined) {
|
||||
return frameworkData["Comms"]
|
||||
}
|
||||
|
||||
return {
|
||||
name: "COMMS :default",
|
||||
large_image: parsedDatatypeImages["COMMS"],
|
||||
count: 0,
|
||||
description: "",
|
||||
id: "",
|
||||
}
|
||||
} else if (category === "email") {
|
||||
if (frameworkData["Email"] !== undefined && frameworkData["Email"].name !== undefined) {
|
||||
return frameworkData["Email"]
|
||||
}
|
||||
|
||||
return {
|
||||
name: "COMMS :default",
|
||||
large_image: parsedDatatypeImages["COMMS"],
|
||||
count: 0,
|
||||
description: "",
|
||||
id: "",
|
||||
}
|
||||
} else if (category === "assets") {
|
||||
if (frameworkData["Assets"] !== undefined && frameworkData["Assets"].name !== undefined) {
|
||||
return frameworkData["Assets"]
|
||||
}
|
||||
|
||||
return {
|
||||
name: "ASSETS :default",
|
||||
large_image: parsedDatatypeImages["ASSETS"],
|
||||
count: 0,
|
||||
description: "",
|
||||
id: "",
|
||||
}
|
||||
} else if (category === "cases") {
|
||||
if (frameworkData["Cases"] !== undefined && frameworkData["Cases"].name !== undefined) {
|
||||
return frameworkData["Cases"]
|
||||
}
|
||||
|
||||
return {
|
||||
name: "CASES :default",
|
||||
large_image: parsedDatatypeImages["CASES"],
|
||||
count: 0,
|
||||
description: "",
|
||||
id: "",
|
||||
}
|
||||
} else if (category === "iam") {
|
||||
if (frameworkData["IAM"] !== undefined && frameworkData["IAM"].name !== undefined) {
|
||||
return frameworkData["IAM"]
|
||||
}
|
||||
|
||||
return {
|
||||
name: "EDR :default",
|
||||
large_image: parsedDatatypeImages["EDR & AV"],
|
||||
count: 0,
|
||||
description: "",
|
||||
id: "",
|
||||
}
|
||||
} else if (category === "network") {
|
||||
if (frameworkData["Network"] !== undefined && frameworkData["Network"].name !== undefined) {
|
||||
return frameworkData["Network"]
|
||||
}
|
||||
|
||||
return {
|
||||
name: "Network :default",
|
||||
large_image: parsedDatatypeImages["NETWORK"],
|
||||
count: 0,
|
||||
description: "",
|
||||
id: "",
|
||||
}
|
||||
} else if (category === "intel") {
|
||||
if (frameworkData["Intel"] !== undefined && frameworkData["Intel"].name !== undefined) {
|
||||
return frameworkData["Intel"]
|
||||
}
|
||||
|
||||
return {
|
||||
name: "INTEL :default",
|
||||
large_image: parsedDatatypeImages["INTEL"],
|
||||
count: 0,
|
||||
description: "",
|
||||
id: "",
|
||||
}
|
||||
} else if (category === "siem") {
|
||||
if (frameworkData["SIEM"] !== undefined && frameworkData["SIEM"].name !== undefined) {
|
||||
return frameworkData["SIEM"]
|
||||
}
|
||||
|
||||
return {
|
||||
name: "SIEM :default",
|
||||
large_image: parsedDatatypeImages["SIEM"],
|
||||
count: 0,
|
||||
description: "",
|
||||
id: "",
|
||||
}
|
||||
} else {
|
||||
console.log("findSpecificApp: unknown category: ", category)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
const parseUsecase = (subcase) => {
|
||||
console.log("parseUsecase: ", subcase)
|
||||
const srcdata = findSpecificApp(frameworkData, subcase.type)
|
||||
const dstdata = findSpecificApp(frameworkData, subcase.last)
|
||||
|
||||
console.log("srcdata: ", srcdata)
|
||||
console.log("dstdata: ", dstdata)
|
||||
|
||||
if (srcdata !== undefined && srcdata !== null) {
|
||||
subcase.srcimg = srcdata.large_image
|
||||
subcase.srcapp = srcdata.name
|
||||
}
|
||||
|
||||
if (dstdata !== undefined && dstdata !== null) {
|
||||
subcase.dstimg = dstdata.large_image
|
||||
subcase.dstapp = dstdata.name
|
||||
}
|
||||
|
||||
return subcase
|
||||
}
|
||||
|
||||
const getUsecase = (subcase, index, subindex) => {
|
||||
console.log(subcase)
|
||||
subcase = parseUsecase(subcase)
|
||||
|
||||
// Timeout 50ms to delay it slightly
|
||||
setTimeout(() => {
|
||||
setInputUsecase(subcase)
|
||||
}, 50)
|
||||
|
||||
fetch(`${globalUrl}/api/v1/workflows/usecases/${escape(subcase.name.replaceAll(" ", "_"))}`, {
|
||||
method: "GET",
|
||||
@@ -174,62 +328,68 @@ const UsecaseListComponent = ({userdata, keys, isCloud, globalUrl, frameworkData
|
||||
},
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.status !== 200) {
|
||||
console.log("Status not 200 for framework!");
|
||||
.then((response) => {
|
||||
if (response.status !== 200) {
|
||||
console.log("Status not 200 for framework!");
|
||||
}
|
||||
|
||||
return response.json();
|
||||
})
|
||||
.then((responseJson) => {
|
||||
console.log("In responseJson for usecase: ", responseJson)
|
||||
var parsedUsecase = responseJson
|
||||
|
||||
if (responseJson.success === false) {
|
||||
|
||||
//img1={inputUsecase.srcimg}
|
||||
//srcapp={inputUsecase.srcapp}
|
||||
//img2={inputUsecase.dstimg}
|
||||
//dstapp={inputUsecase.dstapp}
|
||||
//title={inputUsecase.name}
|
||||
parsedUsecase = subcase
|
||||
} else {
|
||||
parsedUsecase = responseJson
|
||||
|
||||
parsedUsecase.srcimg = subcase.srcimg
|
||||
parsedUsecase.srcapp = subcase.srcapp
|
||||
parsedUsecase.dstimg = subcase.dstimg
|
||||
parsedUsecase.dstapp = subcase.dstapp
|
||||
|
||||
//parsedUsecase = parseUsecase(responseJson)
|
||||
}
|
||||
|
||||
// Look for the type of app and fill in img1, srcapp...
|
||||
console.log("USECASE: ", parsedUsecase)
|
||||
|
||||
setInputUsecase(parsedUsecase)
|
||||
setExpandedIndex(index)
|
||||
setExpandedItem(subindex)
|
||||
|
||||
setTimeout(() => {
|
||||
//console.log("Scroll!")
|
||||
const found = document.getElementById("selected_box");
|
||||
if (found !== undefined && found !== null) {
|
||||
//console.log("FOUND!!")
|
||||
found.scrollTo({
|
||||
top: 100,
|
||||
behavior: "smooth",
|
||||
})
|
||||
}
|
||||
|
||||
return response.json();
|
||||
})
|
||||
.then((responseJson) => {
|
||||
var parsedUsecase = responseJson
|
||||
if (responseJson.success === false) {
|
||||
parsedUsecase = subcase
|
||||
|
||||
//img1={inputUsecase.srcimg}
|
||||
//srcapp={inputUsecase.srcapp}
|
||||
//img2={inputUsecase.dstimg}
|
||||
//dstapp={inputUsecase.dstapp}
|
||||
//title={inputUsecase.name}
|
||||
parsedUsecase = parseUsecase(parsedUsecase, subcase)
|
||||
} else {
|
||||
parsedUsecase = responseJson
|
||||
|
||||
parsedUsecase = parseUsecase(parsedUsecase, responseJson)
|
||||
}
|
||||
|
||||
// Look for the type of app and fill in img1, srcapp...
|
||||
|
||||
|
||||
setInputUsecase(parsedUsecase)
|
||||
setExpandedIndex(index)
|
||||
setExpandedItem(subindex)
|
||||
|
||||
setTimeout(() => {
|
||||
//console.log("Scroll!")
|
||||
const found = document.getElementById("selected_box");
|
||||
if (found !== undefined && found !== null) {
|
||||
//console.log("FOUND!!")
|
||||
found.scrollTo({
|
||||
top: 100,
|
||||
behavior: "smooth",
|
||||
})
|
||||
}
|
||||
|
||||
setFirstLoad(true)
|
||||
setSelectedWorkflows([])
|
||||
}, 100);
|
||||
})
|
||||
.catch((error) => {
|
||||
//toast(error.toString());
|
||||
setInputUsecase({})
|
||||
setExpandedIndex(index)
|
||||
setExpandedItem(subindex)
|
||||
|
||||
setFirstLoad(true)
|
||||
setSelectedWorkflows([])
|
||||
})
|
||||
}
|
||||
}, 100);
|
||||
})
|
||||
.catch((error) => {
|
||||
//toast(error.toString());
|
||||
setInputUsecase({})
|
||||
setExpandedIndex(index)
|
||||
setExpandedItem(subindex)
|
||||
|
||||
setFirstLoad(true)
|
||||
setSelectedWorkflows([])
|
||||
})
|
||||
}
|
||||
|
||||
const setUsecaseItem = (inputUsecase) => {
|
||||
var parsedUsecase = inputUsecase
|
||||
@@ -290,7 +450,7 @@ const UsecaseListComponent = ({userdata, keys, isCloud, globalUrl, frameworkData
|
||||
//toast(error.toString());
|
||||
//setFrameworkLoaded(true)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const setWorkflow = (workflowdata) => {
|
||||
const new_url = `${globalUrl}/api/v1/workflows/${workflowdata.id}`
|
||||
@@ -845,7 +1005,7 @@ const UsecaseListComponent = ({userdata, keys, isCloud, globalUrl, frameworkData
|
||||
: null}
|
||||
<span style={{top: 30, position: "relative",}}>
|
||||
<Typography variant="body1" style={{marginTop: 0,}} onClick={() => {}}>
|
||||
Try it out
|
||||
Try this Usecase
|
||||
</Typography>
|
||||
<WorkflowTemplatePopup
|
||||
userdata={userdata}
|
||||
|
||||
@@ -3419,8 +3419,8 @@ const Workflows = (props) => {
|
||||
>
|
||||
<img
|
||||
style={{
|
||||
height: imgSize,
|
||||
width: imgSize,
|
||||
height: imgSize+4,
|
||||
width: imgSize+4,
|
||||
position: "absolute",
|
||||
top: -2,
|
||||
left: -2,
|
||||
|
||||
Reference in New Issue
Block a user