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)
category = models.CharField(max_length=100, null=True, blank=True)
code_base64 = models.TextField(null=True, blank=True)
default_timeout = models.PositiveIntegerField(default=90)
def __str__(self):
return self.name

View File

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

View File

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

View File

@ -30,6 +30,7 @@ class GetAddScripts(APIView):
"category": request.data["category"],
"description": request.data["description"],
"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
}

View File

@ -511,9 +511,10 @@ export default {
}, 500);
},
runFavScript(scriptpk, agentpk) {
let default_timeout = this.favoriteScripts.find(i => i.value === scriptpk).timeout;
const data = {
pk: agentpk,
timeout: 900,
timeout: default_timeout,
scriptPK: scriptpk,
output: "forget",
args: [],
@ -532,7 +533,7 @@ export default {
}
this.favoriteScripts = r.data
.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));
});
},

View File

@ -291,6 +291,7 @@
props.row.description
}}</q-tooltip>
</q-td>
<q-td>{{ props.row.default_timeout }}</q-td>
</q-tr>
</template>
</q-table>
@ -368,8 +369,15 @@ export default {
align: "left",
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: {

View File

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

View File

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

View File

@ -48,6 +48,17 @@
label="Shell Type"
/>
</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">
<q-select
hint="Press Enter or Tab when adding a new value"
@ -65,7 +76,7 @@
:readonly="readonly"
/>
</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" />
</div>
</q-card-section>
@ -118,6 +129,7 @@ export default {
category: "",
favorite: false,
script_type: "userdefined",
default_timeout: 90,
},
maximized: false,
filterOptions: [],
@ -217,7 +229,7 @@ export default {
return !this.readonly ? "click" : null;
},
getMaxWidth() {
return this.maximized ? "" : "width: 60vw; max-width: 90vw";
return this.maximized ? "" : "width: 70vw; max-width: 90vw";
},
heightVar() {
return this.maximized ? "--prism-height: 80vh" : "--prism-height: 70vh";
@ -232,6 +244,7 @@ export default {
this.localScript.shell = this.script.shell;
this.localScript.category = this.script.category;
this.localScript.script_type = this.script.script_type;
this.localScript.default_timeout = this.script.default_timeout;
this.getCode();
}
},

View File

@ -67,6 +67,17 @@
map-options
/>
</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-space />
<q-btn dense flat label="Cancel" v-close-popup />
@ -92,6 +103,7 @@ export default {
description: "",
shell: "powershell",
category: null,
default_timeout: 90,
},
shellOptions: [
{ label: "Powershell", value: "powershell" },
@ -120,6 +132,7 @@ export default {
formData.append("name", this.script.name);
formData.append("shell", this.script.shell);
formData.append("description", this.script.description);
formData.append("default_timeout", this.script.default_timeout);
this.$axios
.post("/scripts/scripts/", formData)