diff --git a/backend/go-app/codegen.go b/backend/go-app/codegen.go index 90460ad1..88644465 100644 --- a/backend/go-app/codegen.go +++ b/backend/go-app/codegen.go @@ -456,6 +456,40 @@ func generateYaml(swagger *openapi3.Swagger, newmd5 string) (*openapi3.Swagger, } } + // Jesus what a clusterfuck. + // Handles parsing of categories from OpenApi3 custom field + if val, ok := swagger.Info.ExtensionProps.Extensions["x-categories"]; ok { + log.Printf("Categories: %#v", val) + j, err := json.Marshal(&val) + if err == nil { + if j[0] == 0x22 && j[len(j)-1] == 0x22 { + j = j[1 : len(j)-1] + } + + parsedCategories := fmt.Sprintf(`{"categories": %s}`, string(j)) + type parsed struct { + Categories []string `json:"categories"` + } + + var parse parsed + err := json.Unmarshal([]byte(parsedCategories), &parse) + if err != nil { + log.Printf("Failed unmarshaling categories", err) + } else { + api.Categories = parse.Categories + } + } + } + + if len(swagger.Tags) > 0 { + newTags := []string{} + for _, tag := range swagger.Tags { + newTags = append(newTags, tag.Name) + } + + api.Tags = newTags + } + securitySchemes := swagger.Components.SecuritySchemes if securitySchemes != nil { //log.Printf("%#v", securitySchemes) diff --git a/backend/go-app/main.go b/backend/go-app/main.go index fc0d97cc..7e96623f 100644 --- a/backend/go-app/main.go +++ b/backend/go-app/main.go @@ -1696,6 +1696,7 @@ func handleInfo(resp http.ResponseWriter, request *http.Request) { { "success": true, "admin": %s, + "tutorials": [], "orgs": [{"name": "Shuffle", "id": "123", "role": "admin"}], "selected_org": {"name": "Shuffle", "id": "123", "role": "admin"}, "cookies": [{"key": "session_token", "value": "%s", "expiration": %d}] @@ -3129,7 +3130,7 @@ func handleWebhookCallback(resp http.ResponseWriter, request *http.Request) { } for _, item := range hook.Workflows { - log.Printf("Running for workflow %s with startnode %s", item, hook.Start) + log.Printf("Running webhook for workflow %s with startnode %s", item, hook.Start) workflow := Workflow{ ID: "", } diff --git a/backend/go-app/walkoff.go b/backend/go-app/walkoff.go index 47826aab..a72d6a32 100644 --- a/backend/go-app/walkoff.go +++ b/backend/go-app/walkoff.go @@ -121,7 +121,7 @@ type WorkflowApp struct { Actions []WorkflowAppAction `json:"actions" yaml:"actions" required:true datastore:"actions,noindex"` Authentication Authentication `json:"authentication" yaml:"authentication" required:false datastore:"authentication"` Tags []string `json:"tags" yaml:"tags" required:false datastore:"activated"` - Category []string `json:"category" yaml:"category" required:false datastore:"category"` + Categories []string `json:"categories" yaml:"categories" required:false datastore:"categories"` } type WorkflowAppActionParameter struct { @@ -2308,10 +2308,10 @@ func handleExecution(id string, workflow Workflow, request *http.Request) (Workf //log.Println(string(mappedData)) - log.Printf("STARTNODE: %s", workflowExecution.Start) if len(workflowExecution.Start) == 0 { workflowExecution.Start = workflowExecution.Workflow.Start } + log.Printf("STARTNODE: %s", workflowExecution.Start) childNodes := findChildNodes(workflowExecution, workflowExecution.Start) @@ -2535,6 +2535,7 @@ func executeWorkflow(resp http.ResponseWriter, request *http.Request) { return } + log.Printf("STARTING EXEC OF %s!", fileId) workflowExecution, executionResp, err := handleExecution(fileId, *workflow, request) if err == nil { diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 1e6a0fc3..f7a408d1 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -22,6 +22,7 @@ import Dashboard from "./views/Dashboard"; import AdminSetup from "./views/AdminSetup"; import Admin from "./views/Admin"; import Docs from "./views/Docs"; +import Introduction from "./views/Introduction"; import LandingPageNew from "./views/LandingpageNew"; import LoginPage from "./views/LoginPage"; @@ -95,6 +96,7 @@ const App = (message, props) => { .then(response => response.json()) .then(responseJson => { if (responseJson.success === true) { + //console.log(responseJson.success) setUserData(responseJson) setIsLoggedIn(true) @@ -141,6 +143,8 @@ const App = (message, props) => { } /> } /> { window.location.pathname = "/docs/about" }} /> + } /> + } /> { window.location.pathname = "/login" }} /> diff --git a/frontend/src/views/AppCreator.jsx b/frontend/src/views/AppCreator.jsx index e75496f9..9768ada1 100644 --- a/frontend/src/views/AppCreator.jsx +++ b/frontend/src/views/AppCreator.jsx @@ -22,6 +22,9 @@ import Breadcrumbs from '@material-ui/core/Breadcrumbs'; import AppsIcon from '@material-ui/icons/Apps'; import CircularProgress from '@material-ui/core/CircularProgress'; +import Chip from '@material-ui/core/Chip'; +import ChipInput from 'material-ui-chip-input' + import ErrorOutline from '@material-ui/icons/ErrorOutline'; import { useAlert } from "react-alert"; import words from "shellwords" @@ -201,11 +204,14 @@ const AppCreator = (props) => { const [actionsModalOpen, setActionsModalOpen] = useState(false); const [authenticationRequired, setAuthenticationRequired] = useState(false); const [authenticationOption, setAuthenticationOption] = useState(authenticationOptions[0]); + const [newWorkflowTags, setNewWorkflowTags] = React.useState([]); + const [newWorkflowCategories, setNewWorkflowCategories] = React.useState([]); const [parameterName, setParameterName] = useState(""); const [parameterLocation, setParameterLocation] = useState(apikeySelection.length > 0 ? apikeySelection[0] : ""); const [urlPath, setUrlPath] = useState(""); //const [urlPathQueries, setUrlPathQueries] = useState([{"name": "test", "required": false}]); const [urlPathQueries, setUrlPathQueries] = useState([]); + const [update, setUpdate] = useState("") const [urlPathParameters, ] = useState([]); const [firstrequest, setFirstrequest] = React.useState(true) const [, setBasedata] = React.useState({}) @@ -355,13 +361,20 @@ const AppCreator = (props) => { setDescription(data.info.description) document.title = "Apps - "+data.info.title - if (data.info !== null && data.info !== undefined && data.info["x-logo"] !== undefined) { - setFileBase64(data.info["x-logo"]) + if (data.info !== null && data.info !== undefined) { + if (data.info["x-logo"] !== undefined) { + setFileBase64(data.info["x-logo"]) + } + + if (data.info.contact !== undefined) { + setContact(data.info.contact) + } + + if (data.info["x-categories"] !== undefined && data.info["x-categories"].length > 0) { + setNewWorkflowCategories(data.info["x-categories"]) + } } - if (data.info.contact != undefined) { - setContact(data.info.contact) - } if (data.servers !== undefined && data.servers.length > 0) { var firstUrl = data.servers[0].url @@ -372,6 +385,16 @@ const AppCreator = (props) => { } } + if (data.tags !== undefined && data.tags.length > 0) { + for (var key in data.tags) { + newWorkflowTags.push(data.tags[key].name) + } + + setNewWorkflowTags(newWorkflowTags) + } + + console.log(data.info) + // This is annoying (: var securitySchemes = data.components.securityDefinitions if (securitySchemes === undefined) { @@ -553,7 +576,6 @@ const AppCreator = (props) => { "securitySchemes": {}, }, "id": props.match.params.appid, - "securityDefinitions": {}, } if (contact === "") { @@ -566,8 +588,20 @@ const AppCreator = (props) => { data.info["contact"] = contact } - //console.log("LOADED IMAGE: ", data.image) + if (newWorkflowTags.length > 0) { + var newtags = [] + for (var key in newWorkflowTags) { + newtags.push({"name": newWorkflowTags[key]}) + } + data["tags"] = newtags + } + + if (newWorkflowCategories.length > 0) { + data["info"]["x-categories"] = newWorkflowCategories + } + + // Handles actions for (var key in actions) { const item = actions[key] if (item.errors.length > 0) { @@ -594,7 +628,7 @@ const AppCreator = (props) => { "parameters": [] } - console.log("ACTION: ", item) + //console.log("ACTION: ", item) if (item.queries.length > 0) { for (var querykey in item.queries) { @@ -1455,6 +1489,55 @@ const AppCreator = (props) => { + const tagView = +
+

