194 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			194 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
import asyncio
 | 
						|
import subprocess
 | 
						|
 | 
						|
from django.conf import settings
 | 
						|
from django.shortcuts import get_object_or_404
 | 
						|
from django.http import HttpResponse
 | 
						|
from django.utils import timezone as djangotime
 | 
						|
from django.db.models import Q
 | 
						|
from django.core.paginator import Paginator
 | 
						|
from datetime import datetime as dt
 | 
						|
 | 
						|
from rest_framework.response import Response
 | 
						|
from rest_framework import status
 | 
						|
from rest_framework.decorators import api_view
 | 
						|
from rest_framework.views import APIView
 | 
						|
 | 
						|
from .models import PendingAction, AuditLog
 | 
						|
from agents.models import Agent
 | 
						|
from accounts.models import User
 | 
						|
from .serializers import PendingActionSerializer, AuditLogSerializer
 | 
						|
from agents.serializers import AgentHostnameSerializer
 | 
						|
from accounts.serializers import UserSerializer
 | 
						|
from tacticalrmm.utils import notify_error
 | 
						|
 | 
						|
 | 
						|
class GetAuditLogs(APIView):
 | 
						|
    def patch(self, request):
 | 
						|
        from clients.models import Client
 | 
						|
        from agents.models import Agent
 | 
						|
 | 
						|
        pagination = request.data["pagination"]
 | 
						|
 | 
						|
        order_by = (
 | 
						|
            f"-{pagination['sortBy']}"
 | 
						|
            if pagination["descending"]
 | 
						|
            else f"{pagination['sortBy']}"
 | 
						|
        )
 | 
						|
 | 
						|
        agentFilter = Q()
 | 
						|
        clientFilter = Q()
 | 
						|
        actionFilter = Q()
 | 
						|
        objectFilter = Q()
 | 
						|
        userFilter = Q()
 | 
						|
        timeFilter = Q()
 | 
						|
 | 
						|
        if "agentFilter" in request.data:
 | 
						|
            agentFilter = Q(agent__in=request.data["agentFilter"])
 | 
						|
 | 
						|
        elif "clientFilter" in request.data:
 | 
						|
            clients = Client.objects.filter(
 | 
						|
                pk__in=request.data["clientFilter"]
 | 
						|
            ).values_list("id")
 | 
						|
            agents = Agent.objects.filter(site__client_id__in=clients).values_list(
 | 
						|
                "hostname"
 | 
						|
            )
 | 
						|
            clientFilter = Q(agent__in=agents)
 | 
						|
 | 
						|
        if "userFilter" in request.data:
 | 
						|
            userFilter = Q(username__in=request.data["userFilter"])
 | 
						|
 | 
						|
        if "actionFilter" in request.data:
 | 
						|
            actionFilter = Q(action__in=request.data["actionFilter"])
 | 
						|
 | 
						|
        if "objectFilter" in request.data:
 | 
						|
            objectFilter = Q(object_type__in=request.data["objectFilter"])
 | 
						|
 | 
						|
        if "timeFilter" in request.data:
 | 
						|
            timeFilter = Q(
 | 
						|
                entry_time__lte=djangotime.make_aware(dt.today()),
 | 
						|
                entry_time__gt=djangotime.make_aware(dt.today())
 | 
						|
                - djangotime.timedelta(days=request.data["timeFilter"]),
 | 
						|
            )
 | 
						|
 | 
						|
        audit_logs = (
 | 
						|
            AuditLog.objects.filter(agentFilter | clientFilter)
 | 
						|
            .filter(userFilter)
 | 
						|
            .filter(actionFilter)
 | 
						|
            .filter(objectFilter)
 | 
						|
            .filter(timeFilter)
 | 
						|
        ).order_by(order_by)
 | 
						|
 | 
						|
        paginator = Paginator(audit_logs, pagination["rowsPerPage"])
 | 
						|
 | 
						|
        return Response(
 | 
						|
            {
 | 
						|
                "audit_logs": AuditLogSerializer(
 | 
						|
                    paginator.get_page(pagination["page"]), many=True
 | 
						|
                ).data,
 | 
						|
                "total": paginator.count,
 | 
						|
            }
 | 
						|
        )
 | 
						|
 | 
						|
 | 
						|
class FilterOptionsAuditLog(APIView):
 | 
						|
    def post(self, request):
 | 
						|
        if request.data["type"] == "agent":
 | 
						|
            agents = Agent.objects.filter(hostname__icontains=request.data["pattern"])
 | 
						|
            return Response(AgentHostnameSerializer(agents, many=True).data)
 | 
						|
 | 
						|
        if request.data["type"] == "user":
 | 
						|
            users = User.objects.filter(
 | 
						|
                username__icontains=request.data["pattern"], agent=None
 | 
						|
            )
 | 
						|
            return Response(UserSerializer(users, many=True).data)
 | 
						|
 | 
						|
        return Response("error", status=status.HTTP_400_BAD_REQUEST)
 | 
						|
 | 
						|
 | 
						|
