import React, { forwardRef, memo, useContext, useEffect } from 'react'; import theme from "../theme.jsx"; import { toast } from "react-toastify" ; import { Divider, List, ListItem, ListItemText, Button, Tooltip, IconButton, Dialog, DialogTitle, DialogContent, DialogActions, TextField, } from '@mui/material'; import { FileCopy as FileCopyIcon, OpenInNew as OpenInNewIcon, Padding, } from "@mui/icons-material" import { Box, Skeleton, Typography } from '@mui/material'; import { Context } from '../context/ContextApi.jsx'; const SchedulesTab = memo((props) => { const {globalUrl, users, } = props; const [webHooks, setWebHooks] = React.useState([]); const [allSchedules, setAllSchedules] = React.useState([]); const [pipelines, setPipelines] = React.useState([]); const [showLoader, setShowLoader] = React.useState(true); const [pipelineModalOpen, setPipelineModalOpen] = React.useState(false); const [newPipelineValue, setNewPipelineValue] = React.useState("export | sigma /tmp/sigma_rules | to SHUFFLE_WEBHOOK"); useEffect(() => { if (allSchedules.length === 0 && webHooks.length === 0 && pipelines.length === 0) { handleGetAllTriggers() } }, []) const textColor = "#9E9E9E !important"; const changePipelineState = (pipeline, state) => { if (state.trim() === "") { toast("state is not defined"); return; } const data = { name: pipeline.name, id: pipeline.id, type: state, command: pipeline.definition, environment: pipeline.environment, }; if (state === "start") toast("starting the pipeline"); else toast.info("Stopping the pipeline. This may take a few minutes to propagate.") const url = `${globalUrl}/api/v1/triggers/pipeline`; fetch(url, { method: "POST", headers: { "Content-Type": "application/json", Accept: "application/json", }, body: JSON.stringify(data), credentials: "include", }) .then((response) => { if (response.status !== 200) { console.log("Status not 200 for stream results :O!"); toast("Failed to update the pipeline state"); } return response.json(); }) .then((responseJson) => { if (!responseJson.success) { toast.error("Failed to update the pipeline: " + responseJson.reason); } else { setTimeout(() => { handleGetAllTriggers() }, 5000) setTimeout(() => { handleGetAllTriggers() }, 10000) setTimeout(() => { handleGetAllTriggers() }, 20000) setTimeout(() => { handleGetAllTriggers() }, 120000) /* if (state === "start") { toast("Successfully created pipeline"); } else { toast("Sucessfully stopped the pipeline"); } */ } }) .catch((error) => { //toast(error.toString()); console.log("Get schedule error: ", error.toString()); }) } const submitPipelineWrapper = (pipelineValue) => { submitPipeline(pipelineValue) } const NewPipelineView = ( { setPipelineModalOpen(false) }} PaperProps={{ sx: { borderRadius: theme?.palette?.DialogStyle?.borderRadius, border: theme?.palette?.DialogStyle?.border, minWidth: "800px", minHeight: "320px", fontFamily: theme?.typography?.fontFamily, backgroundColor: theme?.palette?.DialogStyle?.backgroundColor, zIndex: 1000, '& .MuiDialogContent-root': { backgroundColor: theme?.palette?.DialogStyle?.backgroundColor, }, '& .MuiDialogTitle-root': { backgroundColor: theme?.palette?.DialogStyle?.backgroundColor, }, '& .MuiDialogActions-root': { backgroundColor: theme?.palette?.DialogStyle?.backgroundColor, }, }, }} > Run a Tenzir pipeline Alpha feature. Deploys to the first available Orborus location. Explore Tenzir Pipelines. The example below exports everything in the Tenzir database, runs Sigma rules on it, and forwards the results to a Shuffle webhook.
setNewPipelineValue(event.target.value) } />
) const submitPipeline = (pipeline, environment) => { var pipelineConfig = { command: pipeline, name: pipeline, type: "create", environment: "", workflow_id: "", trigger_id: "", start_node: "", } if (environment !== undefined && environment !== "") { pipelineConfig.environment = environment } const url = `${globalUrl}/api/v1/triggers/pipeline`; fetch(url, { method: "POST", headers: { "Content-Type": "application/json", Accept: "application/json", }, body: JSON.stringify(pipelineConfig), credentials: "include", }) .then((response) => { if (response.status !== 200) { console.log("Status not 200 for stream results :O!"); } return response.json(); }) .then((responseJson) => { if (!responseJson.success && pipelineConfig.type !== "delete") { toast("Failed to set pipeline: " + responseJson.reason); } else { if (pipelineConfig.type === "create") { toast("Pipeline will be created: " + responseJson.reason) setPipelineModalOpen(false) } else if (pipelineConfig.type === "stop") { toast("Pipeline will be stopped: " + responseJson.reason) setPipelineModalOpen(false) } else { toast("Unknown pipeline type: " + pipelineConfig.type) } } setTimeout(() => { handleGetAllTriggers() }, 5000) setTimeout(() => { handleGetAllTriggers() }, 10000) setTimeout(() => { handleGetAllTriggers() }, 15000) setTimeout(() => { handleGetAllTriggers() }, 20000) }) .catch((error) => { console.log("Get pipeline error: ", error.toString()); }); } const deleteSchedule = (data) => { // FIXME - add some check here ROFL console.log("INPUT: ", data); // Just use this one? const url = globalUrl + "/api/v1/workflows/" + data["workflow_id"] + "/schedule/" + data.id; fetch(url, { method: "DELETE", credentials: "include", headers: { "Content-Type": "application/json", }, }) .then((response) => response.json().then((responseJson) => { if (responseJson["success"] === false) { toast("Failed stopping schedule"); } else { setTimeout(() => { handleGetAllTriggers(); }, 1500); //toast("Successfully stopped schedule!") } }) ) .catch((error) => { console.log("Error in userdata: ", error); }); }; const deleteWebhook = (trigger) => { if (trigger === undefined) { return; } fetch(globalUrl + "/api/v1/hooks/" + trigger.id + "/delete", { method: "DELETE", headers: { "Content-Type": "application/json", Accept: "application/json", }, credentials: "include", }) .then((response) => { if (response.status !== 200) { console.log("Status not 200 for stream results :O!"); } return response.json(); }) .then((responseJson) => { if (responseJson.success) { toast("Successfully stopped webhook"); } else { if (responseJson.reason !== undefined) { toast("Failed stopping webhook: " + responseJson.reason); } } setTimeout(handleGetAllTriggers, 1000); }) .catch((error) => { toast( "Delete webhook error. Contact support or check logs if this persists.", ); }); }; const handleGetAllTriggers = () => { fetch(globalUrl + "/api/v1/triggers", { method: "GET", headers: { "Content-Type": "application/json", Accept: "application/json", }, credentials: "include", }) .then((response) => { if (response.status !== 200) { console.log("Status not 200 for getting all triggers"); } return response.json(); }) .then((responseJson) => { setWebHooks(responseJson.webhooks || []); setAllSchedules(responseJson.schedules || []); setPipelines(responseJson.pipelines || []); setShowLoader(false); }) .catch((error) => { // toast(error.toString()); }); }; const startSchedule = (trigger) => { if (trigger.name.length <= 0) { toast("Error: name can't be empty"); return; } toast("Creating schedule"); const data = { name: trigger.name, frequency: trigger.frequency, execution_argument: trigger.argument, environment: trigger.environment, id: trigger.id, start: trigger.start_node, }; fetch(`${globalUrl}/api/v1/workflows/${trigger.workflow_id}/schedule`, { method: "POST", headers: { "Content-Type": "application/json", Accept: "application/json", }, body: JSON.stringify(data), credentials: "include", }) .then((response) => { if (response.status !== 200) { console.log("Status not 200 for stream results :O!"); } return response.json(); }) .then((responseJson) => { if (!responseJson.success) { toast("Failed to set schedule: " + responseJson.reason); } else { toast("Successfully created schedule"); } setTimeout(handleGetAllTriggers, 1000); }) .catch((error) => { //toast(error.toString()); console.log("Get schedule error: ", error.toString()); }); }; const startWebHook = (trigger) => { const hookname = trigger.info.name; if (hookname.length === 0) { toast("Missing name"); return; } if (trigger.id.length !== 36) { toast("Missing id"); return; } toast("Starting webhook"); const data = { name: hookname, type: "webhook", id: trigger.id, workflow: trigger.workflows[0], start: trigger.start, environment: trigger.environment, auth: trigger.auth, custom_response: trigger.custom_response, version: trigger.version, version_timeout: 15, }; fetch(globalUrl + "/api/v1/hooks/new", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(data), credentials: "include", }) .then((response) => response.json()) .then((responseJson) => { if (responseJson.success) { // Set the status toast("Successfully started webhook"); } else { toast("Failed starting webhook: " + responseJson.reason); } setTimeout(handleGetAllTriggers, 1000); }) .catch((error) => { //console.log(error.toString()); console.log("New webhook error: ", error.toString()); }); }; return (
{NewPipelineView}

Triggers

Triggers are Automatic Workflow starters. Status: Schedules ({allSchedules.length}), Webhooks ({webHooks.length}), Pipelines ({pipelines.length})

Schedules

Schedules used in Workflows. Makes locating and control easier.{" "} Learn more
{["Name", "Interval", "Environment", "Workflow", "Argument", "Action"].map((header, index) => ( ))} {showLoader ? ( [...Array(6)].map((_, rowIndex) => ( {Array(6) .fill() .map((_, colIndex) => ( ))} )) ):( allSchedules?.length === 0 ? (
No schedules found
):( allSchedules.map((schedule, index) => { var bgColor = "#212121" if (index % 2 === 0) { bgColor = "#1a1a1a"; } return ( 0 ? ( schedule.frequency ) : ( {schedule.seconds} seconds ) } /> } /> )} /> ); }) ) )}

