fix vuex in the cmd placeholder computed function and cleanup the scriptDropdowns and actually filter by platform everywhere

This commit is contained in:
sadnub
2024-04-15 13:33:50 -04:00
parent e83463a3cc
commit d4d4bda519
7 changed files with 100 additions and 89 deletions

View File

@@ -666,6 +666,7 @@ export default {
componentProps: {
check: check,
parent: !check ? { agent: selectedAgent.value } : undefined,
plat: type === "script" ? agentPlatform.value : undefined,
},
}).onOk(getChecks);
}

View File

@@ -8,7 +8,7 @@
<q-tooltip class="bg-white text-primary">Close</q-tooltip>
</q-btn>
</q-bar>
<q-card-section v-if="scriptOptions.length === 0">
<q-card-section v-if="filterByPlatformOptions.length === 0">
<p>You need to upload a script first</p>
<p>Settings -> Script Manager</p>
</q-card-section>
@@ -19,7 +19,7 @@
:rules="[(val) => !!val || '*Required']"
outlined
v-model="state.script"
:options="scriptOptions"
:options="filterByPlatformOptions"
label="Select script"
mapOptions
:disable="!!check"
@@ -140,6 +140,7 @@ export default {
props: {
check: Object,
parent: Object, // {agent: agent.agent_id} or {policy: policy.id}
plat: String,
},
setup(props) {
// setup quasar dialog
@@ -148,12 +149,13 @@ export default {
// setup script dropdown
const {
script,
scriptOptions,
filterByPlatformOptions,
defaultTimeout,
defaultArgs,
defaultEnvVars,
} = useScriptDropdown({
script: props.check ? props.check.script : undefined,
plat: props.plat,
onMount: true,
});
@@ -182,7 +184,7 @@ export default {
// non-reactive data
failOptions,
scriptOptions,
filterByPlatformOptions,
severityOptions,
envVarsLabel,

View File

@@ -83,7 +83,7 @@
<tactical-dropdown
:rules="[(val) => !!val || '*Required']"
v-model="state.script"
:options="filteredScriptOptions"
:options="filterByPlatformOptions"
label="Select Script"
outlined
mapOptions
@@ -210,7 +210,14 @@
<script>
// composition imports
import { ref, computed, watch, onMounted } from "vue";
import {
ref,
reactive,
computed,
watch,
onMounted,
defineComponent,
} from "vue";
import { useDialogPluginComponent } from "quasar";
import { useScriptDropdown } from "@/composables/scripts";
import { useAgentDropdown } from "@/composables/agents";
@@ -218,7 +225,6 @@ import { useClientDropdown, useSiteDropdown } from "@/composables/clients";
import { runBulkAction } from "@/api/agents";
import { notifySuccess } from "@/utils/notify";
import { cmdPlaceholder } from "@/composables/agents";
import { removeExtraOptionCategories } from "@/utils/format";
import { envVarsLabel, runAsUserToolTip } from "@/constants/constants";
// ui imports
@@ -250,7 +256,7 @@ const patchModeOptions = [
{ label: "Install", value: "install" },
];
export default {
export default defineComponent({
name: "BulkAction",
components: { TacticalDropdown },
emits: [...useDialogPluginComponent.emits],
@@ -259,7 +265,7 @@ export default {
},
setup(props) {
const shellOptions = computed(() => {
if (state.value.osType === "windows") {
if (state.osType === "windows") {
return [
{ label: "CMD", value: "cmd" },
{ label: "Powershell", value: "powershell" },
@@ -286,7 +292,8 @@ export default {
// dropdown setup
const {
script,
scriptOptions,
plat,
filterByPlatformOptions,
defaultTimeout,
defaultArgs,
defaultEnvVars,
@@ -297,7 +304,7 @@ export default {
const { client, clientOptions, getClientOptions } = useClientDropdown();
// bulk action logic
const state = ref({
const state = reactive({
mode: props.mode,
target: "client",
monType: "all",
@@ -319,7 +326,7 @@ export default {
const loading = ref(false);
watch(
() => state.value.target,
() => state.target,
() => {
client.value = null;
site.value = null;
@@ -327,17 +334,23 @@ export default {
},
);
plat.value = state.osType;
watch(
() => state.value.osType,
() => state.osType,
(newValue) => {
state.value.custom_shell = null;
state.value.run_as_user = false;
state.custom_shell = null;
state.run_as_user = false;
if (newValue === "windows") {
state.value.shell = "cmd";
state.shell = "cmd";
} else {
state.value.shell = "/bin/bash";
state.shell = "/bin/bash";
}
// set plat to filter script options
if (newValue === "all") plat.value = undefined;
else plat.value = newValue;
},
);
@@ -345,7 +358,7 @@ export default {
loading.value = true;
try {
const data = await runBulkAction(state.value);
const data = await runBulkAction(state);
notifySuccess(data);
onDialogHide();
} catch (e) {}
@@ -355,9 +368,7 @@ export default {
const supportsRunAsUser = () => {
const modes = ["script", "command"];
return (
state.value.osType === "windows" && modes.includes(state.value.mode)
);
return state.osType === "windows" && modes.includes(state.mode);
};
// set modal title and caption
@@ -371,21 +382,6 @@ export default {
: "";
});
const filteredScriptOptions = computed(() => {
if (props.mode !== "script") return [];
if (state.value.osType === "all") return scriptOptions.value;
return removeExtraOptionCategories(
scriptOptions.value.filter(
(script) =>
script.category ||
!script.supported_platforms ||
script.supported_platforms.length === 0 ||
script.supported_platforms.includes(state.value.osType),
),
);
});
// component lifecycle hooks
onMounted(() => {
getAgentOptions();
@@ -400,7 +396,7 @@ export default {
agentOptions,
clientOptions,
siteOptions,
filteredScriptOptions,
filterByPlatformOptions,
loading,
shellOptions,
filteredOsTypeOptions,
@@ -426,5 +422,5 @@ export default {
onDialogHide,
};
},
};
});
</script>

View File

@@ -39,9 +39,9 @@
<q-form @submit.prevent="sendScript">
<q-card-section>
<tactical-dropdown
:rules="[(val) => !!val || '*Required']"
:rules="[(val: number) => !!val || '*Required']"
v-model="state.script"
:options="filterByPlatformOptions(agent.plat)"
:options="filterByPlatformOptions"
label="Select script"
outlined
mapOptions
@@ -130,7 +130,7 @@
</q-card-section>
<q-card-section v-if="state.output === 'collector'">
<tactical-dropdown
:rules="[(val) => !!val || '*Required']"
:rules="[(val: number) => !!val || '*Required']"
outlined
v-model="state.custom_field"
:options="customFieldOptions"
@@ -197,7 +197,7 @@ import { formatScriptSyntax } from "@/utils/format";
import TacticalDropdown from "@/components/ui/TacticalDropdown.vue";
// types
import type { Agent } from "@/types/Agent";
import type { Agent } from "@/types/agents";
// static data
const outputOptions = [
@@ -231,6 +231,7 @@ const {
link,
} = useScriptDropdown({
script: props.script,
plat: props.agent.plat,
onMount: true,
});
const { customFieldOptions } = useCustomFieldDropdown({ onMount: true });
@@ -261,7 +262,7 @@ async function sendScript() {
loading.value = false;
if (state.value.output === "forget") {
onDialogHide();
notifySuccess(ret.value);
if (ret.value) notifySuccess(ret.value);
}
}

View File

@@ -41,7 +41,7 @@
v-model="collector"
class="q-pb-sm"
@update:model-value="
localTask.custom_field = null;
localTask.custom_field = undefined;
localTask.collector_all_output = false;
"
/>
@@ -106,13 +106,7 @@
class="col-3"
label="Select script"
v-model="script"
:options="
type === 'policy'
? scriptOptions
: type === 'server'
? filterByPlatformOptions('linux')
: filterByPlatformOptions(plat)
"
:options="filterByPlatformOptions"
filled
mapOptions
filterable
@@ -904,6 +898,7 @@ const { dialogRef, onDialogHide, onDialogOK } = useDialogPluginComponent();
const {
script,
scriptOptions,
plat,
filterByPlatformOptions,
defaultTimeout,
defaultArgs,
@@ -913,6 +908,14 @@ const {
onMount: true,
});
// set plat
plat.value =
props.type === "policy"
? undefined // get all scripts
: props.type === "server"
? "linux" // get only linux scripts for server
: props.plat; // filter scripts based on supported plat
// set defaultTimeout to 30
defaultTimeout.value = 30;

View File

@@ -1,5 +1,5 @@
import { ref } from "vue";
import { useDashboardStore } from "@/stores/dashboard";
import { ref, computed } from "vue";
import { useStore } from "vuex";
import { fetchAgents } from "@/api/agents";
import { formatAgentOptions } from "@/utils/format";
@@ -29,11 +29,12 @@ export function useAgentDropdown() {
}
export function cmdPlaceholder(shell) {
const store = useDashboardStore();
const store = useStore();
const placeholders = computed(() => store.state.run_cmd_placeholder_text);
if (shell === "cmd") return store.runCmdPlaceholders.cmd;
else if (shell === "powershell") return store.runCmdPlaceholders.powershell;
else return store.runCmdPlaceholders.shell;
if (shell === "cmd") return placeholders.value.cmd;
else if (shell === "powershell") return placeholders.value.powershell;
else return placeholders.value.shell;
}
export const agentPlatformOptions = [

View File

@@ -15,26 +15,32 @@ export interface ScriptOption extends Script {
export interface useScriptDropdownParams {
script?: number; // set a selected script on init
plat?: AgentPlatformType; // set a platform for filterByPlatform
onMount?: boolean; // loads script options on mount
}
// script dropdown
export function useScriptDropdown(opts: useScriptDropdownParams) {
export function useScriptDropdown(opts?: useScriptDropdownParams) {
const scriptOptions = ref([] as ScriptOption[]);
const defaultTimeout = ref(30);
const defaultArgs = ref([] as string[]);
const defaultEnvVars = ref([] as string[]);
const script = ref(opts.script);
const script = ref(opts?.script);
const scriptName = ref("");
const syntax = ref<string | undefined>("");
const link = ref<string | undefined>("");
const plat = ref<AgentPlatformType | undefined>(opts?.plat);
const baseUrl =
"https://github.com/amidaware/community-scripts/blob/main/scripts/";
// specify parameters to filter out community scripts
async function getScriptOptions(showCommunityScripts = false) {
async function getScriptOptions() {
scriptOptions.value = Object.freeze(
formatScriptOptions(await fetchScripts({ showCommunityScripts })),
formatScriptOptions(
await fetchScripts({
showCommunityScripts: showCommunityScripts.value,
}),
),
) as ScriptOption[];
}
@@ -64,33 +70,34 @@ export function useScriptDropdown(opts: useScriptDropdownParams) {
const showCommunityScripts = computed(() => store.state.showCommunityScripts);
// filter for only getting server tasks
const serverScriptOptions = computed(() =>
removeExtraOptionCategories(
scriptOptions.value.filter(
(script) =>
script.category ||
!script.supported_platforms ||
script.supported_platforms.length === 0 ||
script.supported_platforms.includes("linux"),
),
),
const serverScriptOptions = computed(
() =>
removeExtraOptionCategories(
scriptOptions.value.filter(
(script) =>
script.category ||
!script.supported_platforms ||
script.supported_platforms.length === 0 ||
script.supported_platforms.includes("linux"),
),
) as ScriptOption[],
);
const filterByPlatformOptions = (plat: AgentPlatformType | undefined) => {
if (!plat) {
const filterByPlatformOptions = computed(() => {
if (!plat.value) {
return scriptOptions.value;
} else {
return removeExtraOptionCategories(
scriptOptions.value.filter(
(script) =>
script.category ||
!script.supported_platforms ||
script.supported_platforms.length === 0 ||
script.supported_platforms.includes(plat.value!),
),
) as ScriptOption[];
}
return removeExtraOptionCategories(
scriptOptions.value.filter(
(script) =>
script.category ||
!script.supported_platforms ||
script.supported_platforms.length === 0 ||
script.supported_platforms.includes(plat),
),
);
};
});
function reset() {
defaultTimeout.value = 30;
@@ -101,8 +108,7 @@ export function useScriptDropdown(opts: useScriptDropdownParams) {
link.value = "";
}
if (opts.onMount)
onMounted(() => getScriptOptions(showCommunityScripts.value));
if (opts?.onMount) onMounted(() => getScriptOptions());
return {
//data
@@ -113,14 +119,15 @@ export function useScriptDropdown(opts: useScriptDropdownParams) {
scriptName,
syntax,
link,
plat,
scriptOptions, // unfiltered options
serverScriptOptions, //only scripts that can run on server
serverScriptOptions, // only scripts that can run on server
filterByPlatformOptions, // use the returned plat to change options
//methods
getScriptOptions,
filterByPlatformOptions,
reset,
reset, // resets dropdown selection state
};
}