Tags

+ { + newWorkflowTags.push(chip) + setNewWorkflowTags(newWorkflowTags) + setUpdate("added"+chip) + }} + onDelete={(chip, index) => { + newWorkflowTags.splice(index, 1) + setNewWorkflowTags(newWorkflowTags) + setUpdate("delete "+chip) + }} + /> + { + newWorkflowCategories.push(chip) + setNewWorkflowCategories(newWorkflowCategories) + setUpdate("added "+chip) + }} + onDelete={(chip, index) => { + newWorkflowCategories.splice(index, 1) + setNewWorkflowCategories(newWorkflowCategories) + setUpdate("delete "+chip) + }} + /> +
+ const actionView =

Actions

@@ -1705,6 +1788,12 @@ const AppCreator = (props) => {
{actionView}
+ + +
+ {tagView} +
+ {/* {/* {testView} diff --git a/frontend/src/views/Apps.jsx b/frontend/src/views/Apps.jsx index 35bef2d4..3ae8b7db 100644 --- a/frontend/src/views/Apps.jsx +++ b/frontend/src/views/Apps.jsx @@ -20,6 +20,7 @@ import YAML from 'yaml' import {Link} from 'react-router-dom'; import Breadcrumbs from '@material-ui/core/Breadcrumbs'; import ReactJson from 'react-json-view' +import Chip from '@material-ui/core/Chip'; import CachedIcon from '@material-ui/icons/Cached'; import CloudDownloadIcon from '@material-ui/icons/CloudDownload'; @@ -477,13 +478,26 @@ const Apps = (props) => {

{newAppname}

-

{description}

+

{description}

{activateButton} {downloadButton} {editButton} {deleteButton} + {selectedApp.tags !== undefined && selectedApp.tags !== null ? +
+ {selectedApp.tags.map(tag => { + return ( + + ) + })} +
+ : null} {selectedApp.link.length > 0 ?

URL: {selectedApp.link}

: null}

ID: {selectedApp.id}

@@ -549,7 +563,7 @@ const Apps = (props) => { })} : null} - {selectedAction.description !== undefined && selectedAction.description !== null ? + {selectedAction.description !== undefined && selectedAction.description !== null && selectedAction.description.length > 0 ?
Action Description
{selectedAction.description} @@ -985,7 +999,7 @@ const Apps = (props) => { } const deleteModal = deleteModalOpen ? - { setDeleteModalOpen(false) @@ -1017,7 +1031,7 @@ const Apps = (props) => { const circularLoader = validation ? : null const appsModalLoad = loadAppsModalOpen ? - { setOpenApi("") @@ -1115,7 +1129,7 @@ const Apps = (props) => { const errorText = openApiError.length > 0 ?
Error: {openApiError}
: null const modalView = openApiModal ? - {setOpenApiModal(false)}} PaperProps={{ diff --git a/frontend/src/views/Introduction.jsx b/frontend/src/views/Introduction.jsx new file mode 100644 index 00000000..5fb15287 --- /dev/null +++ b/frontend/src/views/Introduction.jsx @@ -0,0 +1,217 @@ +import React, { useEffect, useState } from 'react'; +import { useTheme } from '@material-ui/core/styles'; + +import Grid from '@material-ui/core/Grid'; +import Card from '@material-ui/core/Card'; +import CardActionArea from '@material-ui/core/CardActionArea'; +import CardContent from '@material-ui/core/CardContent'; +import CardHeader from '@material-ui/core/CardHeader'; +import Typography from '@material-ui/core/Typography'; +import Button from '@material-ui/core/Button'; + +const Workflows = (props) => { + const { globalUrl, isLoggedIn, isLoaded, } = props + const theme = useTheme(); + const [curView, setCurView] = useState(0); + const [firstrequest, setFirstrequest] = useState(true) + const [selectedItems, setSelectedItems] = useState([]) + + const viewdata1 = [ + { + "title": "General", + "content": "Learn about our ticketing solutions", + "subitems": [ + { + "name": "Search", + "subtitle": "Search for anything, anywhere", + }, + { + "name": "Message", + "subtitle": "Read and send messages", + }, + { + "name": "Parse emails", + "subtitle": "what", + }, + ], + }, + { + "title": "Ticketing", + "subitems": [ + { + "name": "Search", + "subtitle": "Search for anything, anywhere", + }, + { + "name": "Message", + "subtitle": "Read and send messages", + }, + { + "name": "Parse emails", + "subtitle": "what", + }, + ], + }, + { + "title": "Threat intel", + "subitems": [ + { + "name": "Search", + "subtitle": "Search for anything, anywhere", + }, + { + "name": "Message", + "subtitle": "Read and send messages", + }, + { + "name": "Parse emails", + "subtitle": "what", + }, + ], + }, + ] + + if (firstrequest) { + setFirstrequest(false) + if (props.match.params.key) { + console.log("PROPS: ", props.match.params.key) + const viewitem = viewdata1.find(item => item.title.toLowerCase() === props.match.params.key.toLowerCase()) + if (viewitem !== undefined && viewitem !== null) { + setCurView(1) + //setSelectedItem(viewitem) + } + } + } + + + + const cardContentStyle = { + height: "100%", + width: "100%", + padding: 40, + } + + const outerGridView = { + width: "100%", + marginTop: 15, + } + + const paperStyle = { + height: 300, + color: "white", + backgroundColor: theme.palette.surfaceColor, + color: "white", + cursor: "pointer", + display: "flex", + textAlign: "center", + } + + const HandleSelection = (data) => { + const [selected, setSelected] = useState(false); + + var baseStyle = JSON.parse(JSON.stringify(paperStyle)) + if (selected) { + baseStyle.backgroundColor = "white" + baseStyle.color = "black" + } + + return ( + { + console.log(selectedItems) + if (selected) { + const index = selectedItems.findIndex(item => item.title === data.title) + if (index >= 0) { + selectedItems.splice(index, 1) + setSelectedItems(selectedItems) + } + } else { + selectedItems.push(data) + setSelectedItems(selectedItems) + } + + setSelected(!selected) + + //setCurView(1) + //setSelectedItem(data) + //window.location.pathname += "/"+data.title.toLowerCase() + }}> + + + + + {data.title} + + + + + + ) + } + + const view1 = curView === 0 ? +
+ + What are you interested in? + + + {viewdata1.map(data => { + return ( + HandleSelection(data) + ) + })} + + {/* + + */} +
+ : null + + const view2 = curView === 1 ? +
+ + Step 2. + + {/* + + {selectedItem.subitems === undefined ? null : + selectedItem.subitems.map(data => { + return ( + + + + + + {data.name} + + + {data.subtitle} + + + + + + ) + })} + + */} +
+ : null + + const baseView = +
+ {view1} + {view2} +
+ + return ( +
+ {baseView} +
+ ) +} + +export default Workflows diff --git a/frontend/src/views/Workflows.jsx b/frontend/src/views/Workflows.jsx index da077c79..10ecae86 100644 --- a/frontend/src/views/Workflows.jsx +++ b/frontend/src/views/Workflows.jsx @@ -81,7 +81,7 @@ const Workflows = (props) => { }) const deleteModal = deleteModalOpen ? - { setDeleteModalOpen(false) @@ -102,8 +102,9 @@ const Workflows = (props) => {