feat: add default timeout in script manager closes #352

This commit is contained in:
wh1te909
2021-03-31 03:01:46 +00:00
parent b686b53a9c
commit 87fa5ff7a6
11 changed files with 79 additions and 18 deletions

View File

@@ -0,0 +1,18 @@
# Generated by Django 3.1.7 on 2021-03-31 01:08
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('scripts', '0005_auto_20201207_1606'),
]
operations = [
migrations.AddField(
model_name='script',
name='default_timeout',
field=models.PositiveIntegerField(default=90),
),
]

View File

@@ -29,6 +29,7 @@ class Script(BaseAuditModel):
favorite = models.BooleanField(default=False) favorite = models.BooleanField(default=False)
category = models.CharField(max_length=100, null=True, blank=True) category = models.CharField(max_length=100, null=True, blank=True)
code_base64 = models.TextField(null=True, blank=True) code_base64 = models.TextField(null=True, blank=True)
default_timeout = models.PositiveIntegerField(default=90)
def __str__(self): def __str__(self):
return self.name return self.name

View File

@@ -14,6 +14,7 @@ class ScriptTableSerializer(ModelSerializer):
"shell", "shell",
"category", "category",
"favorite", "favorite",
"default_timeout",
] ]
@@ -28,6 +29,7 @@ class ScriptSerializer(ModelSerializer):
"category", "category",
"favorite", "favorite",
"code_base64", "code_base64",
"default_timeout",
] ]

View File

@@ -36,6 +36,7 @@ class TestScriptViews(TacticalTestCase):
"shell": "powershell", "shell": "powershell",
"category": "New", "category": "New",
"code": "Some Test Code\nnew Line", "code": "Some Test Code\nnew Line",
"default_timeout": 99,
} }
# test without file upload # test without file upload
@@ -55,6 +56,7 @@ class TestScriptViews(TacticalTestCase):
"shell": "cmd", "shell": "cmd",
"category": "New", "category": "New",
"filename": file, "filename": file,
"default_timeout": 4455,
} }
# test with file upload # test with file upload
@@ -79,6 +81,7 @@ class TestScriptViews(TacticalTestCase):
"description": "Description Change", "description": "Description Change",
"shell": script.shell, "shell": script.shell,
"code": "Test Code\nAnother Line", "code": "Test Code\nAnother Line",
"default_timeout": 13344556,
} }
# test edit a userdefined script # test edit a userdefined script
@@ -104,6 +107,7 @@ class TestScriptViews(TacticalTestCase):
"shell": script.shell, "shell": script.shell,
"favorite": True, "favorite": True,
"code": "Test Code\nAnother Line", "code": "Test Code\nAnother Line",
"default_timeout": 54345,
} }
# test marking a builtin script as favorite # test marking a builtin script as favorite
resp = self.client.put( resp = self.client.put(

View File

@@ -30,6 +30,7 @@ class GetAddScripts(APIView):
"category": request.data["category"], "category": request.data["category"],
"description": request.data["description"], "description": request.data["description"],
"shell": request.data["shell"], "shell": request.data["shell"],
"default_timeout": request.data["default_timeout"],
"script_type": "userdefined", # force all uploads to be userdefined. built in scripts cannot be edited by user "script_type": "userdefined", # force all uploads to be userdefined. built in scripts cannot be edited by user
} }

View File

@@ -511,9 +511,10 @@ export default {
}, 500); }, 500);
}, },
runFavScript(scriptpk, agentpk) { runFavScript(scriptpk, agentpk) {
let default_timeout = this.favoriteScripts.find(i => i.value === scriptpk).timeout;
const data = { const data = {
pk: agentpk, pk: agentpk,
timeout: 900, timeout: default_timeout,
scriptPK: scriptpk, scriptPK: scriptpk,
output: "forget", output: "forget",
args: [], args: [],
@@ -532,7 +533,7 @@ export default {
} }
this.favoriteScripts = r.data this.favoriteScripts = r.data
.filter(k => k.favorite === true) .filter(k => k.favorite === true)
.map(script => ({ label: script.name, value: script.id })) .map(script => ({ label: script.name, value: script.id, timeout: script.default_timeout }))
.sort((a, b) => a.label.localeCompare(b.label)); .sort((a, b) => a.label.localeCompare(b.label));
}); });
}, },

