Cache contains, Variables, App Activation and Subflow fixes

This commit is contained in:
frikky
2023-04-14 08:43:04 +02:00
parent 27457637c1
commit 30ba687d60
8 changed files with 770 additions and 487 deletions
+21 -29
View File
@@ -842,7 +842,7 @@ func handleRemoteDownloadApp(resp http.ResponseWriter, ctx context.Context, user
app := tmpapp{}
err := json.Unmarshal(respBody, &app)
if err != nil || app.Success == false || len(app.OpenAPI) == 0 {
log.Printf("[ERROR] Failed app unmarshal during auto-download. Success%#v. Applength: %d: %s", app.Success, len(app.OpenAPI), err)
log.Printf("[ERROR] Failed app unmarshal during auto-download. Success: %#v. Applength: %d: %s", app.Success, len(app.OpenAPI), err)
resp.WriteHeader(401)
resp.Write([]byte(`{"success": false, "reason": "App doesn't exist"}`))
return
@@ -960,37 +960,29 @@ func activateWorkflowAppDocker(resp http.ResponseWriter, request *http.Request)
}
}
if app.Sharing || app.Public {
org, err := shuffle.GetOrg(ctx, user.ActiveOrg.Id)
if err == nil {
added := false
if !shuffle.ArrayContains(org.ActiveApps, app.ID) {
org.ActiveApps = append(org.ActiveApps, app.ID)
added = true
}
if added {
err = shuffle.SetOrg(ctx, *org, org.Id)
if err != nil {
log.Printf("[WARNING] Failed setting org when autoadding apps on save: %s", err)
} else {
log.Printf("[INFO] Added public app %s (%s) to org %s (%s)", app.Name, app.ID, user.ActiveOrg.Name, user.ActiveOrg.Id)
cacheKey := fmt.Sprintf("apps_%s", user.Id)
shuffle.DeleteCache(ctx, cacheKey)
}
}
}
} else {
log.Printf("[WARNING] User is trying to activate %s which is NOT public", app.Name)
resp.WriteHeader(401)
resp.Write([]byte(`{"success": false}`))
// Just making sure it's being built properly
if app == nil {
log.Printf("[WARNING] App is nil. This shouldn't happen. Starting remote download(3)")
handleRemoteDownloadApp(resp, ctx, user, fileId)
return
}
log.Printf("[DEBUG] App %s (%s) activated for org %s by user %s", app.Name, app.ID, user.ActiveOrg.Id, user.Username)
// Check the app.. hmm
openApiApp, err := shuffle.GetOpenApiDatastore(ctx, app.ID)
if err != nil {
log.Printf("[WARNING] Error getting app %s (openapi config): %s", app.ID, err)
resp.WriteHeader(401)
resp.Write([]byte(`{"success": false, "reason": "Couldn't find app OpenAPI"}`))
return
}
// If onprem, it should autobuild the container(s) from here
log.Printf("[INFO] User %s (%s) is activating %s. Public: %t, Shared: %t", user.Username, user.Id, app.Name, app.Public, app.Sharing)
buildSwaggerApp(resp, []byte(openApiApp.Body), user, true)
resp.WriteHeader(200)
resp.Write([]byte(`{"success": true}`))
//app.Active = true
//app.Generated = true
//app, err := shuffle.SetApp(ctx, app)
//resp.WriteHeader(200)
//resp.Write([]byte(`{"success": true}`))
}
+1 -1
View File
@@ -19,7 +19,7 @@ require (
github.com/gorilla/mux v1.8.0
github.com/h2non/filetype v1.1.3
github.com/satori/go.uuid v1.2.0
github.com/shuffle/shuffle-shared v0.4.1
github.com/shuffle/shuffle-shared v0.4.2
golang.org/x/crypto v0.3.0
google.golang.org/api v0.103.0
google.golang.org/appengine v1.6.7
+1 -1
View File
@@ -1161,7 +1161,7 @@ func executeWorkflow(resp http.ResponseWriter, request *http.Request) {
}
}
log.Printf("[INFO] Starting execution of %s!", fileId)
log.Printf("[AUDIT] Starting execution of workflow '%s' by user %s (%s)!", fileId, user.Username, user.Id)
user.ActiveOrg.Users = []shuffle.UserMini{}
workflow.ExecutingOrg = user.ActiveOrg
+14 -16
View File
@@ -146,17 +146,18 @@ const ConfigureWorkflow = (props) => {
app: {},
steps: [],
show_steps: false,
};
}
const app = apps.find(
(app) =>
app.name === action.app_name &&
(app.app_version === action.app_version ||
(app.loop_versions !== null &&
app.loop_versions.includes(action.app_version)))
//console.log("Action: ", key, keyval)
const app = apps.find((app) =>
app.id === action.app_id ||
(app.name === action.app_name &&
(app.app_version === action.app_version || (app.loop_versions !== null && app.loop_versions.includes(action.app_version))))
)
//newaction.steps = wazuhSteps
//console.log("FOUND APP: ", app)
if (app === undefined || app === null) {
const subapp = apps.find(app => app.name === action.app_name)
if (subapp !== undefined && subapp !== null) {
@@ -265,17 +266,14 @@ const ConfigureWorkflow = (props) => {
if (workflow.workflow_variables !== undefined && workflow.workflow_variables !== null && workflow.workflow_variables.length !== 0) {
for (let [key,keyval] in Object.entries(workflow.workflow_variables)) {
const variable = workflow.workflow_variables[key];
if (
variable.value === undefined ||
variable.value === undefined ||
variable.value.length < 2
) {
if (variable.value === undefined || variable.value === undefined || variable.value.length === 0) {
variable.value = "";
variable.index = key;
requiredVariables.push(variable);
}
variable.index = key;
}
}
}
if (workflow.triggers !== undefined && workflow.triggers !== null && workflow.triggers.length !== 0) {
for (let [key,keyval] in Object.entries(workflow.triggers)) {
@@ -1015,7 +1013,7 @@ const ConfigureWorkflow = (props) => {
<List>
{requiredActions.map((data, index) => {
return (
<div>
<div key={index}>
{data.steps !== undefined && data.steps !== null && data.show_steps === true ?
<AppWrapper data={data} parentindex={index} />
:
+221 -230
View File
@@ -1909,7 +1909,7 @@ const AngularWorkflow = (defaultprops) => {
};
const getWorkflow = (workflow_id, sourcenode) => {
fetch(globalUrl + "/api/v1/workflows/" + workflow_id, {
fetch(`${globalUrl}/api/v1/workflows/${workflow_id}`, {
method: "GET",
headers: {
"Content-Type": "application/json",
@@ -1920,12 +1920,25 @@ const AngularWorkflow = (defaultprops) => {
.then((response) => {
if (response.status !== 200) {
console.log("Status not 200 for workflows :O!");
window.location.pathname = "/workflows";
if (response.status >= 500) {
alert.info("Something went wrong while loading the workflow. Please reload.")
} else {
alert.info("You don't access to this workflow or loading failed.")
window.location.pathname = "/workflows";
}
}
// Read text from stream
//return response.text();
return response.json();
})
.then((responseJson) => {
// Load as JSON
//console.log("Got workflow TXT: ", responseText)
//const responseJson = JSON.parse(responseText)
//console.log("Got workflow JSON: ", responseJson)
// Not sure why this is necessary.
if (responseJson.isValid === undefined) {
responseJson.isValid = true;
@@ -2145,7 +2158,6 @@ const AngularWorkflow = (defaultprops) => {
setWorkflowDone(true);
// Add error checks
console.log("Workflow: ", responseJson);
if (!responseJson.public) {
if (
!responseJson.previously_saved ||
@@ -2517,8 +2529,6 @@ const AngularWorkflow = (defaultprops) => {
cy.add(decoratorNode)
}
} else {
// Readding the icon after moving the node
if (!found) {
const iconInfo = GetIconInfo(nodedata);
@@ -3187,7 +3197,7 @@ const AngularWorkflow = (defaultprops) => {
}
const activateApp = (appid, refresh) => {
fetch(globalUrl + "/api/v1/apps/" + appid + "/activate", {
fetch(`${globalUrl}/api/v1/apps/${appid}/activate`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
@@ -3204,11 +3214,10 @@ const AngularWorkflow = (defaultprops) => {
})
.then((responseJson) => {
if (responseJson.success === false) {
alert.error("Failed to activate the app")
alert.error("Failed to auto-activate the app. Go to /apps and activate it.")
} else {
alert.success("App activated for your organization! Refresh the page to use the app.")
if (refresh === true) {
alert.success("App activated for your organization! Refresh the page to use the app.")
getApps()
}
}
@@ -3939,6 +3948,7 @@ const AngularWorkflow = (defaultprops) => {
workflow.branches = workflow.branches.filter(
(a) => a.id !== edge.data().id
);
setWorkflow(workflow);
event.target.remove();
@@ -5591,7 +5601,9 @@ const AngularWorkflow = (defaultprops) => {
display: "flex",
};
const VariablesView = () => {
const VariableItem = (props) => {
const { variable, index, type } = props;
const [open, setOpen] = React.useState(false);
const [anchorEl, setAnchorEl] = React.useState(null);
@@ -5600,29 +5612,148 @@ const AngularWorkflow = (defaultprops) => {
setAnchorEl(event.currentTarget);
};
const deleteVariable = (variableIndex) => {
//console.log("Delete:", variableName);
if (workflow.workflow_variables !== undefined && workflow.workflow_variables !== null && workflow.workflow_variables.length > variableIndex) {
workflow.workflow_variables.splice(variableIndex, 1)
}
const deleteVariable = (type, variableIndex) => {
//workflow.workflow_variables = workflow.workflow_variables.filter(
// (data) => data.name !== variableName
//);
setWorkflow(workflow);
console.log("Delete type: ", type, variableIndex)
if (type === "normal") {
if (workflow.workflow_variables !== undefined && workflow.workflow_variables !== null && workflow.workflow_variables.length > variableIndex) {
var vars = JSON.parse(JSON.stringify(workflow.workflow_variables))
vars.splice(variableIndex, 1)
workflow.workflow_variables = vars
console.log("Workflow after del: ", workflow)
setWorkflow(workflow);
setUpdate(Math.random());
}
} else if (type === "exec") {
if (workflow.execution_variables !== undefined && workflow.execution_variables !== null && workflow.execution_variables.length > variableIndex) {
var vars = JSON.parse(JSON.stringify(workflow.execution_variables))
vars.splice(variableIndex, 1)
workflow.execution_variables = vars
console.log("Workflow after del: ", workflow)
setWorkflow(workflow);
setUpdate(Math.random());
}
}
};
const deleteExecutionVariable = (variableIndex) => {
if (workflow.execution_variables !== undefined && workflow.execution_variables !== null && workflow.execution_variables.length > variableIndex) {
workflow.execution_variables.splice(variableIndex, 1)
}
return (
<div key={index}>
<Paper square style={paperVariableStyle} onClick={() => { }}>
<div
style={{
marginLeft: "10px",
marginTop: "5px",
marginBottom: "5px",
width: "2px",
backgroundColor: yellow,
marginRight: "5px",
}}
/>
<div style={{ display: "flex", width: "100%" }}>
<div
style={{
flex: "10",
marginTop: "15px",
marginLeft: "10px",
overflow: "hidden",
}}
onClick={() => {
setVariableInfo({
"name": variable.name,
"description": variable.description,
"value": variable.value,
"index": index,
})
//workflow.execution_variables = workflow.execution_variables.filter(
// (data) => data.name !== variableName
//);
setWorkflow(workflow);
};
if (type === "normal") {
setVariablesModalOpen(true);
} else if (type === "exec") {
setExecutionVariablesModalOpen(true);
} else {
console.log("Unknown type: ", type)
}
}}
>
Name: {variable.name}
</div>
<div style={{ flex: "1", marginLeft: "0px" }}>
<IconButton
aria-label="more"
aria-controls="long-menu"
aria-haspopup="true"
onClick={menuClick}
style={{ color: "white" }}
>
<MoreVertIcon />
</IconButton>
<Menu
id="long-menu"
anchorEl={anchorEl}
keepMounted
open={open}
PaperProps={{
style: {
backgroundColor: surfaceColor,
},
}}
onClose={() => {
setOpen(false);
setAnchorEl(null);
}}
>
<MenuItem
style={{
backgroundColor: inputColor,
color: "white",
}}
onClick={() => {
setOpen(false);
setVariableInfo({
"name": variable.name,
"description": variable.description,
"value": variable.value,
"index": index,
})
if (type === "normal") {
setVariablesModalOpen(true);
} else if (type === "exec") {
setExecutionVariablesModalOpen(true);
} else {
console.log("Unknown type: ", type)
}
}}
key={"Edit"}
>
{"Edit"}
</MenuItem>
<MenuItem
style={{
backgroundColor: inputColor,
color: "white",
}}
onClick={() => {
deleteVariable(type, index);
setOpen(false);
}}
key={"Delete"}
>
{"Delete"}
</MenuItem>
</Menu>
</div>
</div>
</Paper>
</div>
)
}
const VariablesView = () => {
const variableScrollStyle = {
margin: 15,
overflow: "scroll",
@@ -5642,108 +5773,20 @@ const AngularWorkflow = (defaultprops) => {
target="_blank"
style={{ textDecoration: "none", color: "#f85a3e" }}
>
WORKFLOW variables?
Workflow variables?
</a>
{workflow.workflow_variables === null
? null
: workflow.workflow_variables.map((variable, index) => {
: workflow.workflow_variables.map((variable, varindex) => {
return (
<div key={index}>
<Paper square style={paperVariableStyle} onClick={() => { }}>
<div
style={{
marginLeft: "10px",
marginTop: "5px",
marginBottom: "5px",
width: "2px",
backgroundColor: yellow,
marginRight: "5px",
}}
/>
<div style={{ display: "flex", width: "100%" }}>
<div
style={{
flex: "10",
marginTop: "15px",
marginLeft: "10px",
overflow: "hidden",
}}
onClick={() => {
setVariableInfo({
"name": variable.name,
"description": variable.description,
"value": variable.value,
"index": index,
})
setVariablesModalOpen(true);
}}
>
Name: {variable.name}
</div>
<div style={{ flex: "1", marginLeft: "0px" }}>
<IconButton
aria-label="more"
aria-controls="long-menu"
aria-haspopup="true"
onClick={menuClick}
style={{ color: "white" }}
>
<MoreVertIcon />
</IconButton>
<Menu
id="long-menu"
anchorEl={anchorEl}
keepMounted
open={open}
PaperProps={{
style: {
backgroundColor: surfaceColor,
},
}}
onClose={() => {
setOpen(false);
setAnchorEl(null);
}}
>
<MenuItem
style={{
backgroundColor: inputColor,
color: "white",
}}
onClick={() => {
setOpen(false);
setVariableInfo({
"name": variable.name,
"description": variable.description,
"value": variable.value,
"index": index,
})
setVariablesModalOpen(true);
}}
key={"Edit"}
>
{"Edit"}
</MenuItem>
<MenuItem
style={{
backgroundColor: inputColor,
color: "white",
}}
onClick={() => {
deleteVariable(index);
setOpen(false);
}}
key={"Delete"}
>
{"Delete"}
</MenuItem>
</Menu>
</div>
</div>
</Paper>
</div>
<VariableItem
variable={variable}
index={varindex}
type={"normal"}
/>
);
})}
})}
<div style={{ flex: "1" }}>
<Button
fullWidth
@@ -5753,6 +5796,12 @@ const AngularWorkflow = (defaultprops) => {
onClick={() => {
setVariablesModalOpen(true);
setLastSaved(false);
setVariableInfo({
"name": "",
"description": "",
"value": "",
})
}}
>
New workflow variable
@@ -5774,109 +5823,18 @@ const AngularWorkflow = (defaultprops) => {
target="_blank"
style={{ textDecoration: "none", color: "#f85a3e" }}
>
EXECUTION variables?
Runtime variables?
</a>
{workflow.execution_variables === null ||
workflow.execution_variables === undefined
? null
: workflow.execution_variables.map((variable, index) => {
: workflow.execution_variables.map((variable, varindex2) => {
return (
<div>
<Paper square style={paperVariableStyle} onClick={() => { }}>
<div
style={{
marginLeft: "10px",
marginTop: "5px",
marginBottom: "5px",
width: "2px",
backgroundColor: yellow,
marginRight: "5px",
}}
/>
<div style={{ display: "flex", width: "100%" }}>
<div
style={{
flex: "10",
marginTop: "15px",
marginLeft: "10px",
overflow: "hidden",
}}
onClick={() => {
//setNewVariableName(variable.name);
setVariableInfo({
"name": variable.name,
"description": variable.description,
"value": variable.value,
"index": index,
})
setExecutionVariablesModalOpen(true);
}}
>
Name: {variable.name}
</div>
<div style={{ flex: "1", marginLeft: "0px" }}>
<IconButton
aria-label="more"
aria-controls="long-menu"
aria-haspopup="true"
onClick={menuClick}
style={{ color: "white" }}
>
<MoreVertIcon />
</IconButton>
<Menu
id="long-menu"
anchorEl={anchorEl}
keepMounted
open={open}
PaperProps={{
style: {
backgroundColor: surfaceColor,
},
}}
onClose={() => {
setOpen(false);
setAnchorEl(null);
}}
>
<MenuItem
style={{
backgroundColor: inputColor,
color: "white",
}}
onClick={() => {
setOpen(false);
//setNewVariableName(variable.name);
setVariableInfo({
"name": variable.name,
"description": variable.description,
"value": variable.value,
"index": index,
})
setExecutionVariablesModalOpen(true);
}}
key={"Edit"}
>
{"Edit"}
</MenuItem>
<MenuItem
style={{
backgroundColor: inputColor,
color: "white",
}}
onClick={() => {
deleteExecutionVariable(index);
setOpen(false);
}}
key={"Delete"}
>
{"Delete"}
</MenuItem>
</Menu>
</div>
</div>
</Paper>
</div>
<VariableItem
variable={variable}
index={varindex2}
type={"exec"}
/>
);
})}
<div style={{ flex: "1" }}>
@@ -5888,6 +5846,12 @@ const AngularWorkflow = (defaultprops) => {
onClick={() => {
setExecutionVariablesModalOpen(true);
setLastSaved(false);
setVariableInfo({
"name": "",
"description": "",
"value": "",
})
}}
>
New execution variable
@@ -6401,6 +6365,13 @@ const AngularWorkflow = (defaultprops) => {
};
// FIXME: overwrite category if the ACTION chosen has a different category
//
if (!isCloud && (!app.is_valid || (!app.activated && app.generated))) {
console.log("NOT VALID: Activate!")
activateApp(app.id, false)
}
// const image = "url("+app.large_image+")"
// FIXME - find the cytoscape offset position
@@ -7539,11 +7510,7 @@ const AngularWorkflow = (defaultprops) => {
example: "tmp",
})
if (
workflow.workflow_variables !== null &&
workflow.workflow_variables !== undefined &&
workflow.workflow_variables.length > 0
) {
if (workflow.workflow_variables !== null && workflow.workflow_variables !== undefined && workflow.workflow_variables.length > 0) {
for (let varkey in workflow.workflow_variables) {
const item = workflow.workflow_variables[varkey];
actionlist.push({
@@ -14841,6 +14808,8 @@ const AngularWorkflow = (defaultprops) => {
aria-labelledby="draggable-dialog-title"
onClose={() => {
setNewVariableName("");
setNewVariableValue("");
setExecutionVariablesModalOpen(false);
}}
PaperProps={{
@@ -14849,7 +14818,8 @@ const AngularWorkflow = (defaultprops) => {
backgroundColor: surfaceColor,
color: "white",
border: theme.palette.defaultBorder,
maxWidth: "100%",
maxWidth: isMobile ? bodyWidth - 100 : 800,
minWidth: isMobile ? bodyWidth - 100 : 800,
},
}}
>
@@ -14879,15 +14849,32 @@ const AngularWorkflow = (defaultprops) => {
},
}}
margin="dense"
label="Name"
fullWidth
defaultValue={newVariableName}
/>
<TextField
onBlur={(event) => setNewVariableValue(event.target.value)}
color="primary"
placeholder="Default Value (optional)"
style={{ marginTop: 25 }}
InputProps={{
style: {
color: "white",
},
}}
margin="dense"
label="Default Value (optional)"
fullWidth
defaultValue={newVariableValue}
/>
</DialogContent>
<DialogActions>
<Button
style={{ borderRadius: "0px" }}
onClick={() => {
setNewVariableName("");
setNewVariableValue("");
setExecutionVariablesModalOpen(false);
}}
color="primary"
@@ -14916,11 +14903,15 @@ const AngularWorkflow = (defaultprops) => {
if (newVariableName.length > 0) {
workflow.execution_variables[found].name = newVariableName;
}
if (newVariableValue.length > 0) {
workflow.execution_variables[found].value = newVariableValue;
}
} else {
workflow.execution_variables.push({
name: newVariableName,
value: newVariableValue,
description: "An execution variable",
value: "",
id: uuidv4(),
});
}
+1 -1
View File
@@ -11,7 +11,7 @@ require (
github.com/gorilla/mux v1.8.0
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/satori/go.uuid v1.2.0
github.com/shuffle/shuffle-shared v0.3.75
github.com/shuffle/shuffle-shared v0.4.2
)
require (
+2
View File
@@ -216,6 +216,8 @@ github.com/shuffle/shuffle-shared v0.3.51 h1:+JPEGw6R4a320who+SrGP/VqBxZdKPdcLw/
github.com/shuffle/shuffle-shared v0.3.51/go.mod h1:jQrYySmvp/0De5ftrAaY6xwwr7TMfqBmBxQ2AX9yrjQ=
github.com/shuffle/shuffle-shared v0.3.74 h1:i7M1Gug9j2Wa02WuSxKDbXoLvBWKW5Pxf/EpFy6v38Y=
github.com/shuffle/shuffle-shared v0.3.74/go.mod h1:jQrYySmvp/0De5ftrAaY6xwwr7TMfqBmBxQ2AX9yrjQ=
github.com/shuffle/shuffle-shared v0.4.2 h1:GzDAOHN4YMMLzRmmToyO/KSYDziRuEuxLheawlAY3Rk=
github.com/shuffle/shuffle-shared v0.4.2/go.mod h1:jQrYySmvp/0De5ftrAaY6xwwr7TMfqBmBxQ2AX9yrjQ=
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
File diff suppressed because it is too large Load Diff