App framework fixes and new ways to get usecases

This commit is contained in:
frikky
2023-05-16 04:07:33 +02:00
parent f9426e78b0
commit 2b1b84d843
11 changed files with 298 additions and 191 deletions
+2 -2
View File
@@ -263,7 +263,7 @@ func handleGetWorkflowqueue(resp http.ResponseWriter, request *http.Request) {
environment := request.Header.Get("org")
if len(environment) == 0 {
log.Printf("[AUDIT] No 'org' header set (get workflow queue). Required for cloud.")
//log.Printf("[AUDIT] No 'org' header set (get workflow queue). ")
/*
resp.WriteHeader(403)
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Specify the org header. This can be done by setting the 'ORG' environment variable for Orborus to your Org ID in Shuffle"}`)))
@@ -276,7 +276,7 @@ func handleGetWorkflowqueue(resp http.ResponseWriter, request *http.Request) {
// This section is cloud custom for now
auth := request.Header.Get("Authorization")
if len(auth) == 0 {
log.Printf("[AUDIT] No Authorization header set. Required for cloud. Env: %s, org: %s", orgId, environment)
//log.Printf("[AUDIT] No Authorization header set. Env: %s, org: %s", orgId, environment)
/*
resp.WriteHeader(401)
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Specify the auth header (only applicable for cloud for now)."}`)))
+53 -92
View File
@@ -116,58 +116,7 @@ export const usecases = {
"human": true,
},
]},
"Ransomware": {
"manual": [],
"automated": [
{
"source": "BOTTOM_LEFT",
"target": "EDR & AV",
"description": "EDR & AV alert",
"human": false,
},
{
"source": "EDR & AV",
"target": "SHUFFLE",
"description": "",
"human": false,
},
{
"source": "SHUFFLE",
"target": "EDR & AV",
"human": false,
"description": "isolate",
},
{
"source": "SHUFFLE",
"target": "IAM",
"human": false,
"description": "Block access",
},
{
"source": "SHUFFLE",
"target": "COMMS",
"description": "Notify oncall and affected user",
"human": false,
},
{
"source": "SHUFFLE",
"target": "CASES",
"description": "Create enriched alert",
"human": false,
},
{
"source": "SHUFFLE",
"target": "CASES",
"human": false,
},
{
"source": "CASES",
"target": "EDR & AV",
"description": "Validate alert",
"human": true,
},
]
},
"Exploits": {
"manual": [],
"automated": [
@@ -220,46 +169,6 @@ export const usecases = {
},
]
},
"AWS S3 honeypots": {
"manual": [],
"automated": [
{
"source": "TOP_LEFT",
"target": "SIEM",
"description": "S3 logs",
"human": false,
},
{
"source": "SIEM",
"target": "SHUFFLE",
"human": false,
},
{
"source": "SHUFFLE",
"target": "INTEL",
"description": "Add sighting",
"human": false,
},
{
"source": "INTEL",
"target": "SHUFFLE",
"human": false,
},
{
"source": "SHUFFLE",
"target": "CASES",
"description": "Create case",
"human": false,
},
{
"source": "SHUFFLE",
"target": "NETWORK",
"description": "Block IP",
"human": false,
},
]
},
"SIEM alerts": {
"manual": [],
"automated": [
@@ -535,6 +444,58 @@ export const usecases = {
},
]
},
"Ransomware": {
"manual": [],
"automated": [
{
"source": "BOTTOM_LEFT",
"target": "EDR & AV",
"description": "EDR & AV alert",
"human": false,
},
{
"source": "EDR & AV",
"target": "SHUFFLE",
"description": "",
"human": false,
},
{
"source": "SHUFFLE",
"target": "EDR & AV",
"human": false,
"description": "isolate",
},
{
"source": "SHUFFLE",
"target": "IAM",
"human": false,
"description": "Block access",
},
{
"source": "SHUFFLE",
"target": "COMMS",
"description": "Notify oncall and affected user",
"human": false,
},
{
"source": "SHUFFLE",
"target": "CASES",
"description": "Create enriched alert",
"human": false,
},
{
"source": "SHUFFLE",
"target": "CASES",
"human": false,
},
{
"source": "CASES",
"target": "EDR & AV",
"description": "Validate alert",
"human": true,
},
]
},
"Draw": {
}
}
+3 -2
View File
@@ -617,7 +617,7 @@ const { globalUrl, setNotifications, notifications, isLoggedIn, removeCookie, ho
<List style={{display: 'flex', flexDirection: 'row-reverse'}} component="nav">
<ListItem style={{textAlign: "center"}}>
<Link to="/login" style={hrefStyle}>
<Button variant="outlined" color="primary" style={{textTransform: "none", borderRadius: 25, padding: "7px 14px 7px 14px", maxWidth: 100, minWidth: 100, }} onClick={() => {
<Button variant="outlined" style={{textTransform: "none", borderRadius: 25, padding: "7px 14px 7px 14px", maxWidth: 100, minWidth: 100, }} onClick={() => {
if (isCloud) {
ReactGA.event({
category: "header",
@@ -933,7 +933,8 @@ const { globalUrl, setNotifications, notifications, isLoggedIn, removeCookie, ho
<div onMouseOver={handleHomeHover} onMouseOut={handleHomeHoverOut} style={{color: HomeHoverColor, cursor: "pointer"}}>
<Grid container direction="row" alignItems="center">
<Grid item>
<HomeIcon style={{marginTop: 3, marginRight: 5}} />
<img src={"/images/logos/orange_logo.svg"} alt="logo" style={{height: 20, width: 20, marginTop: 3, marginRight: 5, }}/>
{/*<HomeIcon style={{marginTop: 3, marginRight: 5}} />*/}
</Grid>
</Grid>
</div>
+4 -47
View File
@@ -30,6 +30,7 @@ const OrgHeader = (props) => {
globalUrl,
isCloud,
adminTab,
handleEditOrg,
} = props;
const theme = useTheme();
@@ -83,49 +84,6 @@ const OrgHeader = (props) => {
};
}
const handleEditOrg = (
name,
description,
orgId,
image,
defaults,
sso_config
) => {
const data = {
name: name,
description: description,
org_id: orgId,
image: image,
defaults: defaults,
sso_config: sso_config,
};
const url = globalUrl + `/api/v1/orgs/${selectedOrganization.id}`;
fetch(url, {
mode: "cors",
method: "POST",
body: JSON.stringify(data),
credentials: "include",
crossDomain: true,
withCredentials: true,
headers: {
"Content-Type": "application/json; charset=utf-8",
},
})
.then((response) =>
response.json().then((responseJson) => {
if (responseJson["success"] === false) {
alert.error("Failed updating org: ", responseJson.reason);
} else {
alert.success("Successfully edited org!");
}
})
)
.catch((error) => {
alert.error("Err: " + error.toString());
});
};
var image = "";
const editHeaderImage = (event) => {
@@ -151,10 +109,9 @@ const OrgHeader = (props) => {
orgDescription,
selectedOrganization.id,
selectedOrganization.image,
{
},
{
}
{},
{},
[],
)
}
>
+6 -6
View File
@@ -1636,12 +1636,12 @@ const ParsedAction = (props) => {
onClick={() => {
console.log("Clicked field: ", clickedFieldId, data.name)
if (data.name === "file_id") {
console.log("show file video?")
if (setShowVideo !== undefined) {
setShowVideo("https://www.youtube.com/embed/DPYowyTbsSk")
}
}
//if (data.name === "file_id") {
// console.log("show file video?")
// if (setShowVideo !== undefined) {
// setShowVideo("https://www.youtube.com/embed/DPYowyTbsSk")
// }
//}
//(data.name.toLowerCase().includes("api") ||
/*
setExpansionModalOpen(false);
+46 -2
View File
@@ -35,6 +35,7 @@ const defaultValue = {"id": "", "name": "Build your own",
export const usecaseTypes = [{
"name": "enrichment",
"aliases": ["enrichment", "enrich"],
"value": [{
"name": "EDR Ticket Enrichment",
"usecase_references": ["EDR to ticket"],
@@ -51,6 +52,7 @@ export const usecaseTypes = [{
},
{
"name": "SIEM alert Enrichment",
"aliases": ["siem alert enrichment", "siem alert enrich"],
"usecase_references": ["SIEM to ticket"],
"active": true,
"items": [{
@@ -66,6 +68,7 @@ export const usecaseTypes = [{
},
{
"name": "Email Enrichment",
"aliases": ["email enrichment", "email enrich"],
"usecase_references": ["Email management"],
"active": true,
"items": [{
@@ -82,6 +85,7 @@ export const usecaseTypes = [{
},
{
"name": "phishing",
"aliases": ["ransomware", "phish"],
"value": [
{
"name": "Email analysis",
@@ -100,6 +104,7 @@ export const usecaseTypes = [{
},
{
"name": "detection",
"aliases": ["detection", "detect", "siem alerts", "new detections",],
"value": [
{
"name": "Sigma rule detection",
@@ -118,12 +123,13 @@ export const usecaseTypes = [{
},
{
"name": "response",
"aliases": ["response", "respond", "exploits"],
"value": [
{
"name": "EDR host isolation",
"active": false,
"items": [{
"name": "When malicious endpoint activity is detected",
"name": "When exploits are detected",
"app_type": "edr",
"type": "trigger",
},
@@ -133,7 +139,45 @@ export const usecaseTypes = [{
"type": "subflow",
}],
}]
}
},
{
"name": "vulnerabilities",
"aliases": [],
"value": [
{
"name": "Vulnerability is found",
"active": false,
"items": [{
"name": "When a vulnerability is found",
"app_type": "assets",
"type": "trigger",
},
{
"name": "Patch the vulnerability",
"app_type": "edr",
"type": "subflow",
}],
}]
},
{
"name": "approvals",
"aliases": ["approval"],
"value": [
{
"name": "Approval is needed",
"active": false,
"items": [{
"name": "When approval is needed",
"app_type": "iam",
"type": "trigger",
},
{
"name": "Notify the user",
"app_type": "communication",
"type": "subflow",
}],
}]
},
]
export const triggerlist = [
+130 -13
View File
@@ -163,13 +163,9 @@ const Admin = (props) => {
const [selectedUser, setSelectedUser] = React.useState({});
const [newUsername, setNewUsername] = React.useState("");
const [newPassword, setNewPassword] = React.useState("");
const [selectedUserModalOpen, setSelectedUserModalOpen] =
React.useState(false);
const [selectedAuthentication, setSelectedAuthentication] = React.useState(
{}
);
const [selectedAuthenticationModalOpen, setSelectedAuthenticationModalOpen] =
React.useState(false);
const [selectedUserModalOpen, setSelectedUserModalOpen] = React.useState(false);
const [selectedAuthentication, setSelectedAuthentication] = React.useState({});
const [selectedAuthenticationModalOpen, setSelectedAuthenticationModalOpen] = React.useState(false);
const [authenticationFields, setAuthenticationFields] = React.useState([]);
const [showArchived, setShowArchived] = React.useState(false);
const [isDropzone, setIsDropzone] = React.useState(false);
@@ -179,12 +175,10 @@ const Admin = (props) => {
const [secret2FA, setSecret2FA] = React.useState("");
const [show2faSetup, setShow2faSetup] = useState(false);
const [adminTab, setAdminTab] = React.useState(1);
const [showApiKey, setShowApiKey] = useState(false);
const [billingInfo, setBillingInfo] = React.useState({});
const [selectedStatus, setSelectedStatus] = React.useState([]);
useEffect(() => {
if (isDropzone) {
@@ -193,6 +187,8 @@ const Admin = (props) => {
}
}, [isDropzone]);
const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io";
const get2faCode = (userId) => {
@@ -286,6 +282,20 @@ const Admin = (props) => {
*/
const alert = useAlert();
const handleStatusChange = (event) => {
const { value } = event.target;
setSelectedStatus(value);
handleEditOrg(
"",
"",
selectedOrganization.id,
"",
{},
{},
value,
)
}
const deleteAuthentication = (data) => {
alert.info("Deleting auth " + data.label);
@@ -547,6 +557,54 @@ const Admin = (props) => {
});
};
const handleEditOrg = (
name,
description,
orgId,
image,
defaults,
sso_config,
lead_info,
) => {
const data = {
name: name,
description: description,
org_id: orgId,
image: image,
defaults: defaults,
sso_config: sso_config,
lead_info: lead_info,
};
const url = globalUrl + `/api/v1/orgs/${selectedOrganization.id}`;
fetch(url, {
mode: "cors",
method: "POST",
body: JSON.stringify(data),
credentials: "include",
crossDomain: true,
withCredentials: true,
headers: {
"Content-Type": "application/json; charset=utf-8",
},
})
.then((response) =>
response.json().then((responseJson) => {
if (responseJson["success"] === false) {
alert.error("Failed updating org: ", responseJson.reason);
} else {
if (lead_info === undefined || lead_info === null || lead_info === []) {
alert.success("Successfully edited org!");
}
}
})
)
.catch((error) => {
alert.error("Err: " + error.toString());
});
};
const editAuthenticationConfig = (id) => {
const data = {
id: id,
@@ -696,10 +754,18 @@ const Admin = (props) => {
const handleGetOrg = (orgId) => {
if (serverside !== true && window.location.search !== undefined && window.location.search !== null) {
const urlSearchParams = new URLSearchParams(window.location.search);
const params = Object.fromEntries(urlSearchParams.entries());
const foundorgid = params["org_id"];
if (foundorgid !== undefined && foundorgid !== null) {
orgId = foundorgid;
}
}
if (orgId.length === 0) {
alert.error(
"Organization ID not defined. Please contact us on https://shuffler.io if this persists logout."
);
alert.error("Organization ID not defined. Please contact us on https://shuffler.io if this persists logout.");
return;
}
@@ -729,6 +795,31 @@ const Admin = (props) => {
responseJson.sync_features = {};
}
if (responseJson.lead_info !== undefined && responseJson.lead_info !== null) {
var leads = []
if (responseJson.lead_info.customer) {
leads.push("customer")
}
if (responseJson.lead_info.demo_done) {
leads.push("demo done")
}
if (responseJson.lead_info.pov) {
leads.push("pov")
}
if (responseJson.lead_info.lead) {
leads.push("lead")
}
if (responseJson.lead_info.student) {
leads.push("student")
}
setSelectedStatus(leads)
}
setSelectedOrganization(responseJson)
var lists = {
active: {
@@ -2094,6 +2185,31 @@ const Admin = (props) => {
</IconButton>
</Tooltip>
*/}
{userdata.support === true ?
<FormControl sx={{ m: 1, width: 300, }} style={{top: -10, right: 50, position: "absolute" }}>
<InputLabel id="">Status</InputLabel>
<Select
style={{minWidth: 150, maxWidth: 150, }}
labelId="multiselect-status"
id="multiselect-status"
multiple
value={selectedStatus}
onChange={handleStatusChange}
input={<OutlinedInput label="Status" />}
renderValue={(selected) => selected.join(', ')}
MenuProps={MenuProps}
>
{["lead", "pov", "demo done", "customer", "student", ].map((name) => (
<MenuItem key={name} value={name}>
<Checkbox checked={selectedStatus.indexOf(name) > -1} />
<ListItemText primary={name} />
</MenuItem>
))}
</Select>
</FormControl>
: null}
<Tooltip
title={"Copy Organization ID"}
style={{}}
@@ -2152,6 +2268,7 @@ const Admin = (props) => {
globalUrl={globalUrl}
selectedOrganization={selectedOrganization}
adminTab={adminTab}
handleEditOrg={handleEditOrg}
/>
) : (
<div
-8
View File
@@ -14787,14 +14787,6 @@ const AngularWorkflow = (defaultprops) => {
<b>Status </b> {selectedResult.status}
</div>
<h1 onClick={() => {
console.log("APP: ", curapp)
console.log("Data: ", selectedResult)
}}>
HIYA: {selectedResult.action.app_name}
</h1>
{validate.valid ? (
<ReactJson
src={validate.result}
+2 -2
View File
@@ -118,7 +118,7 @@ const Search = (props) => {
// Random names for type & autoComplete. Didn't research :^)
const landingpageDataBrowser =
<div style={{paddingBottom: hidemargins === true ? 0 : 100, color: "white", backgroundColor: theme.palette.surfacColor}}>
<div style={{paddingBottom: hidemargins === true ? 0 : 100, color: "white", }}>
<div style={boxStyle}>
<Tabs
style={{width: 610, margin: "auto", marginTop: hidemargins === true ? 0 : 25, }}
@@ -179,7 +179,7 @@ const Search = (props) => {
// #1f2023?
return(
<div style={{backgroundColor: "#1f2023",}}>
<div style={{}}>
{loadedCheck}
</div>
)
+32 -17
View File
@@ -301,12 +301,14 @@ const Welcome = (props) => {
minWidth: 300,
backgroundColor: theme.palette.surfaceColor,
color: "white",
borderRadius: theme.palette.borderRadius,
}
const actionObject = {
padding: "35px",
maxHeight: 300,
minHeight: 300,
borderRadius: theme.palette.borderRadius,
}
const imageStyle = {
@@ -317,10 +319,22 @@ const Welcome = (props) => {
borderRadius: 75,
objectFit: "scale-down",
}
const buttonStyle = { borderRadius: 8, height: 51, width: 464, fontSize: 16, background: "linear-gradient(89.83deg, #FF8444 0.13%, #F2643B 99.84%)", padding: "16px 24px", top: 75, }
const experienced_image = userdata !== undefined && userdata !== null && userdata.active_org !== undefined && userdata.active_org.image !== undefined && userdata.active_org.image !== null && userdata.active_org.image !== "" ? userdata.active_org.image : "/images/experienced.png"
const buttonStyle = {
borderRadius: 8,
height: 51,
width: 464,
fontSize: 16,
background: "linear-gradient(89.83deg, #FF8444 0.13%, #F2643B 99.84%)",
padding: "16px 24px",
top: 75,
margin: "auto",
itemAlign: "center",
}
const defaultImage = "/images/experienced.png"
const experienced_image = userdata !== undefined && userdata !== null && userdata.active_org !== undefined && userdata.active_org.image !== undefined && userdata.active_org.image !== null && userdata.active_org.image !== "" ? userdata.active_org.image : defaultImage
return (
<div style={{width: 1000, margin: "auto", backgroundColor: theme.palette.platformColor, paddingBottom: 150, minHeight: 1500, }}>
<div style={{width: 1000, margin: "auto", paddingBottom: 150, minHeight: 1500, }}>
{/*
<div style={{position: "fixed", bottom: 110, right: 110, display: "flex", }}>
<img src="/images/Arrow.png" style={{width: 250, height: "100%",}} />
@@ -439,14 +453,14 @@ const Welcome = (props) => {
</Typography>
</div>
*/}
<Typography variant="h4" style={{color: "#F1F1F1", textAlign: "center", paddingRight: "300px"}}>
Help us get to know you.
<Typography variant="h4" style={{color: "#F1F1F1", textAlign: "center", marginTop: 50, }}>
Help us get to know you
</Typography>
<Typography variant="body1" style={{color: "#9E9E9E", textAlign: "center", marginBottom: 50, paddingRight: "366px"}}>
Let us help you create a smoother journey.
<Typography variant="body1" style={{color: "#9E9E9E", textAlign: "center", marginBottom: 50,}}>
We will use this information to personalize your automation
</Typography>
<div style={{display: "flex", marginTop: 70, width: 700, margin: "auto",}}>
<div style={{border: "1px solid #806BFF",}}>
<div style={{border: "1px solid #806BFF", borderRadius: theme.palette.borderRadius, }}>
<Card style={paperObject} onClick={() => {
if (isCloud) {
ReactGA.event({
@@ -466,7 +480,7 @@ const Welcome = (props) => {
New to Shuffle
</Typography>
<Typography variant="body1" style={{marginTop: 10, color: "rgba(255,255,255,0.8)"}}>
Let us guide you for an easier experience.
Let us guide you for an easier experience
</Typography>
</CardActionArea>
</Card>
@@ -488,37 +502,38 @@ const Welcome = (props) => {
navigate("/workflows?message=Skipped intro")
}}>
<CardActionArea style={actionObject}>
<img src={experienced_image} style={{padding: "38px", objectFit: "scale-down", minHeight: 40, maxHeight: 40, }} />
<img src={experienced_image} style={{padding: experienced_image === defaultImage ? 38 : 10, objectFit: "scale-down", minHeight: experienced_image === defaultImage ? 40 : 70, maxHeight: experienced_image === defaultImage ? 40 : 70, bordeRadius: theme.palette.borderRadius, }} />
<Typography variant="h4" style={{color: "#F1F1F1"}}>
Experienced
</Typography>
<Typography variant="body1" style={{marginTop: 10, color: "rgba(255,255,255,0.8)"}}>
You will head to Shuffle right away.
Head to Shuffle right away
</Typography>
</CardActionArea>
</Card>
</div>
{/*
<div style={{display: "flex", flexDirection: "row", }}>
<Button variant="contained" type="submit" fullWidth style={buttonStyle} onClick={() => {
navigate("/workflows?message=Skipped intro")
navigate("/workflows?message=Skipped intro continue")
}}>
Continue
</Button>
</div>
{/*
<div style={{margin: "auto", border: "1px solid rgba(255,255,255,0.5)", borderRadius: theme.palette.borderRadius, marginTop: 50, width: 200, overflow: "wrap", padding: 25, cursor: "pointer", }} onClick={() => {
*/}
<div style={{margin: "auto", borderRadius: theme.palette.borderRadius, marginTop: 50, width: 200, overflow: "wrap", padding: 25, cursor: "pointer", }} onClick={() => {
if (window.drift !== undefined) {
window.drift.api.startInteraction({ interactionId: 341911 })
window.drift.api.startInteraction({ interactionId: 340045 })
} else {
console.log("Couldn't find drift in window.drift and not .drift-open-chat with querySelector: ", window.drift)
}
}}>
<Typography variant="body1" style={{margin: "auto", textAlign: "center"}}>
Want a free Proof of Value with our support team?
Want a demo instead?
</Typography>
</div>
*/}
</div>
</Fade>
}
+20
View File
@@ -3447,6 +3447,26 @@ const Workflows = (props) => {
</div>
) : null}
{/*userdata.priorities !== undefined && userdata.priorities !== null && userdata.priorities.length > 0 ?
<div style={{width: "100%", border: "1px solid rgba(255,255,255,0.1)", borderRadius: theme.palette.borderRadius, marginTop: 10, marginBottom: 10, padding: 15, textAlign: "center", height: 70, textAlign: "left", backgroundColor: theme.palette.surfaceColor, display: "flex", }}>
<div style={{flex: 2, overflow: "hidden",}}>
<Typography variant="body1" >
{userdata.priorities[0].name}
</Typography>
<Typography variant="body2" color="textSecondary">
{userdata.priorities[0].description}
</Typography>
</div>
<div style={{flex: 1, display: "flex", marginLeft: 30, }}>
<Button style={{height: 50, borderRadius: 25, marginTop: 8, width: 200, }} variant="contained" color="secondary" onClick={() => {navigate(userdata.priorities[0].url)}}>
Continue
</Button>
<Button style={{borderRadius: 25, width: 200, height: 50, marginTop: 8, }} variant="text" color="secondary">
Ignore
</Button>
</div>
</div>
: null*/}
<div style={{marginTop: 15, }}>
{view === "grid" ? (