Compare commits

...

43 Commits

Author SHA1 Message Date
wh1te909
f24c6a7a80 Release 0.101.9 2022-12-04 23:01:59 +00:00
wh1te909
d87861c212 bump version 2022-12-04 23:01:35 +00:00
wh1te909
5f56e7017b bump dev 2022-12-03 07:47:28 +00:00
wh1te909
9c033c1c90 feat: env vars 2022-12-01 00:44:56 +00:00
wh1te909
ba14ed348e update reqs 2022-12-01 00:37:44 +00:00
wh1te909
99490bf859 Release 0.101.7 2022-11-13 01:20:33 +00:00
wh1te909
7e25db6622 bump version 2022-11-13 01:20:19 +00:00
wh1te909
78636c436f update reqs 2022-11-08 07:24:55 +00:00
wh1te909
72cdeeaa6a Release 0.101.5 2022-10-25 22:02:34 +00:00
wh1te909
d37122386f bump version 2022-10-25 22:02:23 +00:00
wh1te909
17d960fca9 update reqs 2022-10-25 06:36:07 +00:00
wh1te909
d2e0b8ad9b fix function call 2022-10-23 08:04:32 +00:00
wh1te909
1eca4d605b Release 0.101.3 2022-10-19 22:35:54 +00:00
wh1te909
776c27ec26 bump version 2022-10-19 22:33:09 +00:00
wh1te909
41c61ce152 update reqs 2022-10-19 06:50:50 +00:00
wh1te909
8e9de8b6b6 check if token expired 2022-10-19 06:47:16 +00:00
wh1te909
4cf5f7a3cb update reqs 2022-10-18 00:20:02 +00:00
wh1te909
9729492d1c make link readable in dark mode amidaware/tacticalrmm#1314 2022-10-14 02:06:15 +00:00
wh1te909
52ee98f6f8 Release 0.101.0 2022-09-24 02:43:53 +00:00
wh1te909
d6da8b4a96 bump version 2022-09-24 02:10:26 +00:00
wh1te909
9264cf4044 change dl command 2022-09-24 02:10:03 +00:00
wh1te909
3a45c2a309 mac agent 2022-09-23 22:58:56 +00:00
wh1te909
59de35c698 update reqs 2022-09-23 16:18:06 +00:00
wh1te909
d270b877c9 Release 0.100.9 2022-08-23 05:04:57 +00:00
wh1te909
5b8ac2c809 bump version 2022-08-23 05:04:43 +00:00
wh1te909
83d0ff1c0a bump dev ver 2022-08-22 06:08:34 +00:00
wh1te909
8a6ec6ceab add copy to clipboard for assets tab closes amidaware/tacticalrmm#1246 2022-08-17 17:42:39 +00:00
wh1te909
93dbc74e33 add more fields to search 2022-08-12 01:05:28 +00:00
wh1te909
5f2add48a9 more fuckery 2022-08-10 07:10:32 +00:00
wh1te909
b7369875af remove stuff from payload 2022-08-10 05:57:12 +00:00
wh1te909
2eb6580fed update reqs 2022-08-10 05:56:53 +00:00
wh1te909
fd8b2a1d98 Release 0.100.8 2022-08-09 20:40:48 +00:00
wh1te909
9f85fbb330 bump version 2022-08-09 20:40:39 +00:00
sadnub
ee9715a4cf fix for web for docker dev 2022-08-05 12:07:22 -04:00
wh1te909
76f330fb9c remove seconds 2022-08-05 06:54:23 +00:00
wh1te909
f518043d8d Release 0.100.7 2022-08-01 17:36:11 +00:00
wh1te909
e67c1ff331 bump version 2022-08-01 17:36:00 +00:00
wh1te909
137a5648ce run as user 2022-07-31 22:02:50 +00:00
wh1te909
cc2335558d Release 0.100.6 2022-07-27 06:15:49 +00:00
wh1te909
a944bc50d1 bump version 2022-07-27 06:14:59 +00:00
wh1te909
a8a171ba2c Release 0.100.5 2022-07-10 00:00:08 +00:00
wh1te909
24a63f477e Release 0.100.4 2022-07-07 16:38:14 +00:00
wh1te909
ddeb6293a1 init 2022-05-17 20:46:22 +00:00
30 changed files with 1288 additions and 713 deletions

View File

@@ -0,0 +1,7 @@
COMPOSE_PROJECT_NAME=trmm
IMAGE_REPO=tacticalrmm/
VERSION=latest
# DEV SETTINGS
APP_PORT=443
DOCKER_NETWORK=172.21.0.0/24

