Compare commits

...

33 Commits

Author SHA1 Message Date
wh1te909
f82b589d03 Release 0.12.3 2022-04-11 23:16:28 +00:00
wh1te909
cddac4d0fb bump version 2022-04-11 22:21:57 +00:00
wh1te909
ff41bbd0e5 adjust celery config 2022-04-09 17:09:54 +00:00
wh1te909
4bdb6ae84e fix graphics 2022-04-09 17:09:09 +00:00
wh1te909
58fe14bd31 add coverage badge 2022-04-09 02:10:51 +00:00
wh1te909
97f362ed1e fix for multiprocessing 2022-04-09 01:26:04 +00:00
wh1te909
b63e87ecb6 add parallel 2022-04-09 01:01:32 +00:00
wh1te909
ac3550dfd7 add lcov 2022-04-09 00:48:00 +00:00
wh1te909
8278a4cfd9 remove run 2022-04-09 00:45:02 +00:00
wh1te909
f161a2bbc8 more coveralls 2022-04-09 00:43:47 +00:00
wh1te909
6a94489df0 testing coveralls 2022-04-09 00:26:22 +00:00
wh1te909
c3a0b9192f update reqs 2022-04-08 19:34:38 +00:00
wh1te909
69ff70a9ce typo [skip ci] 2022-04-08 18:49:15 +00:00
wh1te909
5284eb0af8 validate mesh username 2022-04-08 18:47:57 +00:00
wh1te909
58384ae136 update supported version 2022-04-08 18:45:53 +00:00
wh1te909
054cc78e65 add meshctrl 2022-04-08 18:30:17 +00:00
wh1te909
8c283281d6 remove lower() from mesh username 2022-04-08 16:06:44 +00:00
wh1te909
241fe41756 fix env 2022-04-05 22:44:41 +00:00
wh1te909
e50e0626fa also check env 2022-04-05 21:31:13 +00:00
wh1te909
c9135f1573 add option to specify sslmode for nats-api pg connection closes #1049 2022-04-05 21:14:22 +00:00
wh1te909
ec2663a152 Release 0.12.2 2022-04-05 03:44:17 +00:00
wh1te909
7567042c8a bump versions 2022-04-05 03:41:18 +00:00
wh1te909
c99ceb155f update CI badge and supported agent versions 2022-04-04 22:25:13 +00:00
wh1te909
f44c92f0d3 switch to gh actions for tests 2022-04-04 21:54:46 +00:00
wh1te909
492701ec62 change dir 2022-04-04 07:08:57 +00:00
wh1te909
a6d0acaa4d black 2022-04-03 23:14:44 +00:00
wh1te909
f84b4e7274 remove dev deps from pipelines 2022-04-03 23:09:08 +00:00
wh1te909
b7ef5b82d8 add silk to dev 2022-04-03 22:48:27 +00:00
wh1te909
a854d2c38c add authorization to NATS 2022-04-03 22:47:43 +00:00
wh1te909
5140499bbd update uwsgi conf 2022-04-01 06:12:19 +00:00
wh1te909
7183e9ee85 attempt 2 2022-03-31 06:07:23 +00:00
wh1te909
11885e0aca attemp 1 to fix pipelines 2022-03-31 05:54:30 +00:00
wh1te909
2bda4e822c move pipelines 2022-03-31 05:34:50 +00:00
30 changed files with 429 additions and 1028 deletions

66
.github/workflows/ci-tests.yml vendored Normal file
View File

