• 老广's avatar
    Dev beta (#3048) · 164f48e1
    老广 authored
    * [Update] 统一url地址
    
    * [Update] 修改api
    
    * [Update] 使用规范的签名
    
    * [Update] 修改url
    
    * [Update] 修改swagger
    
    * [Update] 添加serializer class避免报错
    
    * [Update] 修改token
    
    * [Update] 支持api key
    
    * [Update] 支持生成api key
    
    * [Update] 修改api重定向
    
    * [Update] 修改翻译
    
    * [Update] 添加说明文档
    
    * [Update] 修复浏览器关闭后session不失效的问题
    
    * [Update] 修改一些内容
    
    * [Update] 修改 jms脚本
    
    * [Update] 修改重定向
    
    * [Update] 修改搜索trim
    
    * [Update] 修改搜索trim
    
    * [Update] 添加sys log
    
    * [Bugfix] 修改登陆错误
    
    * [Update] 优化User操作private_token的接口 (#3091)
    
    * [Update] 优化User操作private_token的接口
    
    * [Update] 优化User操作private_token的接口 2
    
    * [Bugfix] 解决授权了一个节点,当移动节点后,被移动的节点下的资产会放到未分组节点下的问题
    
    * [Update] 升级jquery
    
    * [Update] 默认使用page
    
    * [Update] 修改使用Orgmodel view set
    
    * [Update] 支持 nv的硬盘 https://github.com/jumpserver/jumpserver/issues/1804
    
    * [UPdate] 解决命令执行宽度问题
    
    * [Update] 优化节点
    
    * [Update] 修改nodes过多时创建比较麻烦
    
    * [Update] 修改导入
    
    * [Update] 节点获取更新
    
    * [Update] 修改nodes
    
    * [Update] nodes显示full value
    
    * [Update] 统一使用nodes select2 函数
    
    * [Update] 修改磁盘大小小数
    
    * [Update] 修改 Node service
    
    * [Update] 优化授权节点
    
    * [Update] 修改 node permission
    
    * [Update] 修改asset permission
    
    * [Stash]
    
    * [Update] 修改node assets api
    
    * [Update] 修改tree service,支持资产数量
    
    * [Update] 修改暂时完成
    
    * [Update] 修改一些bug
    Unverified
    164f48e1
command.py 3.56 KB
# -*- coding: utf-8 -*-
#
import time
from django.utils import timezone
from django.shortcuts import HttpResponse
from rest_framework import viewsets
from rest_framework import generics
from rest_framework.response import Response
from django.template import loader


from common.permissions import IsOrgAdminOrAppUser, IsAuditor
from common.utils import get_logger
from ..backends import (
    get_command_storage, get_multi_command_storage,
    SessionCommandSerializer,
)

logger = get_logger(__name__)
__all__ = ['CommandViewSet', 'CommandExportApi']


class CommandQueryMixin:
    command_store = get_command_storage()
    permission_classes = [IsOrgAdminOrAppUser | IsAuditor]
    filter_fields = [
        "asset", "system_user", "user", "session",
    ]
    default_days_ago = 5

    def get_queryset(self):
        date_from, date_to = self.get_date_range()
        q = self.request.query_params
        multi_command_storage = get_multi_command_storage()
        queryset = multi_command_storage.filter(
            date_from=date_from, date_to=date_to, input=q.get("input"),
            user=q.get("user"), asset=q.get("asset"),
            system_user=q.get("system_user")
        )
        return queryset

    def filter_queryset(self, queryset):
        return queryset

    def get_filter_fields(self):
        fields = self.filter_fields
        fields.extend(["date_from", "date_to"])
        return fields

    def get_date_range(self):
        now = timezone.now()
        days_ago = now - timezone.timedelta(days=self.default_days_ago)
        default_start_st = days_ago.timestamp()
        default_end_st = now.timestamp()
        query_params = self.request.query_params
        date_from_st = query_params.get("date_from") or default_start_st
        date_to_st = query_params.get("date_to") or default_end_st
        return float(date_from_st), float(date_to_st)


class CommandViewSet(CommandQueryMixin, viewsets.ModelViewSet):
    """接受app发送来的command log, 格式如下
    {
        "user": "admin",
        "asset": "localhost",
        "system_user": "web",
        "session": "xxxxxx",
        "input": "whoami",
        "output": "d2hvbWFp",  # base64.b64encode(s)
        "timestamp": 1485238673.0
    }

    """
    command_store = get_command_storage()
    serializer_class = SessionCommandSerializer

    def create(self, request, *args, **kwargs):
        serializer = self.serializer_class(data=request.data, many=True)
        if serializer.is_valid():
            ok = self.command_store.bulk_save(serializer.validated_data)
            if ok:
                return Response("ok", status=201)
            else:
                return Response("Save error", status=500)
        else:
            msg = "Command not valid: {}".format(serializer.errors)
            logger.error(msg)
            return Response({"msg": msg}, status=401)


class CommandExportApi(CommandQueryMixin, generics.ListAPIView):
    serializer_class = SessionCommandSerializer

    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())

        template = 'terminal/command_report.html'
        context = {
            'queryset': queryset,
            'total_count': len(queryset),
            'now': time.time(),
        }
        content = loader.render_to_string(template, context, request)
        content_type = 'application/octet-stream'
        response = HttpResponse(content, content_type)
        filename = 'command-report-{}.html'.format(int(time.time()))
        response['Content-Disposition'] = 'attachment; filename="%s"' % filename
        return response