View File

@@ -0,0 +1,26 @@
version: '3.4'
services:
app-dev:
container_name: trmm-app-dev
image: node:16-alpine
restart: always
command: /bin/sh -c "npm install --cache ~/.npm && npm run serve"
user: 1000:1000
working_dir: /workspace/web
volumes:
- ..:/workspace:cached
ports:
- "8080:443"
networks:
dev:
aliases:
- tactical-frontend
networks:
dev:
driver: bridge
ipam:
driver: default
config:
- subnet: ${DOCKER_NETWORK}

1
.gitignore vendored
View File

@@ -33,3 +33,4 @@ yarn-error.log*
*.sln
.env
/public/env-config.js

1528
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "web",
"version": "0.100.6-dev",
"version": "0.101.9",
"private": true,
"productName": "Tactical RMM",
"scripts": {
@@ -10,31 +10,31 @@
"format": "prettier --write \"**/*.{js,ts,vue,,html,md,json}\" --ignore-path .gitignore"
},
"dependencies": {
"@quasar/extras": "1.15.0",
"apexcharts": "3.35.4",
"@quasar/extras": "1.15.6",
"apexcharts": "3.35.5",
"axios": "0.27.2",
"dotenv": "16.0.1",
"dotenv": "16.0.3",
"qrcode.vue": "3.3.3",
"quasar": "2.7.5",
"vue": "3.2.37",
"quasar": "2.10.2",
"vue": "3.2.45",
"vue3-ace-editor": "2.2.2",
"vue3-apexcharts": "1.4.1",
"vuedraggable": "4.1.0",
"vue-router": "4.1.2",
"vuex": "4.0.2"
"vue-router": "4.1.6",
"vuex": "4.1.0"
},
"devDependencies": {
"@quasar/cli": "^1.3.2",
"@intlify/vite-plugin-vue-i18n": "^5.0.1",
"@quasar/app-vite": "^1.0.5",
"@types/node": "^18.6.1",
"@typescript-eslint/eslint-plugin": "^5.30.5",
"@typescript-eslint/parser": "^5.30.5",
"autoprefixer": "^10.4.7",
"eslint": "^8.20.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-vue": "^8.5.0",
"prettier": "^2.7.1",
"typescript": "^4.7.4"
"@intlify/vite-plugin-vue-i18n": "^6.0.3",
"@quasar/app-vite": "^1.1.3",
"@types/node": "^18.11.10",
"@typescript-eslint/eslint-plugin": "^5.45.0",
"@typescript-eslint/parser": "^5.45.0",
"autoprefixer": "10.4.13",
"eslint": "8.28.0",
"eslint-config-prettier": "8.5.0",
"eslint-plugin-vue": "8.7.1",
"prettier": "2.8.0",
"typescript": "4.9.3"
}
}
}

View File

