Compare commits

...

15 Commits

Author SHA1 Message Date
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
15 changed files with 697 additions and 350 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

838
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",
"version": "0.100.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",
"@quasar/extras": "1.15.1",
"apexcharts": "3.35.4",
"axios": "0.27.2",
"dotenv": "16.0.1",
"qrcode.vue": "3.3.3",
"quasar": "2.7.5",
"quasar": "2.7.7",
"vue": "3.2.37",
"vue3-ace-editor": "2.2.2",
"vue3-apexcharts": "1.4.1",
"vuedraggable": "4.1.0",
"vue-router": "4.1.2",
"vue-router": "4.1.3",
"vuex": "4.0.2"
},
"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",
"@intlify/vite-plugin-vue-i18n": "^6.0.0",
"@quasar/app-vite": "^1.0.6",
"@types/node": "^18.6.5",
"@typescript-eslint/eslint-plugin": "^5.33.0",
"@typescript-eslint/parser": "^5.33.0",
"autoprefixer": "^10.4.7",
"eslint": "^8.20.0",
"eslint": "^8.21.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-vue": "^8.5.0",
"prettier": "^2.7.1",
"typescript": "^4.7.4"
}
}
}

View File

@@ -356,6 +356,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

@@ -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

@@ -135,6 +135,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 +208,7 @@ import { runBulkAction } from "@/api/agents";
import { notifySuccess } from "@/utils/notify";
import { cmdPlaceholder } from "@/composables/agents";
import { removeExtraOptionCategories } from "@/utils/format";
import { runAsUserToolTip } from "@/constants/constants";
// ui imports
import TacticalDropdown from "@/components/ui/TacticalDropdown.vue";
@@ -300,6 +306,7 @@ export default {
script,
timeout: defaultTimeout,
args: defaultArgs,
run_as_user: false,
});
const loading = ref(false);
@@ -316,6 +323,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 +345,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 +402,7 @@ export default {
osTypeOptions,
targetOptions,
patchModeOptions,
runAsUserToolTip,
//computed
modalTitle,
@@ -394,6 +410,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

@@ -128,6 +128,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 +178,7 @@ import { useScriptDropdown } from "@/composables/scripts";
import { useCustomFieldDropdown } from "@/composables/core";
import { runScript } from "@/api/agents";
import { notifySuccess } from "@/utils/notify";
import { runAsUserToolTip } from "@/constants/constants";
import {
formatScriptSyntax,
removeExtraOptionCategories,
@@ -220,6 +226,7 @@ export default {
script,
args: defaultArgs,
timeout: defaultTimeout,
run_as_user: false,
});
const ret = ref(null);
@@ -273,6 +280,7 @@ export default {
// non-reactive data
outputOptions,
runAsUserToolTip,
//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

@@ -128,6 +128,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. Not supported on Windows Server.
</q-tooltip>
</q-checkbox>
<q-input
label="Syntax"
type="textarea"
@@ -253,6 +265,7 @@ export default {
default_timeout: 90,
args: [],
script_body: "",
run_as_user: false,
});
if (props.clone) script.value.name = `(Copy) ${script.value.name}`;

View File

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

View File

@@ -3,4 +3,13 @@ const GOARCH_i386 = "386";
const GOARCH_ARM64 = "arm64";
const GOARCH_ARM32 = "arm";
export { GOARCH_AMD64, GOARCH_i386, GOARCH_ARM64, GOARCH_ARM32 };
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. Not supported on Windows Server.";
export {
GOARCH_AMD64,
GOARCH_i386,
GOARCH_ARM64,
GOARCH_ARM32,
runAsUserToolTip,
};

View File

@@ -285,7 +285,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