Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

initial SysTray api PR #1829

Closed
wants to merge 137 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
137 commits
Select commit Hold shift + click to select a range
d791976
Add systray config endpoint for agent
conlan0 Apr 3, 2024
6f1531b
Add systray agent urls
conlan0 Apr 3, 2024
e12d8a1
add agent api communication for systray
conlan0 Apr 3, 2024
cd8182f
Add admin and celery task
conlan0 Apr 3, 2024
0285216
Add systray task to send nats for updated config
conlan0 Apr 3, 2024
6986c9d
Add systray views for frontend
conlan0 Apr 3, 2024
b05194f
Add systray urls for frontend
conlan0 Apr 3, 2024
34aba82
add systray_enabled to core settings
conlan0 Apr 3, 2024
23b56da
add trayicon config to sites
conlan0 Apr 3, 2024
e308c12
Update serializers.py for systray
conlan0 Apr 3, 2024
5b88811
Update celery.py
conlan0 Apr 3, 2024
2edd4c7
Add apiv3 migrations
conlan0 Apr 5, 2024
ca21d7c
add site migrations
conlan0 Apr 5, 2024
b23919f
add core migrations
conlan0 Apr 5, 2024
3b8d62e
Update backup.sh
dinger1986 Apr 2, 2024
258bded
add note about where to find bulk output results
wh1te909 Apr 8, 2024
8308bb5
revert DRF for now until we do more testing
wh1te909 Apr 8, 2024
e37ec80
bump versions
wh1te909 Apr 8, 2024
9c54994
back to dev [skip ci]
wh1te909 Apr 9, 2024
85b7aa1
no-owner for pg_dump
wh1te909 Apr 19, 2024
606bd37
update reqs
wh1te909 Apr 19, 2024
94e7a82
fix script name fixes #1852
wh1te909 Apr 22, 2024
31f337c
revert, already fixed in #1823
wh1te909 Apr 22, 2024
02d77e1
add noninteractive
wh1te909 Apr 25, 2024
9f7cd64
update reqs
wh1te909 May 7, 2024
e0c782e
update reqs
wh1te909 May 16, 2024
3768821
fix snippet bug fixes #1702
wh1te909 May 29, 2024
1d16ff8
switch to localhost to download mesh exe
wh1te909 Jun 8, 2024
f9738b0
update reqs
wh1te909 Jun 8, 2024
0d5ebf5
cleanup pid file on start
wh1te909 Jun 11, 2024
b9df530
fix alert template not assigned on new agent fixes #1896
wh1te909 Jun 19, 2024
e698701
replace expired nginx key
wh1te909 Jun 24, 2024
76c7f3b
troubleshoot_server: Add helper for resolvconf error
silversword411 Jun 24, 2024
58f8529
Added version tracking header info
silversword411 Jun 24, 2024
85fdba0
handle expired nginx signing key
wh1te909 Jun 25, 2024
0ad73d0
update nats-server
wh1te909 Jun 28, 2024
41c1074
init
sadnub Apr 2, 2024
75a05ba
add migrations
sadnub Apr 2, 2024
9622166
fix failure action not saving correctly if a server script
sadnub Apr 16, 2024
02b27bf
black
sadnub Apr 16, 2024
d94564c
fix flake
sadnub Apr 16, 2024
01a2d90
fix webhooks
wh1te909 Apr 16, 2024
ce7f404
set term
wh1te909 Apr 18, 2024
97642dd
modify totp setup view
sadnub Apr 18, 2024
d60f7b4
wrong role name
wh1te909 Apr 18, 2024
0dfd3fe
harden connect method
wh1te909 Apr 18, 2024
49748b7
add view for web hook test and add recursion to the dictionary data r…
sadnub Apr 19, 2024
14d2521
blacked
wh1te909 Apr 22, 2024
afab1c8
fix request body and url
wh1te909 Apr 22, 2024
3230458
cleanup model resolution and potential fix for nested object and arra…
sadnub Apr 23, 2024
a1b213f
allow strings in instance id for Agent hostname
sadnub Apr 23, 2024
c146a2c
Fix string replacement function and fix flaw in regex to match {{mode…
sadnub Apr 23, 2024
45666cc
added check to make sure instance_type == 'none' doesn't trigger a Mo…
sadnub Apr 23, 2024
212dd9a
remove autotasks rework
sadnub Apr 29, 2024
2b4673f
remove run_server_task command
sadnub Apr 29, 2024
ee47ab1
blacked
wh1te909 Apr 29, 2024
d95ea08
remove more server task stuff
sadnub Apr 29, 2024
4de7e58
remove some unused imports
sadnub May 8, 2024
7a073fc
code formatting
sadnub May 8, 2024
17dcc23
fixes some tests for auth, fixes the recursive property lookup, fixes…
sadnub May 14, 2024
88be345
black
sadnub May 14, 2024
ce9a64c
flake
sadnub May 14, 2024
17981f1
use sigkill instead of sigterm
wh1te909 May 22, 2024
eece857
add test server script and start making server scripts/webterm optional
wh1te909 May 22, 2024
0b3d29f
also disable in demo
wh1te909 May 22, 2024
b74b549
fix action/resolved name if webhook
wh1te909 May 28, 2024
d919e13
fix tests
sadnub May 30, 2024
03d7c03
add error handling to webhook test function
sadnub May 30, 2024
75de265
add error handling for server script
wh1te909 Jun 5, 2024
45bb42f
fix tests
wh1te909 Jun 5, 2024
db93d51
add test
wh1te909 Jun 7, 2024
cb2ec22
alerts should not be created if agent in maintenance mode fixes #1849
wh1te909 Jun 7, 2024
65ff062
still need the old login views for frontend transition
wh1te909 Jun 8, 2024
807eee4
rename model fields
wh1te909 Jun 10, 2024
fb5569e
remove migrations
wh1te909 Jun 11, 2024
715202f
redo migrations
wh1te909 Jun 12, 2024
6aa42a0
make description textfield
wh1te909 Jun 12, 2024
5c570ad
make default method post and move imports
wh1te909 Jun 14, 2024
9eacf31
disable web terminal by default
wh1te909 Jun 14, 2024
7a8d95f
return error if disabled
wh1te909 Jun 14, 2024
3d7c35b
add missing returns
wh1te909 Jun 15, 2024
14264d0
simplify query and add logging
wh1te909 Jun 16, 2024
7f84c11
fix deprecation warning
wh1te909 Jun 17, 2024
6b770aa
update reqs
wh1te909 Jun 18, 2024
5df9b5d
use constant
wh1te909 Jun 19, 2024
1bee58b
enforce server script perms when handling alert templates
wh1te909 Jun 19, 2024
55d7559
add auditing to new views
sadnub Jun 20, 2024
485180f
blacked
wh1te909 Jun 21, 2024
71ae545
update pylance settings
wh1te909 Jun 24, 2024
2ff24dd
alerts should still be created even if no notifications are selected
wh1te909 Jun 24, 2024
990c311
fix auditing
wh1te909 Jun 26, 2024
1d84b41
update reqs
wh1te909 Jun 28, 2024
5c55749
delete migrations
wh1te909 Jun 28, 2024
5a5f1e8
redo migrations
wh1te909 Jun 28, 2024
32c5745
use homedir as cwd
wh1te909 Jun 28, 2024
70fe139
bump test vers [skip ci]
wh1te909 Jun 28, 2024
5a6c368
disabled in hosted
wh1te909 Jul 1, 2024
2db2b17
lower workers on smaller instances
wh1te909 Jul 1, 2024
a5c713e
fix auditing/perms for webhook testing
wh1te909 Jul 2, 2024
6b28135
add error handling
wh1te909 Jul 2, 2024
ccfd9fd
wording
wh1te909 Jul 5, 2024
52e9e48
add global option for handling info/warning notifications closes #1834
wh1te909 Jul 5, 2024
0d2f8f6
stop sending resolved message if the alert severity isn't configured …
sadnub Jul 8, 2024
ceff47f
update reqs
wh1te909 Jul 8, 2024
d9286da
make sure server scripts start with shebang
wh1te909 Jul 8, 2024
a0735eb
update nats-api reqs
wh1te909 Jul 8, 2024
00355d3
update bins
wh1te909 Jul 8, 2024
9166af5
more reqs updates
wh1te909 Jul 8, 2024
404dcc4
bump web ver [skip ci]
wh1te909 Jul 8, 2024
e69fe9e
update reqs
wh1te909 Jul 9, 2024
bb9a97b
disable unused websocket endpoint
wh1te909 Jul 9, 2024
0e83607
fix lint
wh1te909 Jul 9, 2024
61505ec
bump versions
wh1te909 Jul 12, 2024
46f00e4
back to dev [skip ci]
wh1te909 Jul 13, 2024
7ee1795
trigger policy refresh on more fields
wh1te909 Jul 17, 2024
512dbd0
fix resolved emails not being sent
wh1te909 Jul 18, 2024
a6f5f22
bump version [skip ci]
wh1te909 Jul 18, 2024
3d9374a
back to dev
wh1te909 Jul 18, 2024
44d4093
add webhook to readme [skip ci]
wh1te909 Jul 18, 2024
9df72b1
fix alert actions not honoring 'run only on' settings and fix availab…
wh1te909 Jul 22, 2024
d8eee28
fix lint
wh1te909 Jul 22, 2024
a1ad8b8
bump version [skip ci]
wh1te909 Jul 22, 2024
9fb17c4
potential fix for webhook failures
wh1te909 Jul 26, 2024
e4cddaa
Enable docker installs to disable web terminal and/or server scripts
bc24fl Jul 26, 2024
979306a
Update entrypoint.sh
bc24fl Jul 27, 2024
3c561c8
Update .env.example
bc24fl Jul 27, 2024
72e63f8
Update docker-compose.yml
bc24fl Jul 27, 2024
8c20086
Update .env.example
bc24fl Jul 27, 2024
56cd495
log body and headers
wh1te909 Jul 28, 2024
42ab02b
more webhook json fixes
wh1te909 Jul 29, 2024
c854bbd
fix custom field view perms fixes #1941
wh1te909 Jul 30, 2024
eea9820
add client and site name to script email closes #1945
wh1te909 Jul 30, 2024
ade88c4
preserve newlines and tabs
wh1te909 Jul 30, 2024
e729e11
also remove control chars
wh1te909 Jul 30, 2024
0a4fd18
fix regex
wh1te909 Aug 1, 2024
891d4fe
add check for turnkey
wh1te909 Aug 4, 2024
e904514
bump versions
wh1te909 Aug 5, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .devcontainer/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ ALLOWED_HOSTS = ['${API_HOST}', '*']
ADMIN_URL = 'admin/'

CORS_ORIGIN_ALLOW_ALL = True
CORS_ORIGIN_WHITELIST = ['https://${API_HOST}']

DATABASES = {
'default': {
Expand Down
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"python.analysis.diagnosticSeverityOverrides": {
"reportUnusedImport": "error",
"reportDuplicateImport": "error",
"reportGeneralTypeIssues": "none"
"reportGeneralTypeIssues": "none",
"reportOptionalMemberAccess": "none",
},
"python.analysis.typeCheckingMode": "basic",
"editor.bracketPairColorization.enabled": true,
Expand Down
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Tactical RMM is a remote monitoring & management tool, built with Django and Vue
It uses an [agent](https://github.com/amidaware/rmmagent) written in golang and integrates with [MeshCentral](https://github.com/Ylianst/MeshCentral)

# [LIVE DEMO](https://demo.tacticalrmm.com/)

Demo database resets every hour. A lot of features are disabled for obvious reasons due to the nature of this app.

### [Discord Chat](https://discord.gg/upGTkWp)
Expand All @@ -23,7 +24,7 @@ Demo database resets every hour. A lot of features are disabled for obvious reas
- Event log viewer
- Services management
- Windows patch management
- Automated checks with email/SMS alerting (cpu, disk, memory, services, scripts, event logs)
- Automated checks with email/SMS/Webhook alerting (cpu, disk, memory, services, scripts, event logs)
- Automated task runner (run scripts on a schedule)
- Remote software installation via chocolatey
- Software and hardware inventory
Expand All @@ -33,9 +34,11 @@ Demo database resets every hour. A lot of features are disabled for obvious reas
- Windows 7, 8.1, 10, 11, Server 2008R2, 2012R2, 2016, 2019, 2022

## Linux agent versions supported

- Any distro with systemd which includes but is not limited to: Debian (10, 11), Ubuntu x86_64 (18.04, 20.04, 22.04), Synology 7, centos, freepbx and more!

## Mac agent versions supported

- 64 bit Intel and Apple Silicon (M1, M2)

## Installation / Backup / Restore / Usage
Expand Down
2 changes: 1 addition & 1 deletion ansible/roles/trmm_dev/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@
tags: nginx
become: yes
ansible.builtin.apt_key:
url: https://nginx.org/packages/keys/nginx_signing.key
url: https://nginx.org/keys/nginx_signing.key
state: present

- name: add nginx repo
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Generated by Django 4.2.13 on 2024-06-28 20:21

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("accounts", "0036_remove_role_can_ping_agents"),
]

operations = [
migrations.AddField(
model_name="role",
name="can_run_server_scripts",
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name="role",
name="can_use_webterm",
field=models.BooleanField(default=False),
),
]
2 changes: 2 additions & 0 deletions api/tacticalrmm/accounts/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ class Role(BaseAuditModel):
can_run_urlactions = models.BooleanField(default=False)
can_view_customfields = models.BooleanField(default=False)
can_manage_customfields = models.BooleanField(default=False)
can_run_server_scripts = models.BooleanField(default=False)
can_use_webterm = models.BooleanField(default=False)

# checks
can_list_checks = models.BooleanField(default=False)
Expand Down
10 changes: 5 additions & 5 deletions api/tacticalrmm/accounts/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ def setUp(self):
self.bob.save()

def test_check_creds(self):
url = "/checkcreds/"
url = "/v2/checkcreds/"

data = {"username": "bob", "password": "hunter2"}
r = self.client.post(url, data, format="json")
self.assertEqual(r.status_code, 200)
self.assertIn("totp", r.data.keys())
self.assertEqual(r.data["totp"], "totp not set")
self.assertEqual(r.data["totp"], False)

data = {"username": "bob", "password": "a3asdsa2314"}
r = self.client.post(url, data, format="json")
Expand All @@ -40,7 +40,7 @@ def test_check_creds(self):
data = {"username": "bob", "password": "hunter2"}
r = self.client.post(url, data, format="json")
self.assertEqual(r.status_code, 200)
self.assertEqual(r.data, "ok")
self.assertEqual(r.data["totp"], True)

# test user set to block dashboard logins
self.bob.block_dashboard_login = True
Expand All @@ -50,7 +50,7 @@ def test_check_creds(self):

@patch("pyotp.TOTP.verify")
def test_login_view(self, mock_verify):
url = "/login/"
url = "/v2/login/"

mock_verify.return_value = True
data = {"username": "bob", "password": "hunter2", "twofactor": "123456"}
Expand Down Expand Up @@ -404,7 +404,7 @@ def test_post_totp_set(self):

r = self.client.post(url)
self.assertEqual(r.status_code, 200)
self.assertEqual(r.data, "totp token already set")
self.assertEqual(r.data, False)


class TestAPIAuthentication(TacticalTestCase):
Expand Down
87 changes: 86 additions & 1 deletion api/tacticalrmm/accounts/views.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import datetime

import pyotp
from django.conf import settings
from django.contrib.auth import login
Expand Down Expand Up @@ -26,7 +28,87 @@
)


class CheckCredsV2(KnoxLoginView):
permission_classes = (AllowAny,)

# restrict time on tokens issued by this view to 3 min
def get_token_ttl(self):
return datetime.timedelta(seconds=180)

def post(self, request, format=None):
# check credentials
serializer = AuthTokenSerializer(data=request.data)
if not serializer.is_valid():
AuditLog.audit_user_failed_login(
request.data["username"], debug_info={"ip": request._client_ip}
)
return notify_error("Bad credentials")

user = serializer.validated_data["user"]

if user.block_dashboard_login:
return notify_error("Bad credentials")

# if totp token not set modify response to notify frontend
if not user.totp_key:
login(request, user)
response = super().post(request, format=None)
response.data["totp"] = False
return response

return Response({"totp": True})


class LoginViewV2(KnoxLoginView):
permission_classes = (AllowAny,)

def post(self, request, format=None):
valid = False

serializer = AuthTokenSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.validated_data["user"]

if user.block_dashboard_login:
return notify_error("Bad credentials")

token = request.data["twofactor"]
totp = pyotp.TOTP(user.totp_key)

if settings.DEBUG and token == "sekret":
valid = True
elif getattr(settings, "DEMO", False):
valid = True
elif totp.verify(token, valid_window=10):
valid = True

if valid:
login(request, user)

# save ip information
ipw = IpWare()
client_ip, _ = ipw.get_client_ip(request.META)
if client_ip:
user.last_login_ip = str(client_ip)
user.save()

AuditLog.audit_user_login_successful(
request.data["username"], debug_info={"ip": request._client_ip}
)
response = super().post(request, format=None)
response.data["username"] = request.user.username
return Response(response.data)
else:
AuditLog.audit_user_failed_twofactor(
request.data["username"], debug_info={"ip": request._client_ip}
)
return notify_error("Bad credentials")


class CheckCreds(KnoxLoginView):
# TODO
# This view is deprecated as of 0.19.0
# Needed for the initial update to 0.19.0 so frontend code doesn't break on login
permission_classes = (AllowAny,)

def post(self, request, format=None):
Expand Down Expand Up @@ -54,6 +136,9 @@ def post(self, request, format=None):


class LoginView(KnoxLoginView):
# TODO
# This view is deprecated as of 0.19.0
# Needed for the initial update to 0.19.0 so frontend code doesn't break on login
permission_classes = (AllowAny,)

def post(self, request, format=None):
Expand Down Expand Up @@ -207,7 +292,7 @@ def post(self, request):
user.save(update_fields=["totp_key"])
return Response(TOTPSetupSerializer(user).data)

return Response("totp token already set")
return Response(False)


class UserUI(APIView):
Expand Down
31 changes: 20 additions & 11 deletions api/tacticalrmm/agents/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
PAAction,
PAStatus,
)
from tacticalrmm.helpers import setup_nats_options
from tacticalrmm.helpers import has_script_actions, has_webhook, setup_nats_options
from tacticalrmm.models import PermissionQuerySet

if TYPE_CHECKING:
Expand Down Expand Up @@ -135,7 +135,12 @@ def save(self, *args, **kwargs):
orig = Agent.objects.get(pk=self.pk)
mon_type_changed = self.monitoring_type != orig.monitoring_type
site_changed = self.site_id != orig.site_id
if mon_type_changed or site_changed:
policy_changed = self.policy != orig.policy
block_inherit = (
self.block_policy_inheritance != orig.block_policy_inheritance
)

if mon_type_changed or site_changed or policy_changed or block_inherit:
self._processing_set_alert_template = True
self.set_alert_template()
self._processing_set_alert_template = False
Expand Down Expand Up @@ -950,18 +955,22 @@ def delete_superseded_updates(self) -> None:
def should_create_alert(
self, alert_template: "Optional[AlertTemplate]" = None
) -> bool:
return bool(
has_agent_notification = (
self.overdue_dashboard_alert
or self.overdue_email_alert
or self.overdue_text_alert
or (
alert_template
and (
alert_template.agent_always_alert
or alert_template.agent_always_email
or alert_template.agent_always_text
)
)
)
has_alert_template_notification = alert_template and (
alert_template.agent_always_alert
or alert_template.agent_always_email
or alert_template.agent_always_text
)

return bool(
has_agent_notification
or has_alert_template_notification
or has_webhook(alert_template, "agent")
or has_script_actions(alert_template, "agent")
)

def send_outage_email(self) -> None:
Expand Down
2 changes: 1 addition & 1 deletion api/tacticalrmm/agents/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ def run_script_email_results_task(
return

CORE = get_core_settings()
subject = f"{agent.hostname} {script.name} Results"
subject = f"{agent.client.name}, {agent.site.name}, {agent.hostname} {script.name} Results"
exec_time = "{:.4f}".format(r["execution_time"])
body = (
subject
Expand Down
6 changes: 4 additions & 2 deletions api/tacticalrmm/agents/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -987,6 +987,8 @@ def bulk(request):
debug_info={"ip": request._client_ip},
)

ht = "Check the History tab on the agent to view the results."

if request.data["mode"] == "command":
if request.data["shell"] == "custom" and request.data["custom_shell"]:
shell = request.data["custom_shell"]
Expand All @@ -1001,7 +1003,7 @@ def bulk(request):
username=request.user.username[:50],
run_as_user=request.data["run_as_user"],
)
return Response(f"Command will now be run on {len(agents)} agents")
return Response(f"Command will now be run on {len(agents)} agents. {ht}")

elif request.data["mode"] == "script":
script = get_object_or_404(Script, pk=request.data["script"])
Expand All @@ -1016,7 +1018,7 @@ def bulk(request):
env_vars=request.data["env_vars"],
)

return Response(f"{script.name} will now be run on {len(agents)} agents")
return Response(f"{script.name} will now be run on {len(agents)} agents. {ht}")

elif request.data["mode"] == "patch":
if request.data["patchMode"] == "install":
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Generated by Django 4.2.13 on 2024-06-28 20:21

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
("core", "0045_coresettings_enable_server_scripts_and_more"),
("alerts", "0013_alerttemplate_action_env_vars_and_more"),
]

operations = [
migrations.AddField(
model_name="alerttemplate",
name="action_rest",
field=models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="url_action_alert_template",
to="core.urlaction",
),
),
migrations.AddField(
model_name="alerttemplate",
name="action_type",
field=models.CharField(
choices=[("script", "Script"), ("server", "Server"), ("rest", "Rest")],
default="script",
max_length=10,
),
),
migrations.AddField(
model_name="alerttemplate",
name="resolved_action_rest",
field=models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="resolved_url_action_alert_template",
to="core.urlaction",
),
),
migrations.AddField(
model_name="alerttemplate",
name="resolved_action_type",
field=models.CharField(
choices=[("script", "Script"), ("server", "Server"), ("rest", "Rest")],
default="script",
max_length=10,
),
),
]
Loading
Loading