FIXES: Added wazuh integration and loads more
This commit is contained in:
+33
-18
@@ -606,11 +606,14 @@ class AppBase:
|
|||||||
if "len" in thistype or "length" in thistype or "lenght" in thistype:
|
if "len" in thistype or "length" in thistype or "lenght" in thistype:
|
||||||
tmp = ""
|
tmp = ""
|
||||||
try:
|
try:
|
||||||
tmpdata = data.replace("\'", "\"")
|
|
||||||
tmp = json.loads(tmpdata)
|
tmp = json.loads(tmpdata)
|
||||||
except:
|
except:
|
||||||
print("Passing bug")
|
try:
|
||||||
pass
|
tmpdata = data.replace("\'", "\"")
|
||||||
|
tmp = json.loads(tmpdata)
|
||||||
|
except:
|
||||||
|
print("[ERROR] Parsing bug for length in app sdk")
|
||||||
|
pass
|
||||||
|
|
||||||
if isinstance(tmp, list):
|
if isinstance(tmp, list):
|
||||||
return len(tmp)
|
return len(tmp)
|
||||||
@@ -649,14 +652,14 @@ class AppBase:
|
|||||||
return tmp
|
return tmp
|
||||||
except IndexError as e:
|
except IndexError as e:
|
||||||
return default_error
|
return default_error
|
||||||
|
|
||||||
# Parses the INNER value and recurses until everything is done
|
# Parses the INNER value and recurses until everything is done
|
||||||
def parse_wrapper(data):
|
def parse_wrapper(data):
|
||||||
try:
|
try:
|
||||||
if "(" not in data or ")" not in data:
|
if "(" not in data or ")" not in data:
|
||||||
return data
|
return (data, False)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
return data
|
return (data, False)
|
||||||
|
|
||||||
#print("Running %s" % data)
|
#print("Running %s" % data)
|
||||||
|
|
||||||
@@ -671,7 +674,7 @@ class AppBase:
|
|||||||
break
|
break
|
||||||
|
|
||||||
if not found:
|
if not found:
|
||||||
return data
|
return (data, False)
|
||||||
|
|
||||||
# Do stuff here.
|
# Do stuff here.
|
||||||
innervalue = parse_nested_param(data, maxDepth(data)-0)
|
innervalue = parse_nested_param(data, maxDepth(data)-0)
|
||||||
@@ -692,10 +695,11 @@ class AppBase:
|
|||||||
|
|
||||||
parsed_value = parse_type(innervalue[0], thistype.lower())
|
parsed_value = parse_type(innervalue[0], thistype.lower())
|
||||||
print("Parsed value from %s: %s" % (thistype, parsed_value))
|
print("Parsed value from %s: %s" % (thistype, parsed_value))
|
||||||
return parsed_value
|
return (parsed_value, True)
|
||||||
|
|
||||||
print("DATA: %s\n" % data)
|
print("DATA: %s\n" % data)
|
||||||
return parse_wrapper(data)
|
return (parse_wrapper(data)[0], True)
|
||||||
|
|
||||||
|
|
||||||
# Looks for parantheses to grab special cases within a string, e.g:
|
# Looks for parantheses to grab special cases within a string, e.g:
|
||||||
# int(1) lower(HELLO) or length(what's the length)
|
# int(1) lower(HELLO) or length(what's the length)
|
||||||
@@ -737,15 +741,20 @@ class AppBase:
|
|||||||
if len(newstring) > 0:
|
if len(newstring) > 0:
|
||||||
newdata.append(newstring)
|
newdata.append(newstring)
|
||||||
|
|
||||||
print("Newdata: ", newdata)
|
|
||||||
parsedlist = []
|
parsedlist = []
|
||||||
non_string = False
|
non_string = False
|
||||||
|
parsed = False
|
||||||
for item in newdata:
|
for item in newdata:
|
||||||
ret = parse_wrapper(item)
|
ret = parse_wrapper(item)
|
||||||
if not isinstance(ret, str):
|
if not isinstance(ret[0], str):
|
||||||
non_string = True
|
non_string = True
|
||||||
|
|
||||||
parsedlist.append(ret)
|
parsedlist.append(ret[0])
|
||||||
|
if ret[1]:
|
||||||
|
parsed = True
|
||||||
|
|
||||||
|
if not parsed:
|
||||||
|
return data
|
||||||
|
|
||||||
if len(parsedlist) > 0 and not non_string:
|
if len(parsedlist) > 0 and not non_string:
|
||||||
print("Returning parsed list: ", parsedlist)
|
print("Returning parsed list: ", parsedlist)
|
||||||
@@ -949,7 +958,6 @@ class AppBase:
|
|||||||
if len(parsersplit) == 1:
|
if len(parsersplit) == 1:
|
||||||
return str(baseresult)+str(appendresult), False
|
return str(baseresult)+str(appendresult), False
|
||||||
|
|
||||||
baseresult = baseresult.replace("\'", "\"")
|
|
||||||
baseresult = baseresult.replace(" True,", " true,")
|
baseresult = baseresult.replace(" True,", " true,")
|
||||||
baseresult = baseresult.replace(" False", " false,")
|
baseresult = baseresult.replace(" False", " false,")
|
||||||
|
|
||||||
@@ -958,8 +966,12 @@ class AppBase:
|
|||||||
try:
|
try:
|
||||||
basejson = json.loads(baseresult)
|
basejson = json.loads(baseresult)
|
||||||
except json.decoder.JSONDecodeError as e:
|
except json.decoder.JSONDecodeError as e:
|
||||||
print("Parser issue with JSON: %s" % e)
|
try:
|
||||||
return str(baseresult)+str(appendresult), False
|
baseresult = baseresult.replace("\'", "\"")
|
||||||
|
basejson = json.loads(baseresult)
|
||||||
|
except json.decoder.JSONDecodeError as e:
|
||||||
|
print("Parser issue with JSON: %s" % e)
|
||||||
|
return str(baseresult)+str(appendresult), False
|
||||||
|
|
||||||
print("After fourth parser return as JSON")
|
print("After fourth parser return as JSON")
|
||||||
|
|
||||||
@@ -1365,14 +1377,17 @@ class AppBase:
|
|||||||
if replacement.startswith("\"") and replacement.endswith("\""):
|
if replacement.startswith("\"") and replacement.endswith("\""):
|
||||||
replacement = replacement[1:len(replacement)-1]
|
replacement = replacement[1:len(replacement)-1]
|
||||||
|
|
||||||
replacement = replacement.replace("\'", "\"", -1)
|
|
||||||
print("POST replacement: %s" % replacement)
|
print("POST replacement: %s" % replacement)
|
||||||
|
|
||||||
json_replacement = replacement
|
json_replacement = replacement
|
||||||
try:
|
try:
|
||||||
json_replacement = json.loads(replacement)
|
json_replacement = json.loads(replacement)
|
||||||
except json.decoder.JSONDecodeError as e:
|
except json.decoder.JSONDecodeError as e:
|
||||||
print("JSON error singular: %s" % e)
|
try:
|
||||||
|
replacement = replacement.replace("\'", "\"", -1)
|
||||||
|
json_replacement = json.loads(replacement)
|
||||||
|
except:
|
||||||
|
print("JSON error singular: %s" % e)
|
||||||
|
|
||||||
if len(json_replacement) > minlength:
|
if len(json_replacement) > minlength:
|
||||||
minlength = len(json_replacement)
|
minlength = len(json_replacement)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
NAME=shuffle-app_sdk
|
NAME=shuffle-app_sdk
|
||||||
VERSION=0.8.32
|
VERSION=0.8.4
|
||||||
|
|
||||||
docker rmi docker.pkg.github.com/frikky/shuffle/$NAME:$VERSION --force
|
docker rmi docker.pkg.github.com/frikky/shuffle/$NAME:$VERSION --force
|
||||||
docker build . -t frikky/shuffle:app_sdk -t frikky/$NAME:$VERSION -t docker.pkg.github.com/frikky/shuffle/$NAME:$VERSION -t ghcr.io/frikky/$NAME:$VERSION
|
docker build . -t frikky/shuffle:app_sdk -t frikky/$NAME:$VERSION -t docker.pkg.github.com/frikky/shuffle/$NAME:$VERSION -t ghcr.io/frikky/$NAME:$VERSION
|
||||||
|
|||||||
@@ -230,6 +230,7 @@ func buildImageMemory(fs billy.Filesystem, tags []string, dockerfileFolder strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Build the actual image
|
// Build the actual image
|
||||||
|
log.Printf("Building %s. This may take up to a few minutes.", dockerfileFolder)
|
||||||
imageBuildResponse, err := client.ImageBuild(
|
imageBuildResponse, err := client.ImageBuild(
|
||||||
ctx,
|
ctx,
|
||||||
dockerFileTarReader,
|
dockerFileTarReader,
|
||||||
|
|||||||
@@ -2483,7 +2483,7 @@ func handleLogin(resp http.ResponseWriter, request *http.Request) {
|
|||||||
if len(users) != 1 {
|
if len(users) != 1 {
|
||||||
log.Printf(`Found multiple or no users with the same username: %s: %d`, data.Username, len(users))
|
log.Printf(`Found multiple or no users with the same username: %s: %d`, data.Username, len(users))
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(401)
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Found %d users with the same username: %s"}`, len(users), data.Username)))
|
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Error: %d users with username %s"}`, len(users), data.Username)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4785,7 +4785,7 @@ func getDocList(resp http.ResponseWriter, request *http.Request) {
|
|||||||
|
|
||||||
if len(item1) == 0 {
|
if len(item1) == 0 {
|
||||||
resp.WriteHeader(500)
|
resp.WriteHeader(500)
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "No docs available."`)))
|
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "No docs available."}`)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4844,7 +4844,7 @@ func getDocs(resp http.ResponseWriter, request *http.Request) {
|
|||||||
location := strings.Split(request.URL.String(), "/")
|
location := strings.Split(request.URL.String(), "/")
|
||||||
if len(location) != 5 {
|
if len(location) != 5 {
|
||||||
resp.WriteHeader(404)
|
resp.WriteHeader(404)
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Bad path. Use e.g. /api/v1/docs/workflows.md"`)))
|
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Bad path. Use e.g. /api/v1/docs/workflows.md"}`)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4868,7 +4868,7 @@ func getDocs(resp http.ResponseWriter, request *http.Request) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Bad path. Use e.g. /api/v1/docs/workflows.md"`)))
|
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Bad path. Use e.g. /api/v1/docs/workflows.md"}`)))
|
||||||
resp.WriteHeader(404)
|
resp.WriteHeader(404)
|
||||||
//setBadMemcache(ctx, docPath)
|
//setBadMemcache(ctx, docPath)
|
||||||
return
|
return
|
||||||
@@ -4877,7 +4877,7 @@ func getDocs(resp http.ResponseWriter, request *http.Request) {
|
|||||||
newresp, err := client.Do(req)
|
newresp, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.WriteHeader(404)
|
resp.WriteHeader(404)
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Bad path. Use e.g. /api/v1/docs/workflows.md"`)))
|
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Bad path. Use e.g. /api/v1/docs/workflows.md"}`)))
|
||||||
//setBadMemcache(ctx, docPath)
|
//setBadMemcache(ctx, docPath)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -4885,7 +4885,7 @@ func getDocs(resp http.ResponseWriter, request *http.Request) {
|
|||||||
body, err := ioutil.ReadAll(newresp.Body)
|
body, err := ioutil.ReadAll(newresp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.WriteHeader(500)
|
resp.WriteHeader(500)
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Can't parse data"`)))
|
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Can't parse data"}`)))
|
||||||
//setBadMemcache(ctx, docPath)
|
//setBadMemcache(ctx, docPath)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -5958,7 +5958,7 @@ func echoOpenapiData(resp http.ResponseWriter, request *http.Request) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("[ERROR] URLbody error: %s", err)
|
log.Printf("[ERROR] URLbody error: %s", err)
|
||||||
resp.WriteHeader(500)
|
resp.WriteHeader(500)
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Can't get data from selected uri"`)))
|
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Can't get data from selected uri"}`)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4015,7 +4015,7 @@ func deleteWorkflowApp(resp http.ResponseWriter, request *http.Request) {
|
|||||||
log.Printf("ID: %s", fileId)
|
log.Printf("ID: %s", fileId)
|
||||||
app, err := getApp(ctx, fileId)
|
app, err := getApp(ctx, fileId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error getting app %s: %s", app.Name, err)
|
log.Printf("Error getting app (delete) %s: %s", fileId, err)
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(401)
|
||||||
resp.Write([]byte(`{"success": false}`))
|
resp.Write([]byte(`{"success": false}`))
|
||||||
return
|
return
|
||||||
@@ -4169,7 +4169,7 @@ func getWorkflowAppConfig(resp http.ResponseWriter, request *http.Request) {
|
|||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
app, err := getApp(ctx, fileId)
|
app, err := getApp(ctx, fileId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error getting app: %s", app.Name)
|
log.Printf("Error getting app (app config): %s", fileId)
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(401)
|
||||||
resp.Write([]byte(`{"success": false}`))
|
resp.Write([]byte(`{"success": false}`))
|
||||||
return
|
return
|
||||||
@@ -4438,7 +4438,7 @@ func updateWorkflowAppConfig(resp http.ResponseWriter, request *http.Request) {
|
|||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
app, err := getApp(ctx, fileId)
|
app, err := getApp(ctx, fileId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error getting app: %s (update app)", app.Name)
|
log.Printf("Error getting app (update app): %s", fileId)
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(401)
|
||||||
resp.Write([]byte(`{"success": false}`))
|
resp.Write([]byte(`{"success": false}`))
|
||||||
return
|
return
|
||||||
|
|||||||
+2
-2
@@ -2,7 +2,7 @@ version: '3'
|
|||||||
services:
|
services:
|
||||||
frontend:
|
frontend:
|
||||||
#build: ./frontend
|
#build: ./frontend
|
||||||
image: ghcr.io/frikky/shuffle-frontend:0.8.4
|
image: ghcr.io/frikky/shuffle-frontend:0.8.42
|
||||||
container_name: shuffle-frontend
|
container_name: shuffle-frontend
|
||||||
hostname: shuffle-frontend
|
hostname: shuffle-frontend
|
||||||
ports:
|
ports:
|
||||||
@@ -45,7 +45,7 @@ services:
|
|||||||
- database
|
- database
|
||||||
orborus:
|
orborus:
|
||||||
#build: ./functions/onprem/orborus
|
#build: ./functions/onprem/orborus
|
||||||
image: ghcr.io/frikky/shuffle-orborus:0.8.31
|
image: ghcr.io/frikky/shuffle-orborus:0.8.32
|
||||||
container_name: shuffle-orborus
|
container_name: shuffle-orborus
|
||||||
hostname: shuffle-orborus
|
hostname: shuffle-orborus
|
||||||
networks:
|
networks:
|
||||||
|
|||||||
@@ -470,6 +470,33 @@ const Admin = (props) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const flushQueue = (name) => {
|
||||||
|
// Just use this one?
|
||||||
|
const url = globalUrl + '/api/v1/flush_queue';
|
||||||
|
fetch(url, {
|
||||||
|
method: 'DELETE',
|
||||||
|
credentials: "include",
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then(response =>
|
||||||
|
response.json().then(responseJson => {
|
||||||
|
if (responseJson["success"] === false) {
|
||||||
|
alert.error(responseJson.reason)
|
||||||
|
getEnvironments()
|
||||||
|
} else {
|
||||||
|
setLoginInfo("")
|
||||||
|
setModalOpen(false)
|
||||||
|
getEnvironments()
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.catch(error => {
|
||||||
|
console.log("Error when deleting: ", error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const deleteEnvironment = (name) => {
|
const deleteEnvironment = (name) => {
|
||||||
// FIXME - add some check here ROFL
|
// FIXME - add some check here ROFL
|
||||||
alert.info("Deleting environment " + name)
|
alert.info("Deleting environment " + name)
|
||||||
@@ -2094,6 +2121,7 @@ const Admin = (props) => {
|
|||||||
style={{minWidth: 150, maxWidth: 150, overflow: "hidden"}}
|
style={{minWidth: 150, maxWidth: 150, overflow: "hidden"}}
|
||||||
>
|
>
|
||||||
<Button disabled={environment.archived} variant="outlined" style={{borderRadius: "0px"}} onClick={() => deleteEnvironment(environment.Name)} color="primary">Archive</Button>
|
<Button disabled={environment.archived} variant="outlined" style={{borderRadius: "0px"}} onClick={() => deleteEnvironment(environment.Name)} color="primary">Archive</Button>
|
||||||
|
{/*<Button disabled={environment.archived} variant="outlined" style={{borderRadius: "0px"}} onClick={() => flushQueue(environment.Name)} color="primary">Flush Queue</Button>*/}
|
||||||
</ListItemText>
|
</ListItemText>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
style={{minWidth: 150, maxWidth: 150, overflow: "hidden"}}
|
style={{minWidth: 150, maxWidth: 150, overflow: "hidden"}}
|
||||||
|
|||||||
@@ -192,7 +192,7 @@ const AngularWorkflow = (props) => {
|
|||||||
const cloudSyncEnabled = props.userdata !== undefined && props.userdata.active_org !== null && props.userdata.active_org !== undefined ? props.userdata.active_org.cloud_sync === true : false
|
const cloudSyncEnabled = props.userdata !== undefined && props.userdata.active_org !== null && props.userdata.active_org !== undefined ? props.userdata.active_org.cloud_sync === true : false
|
||||||
//const triggerEnvironments = cloudSyncEnabled ? ["cloud", "onprem"] : environments
|
//const triggerEnvironments = cloudSyncEnabled ? ["cloud", "onprem"] : environments
|
||||||
const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io"
|
const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io"
|
||||||
const triggerEnvironments = isCloud ? ["cloud"] : ["cloud", "onprem"]
|
const triggerEnvironments = isCloud ? ["cloud"] : ["onprem", "cloud"]
|
||||||
|
|
||||||
const unloadText = 'Are you sure you want to leave without saving (CTRL+S)?'
|
const unloadText = 'Are you sure you want to leave without saving (CTRL+S)?'
|
||||||
useBeforeunload(() => {
|
useBeforeunload(() => {
|
||||||
@@ -2663,7 +2663,6 @@ const AngularWorkflow = (props) => {
|
|||||||
foundResult.result = foundResult.result.split(" None").join(" \"None\"")
|
foundResult.result = foundResult.result.split(" None").join(" \"None\"")
|
||||||
foundResult.result = foundResult.result.split(" False").join(" false")
|
foundResult.result = foundResult.result.split(" False").join(" false")
|
||||||
foundResult.result = foundResult.result.split(" True").join(" true")
|
foundResult.result = foundResult.result.split(" True").join(" true")
|
||||||
foundResult.result = foundResult.result.split("\'").join("\"")
|
|
||||||
|
|
||||||
var jsonvalid = true
|
var jsonvalid = true
|
||||||
try {
|
try {
|
||||||
@@ -2672,7 +2671,15 @@ const AngularWorkflow = (props) => {
|
|||||||
jsonvalid = false
|
jsonvalid = false
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
jsonvalid = false
|
try {
|
||||||
|
foundResult.result = foundResult.result.split("\'").join("\"")
|
||||||
|
const tmp = String(JSON.parse(foundResult.result))
|
||||||
|
if (!foundResult.result.includes("{") && !foundResult.result.includes("[")) {
|
||||||
|
jsonvalid = false
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
jsonvalid = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finds the FIRST json only
|
// Finds the FIRST json only
|
||||||
@@ -5874,7 +5881,6 @@ const AngularWorkflow = (props) => {
|
|||||||
const parsedExecutionArgument = () => {
|
const parsedExecutionArgument = () => {
|
||||||
var showResult = executionData.execution_argument.trim()
|
var showResult = executionData.execution_argument.trim()
|
||||||
showResult = showResult.split(" None").join(" \"None\"")
|
showResult = showResult.split(" None").join(" \"None\"")
|
||||||
showResult = showResult.split("\'").join("\"")
|
|
||||||
showResult = showResult.split(" False").join(" false")
|
showResult = showResult.split(" False").join(" false")
|
||||||
showResult = showResult.split(" True").join(" true")
|
showResult = showResult.split(" True").join(" true")
|
||||||
|
|
||||||
@@ -5885,7 +5891,16 @@ const AngularWorkflow = (props) => {
|
|||||||
jsonvalid = false
|
jsonvalid = false
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
jsonvalid = false
|
showResult = showResult.split("\'").join("\"")
|
||||||
|
|
||||||
|
try {
|
||||||
|
const tmp = String(JSON.parse(showResult))
|
||||||
|
if (!showResult.includes("{") && !showResult.includes("[")) {
|
||||||
|
jsonvalid = false
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
jsonvalid = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (jsonvalid) {
|
if (jsonvalid) {
|
||||||
@@ -6070,21 +6085,28 @@ const AngularWorkflow = (props) => {
|
|||||||
//
|
//
|
||||||
// FIXME: The latter replace doens't really work if ' is used in a string
|
// FIXME: The latter replace doens't really work if ' is used in a string
|
||||||
var showResult = data.result.trim()
|
var showResult = data.result.trim()
|
||||||
|
//console.log(showResult)
|
||||||
showResult = showResult.split(" None").join(" \"None\"")
|
showResult = showResult.split(" None").join(" \"None\"")
|
||||||
showResult = showResult.split(" False").join(" false")
|
showResult = showResult.split(" False").join(" false")
|
||||||
showResult = showResult.split(" True").join(" true")
|
showResult = showResult.split(" True").join(" true")
|
||||||
showResult = showResult.split("\'").join("\"")
|
|
||||||
|
|
||||||
var jsonvalid = true
|
var jsonvalid = true
|
||||||
try {
|
try {
|
||||||
const tmp = String(JSON.parse(showResult))
|
const tmp = String(JSON.parse(showResult))
|
||||||
if (!showResult.includes("{") && !showResult.includes("[")) {
|
if (!showResult.includes("{") && !showResult.includes("[")) {
|
||||||
//console.log("IN HERE: ", tmp)
|
|
||||||
jsonvalid = false
|
jsonvalid = false
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
//console.log("Error: ", e)
|
showResult = showResult.split("\'").join("\"")
|
||||||
jsonvalid = false
|
|
||||||
|
try {
|
||||||
|
const tmp = String(JSON.parse(showResult))
|
||||||
|
if (!showResult.includes("{") && !showResult.includes("[")) {
|
||||||
|
jsonvalid = false
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
jsonvalid = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const curapp = apps.find(a => a.name === data.action.app_name && a.app_version === data.action.app_version)
|
const curapp = apps.find(a => a.name === data.action.app_name && a.app_version === data.action.app_version)
|
||||||
|
|||||||
@@ -46,6 +46,10 @@ const inputColor = "#383B40"
|
|||||||
export const GetParsedPaths = (inputdata, basekey) => {
|
export const GetParsedPaths = (inputdata, basekey) => {
|
||||||
const splitkey = " > "
|
const splitkey = " > "
|
||||||
var parsedValues = []
|
var parsedValues = []
|
||||||
|
if (inputdata === undefined || inputdata === null) {
|
||||||
|
return parsedValues
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof(inputdata) !== "object") {
|
if (typeof(inputdata) !== "object") {
|
||||||
return parsedValues
|
return parsedValues
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ const LoginDialog = props => {
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
setLoginInfo("Error in userdata: ", error)
|
setLoginInfo("Error logging in: ", error)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,6 +80,7 @@ const LoginDialog = props => {
|
|||||||
|
|
||||||
const onSubmit = (e) => {
|
const onSubmit = (e) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
setLoginInfo("")
|
||||||
// FIXME - add some check here ROFL
|
// FIXME - add some check here ROFL
|
||||||
|
|
||||||
// Just use this one?
|
// Just use this one?
|
||||||
@@ -114,7 +115,7 @@ const LoginDialog = props => {
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
setLoginInfo("Error in userdata: " + error)
|
setLoginInfo("Error logging in: " + error)
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
url = baseurl + '/api/v1/users/register';
|
url = baseurl + '/api/v1/users/register';
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Created by Shuffle, AS. <frikky@shuffler.io>.
|
||||||
|
|
||||||
|
WPYTHON_BIN="framework/python/bin/python3"
|
||||||
|
|
||||||
|
SCRIPT_PATH_NAME="$0"
|
||||||
|
|
||||||
|
DIR_NAME="$(cd $(dirname ${SCRIPT_PATH_NAME}); pwd -P)"
|
||||||
|
SCRIPT_NAME="$(basename ${SCRIPT_PATH_NAME})"
|
||||||
|
|
||||||
|
case ${DIR_NAME} in
|
||||||
|
*/active-response/bin | */wodles*)
|
||||||
|
if [ -z "${WAZUH_PATH}" ]; then
|
||||||
|
WAZUH_PATH="$(cd ${DIR_NAME}/../..; pwd)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
PYTHON_SCRIPT="${DIR_NAME}/${SCRIPT_NAME}.py"
|
||||||
|
;;
|
||||||
|
*/bin)
|
||||||
|
if [ -z "${WAZUH_PATH}" ]; then
|
||||||
|
WAZUH_PATH="$(cd ${DIR_NAME}/..; pwd)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
PYTHON_SCRIPT="${WAZUH_PATH}/framework/scripts/${SCRIPT_NAME}.py"
|
||||||
|
;;
|
||||||
|
*/integrations)
|
||||||
|
if [ -z "${WAZUH_PATH}" ]; then
|
||||||
|
WAZUH_PATH="$(cd ${DIR_NAME}/..; pwd)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
PYTHON_SCRIPT="${DIR_NAME}/${SCRIPT_NAME}.py"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
|
||||||
|
${WAZUH_PATH}/${WPYTHON_BIN} ${PYTHON_SCRIPT} "$@"
|
||||||
@@ -0,0 +1,177 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# Created by Shuffle, AS. <frikky@shuffler.io>.
|
||||||
|
# Based on the Slack integration using Webhooks
|
||||||
|
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import os
|
||||||
|
|
||||||
|
try:
|
||||||
|
import requests
|
||||||
|
from requests.auth import HTTPBasicAuth
|
||||||
|
except Exception as e:
|
||||||
|
print("No module 'requests' found. Install: pip install requests")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# ADD THIS TO ossec.conf configuration:
|
||||||
|
# <integration>
|
||||||
|
# <name>custom-shuffle</name>
|
||||||
|
# <hook_url>http://<IP>:3001/api/v1/hooks/<HOOK_ID></hook_url>
|
||||||
|
# <level>3</level>
|
||||||
|
# <alert_format>json</alert_format>
|
||||||
|
# </integration>
|
||||||
|
|
||||||
|
# Global vars
|
||||||
|
|
||||||
|
debug_enabled = False
|
||||||
|
pwd = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
|
||||||
|
json_alert = {}
|
||||||
|
now = time.strftime("%a %b %d %H:%M:%S %Z %Y")
|
||||||
|
|
||||||
|
# Set paths
|
||||||
|
log_file = '{0}/logs/integrations.log'.format(pwd)
|
||||||
|
|
||||||
|
|
||||||
|
def main(args):
|
||||||
|
debug("# Starting")
|
||||||
|
|
||||||
|
# Read args
|
||||||
|
alert_file_location = args[1]
|
||||||
|
webhook = args[3]
|
||||||
|
|
||||||
|
debug("# Webhook")
|
||||||
|
debug(webhook)
|
||||||
|
|
||||||
|
debug("# File location")
|
||||||
|
debug(alert_file_location)
|
||||||
|
|
||||||
|
# Load alert. Parse JSON object.
|
||||||
|
with open(alert_file_location) as alert_file:
|
||||||
|
json_alert = json.load(alert_file)
|
||||||
|
debug("# Processing alert")
|
||||||
|
debug(json_alert)
|
||||||
|
|
||||||
|
debug("# Generating message")
|
||||||
|
msg = generate_msg(json_alert)
|
||||||
|
if isinstance(msg, str):
|
||||||
|
if len(msg) == 0:
|
||||||
|
return
|
||||||
|
debug(msg)
|
||||||
|
|
||||||
|
debug("# Sending message")
|
||||||
|
send_msg(msg, webhook)
|
||||||
|
|
||||||
|
|
||||||
|
def debug(msg):
|
||||||
|
if debug_enabled:
|
||||||
|
msg = "{0}: {1}\n".format(now, msg)
|
||||||
|
print(msg)
|
||||||
|
f = open(log_file, "a")
|
||||||
|
f.write(msg)
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
# Skips container kills to stop self-recursion
|
||||||
|
def filter_msg(alert):
|
||||||
|
# These are things that recursively happen because Shuffle starts Docker containers
|
||||||
|
# Docker integration rules: https://github.com/wazuh/wazuh-ruleset/blob/ae36745db1d3f312db0392f5925c2f2b0ec009a9/rules/0560-docker_integration_rules.xml
|
||||||
|
skip = ["87924", "87900", "87901", "87902", "87903", "87904", "86001", "86002", "86003", "87932", "80710", "87929", "87928",]
|
||||||
|
if alert["rule"]["id"] in skip:
|
||||||
|
return False
|
||||||
|
|
||||||
|
#try:
|
||||||
|
# if "docker" in alert["rule"]["description"].lower() and "
|
||||||
|
#msg['text'] = alert.get('full_log')
|
||||||
|
#except:
|
||||||
|
# pass
|
||||||
|
#msg['title'] = alert['rule']['description'] if 'description' in alert['rule'] else "N/A"
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def generate_msg(alert):
|
||||||
|
if not filter_msg(alert):
|
||||||
|
print("Skipping rule %s" % alert["rule"]["id"])
|
||||||
|
return ""
|
||||||
|
|
||||||
|
level = alert['rule']['level']
|
||||||
|
|
||||||
|
if (level <= 4):
|
||||||
|
color = "good"
|
||||||
|
elif (level >= 5 and level <= 7):
|
||||||
|
color = "warning"
|
||||||
|
else:
|
||||||
|
color = "danger"
|
||||||
|
|
||||||
|
msg = {}
|
||||||
|
msg['color'] = color
|
||||||
|
msg['pretext'] = "WAZUH Alert"
|
||||||
|
msg['title'] = alert['rule']['description'] if 'description' in alert['rule'] else "N/A"
|
||||||
|
msg['text'] = alert.get('full_log')
|
||||||
|
msg['rule_id'] = alert["rule"]["id"]
|
||||||
|
msg['timestamp'] = alert["timestamp"]
|
||||||
|
msg['id'] = alert['id']
|
||||||
|
msg["all_fields"] = alert
|
||||||
|
|
||||||
|
#msg['fields'] = []
|
||||||
|
# msg['fields'].append({
|
||||||
|
# "title": "Agent",
|
||||||
|
# "value": "({0}) - {1}".format(
|
||||||
|
# alert['agent']['id'],
|
||||||
|
# alert['agent']['name']
|
||||||
|
# ),
|
||||||
|
# })
|
||||||
|
#if 'agentless' in alert:
|
||||||
|
# msg['fields'].append({
|
||||||
|
# "title": "Agentless Host",
|
||||||
|
# "value": alert['agentless']['host'],
|
||||||
|
# })
|
||||||
|
|
||||||
|
#msg['fields'].append({"title": "Location", "value": alert['location']})
|
||||||
|
#msg['fields'].append({
|
||||||
|
# "title": "Rule ID",
|
||||||
|
# "value": "{0} _(Level {1})_".format(alert['rule']['id'], level),
|
||||||
|
#})
|
||||||
|
|
||||||
|
#attach = {'attachments': [msg]}
|
||||||
|
|
||||||
|
return json.dumps(msg)
|
||||||
|
|
||||||
|
|
||||||
|
def send_msg(msg, url):
|
||||||
|
headers = {'content-type': 'application/json', 'Accept-Charset': 'UTF-8'}
|
||||||
|
res = requests.post(url, data=msg, headers=headers)
|
||||||
|
debug(res)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
try:
|
||||||
|
# Read arguments
|
||||||
|
bad_arguments = False
|
||||||
|
if len(sys.argv) >= 4:
|
||||||
|
msg = '{0} {1} {2} {3} {4}'.format(
|
||||||
|
now,
|
||||||
|
sys.argv[1],
|
||||||
|
sys.argv[2],
|
||||||
|
sys.argv[3],
|
||||||
|
sys.argv[4] if len(sys.argv) > 4 else '',
|
||||||
|
)
|
||||||
|
debug_enabled = (len(sys.argv) > 4 and sys.argv[4] == 'debug')
|
||||||
|
else:
|
||||||
|
msg = '{0} Wrong arguments'.format(now)
|
||||||
|
bad_arguments = True
|
||||||
|
|
||||||
|
# Logging the call
|
||||||
|
f = open(log_file, 'a')
|
||||||
|
f.write(msg + '\n')
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
if bad_arguments:
|
||||||
|
debug("# Exiting: Bad arguments.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Main function
|
||||||
|
main(sys.argv)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
debug(str(e))
|
||||||
|
raise
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
<integration>
|
<integration>
|
||||||
<name>Shuffle</name>
|
<name>custom-shuffle</name>
|
||||||
<hook_url>http://<IP>:3001/api/v1/hooks/webhook_<HOOK_ID></hook_url>
|
<hook_url>http://<IP>:3001/api/v1/hooks/webhook_<HOOK_ID></hook_url>
|
||||||
<level>2</level>
|
|
||||||
<group>multiple_drops|authentication_failures</group>
|
|
||||||
<alert_format>json</alert_format>
|
<alert_format>json</alert_format>
|
||||||
</integration>
|
</integration>
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
requests
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
# Based on
|
|
||||||
# https://wazuh.com/blog/how-to-integrate-external-software-using-integrator/
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import json
|
|
||||||
import requests
|
|
||||||
from requests.auth import HTTPBasicAuth
|
|
||||||
|
|
||||||
# Set the project attributes
|
|
||||||
project_alias = 'TI'
|
|
||||||
issue_name ='FIM'
|
|
||||||
|
|
||||||
# Read configuration parameters
|
|
||||||
alert_file = open(sys.argv[1])
|
|
||||||
user = sys.argv[2].split(':')[0]
|
|
||||||
api_key = sys.argv[2].split(':')[1]
|
|
||||||
hook_url = sys.argv[3]
|
|
||||||
|
|
||||||
# Read the alert file
|
|
||||||
alert_json = json.loads(alert_file.read())
|
|
||||||
alert_file.close()
|
|
||||||
|
|
||||||
# Extract issue fields
|
|
||||||
alert_level = alert_json['rule']['level']
|
|
||||||
description = alert_json['rule']['description']
|
|
||||||
path = alert_json['syscheck']['path']
|
|
||||||
|
|
||||||
# Generate request
|
|
||||||
msg_data = {}
|
|
||||||
msg_data['fields'] = {}
|
|
||||||
msg_data['fields']['project'] = {}
|
|
||||||
msg_data['fields']['project']['key'] = project_alias
|
|
||||||
msg_data['fields']['summary'] = 'FIM alert on [' + path + ']'
|
|
||||||
msg_data['fields']['description'] = '- State: ' + description + '\n- Alert level: ' + str(alert_level)
|
|
||||||
msg_data['fields']['issuetype'] = {}
|
|
||||||
msg_data['fields']['issuetype']['name'] = issue_name
|
|
||||||
headers = {'content-type': 'application/json', 'Accept-Charset': 'UTF-8'}
|
|
||||||
|
|
||||||
# Send the request
|
|
||||||
requests.post(hook_url, data=json.dumps(msg_data), headers=headers, auth=(user, api_key))
|
|
||||||
|
|
||||||
sys.exit(0)
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
NAME=shuffle-orborus
|
NAME=shuffle-orborus
|
||||||
VERSION=0.8.31
|
VERSION=0.8.32
|
||||||
|
|
||||||
echo "Running docker build with $NAME:$VERSION"
|
echo "Running docker build with $NAME:$VERSION"
|
||||||
#docker rmi frikky/shuffle:$NAME --force
|
#docker rmi frikky/shuffle:$NAME --force
|
||||||
|
|||||||
@@ -562,6 +562,7 @@ func zombiecheck(workerTimeout int) error {
|
|||||||
|
|
||||||
stopContainers := []string{}
|
stopContainers := []string{}
|
||||||
removeContainers := []string{}
|
removeContainers := []string{}
|
||||||
|
log.Printf("Workertimeout: %d", int64(workerTimeout))
|
||||||
for _, container := range containers {
|
for _, container := range containers {
|
||||||
// Skip random containers. Only handle things related to Shuffle.
|
// Skip random containers. Only handle things related to Shuffle.
|
||||||
if !strings.Contains(container.Image, baseimagename) {
|
if !strings.Contains(container.Image, baseimagename) {
|
||||||
@@ -587,10 +588,10 @@ func zombiecheck(workerTimeout int) error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("[INFO] NAME: %s", name)
|
currenttime := time.Now().Unix()
|
||||||
|
log.Printf("[INFO] (%s) NAME: %s. TIME: %d", container.State, name, currenttime-container.Created)
|
||||||
|
|
||||||
// Need to check time here too because a container can be removed the same instant as its created
|
// Need to check time here too because a container can be removed the same instant as its created
|
||||||
currenttime := time.Now().Unix()
|
|
||||||
if container.State != "running" && currenttime-container.Created > int64(workerTimeout) {
|
if container.State != "running" && currenttime-container.Created > int64(workerTimeout) {
|
||||||
removeContainers = append(removeContainers, container.ID)
|
removeContainers = append(removeContainers, container.ID)
|
||||||
containerNames[container.ID] = name
|
containerNames[container.ID] = name
|
||||||
@@ -606,6 +607,7 @@ func zombiecheck(workerTimeout int) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FIXME - add killing of apps with same execution ID too
|
// FIXME - add killing of apps with same execution ID too
|
||||||
|
log.Printf("[INFO] Should STOP %d containers.", len(stopContainers))
|
||||||
for _, containername := range stopContainers {
|
for _, containername := range stopContainers {
|
||||||
log.Printf("[INFO] Stopping and removing container %s", containerNames[containername])
|
log.Printf("[INFO] Stopping and removing container %s", containerNames[containername])
|
||||||
go dockercli.ContainerStop(ctx, containername, nil)
|
go dockercli.ContainerStop(ctx, containername, nil)
|
||||||
@@ -617,6 +619,7 @@ func zombiecheck(workerTimeout int) error {
|
|||||||
Force: true,
|
Force: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Printf("[INFO] Should REMOVE %d containers.", len(removeContainers))
|
||||||
for _, containername := range removeContainers {
|
for _, containername := range removeContainers {
|
||||||
go dockercli.ContainerRemove(ctx, containername, removeOptions)
|
go dockercli.ContainerRemove(ctx, containername, removeOptions)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user