From aacc7ccec24c01231ab415b449d70c90b933ac7b Mon Sep 17 00:00:00 2001 From: Nicole Rappe Date: Fri, 3 Oct 2025 15:59:38 -0600 Subject: [PATCH 1/4] Adjust variable editor row layout --- .../Examples/Write_Canary.txt_to_C_.json | 8 - .../WebUI/src/Assemblies/Assembly_Editor.jsx | 259 ++++++++++++------ Data/Server/job_scheduler.py | 3 - Data/Server/server.py | 3 - 4 files changed, 172 insertions(+), 101 deletions(-) diff --git a/Assemblies/Scripts/Examples/Write_Canary.txt_to_C_.json b/Assemblies/Scripts/Examples/Write_Canary.txt_to_C_.json index 208be71..bace9c0 100644 --- a/Assemblies/Scripts/Examples/Write_Canary.txt_to_C_.json +++ b/Assemblies/Scripts/Examples/Write_Canary.txt_to_C_.json @@ -5,14 +5,6 @@ "category": "script", "type": "powershell", "script": "# Define the file path\n$filePath = \"C:\\Canary.txt\"\n\n# Write some content into the file\n\"SYSTEM Canary is alive.\"ddss | Out-File -FilePath $filePath -Encoding UTF8\n", - "script_lines": [ - "# Define the file path", - "$filePath = \"C:\\Canary.txt\"", - "", - "# Write some content into the file", - "\"SYSTEM Canary is alive.\"ddss | Out-File -FilePath $filePath -Encoding UTF8", - "" - ], "timeout_seconds": 3600, "sites": { "mode": "specific", diff --git a/Data/Server/WebUI/src/Assemblies/Assembly_Editor.jsx b/Data/Server/WebUI/src/Assemblies/Assembly_Editor.jsx index f9dc7ce..e27bf4f 100644 --- a/Data/Server/WebUI/src/Assemblies/Assembly_Editor.jsx +++ b/Data/Server/WebUI/src/Assemblies/Assembly_Editor.jsx @@ -212,13 +212,11 @@ function fromServerDocument(doc = {}, defaultType = "powershell") { assembly.description = doc.description || ""; assembly.category = doc.category || assembly.category; assembly.type = doc.type || assembly.type; - if (Array.isArray(doc.script_lines)) { - assembly.script = doc.script_lines - .map((line) => (line == null ? "" : String(line))) - .join("\n"); - } else { - assembly.script = doc.script ?? doc.content ?? ""; - } + const legacyScript = Array.isArray(doc.script_lines) + ? doc.script_lines.map((line) => (line == null ? "" : String(line))).join("\n") + : ""; + const script = doc.script ?? doc.content ?? legacyScript; + assembly.script = typeof script === "string" ? script : legacyScript; const timeout = doc.timeout_seconds ?? doc.timeout ?? assembly.timeoutSeconds; assembly.timeoutSeconds = Number.isFinite(Number(timeout)) ? Number(timeout) @@ -238,7 +236,6 @@ function toServerDocument(assembly) { const normalizedScript = typeof assembly.script === "string" ? assembly.script.replace(/\r\n/g, "\n") : ""; - const scriptLines = normalizedScript ? normalizedScript.split("\n") : []; const timeoutNumeric = Number(assembly.timeoutSeconds); const timeoutSeconds = Number.isFinite(timeoutNumeric) ? Math.max(0, Math.round(timeoutNumeric)) : 3600; return { @@ -248,7 +245,6 @@ function toServerDocument(assembly) { category: assembly.category || "script", type: assembly.type || "powershell", script: normalizedScript, - script_lines: scriptLines, timeout_seconds: timeoutSeconds, sites: { mode: assembly.sites?.mode === "specific" ? "specific" : "all", @@ -728,12 +724,16 @@ export default function AssemblyEditor({ value={assembly.description} onChange={(e) => updateAssembly({ description: e.target.value })} multiline - minRows={3} + minRows={2} + maxRows={8} fullWidth variant="outlined" sx={{ ...INPUT_BASE_SX, - "& .MuiOutlinedInput-inputMultiline": { padding: "4px 8px" } + "& .MuiOutlinedInput-inputMultiline": { + padding: "6px 12px", + lineHeight: 1.4 + } }} /> @@ -902,92 +902,177 @@ export default function AssemblyEditor({ key={variable.id} sx={{ p: 2, bgcolor: BACKGROUND_COLORS.field, border: "1px solid #2b3544", borderRadius: 1 }} > - - - updateVariable(variable.id, { name: e.target.value })} - fullWidth - variant="outlined" - sx={INPUT_BASE_SX} - /> - - - updateVariable(variable.id, { label: e.target.value })} - fullWidth - variant="outlined" - sx={INPUT_BASE_SX} - /> - - - updateVariable(variable.id, { type: e.target.value })} - sx={SELECT_BASE_SX} - SelectProps={{ MenuProps: MENU_PROPS }} - > - {VARIABLE_TYPE_OPTIONS.map((opt) => ( - {opt.label} - ))} - - - - {variable.type === "boolean" ? ( - updateVariable(variable.id, { defaultValue: e.target.checked })} - sx={{ color: "#58a6ff" }} - /> - } - label="Default Value" - /> - ) : ( + + + + \". For example, a variable named \"message\" would be written in the script as \"$env:message\"." + arrow + placement="top-start" + > updateVariable(variable.id, { defaultValue: e.target.value })} + label="Variable" + value={variable.name} + onChange={(e) => updateVariable(variable.id, { name: e.target.value })} fullWidth variant="outlined" sx={INPUT_BASE_SX} /> + + + + + updateVariable(variable.id, { label: e.target.value })} + fullWidth + variant="outlined" + sx={INPUT_BASE_SX} + /> + + + + + updateVariable(variable.id, { type: e.target.value })} + sx={SELECT_BASE_SX} + SelectProps={{ MenuProps: MENU_PROPS }} + > + {VARIABLE_TYPE_OPTIONS.map((opt) => ( + {opt.label} + ))} + + + + + {variable.type === "boolean" ? ( + + updateVariable(variable.id, { defaultValue: e.target.checked })} + sx={{ color: "#58a6ff" }} + /> + } + label="Default Value" + sx={{ + color: "#9ba3b4", + m: 0, + "& .MuiFormControlLabel-label": { fontSize: "0.95rem" } + }} + /> + + ) : ( + + updateVariable(variable.id, { defaultValue: e.target.value })} + fullWidth + variant="outlined" + sx={INPUT_BASE_SX} + /> + )} - - - + + + + Required + updateVariable(variable.id, { required: e.target.checked })} - sx={{ color: "#58a6ff" }} + sx={{ color: "#58a6ff", p: 0.5 }} + inputProps={{ "aria-label": "Required" }} /> - - - - updateVariable(variable.id, { description: e.target.value })} - fullWidth - multiline - minRows={2} - variant="outlined" - sx={INPUT_BASE_SX} - /> - - - removeVariable(variable.id)} sx={{ color: "#ff6b6b" }}> - - - - + + + + removeVariable(variable.id)} sx={{ color: "#ff6b6b" }}> + + + + + + + + + updateVariable(variable.id, { description: e.target.value })} + fullWidth + variant="outlined" + sx={INPUT_BASE_SX} + /> + + + + ))} diff --git a/Data/Server/job_scheduler.py b/Data/Server/job_scheduler.py index f236faf..e6fd70e 100644 --- a/Data/Server/job_scheduler.py +++ b/Data/Server/job_scheduler.py @@ -182,7 +182,6 @@ class JobScheduler: "category": "application" if default_type == "ansible" else "script", "type": default_type, "script": "", - "script_lines": [], "variables": [], "files": [], "timeout_seconds": 3600, @@ -217,7 +216,6 @@ class JobScheduler: doc["script"] = content_val normalized_script = (doc["script"] or "").replace("\r\n", "\n") doc["script"] = normalized_script - doc["script_lines"] = normalized_script.split("\n") if normalized_script else [] try: timeout_raw = data.get("timeout_seconds", data.get("timeout")) if timeout_raw is None: @@ -271,7 +269,6 @@ class JobScheduler: content = "" normalized_script = (content or "").replace("\r\n", "\n") doc["script"] = normalized_script - doc["script_lines"] = normalized_script.split("\n") if normalized_script else [] return doc def _ansible_root(self) -> str: diff --git a/Data/Server/server.py b/Data/Server/server.py index 6c80221..631eb86 100644 --- a/Data/Server/server.py +++ b/Data/Server/server.py @@ -682,7 +682,6 @@ def _empty_assembly_document(default_type: str = "powershell") -> Dict[str, Any] "category": "application" if (default_type or "").lower() == "ansible" else "script", "type": default_type or "powershell", "script": "", - "script_lines": [], "timeout_seconds": 3600, "sites": {"mode": "all", "values": []}, "variables": [], @@ -718,7 +717,6 @@ def _normalize_assembly_document(obj: Any, default_type: str, base_name: str) -> doc["script"] = content_val normalized_script = (doc["script"] or "").replace("\r\n", "\n") doc["script"] = normalized_script - doc["script_lines"] = normalized_script.split("\n") if normalized_script else [] timeout_val = obj.get("timeout_seconds", obj.get("timeout")) if timeout_val is not None: try: @@ -798,7 +796,6 @@ def _load_assembly_document(abs_path: str, island: str, type_hint: str = "") -> doc["name"] = base_name normalized_script = (content or "").replace("\r\n", "\n") doc["script"] = normalized_script - doc["script_lines"] = normalized_script.split("\n") if normalized_script else [] if default_type == "ansible": doc["category"] = "application" return doc From 80646ee84285509ed135d615b4bedcc51895a034 Mon Sep 17 00:00:00 2001 From: Nicole Rappe Date: Fri, 3 Oct 2025 16:10:05 -0600 Subject: [PATCH 2/4] Reposition variable description and required controls --- .../WebUI/src/Assemblies/Assembly_Editor.jsx | 199 +++++++++--------- 1 file changed, 99 insertions(+), 100 deletions(-) diff --git a/Data/Server/WebUI/src/Assemblies/Assembly_Editor.jsx b/Data/Server/WebUI/src/Assemblies/Assembly_Editor.jsx index e27bf4f..79326b8 100644 --- a/Data/Server/WebUI/src/Assemblies/Assembly_Editor.jsx +++ b/Data/Server/WebUI/src/Assemblies/Assembly_Editor.jsx @@ -918,15 +918,15 @@ export default function AssemblyEditor({ arrow placement="top-start" > - updateVariable(variable.id, { name: e.target.value })} - fullWidth - variant="outlined" - sx={INPUT_BASE_SX} - /> - + updateVariable(variable.id, { name: e.target.value })} + fullWidth + variant="outlined" + sx={INPUT_BASE_SX} + /> + - updateVariable(variable.id, { label: e.target.value })} - fullWidth - variant="outlined" - sx={INPUT_BASE_SX} - /> - + updateVariable(variable.id, { label: e.target.value })} + fullWidth + variant="outlined" + sx={INPUT_BASE_SX} + /> + + + + + updateVariable(variable.id, { description: e.target.value })} + fullWidth + variant="outlined" + sx={INPUT_BASE_SX} + /> + - updateVariable(variable.id, { type: e.target.value })} - sx={SELECT_BASE_SX} - SelectProps={{ MenuProps: MENU_PROPS }} > - {VARIABLE_TYPE_OPTIONS.map((opt) => ( - {opt.label} - ))} - - + updateVariable(variable.id, { type: e.target.value })} + sx={SELECT_BASE_SX} + SelectProps={{ MenuProps: MENU_PROPS }} + > + {VARIABLE_TYPE_OPTIONS.map((opt) => ( + {opt.label} + ))} + + - updateVariable(variable.id, { defaultValue: e.target.checked })} - sx={{ color: "#58a6ff" }} - /> - } - label="Default Value" - sx={{ - color: "#9ba3b4", - m: 0, - "& .MuiFormControlLabel-label": { fontSize: "0.95rem" } - }} - /> - - ) : ( - - updateVariable(variable.id, { defaultValue: e.target.value })} - fullWidth - variant="outlined" - sx={INPUT_BASE_SX} - /> - - )} - - - - Required - - updateVariable(variable.id, { required: e.target.checked })} - sx={{ color: "#58a6ff", p: 0.5 }} - inputProps={{ "aria-label": "Required" }} - /> + > + updateVariable(variable.id, { defaultValue: e.target.checked })} + sx={{ color: "#58a6ff" }} + /> + } + label="Default Value" + sx={{ + color: "#9ba3b4", + m: 0, + "& .MuiFormControlLabel-label": { fontSize: "0.95rem" } + }} + /> + + ) : ( + + updateVariable(variable.id, { defaultValue: e.target.value })} + fullWidth + variant="outlined" + sx={INPUT_BASE_SX} + /> + + )} - - - updateVariable(variable.id, { description: e.target.value })} - fullWidth - variant="outlined" - sx={INPUT_BASE_SX} - /> - + + + Required + + updateVariable(variable.id, { required: e.target.checked })} + sx={{ color: "#58a6ff", p: 0.5 }} + inputProps={{ "aria-label": "Required" }} + /> From 40840089feb9a31ed7d5b5eb1ce5ab3f19e37deb Mon Sep 17 00:00:00 2001 From: Nicole Rappe Date: Fri, 3 Oct 2025 16:30:42 -0600 Subject: [PATCH 3/4] Fixed Placeholder Text and Field Scaling --- .../WebUI/src/Assemblies/Assembly_Editor.jsx | 106 ++++++++++-------- 1 file changed, 59 insertions(+), 47 deletions(-) diff --git a/Data/Server/WebUI/src/Assemblies/Assembly_Editor.jsx b/Data/Server/WebUI/src/Assemblies/Assembly_Editor.jsx index 79326b8..318bfec 100644 --- a/Data/Server/WebUI/src/Assemblies/Assembly_Editor.jsx +++ b/Data/Server/WebUI/src/Assemblies/Assembly_Editor.jsx @@ -66,26 +66,29 @@ const INPUT_BASE_SX = { "&:hover fieldset": { borderColor: "#3a4657" }, "&.Mui-focused fieldset": { borderColor: "#58a6ff" } }, + "& .MuiOutlinedInput-input": { padding: "9px 12px", - fontSize: "0.95rem" + fontSize: "0.95rem", + lineHeight: 1.4 }, + "& .MuiOutlinedInput-inputMultiline": { padding: "9px 12px" }, - "& .MuiInputLabel-root": { color: "#9ba3b4" }, + + "& .MuiInputLabel-root": { + color: "#9ba3b4", + transform: "translate(12px, 11px) scale(0.8)" // label at rest (inside field) + }, "& .MuiInputLabel-root.Mui-focused": { color: "#58a6ff" }, - "& input[type=number]": { - MozAppearance: "textfield" + "& .MuiInputLabel-root.MuiInputLabel-shrink": { + transform: "translate(12px, -6px) scale(0.75)" // floated label position }, - "& input[type=number]::-webkit-outer-spin-button": { - WebkitAppearance: "none", - margin: 0 - }, - "& input[type=number]::-webkit-inner-spin-button": { - WebkitAppearance: "none", - margin: 0 - } + + "& input[type=number]": { MozAppearance: "textfield" }, + "& input[type=number]::-webkit-outer-spin-button": { WebkitAppearance: "none", margin: 0 }, + "& input[type=number]::-webkit-inner-spin-button": { WebkitAppearance: "none", margin: 0 } }; const SELECT_BASE_SX = { @@ -914,7 +917,7 @@ export default function AssemblyEditor({ > \". For example, a variable named \"message\" would be written in the script as \"$env:message\"." + title="This is the name of the variable you will be referencing inside of the script via $env:." arrow placement="top-start" > @@ -944,22 +947,7 @@ export default function AssemblyEditor({ /> - - - updateVariable(variable.id, { description: e.target.value })} - fullWidth - variant="outlined" - sx={INPUT_BASE_SX} - /> - - + )} + + + updateVariable(variable.id, { description: e.target.value })} + fullWidth + variant="outlined" + sx={INPUT_BASE_SX} + /> + + - + - - Required - - updateVariable(variable.id, { required: e.target.checked })} - sx={{ color: "#58a6ff", p: 0.5 }} - inputProps={{ "aria-label": "Required" }} - /> - + Required + + + updateVariable(variable.id, { required: e.target.checked }) + } + sx={{ + color: "#58a6ff", + p: 0.5, + }} + inputProps={{ "aria-label": "Required" }} + /> + From dde1d07210ddad54347545d807e5c1922579000c Mon Sep 17 00:00:00 2001 From: Nicole Rappe Date: Fri, 3 Oct 2025 16:59:41 -0600 Subject: [PATCH 4/4] Misc Updates to Assembly Editor Design --- .../Examples/Write Canary to C Drive Root.ps1 | 5 - .../Examples/Write_Canary.txt_to_C_.json | 26 ---- .../Write_Canary_File_to_C_Drive.json | 24 +++ .../WebUI/src/Assemblies/Assembly_Editor.jsx | 138 ++++++++++-------- 4 files changed, 98 insertions(+), 95 deletions(-) delete mode 100644 Assemblies/Scripts/Examples/Write Canary to C Drive Root.ps1 delete mode 100644 Assemblies/Scripts/Examples/Write_Canary.txt_to_C_.json create mode 100644 Assemblies/Scripts/Examples/Write_Canary_File_to_C_Drive.json diff --git a/Assemblies/Scripts/Examples/Write Canary to C Drive Root.ps1 b/Assemblies/Scripts/Examples/Write Canary to C Drive Root.ps1 deleted file mode 100644 index a1d7a2a..0000000 --- a/Assemblies/Scripts/Examples/Write Canary to C Drive Root.ps1 +++ /dev/null @@ -1,5 +0,0 @@ -# Define the file path -$filePath = "C:\Canary.txt" - -# Write some content into the file -"SYSTEM Canary is alive." | Out-File -FilePath $filePath -Encoding UTF8 diff --git a/Assemblies/Scripts/Examples/Write_Canary.txt_to_C_.json b/Assemblies/Scripts/Examples/Write_Canary.txt_to_C_.json deleted file mode 100644 index bace9c0..0000000 --- a/Assemblies/Scripts/Examples/Write_Canary.txt_to_C_.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "version": 1, - "name": "Write Canary File to C:\\Canary.txt", - "description": "Self-explanatory.", - "category": "script", - "type": "powershell", - "script": "# Define the file path\n$filePath = \"C:\\Canary.txt\"\n\n# Write some content into the file\n\"SYSTEM Canary is alive.\"ddss | Out-File -FilePath $filePath -Encoding UTF8\n", - "timeout_seconds": 3600, - "sites": { - "mode": "specific", - "values": [ - "1" - ] - }, - "variables": [ - { - "name": "Example Variable", - "label": "Important Label", - "type": "string", - "default": "Blah", - "required": false, - "description": "Put something into this variable!" - } - ], - "files": [] -} \ No newline at end of file diff --git a/Assemblies/Scripts/Examples/Write_Canary_File_to_C_Drive.json b/Assemblies/Scripts/Examples/Write_Canary_File_to_C_Drive.json new file mode 100644 index 0000000..2cd3b67 --- /dev/null +++ b/Assemblies/Scripts/Examples/Write_Canary_File_to_C_Drive.json @@ -0,0 +1,24 @@ +{ + "version": 1, + "name": "Write Canary File to C Drive", + "description": "Writes a simple text file to the C:\\ drive of the computer. Requires SYSTEM level execution context to work.", + "category": "script", + "type": "powershell", + "script": "# Define the file path\n$filePath = \"C:\\Canary.txt\"\n\n# Write some content into the file\n$env:canaryMessage | Out-File -FilePath $filePath -Encoding UTF8\n", + "timeout_seconds": 3600, + "sites": { + "mode": "all", + "values": [] + }, + "variables": [ + { + "name": "canaryMessage", + "label": "Canary Message", + "type": "string", + "default": "Hello world!", + "required": true, + "description": "This is the text that will be written into the canary file." + } + ], + "files": [] +} \ No newline at end of file diff --git a/Data/Server/WebUI/src/Assemblies/Assembly_Editor.jsx b/Data/Server/WebUI/src/Assemblies/Assembly_Editor.jsx index 318bfec..5d6e342 100644 --- a/Data/Server/WebUI/src/Assemblies/Assembly_Editor.jsx +++ b/Data/Server/WebUI/src/Assemblies/Assembly_Editor.jsx @@ -624,19 +624,84 @@ export default function AssemblyEditor({ flex: 1, height: "100%", overflow: "hidden", + ml: -0.95, + mt: -0.95, bgcolor: PAGE_BACKGROUND }} > - - - Assembly Editor - - - Create and edit variables, scripts, and other fields related to assemblies. - + + + {/* Left half */} + + + Assembly Editor + Create and edit variables, scripts, and other fields related to assemblies. + + + {/* Right half */} + + + {currentPath ? ( + + + + ) : null} + {currentPath ? ( + + + + ) : null} + + + + + - - {currentPath ? ( - - - - ) : null} - {currentPath ? ( - - - - ) : null} - - @@ -1137,6 +1145,7 @@ export default function AssemblyEditor({ No files uploaded yet. )} +