@api_view()
 | 
						|
def agent_pending_actions(request, pk):
 | 
						|
    action = PendingAction.objects.filter(agent__pk=pk)
 | 
						|
    return Response(PendingActionSerializer(action, many=True).data)
 | 
						|
 | 
						|
 | 
						|
@api_view()
 | 
						|
def all_pending_actions(request):
 | 
						|
    actions = PendingAction.objects.all().select_related("agent")
 | 
						|
    return Response(PendingActionSerializer(actions, many=True).data)
 | 
						|
 | 
						|
 | 
						|
@api_view(["DELETE"])
 | 
						|
def cancel_pending_action(request):
 | 
						|
    action = get_object_or_404(PendingAction, pk=request.data["pk"])
 | 
						|
    if not action.agent.has_gotasks:
 | 
						|
        return notify_error("Requires agent version 1.1.1 or greater")
 | 
						|
 | 
						|
    nats_data = {
 | 
						|
        "func": "delschedtask",
 | 
						|
        "schedtaskpayload": {"name": action.details["taskname"]},
 | 
						|
    }
 | 
						|
    r = asyncio.run(action.agent.nats_cmd(nats_data, timeout=10))
 | 
						|
    if r != "ok":
 | 
						|
        return notify_error(r)
 | 
						|
 | 
						|
    action.delete()
 | 
						|
    return Response(f"{action.agent.hostname}: {action.description} was cancelled")
 | 
						|
 | 
						|
 | 
						|
@api_view()
 | 
						|
def debug_log(request, mode, hostname, order):
 | 
						|
    log_file = settings.LOG_CONFIG["handlers"][0]["sink"]
 | 
						|
 | 
						|
    agents = Agent.objects.all()
 | 
						|
    agent_hostnames = AgentHostnameSerializer(agents, many=True)
 | 
						|
 | 
						|
    switch_mode = {
 | 
						|
        "info": "INFO",
 | 
						|
        "critical": "CRITICAL",
 | 
						|
        "error": "ERROR",
 | 
						|
        "warning": "WARNING",
 | 
						|
    }
 | 
						|
    level = switch_mode.get(mode, "INFO")
 | 
						|
 | 
						|
    if hostname == "all" and order == "latest":
 | 
						|
        cmd = f"grep -h {level} {log_file} | tac"
 | 
						|
    elif hostname == "all" and order == "oldest":
 | 
						|
        cmd = f"grep -h {level} {log_file}"
 | 
						|
    elif hostname != "all" and order == "latest":
 | 
						|
        cmd = f"grep {hostname} {log_file} | grep -h {level} | tac"
 | 
						|
    elif hostname != "all" and order == "oldest":
 | 
						|
        cmd = f"grep {hostname} {log_file} | grep -h {level}"
 | 
						|
    else:
 | 
						|
        return Response("error", status=status.HTTP_400_BAD_REQUEST)
 | 
						|
 | 
						|
    contents = subprocess.run(
 | 
						|
        cmd,
 | 
						|
        stdout=subprocess.PIPE,
 | 
						|
        stderr=subprocess.PIPE,
 | 
						|
        universal_newlines=True,
 | 
						|
        shell=True,
 | 
						|
    )
 | 
						|
 | 
						|
    if not contents.stdout:
 | 
						|
        resp = f"No {mode} logs"
 | 
						|
    else:
 | 
						|
        resp = contents.stdout
 | 
						|
 | 
						|
    return Response({"log": resp, "agents": agent_hostnames.data})
 | 
						|
 | 
						|
 | 
						|
@api_view()
 | 
						|
def download_log(request):
 | 
						|
    log_file = settings.LOG_CONFIG["handlers"][0]["sink"]
 | 
						|
    if settings.DEBUG:
 | 
						|
        with open(log_file, "rb") as f:
 | 
						|
            response = HttpResponse(f.read(), content_type="text/plain")
 | 
						|
            response["Content-Disposition"] = "attachment; filename=debug.log"
 | 
						|
            return response
 | 
						|
    else:
 | 
						|
        response = HttpResponse()
 | 
						|
        response["Content-Disposition"] = "attachment; filename=debug.log"
 | 
						|
        response["X-Accel-Redirect"] = "/private/log/debug.log"
 | 
						|
        return response
 |