@@ -0,0 +1,66 @@
name: Tests CI
on:
push:
branches:
- "*"
pull_request:
branches:
- "*"
jobs:
test:
runs-on: self-hosted
steps:
- uses: actions/checkout@v2
- name: Setup virtual env and install requirements
run: |
sudo -u postgres psql -c 'DROP DATABASE IF EXISTS pipeline'
sudo -u postgres psql -c 'DROP DATABASE IF EXISTS test_pipeline'
sudo -u postgres psql -c 'CREATE DATABASE pipeline'
sudo -u postgres psql -c "SET client_encoding = 'UTF8'" pipeline
pwd
rm -rf /actions-runner/_work/trmm-actions/trmm-actions/api/env
cd api
python3.10 -m venv env
source env/bin/activate
cd tacticalrmm
python --version
SETTINGS_FILE="tacticalrmm/settings.py"
SETUPTOOLS_VER=$(grep "^SETUPTOOLS_VER" "$SETTINGS_FILE" | awk -F'[= "]' '{print $5}')
WHEEL_VER=$(grep "^WHEEL_VER" "$SETTINGS_FILE" | awk -F'[= "]' '{print $5}')
pip install --upgrade pip
pip install setuptools==${SETUPTOOLS_VER} wheel==${WHEEL_VER}
pip install -r requirements.txt -r requirements-test.txt
- name: Run django tests
env:
GHACTIONS: "yes"
run: |
cd api/tacticalrmm
source ../env/bin/activate
rm -f .coverage coverage.lcov
coverage run --concurrency=multiprocessing manage.py test -v 2 --parallel
coverage combine
coverage lcov
if [ $? -ne 0 ]; then
exit 1
fi
- name: Codestyle black
run: |
cd api
source env/bin/activate
black --exclude migrations/ --check tacticalrmm
if [ $? -ne 0 ]; then
exit 1
fi
- name: Coveralls
uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
path-to-lcov: ./api/tacticalrmm/coverage.lcov
base-path: ./api/tacticalrmm

1
.gitignore vendored
View File

@@ -51,3 +51,4 @@ reset_db.sh
run_go_cmd.py
nats-api.conf
ignore/
coverage.lcov

View File

