Re-fixed looping issues in #1012 and bugs from the issue that the initial fix caused
This commit is contained in:
@@ -564,6 +564,7 @@ const AppFramework = (props) => {
|
|||||||
|
|
||||||
const alert = useAlert()
|
const alert = useAlert()
|
||||||
|
|
||||||
|
|
||||||
const handleLoadNextSuggestion = (frameworkData) => {
|
const handleLoadNextSuggestion = (frameworkData) => {
|
||||||
console.log("Should check for next apps to load from App suggestion model")
|
console.log("Should check for next apps to load from App suggestion model")
|
||||||
//fetch(globalUrl + "/api/v1/workflows/usecases", {
|
//fetch(globalUrl + "/api/v1/workflows/usecases", {
|
||||||
@@ -623,7 +624,6 @@ const AppFramework = (props) => {
|
|||||||
suggestions.push(value.slice(0,1))
|
suggestions.push(value.slice(0,1))
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("SUGG: ", suggestions)
|
|
||||||
setInjectedApps(suggestions)
|
setInjectedApps(suggestions)
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
@@ -909,6 +909,10 @@ const AppFramework = (props) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
handleLoadNextSuggestion(frameworkData)
|
||||||
|
}, [])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log("New selected app: ", newSelectedApp, discoveryData)
|
console.log("New selected app: ", newSelectedApp, discoveryData)
|
||||||
if (newSelectedApp.objectID === undefined || newSelectedApp.objectID === undefined || newSelectedApp.objectID.length === 0) {
|
if (newSelectedApp.objectID === undefined || newSelectedApp.objectID === undefined || newSelectedApp.objectID.length === 0) {
|
||||||
@@ -1931,10 +1935,11 @@ const AppFramework = (props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{display: "flex", position: "absolute", top: categoryTop, left: categoryLeft, zIndex: 10010, }}>
|
<div style={{display: "flex", position: "absolute", top: categoryTop, left: categoryLeft, zIndex: 10010, }}>
|
||||||
{apps.map((app) => {
|
{apps.map((app, appIndex) => {
|
||||||
return (
|
return (
|
||||||
<Chip
|
<Chip
|
||||||
avatar={<Avatar alt={app.name} src={app.image_url} style={{backgroundColor: "white", }} />}
|
avatar={<Avatar alt={app.name} src={app.image_url} style={{backgroundColor: "white", }} />}
|
||||||
|
key={app.id}
|
||||||
label={""}
|
label={""}
|
||||||
variant="contained"
|
variant="contained"
|
||||||
style={{}}
|
style={{}}
|
||||||
@@ -2089,6 +2094,9 @@ const AppFramework = (props) => {
|
|||||||
|
|
||||||
setSelectionOpen(true)
|
setSelectionOpen(true)
|
||||||
setDefaultSearch("")
|
setDefaultSearch("")
|
||||||
|
|
||||||
|
//handleLoadNextSuggestion(frameworkData)
|
||||||
|
setInjectedApps([])
|
||||||
|
|
||||||
const foundelement = cy.getElementById(discoveryData.id)
|
const foundelement = cy.getElementById(discoveryData.id)
|
||||||
if (foundelement !== undefined && foundelement !== null) {
|
if (foundelement !== undefined && foundelement !== null) {
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ const ConfigureWorkflow = (props) => {
|
|||||||
|
|
||||||
setFirstLoad(workflow.id)
|
setFirstLoad(workflow.id)
|
||||||
const newactions = [];
|
const newactions = [];
|
||||||
for (let [key, keyval] in workflow.actions.entries()) {
|
for (let [key, keyval] in Object.entries(workflow.actions)) {
|
||||||
const action = workflow.actions[key];
|
const action = workflow.actions[key];
|
||||||
var newaction = {
|
var newaction = {
|
||||||
large_image: action.large_image,
|
large_image: action.large_image,
|
||||||
@@ -175,7 +175,7 @@ const ConfigureWorkflow = (props) => {
|
|||||||
) {
|
) {
|
||||||
// Check if configuration is filled or not
|
// Check if configuration is filled or not
|
||||||
var filled = true;
|
var filled = true;
|
||||||
for (let [key,keyval] in action.parameters.entries()) {
|
for (let [key,keyval] in Object.entries(action.parameters)) {
|
||||||
if (action.parameters[key].configuration) {
|
if (action.parameters[key].configuration) {
|
||||||
//console.log("Found config: ", action.parameters[key])
|
//console.log("Found config: ", action.parameters[key])
|
||||||
if (
|
if (
|
||||||
@@ -216,7 +216,7 @@ const ConfigureWorkflow = (props) => {
|
|||||||
|
|
||||||
if (newaction.must_authenticate) {
|
if (newaction.must_authenticate) {
|
||||||
var authenticationOptions = [];
|
var authenticationOptions = [];
|
||||||
for (let [key,keyval] in appAuthentication.entries()) {
|
for (let [key,keyval] in Object.entries(appAuthentication)) {
|
||||||
const auth = appAuthentication[key];
|
const auth = appAuthentication[key];
|
||||||
if (auth.app.name === app.name && auth.active) {
|
if (auth.app.name === app.name && auth.active) {
|
||||||
//console.log("Found auth: ", auth)
|
//console.log("Found auth: ", auth)
|
||||||
@@ -265,7 +265,7 @@ const ConfigureWorkflow = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (workflow.workflow_variables !== undefined && workflow.workflow_variables !== null && workflow.workflow_variables.length !== 0) {
|
if (workflow.workflow_variables !== undefined && workflow.workflow_variables !== null && workflow.workflow_variables.length !== 0) {
|
||||||
for (let [key,keyval] in workflow.workflow_variables.entries()) {
|
for (let [key,keyval] in Object.entries(workflow.workflow_variables)) {
|
||||||
const variable = workflow.workflow_variables[key];
|
const variable = workflow.workflow_variables[key];
|
||||||
if (
|
if (
|
||||||
variable.value === undefined ||
|
variable.value === undefined ||
|
||||||
@@ -280,7 +280,7 @@ const ConfigureWorkflow = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (workflow.triggers !== undefined && workflow.triggers !== null && workflow.triggers.length !== 0) {
|
if (workflow.triggers !== undefined && workflow.triggers !== null && workflow.triggers.length !== 0) {
|
||||||
for (let [key,keyval] in workflow.triggers.entries()) {
|
for (let [key,keyval] in Object.entries(workflow.triggers)) {
|
||||||
var trigger = workflow.triggers[key];
|
var trigger = workflow.triggers[key];
|
||||||
trigger.index = key;
|
trigger.index = key;
|
||||||
|
|
||||||
@@ -302,7 +302,7 @@ const ConfigureWorkflow = (props) => {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
for (let [subkey,subkeyval] in tmpsteps.entries()) {
|
for (let [subkey,subkeyval] in Object.entries(tmpsteps)) {
|
||||||
newactions[foundindex].steps.push(tmpsteps[subkey])
|
newactions[foundindex].steps.push(tmpsteps[subkey])
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -344,13 +344,13 @@ const ConfigureWorkflow = (props) => {
|
|||||||
setRequiredActions(newactions);
|
setRequiredActions(newactions);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (appAuthentication.length !== previousAuth.length) {
|
if (appAuthentication !== undefined && previousAuth !== undefined && appAuthentication.length !== previousAuth.length) {
|
||||||
var newactions = []
|
var newactions = []
|
||||||
for (let [actionkey, actionkeyval] in requiredActions.entries()) {
|
for (let [actionkey, actionkeyval] in Object.entries(requiredActions)) {
|
||||||
var newaction = requiredActions[actionkey];
|
var newaction = requiredActions[actionkey];
|
||||||
const app = newaction.app;
|
const app = newaction.app;
|
||||||
|
|
||||||
for (let [key,keyval] in appAuthentication.entries()) {
|
for (let [key,keyval] in Object.entries(appAuthentication)) {
|
||||||
const auth = appAuthentication[key];
|
const auth = appAuthentication[key];
|
||||||
|
|
||||||
// Does this account for all the different ones of the same?
|
// Does this account for all the different ones of the same?
|
||||||
@@ -694,7 +694,7 @@ const ConfigureWorkflow = (props) => {
|
|||||||
if (workflow.actions !== null) {
|
if (workflow.actions !== null) {
|
||||||
//console.log(workflow.actions)
|
//console.log(workflow.actions)
|
||||||
alert.info("Setting action to version "+action.update_version)
|
alert.info("Setting action to version "+action.update_version)
|
||||||
for (let [key,keyval] in workflow.actions.entries()) {
|
for (let [key,keyval] in Object.entries(workflow.actions)) {
|
||||||
if (workflow.actions[key].app_name === action.app_name && workflow.actions[key].app_version === action.app_version) {
|
if (workflow.actions[key].app_name === action.app_name && workflow.actions[key].app_version === action.app_version) {
|
||||||
workflow.actions[key].app_version = action.update_version
|
workflow.actions[key].app_version = action.update_version
|
||||||
|
|
||||||
|
|||||||
@@ -277,7 +277,7 @@ const ParsedAction = (props) => {
|
|||||||
console.log("FOUNDACTION: ", foundAction);
|
console.log("FOUNDACTION: ", foundAction);
|
||||||
if (foundAction !== null && foundAction !== undefined) {
|
if (foundAction !== null && foundAction !== undefined) {
|
||||||
var foundparams = [];
|
var foundparams = [];
|
||||||
for (let [paramkey,paramkeyval] in foundAction.parameters.entries()) {
|
for (let [paramkey,paramkeyval] in Object.entries(foundAction.parameters)) {
|
||||||
const param = foundAction.parameters[paramkey];
|
const param = foundAction.parameters[paramkey];
|
||||||
|
|
||||||
const foundParam = selectedAction.parameters.find(
|
const foundParam = selectedAction.parameters.find(
|
||||||
@@ -401,7 +401,7 @@ const ParsedAction = (props) => {
|
|||||||
if (actionlist.length === 0) {
|
if (actionlist.length === 0) {
|
||||||
// FIXME: Have previous execution values in here
|
// FIXME: Have previous execution values in here
|
||||||
if (workflowExecutions.length > 0) {
|
if (workflowExecutions.length > 0) {
|
||||||
for (let [key,keyval] in workflowExecutions.entries()) {
|
for (let [key,keyval] in Object.entries(workflowExecutions)) {
|
||||||
if (
|
if (
|
||||||
workflowExecutions[key].execution_argument === undefined ||
|
workflowExecutions[key].execution_argument === undefined ||
|
||||||
workflowExecutions[key].execution_argument === null ||
|
workflowExecutions[key].execution_argument === null ||
|
||||||
@@ -451,7 +451,7 @@ const ParsedAction = (props) => {
|
|||||||
workflow.workflow_variables !== undefined &&
|
workflow.workflow_variables !== undefined &&
|
||||||
workflow.workflow_variables.length > 0
|
workflow.workflow_variables.length > 0
|
||||||
) {
|
) {
|
||||||
for (let [key,keyval] in workflow.workflow_variables.entries()) {
|
for (let [key,keyval] in Object.entries(workflow.workflow_variables)) {
|
||||||
const item = workflow.workflow_variables[key];
|
const item = workflow.workflow_variables[key];
|
||||||
actionlist.push({
|
actionlist.push({
|
||||||
type: "workflow_variable",
|
type: "workflow_variable",
|
||||||
@@ -470,7 +470,7 @@ const ParsedAction = (props) => {
|
|||||||
workflow.execution_variables !== undefined &&
|
workflow.execution_variables !== undefined &&
|
||||||
workflow.execution_variables.length > 0
|
workflow.execution_variables.length > 0
|
||||||
) {
|
) {
|
||||||
for (let [key,keyval] in workflow.execution_variables.entries()) {
|
for (let [key,keyval] in Object.entries(workflow.execution_variables)) {
|
||||||
const item = workflow.execution_variables[key];
|
const item = workflow.execution_variables[key];
|
||||||
actionlist.push({
|
actionlist.push({
|
||||||
type: "execution_variable",
|
type: "execution_variable",
|
||||||
@@ -488,7 +488,7 @@ const ParsedAction = (props) => {
|
|||||||
var parents = getParents(selectedAction);
|
var parents = getParents(selectedAction);
|
||||||
|
|
||||||
if (parents.length > 1) {
|
if (parents.length > 1) {
|
||||||
for (let [key,keyval] in parents.entries()) {
|
for (let [key,keyval] in Object.entries(parents)) {
|
||||||
const item = parents[key];
|
const item = parents[key];
|
||||||
if (item.label === "Execution Argument") {
|
if (item.label === "Execution Argument") {
|
||||||
continue;
|
continue;
|
||||||
@@ -500,7 +500,7 @@ const ParsedAction = (props) => {
|
|||||||
if (workflowExecutions.length > 0) {
|
if (workflowExecutions.length > 0) {
|
||||||
// Look for the ID
|
// Look for the ID
|
||||||
const found = false;
|
const found = false;
|
||||||
for (let [key,keyval] in workflowExecutions.entries()) {
|
for (let [key,keyval] in Object.entries(workflowExecutions)) {
|
||||||
if (
|
if (
|
||||||
workflowExecutions[key].results === undefined ||
|
workflowExecutions[key].results === undefined ||
|
||||||
workflowExecutions[key].results === null
|
workflowExecutions[key].results === null
|
||||||
@@ -566,13 +566,12 @@ const ParsedAction = (props) => {
|
|||||||
|
|
||||||
if (found !== null && found !== undefined) {
|
if (found !== null && found !== undefined) {
|
||||||
var new_occurences = []
|
var new_occurences = []
|
||||||
for (let [key,keyval] in found.entries()) {
|
for (let [key,keyval] in Object.entries(found)) {
|
||||||
if (found[key][0] !== "\\") {
|
if (found[key][0] !== "\\") {
|
||||||
new_occurences.push(found[key])
|
new_occurences.push(found[key])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("New found: ", new_occurences)
|
|
||||||
found = new_occurences.valueOf()
|
found = new_occurences.valueOf()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -627,9 +626,8 @@ const ParsedAction = (props) => {
|
|||||||
//console.log("Action change: ", selectedAction, data)
|
//console.log("Action change: ", selectedAction, data)
|
||||||
if (data.name.startsWith("${") && data.name.endsWith("}")) {
|
if (data.name.startsWith("${") && data.name.endsWith("}")) {
|
||||||
// PARAM FIX - Gonna use the ID field, even though it's a hack
|
// PARAM FIX - Gonna use the ID field, even though it's a hack
|
||||||
const paramcheck = selectedAction.parameters.find(
|
const paramcheck = selectedAction.parameters.find((param) => param.name === "body");
|
||||||
(param) => param.name === "body"
|
|
||||||
);
|
|
||||||
if (paramcheck !== undefined) {
|
if (paramcheck !== undefined) {
|
||||||
// Escapes all double quotes
|
// Escapes all double quotes
|
||||||
var toReplace = event.target.value.trim()
|
var toReplace = event.target.value.trim()
|
||||||
@@ -730,7 +728,7 @@ const ParsedAction = (props) => {
|
|||||||
|
|
||||||
var curstring = "";
|
var curstring = "";
|
||||||
var record = false;
|
var record = false;
|
||||||
for (let [key,keyval] in selectedActionParameters[count].value.entries()) {
|
for (let [key,keyval] in Object.entries(selectedActionParameters[count].value)) {
|
||||||
const item = selectedActionParameters[count].value[key];
|
const item = selectedActionParameters[count].value[key];
|
||||||
if (record) {
|
if (record) {
|
||||||
curstring += item;
|
curstring += item;
|
||||||
@@ -911,7 +909,7 @@ const ParsedAction = (props) => {
|
|||||||
|
|
||||||
var curstring = ""
|
var curstring = ""
|
||||||
var record = false
|
var record = false
|
||||||
for (let [key,keyval] in selectedActionParameters[count].value.entries()) {
|
for (let [key,keyval] in Object.entries(selectedActionParameters[count].value)) {
|
||||||
const item = selectedActionParameters[count].value[key]
|
const item = selectedActionParameters[count].value[key]
|
||||||
if (record) {
|
if (record) {
|
||||||
curstring += item
|
curstring += item
|
||||||
@@ -1187,7 +1185,7 @@ const ParsedAction = (props) => {
|
|||||||
renderInput={(params) => {
|
renderInput={(params) => {
|
||||||
if (params.inputProps !== undefined && params.inputProps !== null && params.inputProps.value !== undefined && params.inputProps.value !== null) {
|
if (params.inputProps !== undefined && params.inputProps !== null && params.inputProps.value !== undefined && params.inputProps.value !== null) {
|
||||||
const prefixes = ["Post", "Put", "Patch"]
|
const prefixes = ["Post", "Put", "Patch"]
|
||||||
for (let [key,keyval] in prefixes.entries()) {
|
for (let [key,keyval] in Object.entries(prefixes)) {
|
||||||
if (params.inputProps.value.startsWith(prefixes[key])) {
|
if (params.inputProps.value.startsWith(prefixes[key])) {
|
||||||
params.inputProps.value = params.inputProps.value.replace(prefixes[key]+" ", "", -1)
|
params.inputProps.value = params.inputProps.value.replace(prefixes[key]+" ", "", -1)
|
||||||
if (params.inputProps.value.length > 1) {
|
if (params.inputProps.value.length > 1) {
|
||||||
@@ -1346,9 +1344,8 @@ const ParsedAction = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (data.name.startsWith("${") && data.name.endsWith("}")) {
|
if (data.name.startsWith("${") && data.name.endsWith("}")) {
|
||||||
const paramcheck = selectedAction.parameters.find(
|
const paramcheck = selectedAction.parameters.find((param) => param.name === "body");
|
||||||
(param) => param.name === "body"
|
|
||||||
);
|
|
||||||
|
|
||||||
if (paramcheck !== undefined && paramcheck !== null) {
|
if (paramcheck !== undefined && paramcheck !== null) {
|
||||||
if (
|
if (
|
||||||
@@ -1426,8 +1423,8 @@ const ParsedAction = (props) => {
|
|||||||
|
|
||||||
setHideBody(!hideBody);
|
setHideBody(!hideBody);
|
||||||
|
|
||||||
for (let [key,keyval] in selectedActionParameters.entries()) {
|
for (let paramkey in Object.entries(selectedActionParameters)) {
|
||||||
var currentItem = selectedActionParameters[key];
|
var currentItem = selectedActionParameters[paramkey];
|
||||||
if (currentItem.name === "ssl_verify") {
|
if (currentItem.name === "ssl_verify") {
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1472,10 +1469,11 @@ const ParsedAction = (props) => {
|
|||||||
openApiHelperText = "OpenAPI spec: fill the following fields.";
|
openApiHelperText = "OpenAPI spec: fill the following fields.";
|
||||||
//console.log("SHOULD ADD TO selectedActionParameters!: ", found, selectedActionParameters)
|
//console.log("SHOULD ADD TO selectedActionParameters!: ", found, selectedActionParameters)
|
||||||
var changed = false;
|
var changed = false;
|
||||||
for (let [specKey,specKeyVal] in found.entries()) {
|
for (let specKey in found) {
|
||||||
const tmpitem = found[specKey];
|
const tmpitem = found[specKey];
|
||||||
var skip = false;
|
var skip = false;
|
||||||
for (let [innerkey,innerkeyval] in selectedActionParameters.entries()) {
|
|
||||||
|
for (let innerkey in selectedActionParameters) {
|
||||||
if (selectedActionParameters[innerkey].name === tmpitem) {
|
if (selectedActionParameters[innerkey].name === tmpitem) {
|
||||||
skip = true;
|
skip = true;
|
||||||
break;
|
break;
|
||||||
@@ -1707,7 +1705,7 @@ const ParsedAction = (props) => {
|
|||||||
|
|
||||||
var foundnewline = false
|
var foundnewline = false
|
||||||
var allValues = []
|
var allValues = []
|
||||||
for (let [key,keyval] in splitdata.entries()) {
|
for (let [key,keyval] in Object.entries(splitdata)) {
|
||||||
const line = splitdata[key]
|
const line = splitdata[key]
|
||||||
if (line === "") {
|
if (line === "") {
|
||||||
foundnewline = true
|
foundnewline = true
|
||||||
@@ -1777,7 +1775,7 @@ const ParsedAction = (props) => {
|
|||||||
const tmpsplit = selectedActionParameters[count].value.split("\n")
|
const tmpsplit = selectedActionParameters[count].value.split("\n")
|
||||||
var valsplit = []
|
var valsplit = []
|
||||||
var add_empty = false
|
var add_empty = false
|
||||||
for (let [key,keyval] in tmpsplit.entries()) {
|
for (let [key,keyval] in Object.entries(tmpsplit)) {
|
||||||
if (tmpsplit[key] === "") {
|
if (tmpsplit[key] === "") {
|
||||||
add_empty = true
|
add_empty = true
|
||||||
continue
|
continue
|
||||||
@@ -1792,7 +1790,7 @@ const ParsedAction = (props) => {
|
|||||||
console.log("Split: ", valsplit)
|
console.log("Split: ", valsplit)
|
||||||
|
|
||||||
var newarr = []
|
var newarr = []
|
||||||
for (let [key,keyval] in valsplit.entries()) {
|
for (let [key,keyval] in Object.entries(valsplit)) {
|
||||||
var line = valsplit[key]
|
var line = valsplit[key]
|
||||||
|
|
||||||
if (key == index) {
|
if (key == index) {
|
||||||
@@ -1832,7 +1830,7 @@ const ParsedAction = (props) => {
|
|||||||
var tmpsplit = selectedActionParameters[count].value.split("\n")
|
var tmpsplit = selectedActionParameters[count].value.split("\n")
|
||||||
var valsplit = []
|
var valsplit = []
|
||||||
var add_empty = false
|
var add_empty = false
|
||||||
for (let [key,keyval] in tmpsplit.entries()) {
|
for (let [key,keyval] in Object.entries(tmpsplit)) {
|
||||||
if (tmpsplit[key] === "") {
|
if (tmpsplit[key] === "") {
|
||||||
add_empty = true
|
add_empty = true
|
||||||
continue
|
continue
|
||||||
@@ -1847,7 +1845,7 @@ const ParsedAction = (props) => {
|
|||||||
console.log("Split: ", valsplit)
|
console.log("Split: ", valsplit)
|
||||||
|
|
||||||
var newarr = []
|
var newarr = []
|
||||||
for (let [key,keyval] in valsplit.entries()) {
|
for (let [key,keyval] in Object.entries(valsplit)) {
|
||||||
var line = valsplit[key]
|
var line = valsplit[key]
|
||||||
|
|
||||||
if (key == index) {
|
if (key == index) {
|
||||||
@@ -2094,7 +2092,7 @@ const ParsedAction = (props) => {
|
|||||||
: "$" + values[0].autocomplete;
|
: "$" + values[0].autocomplete;
|
||||||
|
|
||||||
toComplete = toComplete.toLowerCase().replaceAll(" ", "_");
|
toComplete = toComplete.toLowerCase().replaceAll(" ", "_");
|
||||||
for (let [key,keyval] in values.entries()) {
|
for (let [key,keyval] in Object.entries(values)) {
|
||||||
if (key == 0 || values[key].autocomplete.length === 0) {
|
if (key == 0 || values[key].autocomplete.length === 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -2205,7 +2203,7 @@ const ParsedAction = (props) => {
|
|||||||
workflow.triggers !== null &&
|
workflow.triggers !== null &&
|
||||||
workflow.triggers.length > 0
|
workflow.triggers.length > 0
|
||||||
) {
|
) {
|
||||||
for (let [key,keyval] in workflow.triggers.entries()) {
|
for (let [key,keyval] in Object.entries(workflow.triggers)) {
|
||||||
const item = workflow.triggers[key];
|
const item = workflow.triggers[key];
|
||||||
|
|
||||||
if (cy !== undefined) {
|
if (cy !== undefined) {
|
||||||
@@ -2727,7 +2725,7 @@ const ParsedAction = (props) => {
|
|||||||
if (workflowExecutions.length > 0) {
|
if (workflowExecutions.length > 0) {
|
||||||
// Look for the ID
|
// Look for the ID
|
||||||
const found = false;
|
const found = false;
|
||||||
for (let [key,keyval] in workflowExecutions.entries()) {
|
for (let [key,keyval] in Object.entries(workflowExecutions)) {
|
||||||
if (
|
if (
|
||||||
workflowExecutions[key].results === undefined ||
|
workflowExecutions[key].results === undefined ||
|
||||||
workflowExecutions[key].results === null
|
workflowExecutions[key].results === null
|
||||||
@@ -2735,6 +2733,11 @@ const ParsedAction = (props) => {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Enforces it to show at least one
|
||||||
|
//if (workflowExecutions[key].execution_argument.includes("too large") && key !== workflowExecutions.length - 1) {
|
||||||
|
// continue
|
||||||
|
//}
|
||||||
|
|
||||||
var foundResult = workflowExecutions[key].results.find(
|
var foundResult = workflowExecutions[key].results.find(
|
||||||
(result) => result.action.id === selectedAction.id
|
(result) => result.action.id === selectedAction.id
|
||||||
)
|
)
|
||||||
@@ -2971,8 +2974,8 @@ const ParsedAction = (props) => {
|
|||||||
//
|
//
|
||||||
// Should make it a function lol
|
// Should make it a function lol
|
||||||
if (workflow.branches !== undefined && workflow.branches !== null) {
|
if (workflow.branches !== undefined && workflow.branches !== null) {
|
||||||
for (let [key,keyval] in workflow.branches.entries()) {
|
for (let [key,keyval] in Object.entries(workflow.branches)) {
|
||||||
for (let [subkey,subkeyval] in workflow.branches[key].conditions.entries()) {
|
for (let [subkey,subkeyval] in Object.entries(workflow.branches[key].conditions)) {
|
||||||
const condition = workflow.branches[key].conditions[subkey]
|
const condition = workflow.branches[key].conditions[subkey]
|
||||||
const sourceparam = condition.source
|
const sourceparam = condition.source
|
||||||
const destinationparam = condition.destination
|
const destinationparam = condition.destination
|
||||||
@@ -3080,12 +3083,12 @@ const ParsedAction = (props) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let [key,keyval] in workflow.actions.entries()) {
|
for (let [key,keyval] in Object.entries(workflow.actions)) {
|
||||||
if (workflow.actions[key].id === selectedAction.id) {
|
if (workflow.actions[key].id === selectedAction.id) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let [subkey, subkeyval] in workflow.actions[key].parameters.entries()) {
|
for (let [subkey, subkeyval] in Object.entries(workflow.actions[key].parameters)) {
|
||||||
const param = workflow.actions[key].parameters[subkey];
|
const param = workflow.actions[key].parameters[subkey];
|
||||||
if (!param.value.includes("$")) {
|
if (!param.value.includes("$")) {
|
||||||
continue
|
continue
|
||||||
@@ -3251,7 +3254,7 @@ const ParsedAction = (props) => {
|
|||||||
selectedAction.selectedAuthentication = {};
|
selectedAction.selectedAuthentication = {};
|
||||||
selectedAction.authentication_id = "";
|
selectedAction.authentication_id = "";
|
||||||
|
|
||||||
for (let [key,keyval] in selectedAction.parameters.entries()) {
|
for (let [key,keyval] in Object.entries(selectedAction.parameters)) {
|
||||||
//console.log(selectedAction.parameters[key])
|
//console.log(selectedAction.parameters[key])
|
||||||
if (selectedAction.parameters[key].configuration) {
|
if (selectedAction.parameters[key].configuration) {
|
||||||
selectedAction.parameters[key].value = "";
|
selectedAction.parameters[key].value = "";
|
||||||
@@ -3568,7 +3571,7 @@ const ParsedAction = (props) => {
|
|||||||
if (method.length > 0 && data.description !== undefined && data.description !== null && data.description.includes("http")) {
|
if (method.length > 0 && data.description !== undefined && data.description !== null && data.description.includes("http")) {
|
||||||
var extraUrl = ""
|
var extraUrl = ""
|
||||||
const descSplit = data.description.split("\n")
|
const descSplit = data.description.split("\n")
|
||||||
for (let [line,lineval] in descSplit.entries()) {
|
for (let [line,lineval] in Object.entries(descSplit)) {
|
||||||
if (descSplit[line].includes("http") && descSplit[line].includes("://")) {
|
if (descSplit[line].includes("http") && descSplit[line].includes("://")) {
|
||||||
const urlsplit = descSplit[line].split("/")
|
const urlsplit = descSplit[line].split("/")
|
||||||
try {
|
try {
|
||||||
@@ -3629,7 +3632,7 @@ const ParsedAction = (props) => {
|
|||||||
renderInput={(params) => {
|
renderInput={(params) => {
|
||||||
if (params.inputProps !== undefined && params.inputProps !== null && params.inputProps.value !== undefined && params.inputProps.value !== null) {
|
if (params.inputProps !== undefined && params.inputProps !== null && params.inputProps.value !== undefined && params.inputProps.value !== null) {
|
||||||
const prefixes = ["Post", "Put", "Patch"]
|
const prefixes = ["Post", "Put", "Patch"]
|
||||||
for (let [key,keyval] in prefixes.entries()) {
|
for (let [key,keyval] in Object.entries(prefixes)) {
|
||||||
if (params.inputProps.value.startsWith(prefixes[key])) {
|
if (params.inputProps.value.startsWith(prefixes[key])) {
|
||||||
params.inputProps.value = params.inputProps.value.replace(prefixes[key]+" ", "", -1)
|
params.inputProps.value = params.inputProps.value.replace(prefixes[key]+" ", "", -1)
|
||||||
if (params.inputProps.value.length > 1) {
|
if (params.inputProps.value.length > 1) {
|
||||||
|
|||||||
@@ -594,7 +594,7 @@ const WelcomeForm = (props) => {
|
|||||||
<Fade in={true}>
|
<Fade in={true}>
|
||||||
<div style={{minHeight: sizing, maxHeight: sizing, marginTop: 20, maxWidth: 500, }}>
|
<div style={{minHeight: sizing, maxHeight: sizing, marginTop: 20, maxWidth: 500, }}>
|
||||||
<Typography variant="body1" style={{marginLeft: 8, marginTop: 50, marginRight: 30, marginBottom: 0, }} color="textSecondary">
|
<Typography variant="body1" style={{marginLeft: 8, marginTop: 50, marginRight: 30, marginBottom: 0, }} color="textSecondary">
|
||||||
Use the buttons below to find your apps, and we will help you connect them later.
|
Apps for each category are shown based on your activity and can be changed by clicking their icon. We will help you connect them later.
|
||||||
</Typography>
|
</Typography>
|
||||||
{/*The app framework helps us access and authenticate the most important APIs for you. */}
|
{/*The app framework helps us access and authenticate the most important APIs for you. */}
|
||||||
|
|
||||||
|
|||||||
@@ -5162,7 +5162,7 @@ const Admin = (props) => {
|
|||||||
index={6}
|
index={6}
|
||||||
value={6}
|
value={6}
|
||||||
label=<span>
|
label=<span>
|
||||||
<BusinessIcon style={iconStyle} /> Organizations
|
<BusinessIcon style={iconStyle} /> Tenants
|
||||||
</span>
|
</span>
|
||||||
/>
|
/>
|
||||||
{/*window.location.protocol == "http:" && window.location.port === "3000" ? <Tab label=<span><CloudIcon style={iconStyle} /> Hybrid</span>/> : null*/}
|
{/*window.location.protocol == "http:" && window.location.port === "3000" ? <Tab label=<span><CloudIcon style={iconStyle} /> Hybrid</span>/> : null*/}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
+193
-152
@@ -299,6 +299,60 @@ const AppCreator = (defaultprops) => {
|
|||||||
const [selectedAction, setSelectedAction] = useState({});
|
const [selectedAction, setSelectedAction] = useState({});
|
||||||
const [authLoaded, setAuthLoaded] = useState(false);
|
const [authLoaded, setAuthLoaded] = useState(false);
|
||||||
|
|
||||||
|
// From 2023: Example to handle action labels
|
||||||
|
// Goal: Make this dynamically load from the backend
|
||||||
|
// and make categories + labels modifyable.
|
||||||
|
//
|
||||||
|
// Categories are the main categories in the App Framework
|
||||||
|
const [categories, setCategories] = useState([
|
||||||
|
{
|
||||||
|
"name": "Communication",
|
||||||
|
"color": "#FFC107",
|
||||||
|
"icon": "communication",
|
||||||
|
"action_labels": [],
|
||||||
|
}, {
|
||||||
|
"name": "SIEM",
|
||||||
|
"color": "#FFC107",
|
||||||
|
"icon": "siem",
|
||||||
|
"action_labels": ["Get alerts", "Search", "Create detection",],
|
||||||
|
}, {
|
||||||
|
"name": "Eradication",
|
||||||
|
"color": "#FFC107",
|
||||||
|
"icon": "eradication",
|
||||||
|
"action_labels": ["List tickets", "Update ticket", "Block hash", "Isolate host"],
|
||||||
|
}, {
|
||||||
|
"name": "Cases",
|
||||||
|
"color": "#FFC107",
|
||||||
|
"icon": "cases",
|
||||||
|
"action_labels": ["List tickets", "Get ticket", "Create ticket", "Update ticket",],
|
||||||
|
}, {
|
||||||
|
"name": "Assets",
|
||||||
|
"color": "#FFC107",
|
||||||
|
"icon": "assets",
|
||||||
|
"action_labels": [],
|
||||||
|
}, {
|
||||||
|
"name": "Intel",
|
||||||
|
"color": "#FFC107",
|
||||||
|
"icon": "intel",
|
||||||
|
"action_labels": [],
|
||||||
|
}, {
|
||||||
|
"name": "IAM",
|
||||||
|
"color": "#FFC107",
|
||||||
|
"icon": "iam",
|
||||||
|
"action_labels": [],
|
||||||
|
}, {
|
||||||
|
"name": "Network",
|
||||||
|
"color": "#FFC107",
|
||||||
|
"icon": "network",
|
||||||
|
"action_labels": ["Block IP",],
|
||||||
|
}, {
|
||||||
|
"name": "Other",
|
||||||
|
"color": "#FFC107",
|
||||||
|
"icon": "other",
|
||||||
|
"action_labels": [],
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
//const [actions, setActions] = useState([{
|
//const [actions, setActions] = useState([{
|
||||||
// "name": "Get workflows",
|
// "name": "Get workflows",
|
||||||
// "description": "Get workflows",
|
// "description": "Get workflows",
|
||||||
@@ -337,6 +391,7 @@ const AppCreator = (defaultprops) => {
|
|||||||
body: "",
|
body: "",
|
||||||
errors: [],
|
errors: [],
|
||||||
example_response: "",
|
example_response: "",
|
||||||
|
action_label: "No Label",
|
||||||
method: actionNonBodyRequest[0],
|
method: actionNonBodyRequest[0],
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -456,8 +511,8 @@ const AppCreator = (defaultprops) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var newitem = data;
|
var newitem = data;
|
||||||
for (let [key,keyval] in paramsplit.entries()) {
|
for (let paramkey in paramsplit) {
|
||||||
var tmpparam = paramsplit[key];
|
var tmpparam = paramsplit[paramkey];
|
||||||
if (tmpparam === "#") {
|
if (tmpparam === "#") {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -579,16 +634,14 @@ const AppCreator = (defaultprops) => {
|
|||||||
console.log("Tags: ", data.tags)
|
console.log("Tags: ", data.tags)
|
||||||
if (data.tags !== undefined && data.tags.length > 0) {
|
if (data.tags !== undefined && data.tags.length > 0) {
|
||||||
var newtags = [];
|
var newtags = [];
|
||||||
for (let [key,keyval] in data.tags.entries()) {
|
for (let tagkey in data.tags) {
|
||||||
if (data.tags[key].name.length > 50) {
|
if (data.tags[tagkey].name.length > 50) {
|
||||||
console.log(
|
console.log("Skipping tag because it's too long: ",data.tags[tagkey].name.length);
|
||||||
"Skipping tag because it's too long: ",
|
|
||||||
data.tags[key].name.length
|
|
||||||
);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
newtags.push(data.tags[key].name);
|
newtags.push(data.tags[tagkey].name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newtags.length > 10) {
|
if (newtags.length > 10) {
|
||||||
@@ -625,6 +678,7 @@ const AppCreator = (defaultprops) => {
|
|||||||
console.log("Paths: ", data.paths)
|
console.log("Paths: ", data.paths)
|
||||||
if (data.paths !== null && data.paths !== undefined) {
|
if (data.paths !== null && data.paths !== undefined) {
|
||||||
for (let [path, pathvalue] of Object.entries(data.paths)) {
|
for (let [path, pathvalue] of Object.entries(data.paths)) {
|
||||||
|
|
||||||
for (let [method, methodvalue] of Object.entries(pathvalue)) {
|
for (let [method, methodvalue] of Object.entries(pathvalue)) {
|
||||||
if (methodvalue === null) {
|
if (methodvalue === null) {
|
||||||
alert.info("Skipped method (null)" + method);
|
alert.info("Skipped method (null)" + method);
|
||||||
@@ -685,24 +739,24 @@ const AppCreator = (defaultprops) => {
|
|||||||
const pathsplit = path.split("/");
|
const pathsplit = path.split("/");
|
||||||
var categoryindex = -1;
|
var categoryindex = -1;
|
||||||
// Stupid way of finding a category/grouping
|
// Stupid way of finding a category/grouping
|
||||||
for (let [key,keyval] in pathsplit.entries()) {
|
for (let splitkey in pathsplit) {
|
||||||
if (pathsplit[key].includes("_shuffle_replace_")) {
|
if (pathsplit[splitkey].includes("_shuffle_replace_")) {
|
||||||
const regex = /_shuffle_replace_\d/i;
|
const regex = /_shuffle_replace_\d/i;
|
||||||
//console.log("NEW: ",
|
//console.log("NEW: ",
|
||||||
pathsplit[key] = pathsplit[key].replaceAll(new RegExp(regex, 'g'), "")
|
pathsplit[splitkey] = pathsplit[splitkey].replaceAll(new RegExp(regex, 'g'), "")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
pathsplit[key].length > 0 &&
|
pathsplit[splitkey].length > 0 &&
|
||||||
pathsplit[key] !== "v1" &&
|
pathsplit[splitkey] !== "v1" &&
|
||||||
pathsplit[key] !== "v2" &&
|
pathsplit[splitkey] !== "v2" &&
|
||||||
pathsplit[key] !== "api" &&
|
pathsplit[splitkey] !== "api" &&
|
||||||
pathsplit[key] !== "1.0" &&
|
pathsplit[splitkey] !== "1.0" &&
|
||||||
pathsplit[key] !== "apis"
|
pathsplit[splitkey] !== "apis"
|
||||||
) {
|
) {
|
||||||
newaction["category"] = pathsplit[key];
|
newaction["category"] = pathsplit[splitkey];
|
||||||
if (!all_categories.includes(pathsplit[key])) {
|
if (!all_categories.includes(pathsplit[splitkey])) {
|
||||||
all_categories.push(pathsplit[key]);
|
all_categories.push(pathsplit[splitkey]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -743,16 +797,14 @@ const AppCreator = (defaultprops) => {
|
|||||||
console.log("Schema: ", methodvalue["requestBody"]["content"]["application/json"]["schema"])
|
console.log("Schema: ", methodvalue["requestBody"]["content"]["application/json"]["schema"])
|
||||||
if (methodvalue["requestBody"]["content"]["application/json"]["schema"]["properties"] !== undefined) {
|
if (methodvalue["requestBody"]["content"]["application/json"]["schema"]["properties"] !== undefined) {
|
||||||
var tmpobject = {};
|
var tmpobject = {};
|
||||||
for (let [prop, propvalue] of Object.entries(
|
for (let prop of methodvalue["requestBody"]["content"]["application/json"]["schema"]["properties"]) {
|
||||||
methodvalue["requestBody"]["content"]["application/json"]["schema"]["properties"]
|
|
||||||
)) {
|
|
||||||
tmpobject[prop] = `\$\{${prop}\}`;
|
tmpobject[prop] = `\$\{${prop}\}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
//console.log("Data: ", data)
|
//console.log("Data: ", data)
|
||||||
for (let [subkey,subkeyval] in methodvalue["requestBody"]["content"][
|
for (let subkey in methodvalue["requestBody"]["content"]["application/json"]["schema"]["required"]) {
|
||||||
"application/json"
|
|
||||||
]["schema"]["required"].entries()) {
|
|
||||||
const tmpitem =
|
const tmpitem =
|
||||||
methodvalue["requestBody"]["content"][
|
methodvalue["requestBody"]["content"][
|
||||||
"application/json"
|
"application/json"
|
||||||
@@ -771,7 +823,7 @@ const AppCreator = (defaultprops) => {
|
|||||||
);
|
);
|
||||||
var newbody = {};
|
var newbody = {};
|
||||||
// Can handle default, required, description and type
|
// Can handle default, required, description and type
|
||||||
for (let [propkey,propkeyval] in retRef.properties.entries()) {
|
for (let propkey in retRef.properties) {
|
||||||
console.log("replace: ", propkey)
|
console.log("replace: ", propkey)
|
||||||
|
|
||||||
const parsedkey = propkey.replaceAll(" ", "_").toLowerCase();
|
const parsedkey = propkey.replaceAll(" ", "_").toLowerCase();
|
||||||
@@ -802,17 +854,12 @@ const AppCreator = (defaultprops) => {
|
|||||||
]["properties"] !== undefined
|
]["properties"] !== undefined
|
||||||
) {
|
) {
|
||||||
var tmpobject = {};
|
var tmpobject = {};
|
||||||
for (let [prop, propvalue] of Object.entries(
|
for (let [prop, propvalue] of Object.entries(methodvalue["requestBody"]["content"]["application/xml"]["schema"]["properties"])) {
|
||||||
methodvalue["requestBody"]["content"]["application/xml"][
|
|
||||||
"schema"
|
|
||||||
]["properties"]
|
|
||||||
)) {
|
|
||||||
tmpobject[prop] = `\$\{${prop}\}`;
|
tmpobject[prop] = `\$\{${prop}\}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let [subkey,subkeyval] in methodvalue["requestBody"]["content"][
|
for (let [subkey,subkeyval] in Object.entries(methodvalue["requestBody"]["content"]["application/xml"]["schema"]["required"])) {
|
||||||
"application/xml"
|
|
||||||
]["schema"]["required"].entries()) {
|
|
||||||
const tmpitem =
|
const tmpitem =
|
||||||
methodvalue["requestBody"]["content"][
|
methodvalue["requestBody"]["content"][
|
||||||
"application/xml"
|
"application/xml"
|
||||||
@@ -854,11 +901,7 @@ const AppCreator = (defaultprops) => {
|
|||||||
"multipart/form-data"
|
"multipart/form-data"
|
||||||
]["schema"] !== null
|
]["schema"] !== null
|
||||||
) {
|
) {
|
||||||
if (
|
if (methodvalue["requestBody"]["content"]["multipart/form-data"]["schema"]["type"] === "object") {
|
||||||
methodvalue["requestBody"]["content"][
|
|
||||||
"multipart/form-data"
|
|
||||||
]["schema"]["type"] === "object"
|
|
||||||
) {
|
|
||||||
const fieldname =
|
const fieldname =
|
||||||
methodvalue["requestBody"]["content"][
|
methodvalue["requestBody"]["content"][
|
||||||
"multipart/form-data"
|
"multipart/form-data"
|
||||||
@@ -912,12 +955,11 @@ const AppCreator = (defaultprops) => {
|
|||||||
if (schemas.length === 1) {
|
if (schemas.length === 1) {
|
||||||
const parameter = handleGetRef({ $ref: schemas[0] }, data);
|
const parameter = handleGetRef({ $ref: schemas[0] }, data);
|
||||||
|
|
||||||
if (
|
console.log("Reading type from parameter: ", parameter)
|
||||||
parameter.properties !== undefined &&
|
if (parameter.properties !== undefined && parameter["type"] === "object") {
|
||||||
parameter["type"] === "object"
|
|
||||||
) {
|
|
||||||
var newbody = {};
|
var newbody = {};
|
||||||
for (let [propkey,propkeyval] in parameter.properties.entries()) {
|
for (let propkey in parameter.properties) {
|
||||||
console.log("propkey2: ", propkey)
|
console.log("propkey2: ", propkey)
|
||||||
const parsedkey = propkey.replaceAll(" ", "_").toLowerCase();
|
const parsedkey = propkey.replaceAll(" ", "_").toLowerCase();
|
||||||
if (parameter.properties[propkey].type === undefined) {
|
if (parameter.properties[propkey].type === undefined) {
|
||||||
@@ -987,7 +1029,6 @@ const AppCreator = (defaultprops) => {
|
|||||||
methodvalue.responses.default.content["text/plain"] !==
|
methodvalue.responses.default.content["text/plain"] !==
|
||||||
undefined
|
undefined
|
||||||
) {
|
) {
|
||||||
console.log("RESP: ", path, methodvalue.responses.default.content["text/plain"])
|
|
||||||
if (
|
if (
|
||||||
methodvalue.responses.default.content["text/plain"][
|
methodvalue.responses.default.content["text/plain"][
|
||||||
"schema"
|
"schema"
|
||||||
@@ -1039,19 +1080,15 @@ const AppCreator = (defaultprops) => {
|
|||||||
],
|
],
|
||||||
data
|
data
|
||||||
);
|
);
|
||||||
//console.log("GOT REF RETURN AS EXAMPLE: ", parameter)
|
|
||||||
|
|
||||||
if (
|
console.log("Reading parameter type 2", parameter)
|
||||||
parameter.properties !== undefined &&
|
if (parameter.properties !== undefined && parameter["type"] === "object") {
|
||||||
parameter["type"] === "object"
|
|
||||||
) {
|
|
||||||
var newbody = {};
|
var newbody = {};
|
||||||
for (let [propkey,propkeyval] in parameter.properties.entries()) {
|
for (let propkey in parameter.properties) {
|
||||||
console.log("propkey3: ", propkey)
|
console.log("propkey3: ", propkey)
|
||||||
|
|
||||||
const parsedkey = propkey.replaceAll(" ", "_").toLowerCase();
|
const parsedkey = propkey.replaceAll(" ", "_").toLowerCase();
|
||||||
if (
|
if (parameter.properties[propkey].type === undefined) {
|
||||||
parameter.properties[propkey].type === undefined
|
|
||||||
) {
|
|
||||||
console.log(
|
console.log(
|
||||||
"Skipping (1): ",
|
"Skipping (1): ",
|
||||||
parameter.properties[propkey]
|
parameter.properties[propkey]
|
||||||
@@ -1130,12 +1167,11 @@ const AppCreator = (defaultprops) => {
|
|||||||
selectedComponent,
|
selectedComponent,
|
||||||
data
|
data
|
||||||
);
|
);
|
||||||
if (
|
|
||||||
parameter.properties !== undefined &&
|
console.log("Reading parameter type 3!")
|
||||||
parameter["type"] === "object"
|
if (parameter.properties !== undefined && parameter["type"] === "object") {
|
||||||
) {
|
|
||||||
var newbody = {};
|
var newbody = {};
|
||||||
for (let [propkey,propkeyval] in parameter.properties.entries()) {
|
for (let propkey in parameter.properties) {
|
||||||
console.log("propkey4: ", propkey)
|
console.log("propkey4: ", propkey)
|
||||||
const parsedkey = propkey.replaceAll(" ", "_").toLowerCase();
|
const parsedkey = propkey.replaceAll(" ", "_").toLowerCase();
|
||||||
if (
|
if (
|
||||||
@@ -1214,12 +1250,11 @@ const AppCreator = (defaultprops) => {
|
|||||||
]["properties"]["data"],
|
]["properties"]["data"],
|
||||||
data
|
data
|
||||||
);
|
);
|
||||||
if (
|
|
||||||
parameter.properties !== undefined &&
|
console.log("Reading type 3: ", parameter)
|
||||||
parameter["type"] === "object"
|
if (parameter.properties !== undefined && parameter["type"] === "object") {
|
||||||
) {
|
|
||||||
var newbody = {};
|
var newbody = {};
|
||||||
for (let [propkey,keyval] in parameter.properties.entries()) {
|
for (let propkey in parameter.properties) {
|
||||||
console.log("propkey5: ", propkey)
|
console.log("propkey5: ", propkey)
|
||||||
const parsedkey = propkey
|
const parsedkey = propkey
|
||||||
.replaceAll(" ", "_")
|
.replaceAll(" ", "_")
|
||||||
@@ -1287,8 +1322,8 @@ const AppCreator = (defaultprops) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let [key,keyval] in methodvalue.parameters.entries()) {
|
for (let paramkey in methodvalue.parameters) {
|
||||||
const parameter = handleGetRef(methodvalue.parameters[key], data);
|
const parameter = handleGetRef(methodvalue.parameters[paramkey], data);
|
||||||
if (parameter.in === "query") {
|
if (parameter.in === "query") {
|
||||||
var tmpaction = {
|
var tmpaction = {
|
||||||
description: parameter.description,
|
description: parameter.description,
|
||||||
@@ -1334,8 +1369,9 @@ const AppCreator = (defaultprops) => {
|
|||||||
if (Object.getOwnPropertyNames(wordlist).length === 0) {
|
if (Object.getOwnPropertyNames(wordlist).length === 0) {
|
||||||
for (let [newpath, pathvalue] of Object.entries(data.paths)) {
|
for (let [newpath, pathvalue] of Object.entries(data.paths)) {
|
||||||
const newpathsplit = newpath.split("/");
|
const newpathsplit = newpath.split("/");
|
||||||
for (let [key,keyval] in newpathsplit.entries()) {
|
|
||||||
const pathitem = newpathsplit[key].toLowerCase();
|
for (let splitkey in newpathsplit) {
|
||||||
|
const pathitem = newpathsplit[splitkey].toLowerCase();
|
||||||
if (wordlist[pathitem] === undefined) {
|
if (wordlist[pathitem] === undefined) {
|
||||||
wordlist[pathitem] = 1;
|
wordlist[pathitem] = 1;
|
||||||
} else {
|
} else {
|
||||||
@@ -1351,8 +1387,8 @@ const AppCreator = (defaultprops) => {
|
|||||||
const urlsplit = path.split("/");
|
const urlsplit = path.split("/");
|
||||||
if (urlsplit.length > 0) {
|
if (urlsplit.length > 0) {
|
||||||
var curname = "";
|
var curname = "";
|
||||||
for (let [key,keyval] in urlsplit.entries()) {
|
for (let urlkey in urlsplit) {
|
||||||
var subpath = urlsplit[key];
|
var subpath = urlsplit[urlkey];
|
||||||
if (wordlist[subpath] > 2 || subpath.length < 1) {
|
if (wordlist[subpath] > 2 || subpath.length < 1) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -1396,8 +1432,7 @@ const AppCreator = (defaultprops) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
newaction.action_label = "No Label"
|
||||||
|
|
||||||
newActions.push(newaction);
|
newActions.push(newaction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1413,11 +1448,11 @@ const AppCreator = (defaultprops) => {
|
|||||||
const regex = /{\w+}/g;
|
const regex = /{\w+}/g;
|
||||||
const found = firstUrl.match(regex);
|
const found = firstUrl.match(regex);
|
||||||
if (found !== null) {
|
if (found !== null) {
|
||||||
for (let [key,keyval] in found.entries()) {
|
for (let foundkey in found) {
|
||||||
const item = found[key].slice(1, found[key].length - 1);
|
const item = found[foundkey].slice(1, found[foundkey].length - 1);
|
||||||
const foundVar = data.servers[0].variables[item];
|
const foundVar = data.servers[0].variables[item];
|
||||||
if (foundVar["default"] !== undefined) {
|
if (foundVar["default"] !== undefined) {
|
||||||
firstUrl = firstUrl.replace(found[key], foundVar["default"]);
|
firstUrl = firstUrl.replace(found[foundkey], foundVar["default"]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1436,7 +1471,6 @@ const AppCreator = (defaultprops) => {
|
|||||||
console.log("NEWAUTH: ", securitySchemes)
|
console.log("NEWAUTH: ", securitySchemes)
|
||||||
// FIXME: Should add Oauth2 (Microsoft) and JWT (Wazuh)
|
// FIXME: Should add Oauth2 (Microsoft) and JWT (Wazuh)
|
||||||
//console.log("SECURITY: ", securitySchemes)
|
//console.log("SECURITY: ", securitySchemes)
|
||||||
//if (Object.entries(securitySchemes) > 1 &&
|
|
||||||
var newauth = [];
|
var newauth = [];
|
||||||
try {
|
try {
|
||||||
var optionset = false
|
var optionset = false
|
||||||
@@ -1558,9 +1592,7 @@ const AppCreator = (defaultprops) => {
|
|||||||
setOauth2Scopes(value[flowkey][basekey].scopes);
|
setOauth2Scopes(value[flowkey][basekey].scopes);
|
||||||
} else {
|
} else {
|
||||||
var newscopes = [];
|
var newscopes = [];
|
||||||
for (let [scopekey, scopevalue] of Object.entries(
|
for (let [scopekey, scopevalue] of Object.entries(value[flowkey][basekey].scopes)) {
|
||||||
value[flowkey][basekey].scopes
|
|
||||||
)) {
|
|
||||||
if (scopekey.startsWith("http")) {
|
if (scopekey.startsWith("http")) {
|
||||||
const scopekeysplit = scopekey.split("/");
|
const scopekeysplit = scopekey.split("/");
|
||||||
if (scopekeysplit.length < 5) {
|
if (scopekeysplit.length < 5) {
|
||||||
@@ -1683,8 +1715,8 @@ const AppCreator = (defaultprops) => {
|
|||||||
|
|
||||||
if (newWorkflowTags.length > 0) {
|
if (newWorkflowTags.length > 0) {
|
||||||
var newtags = [];
|
var newtags = [];
|
||||||
for (let [key,keyval] in newWorkflowTags.entries()) {
|
for (let tagkey in newWorkflowTags) {
|
||||||
newtags.push({ name: newWorkflowTags[key] });
|
newtags.push({ name: newWorkflowTags[tagkey] });
|
||||||
}
|
}
|
||||||
|
|
||||||
data["tags"] = newtags;
|
data["tags"] = newtags;
|
||||||
@@ -1696,8 +1728,8 @@ const AppCreator = (defaultprops) => {
|
|||||||
|
|
||||||
// Handles actions
|
// Handles actions
|
||||||
var handledPaths = []
|
var handledPaths = []
|
||||||
for (let [key,keyval] in actions.entries()) {
|
for (let actionkey in actions) {
|
||||||
var item = JSON.parse(JSON.stringify(actions[key]))
|
var item = JSON.parse(JSON.stringify(actions[actionkey]))
|
||||||
if (item.errors.length > 0) {
|
if (item.errors.length > 0) {
|
||||||
alert.error("Saving with error in action " + item.name);
|
alert.error("Saving with error in action " + item.name);
|
||||||
}
|
}
|
||||||
@@ -1822,7 +1854,7 @@ const AppCreator = (defaultprops) => {
|
|||||||
if (item.queries.length > 0) {
|
if (item.queries.length > 0) {
|
||||||
var skipped = false;
|
var skipped = false;
|
||||||
var querynames = []
|
var querynames = []
|
||||||
for (let [querykey,querykeyval] in item.queries.entries()) {
|
for (let querykey in item.queries) {
|
||||||
const queryitem = item.queries[querykey];
|
const queryitem = item.queries[querykey];
|
||||||
|
|
||||||
if (queryitem === undefined || queryitem === null || queryitem.name === undefined || queryitem.name === null || queryitem.name === "") {
|
if (queryitem === undefined || queryitem === null || queryitem.name === undefined || queryitem.name === null || queryitem.name === "") {
|
||||||
@@ -1923,7 +1955,7 @@ const AppCreator = (defaultprops) => {
|
|||||||
//data.paths[item.url][item.method.toLowerCase()].parameters.push(newitem)
|
//data.paths[item.url][item.method.toLowerCase()].parameters.push(newitem)
|
||||||
|
|
||||||
if (item.paths.length > 0) {
|
if (item.paths.length > 0) {
|
||||||
for (let [querykey,querykeyval] in item.paths.entries()) {
|
for (let querykey in item.paths) {
|
||||||
const queryitem = item.paths[querykey];
|
const queryitem = item.paths[querykey];
|
||||||
|
|
||||||
if (queryitem.toLowerCase() == "url") {
|
if (queryitem.toLowerCase() == "url") {
|
||||||
@@ -1948,9 +1980,7 @@ const AppCreator = (defaultprops) => {
|
|||||||
newitem.description = queryitem.description;
|
newitem.description = queryitem.description;
|
||||||
}
|
}
|
||||||
|
|
||||||
data.paths[item.url][item.method.toLowerCase()].parameters.push(
|
data.paths[item.url][item.method.toLowerCase()].parameters.push(newitem);
|
||||||
newitem
|
|
||||||
);
|
|
||||||
//console.log(queryitem)
|
//console.log(queryitem)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -1958,7 +1988,7 @@ const AppCreator = (defaultprops) => {
|
|||||||
const values = getCurrentPaths(item.url);
|
const values = getCurrentPaths(item.url);
|
||||||
const paths = values[0];
|
const paths = values[0];
|
||||||
|
|
||||||
for (let [querykey,querykeyval] in paths.entries()) {
|
for (let querykey in paths) {
|
||||||
const queryitem = paths[querykey];
|
const queryitem = paths[querykey];
|
||||||
newitem = {
|
newitem = {
|
||||||
in: "path",
|
in: "path",
|
||||||
@@ -1996,25 +2026,25 @@ const AppCreator = (defaultprops) => {
|
|||||||
// but it's the only way we can properly support e.g. GraphQL
|
// but it's the only way we can properly support e.g. GraphQL
|
||||||
// with good examples
|
// with good examples
|
||||||
var newbody = ""
|
var newbody = ""
|
||||||
for (let [key,keyval] in item.body.entries()) {
|
for (let bodykey in item.body) {
|
||||||
if (item.body[key] === "$") {
|
if (item.body[bodykey] === "$") {
|
||||||
if (key > 0) {
|
if (bodykey > 0) {
|
||||||
//console.log("Found: ", item.body[key-1])
|
|
||||||
const newkey = parseInt(key, 10)
|
const newkey = parseInt(bodykey, 10)
|
||||||
if (item.body[newkey-1] !== "\\") {
|
if (item.body[newkey-1] !== "\\") {
|
||||||
if (item.body[newkey+1] !== "\{") {
|
if (item.body[newkey+1] !== "\{") {
|
||||||
newbody += "\\"
|
newbody += "\\"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
newbody += item.body[key]
|
newbody += item.body[bodykey]
|
||||||
} else {
|
} else {
|
||||||
newbody += "\\"
|
newbody += "\\"
|
||||||
newbody += item.body[key]
|
newbody += item.body[bodykey]
|
||||||
}
|
}
|
||||||
//newbody += item.body[key]
|
|
||||||
} else {
|
} else {
|
||||||
newbody += item.body[key]
|
newbody += item.body[bodykey]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2118,42 +2148,43 @@ const AppCreator = (defaultprops) => {
|
|||||||
const required = false;
|
const required = false;
|
||||||
|
|
||||||
const headersSplit = item.headers.split("\n");
|
const headersSplit = item.headers.split("\n");
|
||||||
for (let [key,keyval] in headersSplit.entries()) {
|
for (let headerkey in headersSplit) {
|
||||||
const header = headersSplit[key];
|
const header = headersSplit[headerkey];
|
||||||
// var key = "";
|
|
||||||
|
var innerkey = ""
|
||||||
var value = "";
|
var value = "";
|
||||||
if (header.length > 0 && header.includes("= ")) {
|
if (header.length > 0 && header.includes("= ")) {
|
||||||
const headersplit = header.split("= ");
|
const headersplit = header.split("= ");
|
||||||
key = headersplit[0];
|
innerkey = headersplit[0];
|
||||||
value = headersplit[1];
|
value = headersplit[1];
|
||||||
} else if (header.length > 0 && header.includes(" =")) {
|
} else if (header.length > 0 && header.includes(" =")) {
|
||||||
const headersplit = header.split(" =");
|
const headersplit = header.split(" =");
|
||||||
key = headersplit[0];
|
innerkey = headersplit[0];
|
||||||
value = headersplit[1];
|
value = headersplit[1];
|
||||||
} else if (header.length > 0 && header.includes("=")) {
|
} else if (header.length > 0 && header.includes("=")) {
|
||||||
const headersplit = header.split("=");
|
const headersplit = header.split("=");
|
||||||
key = headersplit[0];
|
innerkey = headersplit[0];
|
||||||
value = headersplit[1];
|
value = headersplit[1];
|
||||||
} else if (header.length > 0 && header.includes(": ")) {
|
} else if (header.length > 0 && header.includes(": ")) {
|
||||||
const headersplit = header.split(": ");
|
const headersplit = header.split(": ");
|
||||||
key = headersplit[0];
|
innerkey = headersplit[0];
|
||||||
value = headersplit[1];
|
value = headersplit[1];
|
||||||
} else if (header.length > 0 && header.includes(" :")) {
|
} else if (header.length > 0 && header.includes(" :")) {
|
||||||
const headersplit = header.split(" :");
|
const headersplit = header.split(" :");
|
||||||
key = headersplit[0];
|
innerkey = headersplit[0];
|
||||||
value = headersplit[1];
|
value = headersplit[1];
|
||||||
} else if (header.length > 0 && header.includes(":")) {
|
} else if (header.length > 0 && header.includes(":")) {
|
||||||
const headersplit = header.split(":");
|
const headersplit = header.split(":");
|
||||||
key = headersplit[0];
|
innerkey = headersplit[0];
|
||||||
value = headersplit[1];
|
value = headersplit[1];
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key.length > 0 && value.length > 0) {
|
if (innerkey.length > 0 && value.length > 0) {
|
||||||
newitem = {
|
newitem = {
|
||||||
in: "header",
|
in: "header",
|
||||||
name: key,
|
name: innerkey,
|
||||||
multiline: false,
|
multiline: false,
|
||||||
description: "Header generated by shuffler.io OpenAPI",
|
description: "Header generated by shuffler.io OpenAPI",
|
||||||
required: false,
|
required: false,
|
||||||
@@ -2235,8 +2266,8 @@ const AppCreator = (defaultprops) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (setExtraAuth.length > 0) {
|
if (setExtraAuth.length > 0) {
|
||||||
for (var key in extraAuth) {
|
for (let authkey in extraAuth) {
|
||||||
const curauth = extraAuth[key];
|
const curauth = extraAuth[authkey];
|
||||||
|
|
||||||
if (curauth.name.toLowerCase() == "url") {
|
if (curauth.name.toLowerCase() == "url") {
|
||||||
alert.error("Can't add extra auth with Name URL");
|
alert.error("Can't add extra auth with Name URL");
|
||||||
@@ -2327,30 +2358,6 @@ const AppCreator = (defaultprops) => {
|
|||||||
</div>
|
</div>
|
||||||
) : null;
|
) : null;
|
||||||
|
|
||||||
// API key
|
|
||||||
//const verifyBaseUrl = () => {
|
|
||||||
// if (baseUrl.startsWith("http://") || baseUrl.startsWith("https://")) {
|
|
||||||
// return true
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (baseUrl.endsWith("/")) {
|
|
||||||
// return true
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return false
|
|
||||||
//}
|
|
||||||
|
|
||||||
//const verifyApiParameter = () => {
|
|
||||||
// const notAllowed = ["!","#","$","%","&","'","^","+","-",".","_","~","|","]","+","$",]
|
|
||||||
// for (var key in notAllowed) {
|
|
||||||
// if (parameterName.includes(notAllowed[key])) {
|
|
||||||
// return false
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return true
|
|
||||||
//}
|
|
||||||
|
|
||||||
const testAction = (index) => {
|
const testAction = (index) => {
|
||||||
console.log("Should test action at index " + index);
|
console.log("Should test action at index " + index);
|
||||||
console.log(actions[index]);
|
console.log(actions[index]);
|
||||||
@@ -3021,6 +3028,9 @@ const AppCreator = (defaultprops) => {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const foundCategory = newWorkflowCategories !== undefined && newWorkflowCategories !== null && newWorkflowCategories.length > 0 ? categories.find((x) => x.name === newWorkflowCategories[0]) : undefined
|
||||||
|
const actionLabels = foundCategory !== undefined && foundCategory !== null && foundCategory.action_labels.length > 0 ? ["No Label"].concat(foundCategory.action_labels) : []
|
||||||
|
|
||||||
const loopActions =
|
const loopActions =
|
||||||
actions.length === 0 ? null : (
|
actions.length === 0 ? null : (
|
||||||
<div>
|
<div>
|
||||||
@@ -3157,6 +3167,48 @@ const AppCreator = (defaultprops) => {
|
|||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
*/}
|
*/}
|
||||||
|
|
||||||
|
{/* From 2023: Example of handling action labels */}
|
||||||
|
{/*actionLabels.length > 0 && newWorkflowCategories !== undefined && newWorkflowCategories !== null && newWorkflowCategories.length > 0 && categories.length > 0 ?
|
||||||
|
(
|
||||||
|
<Select
|
||||||
|
fullWidth
|
||||||
|
onChange={(e) => {
|
||||||
|
console.log("Should change: ", e.target.value)
|
||||||
|
|
||||||
|
actions[index].action_label = e.target.value
|
||||||
|
setActions(actions)
|
||||||
|
setUpdate(Math.random());
|
||||||
|
}}
|
||||||
|
value={data.action_label}
|
||||||
|
style={{
|
||||||
|
backgroundColor: inputColor,
|
||||||
|
paddingLeft: 10,
|
||||||
|
color: "white",
|
||||||
|
height: 30,
|
||||||
|
maxWidth: 50,
|
||||||
|
marginLeft: 10,
|
||||||
|
}}
|
||||||
|
inputProps={{
|
||||||
|
name: "Method",
|
||||||
|
id: "method-option",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{actionLabels.map((label, labelindex) => {
|
||||||
|
return (
|
||||||
|
<MenuItem
|
||||||
|
key={labelindex}
|
||||||
|
value={label}
|
||||||
|
style={{ }}
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
</MenuItem>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</Select>
|
||||||
|
)
|
||||||
|
: null*/}
|
||||||
|
|
||||||
<Tooltip
|
<Tooltip
|
||||||
title="Duplicate action"
|
title="Duplicate action"
|
||||||
placement="bottom"
|
placement="bottom"
|
||||||
@@ -4056,17 +4108,6 @@ const AppCreator = (defaultprops) => {
|
|||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
|
|
||||||
const categories = [
|
|
||||||
"Communication",
|
|
||||||
"Cases",
|
|
||||||
"SIEM",
|
|
||||||
"Assets",
|
|
||||||
"Intel",
|
|
||||||
"IAM",
|
|
||||||
"Network",
|
|
||||||
"Eradication",
|
|
||||||
"Other",
|
|
||||||
];
|
|
||||||
|
|
||||||
const tagView = (
|
const tagView = (
|
||||||
<div style={{ color: "white" }}>
|
<div style={{ color: "white" }}>
|
||||||
@@ -4094,7 +4135,7 @@ const AppCreator = (defaultprops) => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
*/}
|
*/}
|
||||||
<h4>Categories</h4>
|
<h4>Choose a Category</h4>
|
||||||
<Select
|
<Select
|
||||||
fullWidth
|
fullWidth
|
||||||
SelectDisplayProps={{
|
SelectDisplayProps={{
|
||||||
@@ -4114,7 +4155,7 @@ const AppCreator = (defaultprops) => {
|
|||||||
style={{ backgroundColor: inputColor, color: "white", height: "50px" }}
|
style={{ backgroundColor: inputColor, color: "white", height: "50px" }}
|
||||||
>
|
>
|
||||||
{categories.map((data, index) => {
|
{categories.map((data, index) => {
|
||||||
if (data === undefined || data === null || data === "") {
|
if (data === undefined || data === null || data === "" || data === undefined || data === null || data === "") {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4122,9 +4163,9 @@ const AppCreator = (defaultprops) => {
|
|||||||
<MenuItem
|
<MenuItem
|
||||||
key={index}
|
key={index}
|
||||||
style={{ backgroundColor: inputColor, color: "white" }}
|
style={{ backgroundColor: inputColor, color: "white" }}
|
||||||
value={data}
|
value={data.name}
|
||||||
>
|
>
|
||||||
{data}
|
{data.name}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -1020,11 +1020,11 @@ const Workflows = (props) => {
|
|||||||
if (response.status !== 200) {
|
if (response.status !== 200) {
|
||||||
console.log("Status not 200 for workflows :O!: ", response.status);
|
console.log("Status not 200 for workflows :O!: ", response.status);
|
||||||
|
|
||||||
if (isCloud) {
|
//if (isCloud) {
|
||||||
navigate("/search?tab=workflows")
|
// navigate("/search?tab=workflows")
|
||||||
}
|
//}
|
||||||
|
|
||||||
alert.info("Failed getting workflows.");
|
alert.info("Failed getting workflows. Are you logged in?");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -3757,7 +3757,7 @@ const Workflows = (props) => {
|
|||||||
<div style={{borderTop: "1px solid rgba(255,255,255,0.3)", }}>
|
<div style={{borderTop: "1px solid rgba(255,255,255,0.3)", }}>
|
||||||
{gettingStartedItems.map((item, index) => {
|
{gettingStartedItems.map((item, index) => {
|
||||||
return (
|
return (
|
||||||
<GettingStartedItem item={item} index={index} />
|
<GettingStartedItem key={index} item={item} index={index} />
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user