Webhooks

Webhooks used in Shuffle workflows.  Learn more
{["Name", "Environment", "Workflow", "URL", "Action"].map((header, index) => ( ))} {showLoader ? ( [...Array(6)].map((_, rowIndex) => ( {Array(5) .fill() .map((_, colIndex) => ( ))} )) ):( webHooks?.length === 0 ? (
No webhooks found
):( webHooks.map((webhook, index) => { var bgColor = "#212121" if (index % 2 === 0) { bgColor = "#1a1a1a"; } return ( } /> { const copyText = navigator?.clipboard?.writeText(webhook.info.url); if(copyText){ toast.success("URL copied to clipboard"); }else{ toast.error("Failed to copy URL"); } }} > copy ) } /> )} /> ); }) ) )}

Pipelines

Controls Pipelines on your Orborus Runners, e.g. for Log Ingestion, MQ subscriptions or Sigma Detections.{" "} Learn more
{["Command", "Environment", "Total Runs", "Actions"].map((header, index) => ( ))} {showLoader ? ( [...Array(6)].map((_, rowIndex) => { return ( {Array(5) .fill() .map((_, colIndex) => { return ( ) })} ) } ) ): ( pipelines?.length === 0 ? (
No pipeline trigger found
):( pipelines.map((pipeline, index) => { var bgColor = "#212121" if (index % 2 === 0) { bgColor = "#1a1a1a"; } return ( )} /> ); }) ) )}
); }); export default SchedulesTab;