Skip to content

Commit

Permalink
Release 0.8.5
Browse files Browse the repository at this point in the history
  • Loading branch information
wh1te909 committed Oct 10, 2021
2 parents 9011148 + aff659b commit 5c74d1d
Show file tree
Hide file tree
Showing 105 changed files with 3,092 additions and 2,186 deletions.
1 change: 0 additions & 1 deletion .devcontainer/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ POSTGRES_PASS=postgrespass
# DEV SETTINGS
APP_PORT=80
API_PORT=80
API_PROTOCOL=https://
HTTP_PROTOCOL=https
DOCKER_NETWORK=172.21.0.0/24
DOCKER_NGINX_IP=172.21.0.20
Expand Down
1 change: 0 additions & 1 deletion .devcontainer/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,6 @@ services:
CERT_PRIV_KEY: ${CERT_PRIV_KEY}
APP_PORT: ${APP_PORT}
API_PORT: ${API_PORT}
API_PROTOCOL: ${API_PROTOCOL}
DEV: 1
networks:
dev:
Expand Down
1 change: 1 addition & 0 deletions api/tacticalrmm/agents/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ class Meta:
fields = [
"id",
"hostname",
"block_policy_inheritance",
"client",
"site",
"monitoring_type",
Expand Down
36 changes: 7 additions & 29 deletions api/tacticalrmm/agents/tasks.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import asyncio
import datetime as dt
import random
import urllib.parse
from time import sleep
from typing import Union

from alerts.models import Alert
from core.models import CodeSignToken, CoreSettings
from core.models import CoreSettings
from django.conf import settings
from django.utils import timezone as djangotime
from logs.models import DebugLog, PendingAction
Expand All @@ -16,10 +15,10 @@
from tacticalrmm.utils import run_nats_api_cmd

from agents.models import Agent
from agents.utils import get_winagent_url


def agent_update(pk: int, codesigntoken: str = None, force: bool = False) -> str:
from agents.utils import get_exegen_url
def agent_update(pk: int, force: bool = False) -> str:

agent = Agent.objects.get(pk=pk)

Expand All @@ -37,13 +36,7 @@ def agent_update(pk: int, codesigntoken: str = None, force: bool = False) -> str

version = settings.LATEST_AGENT_VER
inno = agent.win_inno_exe

if codesigntoken is not None and pyver.parse(version) >= pyver.parse("1.5.0"):
base_url = get_exegen_url() + "/api/v1/winagents/?"
params = {"version": version, "arch": agent.arch, "token": codesigntoken}
url = base_url + urllib.parse.urlencode(params)
else:
url = agent.winagent_dl
url = get_winagent_url(agent.arch)

if not force:
if agent.pendingactions.filter(
Expand Down Expand Up @@ -77,30 +70,20 @@ def agent_update(pk: int, codesigntoken: str = None, force: bool = False) -> str

@app.task
def force_code_sign(pks: list[int]) -> None:
try:
token = CodeSignToken.objects.first().token # type:ignore
except:
return

chunks = (pks[i : i + 50] for i in range(0, len(pks), 50))
for chunk in chunks:
for pk in chunk:
agent_update(pk=pk, codesigntoken=token, force=True)
agent_update(pk=pk, force=True)
sleep(0.05)
sleep(4)


@app.task
def send_agent_update_task(pks: list[int]) -> None:
try:
codesigntoken = CodeSignToken.objects.first().token # type:ignore
except:
codesigntoken = None

chunks = (pks[i : i + 30] for i in range(0, len(pks), 30))
for chunk in chunks:
for pk in chunk:
agent_update(pk, codesigntoken)
agent_update(pk)
sleep(0.05)
sleep(4)

Expand All @@ -111,11 +94,6 @@ def auto_self_agent_update_task() -> None:
if not core.agent_auto_update: # type:ignore
return

try:
codesigntoken = CodeSignToken.objects.first().token # type:ignore
except:
codesigntoken = None

q = Agent.objects.only("pk", "version")
pks: list[int] = [
i.pk
Expand All @@ -126,7 +104,7 @@ def auto_self_agent_update_task() -> None:
chunks = (pks[i : i + 30] for i in range(0, len(pks), 30))
for chunk in chunks:
for pk in chunk:
agent_update(pk, codesigntoken)
agent_update(pk)
sleep(0.05)
sleep(4)

Expand Down
12 changes: 7 additions & 5 deletions api/tacticalrmm/agents/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -1049,9 +1049,11 @@ def setUp(self):
self.authenticate()
self.setup_coresettings()

@patch("agents.utils.get_exegen_url")
@patch("agents.utils.get_winagent_url")
@patch("agents.models.Agent.nats_cmd")
def test_agent_update(self, nats_cmd, get_exe):
def test_agent_update(self, nats_cmd, get_url):
get_url.return_value = "https://exe.tacticalrmm.io"

from agents.tasks import agent_update

agent_noarch = baker.make_recipe(
Expand All @@ -1077,7 +1079,7 @@ def test_agent_update(self, nats_cmd, get_exe):
version="1.4.14",
)

r = agent_update(agent64_nosign.pk, None)
r = agent_update(agent64_nosign.pk)
self.assertEqual(r, "created")
action = PendingAction.objects.get(agent__pk=agent64_nosign.pk)
self.assertEqual(action.action_type, "agentupdate")
Expand All @@ -1103,7 +1105,7 @@ def test_agent_update(self, nats_cmd, get_exe):
)

# test __with__ code signing (64 bit)
codesign = baker.make("core.CodeSignToken", token="testtoken123")
""" codesign = baker.make("core.CodeSignToken", token="testtoken123")
agent64_sign = baker.make_recipe(
"agents.agent",
operating_system="Windows 10 Pro, 64 bit (build 19041.450)",
Expand Down Expand Up @@ -1153,7 +1155,7 @@ def test_agent_update(self, nats_cmd, get_exe):
)
action = PendingAction.objects.get(agent__pk=agent32_sign.pk)
self.assertEqual(action.action_type, "agentupdate")
self.assertEqual(action.status, "pending")
self.assertEqual(action.status, "pending") """

@patch("agents.tasks.agent_update")
@patch("agents.tasks.sleep", return_value=None)
Expand Down
25 changes: 14 additions & 11 deletions api/tacticalrmm/agents/utils.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import random
import urllib.parse

import requests

from django.conf import settings
from core.models import CodeSignToken


def get_exegen_url() -> str:
Expand All @@ -20,18 +21,20 @@ def get_exegen_url() -> str:


def get_winagent_url(arch: str) -> str:
from core.models import CodeSignToken

dl_url = settings.DL_32 if arch == "32" else settings.DL_64

try:
codetoken = CodeSignToken.objects.first().token
base_url = get_exegen_url() + "/api/v1/winagents/?"
params = {
"version": settings.LATEST_AGENT_VER,
"arch": arch,
"token": codetoken,
}
dl_url = base_url + urllib.parse.urlencode(params)
t: CodeSignToken = CodeSignToken.objects.first() # type: ignore
if t.is_valid:
base_url = get_exegen_url() + "/api/v1/winagents/?"
params = {
"version": settings.LATEST_AGENT_VER,
"arch": arch,
"token": t.token,
}
dl_url = base_url + urllib.parse.urlencode(params)
except:
dl_url = settings.DL_64 if arch == "64" else settings.DL_32
pass

return dl_url
2 changes: 1 addition & 1 deletion api/tacticalrmm/checks/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ def handle_check(self, data):

elif self.status == "passing":
self.fail_count = 0
self.save(update_fields=["status", "fail_count", "alert_severity"])
self.save()
if Alert.objects.filter(assigned_check=self, resolved=False).exists():
Alert.handle_alert_resolve(self)

Expand Down
4 changes: 2 additions & 2 deletions api/tacticalrmm/checks/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,11 +137,11 @@ def delete(self, request, pk):

# Re-evaluate agent checks is policy was enforced
if check.policy.enforced:
generate_agent_checks_task.delay(policy=check.policy)
generate_agent_checks_task.delay(policy=check.policy.pk)

# Agent check deleted
elif check.agent:
check.agent.generate_checks_from_policies()
generate_agent_checks_task.delay(agents=[check.agent.pk])

return Response(f"{check.readable_desc} was deleted!")

Expand Down
45 changes: 39 additions & 6 deletions api/tacticalrmm/core/models.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import requests
import smtplib
from email.message import EmailMessage
from django.db.models.enums import Choices

import pytz
from django.conf import settings
from django.contrib.postgres.fields import ArrayField
from django.core.exceptions import ValidationError
from django.db import models
from twilio.rest import Client as TwClient
from twilio.base.exceptions import TwilioRestException

from logs.models import BaseAuditModel, DebugLog, LOG_LEVEL_CHOICES

Expand Down Expand Up @@ -195,22 +196,29 @@ def send_mail(self, subject, body, alert_template=None, test=False):
else:
return True

def send_sms(self, body, alert_template=None):
if not alert_template or not self.sms_is_configured:
return
def send_sms(self, body, alert_template=None, test=False):
if not alert_template and not self.sms_is_configured:
return "Sms alerting is not setup correctly."

# override email recipients if alert_template is passed and is set
if alert_template and alert_template.text_recipients:
text_recipients = alert_template.email_recipients
text_recipients = alert_template.text_recipients
else:
text_recipients = self.sms_alert_recipients

if not text_recipients:
return "No sms recipients found"

tw_client = TwClient(self.twilio_account_sid, self.twilio_auth_token)
for num in text_recipients:
try:
tw_client.messages.create(body=body, to=num, from_=self.twilio_number)
except Exception as e:
except TwilioRestException as e:
DebugLog.error(message=f"SMS failed to send: {e}")
if test:
return str(e)

return True

@staticmethod
def serialize(core):
Expand Down Expand Up @@ -306,6 +314,31 @@ def save(self, *args, **kwargs):

super(CodeSignToken, self).save(*args, **kwargs)

@property
def is_valid(self) -> bool:
if not self.token:
return False

errors = []
for url in settings.EXE_GEN_URLS:
try:
r = requests.post(
f"{url}/api/v1/checktoken",
json={"token": self.token},
headers={"Content-type": "application/json"},
timeout=15,
)
except Exception as e:
errors.append(str(e))
else:
errors = []
break

if errors:
return False

return r.status_code == 200

def __str__(self):
return "Code signing token"

Expand Down
25 changes: 9 additions & 16 deletions api/tacticalrmm/core/views.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import os
import pprint
import re

from django.conf import settings
from django.db.models.fields import IPAddressField
from django.shortcuts import get_object_or_404
from logs.models import AuditLog
from rest_framework import status
Expand All @@ -14,7 +12,6 @@
from rest_framework.response import Response
from rest_framework.views import APIView

from agents.permissions import MeshPerms
from tacticalrmm.utils import notify_error

from .models import CodeSignToken, CoreSettings, CustomField, GlobalKVStore, URLAction
Expand All @@ -34,7 +31,7 @@


class UploadMeshAgent(APIView):
permission_classes = [IsAuthenticated, MeshPerms]
permission_classes = [IsAuthenticated, EditCoreSettingsPerms]
parser_class = (FileUploadParser,)

def put(self, request, format=None):
Expand All @@ -50,7 +47,9 @@ def put(self, request, format=None):
for chunk in f.chunks():
j.write(chunk)

return Response(status=status.HTTP_201_CREATED)
return Response(
"Mesh Agent uploaded successfully", status=status.HTTP_201_CREATED
)


@api_view()
Expand Down Expand Up @@ -383,22 +382,16 @@ def patch(self, request):

class TwilioSMSTest(APIView):
def get(self, request):
from twilio.rest import Client as TwClient

core = CoreSettings.objects.first()
if not core.sms_is_configured:
return notify_error(
"All fields are required, including at least 1 recipient"
)

try:
tw_client = TwClient(core.twilio_account_sid, core.twilio_auth_token)
tw_client.messages.create(
body="TacticalRMM Test SMS",
to=core.sms_alert_recipients[0],
from_=core.twilio_number,
)
except Exception as e:
return notify_error(pprint.pformat(e))
r = core.send_sms("TacticalRMM Test SMS", test=True)

if not isinstance(r, bool) and isinstance(r, str):
return notify_error(r)

return Response("SMS Test OK!")
return Response("SMS Test sent successfully!")
Loading

0 comments on commit 5c74d1d

Please sign in to comment.