Fixed some frontend things for release and orborus is now better by default

This commit is contained in:
Frikky
2023-10-18 14:58:36 +02:00
parent 595c217a7c
commit 614e39da70
11 changed files with 378 additions and 199 deletions
+1 -1
View File
@@ -3519,7 +3519,7 @@ class AppBase:
if self.action["app_name"].lower() == "shuffle tools":
timeout = 55
timeout = 30
#timeout = 30
try:
executor = concurrent.futures.ThreadPoolExecutor()
+6 -97
View File
@@ -86,59 +86,6 @@ var runningEnvironment = "onprem"
var syncUrl = "https://shuffler.io"
var dbclient *datastore.Client
type Userapi struct {
Username string `datastore:"username"`
ApiKey string `datastore:"apikey"`
}
type ExecutionInfo struct {
TotalApiUsage int64 `json:"total_api_usage" datastore:"total_api_usage"`
TotalWorkflowExecutions int64 `json:"total_workflow_executions" datastore:"total_workflow_executions"`
TotalAppExecutions int64 `json:"total_app_executions" datastore:"total_app_executions"`
TotalCloudExecutions int64 `json:"total_cloud_executions" datastore:"total_cloud_executions"`
TotalOnpremExecutions int64 `json:"total_onprem_executions" datastore:"total_onprem_executions"`
DailyApiUsage int64 `json:"daily_api_usage" datastore:"daily_api_usage"`
DailyWorkflowExecutions int64 `json:"daily_workflow_executions" datastore:"daily_workflow_executions"`
DailyAppExecutions int64 `json:"daily_app_executions" datastore:"daily_app_executions"`
DailyCloudExecutions int64 `json:"daily_cloud_executions" datastore:"daily_cloud_executions"`
DailyOnpremExecutions int64 `json:"daily_onprem_executions" datastore:"daily_onprem_executions"`
}
// "Execution by status"
// Execution history
//type GlobalStatistics struct {
// BackendExecutions int64 `json:"backend_executions" datastore:"backend_executions"`
// WorkflowCount int64 `json:"workflow_count" datastore:"workflow_count"`
// ExecutionCount int64 `json:"execution_count" datastore:"execution_count"`
// ExecutionSuccessCount int64 `json:"execution_success_count" datastore:"execution_success_count"`
// ExecutionAbortCount int64 `json:"execution_abort_count" datastore:"execution_abort_count"`
// ExecutionFailureCount int64 `json:"execution_failure_count" datastore:"execution_failure_count"`
// ExecutionPendingCount int64 `json:"execution_pending_count" datastore:"execution_pending_count"`
// AppUsageCount int64 `json:"app_usage_count" datastore:"app_usage_count"`
// TotalAppsCount int64 `json:"total_apps_count" datastore:"total_apps_count"`
// SelfMadeAppCount int64 `json:"self_made_app_count" datastore:"self_made_app_count"`
// WebhookUsageCount int64 `json:"webhook_usage_count" datastore:"webhook_usage_count"`
// Baseline map[string]int64 `json:"baseline" datastore:"baseline"`
//}
type ParsedOpenApi struct {
Body string `datastore:"body,noindex" json:"body"`
ID string `datastore:"id" json:"id"`
Success bool `datastore:"success,omitempty" json:"success,omitempty"`
}
// Limits set for a user so that they can't do a shitload
type UserLimits struct {
DailyApiUsage int64 `json:"daily_api_usage" datastore:"daily_api_usage"`
DailyWorkflowExecutions int64 `json:"daily_workflow_executions" datastore:"daily_workflow_executions"`
DailyCloudExecutions int64 `json:"daily_cloud_executions" datastore:"daily_cloud_executions"`
DailyTriggers int64 `json:"daily_triggers" datastore:"daily_triggers"`
DailyMailUsage int64 `json:"daily_mail_usage" datastore:"daily_mail_usage"`
MaxTriggers int64 `json:"max_triggers" datastore:"max_triggers"`
MaxWorkflows int64 `json:"max_workflows" datastore:"max_workflows"`
}
type retStruct struct {
Success bool `json:"success"`
SyncFeatures shuffle.SyncFeatures `json:"sync_features"`
@@ -147,43 +94,6 @@ type retStruct struct {
Reason string `json:"reason"`
}
// Saves some data, not sure what to have here lol
type UserAuth struct {
Description string `json:"description" datastore:"description,noindex" yaml:"description"`
Name string `json:"name" datastore:"name" yaml:"name"`
Workflows []string `json:"workflows" datastore:"workflows"`
Username string `json:"username" datastore:"username"`
Fields []UserAuthField `json:"fields" datastore:"fields"`
}
type UserAuthField struct {
Key string `json:"key" datastore:"key"`
Value string `json:"value" datastore:"value,noindex"`
}
// Not environment, but execution environment
//type Environment struct {
// Name string `datastore:"name"`
// Type string `datastore:"type"`
// Registered bool `datastore:"registered"`
// Default bool `datastore:"default" json:"default"`
// Archived bool `datastore:"archived" json:"archived"`
// Id string `datastore:"id" json:"id"`
// OrgId string `datastore:"org_id" json:"org_id"`
//}
// timeout maybe? idk
type session struct {
Username string `datastore:"Username,noindex"`
Id string `datastore:"Id,noindex"`
Session string `datastore:"session,noindex"`
}
type loginStruct struct {
Username string `json:"username"`
Password string `json:"password"`
}
type Contact struct {
Firstname string `json:"firstname"`
Lastname string `json:"lastname"`
@@ -3825,7 +3735,7 @@ func remoteOrgJobHandler(org shuffle.Org, interval int) error {
//log.Printf("Remote Data: %s", respBody)
err = remoteOrgJobController(org, respBody)
if err != nil {
log.Printf("[ERROR] Failed job controller run for %s: %s", respBody, err)
//log.Printf("[ERROR] Failed cloud sync job controller run for '%s': %s", respBody, err)
return err
}
return nil
@@ -3869,7 +3779,7 @@ func runInitEs(ctx context.Context) {
activeOrgs, err := shuffle.GetAllOrgs(ctx)
setUsers := false
//log.Printf("ORGS: %d", len(activeOrgs))
_ = setUsers
if err != nil {
if fmt.Sprintf("%s", err) == "EOF" {
time.Sleep(7 * time.Second)
@@ -3924,7 +3834,7 @@ func runInitEs(ctx context.Context) {
if len(activeOrgs) == 1 {
if len(activeOrgs[0].Users) == 0 {
log.Printf("ORG doesn't have any users??")
log.Printf("[ERROR] Main Org doesn't have any user. Creating.")
users, err := shuffle.GetAllUsers(ctx)
if err != nil && len(users) == 0 {
@@ -3957,10 +3867,9 @@ func runInitEs(ctx context.Context) {
if strings.Contains(os.Getenv("SHUFFLE_OPENSEARCH_URL"), "https") {
log.Printf("[INFO] Waiting during init to make sure the opensearch instance is up and running with security features properly")
time.Sleep(30 * time.Second)
time.Sleep(15 * time.Second)
}
_ = setUsers
schedules, err := shuffle.GetAllSchedules(ctx, "ALL")
if err != nil {
log.Printf("[WARNING] Failed getting schedules during service init: %s", err)
@@ -4104,11 +4013,11 @@ func runInitEs(ctx context.Context) {
continue
}
log.Printf("[DEBUG] Should start schedule for org %s (%s)", org.Name, org.Id)
log.Printf("[DEBUG] Should start cloud schedule for org %s (%s)", org.Name, org.Id)
job := func() {
err := remoteOrgJobHandler(org, interval)
if err != nil {
log.Printf("[ERROR] Failed request with remote org setup (2): %s", err)
log.Printf("[ERROR] Failed request with remote org setup for org %s (2): %s", org.Id, err)
}
}
+5 -5
View File
@@ -1692,6 +1692,8 @@ func handleExecution(id string, workflow shuffle.Workflow, request *http.Request
return shuffle.WorkflowExecution{}, "Cloud not implemented yet", errors.New("Cloud not implemented yet")
}
shuffle.IncrementCache(ctx, workflowExecution.OrgId, "workflow_executions_cloud")
// What it needs to know:
// 1. Parameters
if len(workflowExecution.Workflow.Actions) == 1 {
@@ -1705,13 +1707,11 @@ func handleExecution(id string, workflow shuffle.Workflow, request *http.Request
// If worker, should this backend be a proxy? I think so.
return shuffle.WorkflowExecution{}, "Cloud not implemented yet (2)", errors.New("Cloud not implemented yet")
}
} else {
shuffle.IncrementCache(ctx, workflowExecution.OrgId, "workflow_executions_onprem")
}
//err = increaseStatisticsField(ctx, "workflow_executions", workflow.ID, 1, workflowExecution.ExecutionOrg)
//if err != nil {
// log.Printf("Failed to increase stats execution stats: %s", err)
//}
shuffle.IncrementCache(ctx, workflowExecution.OrgId, "workflow_executions")
return workflowExecution, "", nil
}
+3 -2
View File
@@ -1,7 +1,7 @@
version: '3'
services:
frontend:
image: ghcr.io/shuffle/shuffle-frontend:latest
image: ghcr.io/shuffle/shuffle-frontend:nightly
container_name: shuffle-frontend
hostname: shuffle-frontend
ports:
@@ -61,8 +61,9 @@ services:
hostname: shuffle-opensearch
container_name: shuffle-opensearch
environment:
- bootstrap.memory_lock=true
- "OPENSEARCH_JAVA_OPTS=-Xms2048m -Xmx2048m" # minimum and maximum Java heap size, recommend setting both to 50% of system RAM
- bootstrap.memory_lock=true
- DISABLE_PERFORMANCE_ANALYZER_AGENT_CLI=true
- cluster.initial_master_nodes=shuffle-opensearch
- cluster.routing.allocation.disk.threshold_enabled=false
- cluster.name=shuffle-cluster
+5 -5
View File
@@ -38,7 +38,7 @@ import { toast } from 'react-toastify';
cytoscape.use(edgehandles);
const svgSize = "40px"
const parsedDatatypeImages = {
export const parsedDatatypeImages = {
"SIEM": encodeURI(`data:image/svg+xml;utf-8,<svg fill="rgb(248,90,62)" width="${svgSize}" height="${svgSize}" viewBox="0 0 ${svgSize} ${svgSize}" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M6.93767 0C8.71083 0 10.4114 0.704386 11.6652 1.9582C12.919 3.21202 13.6234 4.91255 13.6234 6.68571C13.6234 8.34171 13.0165 9.864 12.0188 11.0366L12.2965 11.3143H13.1091L18.252 16.4571L16.7091 18L11.5662 12.8571V12.0446L11.2885 11.7669C10.116 12.7646 8.59367 13.3714 6.93767 13.3714C5.16451 13.3714 3.46397 12.667 2.21015 11.4132C0.956339 10.1594 0.251953 8.45888 0.251953 6.68571C0.251953 4.91255 0.956339 3.21202 2.21015 1.9582C3.46397 0.704386 5.16451 0 6.93767 0ZM6.93767 2.05714C4.36624 2.05714 2.3091 4.11429 2.3091 6.68571C2.3091 9.25714 4.36624 11.3143 6.93767 11.3143C9.5091 11.3143 11.5662 9.25714 11.5662 6.68571C11.5662 4.11429 9.5091 2.05714 6.93767 2.05714Z" /></svg>`),
"CASES": encodeURI(`data:image/svg+xml;utf-8,<svg fill="rgb(248,90,62)" width="${svgSize}" height="${svgSize}" viewBox="0 0 ${svgSize} ${svgSize}" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M15.6408 8.39233H18.0922V10.0287H15.6408V8.39233ZM0.115234 8.39233H2.56663V10.0287H0.115234V8.39233ZM9.92083 0.21051V2.66506H8.28656V0.21051H9.92083ZM3.31839 2.25596L5.05889 4.00687L3.89856 5.16051L2.15807 3.42596L3.31839 2.25596ZM13.1485 3.99869L14.8808 2.25596L16.0493 3.42596L14.3088 5.16051L13.1485 3.99869ZM9.10369 4.30142C10.404 4.30142 11.651 4.81863 12.5705 5.73926C13.4899 6.65989 14.0065 7.90854 14.0065 9.21051C14.0065 11.0269 13.0178 12.6141 11.5551 13.4651V14.9378C11.5551 15.1548 11.469 15.3629 11.3158 15.5163C11.1625 15.6698 10.9547 15.756 10.738 15.756H7.46943C7.25271 15.756 7.04487 15.6698 6.89163 15.5163C6.73839 15.3629 6.6523 15.1548 6.6523 14.9378V13.4651C5.18963 12.6141 4.2009 11.0269 4.2009 9.21051C4.2009 7.90854 4.71744 6.65989 5.63689 5.73926C6.55635 4.81863 7.80339 4.30142 9.10369 4.30142ZM10.738 16.5741V17.3923C10.738 17.6093 10.6519 17.8174 10.4986 17.9709C10.3454 18.1243 10.1375 18.2105 9.92083 18.2105H8.28656C8.06984 18.2105 7.862 18.1243 7.70876 17.9709C7.55552 17.8174 7.46943 17.6093 7.46943 17.3923V16.5741H10.738ZM8.28656 14.1196H9.92083V12.3769C11.3345 12.0169 12.3722 10.7323 12.3722 9.21051C12.3722 8.34253 12.0279 7.5101 11.4149 6.89634C10.8019 6.28259 9.97056 5.93778 9.10369 5.93778C8.23683 5.93778 7.40546 6.28259 6.79249 6.89634C6.17953 7.5101 5.83516 8.34253 5.83516 9.21051C5.83516 10.7323 6.87292 12.0169 8.28656 12.3769V14.1196Z" /></svg>`),
@@ -713,7 +713,7 @@ const AppFramework = (props) => {
}
useEffect(() => {
console.log("DISCWRAP CHANG: ", discoveryWrapper)
//console.log("DISCWRAP CHANG: ", discoveryWrapper)
if (discoveryWrapper === undefined || discoveryWrapper.id === "SHUFFLE" || discoveryWrapper.id === undefined || cy === undefined) {
setDiscoveryData({})
@@ -874,7 +874,7 @@ const AppFramework = (props) => {
}, [])
useEffect(() => {
console.log("New selected app: ", newSelectedApp, discoveryData)
//console.log("New selected app: ", newSelectedApp, discoveryData)
if (newSelectedApp.objectID === undefined || newSelectedApp.objectID === undefined || newSelectedApp.objectID.length === 0) {
return
}
@@ -2065,8 +2065,8 @@ const AppFramework = (props) => {
const foundelement = cy.getElementById(discoveryData.id)
if (foundelement !== undefined && foundelement !== null) {
console.log("element: ", foundelement)
console.log("DISC: ", discoveryData)
//console.log("element: ", foundelement)
//console.log("DISC: ", discoveryData)
foundelement.data("large_image", parsedDatatypeImages[discoveryData.id.toUpperCase()])
foundelement.data("text_margin_y", "14px")
foundelement.data("margin_x", "32px")
@@ -12,6 +12,7 @@ import {
Drawer,
CircularProgress,
IconButton,
Tooltip,
} from "@mui/material";
import {
@@ -34,12 +35,38 @@ const WorkflowTemplatePopup = (props) => {
const [workflow, setWorkflow] = useState({});
const [appAuthentication, setAppAuthentication] = React.useState(undefined);
const imagestyleWrapper = {
height: 40,
width: 40,
borderRadius: 40,
border: "1px solid rgba(255,255,255,0.3)",
overflow: "hidden",
display: "flex",
}
const imagestyleWrapperDefault = {
height: 40,
width: 40,
borderRadius: 40,
border: "1px solid red",
overflow: "hidden",
display: "flex",
}
const imagestyle = {
height: 40,
width: 40,
borderRadius: 40,
border: "1px solid rgba(255,255,255,0.3)",
overflow: "hidden",
}
const imagestyleDefault = {
display: "block",
marginLeft: 9,
marginTop: 10,
}
if (title === undefined || title === null || title === "") {
console.log("No title for workflow template popup!");
return null
@@ -297,7 +324,10 @@ const WorkflowTemplatePopup = (props) => {
parsedTitle = title.substring(0, maxlength) + "..."
}
parsedTitle.replaceAll("_", " ")
parsedTitle = parsedTitle.replaceAll("_", " ")
const parsedDescription = description !== undefined && description !== null ? description.replaceAll("_", " ") : ""
return (
<div style={{ display: "flex", maxWidth: 470, minWidth: 470, height: 78, borderRadius: 8 }}>
@@ -334,7 +364,7 @@ const WorkflowTemplatePopup = (props) => {
if (errorMessage !== "") {
toast("Already failed to generate workflow for these apps. Please try again later or contact support@shuffler.io.")
} else if (isActive) {
toast("Workflow already generated. Please try another template, or continue to the next page.")
toast("Workflow already generated. Please try another workflow template!")
// FIXME: Remove these?
loadAppAuth()
@@ -350,22 +380,32 @@ const WorkflowTemplatePopup = (props) => {
>
<div style={{ display: "flex", itemAlign: "left", textAlign: "left", }}>
<div style={{display: "flex", flex: 1, marginTop: 3, }}>
<img src={img1} style={imagestyle} />
{img2 !== "" ?
<span style={{display: "flex", }}>
<TrendingFlatIcon style={{ marginTop: 7 }} />
<img src={img2} style={imagestyle} />
</span>
{img1 !== undefined && img1 !== "" && srcapp !== undefined && srcapp !== "" ?
<Tooltip title={srcapp.replaceAll(":default", "").replaceAll("_", " ").replaceAll(" API", "")} placement="top">
<span style={srcapp !== undefined && srcapp.includes(":default") ? imagestyleWrapperDefault : imagestyleWrapper}>
<img src={img1} style={srcapp !== undefined && srcapp.includes(":default") ? imagestyleDefault : imagestyle} />
</span>
</Tooltip>
:
<span style={{width: 50, }} />
}
{img2 !== undefined && img2 !== "" && dstapp !== undefined && dstapp !== "" ?
<Tooltip title={dstapp.replaceAll(":default", "").replaceAll("_", " ").replaceAll(" API", "")} placement="top">
<span style={{display: "flex", }}>
<TrendingFlatIcon style={{ marginTop: 7, }} />
<img src={img2} style={srcapp !== undefined && srcapp.includes(":default") ? imagestyleDefault : imagestyleWrapper} />
</span>
</Tooltip>
:
<span style={{width: 50, }} />
}
</div>
<div style={{ flex: 3, marginLeft: 20, }}>
<Typography variant="body1" style={{ marginTop: description.length === 0 ? 10 : 0, }} color="rgba(241, 241, 241, 1)">
<Typography variant="body1" style={{ marginTop: parsedDescription.length === 0 ? 10 : 0, }} color="rgba(241, 241, 241, 1)">
{parsedTitle}
</Typography>
<Typography variant="body2" color="textSecondary" style={{ marginTop: 0, marginRight: 0, maxHeight: 16, overflow: "hidden",}} color="rgba(158, 158, 158, 1)">
{description}
{parsedDescription}
</Typography>
</div>
</div>
+4 -3
View File
@@ -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",
+76 -9
View File
@@ -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}
+217 -57
View File
@@ -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}
+2 -2
View File
@@ -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,
+9 -8
View File
@@ -45,7 +45,10 @@ import (
// Starts jobs in bulk, so this could be increased
var sleepTime = 3
var maxConcurrency = 15
// Making it work on low-end machines even during busy times :)
// May cause some things to run slowly
var maxConcurrency = 2
// Timeout if something rashes
var workerTimeoutEnv = os.Getenv("SHUFFLE_ORBORUS_EXECUTION_TIMEOUT")
@@ -586,7 +589,7 @@ func deployWorker(image string, identifier string, env []string, executionReques
hostConfig.NetworkMode = container.NetworkMode(fmt.Sprintf("container:%s", containerId))
if strings.ToLower(cleanupEnv) == "true" {
if strings.ToLower(cleanupEnv) != "false" {
hostConfig.AutoRemove = true
}
@@ -976,10 +979,8 @@ func main() {
}
}
// Handle Cleanup
// var cleanupEnv = strings.ToLower(os.Getenv("CLEANUP"))
// SHUFFLE_CONTAINER_AUTO_CLEANUP=false
if strings.ToLower(os.Getenv("SHUFFLE_CONTAINER_AUTO_CLEANUP")) == "true" {
// Handle Cleanup - made it cleanup by default
if strings.ToLower(os.Getenv("SHUFFLE_CONTAINER_AUTO_CLEANUP")) != "false" {
cleanupEnv = "true"
}
@@ -1145,7 +1146,7 @@ func main() {
// FIXME - add check for StatusCode
if newresp.StatusCode != 200 {
log.Printf("[ERROR] Backend configuration missing (%d): %s", newresp.StatusCode, string(body))
log.Printf("[ERROR] Backend connection failed, or is missing (%d): %s", newresp.StatusCode, string(body))
} else {
if !hasStarted {
log.Printf("[DEBUG] Starting iteration on environment %#v (default = Shuffle). Got statuscode %d from backend on first request", environment, newresp.StatusCode)
@@ -1220,7 +1221,7 @@ func main() {
}
if shuffle.ArrayContains(executionIds, execution.ExecutionId) {
log.Printf("[INFO] Execution already handled: %s", execution.ExecutionId)
log.Printf("[INFO] Execution already handled (rerun of old executions): %s", execution.ExecutionId)
toBeRemoved.Data = append(toBeRemoved.Data, execution)
continue
}