View File

@@ -291,6 +291,7 @@
props.row.description props.row.description
}}</q-tooltip> }}</q-tooltip>
</q-td> </q-td>
<q-td>{{ props.row.default_timeout }}</q-td>
</q-tr> </q-tr>
</template> </template>
</q-table> </q-table>
@@ -368,8 +369,15 @@ export default {
align: "left", align: "left",
sortable: false, sortable: false,
}, },
{
name: "default_timeout",
label: "Default Timeout (seconds)",
field: "default_timeout",
align: "left",
sortable: true,
},
], ],
visibleColumns: ["favorite", "name", "category", "desc", "shell"], visibleColumns: ["favorite", "name", "category", "desc", "shell", "default_timeout"],
}; };
}, },
methods: { methods: {

View File

@@ -92,6 +92,7 @@
map-options map-options
emit-value emit-value
options-dense options-dense
@input="setDefaultTimeout"
/> />
</q-card-section> </q-card-section>
<q-card-section v-if="mode === 'script'" class="q-pt-none"> <q-card-section v-if="mode === 'script'" class="q-pt-none">
@@ -138,11 +139,7 @@
style="max-width: 150px" style="max-width: 150px"
label="Timeout (seconds)" label="Timeout (seconds)"
stack-label stack-label
:rules="[ :rules="[val => !!val || '*Required', val => val >= 5 || 'Minimum is 5 seconds']"
val => !!val || '*Required',
val => val >= 10 || 'Minimum is 10 seconds',
val => val <= 25200 || 'Maximum is 25,200 seconds',
]"
/> />
</q-card-section> </q-card-section>
@@ -200,6 +197,9 @@ export default {
}, },
}, },
methods: { methods: {
setDefaultTimeout() {
this.timeout = this.scriptOptions.find(i => i.value === this.scriptPK).timeout;
},
getScripts() { getScripts() {
let scripts; let scripts;
this.$axios.get("/scripts/scripts/").then(r => { this.$axios.get("/scripts/scripts/").then(r => {
@@ -209,7 +209,7 @@ export default {
scripts = r.data.filter(i => i.script_type !== "builtin"); scripts = r.data.filter(i => i.script_type !== "builtin");
} }
this.scriptOptions = scripts this.scriptOptions = scripts
.map(script => ({ label: script.name, value: script.id })) .map(script => ({ label: script.name, value: script.id, timeout: script.default_timeout }))
.sort((a, b) => a.label.localeCompare(b.label)); .sort((a, b) => a.label.localeCompare(b.label));
}); });
}, },

View File

@@ -17,6 +17,7 @@
map-options map-options
emit-value emit-value
options-dense options-dense
@input="setDefaultTimeout"
/> />
</q-card-section> </q-card-section>
<q-card-section> <q-card-section>
@@ -73,11 +74,7 @@
style="max-width: 150px" style="max-width: 150px"
label="Timeout (seconds)" label="Timeout (seconds)"
stack-label stack-label
:rules="[ :rules="[val => !!val || '*Required', val => val >= 5 || 'Minimum is 5 seconds']"
val => !!val || '*Required',
val => val >= 10 || 'Minimum is 10 seconds',
val => val <= 25200 || 'Maximum is 25,200 seconds',
]"
/> />
</q-card-section> </q-card-section>
<q-card-actions align="center"> <q-card-actions align="center">
@@ -92,7 +89,7 @@
<script> <script>
import mixins from "@/mixins/mixins"; import mixins from "@/mixins/mixins";
import { mapGetters, mapState } from "vuex"; import { mapState } from "vuex";
export default { export default {
name: "RunScript", name: "RunScript",
@@ -123,6 +120,9 @@ export default {
}, },
}, },
methods: { methods: {
setDefaultTimeout() {
this.timeout = this.scriptOptions.find(i => i.value === this.scriptPK).timeout;
},
getScripts() { getScripts() {
let scripts; let scripts;
this.$axios.get("/scripts/scripts/").then(r => { this.$axios.get("/scripts/scripts/").then(r => {
@@ -132,7 +132,7 @@ export default {
scripts = r.data.filter(i => i.script_type !== "builtin"); scripts = r.data.filter(i => i.script_type !== "builtin");
} }
this.scriptOptions = scripts this.scriptOptions = scripts
.map(script => ({ label: script.name, value: script.id })) .map(script => ({ label: script.name, value: script.id, timeout: script.default_timeout }))
.sort((a, b) => a.label.localeCompare(b.label)); .sort((a, b) => a.label.localeCompare(b.label));
}); });
}, },

View File

@@ -48,6 +48,17 @@
label="Shell Type" label="Shell Type"
/> />
</div> </div>
<div class="q-pa-sm col-2">
<q-input
type="number"
filled
dense
:readonly="readonly"
v-model.number="localScript.default_timeout"
label="Timeout (seconds)"
:rules="[val => val >= 5 || 'Minimum is 5']"
/>
</div>
<div class="q-pa-sm col-3"> <div class="q-pa-sm col-3">
<q-select <q-select
hint="Press Enter or Tab when adding a new value" hint="Press Enter or Tab when adding a new value"
@@ -65,7 +76,7 @@
:readonly="readonly" :readonly="readonly"
/> />
</div> </div>
<div class="q-pa-sm col-4"> <div class="q-pa-sm col-2">
<q-input filled dense :readonly="readonly" v-model="localScript.description" label="Description" /> <q-input filled dense :readonly="readonly" v-model="localScript.description" label="Description" />
</div> </div>
</q-card-section> </q-card-section>
@@ -118,6 +129,7 @@ export default {
category: "", category: "",
favorite: false, favorite: false,
script_type: "userdefined", script_type: "userdefined",
default_timeout: 90,
}, },
maximized: false, maximized: false,
filterOptions: [], filterOptions: [],
@@ -217,7 +229,7 @@ export default {
return !this.readonly ? "click" : null; return !this.readonly ? "click" : null;
}, },
getMaxWidth() { getMaxWidth() {
return this.maximized ? "" : "width: 60vw; max-width: 90vw"; return this.maximized ? "" : "width: 70vw; max-width: 90vw";
}, },
heightVar() { heightVar() {
return this.maximized ? "--prism-height: 80vh" : "--prism-height: 70vh"; return this.maximized ? "--prism-height: 80vh" : "--prism-height: 70vh";
@@ -232,6 +244,7 @@ export default {
this.localScript.shell = this.script.shell; this.localScript.shell = this.script.shell;
this.localScript.category = this.script.category; this.localScript.category = this.script.category;
this.localScript.script_type = this.script.script_type; this.localScript.script_type = this.script.script_type;
this.localScript.default_timeout = this.script.default_timeout;
this.getCode(); this.getCode();
} }
}, },