@@ -1,7 +1,7 @@
# Tactical RMM
[![Build Status](https://dev.azure.com/dcparsi/Tactical%20RMM/_apis/build/status/wh1te909.tacticalrmm?branchName=develop)](https://dev.azure.com/dcparsi/Tactical%20RMM/_build/latest?definitionId=4&branchName=develop)
[![Coverage Status](https://coveralls.io/repos/github/wh1te909/tacticalrmm/badge.png?branch=develop&kill_cache=1)](https://coveralls.io/github/wh1te909/tacticalrmm?branch=develop)
![CI Tests](https://github.com/amidaware/tacticalrmm/actions/workflows/ci-tests.yml/badge.svg?branch=develop)
[![Coverage Status](https://coveralls.io/repos/github/amidaware/tacticalrmm/badge.svg?branch=develop)](https://coveralls.io/github/amidaware/tacticalrmm?branch=develop)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/python/black)
Tactical RMM is a remote monitoring & management tool, built with Django and Vue.\
@@ -28,9 +28,12 @@ Demo database resets every hour. A lot of features are disabled for obvious reas
- Remote software installation via chocolatey
- Software and hardware inventory
## Windows versions supported
## Windows agent versions supported
- Windows 7, 8.1, 10, Server 2008R2, 2012R2, 2016, 2019
- Windows 7, 8.1, 10, 11, Server 2008R2, 2012R2, 2016, 2019, 2022
## Linux agent versions supported
- Any distro with systemd
## Installation / Backup / Restore / Usage

View File

@@ -4,8 +4,8 @@
| Version | Supported |
| ------- | ------------------ |
| 0.12.0 | :white_check_mark: |
| < 0.12.0 | :x: |
| 0.12.2 | :white_check_mark: |
| < 0.12.2 | :x: |
## Reporting a Vulnerability

View File

@@ -1,7 +1,5 @@
import asyncio
import base64
import re
import time
from collections import Counter
from distutils.version import LooseVersion
from typing import Any
@@ -11,10 +9,6 @@ import nats
import validators
from asgiref.sync import sync_to_async
from core.models import TZ_CHOICES, CoreSettings
from Crypto.Cipher import AES
from Crypto.Hash import SHA3_384
from Crypto.Random import get_random_bytes
from Crypto.Util.Padding import pad
from django.conf import settings
from django.contrib.postgres.fields import ArrayField
from django.db import models
@@ -219,7 +213,8 @@ class Agent(BaseAuditModel):
try:
if not self.wmi_detail["gpus"]:
return "No graphics cards"
return self.wmi_detail["gpus"]
return ", ".join(self.wmi_detail["gpus"])
except:
return "Error getting graphics cards"
@@ -613,30 +608,6 @@ class Agent(BaseAuditModel):
# Generate tasks based on policies
Policy.generate_policy_tasks(self)
# https://github.com/Ylianst/MeshCentral/issues/59#issuecomment-521965347
def get_login_token(self, key, user, action=3):
try:
key = bytes.fromhex(key)
key1 = key[0:48]
key2 = key[48:]
msg = '{{"a":{}, "u":"{}","time":{}}}'.format(
action, user.lower(), int(time.time())
)
iv = get_random_bytes(16)
# sha
h = SHA3_384.new()
h.update(key1)
hashed_msg = h.digest() + msg.encode()
# aes
cipher = AES.new(key2, AES.MODE_CBC, iv)
msg = cipher.encrypt(pad(hashed_msg, 16))
return base64.b64encode(iv + msg, altchars=b"@$").decode("utf-8")
except Exception:
return "err"
def _do_nats_debug(self, agent, message):
DebugLog.error(agent=agent, log_type="agent_issues", message=message)

View File

@@ -519,7 +519,7 @@ class TestAgentViews(TacticalTestCase):
self.check_not_authenticated("post", url)
@patch("agents.models.Agent.get_login_token")
@patch("meshctrl.utils.get_auth_token")
def test_meshcentral_tabs(self, mock_token):
url = f"{base_url}/{self.agent.agent_id}/meshcentral/"
mock_token.return_value = "askjh1k238uasdhk487234jadhsajksdhasd"
@@ -547,10 +547,6 @@ class TestAgentViews(TacticalTestCase):
self.assertEqual(r.status_code, 200)
mock_token.return_value = "err"
r = self.client.get(url)
self.assertEqual(r.status_code, 400)
self.check_not_authenticated("get", url)
@patch("agents.models.Agent.nats_cmd")

View File

@@ -4,6 +4,7 @@ import os
import random
import string
import time
from meshctrl.utils import get_auth_token
from core.models import CodeSignToken, CoreSettings
from core.utils import get_mesh_ws_url, remove_mesh_agent, send_command_with_mesh
@@ -208,13 +209,7 @@ class AgentMeshCentral(APIView):
agent = get_object_or_404(Agent, agent_id=agent_id)
core = CoreSettings.objects.first()
token = agent.get_login_token(
key=core.mesh_token,
user=f"user//{core.mesh_username.lower()}", # type:ignore
)
if token == "err":
return notify_error("Invalid mesh token")
token = get_auth_token(user=core.mesh_username, key=core.mesh_token)
control = f"{core.mesh_site}/?login={token}&gotonode={agent.mesh_node_id}&viewmode=11&hide=31" # type:ignore
terminal = f"{core.mesh_site}/?login={token}&gotonode={agent.mesh_node_id}&viewmode=12&hide=31" # type:ignore

View File

@@ -1,9 +1,10 @@
import asyncio
from meshctrl.utils import get_auth_token
from django.core.management.base import BaseCommand
from core.models import CoreSettings
from core.utils import get_auth_token, get_mesh_device_id, get_mesh_ws_url
from core.utils import get_mesh_device_id, get_mesh_ws_url
class Command(BaseCommand):

View File

@@ -12,6 +12,13 @@ class Command(BaseCommand):
self.stdout.write("Creating configuration for nats-api...")
db = settings.DATABASES["default"]
if hasattr(settings, "DB_SSL"):
ssl = settings.DB_SSL
elif "DB_SSL" in os.environ:
ssl = os.getenv("DB_SSL")
else:
ssl = "disable"
config = {
"key": settings.SECRET_KEY,
"natsurl": f"tls://{settings.ALLOWED_HOSTS[0]}:4222",
@@ -20,6 +27,7 @@ class Command(BaseCommand):
"host": db["HOST"],
"port": int(db["PORT"]),
"dbname": db["NAME"],
"sslmode": ssl,
}
conf = os.path.join(settings.BASE_DIR, "nats-api.conf")
with open(conf, "w") as f:

View File

@@ -45,9 +45,9 @@ class Command(BaseCommand):
# Check for Mesh Username
if (
not mesh_settings.mesh_username
or settings.MESH_USERNAME != mesh_settings.mesh_username
or settings.MESH_USERNAME.lower() != mesh_settings.mesh_username
):
mesh_settings.mesh_username = settings.MESH_USERNAME
mesh_settings.mesh_username = settings.MESH_USERNAME.lower()
# Check for Mesh Site
if (

View File

@@ -97,7 +97,7 @@ class CoreSettings(BaseAuditModel):
if not self.pk:
try:
self.mesh_site = settings.MESH_SITE
self.mesh_username = settings.MESH_USERNAME
self.mesh_username = settings.MESH_USERNAME.lower()
self.mesh_token = settings.MESH_TOKEN_KEY
except:
pass

View File

@@ -1,30 +1,14 @@
import json
import tempfile
import time
from base64 import b64encode
from meshctrl.utils import get_auth_token
import requests
import websockets
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
from django.conf import settings
from django.http import FileResponse
def get_auth_token(user, key):
key = bytes.fromhex(key)
key1 = key[0:32]
msg = '{{"userid":"{}", "domainid":"{}", "time":{}}}'.format(
f"user//{user}", "", int(time.time())
)
iv = get_random_bytes(12)
a = AES.new(key1, AES.MODE_GCM, iv)
msg, tag = a.encrypt_and_digest(bytes(msg, "utf-8")) # type: ignore
return b64encode(iv + tag + msg, altchars=b"@$").decode("utf-8")
def get_mesh_ws_url() -> str:
from core.models import CoreSettings

View File

@@ -3,3 +3,4 @@ Werkzeug
django-extensions
isort
types-pytz
django-silk

View File

@@ -1,3 +1,5 @@
coverage==6.3.2
coveralls==3.3.1
model_bakery
coverage
coveralls
model_bakery
black
tblib

View File

@@ -1,5 +1,5 @@
asgiref==3.5.0
celery==5.2.3
celery==5.2.6
certifi==2021.10.8
cffi==1.15.0
channels==3.0.4
@@ -14,8 +14,7 @@ django-rest-knox==4.2.0
djangorestframework==3.13.1
future==0.18.2
msgpack==1.0.3
nats-py==2.0.0
packaging==21.3
nats-py==2.1.0
psycopg2-binary==2.9.3
pycparser==2.21
pycryptodome==3.14.1
@@ -23,15 +22,16 @@ pyotp==2.6.0
pyparsing==3.0.7
pytz==2022.1
qrcode==7.3.1
redis==4.1.4
redis==4.2.2
requests==2.27.1
six==1.16.0
sqlparse==0.4.2
twilio==7.8.0
twilio==7.8.1
urllib3==1.26.9
uWSGI==2.0.20
validators==0.18.2
vine==5.0.0
websockets==10.2
zipp==3.7.0
drf_spectacular==0.21.2
zipp==3.8.0
drf_spectacular==0.21.2
meshctrl==0.1.13

View File

@@ -17,22 +17,22 @@ LINUX_AGENT_SCRIPT = BASE_DIR / "core" / "agent_linux.sh"
AUTH_USER_MODEL = "accounts.User"
# latest release
TRMM_VERSION = "0.12.1"
TRMM_VERSION = "0.12.3"
# bump this version everytime vue code is changed
# to alert user they need to manually refresh their browser
APP_VER = "0.0.159"
APP_VER = "0.0.160"
# https://github.com/amidaware/rmmagent
LATEST_AGENT_VER = "2.0.1"
LATEST_AGENT_VER = "2.0.2"
MESH_VER = "0.9.98"
MESH_VER = "1.0.2"
NATS_SERVER_VER = "2.7.4"
# for the update script, bump when need to recreate venv or npm install
PIP_VER = "27"
NPM_VER = "30"
PIP_VER = "28"
NPM_VER = "31"
SETUPTOOLS_VER = "59.6.0"
WHEEL_VER = "0.37.1"
@@ -52,6 +52,29 @@ REST_KNOX = {
"MIN_REFRESH_INTERVAL": 600,
}
if "GHACTIONS" in os.environ:
print("-----------------------PIPELINE----------------------------")
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": "pipeline",
"USER": "pipeline",
"PASSWORD": "pipeline123456",
"HOST": "127.0.0.1",
"PORT": "",
}
}
SECRET_KEY = "abcdefghijklmnoptravis123456789"
DEBUG = False
ALLOWED_HOSTS = ["api.example.com"]
ADMIN_URL = "abc123456/"
CORS_ORIGIN_WHITELIST = ["https://rmm.example.com"]
MESH_USERNAME = "pipeline"
MESH_SITE = "https://example.com"
MESH_TOKEN_KEY = "bd65e957a1e70c622d32523f61508400d6cd0937001a7ac12042227eba0b9ed625233851a316d4f489f02994145f74537a331415d00047dbbf13d940f556806dffe7a8ce1de216dc49edbad0c1a7399c"
REDIS_HOST = "localhost"
ADMIN_ENABLED = False
try:
from .local_settings import *
except ImportError:
@@ -74,11 +97,34 @@ SPECTACULAR_SETTINGS = {
"AUTHENTICATION_WHITELIST": ["tacticalrmm.auth.APIAuthentication"],
}
if not "AZPIPELINE" in os.environ:
if not DEBUG: # type: ignore
REST_FRAMEWORK.update(
{"DEFAULT_RENDERER_CLASSES": ("rest_framework.renderers.JSONRenderer",)}
)
if not DEBUG: # type: ignore
REST_FRAMEWORK.update(
{"DEFAULT_RENDERER_CLASSES": ("rest_framework.renderers.JSONRenderer",)}
)
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"corsheaders.middleware.CorsMiddleware", ##
"tacticalrmm.middleware.LogIPMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"tacticalrmm.middleware.AuditMiddleware",
"tacticalrmm.middleware.LinuxMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]
if ADMIN_ENABLED: # type: ignore
MIDDLEWARE += ("django.contrib.messages.middleware.MessageMiddleware",)
try:
if DEMO: # type: ignore
MIDDLEWARE += ("tacticalrmm.middleware.DemoMiddleware",)
except:
pass
INSTALLED_APPS = [
"django.contrib.auth",
@@ -107,21 +153,23 @@ INSTALLED_APPS = [
"drf_spectacular",
]
if not "AZPIPELINE" in os.environ:
if DEBUG: # type: ignore
INSTALLED_APPS += ("django_extensions",)
CHANNEL_LAYERS = {
"default": {
"BACKEND": "channels_redis.core.RedisChannelLayer",
"CONFIG": {
"hosts": [(REDIS_HOST, 6379)], # type: ignore
},
if DEBUG: # type: ignore
INSTALLED_APPS += (
"django_extensions",
"silk",
)
MIDDLEWARE.insert(0, "silk.middleware.SilkyMiddleware")
CHANNEL_LAYERS = {
"default": {
"BACKEND": "channels_redis.core.RedisChannelLayer",
"CONFIG": {
"hosts": [(REDIS_HOST, 6379)], # type: ignore
},
}
if "AZPIPELINE" in os.environ:
ADMIN_ENABLED = False
},
}
if ADMIN_ENABLED: # type: ignore
INSTALLED_APPS += (
@@ -130,28 +178,6 @@ if ADMIN_ENABLED: # type: ignore
)
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"corsheaders.middleware.CorsMiddleware", ##
"tacticalrmm.middleware.LogIPMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"tacticalrmm.middleware.AuditMiddleware",
"tacticalrmm.middleware.LinuxMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]
if ADMIN_ENABLED: # type: ignore
MIDDLEWARE += ("django.contrib.messages.middleware.MessageMiddleware",)
try:
if DEMO: # type: ignore
MIDDLEWARE += ("tacticalrmm.middleware.DemoMiddleware",)
except:
pass
ROOT_URLCONF = "tacticalrmm.urls"
@@ -226,38 +252,3 @@ LOGGING = {
"django.request": {"handlers": ["file"], "level": "ERROR", "propagate": True}
},
}
if "AZPIPELINE" in os.environ:
print("PIPELINE")
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": "pipeline",
"USER": "pipeline",
"PASSWORD": "pipeline123456",
"HOST": "127.0.0.1",
"PORT": "",
}
}
REST_FRAMEWORK = {
"DATETIME_FORMAT": "%b-%d-%Y - %H:%M",
"DEFAULT_PERMISSION_CLASSES": ("rest_framework.permissions.IsAuthenticated",),
"DEFAULT_AUTHENTICATION_CLASSES": (
"knox.auth.TokenAuthentication",
"tacticalrmm.auth.APIAuthentication",
),
"DEFAULT_RENDERER_CLASSES": ("rest_framework.renderers.JSONRenderer",),
}
ALLOWED_HOSTS = ["api.example.com"]
DEBUG = True
SECRET_KEY = "abcdefghijklmnoptravis123456789"
ADMIN_URL = "abc123456/"
SCRIPTS_DIR = os.path.join(Path(BASE_DIR).parents[1], "scripts")
MESH_USERNAME = "pipeline"
MESH_SITE = "https://example.com"
MESH_TOKEN_KEY = "bd65e957a1e70c622d32523f61508400d6cd0937001a7ac12042227eba0b9ed625233851a316d4f489f02994145f74537a331415d00047dbbf13d940f556806dffe7a8ce1de216dc49edbad0c1a7399c"
REDIS_HOST = "localhost"

View File

@@ -43,6 +43,9 @@ if getattr(settings, "ADMIN_ENABLED", False):
urlpatterns += (path(settings.ADMIN_URL, admin.site.urls),)
if getattr(settings, "DEBUG", False):
urlpatterns += [path("silk/", include("silk.urls", namespace="silk"))]
if getattr(settings, "SWAGGER_ENABLED", False):
from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView

View File

@@ -161,14 +161,28 @@ def convert_to_iso_duration(string: str) -> str:
def reload_nats():
users = [{"user": "tacticalrmm", "password": settings.SECRET_KEY}]
users = [
{
"user": "tacticalrmm",
"password": settings.SECRET_KEY,
"permissions": {"publish": ">", "subscribe": ">"},
}
]
agents = Agent.objects.prefetch_related("user").only(
"pk", "agent_id"
) # type:ignore
for agent in agents:
try:
users.append(
{"user": agent.agent_id, "password": agent.user.auth_token.key}
{
"user": agent.agent_id,
"password": agent.user.auth_token.key,
"permissions": {
"publish": {"allow": agent.agent_id},
"subscribe": {"allow": agent.agent_id},
"allow_responses": True,
},
}
)
except:
DebugLog.critical(

View File

@@ -1,65 +0,0 @@
trigger:
- master
- develop
jobs:
- job: setup_env
displayName: "Setup"
strategy:
matrix:
Debian10:
AGENT_NAME: "az-pipeline-fran"
pool:
name: linux-vms
demands:
- agent.name -equals $(AGENT_NAME)
steps:
- script: |
sudo -u postgres psql -c 'DROP DATABASE IF EXISTS pipeline'
sudo -u postgres psql -c 'DROP DATABASE IF EXISTS test_pipeline'
sudo -u postgres psql -c 'CREATE DATABASE pipeline'
sudo -u postgres psql -c "SET client_encoding = 'UTF8'" pipeline
SETTINGS_FILE="/myagent/_work/1/s/api/tacticalrmm/tacticalrmm/settings.py"
rm -rf /myagent/_work/1/s/api/env
cd /myagent/_work/1/s/api
python3.10 -m venv env
source env/bin/activate
cd /myagent/_work/1/s/api/tacticalrmm
pip install --trusted-host pypi.org --trusted-host pypi.python.org --trusted-host files.pythonhosted.org --upgrade pip
SETUPTOOLS_VER=$(grep "^SETUPTOOLS_VER" "$SETTINGS_FILE" | awk -F'[= "]' '{print $5}')
WHEEL_VER=$(grep "^WHEEL_VER" "$SETTINGS_FILE" | awk -F'[= "]' '{print $5}')
pip install --trusted-host pypi.org --trusted-host pypi.python.org --trusted-host files.pythonhosted.org setuptools==${SETUPTOOLS_VER} wheel==${WHEEL_VER}
pip install --trusted-host pypi.org --trusted-host pypi.python.org --trusted-host files.pythonhosted.org -r requirements.txt -r requirements-test.txt -r requirements-dev.txt
displayName: "Install Python Dependencies"
- script: |
cd /myagent/_work/1/s/api
source env/bin/activate
cd /myagent/_work/1/s/api/tacticalrmm
coverage run manage.py test -v 2
if [ $? -ne 0 ]; then
exit 1
fi
displayName: "Run django tests"
- script: |
cd /myagent/_work/1/s/api
source env/bin/activate
black --exclude migrations/ --check tacticalrmm
if [ $? -ne 0 ]; then
exit 1
fi
displayName: "Codestyle black"
- script: |
cd /myagent/_work/1/s/api
source env/bin/activate
cd /myagent/_work/1/s/api/tacticalrmm
export CIRCLE_BRANCH=$BUILD_SOURCEBRANCH
coveralls
displayName: "coveralls"
env:
CIRCLECI: 1
CIRCLE_BUILD_NUM: $(Build.BuildNumber)

View File

@@ -129,11 +129,13 @@ processes = ${uwsgiprocs}
threads = ${uwsgiprocs}
enable-threads = true
socket = 0.0.0.0:8080
harakiri = 300
chmod-socket = 660
buffer-size = 65535
vacuum = true
die-on-term = true
max-requests = 2000
max-requests = 500
disable-logging = true
EOF
)"

View File

@@ -1,6 +1,6 @@
#!/bin/bash
SCRIPT_VERSION="59"
SCRIPT_VERSION="61"
SCRIPT_URL='https://raw.githubusercontent.com/amidaware/tacticalrmm/master/install.sh'
sudo apt install -y curl wget dirmngr gnupg lsb-release
@@ -406,6 +406,7 @@ buffer-size = 65535
vacuum = true
die-on-term = true
max-requests = 500
disable-logging = true
EOF
)"
echo "${uwsgini}" > /rmm/api/tacticalrmm/app.ini
@@ -657,7 +658,7 @@ CELERY_APP="tacticalrmm"
CELERYD_MULTI="multi"
CELERYD_OPTS="--time-limit=86400 --autoscale=50,3"
CELERYD_OPTS="--time-limit=86400 --autoscale=20,2"
CELERYD_PID_FILE="/rmm/api/tacticalrmm/%n.pid"
CELERYD_LOG_FILE="/var/log/celery/%n%I.log"

View File

@@ -11,7 +11,7 @@ import (
)
var (
version = "3.0.1"
version = "3.0.2"
log = logrus.New()
)

Binary file not shown.

View File

@@ -13,4 +13,5 @@ type DjangoConfig struct {
Host string `json:"host"`
Port int `json:"port"`
DBName string `json:"dbname"`
SSLMode string `json:"sslmode"`
}

View File

@@ -41,8 +41,8 @@ func GetConfig(cfg string) (db *sqlx.DB, r DjangoConfig, err error) {
}
psqlInfo := fmt.Sprintf("host=%s port=%d user=%s "+
"password=%s dbname=%s sslmode=disable",
r.Host, r.Port, r.User, r.Pass, r.DBName)
"password=%s dbname=%s sslmode=%s",
r.Host, r.Port, r.User, r.Pass, r.DBName, r.SSLMode)
db, err = sqlx.Connect("postgres", psqlInfo)
if err != nil {

View File

@@ -1,6 +1,6 @@
#!/bin/bash
SCRIPT_VERSION="34"
SCRIPT_VERSION="35"
SCRIPT_URL='https://raw.githubusercontent.com/amidaware/tacticalrmm/master/restore.sh'
sudo apt update
@@ -276,6 +276,7 @@ buffer-size = 65535
vacuum = true
die-on-term = true
max-requests = 500
disable-logging = true
EOF
)"
echo "${uwsgini}" > /rmm/api/tacticalrmm/app.ini

View File

@@ -1,6 +1,6 @@
#!/bin/bash
SCRIPT_VERSION="131"
SCRIPT_VERSION="133"
SCRIPT_URL='https://raw.githubusercontent.com/amidaware/tacticalrmm/master/update.sh'
LATEST_SETTINGS_URL='https://raw.githubusercontent.com/amidaware/tacticalrmm/master/api/tacticalrmm/tacticalrmm/settings.py'
YELLOW='\033[1;33m'
@@ -144,6 +144,7 @@ buffer-size = 65535
vacuum = true
die-on-term = true
max-requests = 500
disable-logging = true
EOF
)"
echo "${uwsgini}" > /rmm/api/tacticalrmm/app.ini
@@ -257,6 +258,11 @@ sudo chown ${USER}:${USER} -R /etc/conf.d/
sudo chown ${USER}:${USER} -R /etc/letsencrypt
sudo chmod 775 -R /etc/letsencrypt
CHECK_CELERY_CONFIG=$(grep "autoscale=20,2" /etc/conf.d/celery.conf)
if ! [[ $CHECK_CELERY_CONFIG ]]; then
sed -i 's/CELERYD_OPTS=.*/CELERYD_OPTS="--time-limit=86400 --autoscale=20,2"/g' /etc/conf.d/celery.conf
fi
CHECK_ADMIN_ENABLED=$(grep ADMIN_ENABLED /rmm/api/tacticalrmm/tacticalrmm/local_settings.py)
if ! [[ $CHECK_ADMIN_ENABLED ]]; then
adminenabled="$(cat << EOF

987
web/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -10,12 +10,12 @@
"test:e2e:ci": "cross-env E2E_TEST=true start-test \"quasar dev\" http-get://localhost:8080 \"cypress run\""
},
"dependencies": {
"@quasar/extras": "^1.13.3",
"@quasar/extras": "^1.13.5",
"apexcharts": "^3.33.2",
"axios": "^0.26.1",
"dotenv": "^16.0.0",
"qrcode.vue": "^3.3.3",
"quasar": "^2.6.1",
"quasar": "^2.6.6",
"vue": "^3.2.31",
"vue3-ace-editor": "^2.2.2",
"vue3-apexcharts": "^1.4.1",
@@ -23,7 +23,7 @@
"vuex": "^4.0.2"
},
"devDependencies": {
"@quasar/app-webpack": "^3.4.5",
"@quasar/app-webpack": "^3.5.0",
"@quasar/cli": "^1.3.2"
},
"browserslist": [

View File

@@ -304,7 +304,15 @@
<q-card-section class="row">
<div class="col-4">Username:</div>
<div class="col-2"></div>
<q-input dense outlined v-model="settings.mesh_username" class="col-6" />
<q-input
dense
outlined
v-model="settings.mesh_username"
class="col-6"
:rules="[
val => (val == val.toLowerCase() && val != val.toUpperCase()) || 'Username must be all lowercase',
]"
/>
</q-card-section>
<q-card-section class="row">
<div class="col-4">Mesh Site:</div>