Release 0.16.4
This commit is contained in:
		@@ -570,6 +570,13 @@ def install_agent(request):
 | 
			
		||||
    from agents.utils import get_agent_url
 | 
			
		||||
    from core.utils import token_is_valid
 | 
			
		||||
 | 
			
		||||
    insecure = getattr(settings, "TRMM_INSECURE", False)
 | 
			
		||||
 | 
			
		||||
    if insecure and request.data["installMethod"] in {"exe", "powershell"}:
 | 
			
		||||
        return notify_error(
 | 
			
		||||
            "Not available in insecure mode. Please use the 'Manual' method."
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    # TODO rework this ghetto validation hack
 | 
			
		||||
    # https://github.com/amidaware/tacticalrmm/issues/1461
 | 
			
		||||
    try:
 | 
			
		||||
@@ -672,6 +679,9 @@ def install_agent(request):
 | 
			
		||||
            if int(request.data["power"]):
 | 
			
		||||
                cmd.append("--power")
 | 
			
		||||
 | 
			
		||||
            if insecure:
 | 
			
		||||
                cmd.append("--insecure")
 | 
			
		||||
 | 
			
		||||
            resp["cmd"] = " ".join(str(i) for i in cmd)
 | 
			
		||||
        else:
 | 
			
		||||
            install_flags.insert(0, f"sudo ./{inno}")
 | 
			
		||||
@@ -680,6 +690,8 @@ def install_agent(request):
 | 
			
		||||
            resp["cmd"] = (
 | 
			
		||||
                dl + f" && chmod +x {inno} && " + " ".join(str(i) for i in cmd)
 | 
			
		||||
            )
 | 
			
		||||
            if insecure:
 | 
			
		||||
                resp["cmd"] += " --insecure"
 | 
			
		||||
 | 
			
		||||
        resp["url"] = download_url
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -172,6 +172,31 @@ class TestCheckViews(TacticalTestCase):
 | 
			
		||||
 | 
			
		||||
        self.check_not_authenticated("post", url)
 | 
			
		||||
 | 
			
		||||
    def test_reset_all_checks_status(self):
 | 
			
		||||
        # setup data
 | 
			
		||||
        agent = baker.make_recipe("agents.agent")
 | 
			
		||||
        check = baker.make_recipe("checks.diskspace_check", agent=agent)
 | 
			
		||||
        baker.make("checks.CheckResult", assigned_check=check, agent=agent)
 | 
			
		||||
        baker.make(
 | 
			
		||||
            "checks.CheckHistory",
 | 
			
		||||
            check_id=check.id,
 | 
			
		||||
            agent_id=agent.agent_id,
 | 
			
		||||
            _quantity=30,
 | 
			
		||||
        )
 | 
			
		||||
        baker.make(
 | 
			
		||||
            "checks.CheckHistory",
 | 
			
		||||
            check_id=check.id,
 | 
			
		||||
            agent_id=agent.agent_id,
 | 
			
		||||
            _quantity=30,
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        url = f"{base_url}/{agent.agent_id}/resetall/"
 | 
			
		||||
 | 
			
		||||
        resp = self.client.post(url)
 | 
			
		||||
        self.assertEqual(resp.status_code, 200)
 | 
			
		||||
 | 
			
		||||
        self.check_not_authenticated("post", url)
 | 
			
		||||
 | 
			
		||||
    def test_add_memory_check(self):
 | 
			
		||||
        url = f"{base_url}/"
 | 
			
		||||
        agent = baker.make_recipe("agents.agent")
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@ urlpatterns = [
 | 
			
		||||
    path("", views.GetAddChecks.as_view()),
 | 
			
		||||
    path("<int:pk>/", views.GetUpdateDeleteCheck.as_view()),
 | 
			
		||||
    path("<int:pk>/reset/", views.ResetCheck.as_view()),
 | 
			
		||||
    path("<agent:agent_id>/resetall/", views.ResetAllChecksStatus.as_view()),
 | 
			
		||||
    path("<agent:agent_id>/run/", views.run_checks),
 | 
			
		||||
    path("<int:pk>/history/", views.GetCheckHistory.as_view()),
 | 
			
		||||
    path("<str:target>/<int:pk>/csbulkrun/", views.bulk_run_checks),
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
import asyncio
 | 
			
		||||
from datetime import datetime as dt
 | 
			
		||||
 | 
			
		||||
from django.db.models import Q
 | 
			
		||||
from django.db.models import Prefetch, Q
 | 
			
		||||
from django.shortcuts import get_object_or_404
 | 
			
		||||
from django.utils import timezone as djangotime
 | 
			
		||||
from rest_framework.decorators import api_view, permission_classes
 | 
			
		||||
@@ -13,7 +13,7 @@ from rest_framework.views import APIView
 | 
			
		||||
from agents.models import Agent
 | 
			
		||||
from alerts.models import Alert
 | 
			
		||||
from automation.models import Policy
 | 
			
		||||
from tacticalrmm.constants import CheckStatus, CheckType
 | 
			
		||||
from tacticalrmm.constants import AGENT_DEFER, CheckStatus, CheckType
 | 
			
		||||
from tacticalrmm.exceptions import NatsDown
 | 
			
		||||
from tacticalrmm.helpers import notify_error
 | 
			
		||||
from tacticalrmm.nats_utils import abulk_nats_command
 | 
			
		||||
@@ -122,15 +122,54 @@ class ResetCheck(APIView):
 | 
			
		||||
        result.save()
 | 
			
		||||
 | 
			
		||||
        # resolve any alerts that are open
 | 
			
		||||
        alert = Alert.create_or_return_check_alert(
 | 
			
		||||
        if alert := Alert.create_or_return_check_alert(
 | 
			
		||||
            result.assigned_check, agent=result.agent, skip_create=True
 | 
			
		||||
        )
 | 
			
		||||
        if alert:
 | 
			
		||||
        ):
 | 
			
		||||
            alert.resolve()
 | 
			
		||||
 | 
			
		||||
        return Response("The check status was reset")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ResetAllChecksStatus(APIView):
 | 
			
		||||
    permission_classes = [IsAuthenticated, ChecksPerms]
 | 
			
		||||
 | 
			
		||||
    def post(self, request, agent_id):
 | 
			
		||||
        agent = get_object_or_404(
 | 
			
		||||
            Agent.objects.defer(*AGENT_DEFER)
 | 
			
		||||
            .select_related(
 | 
			
		||||
                "policy",
 | 
			
		||||
                "policy__alert_template",
 | 
			
		||||
                "alert_template",
 | 
			
		||||
            )
 | 
			
		||||
            .prefetch_related(
 | 
			
		||||
                Prefetch(
 | 
			
		||||
                    "checkresults",
 | 
			
		||||
                    queryset=CheckResult.objects.select_related("assigned_check"),
 | 
			
		||||
                ),
 | 
			
		||||
                "agentchecks",
 | 
			
		||||
            ),
 | 
			
		||||
            agent_id=agent_id,
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        if not _has_perm_on_agent(request.user, agent.agent_id):
 | 
			
		||||
            raise PermissionDenied()
 | 
			
		||||
 | 
			
		||||
        for check in agent.get_checks_with_policies():
 | 
			
		||||
            try:
 | 
			
		||||
                result = check.check_result
 | 
			
		||||
                result.status = CheckStatus.PASSING
 | 
			
		||||
                result.save()
 | 
			
		||||
                if alert := Alert.create_or_return_check_alert(
 | 
			
		||||
                    result.assigned_check, agent=agent, skip_create=True
 | 
			
		||||
                ):
 | 
			
		||||
                    alert.resolve()
 | 
			
		||||
            except:
 | 
			
		||||
                # check hasn't run yet, no check result entry
 | 
			
		||||
                continue
 | 
			
		||||
 | 
			
		||||
        return Response("All checks status were reset")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class GetCheckHistory(APIView):
 | 
			
		||||
    permission_classes = [IsAuthenticated, ChecksPerms]
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@ import re
 | 
			
		||||
import uuid
 | 
			
		||||
from contextlib import suppress
 | 
			
		||||
 | 
			
		||||
from django.conf import settings
 | 
			
		||||
from django.db.models import Count, Exists, OuterRef, Prefetch, prefetch_related_objects
 | 
			
		||||
from django.shortcuts import get_object_or_404
 | 
			
		||||
from django.utils import timezone as djangotime
 | 
			
		||||
@@ -288,6 +289,9 @@ class AgentDeployment(APIView):
 | 
			
		||||
        return Response(DeploymentSerializer(deps, many=True).data)
 | 
			
		||||
 | 
			
		||||
    def post(self, request):
 | 
			
		||||
        if getattr(settings, "TRMM_INSECURE", False):
 | 
			
		||||
            return notify_error("Not available in insecure mode")
 | 
			
		||||
 | 
			
		||||
        from accounts.models import User
 | 
			
		||||
 | 
			
		||||
        site = get_object_or_404(Site, pk=request.data["site"])
 | 
			
		||||
@@ -343,6 +347,9 @@ class GenerateAgent(APIView):
 | 
			
		||||
    permission_classes = (AllowAny,)
 | 
			
		||||
 | 
			
		||||
    def get(self, request, uid):
 | 
			
		||||
        if getattr(settings, "TRMM_INSECURE", False):
 | 
			
		||||
            return notify_error("Not available in insecure mode")
 | 
			
		||||
 | 
			
		||||
        from tacticalrmm.utils import generate_winagent_exe
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,16 @@ if [ "${HAS_SYSTEMD}" != 'systemd' ]; then
 | 
			
		||||
    exit 1
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if [[ $DISPLAY ]]; then
 | 
			
		||||
    echo "ERROR: Display detected. Installer only supports running headless, i.e from ssh."
 | 
			
		||||
    echo "If you cannot ssh in then please run 'sudo systemctl isolate multi-user.target' to switch to a non-graphical user session and run the installer again."
 | 
			
		||||
    exit 1
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
DEBUG=0
 | 
			
		||||
INSECURE=0
 | 
			
		||||
NOMESH=0
 | 
			
		||||
 | 
			
		||||
agentDL='agentDLChange'
 | 
			
		||||
meshDL='meshDLChange'
 | 
			
		||||
 | 
			
		||||
@@ -124,6 +134,19 @@ if [ $# -ne 0 ] && [ $1 == 'uninstall' ]; then
 | 
			
		||||
    exit 0
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
while [[ "$#" -gt 0 ]]; do
 | 
			
		||||
    case $1 in
 | 
			
		||||
    --debug) DEBUG=1 ;;
 | 
			
		||||
    --insecure) INSECURE=1 ;;
 | 
			
		||||
    --nomesh) NOMESH=1 ;;
 | 
			
		||||
    *)
 | 
			
		||||
        echo "ERROR: Unknown parameter: $1"
 | 
			
		||||
        exit 1
 | 
			
		||||
        ;;
 | 
			
		||||
    esac
 | 
			
		||||
    shift
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
RemoveOldAgent
 | 
			
		||||
 | 
			
		||||
echo "Downloading tactical agent..."
 | 
			
		||||
@@ -136,7 +159,7 @@ chmod +x ${agentBin}
 | 
			
		||||
 | 
			
		||||
MESH_NODE_ID=""
 | 
			
		||||
 | 
			
		||||
if [ $# -ne 0 ] && [ $1 == '--nomesh' ]; then
 | 
			
		||||
if [[ $NOMESH -eq 1 ]]; then
 | 
			
		||||
    echo "Skipping mesh install"
 | 
			
		||||
else
 | 
			
		||||
    if [ -f "${meshSystemBin}" ]; then
 | 
			
		||||
@@ -154,18 +177,22 @@ if [ ! -d "${agentBinPath}" ]; then
 | 
			
		||||
    mkdir -p ${agentBinPath}
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if [ $# -ne 0 ] && [ $1 == '--debug' ]; then
 | 
			
		||||
    INSTALL_CMD="${agentBin} -m install -api ${apiURL} -client-id ${clientID} -site-id ${siteID} -agent-type ${agentType} -auth ${token} -log debug"
 | 
			
		||||
else
 | 
			
		||||
    INSTALL_CMD="${agentBin} -m install -api ${apiURL} -client-id ${clientID} -site-id ${siteID} -agent-type ${agentType} -auth ${token}"
 | 
			
		||||
fi
 | 
			
		||||
INSTALL_CMD="${agentBin} -m install -api ${apiURL} -client-id ${clientID} -site-id ${siteID} -agent-type ${agentType} -auth ${token}"
 | 
			
		||||
 | 
			
		||||
if [ "${MESH_NODE_ID}" != '' ]; then
 | 
			
		||||
    INSTALL_CMD+=" -meshnodeid ${MESH_NODE_ID}"
 | 
			
		||||
    INSTALL_CMD+=" --meshnodeid ${MESH_NODE_ID}"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if [[ $DEBUG -eq 1 ]]; then
 | 
			
		||||
    INSTALL_CMD+=" --log debug"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if [[ $INSECURE -eq 1 ]]; then
 | 
			
		||||
    INSTALL_CMD+=" --insecure"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if [ "${proxy}" != '' ]; then
 | 
			
		||||
    INSTALL_CMD+=" -proxy ${proxy}"
 | 
			
		||||
    INSTALL_CMD+=" --proxy ${proxy}"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
eval ${INSTALL_CMD}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@ import os
 | 
			
		||||
from django.conf import settings
 | 
			
		||||
from django.core.management.base import BaseCommand
 | 
			
		||||
 | 
			
		||||
from tacticalrmm.helpers import get_nats_ports
 | 
			
		||||
from tacticalrmm.helpers import get_nats_internal_protocol, get_nats_ports
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Command(BaseCommand):
 | 
			
		||||
@@ -21,9 +21,10 @@ class Command(BaseCommand):
 | 
			
		||||
            ssl = "disable"
 | 
			
		||||
 | 
			
		||||
        nats_std_port, _ = get_nats_ports()
 | 
			
		||||
        proto = get_nats_internal_protocol()
 | 
			
		||||
        config = {
 | 
			
		||||
            "key": settings.SECRET_KEY,
 | 
			
		||||
            "natsurl": f"tls://{settings.ALLOWED_HOSTS[0]}:{nats_std_port}",
 | 
			
		||||
            "natsurl": f"{proto}://{settings.ALLOWED_HOSTS[0]}:{nats_std_port}",
 | 
			
		||||
            "user": db["USER"],
 | 
			
		||||
            "pass": db["PASSWORD"],
 | 
			
		||||
            "host": db["HOST"],
 | 
			
		||||
 
 | 
			
		||||
@@ -502,3 +502,27 @@ class TestCoreUtils(TacticalTestCase):
 | 
			
		||||
            r,
 | 
			
		||||
            "http://tactical-meshcentral:4443/meshagents?id=4&meshid=abc123&installflags=0",
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    @override_settings(TRMM_INSECURE=True)
 | 
			
		||||
    def test_get_meshagent_url_insecure(self):
 | 
			
		||||
        r = get_meshagent_url(
 | 
			
		||||
            ident=MeshAgentIdent.DARWIN_UNIVERSAL,
 | 
			
		||||
            plat="darwin",
 | 
			
		||||
            mesh_site="https://mesh.example.com",
 | 
			
		||||
            mesh_device_id="abc123",
 | 
			
		||||
        )
 | 
			
		||||
        self.assertEqual(
 | 
			
		||||
            r,
 | 
			
		||||
            "http://mesh.example.com:4430/meshagents?id=abc123&installflags=2&meshinstall=10005",
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        r = get_meshagent_url(
 | 
			
		||||
            ident=MeshAgentIdent.WIN64,
 | 
			
		||||
            plat="windows",
 | 
			
		||||
            mesh_site="https://mesh.example.com",
 | 
			
		||||
            mesh_device_id="abc123",
 | 
			
		||||
        )
 | 
			
		||||
        self.assertEqual(
 | 
			
		||||
            r,
 | 
			
		||||
            "http://mesh.example.com:4430/meshagents?id=4&meshid=abc123&installflags=0",
 | 
			
		||||
        )
 | 
			
		||||
 
 | 
			
		||||
@@ -88,8 +88,12 @@ def get_mesh_ws_url() -> str:
 | 
			
		||||
    if settings.DOCKER_BUILD:
 | 
			
		||||
        uri = f"{settings.MESH_WS_URL}/control.ashx?auth={token}"
 | 
			
		||||
    else:
 | 
			
		||||
        site = core.mesh_site.replace("https", "wss")
 | 
			
		||||
        uri = f"{site}/control.ashx?auth={token}"
 | 
			
		||||
        if getattr(settings, "TRMM_INSECURE", False):
 | 
			
		||||
            site = core.mesh_site.replace("https", "ws")
 | 
			
		||||
            uri = f"{site}:4430/control.ashx?auth={token}"
 | 
			
		||||
        else:
 | 
			
		||||
            site = core.mesh_site.replace("https", "wss")
 | 
			
		||||
            uri = f"{site}/control.ashx?auth={token}"
 | 
			
		||||
 | 
			
		||||
    return uri
 | 
			
		||||
 | 
			
		||||
@@ -181,6 +185,8 @@ def get_meshagent_url(
 | 
			
		||||
) -> str:
 | 
			
		||||
    if settings.DOCKER_BUILD:
 | 
			
		||||
        base = settings.MESH_WS_URL.replace("ws://", "http://")
 | 
			
		||||
    elif getattr(settings, "TRMM_INSECURE", False):
 | 
			
		||||
        base = mesh_site.replace("https", "http") + ":4430"
 | 
			
		||||
    else:
 | 
			
		||||
        base = mesh_site
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -42,6 +42,13 @@ def get_nats_ports() -> tuple[int, int]:
 | 
			
		||||
    return nats_standard_port, nats_websocket_port
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_nats_internal_protocol() -> str:
 | 
			
		||||
    if getattr(settings, "TRMM_INSECURE", False):
 | 
			
		||||
        return "nats"
 | 
			
		||||
 | 
			
		||||
    return "tls"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def date_is_in_past(*, datetime_obj: "datetime", agent_tz: str) -> bool:
 | 
			
		||||
    """
 | 
			
		||||
    datetime_obj must be a naive datetime
 | 
			
		||||
@@ -66,8 +73,9 @@ def rand_range(min: int, max: int) -> float:
 | 
			
		||||
 | 
			
		||||
def setup_nats_options() -> dict[str, Any]:
 | 
			
		||||
    nats_std_port, _ = get_nats_ports()
 | 
			
		||||
    proto = get_nats_internal_protocol()
 | 
			
		||||
    opts = {
 | 
			
		||||
        "servers": f"tls://{settings.ALLOWED_HOSTS[0]}:{nats_std_port}",
 | 
			
		||||
        "servers": f"{proto}://{settings.ALLOWED_HOSTS[0]}:{nats_std_port}",
 | 
			
		||||
        "user": "tacticalrmm",
 | 
			
		||||
        "name": "trmm-django",
 | 
			
		||||
        "password": settings.SECRET_KEY,
 | 
			
		||||
 
 | 
			
		||||
@@ -20,17 +20,17 @@ MAC_UNINSTALL = BASE_DIR / "core" / "mac_uninstall.sh"
 | 
			
		||||
AUTH_USER_MODEL = "accounts.User"
 | 
			
		||||
 | 
			
		||||
# latest release
 | 
			
		||||
TRMM_VERSION = "0.16.3"
 | 
			
		||||
TRMM_VERSION = "0.16.4"
 | 
			
		||||
 | 
			
		||||
# https://github.com/amidaware/tacticalrmm-web
 | 
			
		||||
WEB_VERSION = "0.101.28"
 | 
			
		||||
WEB_VERSION = "0.101.29"
 | 
			
		||||
 | 
			
		||||
# bump this version everytime vue code is changed
 | 
			
		||||
# to alert user they need to manually refresh their browser
 | 
			
		||||
APP_VER = "0.0.183"
 | 
			
		||||
APP_VER = "0.0.184"
 | 
			
		||||
 | 
			
		||||
# https://github.com/amidaware/rmmagent
 | 
			
		||||
LATEST_AGENT_VER = "2.4.11"
 | 
			
		||||
LATEST_AGENT_VER = "2.5.0"
 | 
			
		||||
 | 
			
		||||
MESH_VER = "1.1.9"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -34,7 +34,12 @@ from tacticalrmm.constants import (
 | 
			
		||||
    DebugLogType,
 | 
			
		||||
    ScriptShell,
 | 
			
		||||
)
 | 
			
		||||
from tacticalrmm.helpers import get_certs, get_nats_ports, notify_error
 | 
			
		||||
from tacticalrmm.helpers import (
 | 
			
		||||
    get_certs,
 | 
			
		||||
    get_nats_internal_protocol,
 | 
			
		||||
    get_nats_ports,
 | 
			
		||||
    notify_error,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def generate_winagent_exe(
 | 
			
		||||
@@ -204,10 +209,6 @@ def reload_nats() -> None:
 | 
			
		||||
    nats_std_port, nats_ws_port = get_nats_ports()
 | 
			
		||||
 | 
			
		||||
    config = {
 | 
			
		||||
        "tls": {
 | 
			
		||||
            "cert_file": cert_file,
 | 
			
		||||
            "key_file": key_file,
 | 
			
		||||
        },
 | 
			
		||||
        "authorization": {"users": users},
 | 
			
		||||
        "max_payload": 67108864,
 | 
			
		||||
        "port": nats_std_port,  # internal only
 | 
			
		||||
@@ -217,6 +218,12 @@ def reload_nats() -> None:
 | 
			
		||||
        },
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if get_nats_internal_protocol() == "tls":
 | 
			
		||||
        config["tls"] = {
 | 
			
		||||
            "cert_file": cert_file,
 | 
			
		||||
            "key_file": key_file,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    if "NATS_HTTP_PORT" in os.environ:
 | 
			
		||||
        config["http_port"] = int(os.getenv("NATS_HTTP_PORT"))  # type: ignore
 | 
			
		||||
    elif hasattr(settings, "NATS_HTTP_PORT"):
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										11
									
								
								backup.sh
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								backup.sh
									
									
									
									
									
								
							@@ -1,6 +1,6 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
 | 
			
		||||
SCRIPT_VERSION="28"
 | 
			
		||||
SCRIPT_VERSION="29"
 | 
			
		||||
 | 
			
		||||
GREEN='\033[0;32m'
 | 
			
		||||
YELLOW='\033[1;33m'
 | 
			
		||||
@@ -72,7 +72,7 @@ mkdir ${tmp_dir}/confd
 | 
			
		||||
POSTGRES_USER=$(/rmm/api/env/bin/python /rmm/api/tacticalrmm/manage.py get_config dbuser)
 | 
			
		||||
POSTGRES_PW=$(/rmm/api/env/bin/python /rmm/api/tacticalrmm/manage.py get_config dbpw)
 | 
			
		||||
 | 
			
		||||
pg_dump --dbname=postgresql://"${POSTGRES_USER}":"${POSTGRES_PW}"@127.0.0.1:5432/tacticalrmm | gzip -9 >${tmp_dir}/postgres/db-${dt_now}.psql.gz
 | 
			
		||||
pg_dump --dbname=postgresql://"${POSTGRES_USER}":"${POSTGRES_PW}"@localhost:5432/tacticalrmm | gzip -9 >${tmp_dir}/postgres/db-${dt_now}.psql.gz
 | 
			
		||||
 | 
			
		||||
node /meshcentral/node_modules/meshcentral --dbexport # for import to postgres
 | 
			
		||||
 | 
			
		||||
@@ -82,7 +82,7 @@ if grep -q postgres "/meshcentral/meshcentral-data/config.json"; then
 | 
			
		||||
    fi
 | 
			
		||||
    MESH_POSTGRES_USER=$(jq '.settings.postgres.user' /meshcentral/meshcentral-data/config.json -r)
 | 
			
		||||
    MESH_POSTGRES_PW=$(jq '.settings.postgres.password' /meshcentral/meshcentral-data/config.json -r)
 | 
			
		||||
    pg_dump --dbname=postgresql://"${MESH_POSTGRES_USER}":"${MESH_POSTGRES_PW}"@127.0.0.1:5432/meshcentral | gzip -9 >${tmp_dir}/postgres/mesh-db-${dt_now}.psql.gz
 | 
			
		||||
    pg_dump --dbname=postgresql://"${MESH_POSTGRES_USER}":"${MESH_POSTGRES_PW}"@localhost:5432/meshcentral | gzip -9 >${tmp_dir}/postgres/mesh-db-${dt_now}.psql.gz
 | 
			
		||||
else
 | 
			
		||||
    mongodump --gzip --out=${tmp_dir}/meshcentral/mongo
 | 
			
		||||
fi
 | 
			
		||||
@@ -101,6 +101,11 @@ if grep -q CERT_FILE "$local_settings"; then
 | 
			
		||||
    KEY_FILE=$(grep "^KEY_FILE" "$local_settings" | awk -F'[= "]' '{print $5}')
 | 
			
		||||
    cp -p $CERT_FILE ${tmp_dir}/certs/custom/cert
 | 
			
		||||
    cp -p $KEY_FILE ${tmp_dir}/certs/custom/key
 | 
			
		||||
elif grep -q TRMM_INSECURE "$local_settings"; then
 | 
			
		||||
    mkdir -p ${tmp_dir}/certs/selfsigned
 | 
			
		||||
    certdir='/etc/ssl/tactical'
 | 
			
		||||
    cp -p ${certdir}/key.pem ${tmp_dir}/certs/selfsigned/
 | 
			
		||||
    cp -p ${certdir}/cert.pem ${tmp_dir}/certs/selfsigned/
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
for i in rmm frontend meshcentral; do
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										62
									
								
								install.sh
									
									
									
									
									
								
							
							
						
						
									
										62
									
								
								install.sh
									
									
									
									
									
								
							@@ -1,9 +1,9 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
 | 
			
		||||
SCRIPT_VERSION="76"
 | 
			
		||||
SCRIPT_VERSION="77"
 | 
			
		||||
SCRIPT_URL='https://raw.githubusercontent.com/amidaware/tacticalrmm/master/install.sh'
 | 
			
		||||
 | 
			
		||||
sudo apt install -y curl wget dirmngr gnupg lsb-release
 | 
			
		||||
sudo apt install -y curl wget dirmngr gnupg lsb-release ca-certificates
 | 
			
		||||
 | 
			
		||||
GREEN='\033[0;32m'
 | 
			
		||||
YELLOW='\033[1;33m'
 | 
			
		||||
@@ -14,6 +14,7 @@ NC='\033[0m'
 | 
			
		||||
SCRIPTS_DIR='/opt/trmm-community-scripts'
 | 
			
		||||
PYTHON_VER='3.11.4'
 | 
			
		||||
SETTINGS_FILE='/rmm/api/tacticalrmm/tacticalrmm/settings.py'
 | 
			
		||||
local_settings='/rmm/api/tacticalrmm/tacticalrmm/local_settings.py'
 | 
			
		||||
 | 
			
		||||
TMP_FILE=$(mktemp -p "" "rmminstall_XXXXXXXXXX")
 | 
			
		||||
curl -s -L "${SCRIPT_URL}" >${TMP_FILE}
 | 
			
		||||
@@ -161,19 +162,38 @@ if echo "$IPV4" | grep -qE '^(10\.|172\.1[6789]\.|172\.2[0-9]\.|172\.3[01]\.|192
 | 
			
		||||
  BEHIND_NAT=true
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
insecure=false
 | 
			
		||||
if [[ $* == *--insecure* ]]; then
 | 
			
		||||
  insecure=true
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
sudo apt install -y software-properties-common
 | 
			
		||||
sudo apt update
 | 
			
		||||
sudo apt install -y certbot openssl
 | 
			
		||||
sudo apt install -y openssl
 | 
			
		||||
 | 
			
		||||
print_green 'Getting wildcard cert'
 | 
			
		||||
if [[ "$insecure" = true ]]; then
 | 
			
		||||
  print_green 'Generating self-signed cert'
 | 
			
		||||
  certdir='/etc/ssl/tactical'
 | 
			
		||||
  sudo mkdir -p $certdir
 | 
			
		||||
  sudo chown ${USER}:${USER} $certdir
 | 
			
		||||
  sudo chmod 770 $certdir
 | 
			
		||||
  CERT_PRIV_KEY=${certdir}/key.pem
 | 
			
		||||
  CERT_PUB_KEY=${certdir}/cert.pem
 | 
			
		||||
  openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 \
 | 
			
		||||
    -nodes -keyout ${CERT_PRIV_KEY} -out ${CERT_PUB_KEY} -subj "/CN=${rootdomain}" \
 | 
			
		||||
    -addext "subjectAltName=DNS:${rootdomain},DNS:*.${rootdomain}"
 | 
			
		||||
 | 
			
		||||
else
 | 
			
		||||
  sudo apt install -y certbot
 | 
			
		||||
  print_green 'Getting wildcard cert'
 | 
			
		||||
 | 
			
		||||
sudo certbot certonly --manual -d *.${rootdomain} --agree-tos --no-bootstrap --preferred-challenges dns -m ${letsemail} --no-eff-email
 | 
			
		||||
while [[ $? -ne 0 ]]; do
 | 
			
		||||
  sudo certbot certonly --manual -d *.${rootdomain} --agree-tos --no-bootstrap --preferred-challenges dns -m ${letsemail} --no-eff-email
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
CERT_PRIV_KEY=/etc/letsencrypt/live/${rootdomain}/privkey.pem
 | 
			
		||||
CERT_PUB_KEY=/etc/letsencrypt/live/${rootdomain}/fullchain.pem
 | 
			
		||||
  while [[ $? -ne 0 ]]; do
 | 
			
		||||
    sudo certbot certonly --manual -d *.${rootdomain} --agree-tos --no-bootstrap --preferred-challenges dns -m ${letsemail} --no-eff-email
 | 
			
		||||
  done
 | 
			
		||||
  CERT_PRIV_KEY=/etc/letsencrypt/live/${rootdomain}/privkey.pem
 | 
			
		||||
  CERT_PUB_KEY=/etc/letsencrypt/live/${rootdomain}/fullchain.pem
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
sudo chown ${USER}:${USER} -R /etc/letsencrypt
 | 
			
		||||
 | 
			
		||||
@@ -232,7 +252,10 @@ done
 | 
			
		||||
 | 
			
		||||
print_green 'Installing NodeJS'
 | 
			
		||||
 | 
			
		||||
curl -sL https://deb.nodesource.com/setup_18.x | sudo -E bash -
 | 
			
		||||
sudo mkdir -p /etc/apt/keyrings
 | 
			
		||||
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
 | 
			
		||||
NODE_MAJOR=18
 | 
			
		||||
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list
 | 
			
		||||
sudo apt update
 | 
			
		||||
sudo apt install -y gcc g++ make
 | 
			
		||||
sudo apt install -y nodejs
 | 
			
		||||
@@ -253,7 +276,7 @@ cd ~
 | 
			
		||||
sudo rm -rf Python-${PYTHON_VER} Python-${PYTHON_VER}.tgz
 | 
			
		||||
 | 
			
		||||
print_green 'Installing redis and git'
 | 
			
		||||
sudo apt install -y ca-certificates redis git
 | 
			
		||||
sudo apt install -y redis git
 | 
			
		||||
 | 
			
		||||
print_green 'Installing postgresql'
 | 
			
		||||
 | 
			
		||||
@@ -429,7 +452,11 @@ REDIS_HOST    = "localhost"
 | 
			
		||||
ADMIN_ENABLED = True
 | 
			
		||||
EOF
 | 
			
		||||
)"
 | 
			
		||||
echo "${localvars}" >/rmm/api/tacticalrmm/tacticalrmm/local_settings.py
 | 
			
		||||
echo "${localvars}" >$local_settings
 | 
			
		||||
 | 
			
		||||
if [[ "$insecure" = true ]]; then
 | 
			
		||||
  echo "TRMM_INSECURE = True" | tee --append $local_settings >/dev/null
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if [ "$arch" = "x86_64" ]; then
 | 
			
		||||
  natsapi='nats-api'
 | 
			
		||||
@@ -462,7 +489,7 @@ python manage.py load_community_scripts
 | 
			
		||||
WEB_VERSION=$(python manage.py get_config webversion)
 | 
			
		||||
printf >&2 "${YELLOW}%0.s*${NC}" {1..80}
 | 
			
		||||
printf >&2 "\n"
 | 
			
		||||
printf >&2 "${YELLOW}Please create your login for the RMM website and django admin${NC}\n"
 | 
			
		||||
printf >&2 "${YELLOW}Please create your login for the RMM website${NC}\n"
 | 
			
		||||
printf >&2 "${YELLOW}%0.s*${NC}" {1..80}
 | 
			
		||||
printf >&2 "\n"
 | 
			
		||||
echo -ne "Username: "
 | 
			
		||||
@@ -872,7 +899,7 @@ done
 | 
			
		||||
sleep 5
 | 
			
		||||
sudo systemctl enable meshcentral
 | 
			
		||||
 | 
			
		||||
print_green 'Starting meshcentral and waiting for it to install plugins'
 | 
			
		||||
print_green 'Starting meshcentral and waiting for it to be ready'
 | 
			
		||||
 | 
			
		||||
sudo systemctl restart meshcentral
 | 
			
		||||
 | 
			
		||||
@@ -896,7 +923,7 @@ meshtoken="$(
 | 
			
		||||
MESH_TOKEN_KEY = "${MESHTOKENKEY}"
 | 
			
		||||
EOF
 | 
			
		||||
)"
 | 
			
		||||
echo "${meshtoken}" | tee --append /rmm/api/tacticalrmm/tacticalrmm/local_settings.py >/dev/null
 | 
			
		||||
echo "${meshtoken}" | tee --append $local_settings >/dev/null
 | 
			
		||||
 | 
			
		||||
print_green 'Creating meshcentral account and group'
 | 
			
		||||
 | 
			
		||||
@@ -933,7 +960,7 @@ sudo systemctl enable nats-api.service
 | 
			
		||||
sudo systemctl start nats-api.service
 | 
			
		||||
 | 
			
		||||
## disable django admin
 | 
			
		||||
sed -i 's/ADMIN_ENABLED = True/ADMIN_ENABLED = False/g' /rmm/api/tacticalrmm/tacticalrmm/local_settings.py
 | 
			
		||||
sed -i 's/ADMIN_ENABLED = True/ADMIN_ENABLED = False/g' $local_settings
 | 
			
		||||
 | 
			
		||||
print_green 'Restarting services'
 | 
			
		||||
for i in rmm.service daphne.service celery.service celerybeat.service; do
 | 
			
		||||
@@ -945,7 +972,6 @@ printf >&2 "${YELLOW}%0.s*${NC}" {1..80}
 | 
			
		||||
printf >&2 "\n\n"
 | 
			
		||||
printf >&2 "${YELLOW}Installation complete!${NC}\n\n"
 | 
			
		||||
printf >&2 "${YELLOW}Access your rmm at: ${GREEN}https://${frontenddomain}${NC}\n\n"
 | 
			
		||||
printf >&2 "${YELLOW}Django admin url (disabled by default): ${GREEN}https://${rmmdomain}/${ADMINURL}/${NC}\n\n"
 | 
			
		||||
printf >&2 "${YELLOW}MeshCentral username: ${GREEN}${meshusername}${NC}\n"
 | 
			
		||||
printf >&2 "${YELLOW}MeshCentral password: ${GREEN}${MESHPASSWD}${NC}\n\n"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										19
									
								
								restore.sh
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								restore.sh
									
									
									
									
									
								
							@@ -1,10 +1,10 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
 | 
			
		||||
SCRIPT_VERSION="51"
 | 
			
		||||
SCRIPT_VERSION="52"
 | 
			
		||||
SCRIPT_URL='https://raw.githubusercontent.com/amidaware/tacticalrmm/master/restore.sh'
 | 
			
		||||
 | 
			
		||||
sudo apt update
 | 
			
		||||
sudo apt install -y curl wget dirmngr gnupg lsb-release
 | 
			
		||||
sudo apt install -y curl wget dirmngr gnupg lsb-release ca-certificates
 | 
			
		||||
 | 
			
		||||
GREEN='\033[0;32m'
 | 
			
		||||
YELLOW='\033[1;33m'
 | 
			
		||||
@@ -122,7 +122,10 @@ sudo apt update
 | 
			
		||||
 | 
			
		||||
print_green 'Installing NodeJS'
 | 
			
		||||
 | 
			
		||||
curl -sL https://deb.nodesource.com/setup_18.x | sudo -E bash -
 | 
			
		||||
sudo mkdir -p /etc/apt/keyrings
 | 
			
		||||
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
 | 
			
		||||
NODE_MAJOR=18
 | 
			
		||||
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list
 | 
			
		||||
sudo apt update
 | 
			
		||||
sudo apt install -y gcc g++ make
 | 
			
		||||
sudo apt install -y nodejs
 | 
			
		||||
@@ -209,7 +212,13 @@ if [ -d "${tmp_dir}/certs/custom" ]; then
 | 
			
		||||
 | 
			
		||||
  cp -p ${tmp_dir}/certs/custom/cert $CERT_FILE
 | 
			
		||||
  cp -p ${tmp_dir}/certs/custom/key $KEY_FILE
 | 
			
		||||
 | 
			
		||||
elif [ -d "${tmp_dir}/certs/selfsigned" ]; then
 | 
			
		||||
  certdir='/etc/ssl/tactical'
 | 
			
		||||
  sudo mkdir -p $certdir
 | 
			
		||||
  sudo chown ${USER}:${USER} $certdir
 | 
			
		||||
  sudo chmod 770 $certdir
 | 
			
		||||
  cp -p ${tmp_dir}/certs/selfsigned/key.pem $certdir
 | 
			
		||||
  cp -p ${tmp_dir}/certs/selfsigned/cert.pem $certdir
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
print_green 'Restoring celery configs'
 | 
			
		||||
@@ -238,7 +247,7 @@ cd ~
 | 
			
		||||
sudo rm -rf Python-${PYTHON_VER} Python-${PYTHON_VER}.tgz
 | 
			
		||||
 | 
			
		||||
print_green 'Installing redis and git'
 | 
			
		||||
sudo apt install -y ca-certificates redis git
 | 
			
		||||
sudo apt install -y redis git
 | 
			
		||||
 | 
			
		||||
print_green 'Installing postgresql'
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user