View File

@@ -67,6 +67,17 @@
map-options map-options
/> />
</q-card-section> </q-card-section>
<q-card-section class="row">
<div class="col-4">Default Timeout (seconds)</div>
<q-input
type="number"
outlined
dense
class="col-8"
v-model.number="script.default_timeout"
:rules="[val => val >= 5 || 'Minimum is 5']"
/>
</q-card-section>
<q-card-actions> <q-card-actions>
<q-space /> <q-space />
<q-btn dense flat label="Cancel" v-close-popup /> <q-btn dense flat label="Cancel" v-close-popup />
@@ -92,6 +103,7 @@ export default {
description: "", description: "",
shell: "powershell", shell: "powershell",
category: null, category: null,
default_timeout: 90,
}, },
shellOptions: [ shellOptions: [
{ label: "Powershell", value: "powershell" }, { label: "Powershell", value: "powershell" },
@@ -120,6 +132,7 @@ export default {
formData.append("name", this.script.name); formData.append("name", this.script.name);
formData.append("shell", this.script.shell); formData.append("shell", this.script.shell);
formData.append("description", this.script.description); formData.append("description", this.script.description);
formData.append("default_timeout", this.script.default_timeout);
this.$axios this.$axios
.post("/scripts/scripts/", formData) .post("/scripts/scripts/", formData)