You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
jumpserver/apps/terminal/views/session.py

143 lines
4.7 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# -*- 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