diff --git a/.gitignore b/.gitignore index ac2d768f8..89b6e1384 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,4 @@ tags jumpserver.iml .python-version tmp/* +sessions/* diff --git a/apps/applications/api.py b/apps/applications/api.py index 59696772c..1e2c38450 100644 --- a/apps/applications/api.py +++ b/apps/applications/api.py @@ -2,11 +2,15 @@ # from collections import OrderedDict import copy +import logging + +import os from rest_framework import viewsets, serializers from rest_framework.views import APIView, Response from rest_framework.permissions import AllowAny from django.shortcuts import get_object_or_404 from django.utils import timezone +from django.conf import settings from .models import Terminal, TerminalStatus, TerminalSession, TerminalTask from .serializers import TerminalSerializer, TerminalStatusSerializer, \ @@ -15,6 +19,8 @@ from .hands import IsSuperUserOrAppUser, IsAppUser, ProxyLog, \ IsSuperUserOrAppUserOrUserReadonly from common.utils import get_object_or_none +logger = logging.getLogger(__file__) + class TerminalViewSet(viewsets.ModelViewSet): queryset = Terminal.objects.filter(is_deleted=False) @@ -62,20 +68,28 @@ class TerminalStatusViewSet(viewsets.ModelViewSet): session_serializer_class = TerminalSessionSerializer def create(self, request, *args, **kwargs): + self.handle_sessions() + return super().create(request, *args, **kwargs) + + def handle_sessions(self): sessions_active = [] - for session_data in request.data.get("sessions", []): + for session_data in self.request.data.get("sessions", []): session_data["terminal"] = self.request.user.terminal.id _id = session_data["id"] session = get_object_or_none(TerminalSession, id=_id) if session: - serializer = TerminalSessionSerializer(data=session_data, instance=session) + serializer = TerminalSessionSerializer(data=session_data, + instance=session) else: serializer = TerminalSessionSerializer(data=session_data) if serializer.is_valid(): serializer.save() + else: + logger.error("session serializer is not valid {}".format( + serializer.errors)) - if session_data["is_finished"]: + if not session_data["is_finished"]: sessions_active.append(session_data["id"]) sessions_in_db_active = TerminalSession.objects.filter( @@ -83,13 +97,11 @@ class TerminalStatusViewSet(viewsets.ModelViewSet): ) for session in sessions_in_db_active: - if session.id not in sessions_active: + if str(session.id) not in sessions_active: session.is_finished = True session.date_end = timezone.now() session.save() - return super().create(request, *args, **kwargs) - def get_queryset(self): terminal_id = self.kwargs.get("terminal", None) if terminal_id: @@ -135,3 +147,29 @@ class TerminalTaskViewSet(viewsets.ModelViewSet): terminal = self.request.user.terminal self.queryset = terminal.terminalstatus_set.all() return self.queryset + + +class SessionReplayAPI(APIView): + permission_classes = (IsSuperUserOrAppUser,) + + def post(self, request, **kwargs): + session_id = kwargs.get("pk", None) + session = get_object_or_404(TerminalSession, id=session_id) + record_dir = settings.CONFIG.SESSION_RECORDE_DIR + date = session.date_start.strftime("%Y-%m-%d") + record_dir = os.path.join(record_dir, date) + record_filename = os.path.join(record_dir, str(session.id)) + + if not os.path.exists(record_dir): + os.makedirs(record_dir) + + archive_stream = request.data.get("archive") + if not archive_stream: + return Response("None file upload", status=400) + + with open(record_filename, 'wb') as f: + for chunk in archive_stream.chunks(): + f.write(chunk) + session.has_replay = True + session.save() + return Response({"session_id": session.id}, status=201) diff --git a/apps/applications/models.py b/apps/applications/models.py index 38e606498..adf3f1bbd 100644 --- a/apps/applications/models.py +++ b/apps/applications/models.py @@ -69,9 +69,6 @@ class TerminalStatus(models.Model): class Meta: db_table = 'terminal_status' - # def __str__(self): - # return "<{} status>".format(self.terminal.name) - class TerminalSession(models.Model): LOGIN_FROM_CHOICES = ( @@ -85,6 +82,8 @@ class TerminalSession(models.Model): system_user = models.CharField(max_length=128, verbose_name=_("System User")) login_from = models.CharField(max_length=2, choices=LOGIN_FROM_CHOICES, default="ST") is_finished = models.BooleanField(default=False) + has_replay = models.BooleanField(default=False, verbose_name=_("Replay")) + has_command = models.BooleanField(default=False, verbose_name=_("Command")) terminal = models.IntegerField(null=True, verbose_name=_("Terminal")) date_start = models.DateTimeField(verbose_name=_("Date Start")) date_end = models.DateTimeField(verbose_name=_("Date End"), null=True) diff --git a/apps/applications/serializers.py b/apps/applications/serializers.py index 6118ac62e..03667a369 100644 --- a/apps/applications/serializers.py +++ b/apps/applications/serializers.py @@ -19,11 +19,11 @@ class TerminalSerializer(serializers.ModelSerializer): @staticmethod def get_session_connected(obj): - return ProxyLog.objects.filter(terminal=obj.name, is_finished=False).count() + return TerminalSession.objects.filter(terminal=obj.id, is_finished=False) @staticmethod def get_is_alive(obj): - log = obj.terminalheatbeat_set.last() + log = obj.terminalstatus_set.last() if log and timezone.now() - log.date_created < timezone.timedelta(seconds=600): return True else: diff --git a/apps/applications/templates/applications/terminal_list.html b/apps/applications/templates/applications/terminal_list.html index bd3f72c0c..f85b2d5e7 100644 --- a/apps/applications/templates/applications/terminal_list.html +++ b/apps/applications/templates/applications/terminal_list.html @@ -79,7 +79,7 @@ $(document).ready(function(){ var reject_btn = '{% trans "Reject" %}' .replace('99991937', cellData) .replace('99991938', rowData.name); - var connect_btn = '{% trans "Connect" %} ' + var connect_btn = '{% trans "Connect" %} ' .replace('99991937', cellData); if (rowData.is_accepted) { {% if user.is_superuser %} @@ -96,7 +96,7 @@ $(document).ready(function(){ ], ajax_url: '{% url "api-applications:terminal-list" %}', columns: [{data: function(){return ""}}, {data: "name" }, {data: "remote_addr" }, {data: "ssh_port"}, {data: "http_port"}, - {data: "session_connected"}, {data: "is_alive" }, {data: 'is_alive'}, {data: "id"}], + {data: "session_connected"}, {data: "is_accepted" }, {data: 'is_alive'}, {data: "id"}], op_html: $('#actions').html() }; jumpserver.initDataTable(options); diff --git a/apps/applications/templates/applications/terminal_update.html b/apps/applications/templates/applications/terminal_update.html index d9621abaa..624dc6e7e 100644 --- a/apps/applications/templates/applications/terminal_update.html +++ b/apps/applications/templates/applications/terminal_update.html @@ -33,8 +33,8 @@