@@ -196,6 +196,14 @@
>
<q-tooltip>Linux</q-tooltip>
</q-icon>
<q-icon
v-else-if="props.row.plat === 'darwin'"
name="mdi-apple"
size="sm"
color="primary"
>
<q-tooltip>macOS</q-tooltip>
</q-icon>
</q-td>
<q-td key="checks-status" :props="props">
@@ -356,6 +364,27 @@ export default {
},
methods: {
filterTable(rows, terms, cols, cellValue) {
const hiddenFields = [
"version",
"operating_system",
"public_ip",
"cpu_model",
"graphics",
"local_ips",
"make_model",
"physical_disks",
];
// quasar filter only does visible columns so this is a hack to add hidden columns we want to filter
for (const elem of hiddenFields) {
if (!cols.find((o) => o.name === elem)) {
cols.push({
name: elem,
field: elem,
});
}
}
const lowerTerms = terms ? terms.toLowerCase() : "";
let advancedFilter = false;
let availability = null;

View File

@@ -310,9 +310,10 @@ export default {
}
function showUpdateDetails(update) {
const color = $q.dark.isActive ? "white" : "";
let support_urls = "";
update.more_info_urls.forEach((u) => {
support_urls += `<a href='${u}' target='_blank'>${u}</a><br/>`;
support_urls += `<a style='color: ${color}' href='${u}' target='_blank'>${u}</a><br/>`;
});
let cats = update.categories.join(", ");
$q.dialog({

View File

@@ -7,6 +7,17 @@
<q-badge color="primary" class="q-ml-sm text-caption">{{
v
}}</q-badge>
<q-btn
v-if="!!v"
size="sm"
class="q-ml-xs"
flat
round
icon="content_copy"
@click="copyValueToClip(v)"
>
<q-tooltip>Copy to Clipboard</q-tooltip>
</q-btn>
</div>
</div>
<q-separator v-if="info.length > 1" />
@@ -15,6 +26,8 @@
</template>
<script>
import { copyToClipboard } from "quasar";
import { notifySuccess } from "@/utils/notify";
// composition imports
import { computed } from "vue";
import { useStore } from "vuex";
@@ -28,9 +41,17 @@ export default {
const store = useStore();
const tabHeight = computed(() => store.state.tabHeight);
function copyValueToClip(val) {
copyToClipboard(val)
.then(() => {
notifySuccess("Copied to clipboard");
})
}
return {
tabHeight,
uid,
copyValueToClip,
};
},
};

View File

@@ -39,6 +39,19 @@
new-value-mode="add"
/>
</q-card-section>
<q-card-section>
<q-select
dense
:label="envVarsLabel"
filled
v-model="state.env_vars"
use-input
use-chips
multiple
hide-dropdown-icon
new-value-mode="add"
/>
</q-card-section>
<q-card-section>
<tactical-dropdown
label="Informational return codes (press Enter after typing each code)"
@@ -115,6 +128,7 @@ import { useDialogPluginComponent } from "quasar";
import { useCheckModal } from "@/composables/checks";
import { useScriptDropdown } from "@/composables/scripts";
import { validateRetcode } from "@/utils/validation";
import { envVarsLabel } from "@/constants/constants"
// ui imports
import TacticalDropdown from "@/components/ui/TacticalDropdown.vue";
@@ -132,7 +146,7 @@ export default {
const { dialogRef, onDialogHide, onDialogOK } = useDialogPluginComponent();
// setup script dropdown
const { script, scriptOptions, defaultTimeout, defaultArgs } =
const { script, scriptOptions, defaultTimeout, defaultArgs, defaultEnvVars } =
useScriptDropdown(props.check ? props.check.script : undefined, {
onMount: true,
});
@@ -145,6 +159,7 @@ export default {
...props.parent,
script,
script_args: defaultArgs,
env_vars: defaultEnvVars,
timeout: defaultTimeout,
check_type: "script",
fails_b4_alert: 1,
@@ -163,6 +178,7 @@ export default {
failOptions,
scriptOptions,
severityOptions,
envVarsLabel,
// methods
submit,

View File

@@ -208,7 +208,7 @@ export default {
}
// component lifecycle hooks
onMounted(getAPIKeys());
onMounted(getAPIKeys);
return {
// reactive data
keys,

View File

@@ -10,10 +10,13 @@
</q-card-actions>
</q-card-section>
<q-card-section>
<p class="text-subtitle1">
<p v-if="info.plat === 'windows'" class="text-subtitle1">
Download the agent then run the following command from an elevated
command prompt on the device you want to add.
</p>
<p v-else-if="info.plat === 'darwin'" class="text-subtitle1">
Run the following command from a terminal
</p>
<p>
<q-field outlined :color="$q.dark.isActive ? 'white' : 'black'">
<code>{{ info.data.cmd }}</code>
@@ -37,7 +40,7 @@
</q-badge>
<span>Do not popup any message boxes during install</span>
</div>
<div class="q-pa-xs q-gutter-xs">
<div v-if="info.plat === 'windows'" class="q-pa-xs q-gutter-xs">
<q-badge class="text-caption q-mr-xs" color="grey" text-color="black">
<code
>-local-mesh "C:\\&lt;some folder or
@@ -46,7 +49,7 @@
</q-badge>
<span> To skip downloading the Mesh Agent during the install.</span>
</div>
<div class="q-pa-xs q-gutter-xs">
<div v-if="info.plat === 'windows'" class="q-pa-xs q-gutter-xs">
<q-badge class="text-caption q-mr-xs" color="grey" text-color="black">
<code
>-meshdir "C:\Program Files\Your Company Name\Mesh Agent"</code
@@ -63,7 +66,7 @@
</q-badge>
<span>Don't install the mesh agent</span>
</div>
<div class="q-pa-xs q-gutter-xs">
<div v-if="info.plat === 'windows'" class="q-pa-xs q-gutter-xs">
<q-badge class="text-caption q-mr-xs" color="grey" text-color="black">
<code>-cert "C:\\&lt;some folder or path&gt;\\ca.pem"</code>
</q-badge>
@@ -86,12 +89,12 @@
<p class="text-italic">
Note: the auth token above will be valid for {{ info.expires }} hours.
</p>
<q-btn
<q-btn v-if="info.plat === 'windows'"
type="a"
:href="info.data.url"
color="primary"
label="Download Agent"
/>
></q-btn>
</q-card-section>
</q-card>
</template>

View File

@@ -102,6 +102,18 @@
new-value-mode="add"
/>
</q-card-section>
<q-card-section v-if="mode === 'script'" class="q-pt-none">
<tactical-dropdown
v-model="state.env_vars"
:label="envVarsLabel"
filled
use-input
multiple
hide-dropdown-icon
input-debounce="0"
new-value-mode="add"
/>
</q-card-section>
<q-card-section v-if="mode === 'command'">
<p>Shell</p>
@@ -135,6 +147,11 @@
:rules="[(val) => !!val || '*Required']"
/>
</q-card-section>
<q-card-section v-if="supportsRunAsUser()" class="q-pt-none">
<q-checkbox v-model="state.run_as_user" label="Run As User">
<q-tooltip>{{ runAsUserToolTip }}</q-tooltip>
</q-checkbox>
</q-card-section>
<q-card-section v-if="mode === 'script' || mode === 'command'">
<q-input
@@ -203,6 +220,7 @@ 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
import TacticalDropdown from "@/components/ui/TacticalDropdown.vue";
@@ -217,6 +235,7 @@ const monTypeOptions = [
const osTypeOptions = [
{ label: "Windows", value: "windows" },
{ label: "Linux", value: "linux" },
{ label: "macOS", value: "darwin" },
{ label: "All", value: "all" },
];
@@ -277,6 +296,7 @@ export default {
scriptOptions,
defaultTimeout,
defaultArgs,
defaultEnvVars,
getScriptOptions,
} = useScriptDropdown();
const { agents, agentOptions, getAgentOptions } = useAgentDropdown();
@@ -300,6 +320,8 @@ export default {
script,
timeout: defaultTimeout,
args: defaultArgs,
env_vars: defaultEnvVars,
run_as_user: false,
});
const loading = ref(false);
@@ -316,6 +338,7 @@ export default {
() => state.value.osType,
(newValue) => {
state.value.custom_shell = null;
state.value.run_as_user = false;
if (newValue === "windows") {
state.value.shell = "cmd";
@@ -337,6 +360,13 @@ export default {
loading.value = false;
}
const supportsRunAsUser = () => {
const modes = ["script", "command"];
return (
state.value.osType === "windows" && modes.includes(state.value.mode)
);
};
// set modal title and caption
const modalTitle = computed(() => {
return props.mode === "command"
@@ -387,6 +417,8 @@ export default {
osTypeOptions,
targetOptions,
patchModeOptions,
runAsUserToolTip,
envVarsLabel,
//computed
modalTitle,
@@ -394,6 +426,7 @@ export default {
//methods
submit,
cmdPlaceholder,
supportsRunAsUser,
// quasar dialog plugin
dialogRef,

View File

@@ -465,8 +465,51 @@ export default {
});
},
editAgent() {
delete this.agent.all_timezones;
delete this.agent.timezone;
// TODO we need to fix the serializer to not send this stuff
const toRemove = [
"created_by",
"created_time",
"modified_by",
"modified_time",
"all_timezones",
"timezone",
"wmi_detail",
"services",
"status",
"cpu_model",
"local_ips",
"make_model",
"physical_disks",
"graphics",
"checks",
"patches_last_installed",
"last_seen",
"applied_policies",
"effective_patch_policy",
"version",
"operating_system",
"plat",
"goarch",
"hostname",
"public_ip",
"total_ram",
"disks",
"boot_time",
"logged_in_username",
"last_logged_in_user",
"needs_reboot",
"choco_installed",
"policy",
"mesh_node_id",
"block_policy_inheritance",
"maintenance_mode",
"alert_template",
"client",
"site_name",
];
for (const elem of toRemove) {
delete this.agent[elem];
}
// only send the timezone data if it has changed
// this way django will keep the db column as null and inherit from the global setting
@@ -503,7 +546,7 @@ export default {
else if (day === 0) result += "Sun, ";
}
return result.trimRight(",");
return result.trimEnd(",");
},
},
mounted() {

View File

@@ -52,6 +52,15 @@
goarch = GOARCH_AMD64;
"
/>
<q-radio
v-model="agentOS"
val="darwin"
label="macOS"
@update:model-value="
installMethod = 'mac';
goarch = GOARCH_AMD64;
"
/>
</div>
</q-card-section>
<q-card-section>
@@ -105,37 +114,37 @@
v-model="goarch"
:val="GOARCH_AMD64"
label="64 bit"
v-show="agentOS === 'windows'"
/>
<q-radio
v-model="goarch"
:val="GOARCH_i386"
label="32 bit"
v-show="agentOS === 'windows'"
v-show="agentOS === 'windows' || agentOS === 'linux'"
/>
<q-radio
v-model="goarch"
:val="GOARCH_AMD64"
label="64 bit"
v-show="agentOS !== 'windows'"
label="Intel 64 bit"
v-show="agentOS === 'darwin'"
/>
<q-radio
v-model="goarch"
:val="GOARCH_i386"
label="32 bit"
v-show="agentOS !== 'windows'"
v-show="agentOS !== 'darwin'"
/>
<q-radio
v-model="goarch"
:val="GOARCH_ARM64"
label="ARM 64 bit"
v-show="agentOS !== 'windows'"
v-show="agentOS === 'linux'"
/>
<q-radio
v-model="goarch"
:val="GOARCH_ARM64"
label="Apple Silicon (M1, M2)"
v-show="agentOS === 'darwin'"
/>
<q-radio
v-model="goarch"
:val="GOARCH_ARM32"
label="ARM 32 bit (Rasp Pi)"
v-show="agentOS !== 'windows'"
v-show="agentOS === 'linux'"
/>
</div>
</q-card-section>
@@ -266,12 +275,13 @@ export default {
plat: this.agentOS,
};
if (this.installMethod === "manual") {
if (this.installMethod === "manual" || this.installMethod === "mac") {
this.$axios.post("/agents/installer/", data).then((r) => {
this.info = {
expires: this.expires,
data: r.data,
goarch: this.goarch,
plat: this.agentOS,
};
this.showAgentDownload = true;
});
@@ -343,6 +353,9 @@ export default {
case "bash":
text = "Download linux install script";
break;
case "mac":
text = "Show installation instructions";
break;
}
return text;

View File

@@ -77,6 +77,18 @@
new-value-mode="add"
/>
</q-card-section>
<q-card-section>
<tactical-dropdown
v-model="state.env_vars"
:label="envVarsLabel"
filled
use-input
multiple
hide-dropdown-icon
input-debounce="0"
new-value-mode="add"
/>
</q-card-section>
<q-card-section>
<q-option-group
v-model="state.output"
@@ -128,6 +140,11 @@
/>
<q-checkbox v-model="state.save_all_output" label="Save all output" />
</q-card-section>
<q-card-section v-if="agent.plat === 'windows'">
<q-checkbox v-model="state.run_as_user" label="Run As User">
<q-tooltip>{{ runAsUserToolTip }}</q-tooltip>
</q-checkbox>
</q-card-section>
<q-card-section>
<q-input
v-model.number="state.timeout"
@@ -173,6 +190,7 @@ import { useScriptDropdown } from "@/composables/scripts";
import { useCustomFieldDropdown } from "@/composables/core";
import { runScript } from "@/api/agents";
import { notifySuccess } from "@/utils/notify";
import { envVarsLabel, runAsUserToolTip } from "@/constants/constants";
import {
formatScriptSyntax,
removeExtraOptionCategories,
@@ -203,7 +221,7 @@ export default {
const { dialogRef, onDialogHide } = useDialogPluginComponent();
// setup dropdowns
const { script, scriptOptions, defaultTimeout, defaultArgs, syntax, link } =
const { script, scriptOptions, defaultTimeout, defaultArgs, defaultEnvVars, syntax, link } =
useScriptDropdown(props.script, {
onMount: true,
filterByPlatform: props.agent.plat,
@@ -219,7 +237,9 @@ export default {
save_all_output: false,
script,
args: defaultArgs,
env_vars: defaultEnvVars,
timeout: defaultTimeout,
run_as_user: false,
});
const ret = ref(null);
@@ -273,6 +293,8 @@ export default {
// non-reactive data
outputOptions,
runAsUserToolTip,
envVarsLabel,
//methods
formatScriptSyntax,

View File

@@ -51,6 +51,11 @@
/>
</div>
</q-card-section>
<q-card-section v-if="agent.plat === 'windows'">
<q-checkbox v-model="state.run_as_user" label="Run As User">
<q-tooltip>{{ runAsUserToolTip }}</q-tooltip>
</q-checkbox>
</q-card-section>
<q-card-section v-if="state.shell === 'custom'">
<q-input
v-model="state.custom_shell"
@@ -117,6 +122,7 @@ import { ref } from "vue";
import { useDialogPluginComponent } from "quasar";
import { sendAgentCommand } from "@/api/agents";
import { cmdPlaceholder } from "@/composables/agents";
import { runAsUserToolTip } from "@/constants/constants";
export default {
name: "SendCommand",
@@ -134,6 +140,7 @@ export default {
cmd: null,
timeout: 30,
custom_shell: null,
run_as_user: false,
});
const loading = ref(false);
@@ -156,6 +163,9 @@ export default {
loading,
ret,
// non reactivete data
runAsUserToolTip,
// methods
submit,
cmdPlaceholder,

View File

@@ -204,6 +204,20 @@
new-value-mode="add"
/>
<q-select
class="q-mb-sm"
dense
label="Failure action environment vars (press Enter after typing each key=value pair)"
filled
v-model="template.action_env_vars"
use-input
use-chips
multiple
hide-dropdown-icon
input-debounce="0"
new-value-mode="add"
/>
<q-input
class="q-mb-sm"
label="Failure action timeout (seconds)"
@@ -277,6 +291,20 @@
new-value-mode="add"
/>
<q-select
class="q-mb-sm"
dense
label="Resolved action environment vars (press Enter after typing each key=value pair)"
filled
v-model="template.resolved_action_env_vars"
use-input
use-chips
multiple
hide-dropdown-icon
input-debounce="0"
new-value-mode="add"
/>
<q-input
class="q-mb-sm"
label="Resolved action timeout (seconds)"
@@ -696,9 +724,11 @@ export default {
is_active: true,
action: null,
action_args: [],
action_env_vars: [],
action_timeout: 15,
resolved_action: null,
resolved_action_args: [],
resolved_action_env_vars: [],
resolved_action_timeout: 15,
email_recipients: [],
email_from: "",
@@ -762,11 +792,13 @@ export default {
(i) => i.value === this.template.action
);
this.template.action_args = script.args;
this.template.action_env_vars = script.env_vars;
} else if (type === "resolved") {
const script = this.scriptOptions.find(
(i) => i.value === this.template.resolved_action
);
this.template.resolved_action_args = script.args;
this.template.resolved_action_env_vars = script.env_vars;
}
},
toggleAddEmail() {

View File

@@ -118,6 +118,17 @@
new-value-mode="add"
:readonly="readonly"
/>
<tactical-dropdown
v-model="formScript.env_vars"
:label="envVarsLabel"
filled
use-input
multiple
hide-dropdown-icon
input-debounce="0"
new-value-mode="add"
:readonly="readonly"
/>
<q-input
type="number"
filled
@@ -128,6 +139,18 @@
:rules="[(val) => val >= 5 || 'Minimum is 5']"
hide-bottom-space
/>
<q-checkbox
v-model="formScript.run_as_user"
label="Run As User (Windows only)"
>
<q-tooltip
>Setting this value on the script model will always override any
'Run As User' checkboxes in the UI and force this script to
always be run in the context of the logged in user. If no user
is logged in, the script will not run and an error will be
returned.
</q-tooltip>
</q-checkbox>
<q-input
label="Syntax"
type="textarea"
@@ -217,6 +240,7 @@ import "ace-builds/src-noconflict/theme-tomorrow";
// static data
import { shellOptions } from "@/composables/scripts";
import { envVarsLabel } from "@/constants/constants";
export default {
name: "ScriptFormModal",
@@ -253,6 +277,8 @@ export default {
default_timeout: 90,
args: [],
script_body: "",
run_as_user: false,
env_vars: [],
});
if (props.clone) script.value.name = `(Copy) ${script.value.name}`;
@@ -350,6 +376,7 @@ export default {
// non-reactive data
shellOptions,
agentPlatformOptions,
envVarsLabel,
//computed
title,

View File

@@ -867,7 +867,7 @@ export default {
}
// component life cycle hooks
onMounted(getScripts());
onMounted(getScripts);
return {
// reactive data

View File

@@ -93,6 +93,20 @@
/>
</q-card-section>
<q-card-section>
<tactical-dropdown
v-model="script.env_vars"
label="Environment Variables"
placeholder="(press Enter after typing each key=value pair)"
filled
use-input
multiple
hide-dropdown-icon
input-debounce="0"
new-value-mode="add"
/>
</q-card-section>
<q-card-section>
<q-input
label="Default Timeout"

View File

@@ -44,6 +44,8 @@ export default {
timeout: props.script.default_timeout,
args: props.script.args,
shell: props.script.shell,
run_as_user: props.script.run_as_user,
env_vars: props.script.env_vars,
};
try {
ret.value = await testScript(props.agent, data);

View File

@@ -102,7 +102,7 @@
<tactical-dropdown
v-if="actionType === 'script'"
class="col-4"
class="col-3"
label="Select script"
v-model="script"
:options="scriptOptions"
@@ -113,7 +113,7 @@
<q-select
v-if="actionType === 'script'"
class="col-5"
class="col-3"
dense
label="Script Arguments (press Enter after typing each argument)"
filled
@@ -126,6 +126,21 @@
new-value-mode="add"
/>
<q-select
v-if="actionType === 'script'"
class="col-3"
dense
:label="envVarsLabel"
filled
v-model="defaultEnvVars"
use-input
use-chips
multiple
hide-dropdown-icon
input-debounce="0"
new-value-mode="add"
/>
<q-input
v-if="actionType === 'script'"
class="col-2"
@@ -210,6 +225,9 @@
<q-item-label caption>
Arguments: {{ element.script_args }}
</q-item-label>
<q-item-label caption>
Env Vars: {{ element.env_vars }}
</q-item-label>
<q-item-label caption>
Timeout: {{ element.timeout }}
</q-item-label>
@@ -727,6 +745,7 @@ import { useCheckDropdown } from "@/composables/checks";
import { useCustomFieldDropdown } from "@/composables/core";
import { notifySuccess, notifyError } from "@/utils/notify";
import { validateTimePeriod } from "@/utils/validation";
import { envVarsLabel } from "@/constants/constants";
import {
convertPeriodToSeconds,
convertToBitArray,
@@ -817,7 +836,7 @@ export default {
const { dialogRef, onDialogHide, onDialogOK } = useDialogPluginComponent();
// setup dropdowns
const { script, scriptOptions, defaultTimeout, defaultArgs } =
const { script, scriptOptions, defaultTimeout, defaultArgs, defaultEnvVars } =
useScriptDropdown(undefined, {
onMount: true,
});
@@ -914,6 +933,7 @@ export default {
script: script.value,
timeout: defaultTimeout.value,
script_args: defaultArgs.value,
env_vars: defaultEnvVars.value,
});
} else if (actionType.value === "cmd") {
task.value.actions.push({
@@ -927,6 +947,7 @@ export default {
// clear fields after add
script.value = null;
defaultArgs.value = [];
defaultEnvVars.value = [];
defaultTimeout.value = 30;
command.value = "";
}
@@ -1089,6 +1110,7 @@ export default {
script,
defaultTimeout,
defaultArgs,
defaultEnvVars,
actionType,
command,
shell,
@@ -1116,6 +1138,7 @@ export default {
monthOptions,
taskTypeOptions,
taskInstancePolicyOptions,
envVarsLabel,
// methods
submit,

View File

@@ -31,7 +31,7 @@ export function useUserDropdown(onMount = false) {
}
if (onMount) {
onMounted(getUserOptions());
onMounted(getUserOptions);
}
return {

View File

@@ -37,4 +37,5 @@ export function cmdPlaceholder(shell) {
export const agentPlatformOptions = [
{ value: "windows", label: "Windows" },
{ value: "linux", label: "Linux" },
{ value: "darwin", label: "macOS" },
];

View File

@@ -8,6 +8,7 @@ export function useScriptDropdown(setScript = null, { onMount = false } = {}) {
const scriptOptions = ref([]);
const defaultTimeout = ref(30);
const defaultArgs = ref([]);
const defaultEnvVars = ref([]);
const script = ref(setScript);
const syntax = ref("");
const link = ref("");
@@ -29,6 +30,7 @@ export function useScriptDropdown(setScript = null, { onMount = false } = {}) {
);
defaultTimeout.value = tmpScript.timeout;
defaultArgs.value = tmpScript.args;
defaultEnvVars.value = tmpScript.env_vars,
syntax.value = tmpScript.syntax;
link.value =
tmpScript.script_type === "builtin"
@@ -49,6 +51,7 @@ export function useScriptDropdown(setScript = null, { onMount = false } = {}) {
scriptOptions,
defaultTimeout,
defaultArgs,
defaultEnvVars,
syntax,
link,

View File

@@ -1,6 +1,10 @@
const GOARCH_AMD64 = "amd64";
const GOARCH_i386 = "386";
const GOARCH_ARM64 = "arm64";
const GOARCH_ARM32 = "arm";
export const GOARCH_AMD64 = "amd64";
export const GOARCH_i386 = "386";
export const GOARCH_ARM64 = "arm64";
export const GOARCH_ARM32 = "arm";
export { GOARCH_AMD64, GOARCH_i386, GOARCH_ARM64, GOARCH_ARM32 };
export const runAsUserToolTip =
"Run in the context of the logged in user. If no user is logged in, the script will not run and an error will be returned.";
export const envVarsLabel =
"Environment vars (press Enter after typing each key=value pair)"

View File

@@ -14,6 +14,22 @@
@click="$store.dispatch('reload')"
/>
</q-banner>
<q-banner
v-if="!hosted && tokenExpired"
inline-actions
class="bg-yellow text-black text-center"
>
<q-icon size="xl" name="warning" />
<span><br />Your code signing token is no longer valid.<br/><br/>
If you have downgraded or cancelled your sponsorship, please delete your token from the Code Signing modal and refresh to get rid of this banner.<br/><br/>
For any issues or to renew your sponsorship please email support@amidaware.com<br/><br/></span>
<q-btn
color="dark"
icon="refresh"
label="Refresh"
@click="$store.dispatch('reload')"
/>
</q-banner>
<q-toolbar>
<q-btn
dense
@@ -167,6 +183,7 @@ export default {
const needRefresh = computed(() => store.state.needrefresh);
const user = computed(() => store.state.username);
const hosted = computed(() => store.state.hosted);
const tokenExpired = computed(() => store.state.tokenExpired);
const latestReleaseURL = computed(() => {
return latestTRMMVersion.value
@@ -259,6 +276,8 @@ export default {
user,
needRefresh,
darkMode,
hosted,
tokenExpired,
// methods
showUserPreferences,

View File

@@ -193,6 +193,7 @@ export default {
value: script.id,
timeout: script.default_timeout,
args: script.args,
env_vars: script.env_vars,
});
} else if (cat === "Unassigned" && !script.category) {
tmp.push({
@@ -200,6 +201,7 @@ export default {
value: script.id,
timeout: script.default_timeout,
args: script.args,
env_vars: script.env_vars,
});
}
});

View File

@@ -17,6 +17,7 @@ export default function () {
agentPlatform: "windows",
agentTableLoading: false,
needrefresh: false,
tokenExpired: false,
refreshSummaryTab: false,
tableHeight: "300px",
tabHeight: "300px",
@@ -83,6 +84,9 @@ export default function () {
SET_REFRESH_NEEDED(state, action) {
state.needrefresh = action;
},
SET_TOKEN_EXPIRED(state, action) {
state.tokenExpired = action;
},
SET_SPLITTER(state, val) {
// top toolbar is 50px. Filebar is 40px and agent filter tabs are 44px
state.tableHeight = `${Screen.height - 50 - 40 - 78 - val}px`;
@@ -212,6 +216,7 @@ export default function () {
context.commit("SET_URL_ACTION", data.url_action);
context.commit("setShowCommunityScripts", data.show_community_scripts);
context.commit("SET_HOSTED", data.hosted);
context.commit("SET_TOKEN_EXPIRED", data.token_is_expired);
if (data.date_format && data.date_format !== "")
context.commit("setDateFormat", data.date_format);

View File

@@ -68,6 +68,7 @@ export function formatScriptOptions(data) {
value: script.id,
timeout: script.default_timeout,
args: script.args,
env_vars: script.env_vars,
filename: script.filename,
syntax: script.syntax,
script_type: script.script_type,
@@ -80,6 +81,7 @@ export function formatScriptOptions(data) {
value: script.id,
timeout: script.default_timeout,
args: script.args,
env_vars: script.env_vars,
filename: script.filename,
syntax: script.syntax,
script_type: script.script_type,
@@ -285,7 +287,7 @@ export function formatDateInputField(isoDateString, noTimezone = false) {
if (noTimezone) {
isoDateString = isoDateString.replace("Z", "");
}
return date.formatDate(isoDateString, "YYYY-MM-DDTHH:mm:ss");
return date.formatDate(isoDateString, "YYYY-MM-DDTHH:mm");
}
// converts a local date string "YYYY-MM-DDTHH:mm:ss" to an iso date string with the local timezone