From 101f878643ce77c3c47b7cfa02480f306cfbbfb4 Mon Sep 17 00:00:00 2001 From: frikky Date: Wed, 1 Dec 2021 22:22:50 +0100 Subject: [PATCH 01/42] Fixed a copy bug for firefox --- docker-compose.yml | 4 +-- frontend/src/views/Admin.jsx | 10 +++----- frontend/src/views/AngularWorkflow.jsx | 35 ++++++++++++++++++++++---- frontend/src/views/Docs.jsx | 8 +++--- frontend/src/views/SettingsPage.jsx | 6 ++--- frontend/src/views/Workflows.jsx | 2 +- 6 files changed, 45 insertions(+), 20 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index b03ecd3f..1a54e2ff 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ version: '3' services: frontend: - #build: ./frontend + build: ./frontend image: ghcr.io/frikky/shuffle-frontend:nightly container_name: shuffle-frontend hostname: shuffle-frontend @@ -16,7 +16,7 @@ services: depends_on: - backend backend: - build: ./backend + #build: ./backend image: ghcr.io/frikky/shuffle-backend:nightly container_name: shuffle-backend hostname: ${BACKEND_HOSTNAME} diff --git a/frontend/src/views/Admin.jsx b/frontend/src/views/Admin.jsx index a4a0de47..13ee69df 100644 --- a/frontend/src/views/Admin.jsx +++ b/frontend/src/views/Admin.jsx @@ -1764,16 +1764,14 @@ const Admin = (props) => { run2FASetup(userdata); }} disabled={ - (selectedUser.role === "admin" && - selectedUser.username !== userdata.username) || - selectedUser.active === false + (selectedUser.role === "admin" && selectedUser.username !== userdata.username) } variant="outlined" color="primary" > - {selectedUser.mfa_info !== undefined && - selectedUser.mfa_info !== null && - selectedUser.mfa_info.active === true + { selectedUser.mfa_info !== undefined && + selectedUser.mfa_info !== null && + selectedUser.mfa_info.active === true ? "Disable 2FA" : "Enable 2FA"} diff --git a/frontend/src/views/AngularWorkflow.jsx b/frontend/src/views/AngularWorkflow.jsx index 2643c0ec..3c2c62c4 100644 --- a/frontend/src/views/AngularWorkflow.jsx +++ b/frontend/src/views/AngularWorkflow.jsx @@ -2983,6 +2983,16 @@ const AngularWorkflow = (props) => { } } + if ( + event.target !== undefined && + event.target !== null + ) { + if (event.target.localName !== "body") { + console.log("Skipping because body is not targeted") + return; + } + } + console.log("CTRL+C"); if (cy !== undefined) { var cydata = cy.$(":selected").jsons(); @@ -3051,18 +3061,30 @@ const AngularWorkflow = (props) => { }; const handlePaste = (event) => { - //console.log(event) + //console.log("EV: ", event) if ( event.path !== undefined && event.path !== null && event.path.length > 0 ) { - //console.log(event.path[0]) + console.log("PATH: ", event.path[0]) if (event.path[0].localName !== "body") { //console.log("Skipping because body is not targeted") return; } - } + } + + console.log("PATH2: ", event.target) + if ( + event.target !== undefined && + event.target !== null + ) { + if (event.target.localName !== "body") { + //console.log("Skipping because body is not targeted") + return; + } + } + event.preventDefault(); const clipboard = (event.originalEvent || event).clipboardData.getData( @@ -3078,6 +3100,7 @@ const AngularWorkflow = (props) => { for (var key in parsedjson) { const item = parsedjson[key]; console.log("Adding: ", item); + item.data.id = uuidv4() cy.add({ group: item.group, @@ -5025,7 +5048,7 @@ const AngularWorkflow = (props) => { : -
+
{extraMessage}
@@ -10571,7 +10594,9 @@ const AngularWorkflow = (props) => { executionData.completed_at !== null && executionData.completed_at > 0 ? (
- + { + console.log(executionData) + }}> Finished   diff --git a/frontend/src/views/Docs.jsx b/frontend/src/views/Docs.jsx index 6c3df78d..a99f39c4 100644 --- a/frontend/src/views/Docs.jsx +++ b/frontend/src/views/Docs.jsx @@ -72,13 +72,14 @@ const Docs = (props) => { position: "relative", padding: 30, paddingTop: 15, - height: "80vh", marginTop: 15, + minHeight: "50vh", + //height: "50vh", }; const SideBar = { maxWidth: 250, - flex: "1", + flex: 1, position: "fixed", }; @@ -649,8 +650,9 @@ const Docs = (props) => { // // {imageModal} + // Padding and zIndex etc set because of footer in cloud. const loadedCheck = ( -
+
{postDataBrowser} {postDataMobile}
diff --git a/frontend/src/views/SettingsPage.jsx b/frontend/src/views/SettingsPage.jsx index 7c6a4a87..7f60aef0 100644 --- a/frontend/src/views/SettingsPage.jsx +++ b/frontend/src/views/SettingsPage.jsx @@ -384,12 +384,12 @@ const Settings = (props) => { {data.name} - {data.collection.name} + {data.collection} {data.name} @@ -746,7 +746,7 @@ const Settings = (props) => { > ethereum-icon diff --git a/frontend/src/views/Workflows.jsx b/frontend/src/views/Workflows.jsx index 1bd9abf1..f717f9c5 100644 --- a/frontend/src/views/Workflows.jsx +++ b/frontend/src/views/Workflows.jsx @@ -2521,8 +2521,8 @@ const Workflows = (props) => { Learn more about Workflows From 05cbc93c0981b22ebbd0e18876461a34008856d8 Mon Sep 17 00:00:00 2001 From: frikky Date: Thu, 2 Dec 2021 00:38:37 +0100 Subject: [PATCH 02/42] Cleaned up compose and upgraded backend shared version --- backend/go-app/go.mod | 2 +- docker-compose.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/go-app/go.mod b/backend/go-app/go.mod index c08245ed..a479da25 100644 --- a/backend/go-app/go.mod +++ b/backend/go-app/go.mod @@ -22,7 +22,7 @@ require ( github.com/gorilla/mux v1.8.0 github.com/h2non/filetype v1.1.1 github.com/satori/go.uuid v1.2.0 - github.com/shuffle/shuffle-shared v0.1.44 + github.com/shuffle/shuffle-shared v0.1.50 github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect go4.org v0.0.0-20201209231011-d4a079459e60 // indirect golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 diff --git a/docker-compose.yml b/docker-compose.yml index 1a54e2ff..8a8ba025 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ version: '3' services: frontend: - build: ./frontend + #build: ./frontend image: ghcr.io/frikky/shuffle-frontend:nightly container_name: shuffle-frontend hostname: shuffle-frontend From 80519e3c06c4912d0c0a67707245bca5781d8328 Mon Sep 17 00:00:00 2001 From: frikky Date: Thu, 2 Dec 2021 16:57:28 +0100 Subject: [PATCH 03/42] Added better README overview --- README.md | 20 +++++++++++++++++--- frontend/src/views/AngularWorkflow.jsx | 2 +- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c09bd090..ed65911c 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,21 @@ -# Shuffle -[Shuffle](https://shuffler.io) is an automation platform focused on accessibility. We believe everyone should have access to efficient processes, and are striving to make that a possibility by making integrations for YOUR tools. Security Operations is complex, but it doesn't have to be. +

-[![Discord](https://img.shields.io/discord/463752820026376202.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/B2CBzUm) +[![Shuffle Logo](https://shuffler.io/images/white_logo_new.png)](https://shuffler.io) + +Shuffle Automation + +

+[Shuffle](https://shuffler.io) is an automation platform for and by the community, focusing on accessibility for anyone to automate. Security operations is complex, but it doesn't have to be. + +[_Key Features_](https://shuffler.io/docs/features) — +[_Community & Support_](https://discord.gg/B2CBzUm) +[_Documentation_](https://shuffler.io/docs) — +[_Getting Started_](https://shuffler.io/docs/getting_started) — +[_Development_](https://github.com/frikky/Shuffle/blob/master/.github/CONTRIBUTING.md) — + +Follow us on Twitter at [@shuffleio](https://twitter.com/shuffleio). + +

![Example Shuffle webhook integration](https://github.com/frikky/Shuffle/blob/master/frontend/src/assets/img/github_shuffle_img.png) diff --git a/frontend/src/views/AngularWorkflow.jsx b/frontend/src/views/AngularWorkflow.jsx index 3c2c62c4..76faca3e 100644 --- a/frontend/src/views/AngularWorkflow.jsx +++ b/frontend/src/views/AngularWorkflow.jsx @@ -6723,7 +6723,7 @@ const AngularWorkflow = (props) => { }} />
- Select folders + Select {triggerAuthentication.type === "gmail" ? "labels" : "folders"} (CTRL+click)
{ borderRadius: theme.palette.borderRadius, }} > - {environments.map((data) => { - if (data.archived) { + {environments.map((data, index) => { + if (data.archived === true) { return null; } return ( { newActionname = data.label; } + var newActiondescription = data.description; + console.log("DESC: ", newActiondescription) + if ( + data.description === undefined || data.description === null + ) { + newActiondescription = "Description: No description defined for this action" + } else { + newActiondescription = "Description: "+newActiondescription + } + const iconInfo = GetIconInfo({ name: data.name }); const useIcon = iconInfo.originalIcon; @@ -2671,32 +2682,40 @@ const ParsedAction = (props) => { newActionname.substring(1) ).replaceAll("_", " "); + + return ( -
- - {useIcon} - - {newActionname} -
+ +
+ + {useIcon} + + {newActionname} +
+
); }} renderInput={(params) => { return ( - + ); }} /> diff --git a/frontend/src/views/AngularWorkflow.jsx b/frontend/src/views/AngularWorkflow.jsx index 979e438b..69ecd26a 100644 --- a/frontend/src/views/AngularWorkflow.jsx +++ b/frontend/src/views/AngularWorkflow.jsx @@ -2132,6 +2132,7 @@ const AngularWorkflow = (props) => { if (data.id !== undefined && data.app_name !== undefined) { //newapps.push(data) workflow.actions.push(data) + setWorkflow(workflow) curaction = data } else { alert.error("Action not found. Please remake it."); @@ -2257,10 +2258,16 @@ const AngularWorkflow = (props) => { cy.on("free", "node", (e) => onNodeDragStop(e, curaction)); } - if (environments !== undefined && environments !== null) { - var env = environments.find((a) => a.Name === curaction.environment); + console.log("Object: ", environments) + if (environments !== undefined && environments !== null && (typeof environments === "array" || typeof environments === "object")) { + var parsedenv = environments + if (typeof environments === "object") { + parsedenv = [environments] + } + + var env = parsedenv.find((a) => a.Name === curaction.environment); if (!env || env === undefined) { - env = environments[defaultEnvironmentIndex]; + env = parsedenv[defaultEnvironmentIndex]; } setSelectedActionEnvironment(env); @@ -2384,7 +2391,13 @@ const AngularWorkflow = (props) => { // Finds the FIRST json only if (jsonvalid) { - exampledata = JSON.parse(foundResult.result); + try { + exampledata = JSON.parse(foundResult.result) + } catch (e) { + console.log("Result: ", exampledata) + + } + break; } } @@ -2596,10 +2609,17 @@ const AngularWorkflow = (props) => { } } + const eventTarget = event.target.target() + console.log("BUTTON! Find parent from: ", eventTarget) + if (eventTarget.data("isButton") === true) { + console.log("ACTUALLY A BUTTON!") + } + if ( - event.target.target().data("isButton") === true || - event.target.target().data("isDescriptor") === true + eventTarget.data("isDescriptor") === true || + eventTarget.data("type") === "COMMENT" ) { + console.log("Removing because of descriptor or comment") event.target.remove(); return; } @@ -3152,9 +3172,9 @@ const AngularWorkflow = (props) => { if (response.status !== 200) { console.log("Status not 200 for apps :O!"); if (isCloud) { - setEnvironments({ name: "Cloud", type: "cloud" }); + setEnvironments([{ Name: "Cloud", Type: "cloud" }]); } else { - setEnvironments({ name: "Onprem", type: "onprem" }); + setEnvironments([{ Name: "Onprem", Type: "onprem" }]); } return; @@ -3191,7 +3211,7 @@ const AngularWorkflow = (props) => { // FIXME: Don't allow multiple in cloud yet. Cloud -> Onprem isn't stable. if (isCloud) { - setEnvironments({ name: "Cloud", type: "cloud" }); + setEnvironments([{ Name: "Cloud", Type: "cloud" }]); } else { setEnvironments(responseJson); } @@ -3505,9 +3525,11 @@ const AngularWorkflow = (props) => { const onNodeHover = (event) => { const nodedata = event.target.data(); - if (nodedata.finished === false) { - return; - } + + //console.log("NODE: ", nodedata) + //if (nodedata.finished === false) { + // return; + //} //var parentNode = cy.$("#" + event.target.data("id")); //if (parentNode.data("isButton") || parentNode.data("buttonId")) return; @@ -10141,6 +10163,9 @@ const AngularWorkflow = (props) => { /* Copy the text inside the text field */ document.execCommand("copy"); + + console.log("COPYING!"); + alert.info("Copied value to clipboard, NOT json path.") } else { console.log("Failed to copy from " + elementName + ": ", copyText); } @@ -10208,7 +10233,7 @@ const AngularWorkflow = (props) => { /* Copy the text inside the text field */ document.execCommand("copy"); console.log("COPYING!"); - alert.info("Copied value to clipboard.") + alert.info("Copied JSON path to clipboard.") } else { console.log("Couldn't find element ", elementName); } diff --git a/frontend/src/views/AppCreator.jsx b/frontend/src/views/AppCreator.jsx index c11970d8..c87694dd 100644 --- a/frontend/src/views/AppCreator.jsx +++ b/frontend/src/views/AppCreator.jsx @@ -1332,6 +1332,7 @@ const AppCreator = (props) => { } } + if (data.servers !== undefined && data.servers.length > 0) { var firstUrl = data.servers[0].url; if ( @@ -1366,123 +1367,128 @@ const AppCreator = (props) => { //console.log("SECURITY: ", securitySchemes) //if (Object.entries(securitySchemes) > 1 && var newauth = []; - for (const [key, value] of Object.entries(securitySchemes)) { - console.log(key, value); - if (key === "jwt") { - setAuthenticationOption("JWT"); - setAuthenticationRequired(true); + try { + for (const [key, value] of Object.entries(securitySchemes)) { + console.log(key, value); + if (key === "jwt") { + setAuthenticationOption("JWT"); + setAuthenticationRequired(true); - if ( - value.in !== undefined && - value.in !== null && - value.in.length > 0 - ) { - setParameterName(value.in); - } - } else if (value.scheme === "bearer") { - setAuthenticationOption("Bearer auth"); - setAuthenticationRequired(true); - } else if (key === "Oauth2" || key === "Oauth2c") { - //alert.info("Can't handle Oauth2 auth yet.") - setAuthenticationOption("Oauth2"); - setAuthenticationRequired(true); + if ( + value.in !== undefined && + value.in !== null && + value.in.length > 0 + ) { + setParameterName(value.in); + } + } else if (value.scheme === "bearer") { + setAuthenticationOption("Bearer auth"); + setAuthenticationRequired(true); + } else if (key === "Oauth2" || key === "Oauth2c") { + //alert.info("Can't handle Oauth2 auth yet.") + setAuthenticationOption("Oauth2"); + setAuthenticationRequired(true); - //console.log("FLOW-1: ", value) - const flowkey = value.flow === undefined ? "flows" : "flow"; - //console.log("FLOW: ", value[flowkey]) - const basekey = - value[flowkey].authorizationCode !== undefined - ? "authorizationCode" - : "implicit"; - //console.log("FLOW2: ", value[flowkey][basekey]) - if ( - value[flowkey] !== undefined && - value[flowkey][basekey] !== undefined - ) { - if ( - value[flowkey][basekey].authorizationUrl !== undefined && - parameterName.length === 0 - ) { - setParameterName(value[flowkey][basekey].authorizationUrl); - } + //console.log("FLOW-1: ", value) + const flowkey = value.flow === undefined ? "flows" : "flow"; + //console.log("FLOW: ", value[flowkey]) + const basekey = + value[flowkey].authorizationCode !== undefined + ? "authorizationCode" + : "implicit"; + //console.log("FLOW2: ", value[flowkey][basekey]) + if ( + value[flowkey] !== undefined && + value[flowkey][basekey] !== undefined + ) { + if ( + value[flowkey][basekey].authorizationUrl !== undefined && + parameterName.length === 0 + ) { + setParameterName(value[flowkey][basekey].authorizationUrl); + } - var tokenUrl = ""; - if (value[flowkey][basekey].tokenUrl !== undefined) { - setParameterLocation(value[flowkey][basekey].tokenUrl); - tokenUrl = value[flowkey][basekey].tokenUrl; - } else { - setParameterLocation(""); - } + var tokenUrl = ""; + if (value[flowkey][basekey].tokenUrl !== undefined) { + setParameterLocation(value[flowkey][basekey].tokenUrl); + tokenUrl = value[flowkey][basekey].tokenUrl; + } else { + setParameterLocation(""); + } - if (value[flowkey][basekey].refreshUrl !== undefined) { - setRefreshUrl(value[flowkey][basekey].refreshUrl); - } else if (tokenUrl.length > 0) { - setRefreshUrl(tokenUrl); - } + if (value[flowkey][basekey].refreshUrl !== undefined) { + setRefreshUrl(value[flowkey][basekey].refreshUrl); + } else if (tokenUrl.length > 0) { + setRefreshUrl(tokenUrl); + } - if ( - value[flowkey][basekey].scopes !== undefined && - value[flowkey][basekey].scopes !== null - ) { - if (value[flowkey][basekey].scopes.length > 0) { - setOauth2Scopes(value[flowkey][basekey].scopes); - } else { - var newscopes = []; - for (let [scopekey, scopevalue] of Object.entries( - value[flowkey][basekey].scopes - )) { - if (scopekey.startsWith("http")) { - const scopekeysplit = scopekey.split("/"); - if (scopekeysplit.length < 5) { - console.log("Skipping scope: ", scopekey); - alert.info("Skipping scope: " + scopekey); - continue; - } + if ( + value[flowkey][basekey].scopes !== undefined && + value[flowkey][basekey].scopes !== null + ) { + if (value[flowkey][basekey].scopes.length > 0) { + setOauth2Scopes(value[flowkey][basekey].scopes); + } else { + var newscopes = []; + for (let [scopekey, scopevalue] of Object.entries( + value[flowkey][basekey].scopes + )) { + if (scopekey.startsWith("http")) { + const scopekeysplit = scopekey.split("/"); + if (scopekeysplit.length < 5) { + console.log("Skipping scope: ", scopekey); + alert.info("Skipping scope: " + scopekey); + continue; + } - //console.log("Checking scope for: ", scopekey, scopekeysplit.length) - } + //console.log("Checking scope for: ", scopekey, scopekeysplit.length) + } - newscopes.push(scopekey); - } + newscopes.push(scopekey); + } - setOauth2Scopes(newscopes); - } - } - } else { - console.log( - "Bad flowkey and basekey for oauth2: ", - flowkey, - basekey - ); - } - } else if (key === "ApiKeyAuth") { - setAuthenticationOption("API key"); + setOauth2Scopes(newscopes); + } + } + } else { + console.log( + "Bad flowkey and basekey for oauth2: ", + flowkey, + basekey + ); + } + } else if (key === "ApiKeyAuth" || key === "Token") { + setAuthenticationOption("API key"); - value.in = value.in.charAt(0).toUpperCase() + value.in.slice(1); - setParameterLocation(value.in); - if (!apikeySelection.includes(value.in)) { - console.log("APIKEY SELECT: ", apikeySelection); - alert.error("Might be error in setting up API key authentication"); - } + value.in = value.in.charAt(0).toUpperCase() + value.in.slice(1); + setParameterLocation(value.in); + if (!apikeySelection.includes(value.in)) { + console.log("APIKEY SELECT: ", apikeySelection); + alert.error("Might be error in setting up API key authentication"); + } - console.log("PARAM NAME: ", value.name); - setParameterName(value.name); - setAuthenticationRequired(true); - } else if (value.scheme === "basic") { - setAuthenticationOption("Basic auth"); - setAuthenticationRequired(true); - } else if (value.scheme === "oauth2") { - setAuthenticationOption("Oauth2"); - setAuthenticationRequired(true); - } else { - alert.error("Couldn't handle AUTH type: ", key); - //newauth.push({ - // "name": key, - // "type": value.in, - // "example": "", - //}) - } - } + console.log("PARAM NAME: ", value.name); + setParameterName(value.name); + setAuthenticationRequired(true); + } else if (value.scheme === "basic") { + setAuthenticationOption("Basic auth"); + setAuthenticationRequired(true); + } else if (value.scheme === "oauth2") { + setAuthenticationOption("Oauth2"); + setAuthenticationRequired(true); + } else { + alert.error("Couldn't handle AUTH type: ", key); + //newauth.push({ + // "name": key, + // "type": value.in, + // "example": "", + //}) + } + } + } catch (e) { + alert.error("Failed to handle auth") + console.log("Error: ", e) + } if (newauth.length > 0) { setExtraAuth(newauth); @@ -2192,7 +2198,7 @@ const AppCreator = (props) => { //console.log("Location: ", parameterLocation) //console.log("Name: ", parameterName) const extraKeys = ( -
+
Extra authentication {extraAuth.length === 0 ? ( @@ -4394,7 +4400,7 @@ const AppCreator = (props) => { const imageInfo = ( { maxWidth: 250, flex: 1, position: "fixed", + maxHeight: "83vh", + overflowX: "hidden", + overflowY: "auto", }; const fetchDocList = () => { From 3f033bf73251541ccd7f0eb366593c7873847131 Mon Sep 17 00:00:00 2001 From: frikky Date: Thu, 16 Dec 2021 03:41:43 +0100 Subject: [PATCH 11/42] Added description reader for actions --- frontend/src/components/ParsedAction.jsx | 49 ++++++++++++++------- frontend/src/views/AngularWorkflow.jsx | 54 +++++++++++++++++++++++- 2 files changed, 85 insertions(+), 18 deletions(-) diff --git a/frontend/src/components/ParsedAction.jsx b/frontend/src/components/ParsedAction.jsx index d4e27bcc..e5d6ae55 100644 --- a/frontend/src/components/ParsedAction.jsx +++ b/frontend/src/components/ParsedAction.jsx @@ -170,6 +170,7 @@ const ParsedAction = (props) => { const [activateHidingBody, setActivateHidingBody] = React.useState(false); const [codedata, setcodedata] = React.useState(""); const [fieldCount, setFieldCount] = React.useState(0); + const [hiddenDescription, setHiddenDescription] = React.useState(true); const keywords = [ "len(", @@ -978,6 +979,9 @@ const ParsedAction = (props) => { return helperText } + console.log("D: ", selectedAction) + console.log("DESC: ", selectedAction.description) + console.log("DESC2: ", selectedApp.description) // FIXME: Issue #40 - selectedActionParameters not reset if ( @@ -987,7 +991,22 @@ const ParsedAction = (props) => { var authWritten = false; return (
- Parameters + + + {selectedActionParameters.map((data, count) => { if (data.variant === "") { data.variant = "STATIC_VALUE"; @@ -2665,7 +2684,7 @@ const ParsedAction = (props) => { } var newActiondescription = data.description; - console.log("DESC: ", newActiondescription) + //console.log("DESC: ", newActiondescription) if ( data.description === undefined || data.description === null ) { @@ -2756,20 +2775,18 @@ const ParsedAction = (props) => { : null*/} - {selectedAction.description !== undefined && - selectedAction.description.length > 0 && - hideExtraTypes !== true ? ( -
- {selectedAction.description} -
- ) : null} + {selectedAction.description !== undefined && selectedAction.description !== null && selectedAction.description.length > 0 && hideExtraTypes !== true && hiddenDescription === false ? ( +
+ {selectedAction.description} +
+ ) : null}
{ console.log("BUTTON! Find parent from: ", eventTarget) if (eventTarget.data("isButton") === true) { console.log("ACTUALLY A BUTTON!") + const parentNode = cy.getElementById(eventTarget.data("attachedTo")) + event.target.remove() + console.log("Setting it to parentnode: ", parentNode.data()) + if (parentNode !== undefined && parentNode !== null) { + //event.target.data("target", eventTarget.data("attachedTo")) + + const newEdgeUuid = uuidv4() + const newcybranch = { + source: event.target.data("source"), + target: eventTarget.data("attachedTo"), + _id: newEdgeUuid, + id: newEdgeUuid, + hasErrors: event.target.data("hasErrors"), + }; + + const edgeToBeAdded = { + group: "edges", + data: newcybranch, + } + + cy.add(edgeToBeAdded); + } } if ( @@ -2739,11 +2761,14 @@ const AngularWorkflow = (props) => { setLastSaved(false); const node = event.target; const nodedata = event.target.data(); - if (nodedata.finished === false || - (nodedata.id !== undefined && nodedata.is_valid === undefined) + + if (nodedata.finished === false || (nodedata.id !== undefined && nodedata.is_valid === undefined) ) { + //if (nodedata.app_id === undefined) { console.log("Returning because node is not valid: ", nodedata) return; + + //} } //parsedApp.data.finished = true; @@ -4800,6 +4825,7 @@ const AngularWorkflow = (props) => { const actionLabel = getNextActionName(app.name); var parameters = null; var example = ""; + var description = "" if ( app.actions[0].parameters !== null && @@ -4807,6 +4833,7 @@ const AngularWorkflow = (props) => { ) { parameters = app.actions[0].parameters; } + if ( app.actions[0].returns.example !== undefined && app.actions[0].returns.example !== null && @@ -4815,20 +4842,31 @@ const AngularWorkflow = (props) => { example = app.actions[0].returns.example; } + if ( + app.actions[0].description !== undefined && + app.actions[0].description !== null && + app.actions[0].description.length > 0 + ) { + description = app.actions[0].description + } + const parsedEnvironments = environments === null || environments === [] ? "cloud" : environments[defaultEnvironmentIndex] === undefined ? "cloud" : environments[defaultEnvironmentIndex].Name; + const newAppData = { app_name: app.name, app_version: app.app_version, app_id: app.id, sharing: app.sharing, private_id: app.private_id, + description: description, environment: parsedEnvironments, errors: [], + finished: false, id_: newNodeId, _id_: newNodeId, id: newNodeId, @@ -5158,6 +5196,10 @@ const AngularWorkflow = (props) => { }; const setNewSelectedAction = (e) => { + if (selectedApp.actions === undefined || selectedApp.actions === null) { + return + } + const newaction = selectedApp.actions.find( (a) => a.name === e.target.value ); @@ -5216,6 +5258,14 @@ const AngularWorkflow = (props) => { newSelectedAction.example = newaction.returns.example; } + if ( + newaction.description !== undefined && + newaction.description !== null && + newaction.description.length > 0 + ) { + newSelectedAction.description = newaction.description + } + // FIXME - this is broken sometimes lol //var env = environments.find(a => a.Name === newaction.environment) //if ((!env || env === undefined) && selectedAction.environment === undefined ) { From 69541676cf1dae7ff5fb05d4f0b6122155eae996 Mon Sep 17 00:00:00 2001 From: frikky Date: Thu, 16 Dec 2021 04:18:51 +0100 Subject: [PATCH 12/42] Started fixing background issues for condition and documentation modals --- frontend/src/components/ParsedAction.jsx | 30 ++++-- frontend/src/views/AngularWorkflow.jsx | 117 ++++++++++++++--------- 2 files changed, 90 insertions(+), 57 deletions(-) diff --git a/frontend/src/components/ParsedAction.jsx b/frontend/src/components/ParsedAction.jsx index e5d6ae55..a35ee256 100644 --- a/frontend/src/components/ParsedAction.jsx +++ b/frontend/src/components/ParsedAction.jsx @@ -979,9 +979,9 @@ const ParsedAction = (props) => { return helperText } - console.log("D: ", selectedAction) - console.log("DESC: ", selectedAction.description) - console.log("DESC2: ", selectedApp.description) + //console.log("D: ", selectedAction) + //console.log("DESC: ", selectedAction.description) + //console.log("DESC2: ", selectedApp.description) // FIXME: Issue #40 - selectedActionParameters not reset if ( @@ -993,13 +993,14 @@ const ParsedAction = (props) => {
+
- - */} - { - const elementName = "copy_element_shuffle"; - var copyText = document.getElementById(elementName); - if (copyText !== null && copyText !== undefined) { - const clipboard = navigator.clipboard; - if (clipboard === undefined) { - alert.error( - "Can only copy over HTTPS (port 3443)" - ); - return; - } - - navigator.clipboard.writeText(file.id); - copyText.select(); - copyText.setSelectionRange( - 0, - 99999 - ); /* For mobile devices */ - - /* Copy the text inside the text field */ - document.execCommand("copy"); - - alert.info(file.id + " copied to clipboard"); - } - }} - > - - - /> ); })} @@ -4095,7 +4144,7 @@ const Admin = (props) => { diff --git a/frontend/src/views/AppCreator.jsx b/frontend/src/views/AppCreator.jsx index 1ac122b8..9f5e3c1c 100644 --- a/frontend/src/views/AppCreator.jsx +++ b/frontend/src/views/AppCreator.jsx @@ -3501,6 +3501,9 @@ const AppCreator = (props) => { } } + // Found that dashes in the URL doesn't work + parsedurl = parsedurl.replace("-", "_") + if (event.target.value !== parsedurl) { setUrlPath(parsedurl); setActionField("url", parsedurl); From ed0c6250d6e4a4bbfd485b8359fcf2a6684f0e26 Mon Sep 17 00:00:00 2001 From: frikky Date: Thu, 30 Dec 2021 17:15:27 +0100 Subject: [PATCH 33/42] Added tab control in admin UI when clicking tabs --- frontend/src/views/Admin.jsx | 44 ++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/frontend/src/views/Admin.jsx b/frontend/src/views/Admin.jsx index c5ecc336..b8c73e3a 100644 --- a/frontend/src/views/Admin.jsx +++ b/frontend/src/views/Admin.jsx @@ -86,7 +86,7 @@ const MenuProps = { const Admin = (props) => { - const { globalUrl, userdata } = props; + const { globalUrl, userdata, serverside} = props; var upload = ""; var to_be_copied = ""; @@ -1357,12 +1357,12 @@ const Admin = (props) => { 3: "files", 4: "schedules", 5: "environments", - 6: "categories", + 6: "suborgs", }; - const setConfig = (event, newValue) => { - //console.log("Value: ", newValue) + const setConfig = (event, inputValue) => { + const newValue = parseInt(inputValue) - setCurTab(parseInt(newValue)); + setCurTab(newValue) if (newValue === 1) { document.title = "Shuffle - admin - users"; getUsers(); @@ -1385,18 +1385,13 @@ const Admin = (props) => { document.title = "Shuffle - admin"; } + console.log("NEWVALUE: ", newValue) + if (newValue === 6) { console.log("Should get apps for categories."); } - //var theURL = window.location.pathname - //FIXME: Add url edits - //var theURL = window.location - //theURL.replace(`/${views[curTab]}`, `/${views[newValue]}`) - //window.history.pushState({"html":response.html,"pageTitle":response.pageTitle},"", urlPath); - - //console.log(newpath) - //window.location.pathame = newpath + props.history.push(`/admin?tab=${views[newValue]}`) setModalUser({}); }; @@ -1408,13 +1403,24 @@ const Admin = (props) => { getUsers(); } else { getSettings(); - } + } - if (props.match.params.key !== undefined) { - //const tmpitem = views[props.match.params.key] - setConfig("", props.match.params.key); - } - } + 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 foundTab = params["tab"] + if (foundTab !== null && foundTab !== undefined) { + for (var key in Object.keys(views)) { + const value = views[key] + console.log(key, value) + if (value === foundTab) { + setConfig("", key) + break + } + } + } + } + } if ( selectedOrganization.id === undefined && From 287c25436054153d421331791dbef04d54e6ca0a Mon Sep 17 00:00:00 2001 From: frikky Date: Thu, 30 Dec 2021 18:34:00 +0100 Subject: [PATCH 34/42] #643: Fixed security issues in launch branch as well --- docker-compose.yml | 4 ++-- frontend/Dockerfile | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 0ec19fe0..a7bd17b2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ version: '3' services: frontend: - build: ./frontend + #build: ./frontend image: ghcr.io/frikky/shuffle-frontend:nightly container_name: shuffle-frontend hostname: shuffle-frontend @@ -64,7 +64,7 @@ services: - SHUFFLE_SWARM_NETWORK_NAME=shuffle-executions restart: unless-stopped opensearch: - image: opensearchproject/opensearch:1.2.1 + image: opensearchproject/opensearch:1.2.3 hostname: shuffle-opensearch container_name: shuffle-opensearch environment: diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 5c29245a..84867823 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -21,7 +21,7 @@ RUN rm -rf /usr/src/app/node_modules/webpack RUN yarn build # Production environment -FROM nginx:1.21.3 +FROM nginx:1.21.5 RUN mkdir -p /usr/share/nginx/html/build RUN mkdir -p /usr/share/nginx/html/css From 24dcb7ebfb9022747b2bb1c0e9fac4d80418cf85 Mon Sep 17 00:00:00 2001 From: frikky Date: Thu, 30 Dec 2021 18:36:07 +0100 Subject: [PATCH 35/42] #566: Bumped alpine --- functions/onprem/orborus/Dockerfile | 2 +- functions/onprem/worker/Dockerfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/functions/onprem/orborus/Dockerfile b/functions/onprem/orborus/Dockerfile index 00cd6b55..dd7a0977 100644 --- a/functions/onprem/orborus/Dockerfile +++ b/functions/onprem/orborus/Dockerfile @@ -15,7 +15,7 @@ RUN go get github.com/docker/docker/api/types && \ RUN go build RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o orborus . -FROM alpine:3.14.2 +FROM alpine:3.15.0 RUN apk add --no-cache bash tzdata COPY --from=builder /app/ / diff --git a/functions/onprem/worker/Dockerfile b/functions/onprem/worker/Dockerfile index 904f8988..0fe187bd 100644 --- a/functions/onprem/worker/Dockerfile +++ b/functions/onprem/worker/Dockerfile @@ -27,7 +27,7 @@ RUN go build RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o worker . ## ALPINE IMAGE -FROM alpine:3.14.2 +FROM alpine:3.15.0 ENV SHUFFLE_BASE_IMAGE_REGISTRY=docker.io ENV SHUFFLE_BASE_IMAGE_NAME=frikky/shuffle From 1b22617632b656b567850349c546b32a8011e064 Mon Sep 17 00:00:00 2001 From: frikky Date: Thu, 30 Dec 2021 18:38:12 +0100 Subject: [PATCH 36/42] #645: Fixed install guide in launch as well --- .github/install-guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/install-guide.md b/.github/install-guide.md index d1dfcf76..0864a172 100644 --- a/.github/install-guide.md +++ b/.github/install-guide.md @@ -17,7 +17,7 @@ cd Shuffle 3. Fix prerequisites for the Opensearch database (Elasticsearch): ``` -sudo chown 1000:1000 -R shuffle-database # Required for Opensearch +sudo chown -R 1000:1000 shuffle-database # Required for Opensearch ``` 4. Run docker-compose. From e3867091182e320f834f83992e2fd8ac79cbbd69 Mon Sep 17 00:00:00 2001 From: frikky Date: Fri, 31 Dec 2021 01:01:36 +0100 Subject: [PATCH 37/42] #168: Fixed a lot of the tiny annoyances of Oauth2 apps --- frontend/src/components/Oauth2Auth.jsx | 68 +++++----- frontend/src/components/ParsedAction.jsx | 11 +- frontend/src/views/AppCreator.jsx | 152 ++++++++++++++++++++--- 3 files changed, 177 insertions(+), 54 deletions(-) diff --git a/frontend/src/components/Oauth2Auth.jsx b/frontend/src/components/Oauth2Auth.jsx index 634ccf67..be7a8088 100644 --- a/frontend/src/components/Oauth2Auth.jsx +++ b/frontend/src/components/Oauth2Auth.jsx @@ -311,10 +311,7 @@ const AuthenticationOauth2 = (props) => { - - Oauth2 requires a client ID and secret to authenticate. This is - usually made in the remote system. - + Oauth2 requires a client ID and secret to authenticate, defined in the remote system. Your redirect URL is https://shuffler.io/set_authentication. {
); })} - {allscopes.length === 0 ? null : ( - } - renderValue={(selected) => selected.join(", ")} - MenuProps={MenuProps} - > - {allscopes.map((data, index) => { - return ( - - -1} /> - - - ); - })} - - )} { color: "white", marginLeft: "5px", maxWidth: "95%", - height: 50, fontSize: "1em", + height: "50px", }, }} fullWidth @@ -505,14 +476,15 @@ const AuthenticationOauth2 = (props) => { style={{ backgroundColor: theme.palette.inputColor, borderRadius: theme.palette.borderRadius, + marginBottom: 10, }} InputProps={{ style: { color: "white", marginLeft: "5px", maxWidth: "95%", - height: 50, fontSize: "1em", + height: "50px", }, }} fullWidth @@ -523,6 +495,36 @@ const AuthenticationOauth2 = (props) => { //authenticationOption.label = event.target.value }} /> + {allscopes.length === 0 ? null : ( + + Scopes + } + renderValue={(selected) => selected.join(", ")} + MenuProps={MenuProps} + > + {allscopes.map((data, index) => { + return ( + + -1} /> + + + ); + })} + + + )} )}