diff --git a/.env b/.env index 687fcf58..33c6c318 100644 --- a/.env +++ b/.env @@ -55,7 +55,7 @@ SHUFFLE_ORBORUS_STARTUP_DELAY= # Used for setting up a startup delay for Orbor SHUFFLE_BASE_IMAGE_NAME=shuffle SHUFFLE_BASE_IMAGE_REGISTRY=ghcr.io -SHUFFLE_BASE_IMAGE_TAG_SUFFIX="-1.0.0" +SHUFFLE_BASE_IMAGE_TAG_SUFFIX="-1.1.0" # Used for auto-cleanup of containers. REALLY important at scale. SHUFFLE_CONTAINER_AUTO_CLEANUP=false diff --git a/frontend/src/components/AppGrid.jsx b/frontend/src/components/AppGrid.jsx index 562146c0..690d7cb4 100644 --- a/frontend/src/components/AppGrid.jsx +++ b/frontend/src/components/AppGrid.jsx @@ -1,6 +1,6 @@ import React, {useEffect, useState} from 'react'; -import ReactGA from 'react-ga'; +import ReactGA from 'react-ga4'; import { useTheme } from '@material-ui/core/styles'; import {Link} from 'react-router-dom'; diff --git a/frontend/src/components/Appsearch.jsx b/frontend/src/components/Appsearch.jsx index 9f219722..9da69a70 100644 --- a/frontend/src/components/Appsearch.jsx +++ b/frontend/src/components/Appsearch.jsx @@ -1,5 +1,5 @@ import React, { useState, useEffect } from 'react'; -import ReactGA from 'react-ga'; +import ReactGA from 'react-ga4'; import { useTheme } from '@material-ui/core/styles'; import {Link} from 'react-router-dom'; import { useAlert } from "react-alert"; diff --git a/frontend/src/components/CreatorGrid.jsx b/frontend/src/components/CreatorGrid.jsx index f09f84a0..584e0f6e 100644 --- a/frontend/src/components/CreatorGrid.jsx +++ b/frontend/src/components/CreatorGrid.jsx @@ -1,6 +1,6 @@ import React, { useEffect, useState } from 'react'; -import ReactGA from 'react-ga'; +import ReactGA from 'react-ga4'; import { useTheme } from '@material-ui/core/styles'; import {Link} from 'react-router-dom'; diff --git a/frontend/src/components/DocsGrid.jsx b/frontend/src/components/DocsGrid.jsx index 706c861a..ea20cd0e 100644 --- a/frontend/src/components/DocsGrid.jsx +++ b/frontend/src/components/DocsGrid.jsx @@ -1,6 +1,6 @@ import React, {useEffect, useState} from 'react'; -import ReactGA from 'react-ga'; +import ReactGA from 'react-ga4'; import { useTheme } from '@material-ui/core/styles'; import {Link} from 'react-router-dom'; diff --git a/frontend/src/components/Searchfield.jsx b/frontend/src/components/Searchfield.jsx index 43fa7934..f1e3aa77 100644 --- a/frontend/src/components/Searchfield.jsx +++ b/frontend/src/components/Searchfield.jsx @@ -625,7 +625,7 @@ const SearchField = props => { const CustomDocHits = connectHits(DocHits) return ( -
+
{ console.log("CLICKED") }}> diff --git a/frontend/src/components/SecurityFramework.jsx b/frontend/src/components/SecurityFramework.jsx index 7139f7a6..9e3a7b90 100644 --- a/frontend/src/components/SecurityFramework.jsx +++ b/frontend/src/components/SecurityFramework.jsx @@ -2,7 +2,7 @@ import React, {useState } from 'react'; import {isMobile} from "react-device-detect"; import AppFramework, { usecases } from "../components/AppFramework.jsx"; import {Link} from 'react-router-dom'; -import ReactGA from 'react-ga'; +import ReactGA from 'react-ga4'; import { Button, LinearProgress, Typography } from '@material-ui/core'; diff --git a/frontend/src/components/SuggestedWorkflows.jsx b/frontend/src/components/SuggestedWorkflows.jsx index 69349846..6bbc15e7 100644 --- a/frontend/src/components/SuggestedWorkflows.jsx +++ b/frontend/src/components/SuggestedWorkflows.jsx @@ -1,5 +1,5 @@ import React, { useState, useEffect } from 'react'; -import ReactGA from 'react-ga'; +import ReactGA from 'react-ga4'; import theme from '../theme'; import PaperComponent from "../components/PaperComponent.jsx" import UsecaseSearch, { usecaseTypes } from "../components/UsecaseSearch.jsx" diff --git a/frontend/src/components/WelcomeForm2.jsx b/frontend/src/components/WelcomeForm2.jsx index 79a89f06..f78f65aa 100644 --- a/frontend/src/components/WelcomeForm2.jsx +++ b/frontend/src/components/WelcomeForm2.jsx @@ -1,5 +1,5 @@ import React, { useState, useEffect } from "react"; -import ReactGA from 'react-ga'; +import ReactGA from 'react-ga4'; import Button from "@material-ui/core/Button"; import Checkbox from '@mui/material/Checkbox'; diff --git a/frontend/src/components/Workflowsearch.jsx b/frontend/src/components/Workflowsearch.jsx index 73539521..152fdd83 100644 --- a/frontend/src/components/Workflowsearch.jsx +++ b/frontend/src/components/Workflowsearch.jsx @@ -1,6 +1,5 @@ import React, { useState, useEffect } from 'react'; -import ReactGA from 'react-ga'; import { useTheme } from '@material-ui/core/styles'; import {Link} from 'react-router-dom'; @@ -159,25 +158,10 @@ const WorkflowSearch = props => { return ( { setMouseHoverIndex(index) - /* - ReactGA.event({ - category: "app_grid_view", - action: `search_bar_click`, - label: "", - }) - */ }} onMouseOut={() => { setMouseHoverIndex(-1) }} onClick={() => { setNewSelectedApp(data) - //if (data.objectID !== data.objectID) { - //} - - //ReactGA.event({ - // category: "app_search", - // action: `app_${parsedname}_${data.id}_click`, - // label: "", - //}) }}>
{/*{data.name}*/} diff --git a/frontend/src/views/AngularWorkflow.jsx b/frontend/src/views/AngularWorkflow.jsx index a821a0f3..f07c8497 100644 --- a/frontend/src/views/AngularWorkflow.jsx +++ b/frontend/src/views/AngularWorkflow.jsx @@ -415,7 +415,7 @@ const AngularWorkflow = (defaultprops) => { // Set it from 2500 to 6000 to reduce overall load const { start, stop } = useInterval({ duration: 3000, - startImmediate: true, + startImmediate: false, callback: () => { fetchUpdates(); }, @@ -981,6 +981,9 @@ const AngularWorkflow = (defaultprops) => { // Controls the colors and direction of execution results. // Style is in defaultCytoscapeStyle.js const handleUpdateResults = (responseJson, executionRequest) => { + if (responseJson === undefined || responseJson === null || responseJson.success === false) { + return + } //console.log(responseJson) // Loop nodes and find results // Update on every interval? idk @@ -2952,10 +2955,19 @@ const AngularWorkflow = (defaultprops) => { getSettings(); } else if (data.app_name === "Webhook") { if (workflow.triggers[trigger_index].parameters !== undefined && workflow.triggers[trigger_index].parameters !== null && workflow.triggers[trigger_index].parameters.length > 0) { + console.log("Can set params here!") workflow.triggers[trigger_index].parameters[0] = { name: "url", value: referenceUrl + "webhook_" + workflow.triggers[trigger_index].id, }; + + if (workflow.triggers[trigger_index].parameters.length < 5) { + console.log("Adding to webhook params!") + workflow.triggers[trigger_index].parameters.push({ + name: "await_response", + value: "v1," + }) + } } } @@ -10538,7 +10550,7 @@ const AngularWorkflow = (defaultprops) => { }} fullWidth multiline - rows="4" + rows="2" defaultValue={trigger_header_auth} color="primary" disabled={selectedTrigger.status === "running"} @@ -10557,7 +10569,44 @@ const AngularWorkflow = (defaultprops) => { }} />
-
+ {isCloud && workflow.triggers[selectedTriggerIndex].parameters.length > 4 ? + + { + if (selectedTrigger.parameters === null) { + selectedTrigger.parameters = []; + } + + // Sets the webhook to run as version 2.. kinda + var value = "v2" + if (workflow.triggers[selectedTriggerIndex].parameters[4].value.includes("v2")) { + value = "v1" + } + + workflow.triggers[selectedTriggerIndex].parameters[4] = { + name: "await_response", + value: value + } + + setWorkflow(workflow) + setUpdate(Math.random()) + }} + color="primary" + value="await_response" + /> + } + label={
Wait For Response
} + /> +
+ : null} +
); @@ -10707,12 +10756,7 @@ const AngularWorkflow = (defaultprops) => { const branch = workflow.branches.find( (branch) => branch.source_id === trigger.id ); - if ( - branch === undefined && - (workflow.start === undefined || - workflow.start === null || - workflow.start.length === 0) - ) { + if (branch === undefined && (workflow.start === undefined || workflow.start === null || workflow.start.length === 0)) { alert.error("No webhook node defined"); } @@ -10721,14 +10765,20 @@ const AngularWorkflow = (defaultprops) => { startNode = branch.destination_id; } - const param = trigger.parameters.find( - (param) => param.name === "auth_headers" - ); + const param = trigger.parameters.find((param) => param.name === "auth_headers"); var auth = ""; if (param !== undefined && param !== null) { auth = param.value; } + + // Version: v2 = await response for 30 sec + const await_resp = trigger.parameters.find((param) => param.name === "await_response"); + var version = ""; + if (await_resp !== undefined && await_resp !== null) { + version = await_resp.value; + } + const customRespParam = trigger.parameters.find( (param) => param.name === "custom_response_body" ) @@ -10737,7 +10787,6 @@ const AngularWorkflow = (defaultprops) => { custom_response = customRespParam.value; } - console.log("TRIG: ", trigger); const data = { name: hookname, type: "webhook", @@ -10747,8 +10796,12 @@ const AngularWorkflow = (defaultprops) => { environment: trigger.environment, auth: auth, custom_response: custom_response, + version: version, + version_timeout: 15, }; + console.log("Trigger data: ", data) + fetch(globalUrl + "/api/v1/hooks/new", { method: "POST", headers: { "content-type": "application/json" }, diff --git a/frontend/src/views/AppCreator.jsx b/frontend/src/views/AppCreator.jsx index 44b2f271..5719b39f 100644 --- a/frontend/src/views/AppCreator.jsx +++ b/frontend/src/views/AppCreator.jsx @@ -222,6 +222,55 @@ const parseCurl = (s) => { return out; }; +export const appCategories = [ + { + "name": "Communication", + "color": "#FFC107", + "icon": "communication", + "action_labels": ["List Messages", "Send Message",], + }, { + "name": "SIEM", + "color": "#FFC107", + "icon": "siem", + "action_labels": ["Get alerts", "Search", "Create detection",], + }, { + "name": "Eradication", + "color": "#FFC107", + "icon": "eradication", + "action_labels": ["List tickets", "Update ticket", "Block hash", "Isolate host"], + }, { + "name": "Cases", + "color": "#FFC107", + "icon": "cases", + "action_labels": ["List tickets", "Get ticket", "Create ticket", "Update ticket",], + }, { + "name": "Assets", + "color": "#FFC107", + "icon": "assets", + "action_labels": [], + }, { + "name": "Intel", + "color": "#FFC107", + "icon": "intel", + "action_labels": [], + }, { + "name": "IAM", + "color": "#FFC107", + "icon": "iam", + "action_labels": [], + }, { + "name": "Network", + "color": "#FFC107", + "icon": "network", + "action_labels": ["Block IP",], + }, { + "name": "Other", + "color": "#FFC107", + "icon": "other", + "action_labels": [], + }, +] + export const base64_decode = (str) => { return decodeURIComponent( atob(str).split("").map(function (c) { @@ -310,81 +359,8 @@ const AppCreator = (defaultprops) => { // From 2023: Example to handle action labels // Goal: Make this dynamically load from the backend // and make categories + labels modifyable. - // // Categories are the main categories in the App Framework - const [categories, setCategories] = useState([ - { - "name": "Communication", - "color": "#FFC107", - "icon": "communication", - "action_labels": [], - }, { - "name": "SIEM", - "color": "#FFC107", - "icon": "siem", - "action_labels": ["Get alerts", "Search", "Create detection",], - }, { - "name": "Eradication", - "color": "#FFC107", - "icon": "eradication", - "action_labels": ["List tickets", "Update ticket", "Block hash", "Isolate host"], - }, { - "name": "Cases", - "color": "#FFC107", - "icon": "cases", - "action_labels": ["List tickets", "Get ticket", "Create ticket", "Update ticket",], - }, { - "name": "Assets", - "color": "#FFC107", - "icon": "assets", - "action_labels": [], - }, { - "name": "Intel", - "color": "#FFC107", - "icon": "intel", - "action_labels": [], - }, { - "name": "IAM", - "color": "#FFC107", - "icon": "iam", - "action_labels": [], - }, { - "name": "Network", - "color": "#FFC107", - "icon": "network", - "action_labels": ["Block IP",], - }, { - "name": "Other", - "color": "#FFC107", - "icon": "other", - "action_labels": [], - } - ]); - - //const [actions, setActions] = useState([{ - // "name": "Get workflows", - // "description": "Get workflows", - // "url": "/workflows", - // "headers": "", - // "queries": [], - // "paths": [], - // "body": "", - // "errors": ["wutface", "WOAH"], - // "method": actionNonBodyRequest[0], - //}, { - // "name": "Get workflow", - // "description": "Get workflow", - // "url": "/workflows/{id}", - // "headers": "", - // "queries": [], - // "paths": ["id"], - // "body": "", - // "errors": ["wutface", "WOAH"], - // "method": actionNonBodyRequest[0], - //}, - // - //]) - + const [categories, setCategories] = useState(appCategories) const [currentActionMethod, setCurrentActionMethod] = useState( actionNonBodyRequest[0] ) diff --git a/frontend/src/views/GettingStarted.jsx b/frontend/src/views/GettingStarted.jsx index b42bddef..87dd1be0 100644 --- a/frontend/src/views/GettingStarted.jsx +++ b/frontend/src/views/GettingStarted.jsx @@ -2,7 +2,7 @@ import React, { useEffect, useContext } from "react"; import { makeStyles } from "@material-ui/core/styles"; import { useTheme } from "@material-ui/core/styles"; -import ReactGA from 'react-ga'; +import ReactGA from 'react-ga4'; import SecurityFramework from '../components/SecurityFramework.jsx'; import { diff --git a/frontend/src/views/Welcome.jsx b/frontend/src/views/Welcome.jsx index ab80c18e..06c6352f 100644 --- a/frontend/src/views/Welcome.jsx +++ b/frontend/src/views/Welcome.jsx @@ -1,5 +1,5 @@ import React, { useState, useEffect } from 'react'; -import ReactGA from 'react-ga'; +import ReactGA from 'react-ga4'; import WelcomeForm2 from "../components/WelcomeForm2.jsx"; import Stepper from "@material-ui/core/Stepper"; import Step from "@material-ui/core/Step"; diff --git a/frontend/src/views/Workflows.jsx b/frontend/src/views/Workflows.jsx index 4d8adb23..5de0e799 100644 --- a/frontend/src/views/Workflows.jsx +++ b/frontend/src/views/Workflows.jsx @@ -551,7 +551,6 @@ const Workflows = (props) => { const [deleteModalOpen, setDeleteModalOpen] = React.useState(false); const [publishModalOpen, setPublishModalOpen] = React.useState(false); const [editingWorkflow, setEditingWorkflow] = React.useState({}); - const [importLoading, setImportLoading] = React.useState(false); const [isDropzone, setIsDropzone] = React.useState(false); const [view, setView] = React.useState("grid"); const [filters, setFilters] = React.useState([]); @@ -585,10 +584,10 @@ const Workflows = (props) => { } setGettingStartedItems(activeFiltered) - const doneFiltered = activeFiltered.filter((item) => item.done === true) - if (doneFiltered.length > 0) { - console.log("DONE: ", doneFiltered) - } + //const doneFiltered = activeFiltered.filter((item) => item.done === true) + //if (doneFiltered.length > 0) { + // console.log("DONE: ", doneFiltered) + //} const sidebar = localStorage.getItem(sidebarKey); if (sidebar === null || sidebar === undefined) { @@ -597,13 +596,10 @@ const Workflows = (props) => { localStorage.setItem(sidebarKey, "open"); setDrawerOpen(true) } else { - console.log("Got sidebar: ", sidebar) - if (sidebar === "open") { console.log("OPEN the thingy!") setDrawerOpen(true) } else { - console.log("Close the thingy!") setDrawerOpen(false) } } @@ -1229,7 +1225,6 @@ const Workflows = (props) => { display: "flex", flexWrap: "wrap", alignContent: "space-between", - marginTop: 5, }; const paperAppStyle = { @@ -2212,7 +2207,7 @@ const Workflows = (props) => { setTimeout(() => { getAvailableWorkflows(); }, 2500); - setImportLoading(false); + setSubmitLoading(false) setModalOpen(false); } else { //alert.info("Successfully changed basic info for workflow"); @@ -2223,7 +2218,7 @@ const Workflows = (props) => { }) .catch((error) => { alert.error(error.toString()); - setImportLoading(false); + setSubmitLoading(false) setModalOpen(false); setSubmitLoading(false); }); @@ -2231,8 +2226,8 @@ const Workflows = (props) => { const importFiles = (event) => { console.log("Importing!"); + setSubmitLoading(true) - setImportLoading(true); if (event.target.files.length > 0) { console.log("Files: !", event.target.files.length); for (var key in event.target.files) { @@ -2240,7 +2235,7 @@ const Workflows = (props) => { if (file.type !== "application/json") { if (file.type !== undefined) { alert.error("File has to contain valid json"); - setImportLoading(false); + setSubmitLoading(false) } continue; @@ -2254,7 +2249,7 @@ const Workflows = (props) => { data = JSON.parse(reader.result); } catch (e) { alert.error("Invalid JSON: " + e); - setImportLoading(false); + setSubmitLoading(false) return; } @@ -2981,20 +2976,15 @@ const Workflows = (props) => { )} - {importLoading ? ( - - ) : ( - - )} + { }} */} -
+
{!isMobile && usecases !== null && usecases !== undefined && usecases.length > 0 ?
{usecases.map((usecase, index) => { @@ -3320,12 +3310,12 @@ const Workflows = (props) => { }} > - - + + {usecase.name} - - In use: {usecase.matches.length}/{usecase.list.length} + + {usecase.matches.length}/{usecase.list.length} @@ -3334,7 +3324,8 @@ const Workflows = (props) => {
: null}
-
+ +
{!isMobile && actionImageList !== undefined && actionImageList !== null && @@ -3435,44 +3426,48 @@ const Workflows = (props) => { })}
) : null} - {view === "grid" ? ( - - - - - {filteredWorkflows.map((data, index) => { - // Shouldn't be a part of this list - if (data.public === true) { - return null - } - if (firstLoad) { - workflowDelay += 75 - } else { +
+ {view === "grid" ? ( + + + + + + {filteredWorkflows.map((data, index) => { + // Shouldn't be a part of this list + if (data.public === true) { + return null + } + + if (firstLoad) { + workflowDelay += 75 + } else { + return ( + + + + ) + } + return ( - - - + + + + + ) - } + })} + + ) : ( + + )} +
- return ( - - - - - - ) - })} -
- ) : ( - - )} - -
-
-
+
+
+
); }; diff --git a/functions/onprem/orborus/orborus.go b/functions/onprem/orborus/orborus.go index 9c5b9b69..8d1233a8 100644 --- a/functions/onprem/orborus/orborus.go +++ b/functions/onprem/orborus/orborus.go @@ -65,7 +65,8 @@ var newWorkerImage = os.Getenv("SHUFFLE_WORKER_IMAGE") // var baseimagename = "shuffle/shuffle" var baseimagename = os.Getenv("SHUFFLE_BASE_IMAGE_NAME") var baseimageregistry = os.Getenv("SHUFFLE_BASE_IMAGE_REGISTRY") -var baseimagetagsuffix = os.Getenv("SHUFFLE_BASE_IMAGE_TAG_SUFFIX") + +//var baseimagetagsuffix = os.Getenv("SHUFFLE_BASE_IMAGE_TAG_SUFFIX") // Used for cloud with auth var auth = os.Getenv("AUTH")