mirror of https://github.com/jumpserver/jumpserver
				
				
				
			
		
			
				
	
	
		
			143 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Python
		
	
	
			
		
		
	
	
			143 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Python
		
	
	
# -*- coding: utf-8 -*-
 | 
						||
#
 | 
						||
import os
 | 
						||
import tarfile
 | 
						||
 | 
						||
from django.views.generic import ListView, TemplateView, DetailView
 | 
						||
from django.views.generic.edit import SingleObjectMixin
 | 
						||
from django.utils.translation import ugettext as _
 | 
						||
from django.utils import timezone
 | 
						||
from django.utils.encoding import escape_uri_path
 | 
						||
from django.http import FileResponse, HttpResponse
 | 
						||
from django.core.files.storage import default_storage
 | 
						||
 | 
						||
from common.permissions import PermissionsMixin, IsOrgAdmin, IsOrgAuditor
 | 
						||
from common.utils import model_to_json
 | 
						||
from ..models import Session
 | 
						||
from ..backends import get_multi_command_storage
 | 
						||
from .. import utils
 | 
						||
 | 
						||
 | 
						||
__all__ = [
 | 
						||
    'SessionOnlineListView', 'SessionOfflineListView',
 | 
						||
    'SessionDetailView', 'SessionReplayDownloadView',
 | 
						||
    'SessionCommandsView',
 | 
						||
]
 | 
						||
 | 
						||
 | 
						||
class SessionListView(PermissionsMixin, TemplateView):
 | 
						||
    model = Session
 | 
						||
    template_name = 'terminal/session_list.html'
 | 
						||
    date_from = date_to = None
 | 
						||
    permission_classes = [IsOrgAdmin | IsOrgAuditor]
 | 
						||
    default_days_ago = 5
 | 
						||
 | 
						||
    def get_context_data(self, **kwargs):
 | 
						||
        now = timezone.now()
 | 
						||
        context = {
 | 
						||
            'date_from': now - timezone.timedelta(days=self.default_days_ago),
 | 
						||
            'date_to': now,
 | 
						||
        }
 | 
						||
        kwargs.update(context)
 | 
						||
        return super().get_context_data(**kwargs)
 | 
						||
 | 
						||
 | 
						||
class SessionOnlineListView(SessionListView):
 | 
						||
    def get_context_data(self, **kwargs):
 | 
						||
        context = {
 | 
						||
            'app': _('Sessions'),
 | 
						||
            'action': _('Session online list'),
 | 
						||
            'type': 'online',
 | 
						||
        }
 | 
						||
        kwargs.update(context)
 | 
						||
        return super().get_context_data(**kwargs)
 | 
						||
 | 
						||
 | 
						||
class SessionOfflineListView(SessionListView):
 | 
						||
    def get_context_data(self, **kwargs):
 | 
						||
        context = {
 | 
						||
            'app': _('Sessions'),
 | 
						||
            'action': _('Session offline'),
 | 
						||
            'type': 'offline',
 | 
						||
        }
 | 
						||
        kwargs.update(context)
 | 
						||
        return super().get_context_data(**kwargs)
 | 
						||
 | 
						||
 | 
						||
class SessionDetailView(PermissionsMixin, DetailView):
 | 
						||
    template_name = 'terminal/session_detail.html'
 | 
						||
    model = Session
 | 
						||
    permission_classes = [IsOrgAdmin | IsOrgAuditor]
 | 
						||
 | 
						||
    def get_context_data(self, **kwargs):
 | 
						||
        context = {
 | 
						||
            'app': _('Sessions'),
 | 
						||
            'action': _('Session detail'),
 | 
						||
        }
 | 
						||
        kwargs.update(context)
 | 
						||
        return super().get_context_data(**kwargs)
 | 
						||
 | 
						||
 | 
						||
class SessionCommandsView(SingleObjectMixin, PermissionsMixin, ListView):
 | 
						||
    template_name = 'terminal/session_commands.html'
 | 
						||
    model = Session
 | 
						||
    object = None
 | 
						||
    permission_classes = [IsOrgAdmin | IsOrgAuditor]
 | 
						||
 | 
						||
    def get(self, request, *args, **kwargs):
 | 
						||
        self.object = self.get_object(queryset=self.model.objects.all())
 | 
						||
        return super().get(request, *args, **kwargs)
 | 
						||
 | 
						||
    def get_queryset(self):
 | 
						||
        command_store = get_multi_command_storage()
 | 
						||
        return command_store.filter(session=self.object.id)
 | 
						||
 | 
						||
    def get_context_data(self, **kwargs):
 | 
						||
        context = {
 | 
						||
            'app': _('Sessions'),
 | 
						||
            'action': _('Session detail'),
 | 
						||
        }
 | 
						||
        kwargs.update(context)
 | 
						||
        return super().get_context_data(**kwargs)
 | 
						||
 | 
						||
 | 
						||
class SessionReplayDownloadView(PermissionsMixin, DetailView):
 | 
						||
    permission_classes = [IsOrgAdmin | IsOrgAuditor]
 | 
						||
    model = Session
 | 
						||
 | 
						||
    @staticmethod
 | 
						||
    def prepare_offline_file(session, local_path):
 | 
						||
        replay_path = default_storage.path(local_path)
 | 
						||
        current_dir = os.getcwd()
 | 
						||
        dir_path = os.path.dirname(replay_path)
 | 
						||
        replay_filename = os.path.basename(replay_path)
 | 
						||
        meta_filename = '{}.json'.format(session.id)
 | 
						||
        offline_filename = '{}.tar'.format(session.id)
 | 
						||
        os.chdir(dir_path)
 | 
						||
 | 
						||
        with open(meta_filename, 'wt') as f:
 | 
						||
            f.write(model_to_json(session))
 | 
						||
 | 
						||
        with tarfile.open(offline_filename, 'w') as f:
 | 
						||
            f.add(replay_filename)
 | 
						||
            f.add(meta_filename)
 | 
						||
        file = open(offline_filename, 'rb')
 | 
						||
        os.chdir(current_dir)
 | 
						||
        return file
 | 
						||
 | 
						||
    def get(self, request, *args, **kwargs):
 | 
						||
        session = self.get_object()
 | 
						||
        local_path, url = utils.get_session_replay_url(session)
 | 
						||
        if local_path is None:
 | 
						||
            error = url
 | 
						||
            return HttpResponse(error)
 | 
						||
        file = self.prepare_offline_file(session, local_path)
 | 
						||
        response = FileResponse(file)
 | 
						||
        response['Content-Type'] = 'application/octet-stream'
 | 
						||
        # 这里要注意哦,网上查到的方法都是response['Content-Disposition']='attachment;filename="filename.py"',
 | 
						||
        # 但是如果文件名是英文名没问题,如果文件名包含中文,下载下来的文件名会被改为url中的path。
 | 
						||
        filename = escape_uri_path('{}.tar'.format(session.id))
 | 
						||
        disposition = "attachment; filename*=UTF-8''{}".format(filename)
 | 
						||
        response["Content-Disposition"] = disposition
 | 
						||
        return response
 |