Added categories to workflows
This commit is contained in:
@@ -2877,8 +2877,8 @@ func fixUserOrg(ctx context.Context, user *User) *User {
|
|||||||
|
|
||||||
// Used for testing only. Shouldn't impact production.
|
// Used for testing only. Shouldn't impact production.
|
||||||
func handleCors(resp http.ResponseWriter, request *http.Request) bool {
|
func handleCors(resp http.ResponseWriter, request *http.Request) bool {
|
||||||
//allowedOrigins := "http://localhost:3000"
|
allowedOrigins := "http://localhost:3000"
|
||||||
allowedOrigins := "http://localhost:3002"
|
//allowedOrigins := "http://localhost:3002"
|
||||||
|
|
||||||
resp.Header().Set("Vary", "Origin")
|
resp.Header().Set("Vary", "Origin")
|
||||||
resp.Header().Set("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, remember-me, Authorization")
|
resp.Header().Set("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, remember-me, Authorization")
|
||||||
@@ -4628,7 +4628,7 @@ func findAvailablePorts(startRange int64, endRange int64) string {
|
|||||||
func handleSendalert(resp http.ResponseWriter, request *http.Request) {
|
func handleSendalert(resp http.ResponseWriter, request *http.Request) {
|
||||||
user, err := handleApiAuthentication(resp, request)
|
user, err := handleApiAuthentication(resp, request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Api authentication failed in getworkflows: %s", err)
|
log.Printf("Api authentication failed in sendalert: %s", err)
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(401)
|
||||||
resp.Write([]byte(`{"success": false}`))
|
resp.Write([]byte(`{"success": false}`))
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -190,6 +190,10 @@ type WorkflowApp struct {
|
|||||||
Name string `json:"name" datastore:"name" yaml:"name"`
|
Name string `json:"name" datastore:"name" yaml:"name"`
|
||||||
Url string `json:"url" datastore:"url" yaml:"url"`
|
Url string `json:"url" datastore:"url" yaml:"url"`
|
||||||
} `json:"contact_info" datastore:"contact_info" yaml:"contact_info" required:false`
|
} `json:"contact_info" datastore:"contact_info" yaml:"contact_info" required:false`
|
||||||
|
ReferenceInfo struct {
|
||||||
|
DocumentationUrl string `json:"documentation_url" datastore:"documentation_url"`
|
||||||
|
GithubUrl string `json:"github_url" datastore:"github_url"`
|
||||||
|
}
|
||||||
Actions []WorkflowAppAction `json:"actions" yaml:"actions" required:true datastore:"actions,noindex"`
|
Actions []WorkflowAppAction `json:"actions" yaml:"actions" required:true datastore:"actions,noindex"`
|
||||||
Authentication Authentication `json:"authentication" yaml:"authentication" required:false datastore:"authentication"`
|
Authentication Authentication `json:"authentication" yaml:"authentication" required:false datastore:"authentication"`
|
||||||
Tags []string `json:"tags" yaml:"tags" required:false datastore:"activated"`
|
Tags []string `json:"tags" yaml:"tags" required:false datastore:"activated"`
|
||||||
@@ -317,6 +321,7 @@ type Action struct {
|
|||||||
AuthenticationId string `json:"authentication_id" datastore:"authentication_id"`
|
AuthenticationId string `json:"authentication_id" datastore:"authentication_id"`
|
||||||
Example string `json:"example,omitempty" datastore:"example"`
|
Example string `json:"example,omitempty" datastore:"example"`
|
||||||
AuthNotRequired bool `json:"auth_not_required,omitempty" datastore:"auth_not_required" yaml:"auth_not_required"`
|
AuthNotRequired bool `json:"auth_not_required,omitempty" datastore:"auth_not_required" yaml:"auth_not_required"`
|
||||||
|
Category string `json:"category" datastore:"category"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Added environment for location to execute
|
// Added environment for location to execute
|
||||||
@@ -406,8 +411,26 @@ type Workflow struct {
|
|||||||
Name string `json:"name" datastore:"name"`
|
Name string `json:"name" datastore:"name"`
|
||||||
Value string `json:"value" datastore:"value,noindex"`
|
Value string `json:"value" datastore:"value,noindex"`
|
||||||
} `json:"execution_variables,omitempty" datastore:"execution_variables"`
|
} `json:"execution_variables,omitempty" datastore:"execution_variables"`
|
||||||
ExecutionEnvironment string `json:"execution_environment" datastore:"execution_environment"`
|
ExecutionEnvironment string `json:"execution_environment" datastore:"execution_environment"`
|
||||||
PreviouslySaved bool `json:"first_save" datastore:"first_save"`
|
PreviouslySaved bool `json:"first_save" datastore:"first_save"`
|
||||||
|
Categories Categories `json:"categories" datastore:"categories"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Category struct {
|
||||||
|
Name string `json:"name" datastore:"name"`
|
||||||
|
Description string `json:"description" datastore:"description"`
|
||||||
|
Count int64 `json:"count" datastore:"count"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Categories struct {
|
||||||
|
SIEM Category `json:"siem" datastore:"siem"`
|
||||||
|
Communication Category `json:"communication" datastore:"communication"`
|
||||||
|
Assets Category `json:"assets" datastore:"assets"`
|
||||||
|
Cases Category `json:"cases" datastore:"cases"`
|
||||||
|
Network Category `json:"network" datastore:"network"`
|
||||||
|
Intel Category `json:"intel" datastore:"intel"`
|
||||||
|
EDR Category `json:"edr" datastore:"edr"`
|
||||||
|
Other Category `json:"other" datastore:"other"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ActionResult struct {
|
type ActionResult struct {
|
||||||
@@ -1641,13 +1664,16 @@ func getWorkflows(resp http.ResponseWriter, request *http.Request) {
|
|||||||
q = q.Limit(35)
|
q = q.Limit(35)
|
||||||
_, err = dbclient.GetAll(ctx, q, &workflows)
|
_, err = dbclient.GetAll(ctx, q, &workflows)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed getting workflows for user %s: %s", user.Username, err)
|
log.Printf("Failed getting workflows for user %s: %s (0)", user.Username, err)
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(401)
|
||||||
resp.Write([]byte(`{"success": false}`))
|
resp.Write([]byte(`{"success": false}`))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Printf("Failed getting workflows for user %s: %s", user.Username, err)
|
log.Printf("Failed getting workflows for user %s: %s (1)", user.Username, err)
|
||||||
|
//DeleteKey(ctx, "workflow", "5694357e-8063-4580-8529-301cc72df951")
|
||||||
|
|
||||||
|
//log.Printf("Workflows: %#v", workflows)
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(401)
|
||||||
resp.Write([]byte(`{"success": false}`))
|
resp.Write([]byte(`{"success": false}`))
|
||||||
return
|
return
|
||||||
@@ -2066,6 +2092,32 @@ func updateAppAuth(auth AppAuthenticationStorage, workflowId, nodeId string, add
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func handleCategoryIncrease(workflow Workflow, action Action) Categories {
|
||||||
|
if action.Category == "" {
|
||||||
|
log.Printf("Should find app's categories as it's empty during save")
|
||||||
|
return workflow.Categories
|
||||||
|
}
|
||||||
|
|
||||||
|
newCategory := "cases"
|
||||||
|
log.Printf("Adding %s category", newCategory)
|
||||||
|
switch category := newCategory; {
|
||||||
|
case category == "cases":
|
||||||
|
workflow.Categories.Cases.Count += 1
|
||||||
|
default:
|
||||||
|
log.Printf("Can't handle category %s", category)
|
||||||
|
}
|
||||||
|
|
||||||
|
//Categories Categories `json:"categories" datastore:"categories"`
|
||||||
|
//found := false
|
||||||
|
//for _, category := range workflow.Categories {
|
||||||
|
// if category == newCategory {
|
||||||
|
// log.Printf("Category %s already exists", category)
|
||||||
|
// return workflow
|
||||||
|
//}
|
||||||
|
//workflow.Categories = handleCategoryIncrease(workflow, action.Category)
|
||||||
|
return workflow.Categories
|
||||||
|
}
|
||||||
|
|
||||||
// Saves a workflow to an ID
|
// Saves a workflow to an ID
|
||||||
func saveWorkflow(resp http.ResponseWriter, request *http.Request) {
|
func saveWorkflow(resp http.ResponseWriter, request *http.Request) {
|
||||||
cors := handleCors(resp, request)
|
cors := handleCors(resp, request)
|
||||||
@@ -2166,6 +2218,7 @@ func saveWorkflow(resp http.ResponseWriter, request *http.Request) {
|
|||||||
// FIXME - this shouldn't be necessary with proper API checks
|
// FIXME - this shouldn't be necessary with proper API checks
|
||||||
newActions := []Action{}
|
newActions := []Action{}
|
||||||
allNodes := []string{}
|
allNodes := []string{}
|
||||||
|
workflow.Categories = Categories{}
|
||||||
|
|
||||||
//log.Printf("Action: %#v", action.Authentication)
|
//log.Printf("Action: %#v", action.Authentication)
|
||||||
for _, action := range workflow.Actions {
|
for _, action := range workflow.Actions {
|
||||||
@@ -2193,6 +2246,7 @@ func saveWorkflow(resp http.ResponseWriter, request *http.Request) {
|
|||||||
action.Errors = []string{}
|
action.Errors = []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
workflow.Categories = handleCategoryIncrease(workflow, action)
|
||||||
newActions = append(newActions, action)
|
newActions = append(newActions, action)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2203,7 +2257,7 @@ func saveWorkflow(resp http.ResponseWriter, request *http.Request) {
|
|||||||
workflowapps, apperr := getAllWorkflowApps(ctx, 500)
|
workflowapps, apperr := getAllWorkflowApps(ctx, 500)
|
||||||
allAuths, err := getAllWorkflowAppAuth(ctx, user.ActiveOrg.Id)
|
allAuths, err := getAllWorkflowAppAuth(ctx, user.ActiveOrg.Id)
|
||||||
if err == nil && len(workflowapps) > 0 && apperr == nil {
|
if err == nil && len(workflowapps) > 0 && apperr == nil {
|
||||||
log.Printf("Setting actions")
|
//log.Printf("Setting actions")
|
||||||
actionFixing := []Action{}
|
actionFixing := []Action{}
|
||||||
appsAdded := []string{}
|
appsAdded := []string{}
|
||||||
for _, action := range newActions {
|
for _, action := range newActions {
|
||||||
@@ -2533,7 +2587,7 @@ func saveWorkflow(resp http.ResponseWriter, request *http.Request) {
|
|||||||
// FIXME - might be a sploit to run someone elses app if getAllWorkflowApps
|
// FIXME - might be a sploit to run someone elses app if getAllWorkflowApps
|
||||||
// doesn't check sharing=true
|
// doesn't check sharing=true
|
||||||
// Have to do it like this to add the user's apps
|
// Have to do it like this to add the user's apps
|
||||||
log.Println("Apps set starting")
|
//log.Println("Apps set starting")
|
||||||
//log.Printf("EXIT ON ERROR: %#v", workflow.Configuration.ExitOnError)
|
//log.Printf("EXIT ON ERROR: %#v", workflow.Configuration.ExitOnError)
|
||||||
workflowApps := []WorkflowApp{}
|
workflowApps := []WorkflowApp{}
|
||||||
//memcacheName = "all_apps"
|
//memcacheName = "all_apps"
|
||||||
@@ -4625,7 +4679,7 @@ func deleteWorkflowApp(resp http.ResponseWriter, request *http.Request) {
|
|||||||
user.PrivateApps = privateApps
|
user.PrivateApps = privateApps
|
||||||
err = setUser(ctx, &user)
|
err = setUser(ctx, &user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("[ERROR]Failed removing %s app for user %s: %s", app.Name, user.Username, err)
|
log.Printf("[ERROR] Failed removing %s app for user %s: %s", app.Name, user.Username, err)
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(401)
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": true"}`)))
|
resp.Write([]byte(fmt.Sprintf(`{"success": true"}`)))
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -433,7 +433,7 @@ const AngularWorkflow = (props) => {
|
|||||||
const abortExecution = () => {
|
const abortExecution = () => {
|
||||||
setExecutionRunning(false)
|
setExecutionRunning(false)
|
||||||
|
|
||||||
alert.info("Aborting execution")
|
//alert.info("Aborting execution")
|
||||||
fetch(globalUrl+"/api/v1/workflows/"+props.match.params.key+"/executions/"+executionRequest.execution_id+"/abort", {
|
fetch(globalUrl+"/api/v1/workflows/"+props.match.params.key+"/executions/"+executionRequest.execution_id+"/abort", {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
@@ -1859,13 +1859,6 @@ const AngularWorkflow = (props) => {
|
|||||||
height: "100%",
|
height: "100%",
|
||||||
}
|
}
|
||||||
|
|
||||||
const scrollStyle = {
|
|
||||||
marginTop: 10,
|
|
||||||
overflow: "scroll",
|
|
||||||
height: "100%",
|
|
||||||
overflowX: "auto",
|
|
||||||
overflowY: "auto",
|
|
||||||
}
|
|
||||||
|
|
||||||
const paperAppStyle = {
|
const paperAppStyle = {
|
||||||
borderRadius: borderRadius,
|
borderRadius: borderRadius,
|
||||||
@@ -2429,8 +2422,11 @@ const AngularWorkflow = (props) => {
|
|||||||
authentication: [],
|
authentication: [],
|
||||||
execution_variable: undefined,
|
execution_variable: undefined,
|
||||||
example: example,
|
example: example,
|
||||||
|
category: app.categories !== null && app.categories !== undefined && app.categories.length > 0 ? app.categories[0] : ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: overwrite category if the ACTION chosen has a different category
|
||||||
|
|
||||||
// const image = "url("+app.large_image+")"
|
// const image = "url("+app.large_image+")"
|
||||||
|
|
||||||
// FIXME - find the cytoscape offset position
|
// FIXME - find the cytoscape offset position
|
||||||
@@ -2489,6 +2485,8 @@ const AngularWorkflow = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
workflow.actions.push(newAppData)
|
workflow.actions.push(newAppData)
|
||||||
|
|
||||||
|
console.log(workflow.categories)
|
||||||
setWorkflow(workflow)
|
setWorkflow(workflow)
|
||||||
|
|
||||||
if (newAppPopup) {
|
if (newAppPopup) {
|
||||||
@@ -2605,7 +2603,6 @@ const AngularWorkflow = (props) => {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("APP: ", app)
|
|
||||||
return(
|
return(
|
||||||
<ParsedAppPaper key={index} app={app} />
|
<ParsedAppPaper key={index} app={app} />
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -195,7 +195,7 @@ const AppCreator = (props) => {
|
|||||||
const alert = useAlert()
|
const alert = useAlert()
|
||||||
|
|
||||||
var upload = ""
|
var upload = ""
|
||||||
const increaseAmount = 30
|
const increaseAmount = 50
|
||||||
const actionNonBodyRequest = ["GET", "HEAD", "DELETE", "CONNECT"]
|
const actionNonBodyRequest = ["GET", "HEAD", "DELETE", "CONNECT"]
|
||||||
const actionBodyRequest = ["POST", "PUT", "PATCH",]
|
const actionBodyRequest = ["POST", "PUT", "PATCH",]
|
||||||
const authenticationOptions = ["No authentication", "API key", "Bearer auth", "Basic auth", ]
|
const authenticationOptions = ["No authentication", "API key", "Bearer auth", "Basic auth", ]
|
||||||
@@ -1230,6 +1230,11 @@ const AppCreator = (props) => {
|
|||||||
newAction.errors.push("Can't have the same name")
|
newAction.errors.push("Can't have the same name")
|
||||||
|
|
||||||
actions.push(newAction)
|
actions.push(newAction)
|
||||||
|
|
||||||
|
if (actions.length > actionAmount) {
|
||||||
|
setActionAmount(actions.length)
|
||||||
|
}
|
||||||
|
|
||||||
setActions(actions)
|
setActions(actions)
|
||||||
setUpdate(Math.random())
|
setUpdate(Math.random())
|
||||||
}
|
}
|
||||||
@@ -1539,6 +1544,11 @@ const AppCreator = (props) => {
|
|||||||
actions[actionIndex] = currentAction
|
actions[actionIndex] = currentAction
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (actions.length > actionAmount) {
|
||||||
|
setActionAmount(actions.length)
|
||||||
|
}
|
||||||
|
|
||||||
setActions(actions)
|
setActions(actions)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1973,6 +1983,7 @@ const AppCreator = (props) => {
|
|||||||
setUrlPathQueries([])
|
setUrlPathQueries([])
|
||||||
setUrlPath("")
|
setUrlPath("")
|
||||||
setFileUploadEnabled(false)
|
setFileUploadEnabled(false)
|
||||||
|
|
||||||
}}>
|
}}>
|
||||||
Submit
|
Submit
|
||||||
</Button>
|
</Button>
|
||||||
@@ -2053,8 +2064,10 @@ const AppCreator = (props) => {
|
|||||||
setCurrentActionMethod(actionNonBodyRequest[0])
|
setCurrentActionMethod(actionNonBodyRequest[0])
|
||||||
setActionsModalOpen(true)
|
setActionsModalOpen(true)
|
||||||
}}>New action</Button>
|
}}>New action</Button>
|
||||||
|
{/*
|
||||||
|
{actionAmount} {actions.length}
|
||||||
{actionAmount > 0 && actionAmount < actions.length ? null :
|
{actionAmount > 0 && actionAmount < actions.length ? null :
|
||||||
<Button color="primary" style={{marginTop: "20px", borderRadius: "0px", textAlign: "center"}} variant="outlined" onClick={() => {
|
<Button color="primary" style={{float: "right", marginTop: "20px", borderRadius: "0px", textAlign: "center"}} variant="outlined" onClick={() => {
|
||||||
if (actionAmount+increaseAmount > actions.length) {
|
if (actionAmount+increaseAmount > actions.length) {
|
||||||
setActionAmount(actions.length)
|
setActionAmount(actions.length)
|
||||||
} else {
|
} else {
|
||||||
@@ -2064,6 +2077,7 @@ const AppCreator = (props) => {
|
|||||||
See more actions
|
See more actions
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
|
*/}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -2136,7 +2150,7 @@ const AppCreator = (props) => {
|
|||||||
</h2>
|
</h2>
|
||||||
</Link>
|
</Link>
|
||||||
<h2>
|
<h2>
|
||||||
{name}
|
{name} ({actions === null || actions === undefined ? 0 : actions.length})
|
||||||
</h2>
|
</h2>
|
||||||
</Breadcrumbs>
|
</Breadcrumbs>
|
||||||
<Paper style={boxStyle}>
|
<Paper style={boxStyle}>
|
||||||
|
|||||||
@@ -169,7 +169,7 @@ const Apps = (props) => {
|
|||||||
|
|
||||||
function sortByKey(array, key) {
|
function sortByKey(array, key) {
|
||||||
if (array === undefined || array === null) {
|
if (array === undefined || array === null) {
|
||||||
return []
|
return array
|
||||||
}
|
}
|
||||||
|
|
||||||
return array.sort(function(a, b) {
|
return array.sort(function(a, b) {
|
||||||
|
|||||||
@@ -191,18 +191,21 @@ const Workflows = (props) => {
|
|||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (response.status !== 200) {
|
if (response.status !== 200) {
|
||||||
console.log("Status not 200 for workflows :O!")
|
console.log("Status not 200 for workflows :O!: ", response.status)
|
||||||
|
alert.info("Failed getting workflows.")
|
||||||
|
setWorkflowDone(true)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return response.json()
|
return response.json()
|
||||||
})
|
})
|
||||||
.then((responseJson) => {
|
.then((responseJson) => {
|
||||||
setSelectedExecution({})
|
setSelectedExecution({})
|
||||||
setWorkflowExecutions([])
|
setWorkflowExecutions([])
|
||||||
|
|
||||||
if (responseJson !== undefined) {
|
if (responseJson !== undefined) {
|
||||||
setWorkflows(responseJson)
|
setWorkflows(responseJson)
|
||||||
setWorkflowDone(true)
|
setWorkflowDone(true)
|
||||||
} else {
|
} else {
|
||||||
if (isLoggedIn) {
|
if (isLoggedIn) {
|
||||||
alert.error("An error occurred while loading workflows")
|
alert.error("An error occurred while loading workflows")
|
||||||
|
|||||||
@@ -258,7 +258,7 @@ func initializeImages() {
|
|||||||
log.Printf("[WARNING] SHUFFLE_APP_SDK_VERSION not defined. Defaulting to %s", appSdkVersion)
|
log.Printf("[WARNING] SHUFFLE_APP_SDK_VERSION not defined. Defaulting to %s", appSdkVersion)
|
||||||
}
|
}
|
||||||
if workerVersion == "" {
|
if workerVersion == "" {
|
||||||
workerVersion = "0.8.54"
|
workerVersion = "0.8.56"
|
||||||
log.Printf("[WARNING] SHUFFLE_WORKER_VERSION not defined. Defaulting to %s", workerVersion)
|
log.Printf("[WARNING] SHUFFLE_WORKER_VERSION not defined. Defaulting to %s", workerVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user