mirror of https://github.com/jumpserver/jumpserver
[Update] 更新index view
parent
71a3079221
commit
a5f9735906
|
@ -1 +0,0 @@
|
||||||
|
|
|
@ -1,92 +0,0 @@
|
||||||
# ~*~ coding: utf-8 ~*~
|
|
||||||
#
|
|
||||||
|
|
||||||
|
|
||||||
from __future__ import absolute_import, unicode_literals
|
|
||||||
|
|
||||||
from rest_framework import generics, viewsets
|
|
||||||
from rest_framework_bulk import BulkModelViewSet
|
|
||||||
|
|
||||||
from audits.backends import command_store, record_store
|
|
||||||
from audits.backends.command.serializers import CommandLogSerializer
|
|
||||||
from audits.backends.record.serializers import RecordSerializer
|
|
||||||
from . import models, serializers
|
|
||||||
from .hands import IsSuperUserOrAppUser, IsAppUser
|
|
||||||
|
|
||||||
|
|
||||||
class ProxyLogReceiveView(generics.CreateAPIView):
|
|
||||||
queryset = models.ProxyLog.objects.all()
|
|
||||||
serializer_class = serializers.ProxyLogSerializer
|
|
||||||
permission_classes = (IsAppUser,)
|
|
||||||
|
|
||||||
def get_serializer(self, *args, **kwargs):
|
|
||||||
kwargs['data']['terminal'] = self.request.user.terminal.name
|
|
||||||
return super(ProxyLogReceiveView, self).get_serializer(*args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class ProxyLogViewSet(viewsets.ModelViewSet):
|
|
||||||
"""User proxy to backend server need call this api.
|
|
||||||
|
|
||||||
params: {
|
|
||||||
"username": "",
|
|
||||||
"name": "",
|
|
||||||
"hostname": "",
|
|
||||||
"ip": "",
|
|
||||||
"terminal": "",
|
|
||||||
"login_type": "",
|
|
||||||
"system_user": "",
|
|
||||||
"was_failed": "",
|
|
||||||
"date_start": ""
|
|
||||||
}
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
queryset = models.ProxyLog.objects.all()
|
|
||||||
serializer_class = serializers.ProxyLogSerializer
|
|
||||||
permission_classes = (IsSuperUserOrAppUser,)
|
|
||||||
|
|
||||||
|
|
||||||
class CommandLogViewSet(BulkModelViewSet):
|
|
||||||
"""接受app发送来的command log, 格式如下
|
|
||||||
{
|
|
||||||
"proxy_log_id": 23,
|
|
||||||
"user": "admin",
|
|
||||||
"asset": "localhost",
|
|
||||||
"system_user": "web",
|
|
||||||
"command_no": 1,
|
|
||||||
"command": "whoami",
|
|
||||||
"output": "d2hvbWFp", # base64.b64encode(s)
|
|
||||||
"timestamp": 1485238673.0
|
|
||||||
}
|
|
||||||
|
|
||||||
"""
|
|
||||||
queryset = command_store.all()
|
|
||||||
serializer_class = CommandLogSerializer
|
|
||||||
permission_classes = (IsSuperUserOrAppUser,)
|
|
||||||
|
|
||||||
|
|
||||||
class RecordLogViewSet(BulkModelViewSet):
|
|
||||||
"""接受app发送来的record log, 格式如下
|
|
||||||
{
|
|
||||||
"proxy_log_id": 23,
|
|
||||||
"output": "d2hvbWFp", # base64.b64encode(s)
|
|
||||||
"timestamp": 1485238673.0
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
serializer_class = RecordSerializer
|
|
||||||
permission_classes = (IsSuperUserOrAppUser,)
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
filter_kwargs = {}
|
|
||||||
proxy_log_id = self.request.query_params.get('proxy_log_id')
|
|
||||||
data_from_ts = self.request.query_params.get('date_from_ts')
|
|
||||||
if proxy_log_id:
|
|
||||||
filter_kwargs['proxy_log_id'] = proxy_log_id
|
|
||||||
if data_from_ts:
|
|
||||||
filter_kwargs['date_from_ts'] = data_from_ts
|
|
||||||
if filter_kwargs:
|
|
||||||
return record_store.filter(**filter_kwargs)
|
|
||||||
else:
|
|
||||||
return record_store.all()
|
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
from django.apps import AppConfig
|
|
||||||
|
|
||||||
|
|
||||||
class AuditsConfig(AppConfig):
|
|
||||||
name = 'audits'
|
|
|
@ -1,10 +0,0 @@
|
||||||
from importlib import import_module
|
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
command_engine = import_module(settings.COMMAND_STORE_BACKEND)
|
|
||||||
command_store = command_engine.CommandStore()
|
|
||||||
record_engine = import_module(settings.RECORD_STORE_BACKEND)
|
|
||||||
record_store = record_engine.RecordStore()
|
|
||||||
from .command.serializers import CommandLogSerializer
|
|
||||||
|
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
# coding: utf-8
|
|
||||||
import abc
|
|
||||||
|
|
||||||
|
|
||||||
class CommandBase(object):
|
|
||||||
__metaclass__ = abc.ABCMeta
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def save(self, proxy_log_id, user, asset, system_user,
|
|
||||||
command_no, command, output, timestamp):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def filter(self, date_from_ts=None, date_to_ts=None, user='',
|
|
||||||
asset='', system_user='', command='', proxy_log_id=0):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,45 +0,0 @@
|
||||||
# ~*~ coding: utf-8 ~*~
|
|
||||||
|
|
||||||
from .base import CommandBase
|
|
||||||
from audits.models import CommandLog
|
|
||||||
|
|
||||||
|
|
||||||
class CommandStore(CommandBase):
|
|
||||||
model = CommandLog
|
|
||||||
queryset = []
|
|
||||||
|
|
||||||
def save(self, proxy_log_id, user, asset, system_user,
|
|
||||||
command_no, command, output, timestamp):
|
|
||||||
self.model.objects.create(
|
|
||||||
proxy_log_id=proxy_log_id, user=user, asset=asset,
|
|
||||||
system_user=system_user, command_no=command_no,
|
|
||||||
command=command, output=output, timestamp=timestamp
|
|
||||||
)
|
|
||||||
|
|
||||||
def filter(self, date_from_ts=None, date_to_ts=None, user='',
|
|
||||||
asset='', system_user='', command='', proxy_log_id=0):
|
|
||||||
filter_kwargs = {}
|
|
||||||
|
|
||||||
if date_from_ts:
|
|
||||||
filter_kwargs['timestamp__gte'] = date_from_ts
|
|
||||||
if date_to_ts:
|
|
||||||
filter_kwargs['timestamp__lte'] = date_to_ts
|
|
||||||
if user:
|
|
||||||
filter_kwargs['user'] = user
|
|
||||||
if asset:
|
|
||||||
filter_kwargs['asset'] = asset
|
|
||||||
if system_user:
|
|
||||||
filter_kwargs['system_user'] = system_user
|
|
||||||
if command:
|
|
||||||
filter_kwargs['command__icontains'] = command
|
|
||||||
if proxy_log_id:
|
|
||||||
filter_kwargs['proxy_log_id'] = proxy_log_id
|
|
||||||
|
|
||||||
if filter_kwargs:
|
|
||||||
self.queryset = self.model.objects.filter(**filter_kwargs)
|
|
||||||
return self.queryset
|
|
||||||
|
|
||||||
def all(self):
|
|
||||||
"""返回所有数据"""
|
|
||||||
return self.model.objects.iterator()
|
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
# ~*~ coding: utf-8 ~*~
|
|
||||||
import base64
|
|
||||||
from rest_framework import serializers
|
|
||||||
from audits.models import CommandLog
|
|
||||||
from audits.backends import command_store
|
|
||||||
|
|
||||||
|
|
||||||
class CommandLogSerializer(serializers.ModelSerializer):
|
|
||||||
"""使用这个类作为基础Command Log Serializer类, 用来序列化"""
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = CommandLog
|
|
||||||
fields = '__all__'
|
|
||||||
|
|
||||||
def create(self, validated_data):
|
|
||||||
try:
|
|
||||||
output = validated_data['output']
|
|
||||||
validated_data['output'] = base64.b64decode(output)
|
|
||||||
except IndexError:
|
|
||||||
pass
|
|
||||||
return command_store.save(**dict(validated_data))
|
|
|
@ -1,2 +0,0 @@
|
||||||
# ~*~ coding: utf-8 ~*~
|
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
# coding: utf-8
|
|
||||||
import abc
|
|
||||||
|
|
||||||
|
|
||||||
class RecordBase(object):
|
|
||||||
__metaclass__ = abc.ABCMeta
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def save(self, proxy_log_id, output, timestamp):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def filter(self, date_from_ts=None, proxy_log_id=None):
|
|
||||||
pass
|
|
|
@ -1,31 +0,0 @@
|
||||||
# ~*~ coding: utf-8 ~*~
|
|
||||||
|
|
||||||
from .base import RecordBase
|
|
||||||
from audits.models import RecordLog
|
|
||||||
|
|
||||||
|
|
||||||
class RecordStore(RecordBase):
|
|
||||||
model = RecordLog
|
|
||||||
queryset = []
|
|
||||||
|
|
||||||
def save(self, proxy_log_id, output, timestamp):
|
|
||||||
return self.model.objects.create(
|
|
||||||
proxy_log_id=proxy_log_id, output=output, timestamp=timestamp
|
|
||||||
)
|
|
||||||
|
|
||||||
def filter(self, date_from_ts=None, proxy_log_id=''):
|
|
||||||
filter_kwargs = {}
|
|
||||||
|
|
||||||
if date_from_ts:
|
|
||||||
filter_kwargs['timestamp__gte'] = date_from_ts
|
|
||||||
if proxy_log_id:
|
|
||||||
filter_kwargs['proxy_log_id'] = proxy_log_id
|
|
||||||
|
|
||||||
if filter_kwargs:
|
|
||||||
self.queryset = self.model.objects.filter(**filter_kwargs)
|
|
||||||
return self.queryset
|
|
||||||
|
|
||||||
def all(self):
|
|
||||||
"""返回所有数据"""
|
|
||||||
return self.model.objects.all()
|
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
# ~*~ coding: utf-8 ~*~
|
|
||||||
import base64
|
|
||||||
from rest_framework import serializers
|
|
||||||
from audits.models import RecordLog
|
|
||||||
from audits.backends import record_store
|
|
||||||
|
|
||||||
|
|
||||||
class RecordSerializer(serializers.ModelSerializer):
|
|
||||||
"""使用这个类作为基础Command Log Serializer类, 用来序列化"""
|
|
||||||
class Meta:
|
|
||||||
model = RecordLog
|
|
||||||
fields = '__all__'
|
|
||||||
|
|
||||||
def create(self, validated_data):
|
|
||||||
try:
|
|
||||||
output = validated_data['output']
|
|
||||||
validated_data['output'] = base64.b64decode(output)
|
|
||||||
except IndexError:
|
|
||||||
pass
|
|
||||||
return record_store.save(**dict(validated_data))
|
|
|
@ -1,8 +0,0 @@
|
||||||
# ~*~ coding: utf-8 ~*~
|
|
||||||
#
|
|
||||||
|
|
||||||
from users.utils import AdminUserRequiredMixin
|
|
||||||
from users.models import User
|
|
||||||
from assets.models import Asset, SystemUser
|
|
||||||
from users.permissions import IsSuperUserOrAppUser, IsAppUser
|
|
||||||
from terminal.models import Terminal
|
|
|
@ -1,99 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
#
|
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
import uuid
|
|
||||||
|
|
||||||
from django.db import models
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
|
||||||
|
|
||||||
|
|
||||||
class LoginLog(models.Model):
|
|
||||||
LOGIN_TYPE_CHOICE = (
|
|
||||||
('W', 'Web'),
|
|
||||||
('ST', 'SSH Terminal'),
|
|
||||||
('WT', 'Web Terminal')
|
|
||||||
)
|
|
||||||
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
|
||||||
username = models.CharField(max_length=20, verbose_name=_('Username'))
|
|
||||||
name = models.CharField(max_length=20, blank=True, verbose_name=_('Name'))
|
|
||||||
login_type = models.CharField(choices=LOGIN_TYPE_CHOICE, max_length=2,
|
|
||||||
verbose_name=_('Login type'))
|
|
||||||
login_ip = models.GenericIPAddressField(verbose_name=_('Login ip'))
|
|
||||||
login_city = models.CharField(max_length=254, blank=True, null=True,
|
|
||||||
verbose_name=_('Login city'))
|
|
||||||
user_agent = models.CharField(max_length=254, blank=True, null=True,
|
|
||||||
verbose_name=_('User agent'))
|
|
||||||
date_login = models.DateTimeField(auto_now_add=True,
|
|
||||||
verbose_name=_('Date login'))
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
db_table = 'login_log'
|
|
||||||
ordering = ['-date_login', 'username']
|
|
||||||
|
|
||||||
|
|
||||||
class ProxyLog(models.Model):
|
|
||||||
LOGIN_TYPE_CHOICE = (
|
|
||||||
('ST', 'SSH Terminal'),
|
|
||||||
('WT', 'Web Terminal'),
|
|
||||||
)
|
|
||||||
|
|
||||||
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
|
||||||
user = models.CharField(max_length=32, verbose_name=_('User'))
|
|
||||||
asset = models.CharField(max_length=32, verbose_name=_('Asset'))
|
|
||||||
system_user = models.CharField(max_length=32, verbose_name=_('System user'))
|
|
||||||
login_type = models.CharField(
|
|
||||||
choices=LOGIN_TYPE_CHOICE, max_length=2, blank=True,
|
|
||||||
null=True, verbose_name=_('Login type'))
|
|
||||||
terminal = models.CharField(
|
|
||||||
max_length=32, blank=True, null=True, verbose_name=_('Terminal'))
|
|
||||||
is_failed = models.BooleanField(
|
|
||||||
default=False, verbose_name=_('Did connect failed'))
|
|
||||||
is_finished = models.BooleanField(
|
|
||||||
default=False, verbose_name=_('Is finished'))
|
|
||||||
date_start = models.DateTimeField(
|
|
||||||
auto_created=True, verbose_name=_('Date start'))
|
|
||||||
date_finished = models.DateTimeField(
|
|
||||||
null=True, verbose_name=_('Date finished'))
|
|
||||||
|
|
||||||
def __unicode__(self):
|
|
||||||
return '%s-%s-%s' % (self.user, self.asset, self.system_user)
|
|
||||||
|
|
||||||
def commands(self):
|
|
||||||
from audits.backends import command_store
|
|
||||||
return command_store.filter(proxy_log_id=self.id)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
ordering = ['-date_start', 'user']
|
|
||||||
|
|
||||||
|
|
||||||
class CommandLog(models.Model):
|
|
||||||
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
|
||||||
proxy_log_id = models.IntegerField(db_index=True)
|
|
||||||
user = models.CharField(max_length=48, db_index=True)
|
|
||||||
asset = models.CharField(max_length=128, db_index=True)
|
|
||||||
system_user = models.CharField(max_length=48, db_index=True)
|
|
||||||
command_no = models.IntegerField()
|
|
||||||
command = models.TextField(max_length=767, blank=True)
|
|
||||||
output = models.TextField(blank=True)
|
|
||||||
timestamp = models.FloatField(db_index=True)
|
|
||||||
|
|
||||||
def __unicode__(self):
|
|
||||||
return '%s: %s' % (self.id, self.command)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
ordering = ['command_no', 'command']
|
|
||||||
|
|
||||||
|
|
||||||
class RecordLog(models.Model):
|
|
||||||
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
|
||||||
proxy_log_id = models.IntegerField(db_index=True)
|
|
||||||
output = models.TextField(verbose_name=_('Output'))
|
|
||||||
timestamp = models.FloatField(db_index=True)
|
|
||||||
|
|
||||||
def __unicode__(self):
|
|
||||||
return 'Record: %s' % self.proxy_log_id
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
ordering = ['timestamp']
|
|
|
@ -1,28 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
#
|
|
||||||
from __future__ import absolute_import, unicode_literals
|
|
||||||
from rest_framework import serializers
|
|
||||||
|
|
||||||
from common.utils import timesince
|
|
||||||
from . import models
|
|
||||||
|
|
||||||
|
|
||||||
class ProxyLogSerializer(serializers.ModelSerializer):
|
|
||||||
time = serializers.SerializerMethodField()
|
|
||||||
command_length = serializers.SerializerMethodField()
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = models.ProxyLog
|
|
||||||
fields = '__all__'
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_time(obj):
|
|
||||||
if not obj.is_finished:
|
|
||||||
return ''
|
|
||||||
else:
|
|
||||||
return timesince(obj.date_start, since=obj.date_finished)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_command_length(obj):
|
|
||||||
return 2
|
|
||||||
|
|
|
@ -1,109 +0,0 @@
|
||||||
{% extends '_base_list.html' %}
|
|
||||||
{% load i18n %}
|
|
||||||
{% load static %}
|
|
||||||
{% load common_tags %}
|
|
||||||
{% block content_left_head %}
|
|
||||||
<link href="{% static "css/plugins/footable/footable.core.css" %}" rel="stylesheet">
|
|
||||||
<link href="{% static 'css/plugins/datepicker/datepicker3.css' %}" rel="stylesheet">
|
|
||||||
<style>
|
|
||||||
#search_btn {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block table_search %}
|
|
||||||
<form id="search_form" method="get" action="" class="pull-right form-inline">
|
|
||||||
<div class="form-group" id="date">
|
|
||||||
<div class="input-daterange input-group" id="datepicker">
|
|
||||||
<span class="input-group-addon"><i class="fa fa-calendar"></i></span>
|
|
||||||
<input type="text" class="input-sm form-control" style="width: 100px;" name="date_from" value="{{ date_from }}">
|
|
||||||
<span class="input-group-addon">to</span>
|
|
||||||
<input type="text" class="input-sm form-control" style="width: 100px;" name="date_to" value="{{ date_to }}">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="input-group">
|
|
||||||
<select class="select2 form-control" name="username">
|
|
||||||
<option value="">{% trans 'User' %}</option>
|
|
||||||
{% for u in user_list %}
|
|
||||||
<option value="{{ u.username }}" {% if username == u.username %} selected {% endif %}>{{ u.username }}</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="input-group">
|
|
||||||
<select class="select2 form-control" name="ip">
|
|
||||||
<option value="">{% trans 'Asset' %}</option>
|
|
||||||
{% for a in asset_list %}
|
|
||||||
<option value="{{ a.ip }}" {% if ip == a.ip %} selected {% endif %}>{{ a.ip }}</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="input-group">
|
|
||||||
<select class="select2 form-control" name="system_user">
|
|
||||||
<option value="">{% trans 'System user' %}</option>
|
|
||||||
{% for s in system_user_list %}
|
|
||||||
<option value="{{ s.username }}" {% if s.username == system_user %} selected {% endif %}>{{ s.username }}</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="input-group">
|
|
||||||
<input type="text" class="form-control input-sm" name="command" placeholder="Command" value="{{ command }}">
|
|
||||||
</div>
|
|
||||||
<div class="input-group">
|
|
||||||
<div class="input-group-btn">
|
|
||||||
<button id='search_btn' type="submit" class="btn btn-sm btn-primary">
|
|
||||||
搜索
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
{% endblock %}
|
|
||||||
{% block table_container %}
|
|
||||||
<table class="footable table table-stripped toggle-arrow-tiny" data-page="false">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th data-toggle="true">ID</th>
|
|
||||||
<th>Command</th>
|
|
||||||
<th>Username</th>
|
|
||||||
<th>IP</th>
|
|
||||||
<th>System user</th>
|
|
||||||
<th>Proxy log</th>
|
|
||||||
<th>Datetime</th>
|
|
||||||
<th data-hide="all">Output</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for command in command_list %}
|
|
||||||
<tr>
|
|
||||||
<td>{{ command.id }}</td>
|
|
||||||
<td>{{ command.command }}</td>
|
|
||||||
<td>{{ command.user }}</td>
|
|
||||||
<td>{{ command.asset }}</td>
|
|
||||||
<td>{{ command.system_user }}</td>
|
|
||||||
<td><a href="{% url 'audits:proxy-log-detail' pk=command.proxy_log_id %}">{{ command.proxy_log_id}}</a></td>
|
|
||||||
<td>{{ command.timestamp|ts_to_date }}</td>
|
|
||||||
<td><pre style="border: none; background: none">{{ command.output|to_html|safe }}</pre></td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block custom_foot_js %}
|
|
||||||
<script src="{% static "js/plugins/footable/footable.all.min.js" %}"></script>
|
|
||||||
<script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"></script>
|
|
||||||
<script>
|
|
||||||
$(document).ready(function () {
|
|
||||||
$('.footable').footable();
|
|
||||||
$('.select2').select2();
|
|
||||||
$('#date .input-daterange').datepicker({
|
|
||||||
dateFormat: 'mm/dd/yy',
|
|
||||||
keyboardNavigation: false,
|
|
||||||
forceParse: false,
|
|
||||||
autoclose: true
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
|
|
|
@ -1,101 +0,0 @@
|
||||||
{% extends '_base_list.html' %}
|
|
||||||
{% load i18n %}
|
|
||||||
{% load static %}
|
|
||||||
{% load common_tags %}
|
|
||||||
{% block content_left_head %}
|
|
||||||
<link href="{% static 'css/plugins/datepicker/datepicker3.css' %}" rel="stylesheet">
|
|
||||||
<style>
|
|
||||||
#search_btn {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
|
|
||||||
{% block table_search %}
|
|
||||||
<form id="search_form" method="get" action="" class="pull-right form-inline">
|
|
||||||
<div class="form-group" id="date">
|
|
||||||
<div class="input-daterange input-group" id="datepicker">
|
|
||||||
<span class="input-group-addon"><i class="fa fa-calendar"></i></span>
|
|
||||||
<input type="text" class="input-sm form-control" style="width: 100px;" name="date_from" value="{{ date_from }}">
|
|
||||||
<span class="input-group-addon">to</span>
|
|
||||||
<input type="text" class="input-sm form-control" style="width: 100px;" name="date_to" value="{{ date_to }}">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="input-group">
|
|
||||||
<select class="select2 form-control" name="username">
|
|
||||||
<option value="">{% trans 'Select user' %}</option>
|
|
||||||
{% for user in user_list %}
|
|
||||||
<option value="{{ user.username }}" {% if user.username == username %} selected {% endif %}>{{ user.username }}</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="input-group">
|
|
||||||
<input type="text" class="form-control input-sm" name="keyword" placeholder="Search" value="{{ keyword }}">
|
|
||||||
</div>
|
|
||||||
<div class="input-group">
|
|
||||||
<div class="input-group-btn">
|
|
||||||
<button id='search_btn' type="submit" class="btn btn-sm btn-primary">
|
|
||||||
搜索
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block table_head %}
|
|
||||||
<th class="text-center">{% trans 'ID' %}</th>
|
|
||||||
<th class="text-center">{% trans 'Username' %}</th>
|
|
||||||
<th class="text-center">{% trans 'Name' %}</th>
|
|
||||||
<th class="text-center">{% trans 'Type' %}</th>
|
|
||||||
<th class="text-center">{% trans 'UA' %}</th>
|
|
||||||
<th class="text-center">{% trans 'IP' %}</th>
|
|
||||||
<th class="text-center">{% trans 'City' %}</th>
|
|
||||||
<th class="text-center">{% trans 'Date' %}</th>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block table_body %}
|
|
||||||
{% for login_log in login_log_list %}
|
|
||||||
<tr class="gradeX">
|
|
||||||
<td class="text-center">
|
|
||||||
{{ login_log.id }}
|
|
||||||
{# <a href="{% url 'audits:proxy-log-detail' pk=login_log.id %}">{{ login_log.id }}</a>#}
|
|
||||||
</td>
|
|
||||||
<td class="text-center">{{ login_log.username }}</td>
|
|
||||||
<td class="text-center">{{ login_log.name }}</td>
|
|
||||||
<td class="text-center">{{ login_log.get_login_type_display }}</td>
|
|
||||||
{% if login_log.login_type == 'W' %}
|
|
||||||
<td class="text-center">
|
|
||||||
<span href="javascript:void(0);" data-toggle="tooltips" title="{{ login_log.user_agent }}">{{ login_log.user_agent | truncatechars:20 }}</span>
|
|
||||||
</td>
|
|
||||||
{% else %}
|
|
||||||
<td class="text-center">{{ login_log.terminal }}</td>
|
|
||||||
{% endif %}
|
|
||||||
<td class="text-center">{{ login_log.login_ip }}</td>
|
|
||||||
<td class="text-center">{{ login_log.login_city }}</td>
|
|
||||||
<td class="text-center">{{ login_log.date_login }}</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block custom_foot_js %}
|
|
||||||
<script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"></script>
|
|
||||||
<script>
|
|
||||||
$(document).ready(function() {
|
|
||||||
$('table').DataTable({
|
|
||||||
"searching": false,
|
|
||||||
"bInfo" : false,
|
|
||||||
"paging": false,
|
|
||||||
"order": []
|
|
||||||
});
|
|
||||||
$('#date .input-daterange').datepicker({
|
|
||||||
dateFormat: 'mm/dd/yy',
|
|
||||||
keyboardNavigation: false,
|
|
||||||
forceParse: false,
|
|
||||||
autoclose: true
|
|
||||||
});
|
|
||||||
$('.select2').select2();
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
|
@ -1,58 +0,0 @@
|
||||||
{% load static %}
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<meta name="renderer" content="webkit">
|
|
||||||
{% include '_head_css_js.html' %}
|
|
||||||
<link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet">
|
|
||||||
<link href="{% static "css/plugins/footable/footable.core.css" %}" rel="stylesheet">
|
|
||||||
<script src="{% static 'js/jquery-2.1.1.js' %}"></script>
|
|
||||||
<script src="{% static 'js/plugins/sweetalert/sweetalert.min.js' %}"></script>
|
|
||||||
<script src="{% static 'js/bootstrap.min.js' %}"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="wrapper wrapper-content animated fadeInRight">
|
|
||||||
<div class="tab-content">
|
|
||||||
<div class="ibox-content">
|
|
||||||
<input type="text" class="form-control input-sm m-b-xs" id="filter"
|
|
||||||
placeholder="Search in table">
|
|
||||||
<table class="footable table table-stripped toggle-arrow-tiny" data-page-size="10" data-filter=#filter>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th data-toggle="true">ID</th>
|
|
||||||
<th>Command</th>
|
|
||||||
<th data-hide="all">Output</th>
|
|
||||||
<th>Datetime</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody class="table_body">
|
|
||||||
{% for command in object_list %}
|
|
||||||
<tr>
|
|
||||||
<td>{{ command.command_no }}</td>
|
|
||||||
<td>{{ command.command }}</td>
|
|
||||||
<td>{{ command.output_decode |safe }}</td>
|
|
||||||
<td>{{ command.datetime }}</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
<tfoot>
|
|
||||||
<tr>
|
|
||||||
<td colspan="5">
|
|
||||||
<ul class="pagination pull-right"></ul>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tfoot>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
<script src="{% static "js/plugins/footable/footable.all.min.js" %}"></script>
|
|
||||||
<script>
|
|
||||||
$(document).ready(function () {
|
|
||||||
$('.footable').footable();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</html>
|
|
|
@ -1,85 +0,0 @@
|
||||||
{% extends 'base.html' %}
|
|
||||||
{% load static %}
|
|
||||||
{% load i18n %}
|
|
||||||
{% load common_tags %}
|
|
||||||
|
|
||||||
{% block custom_head_css_js %}
|
|
||||||
<link href="{% static "css/plugins/footable/footable.core.css" %}" rel="stylesheet">
|
|
||||||
{% endblock %}
|
|
||||||
{% block content %}
|
|
||||||
<div class="wrapper wrapper-content animated fadeInRight">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-sm-12">
|
|
||||||
<div class="ibox float-e-margins">
|
|
||||||
<div class="panel-options">
|
|
||||||
<ul class="nav nav-tabs">
|
|
||||||
<li class="active">
|
|
||||||
<a href="#" class="text-center"> {% trans 'Proxy log detail' %} </a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div class="tab-content">
|
|
||||||
<div class="col-sm-11" style="padding-left: 0;">
|
|
||||||
<div class="ibox float-e-margins">
|
|
||||||
<div class="ibox-title">
|
|
||||||
<span style="float: left">{% trans 'Command log list' %} <b>{{ user_object.name }}</b></span>
|
|
||||||
<div class="ibox-tools">
|
|
||||||
<a class="collapse-link">
|
|
||||||
<i class="fa fa-chevron-up"></i>
|
|
||||||
</a>
|
|
||||||
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
|
|
||||||
<i class="fa fa-wrench"></i>
|
|
||||||
</a>
|
|
||||||
<ul class="dropdown-menu dropdown-user">
|
|
||||||
</ul>
|
|
||||||
<a class="close-link">
|
|
||||||
<i class="fa fa-times"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="ibox-content">
|
|
||||||
<table id="command-log" class="footable table table-stripped toggle-arrow-tiny" data-page-size="10">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th data-toggle="true">ID</th>
|
|
||||||
<th>Command</th>
|
|
||||||
<th data-hide="all">Output</th>
|
|
||||||
<th>Datetime</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for command in object_list %}
|
|
||||||
<tr>
|
|
||||||
<td>{{ command.command_no }}</td>
|
|
||||||
<td>{{ command.command }}</td>
|
|
||||||
<td><pre style="border: none;background: none">{{ command.output|to_html|safe}}</pre></td>
|
|
||||||
<td>{{ command.timestamp|ts_to_date}}</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
<tfoot>
|
|
||||||
<tr>
|
|
||||||
<td colspan="5">
|
|
||||||
<ul class="pagination pull-right"></ul>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tfoot>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
||||||
{% block custom_foot_js %}
|
|
||||||
<script src="{% static "js/plugins/footable/footable.all.min.js" %}"></script>
|
|
||||||
<script>
|
|
||||||
$(document).ready(function () {
|
|
||||||
$('.footable').footable();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
|
|
@ -1,159 +0,0 @@
|
||||||
{% extends '_base_list.html' %}
|
|
||||||
{% load i18n %}
|
|
||||||
{% load static %}
|
|
||||||
{% block content_left_head %}
|
|
||||||
<link href="{% static 'css/plugins/datepicker/datepicker3.css' %}" rel="stylesheet">
|
|
||||||
<style>
|
|
||||||
#search_btn {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
|
|
||||||
{% block table_search %}
|
|
||||||
<form id="search_form" method="get" action="" class="pull-right form-inline">
|
|
||||||
<div class="form-group" id="date">
|
|
||||||
<div class="input-daterange input-group" id="datepicker">
|
|
||||||
<span class="input-group-addon"><i class="fa fa-calendar"></i></span>
|
|
||||||
<input type="text" class="input-sm form-control" style="width: 100px;" name="date_from" value="{{ date_from }}">
|
|
||||||
<span class="input-group-addon">to</span>
|
|
||||||
<input type="text" class="input-sm form-control" style="width: 100px;" name="date_to" value="{{ date_to }}">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="input-group">
|
|
||||||
<select class="select2 form-control" name="username">
|
|
||||||
<option value="">{% trans 'User' %}</option>
|
|
||||||
{% for u in user_list %}
|
|
||||||
<option value="{{ u }}" {% if u == username %} selected {% endif %}>{{ u }}</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="input-group">
|
|
||||||
<select class="select2 form-control" name="ip">
|
|
||||||
<option value="">{% trans 'Asset' %}</option>
|
|
||||||
{% for a in asset_list %}
|
|
||||||
<option value="{{ a }}" {% if a == ip %} selected {% endif %}>{{ a }}</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="input-group">
|
|
||||||
<select class="select2 form-control" name="system_user">
|
|
||||||
<option value="">{% trans 'System user' %}</option>
|
|
||||||
{% for su in system_user_list %}
|
|
||||||
<option value="{{ su }}" {% if su == system_user %} selected {% endif %}>{{ su }}</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="input-group">
|
|
||||||
<input type="text" class="form-control input-sm" name="keyword" placeholder="Keyword" value="{{ keyword }}">
|
|
||||||
</div>
|
|
||||||
<div class="input-group">
|
|
||||||
<div class="input-group-btn">
|
|
||||||
<button id='search_btn' type="submit" class="btn btn-sm btn-primary">
|
|
||||||
搜索
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block table_head %}
|
|
||||||
<th class="text-center"></th>
|
|
||||||
<th class="text-center">{% trans 'ID' %}</th>
|
|
||||||
<th class="text-center">{% trans 'User' %}</th>
|
|
||||||
<th class="text-center">{% trans 'Asset' %}</th>
|
|
||||||
<th class="text-center">{% trans 'System user' %}</th>
|
|
||||||
<th class="text-center">{% trans 'Terminal' %}</th>
|
|
||||||
<th class="text-center">{% trans 'Command' %}</th>
|
|
||||||
<th class="text-center">{% trans 'Success' %}</th>
|
|
||||||
<th class="text-center">{% trans 'Finished' %}</th>
|
|
||||||
<th class="text-center">{% trans 'Play' %}</th>
|
|
||||||
<th class="text-center">{% trans 'Date start' %}</th>
|
|
||||||
<th class="text-center">{% trans 'Time' %}</th>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block table_body %}
|
|
||||||
{% for proxy_log in proxy_log_list %}
|
|
||||||
<tr class="gradeX">
|
|
||||||
<td class="text-center"><input type="checkbox" class="cbx-term" value="{{ proxy_log.id }}"></td>
|
|
||||||
<td class="text-center">
|
|
||||||
<a href="{% url 'audits:proxy-log-detail' pk=proxy_log.id %}">{{ proxy_log.id }}</a>
|
|
||||||
</td>
|
|
||||||
<td class="text-center">{{ proxy_log.user }}</td>
|
|
||||||
<td class="text-center">{{ proxy_log.asset }}</td>
|
|
||||||
<td class="text-center">{{ proxy_log.system_user }}</td>
|
|
||||||
<td class="text-center">{{ proxy_log.terminal }}</td>
|
|
||||||
<td class="text-center">{{ proxy_log.commands.all|length}}</td>
|
|
||||||
<td class="text-center">
|
|
||||||
{% if proxy_log.is_failed %}
|
|
||||||
<i class="fa fa-times text-danger"></i>
|
|
||||||
{% else %}
|
|
||||||
<i class="fa fa-check text-navy"></i>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
{% if proxy_log.is_finished %}
|
|
||||||
<td class="text-center">
|
|
||||||
<i class="fa fa-check text-navy"></i>
|
|
||||||
</td>
|
|
||||||
<td class="text-center">
|
|
||||||
<a><span class="text-navy"><i class="fa fa-play-circle"></i></span></a>
|
|
||||||
</td>
|
|
||||||
{% else %}
|
|
||||||
<td class="text-center">
|
|
||||||
<a class="btn-term" value="{{ proxy_log.id }}"><i class="fa fa-times text-danger"></i></a>
|
|
||||||
</td>
|
|
||||||
<td class="text-center">
|
|
||||||
<a><span class="text-danger"><i class="fa fa-eye"></i></span></a>
|
|
||||||
</td>
|
|
||||||
{% endif %}
|
|
||||||
<td class="text-center">{{ proxy_log.date_start }}</td>
|
|
||||||
<td class="text-center">{{ proxy_log.date_finished|timeuntil:proxy_log.date_start }}</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
|
|
||||||
{% block custom_foot_js %}
|
|
||||||
<script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"></script>
|
|
||||||
<script>
|
|
||||||
function terminateConnection(data) {
|
|
||||||
function success() {
|
|
||||||
window.setTimeout(function () {
|
|
||||||
window.location.reload()
|
|
||||||
}, 300)
|
|
||||||
}
|
|
||||||
var the_url = "";
|
|
||||||
APIUpdateAttr({url: the_url, method: 'POST', body: JSON.stringify(data), success: success, success_message: 'Terminate success'});
|
|
||||||
}
|
|
||||||
$(document).ready(function() {
|
|
||||||
$('table').DataTable({
|
|
||||||
"searching": false,
|
|
||||||
"paging": false,
|
|
||||||
"bInfo" : false,
|
|
||||||
"order": []
|
|
||||||
});
|
|
||||||
$('.select2').select2();
|
|
||||||
$('#date .input-daterange').datepicker({
|
|
||||||
dateFormat: 'mm/dd/yy',
|
|
||||||
keyboardNavigation: false,
|
|
||||||
forceParse: false,
|
|
||||||
autoclose: true
|
|
||||||
});
|
|
||||||
}).on('click', '.btn-term', function () {
|
|
||||||
var $this = $(this);
|
|
||||||
var proxy_log_id = $this.attr('value');
|
|
||||||
var data = {
|
|
||||||
proxy_log_id: proxy_log_id
|
|
||||||
};
|
|
||||||
terminateConnection(data)
|
|
||||||
}).on('click', '#btn_bulk_update', function () {
|
|
||||||
var data = [];
|
|
||||||
$('.cbx-term:checked').each(function () {
|
|
||||||
data.push({proxy_log_id: $(this).attr('value')})
|
|
||||||
});
|
|
||||||
terminateConnection(data)
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
|
@ -1,173 +0,0 @@
|
||||||
{% extends '_base_list.html' %}
|
|
||||||
{% load i18n %}
|
|
||||||
{% load static %}
|
|
||||||
{% block content_left_head %}
|
|
||||||
<link href="{% static 'css/plugins/datepicker/datepicker3.css' %}" rel="stylesheet">
|
|
||||||
<style>
|
|
||||||
#search_btn {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
|
|
||||||
{% block table_search %}
|
|
||||||
<form id="search_form" method="get" action="" class="pull-right form-inline">
|
|
||||||
<div class="form-group" id="date">
|
|
||||||
<div class="input-daterange input-group" id="datepicker">
|
|
||||||
<span class="input-group-addon"><i class="fa fa-calendar"></i></span>
|
|
||||||
<input type="text" class="input-sm form-control" style="width: 100px;" name="date_from" value="{{ date_from }}">
|
|
||||||
<span class="input-group-addon">to</span>
|
|
||||||
<input type="text" class="input-sm form-control" style="width: 100px;" name="date_to" value="{{ date_to }}">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="input-group">
|
|
||||||
<select class="select2 form-control" name="username">
|
|
||||||
<option value="">{% trans 'User' %}</option>
|
|
||||||
{% for u in user_list %}
|
|
||||||
<option value="{{ u }}" {% if u == username %} selected {% endif %}>{{ u }}</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="input-group">
|
|
||||||
<select class="select2 form-control" name="ip">
|
|
||||||
<option value="">{% trans 'Asset' %}</option>
|
|
||||||
{% for a in asset_list %}
|
|
||||||
<option value="{{ a }}" {% if a == ip %} selected {% endif %}>{{ a }}</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="input-group">
|
|
||||||
<select class="select2 form-control" name="system_user">
|
|
||||||
<option value="">{% trans 'System user' %}</option>
|
|
||||||
{% for su in system_user_list %}
|
|
||||||
<option value="{{ su }}" {% if su == system_user %} selected {% endif %}>{{ su }}</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="input-group">
|
|
||||||
<input type="text" class="form-control input-sm" name="keyword" placeholder="Keyword" value="{{ keyword }}">
|
|
||||||
</div>
|
|
||||||
<div class="input-group">
|
|
||||||
<div class="input-group-btn">
|
|
||||||
<button id='search_btn' type="submit" class="btn btn-sm btn-primary">
|
|
||||||
搜索
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block table_head %}
|
|
||||||
<th class="text-center"></th>
|
|
||||||
<th class="text-center">{% trans 'ID' %}</th>
|
|
||||||
<th class="text-center">{% trans 'User' %}</th>
|
|
||||||
<th class="text-center">{% trans 'Asset' %}</th>
|
|
||||||
<th class="text-center">{% trans 'System user' %}</th>
|
|
||||||
<th class="text-center">{% trans 'Terminal' %}</th>
|
|
||||||
<th class="text-center">{% trans 'Command' %}</th>
|
|
||||||
<th class="text-center">{% trans 'Success' %}</th>
|
|
||||||
<th class="text-center">{% trans 'Finished' %}</th>
|
|
||||||
<th class="text-center">{% trans 'Monitor' %}</th>
|
|
||||||
<th class="text-center">{% trans 'Date start' %}</th>
|
|
||||||
<th class="text-center">{% trans 'Time' %}</th>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block table_body %}
|
|
||||||
{% for proxy_log in proxy_log_list %}
|
|
||||||
<tr class="gradeX">
|
|
||||||
<td class="text-center"><input type="checkbox" class="cbx-term" value="{{ proxy_log.id }}"></td>
|
|
||||||
<td class="text-center">
|
|
||||||
<a href="{% url 'audits:proxy-log-detail' pk=proxy_log.id %}">{{ proxy_log.id }}</a>
|
|
||||||
</td>
|
|
||||||
<td class="text-center">{{ proxy_log.user }}</td>
|
|
||||||
<td class="text-center">{{ proxy_log.asset }}</td>
|
|
||||||
<td class="text-center">{{ proxy_log.system_user }}</td>
|
|
||||||
<td class="text-center">{{ proxy_log.terminal }}</td>
|
|
||||||
<td class="text-center">{{ proxy_log.commands.all|length}}</td>
|
|
||||||
<td class="text-center">
|
|
||||||
{% if proxy_log.is_failed %}
|
|
||||||
<i class="fa fa-times text-danger"></i>
|
|
||||||
{% else %}
|
|
||||||
<i class="fa fa-check text-navy"></i>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
{% if proxy_log.is_finished %}
|
|
||||||
<td class="text-center">
|
|
||||||
<i class="fa fa-check text-navy"></i>
|
|
||||||
</td>
|
|
||||||
<td class="text-center">
|
|
||||||
<a><span class="text-navy"><i class="fa fa-play-circle"></i></span></a>
|
|
||||||
</td>
|
|
||||||
{% else %}
|
|
||||||
<td class="text-center">
|
|
||||||
<a class="btn-term" value="{{ proxy_log.id }}"><i class="fa fa-times text-danger"></i></a>
|
|
||||||
</td>
|
|
||||||
<td class="text-center">
|
|
||||||
<a><span class="text-danger"><i class="fa fa-eye"></i></span></a>
|
|
||||||
</td>
|
|
||||||
{% endif %}
|
|
||||||
<td class="text-center">{{ proxy_log.date_start }}</td>
|
|
||||||
<td class="text-center">{{ proxy_log.date_finished|timeuntil:proxy_log.date_start }}</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content_bottom_left %}
|
|
||||||
<div id="actions">
|
|
||||||
<div class="input-group">
|
|
||||||
<select class="form-control m-b" style="width: auto" id="slct_bulk_update">
|
|
||||||
<option value="terminate">{% trans 'Terminate selected' %}</option>
|
|
||||||
</select>
|
|
||||||
<div class="input-group-btn pull-left" style="padding-left: 5px;">
|
|
||||||
<button id='btn_bulk_update' style="height: 32px;" class="btn btn-sm btn-primary">
|
|
||||||
{% trans 'Submit' %}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block custom_foot_js %}
|
|
||||||
<script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"></script>
|
|
||||||
<script>
|
|
||||||
function terminateConnection(data) {
|
|
||||||
function success() {
|
|
||||||
window.setTimeout(function () {
|
|
||||||
window.location.reload()
|
|
||||||
}, 300)
|
|
||||||
}
|
|
||||||
var the_url = "";
|
|
||||||
APIUpdateAttr({url: the_url, method: 'POST', body: JSON.stringify(data), success: success, success_message: 'Terminate success'});
|
|
||||||
}
|
|
||||||
$(document).ready(function() {
|
|
||||||
$('table').DataTable({
|
|
||||||
"searching": false,
|
|
||||||
"paging": false,
|
|
||||||
"bInfo" : false,
|
|
||||||
"order": []
|
|
||||||
});
|
|
||||||
$('.select2').select2();
|
|
||||||
$('#date .input-daterange').datepicker({
|
|
||||||
dateFormat: 'mm/dd/yy',
|
|
||||||
keyboardNavigation: false,
|
|
||||||
forceParse: false,
|
|
||||||
autoclose: true
|
|
||||||
});
|
|
||||||
}).on('click', '.btn-term', function () {
|
|
||||||
var $this = $(this);
|
|
||||||
var proxy_log_id = $this.attr('value');
|
|
||||||
var data = {
|
|
||||||
proxy_log_id: proxy_log_id
|
|
||||||
};
|
|
||||||
terminateConnection(data)
|
|
||||||
}).on('click', '#btn_bulk_update', function () {
|
|
||||||
var data = [];
|
|
||||||
$('.cbx-term:checked').each(function () {
|
|
||||||
data.push({proxy_log_id: $(this).attr('value')})
|
|
||||||
});
|
|
||||||
terminateConnection(data)
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
from django.test import TestCase
|
|
||||||
|
|
||||||
# Create your tests here.
|
|
|
@ -1 +0,0 @@
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
from django.conf.urls import url
|
|
||||||
from rest_framework import routers
|
|
||||||
|
|
||||||
from .. import api
|
|
||||||
|
|
||||||
app_name = 'audits'
|
|
||||||
|
|
||||||
router = routers.DefaultRouter()
|
|
||||||
router.register(r'v1/proxy-log', api.ProxyLogViewSet, 'proxy-log')
|
|
||||||
router.register(r'v1/command-log', api.CommandLogViewSet, 'command-log')
|
|
||||||
router.register(r'v1/replay-log', api.RecordLogViewSet, 'replay-log')
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
url(r'^v1/proxy-log/receive/$', api.ProxyLogReceiveView.as_view(),
|
|
||||||
name='proxy-log-receive'),
|
|
||||||
]
|
|
||||||
|
|
||||||
urlpatterns += router.urls
|
|
|
@ -1,19 +0,0 @@
|
||||||
from django.conf.urls import url
|
|
||||||
from .. import views
|
|
||||||
|
|
||||||
app_name = 'audits'
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
url(r'^proxy-log-offline/$', views.ProxyLogOfflineListView.as_view(),
|
|
||||||
name='proxy-log-offline-list'),
|
|
||||||
url(r'^proxy-log-online/$', views.ProxyLogOnlineListView.as_view(),
|
|
||||||
name='proxy-log-online-list'),
|
|
||||||
url(r'^proxy-log/(?P<pk>[0-9a-zA-Z\-]+)/$', views.ProxyLogDetailView.as_view(),
|
|
||||||
name='proxy-log-detail'),
|
|
||||||
url(r'^command-log/$', views.CommandLogListView.as_view(),
|
|
||||||
name='command-log-list'),
|
|
||||||
url(r'^login-log/$', views.LoginLogListView.as_view(),
|
|
||||||
name='login-log-list'),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
# ~*~ coding: utf-8 ~*~
|
|
||||||
#
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
import requests
|
|
||||||
import ipaddress
|
|
||||||
|
|
||||||
from .models import LoginLog
|
|
||||||
|
|
||||||
|
|
||||||
def validate_ip(ip):
|
|
||||||
try:
|
|
||||||
ipaddress.ip_address(ip)
|
|
||||||
return True
|
|
||||||
except ValueError:
|
|
||||||
print('valid error')
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def write_login_log(username, name='', login_type='',
|
|
||||||
login_ip='', user_agent=''):
|
|
||||||
if not (login_ip and validate_ip(login_ip)):
|
|
||||||
login_ip = '0.0.0.0'
|
|
||||||
if not name:
|
|
||||||
name = username
|
|
||||||
login_city = get_ip_city(login_ip)
|
|
||||||
LoginLog.objects.create(username=username, name=name, login_type=login_type,
|
|
||||||
login_ip=login_ip, login_city=login_city, user_agent=user_agent)
|
|
||||||
|
|
||||||
|
|
||||||
def get_ip_city(ip, timeout=10):
|
|
||||||
# Taobao ip api: http://ip.taobao.com//service/getIpInfo.php?ip=8.8.8.8
|
|
||||||
# Sina ip api: http://int.dpool.sina.com.cn/iplookup/iplookup.php?ip=8.8.8.8&format=json
|
|
||||||
|
|
||||||
url = 'http://int.dpool.sina.com.cn/iplookup/iplookup.php?ip=%s&format=json' % ip
|
|
||||||
try:
|
|
||||||
r = requests.get(url, timeout=timeout)
|
|
||||||
except requests.Timeout:
|
|
||||||
r = None
|
|
||||||
city = 'Unknown'
|
|
||||||
if r and r.status_code == 200:
|
|
||||||
try:
|
|
||||||
data = r.json()
|
|
||||||
if not isinstance(data, int) and data['ret'] == 1:
|
|
||||||
city = data['country'] + ' ' + data['city']
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
return city
|
|
||||||
|
|
||||||
|
|
|
@ -1,272 +0,0 @@
|
||||||
# ~*~ coding: utf-8 ~*~
|
|
||||||
#
|
|
||||||
import time
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
from django.views.generic import ListView, UpdateView, DeleteView, DetailView, TemplateView
|
|
||||||
from django.views.generic.edit import SingleObjectMixin
|
|
||||||
from django.utils.translation import ugettext as _
|
|
||||||
from django.utils import timezone
|
|
||||||
from django.utils.module_loading import import_string
|
|
||||||
from django.urls import reverse_lazy
|
|
||||||
from django.http import HttpResponse
|
|
||||||
from django.conf import settings
|
|
||||||
from django.db.models import Q
|
|
||||||
|
|
||||||
from .models import ProxyLog, CommandLog, LoginLog
|
|
||||||
from .hands import User, Asset, SystemUser, AdminUserRequiredMixin
|
|
||||||
from audits.backends import command_store
|
|
||||||
from audits.backends import CommandLogSerializer
|
|
||||||
|
|
||||||
|
|
||||||
class ProxyLogListView(AdminUserRequiredMixin, ListView):
|
|
||||||
model = ProxyLog
|
|
||||||
template_name = 'audits/proxy_log_online_list.html'
|
|
||||||
context_object_name = 'proxy_log_list'
|
|
||||||
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
|
|
||||||
keyword = username = hostname = system_user = date_from_s = date_to_s = ''
|
|
||||||
ordering = ['is_finished', '-id']
|
|
||||||
date_format = '%m/%d/%Y'
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
date_now = timezone.localtime(timezone.now())
|
|
||||||
date_to_default = date_now.strftime(self.date_format)
|
|
||||||
date_from_default = (date_now-timezone.timedelta(7))\
|
|
||||||
.strftime(self.date_format)
|
|
||||||
|
|
||||||
self.queryset = super(ProxyLogListView, self).get_queryset()
|
|
||||||
self.keyword = self.request.GET.get('keyword', '')
|
|
||||||
self.username = self.request.GET.get('username')
|
|
||||||
self.ip = self.request.GET.get('ip')
|
|
||||||
self.system_user = self.request.GET.get('system_user')
|
|
||||||
self.date_from_s = self.request.GET.get('date_from', date_from_default)
|
|
||||||
self.date_to_s = self.request.GET.get('date_to', date_to_default)
|
|
||||||
|
|
||||||
filter_kwargs = {}
|
|
||||||
if self.date_from_s:
|
|
||||||
date_from = datetime.strptime(self.date_from_s, self.date_format)
|
|
||||||
date_from = date_from.replace(tzinfo=timezone.get_current_timezone())
|
|
||||||
filter_kwargs['date_start__gt'] = date_from
|
|
||||||
if self.date_to_s:
|
|
||||||
date_to = timezone.datetime.strptime(
|
|
||||||
self.date_to_s + ' 23:59:59', '%m/%d/%Y %H:%M:%S')
|
|
||||||
date_to = date_to.replace(tzinfo=timezone.get_current_timezone())
|
|
||||||
filter_kwargs['date_start__lt'] = date_to
|
|
||||||
if self.username:
|
|
||||||
filter_kwargs['user'] = self.username
|
|
||||||
if self.ip:
|
|
||||||
filter_kwargs['asset'] = self.ip
|
|
||||||
if self.system_user:
|
|
||||||
filter_kwargs['system_user'] = self.system_user
|
|
||||||
if self.keyword:
|
|
||||||
self.queryset = self.queryset.filter(
|
|
||||||
Q(user__icontains=self.keyword) |
|
|
||||||
Q(asset__icontains=self.keyword) |
|
|
||||||
Q(system_user__icontains=self.keyword)).distinct()
|
|
||||||
if filter_kwargs:
|
|
||||||
self.queryset = self.queryset.filter(**filter_kwargs)
|
|
||||||
return self.queryset
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
|
||||||
context = {
|
|
||||||
'app': _('Audits'),
|
|
||||||
'action': _('Proxy log list'),
|
|
||||||
'user_list': set(
|
|
||||||
list(ProxyLog.objects.values_list('user', flat=True))),
|
|
||||||
'asset_list': set(
|
|
||||||
list(ProxyLog.objects.values_list('asset', flat=True))),
|
|
||||||
'system_user_list': set(
|
|
||||||
list(ProxyLog.objects.values_list('system_user', flat=True))),
|
|
||||||
'keyword': self.keyword,
|
|
||||||
'date_from': self.date_from_s,
|
|
||||||
'date_to': self.date_to_s,
|
|
||||||
'username': self.username,
|
|
||||||
'ip': self.ip,
|
|
||||||
'system_user': self.system_user,
|
|
||||||
}
|
|
||||||
kwargs.update(context)
|
|
||||||
return super(ProxyLogListView, self).get_context_data(**kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class ProxyLogOfflineListView(ProxyLogListView):
|
|
||||||
template_name = 'audits/proxy_log_offline_list.html'
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
queryset = super(ProxyLogOfflineListView, self).get_queryset()
|
|
||||||
queryset = queryset.filter(is_finished=True)
|
|
||||||
return queryset
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
|
||||||
context = {
|
|
||||||
'action': _('Proxy log offline list'),
|
|
||||||
}
|
|
||||||
kwargs.update(context)
|
|
||||||
return super(ProxyLogOfflineListView, self).get_context_data(**kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class ProxyLogOnlineListView(ProxyLogListView):
|
|
||||||
template_name = 'audits/proxy_log_online_list.html'
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
queryset = super(ProxyLogOnlineListView, self).get_queryset()
|
|
||||||
queryset = queryset.filter(is_finished=False)
|
|
||||||
return queryset
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
|
||||||
context = {
|
|
||||||
'action': _('Proxy log online list'),
|
|
||||||
}
|
|
||||||
kwargs.update(context)
|
|
||||||
return super(ProxyLogOnlineListView, self).get_context_data(**kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class ProxyLogDetailView(AdminUserRequiredMixin,
|
|
||||||
SingleObjectMixin,
|
|
||||||
ListView):
|
|
||||||
template_name = 'audits/proxy_log_detail.html'
|
|
||||||
context_object_name = 'proxy_log'
|
|
||||||
object = ''
|
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
|
||||||
self.object = self.get_object(queryset=ProxyLog.objects.all())
|
|
||||||
return super(ProxyLogDetailView, self).get(request, *args, **kwargs)
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
return list(command_store.filter(proxy_log_id=self.object.id))
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
|
||||||
context = {
|
|
||||||
'app': 'Audits',
|
|
||||||
'action': 'Proxy log detail',
|
|
||||||
}
|
|
||||||
kwargs.update(context)
|
|
||||||
return super(ProxyLogDetailView, self).get_context_data(**kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
# class ProxyLogCommandsListView(AdminUserRequiredMixin,
|
|
||||||
# SingleObjectMixin,
|
|
||||||
# ListView):
|
|
||||||
# template_name = 'audits/proxy_log_commands_list_modal.html'
|
|
||||||
# object = ''
|
|
||||||
#
|
|
||||||
# def get(self, request, *args, **kwargs):
|
|
||||||
# self.object = self.get_object(queryset=ProxyLog.objects.all())
|
|
||||||
# return super(ProxyLogCommandsListView, self).\
|
|
||||||
# get(request, *args, **kwargs)
|
|
||||||
#
|
|
||||||
# def get_queryset(self):
|
|
||||||
# return list(self.object.command_log.all())
|
|
||||||
|
|
||||||
|
|
||||||
class CommandLogListView(AdminUserRequiredMixin, ListView):
|
|
||||||
template_name = 'audits/command_log_list.html'
|
|
||||||
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
|
|
||||||
context_object_name = 'command_list'
|
|
||||||
username = ip = system_user = command = date_from_s = date_to_s = ''
|
|
||||||
date_format = '%m/%d/%Y'
|
|
||||||
ordering = ['-id']
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
date_now = timezone.localtime(timezone.now())
|
|
||||||
date_to_default = date_now.strftime(self.date_format)
|
|
||||||
date_from_default = (date_now - timezone.timedelta(7)) \
|
|
||||||
.strftime(self.date_format)
|
|
||||||
self.command = self.request.GET.get('command', '')
|
|
||||||
self.username = self.request.GET.get('username')
|
|
||||||
self.ip = self.request.GET.get('ip')
|
|
||||||
self.system_user = self.request.GET.get('system_user')
|
|
||||||
self.date_from_s = \
|
|
||||||
self.request.GET.get('date_from', date_from_default)
|
|
||||||
self.date_to_s = \
|
|
||||||
self.request.GET.get('date_to', date_to_default)
|
|
||||||
|
|
||||||
filter_kwargs = {}
|
|
||||||
if self.date_from_s:
|
|
||||||
date_from = datetime.strptime(self.date_from_s, self.date_format)\
|
|
||||||
.replace(tzinfo=timezone.get_current_timezone())
|
|
||||||
# date_from_utc = date_from.astimezone(pytz.utc)
|
|
||||||
date_from_ts = time.mktime(date_from.timetuple())
|
|
||||||
filter_kwargs['date_from_ts'] = date_from_ts
|
|
||||||
if self.date_to_s:
|
|
||||||
date_to = datetime.strptime(
|
|
||||||
self.date_to_s + ' 23:59:59', '%m/%d/%Y %H:%M:%S')\
|
|
||||||
.replace(tzinfo=timezone.get_current_timezone())
|
|
||||||
date_to_ts = time.mktime(date_to.timetuple())
|
|
||||||
filter_kwargs['date_to_ts'] = date_to_ts
|
|
||||||
if self.username:
|
|
||||||
filter_kwargs['user'] = self.username
|
|
||||||
if self.ip:
|
|
||||||
filter_kwargs['asset'] = self.ip
|
|
||||||
if self.system_user:
|
|
||||||
filter_kwargs['system_user'] = self.system_user
|
|
||||||
if self.command:
|
|
||||||
filter_kwargs['command'] = self.command
|
|
||||||
self.queryset = command_store.filter(**filter_kwargs).order_by(*self.ordering)
|
|
||||||
return self.queryset
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
|
||||||
context = {
|
|
||||||
'app': _('Audits'),
|
|
||||||
'action': _('Command log list'),
|
|
||||||
'user_list': User.objects.all().order_by('username'),
|
|
||||||
'asset_list': Asset.objects.all().order_by('ip'),
|
|
||||||
'system_user_list': SystemUser.objects.all().order_by('username'),
|
|
||||||
'command': self.command,
|
|
||||||
'date_from': self.date_from_s,
|
|
||||||
'date_to': self.date_to_s,
|
|
||||||
'username': self.username,
|
|
||||||
'ip': self.ip,
|
|
||||||
'system_user': self.system_user,
|
|
||||||
}
|
|
||||||
kwargs.update(context)
|
|
||||||
return super(CommandLogListView, self).get_context_data(**kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class LoginLogListView(AdminUserRequiredMixin, ListView):
|
|
||||||
model = LoginLog
|
|
||||||
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
|
|
||||||
template_name = 'audits/login_log_list.html'
|
|
||||||
context_object_name = 'login_log_list'
|
|
||||||
keyword = username = date_from_s = date_to_s = ''
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
date_now = timezone.localtime(timezone.now())
|
|
||||||
now_s = date_now.strftime('%m/%d/%Y')
|
|
||||||
seven_days_ago_s = (date_now - timezone.timedelta(7))\
|
|
||||||
.strftime('%m/%d/%Y')
|
|
||||||
self.queryset = super(LoginLogListView, self).get_queryset()
|
|
||||||
self.keyword = keyword = self.request.GET.get('keyword', '')
|
|
||||||
self.username = username = self.request.GET.get('username', '')
|
|
||||||
self.date_from_s = date_from_s = self.request.GET.get(
|
|
||||||
'date_from', '%s' % seven_days_ago_s)
|
|
||||||
self.date_to_s = date_to_s = self.request.GET.get(
|
|
||||||
'date_to', '%s' % now_s)
|
|
||||||
|
|
||||||
if date_from_s:
|
|
||||||
date_from = timezone.datetime.strptime(date_from_s, '%m/%d/%Y')
|
|
||||||
self.queryset = self.queryset.filter(date_login__gt=date_from)
|
|
||||||
if date_to_s:
|
|
||||||
date_to = timezone.datetime.strptime(
|
|
||||||
date_to_s + ' 23:59:59', '%m/%d/%Y %H:%M:%S')
|
|
||||||
self.queryset = self.queryset.filter(date_login__lt=date_to)
|
|
||||||
if username:
|
|
||||||
self.queryset = self.queryset.filter(username=username)
|
|
||||||
if keyword:
|
|
||||||
self.queryset = self.queryset.filter(
|
|
||||||
Q(username__contains=keyword) |
|
|
||||||
Q(name__icontains=keyword) |
|
|
||||||
Q(login_ip=keyword)).distinct()
|
|
||||||
return self.queryset
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
|
||||||
context = {
|
|
||||||
'app': _('Audits'),
|
|
||||||
'action': _('Proxy log list'),
|
|
||||||
'user_list': User.objects.all().order_by('username'),
|
|
||||||
'keyword': self.keyword,
|
|
||||||
'date_from': self.date_from_s,
|
|
||||||
'date_to': self.date_to_s,
|
|
||||||
'username': self.username,
|
|
||||||
}
|
|
||||||
kwargs.update(context)
|
|
||||||
return super(LoginLogListView, self).get_context_data(**kwargs)
|
|
|
@ -3,7 +3,6 @@
|
||||||
from django import template
|
from django import template
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.html import escape
|
from django.utils.html import escape
|
||||||
from audits.backends import command_store
|
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
|
|
||||||
|
@ -70,6 +69,6 @@ def to_html(s):
|
||||||
return escape(s).replace('\n', '<br />')
|
return escape(s).replace('\n', '<br />')
|
||||||
|
|
||||||
|
|
||||||
@register.filter
|
# @register.filter
|
||||||
def proxy_log_commands(log_id):
|
# def proxy_log_commands(log_id):
|
||||||
return command_store.filter(proxy_log_id=log_id)
|
# return 1
|
||||||
|
|
|
@ -1,4 +1,2 @@
|
||||||
from __future__ import absolute_import, unicode_literals
|
from __future__ import absolute_import, unicode_literals
|
||||||
|
|
||||||
from django.shortcuts import render
|
|
||||||
from django.views.generic import TemplateView
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ from django.shortcuts import HttpResponse
|
||||||
|
|
||||||
|
|
||||||
DEMO_MODE = os.environ.get("DEMO_MODE", "")
|
DEMO_MODE = os.environ.get("DEMO_MODE", "")
|
||||||
SAFE_URL = r'^/users/login|^/api/terminal/v1/.*|/api/audits/.*|/api/users/v1/auth/|/api/users/v1/profile/'
|
SAFE_URL = r'^/users/login|^/api/terminal/v1/.*|/api/terminal/.*|/api/users/v1/auth/|/api/users/v1/profile/'
|
||||||
|
|
||||||
|
|
||||||
class TimezoneMiddleware(MiddlewareMixin):
|
class TimezoneMiddleware(MiddlewareMixin):
|
||||||
|
|
|
@ -59,7 +59,7 @@ INSTALLED_APPS = [
|
||||||
'assets.apps.AssetsConfig',
|
'assets.apps.AssetsConfig',
|
||||||
'perms.apps.PermsConfig',
|
'perms.apps.PermsConfig',
|
||||||
'ops.apps.OpsConfig',
|
'ops.apps.OpsConfig',
|
||||||
'audits.apps.AuditsConfig',
|
# 'audits.apps.AuditsConfig',
|
||||||
'common.apps.CommonConfig',
|
'common.apps.CommonConfig',
|
||||||
'terminal.apps.ApplicationsConfig',
|
'terminal.apps.ApplicationsConfig',
|
||||||
'rest_framework',
|
'rest_framework',
|
||||||
|
@ -364,7 +364,7 @@ CAPTCHA_NOISE_FUNCTIONS = ('captcha.helpers.noise_dots',)
|
||||||
CAPTCHA_TEST_MODE = CONFIG.CAPTCHA_TEST_MODE
|
CAPTCHA_TEST_MODE = CONFIG.CAPTCHA_TEST_MODE
|
||||||
|
|
||||||
COMMAND_STORE_BACKEND = 'terminal.backends.command.db'
|
COMMAND_STORE_BACKEND = 'terminal.backends.command.db'
|
||||||
RECORD_STORE_BACKEND = 'terminal.backends.replay.db'
|
REPLAY_STORE_BACKEND = 'terminal.backends.replay.db'
|
||||||
|
|
||||||
|
|
||||||
# Django bootstrap3 setting, more see http://django-bootstrap3.readthedocs.io/en/latest/settings.html
|
# Django bootstrap3 setting, more see http://django-bootstrap3.readthedocs.io/en/latest/settings.html
|
||||||
|
|
|
@ -16,7 +16,7 @@ urlpatterns = [
|
||||||
url(r'^users/', include('users.urls.views_urls', namespace='users')),
|
url(r'^users/', include('users.urls.views_urls', namespace='users')),
|
||||||
url(r'^assets/', include('assets.urls.views_urls', namespace='assets')),
|
url(r'^assets/', include('assets.urls.views_urls', namespace='assets')),
|
||||||
url(r'^perms/', include('perms.urls.views_urls', namespace='perms')),
|
url(r'^perms/', include('perms.urls.views_urls', namespace='perms')),
|
||||||
url(r'^audits/', include('audits.urls.views_urls', namespace='audits')),
|
# url(r'^audits/', include('audits.urls.views_urls', namespace='audits')),
|
||||||
url(r'^terminal/', include('terminal.urls.views_urls', namespace='terminal')),
|
url(r'^terminal/', include('terminal.urls.views_urls', namespace='terminal')),
|
||||||
url(r'^ops/', include('ops.urls.view_urls', namespace='ops')),
|
url(r'^ops/', include('ops.urls.view_urls', namespace='ops')),
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ urlpatterns = [
|
||||||
url(r'^api/users/', include('users.urls.api_urls', namespace='api-users')),
|
url(r'^api/users/', include('users.urls.api_urls', namespace='api-users')),
|
||||||
url(r'^api/assets/', include('assets.urls.api_urls', namespace='api-assets')),
|
url(r'^api/assets/', include('assets.urls.api_urls', namespace='api-assets')),
|
||||||
url(r'^api/perms/', include('perms.urls.api_urls', namespace='api-perms')),
|
url(r'^api/perms/', include('perms.urls.api_urls', namespace='api-perms')),
|
||||||
url(r'^api/audits/', include('audits.urls.api_urls', namespace='api-audits')),
|
# url(r'^api/audits/', include('audits.urls.api_urls', namespace='api-audits')),
|
||||||
url(r'^api/terminal/', include('terminal.urls.api_urls', namespace='api-terminal')),
|
url(r'^api/terminal/', include('terminal.urls.api_urls', namespace='api-terminal')),
|
||||||
url(r'^api/ops/', include('ops.urls.api_urls', namespace='api-ops')),
|
url(r'^api/ops/', include('ops.urls.api_urls', namespace='api-ops')),
|
||||||
url(r'^captcha/', include('captcha.urls')),
|
url(r'^captcha/', include('captcha.urls')),
|
||||||
|
|
|
@ -6,70 +6,146 @@ from django.shortcuts import redirect
|
||||||
|
|
||||||
from users.models import User
|
from users.models import User
|
||||||
from assets.models import Asset
|
from assets.models import Asset
|
||||||
from audits.models import ProxyLog
|
from terminal.models import Session
|
||||||
|
|
||||||
|
|
||||||
class IndexView(LoginRequiredMixin, TemplateView):
|
class IndexView(LoginRequiredMixin, TemplateView):
|
||||||
template_name = 'index.html'
|
template_name = 'index.html'
|
||||||
|
|
||||||
|
session_week = None
|
||||||
|
session_month = None
|
||||||
|
session_month_dates = []
|
||||||
|
session_month_dates_archive = []
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
if not request.user.is_superuser:
|
if not request.user.is_superuser:
|
||||||
return redirect('assets:user-asset-list')
|
return redirect('assets:user-asset-list')
|
||||||
return super(IndexView, self).get(request, *args, **kwargs)
|
return super(IndexView, self).get(request, *args, **kwargs)
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
@staticmethod
|
||||||
seven_days_ago = timezone.now() - timezone.timedelta(days=7)
|
def get_user_count():
|
||||||
month_ago = timezone.now() - timezone.timedelta(days=30)
|
return User.objects.filter(role__in=('Admin', 'User')).count()
|
||||||
proxy_log_seven_days = ProxyLog.objects.filter(date_start__gt=seven_days_ago, is_failed=False)
|
|
||||||
proxy_log_month = ProxyLog.objects.filter(date_start__gt=month_ago, is_failed=False)
|
@staticmethod
|
||||||
month_dates = proxy_log_month.dates('date_start', 'day')
|
def get_asset_count():
|
||||||
month_total_visit = [ProxyLog.objects.filter(date_start__date=d) for d in month_dates]
|
return Asset.objects.all().count()
|
||||||
month_str = [d.strftime('%m-%d') for d in month_dates] or ['0']
|
|
||||||
month_total_visit_count = [p.count() for p in month_total_visit] or [0]
|
@staticmethod
|
||||||
month_user = [p.values('user').distinct().count() for p in month_total_visit] or [0]
|
def get_online_user_count():
|
||||||
month_asset = [p.values('asset').distinct().count() for p in month_total_visit] or [0]
|
return len(set(Session.objects.filter(is_finished=False).values_list('user', flat=True)))
|
||||||
month_user_active = User.objects.filter(last_login__gt=month_ago).count()
|
|
||||||
month_user_inactive = User.objects.filter(last_login__lt=month_ago).count()
|
@staticmethod
|
||||||
month_user_disabled = User.objects.filter(is_active=False).count()
|
def get_online_session_count():
|
||||||
month_asset_active = proxy_log_month.values('asset').distinct().count()
|
return Session.objects.filter(is_finished=False).count()
|
||||||
month_asset_inactive = Asset.objects.all().count() - month_asset_active
|
|
||||||
month_asset_disabled = Asset.objects.filter(is_active=False).count()
|
def get_top5_user_a_week(self):
|
||||||
week_asset_hot_ten = list(proxy_log_seven_days.values('asset').annotate(total=Count('asset')).order_by('-total')[:10])
|
return self.session_week.values('user').annotate(total=Count('user')).order_by('-total')[:5]
|
||||||
for p in week_asset_hot_ten:
|
|
||||||
last_login = ProxyLog.objects.filter(asset=p['asset']).order_by('date_start').last()
|
def get_week_login_user_count(self):
|
||||||
p['last'] = last_login
|
return self.session_week.values('user').distinct().count()
|
||||||
last_login_ten = ProxyLog.objects.all().order_by('-date_start')[:10]
|
|
||||||
for p in last_login_ten:
|
def get_week_login_asset_count(self):
|
||||||
|
return self.session_week.values('asset').distinct().count()
|
||||||
|
|
||||||
|
def get_month_day_metrics(self):
|
||||||
|
month_str = [d.strftime('%m-%d') for d in self.session_month_dates] or ['0']
|
||||||
|
return month_str
|
||||||
|
|
||||||
|
def get_month_login_metrics(self):
|
||||||
|
return [self.session_month.filter(date_start__date=d).count()
|
||||||
|
for d in self.session_month_dates]
|
||||||
|
|
||||||
|
def get_month_active_user_metrics(self):
|
||||||
|
if self.session_month_dates_archive:
|
||||||
|
return [q.values('user').distinct().count()
|
||||||
|
for q in self.session_month_dates_archive]
|
||||||
|
else:
|
||||||
|
return [0]
|
||||||
|
|
||||||
|
def get_month_active_asset_metrics(self):
|
||||||
|
if self.session_month_dates_archive:
|
||||||
|
return [q.values('asset').distinct().count()
|
||||||
|
for q in self.session_month_dates_archive]
|
||||||
|
else:
|
||||||
|
return [0]
|
||||||
|
|
||||||
|
def get_month_active_user_total(self):
|
||||||
|
return self.session_month.values('user').distinct().count()
|
||||||
|
|
||||||
|
def get_month_inactive_user_total(self):
|
||||||
|
return User.objects.all().count() - self.get_month_active_user_total()
|
||||||
|
|
||||||
|
def get_month_active_asset_total(self):
|
||||||
|
return self.session_month.values('asset').distinct().count()
|
||||||
|
|
||||||
|
def get_month_inactive_asset_total(self):
|
||||||
|
return Asset.objects.all().count() - self.get_month_active_asset_total()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_user_disabled_total():
|
||||||
|
return User.objects.filter(is_active=False).count()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_asset_disabled_total():
|
||||||
|
return Asset.objects.filter(is_active=False).count()
|
||||||
|
|
||||||
|
def get_week_top10_asset(self):
|
||||||
|
assets = list(self.session_week.values('asset').annotate(total=Count('asset')).order_by('-total')[:10])
|
||||||
|
for asset in assets:
|
||||||
|
last_login = self.session_week.filter(asset=asset["asset"]).order_by('date_start').last()
|
||||||
|
asset['last'] = last_login
|
||||||
|
print(asset)
|
||||||
|
return assets
|
||||||
|
|
||||||
|
def get_week_top10_user(self):
|
||||||
|
users = list(self.session_week.values('user').annotate(
|
||||||
|
total=Count('asset')).order_by('-total')[:10])
|
||||||
|
for user in users:
|
||||||
|
last_login = self.session_week.filter(user=user["user"]).order_by('date_start').last()
|
||||||
|
user['last'] = last_login
|
||||||
|
return users
|
||||||
|
|
||||||
|
def get_last10_sessions(self):
|
||||||
|
sessions = self.session_week.order_by('-date_start')[:10]
|
||||||
|
for session in sessions:
|
||||||
try:
|
try:
|
||||||
p.avatar_url = User.objects.get(username=p.user).avatar_url()
|
session.avatar_url = User.objects.get(username=session.user).avatar_url()
|
||||||
except User.DoesNotExist:
|
except User.DoesNotExist:
|
||||||
p.avatar_url = User.objects.first().avatar_url()
|
session.avatar_url = User.objects.first().avatar_url()
|
||||||
week_user_hot_ten = list(proxy_log_seven_days.values('user').annotate(total=Count('user')).order_by('-total')[:10])
|
return sessions
|
||||||
for p in week_user_hot_ten:
|
|
||||||
last_login = ProxyLog.objects.filter(user=p['user']).order_by('date_start').last()
|
def get_context_data(self, **kwargs):
|
||||||
p['last'] = last_login
|
week_ago = timezone.now() - timezone.timedelta(weeks=1)
|
||||||
|
month_ago = timezone.now() - timezone.timedelta(days=30)
|
||||||
|
self.session_week = Session.objects.filter(date_start__gt=week_ago)
|
||||||
|
self.session_month = Session.objects.filter(date_start__gt=month_ago)
|
||||||
|
self.session_month_dates = self.session_month.dates('date_start', 'day')
|
||||||
|
self.session_month_dates_archive = [
|
||||||
|
self.session_month.filter(date_start__date=d)
|
||||||
|
for d in self.session_month_dates
|
||||||
|
]
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
'assets_count': Asset.objects.count(),
|
'assets_count': self.get_asset_count(),
|
||||||
'users_count': User.objects.filter(role__in=('Admin', 'User')).count(),
|
'users_count': self.get_user_count(),
|
||||||
'online_user_count': ProxyLog.objects.filter(is_finished=False).values('user').distinct().count(),
|
'online_user_count': self.get_online_user_count(),
|
||||||
'online_asset_count': ProxyLog.objects.filter(is_finished=False).values('asset').distinct().count(),
|
'online_asset_count': self.get_online_session_count(),
|
||||||
'user_visit_count_weekly': proxy_log_seven_days.values('user').distinct().count(),
|
'user_visit_count_weekly': self.get_week_login_user_count(),
|
||||||
'asset_visit_count_weekly': proxy_log_seven_days.count(),
|
'asset_visit_count_weekly': self.get_week_login_asset_count(),
|
||||||
'user_visit_count_top_five': proxy_log_seven_days.values('user').annotate(total=Count('user')).order_by('-total')[:5],
|
'user_visit_count_top_five': self.get_top5_user_a_week(),
|
||||||
'month_str': month_str,
|
'month_str': self.get_month_day_metrics(),
|
||||||
'month_total_visit_count': month_total_visit_count,
|
'month_total_visit_count': self.get_month_login_metrics(),
|
||||||
'month_user': month_user,
|
'month_user': self.get_month_active_user_metrics(),
|
||||||
'mouth_asset': month_asset,
|
'mouth_asset': self.get_month_active_asset_metrics(),
|
||||||
'month_user_active': month_user_active,
|
'month_user_active': self.get_month_active_user_total(),
|
||||||
'month_user_inactive': month_user_inactive,
|
'month_user_inactive': self.get_month_inactive_user_total(),
|
||||||
'month_user_disabled': month_user_disabled,
|
'month_user_disabled': self.get_user_disabled_total(),
|
||||||
'month_asset_active': month_asset_active,
|
'month_asset_active': self.get_month_active_asset_total(),
|
||||||
'month_asset_inactive': month_asset_inactive,
|
'month_asset_inactive': self.get_month_inactive_asset_total(),
|
||||||
'month_asset_disabled': month_asset_disabled,
|
'month_asset_disabled': self.get_asset_disabled_total(),
|
||||||
'week_asset_hot_ten': week_asset_hot_ten,
|
'week_asset_hot_ten': self.get_week_top10_asset(),
|
||||||
'last_login_ten': last_login_ten,
|
'last_login_ten': self.get_last10_sessions(),
|
||||||
'week_user_hot_ten': week_user_hot_ten,
|
'week_user_hot_ten': self.get_week_top10_user(),
|
||||||
}
|
}
|
||||||
|
|
||||||
kwargs.update(context)
|
kwargs.update(context)
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
<h5>在线用户</h5>
|
<h5>在线用户</h5>
|
||||||
</div>
|
</div>
|
||||||
<div class="ibox-content">
|
<div class="ibox-content">
|
||||||
<h1 class="no-margins"><a href="{% url 'audits:proxy-log-online-list' %}"> <span id="online_users"></span>{{ online_user_count }}</a></h1>
|
<h1 class="no-margins"><a href="{% url 'terminal:session-online-list' %}"> <span id="online_users"></span>{{ online_user_count }}</a></h1>
|
||||||
<small>Online user</small>
|
<small>Online user</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -45,11 +45,11 @@
|
||||||
<div class="ibox float-e-margins">
|
<div class="ibox float-e-margins">
|
||||||
<div class="ibox-title">
|
<div class="ibox-title">
|
||||||
<span class="label label-danger pull-right">Connected</span>
|
<span class="label label-danger pull-right">Connected</span>
|
||||||
<h5>已连接服务器</h5>
|
<h5>在线会话</h5>
|
||||||
</div>
|
</div>
|
||||||
<div class="ibox-content">
|
<div class="ibox-content">
|
||||||
<h1 class="no-margins"><a href="{% url 'audits:proxy-log-online-list' %}"> <span id="online_hosts"></span>{{ online_asset_count }}</a></h1>
|
<h1 class="no-margins"><a href="{% url 'terminal:session-online-list' %}"> <span id="online_hosts"></span>{{ online_asset_count }}</a></h1>
|
||||||
<small>Connected host</small>
|
<small>Online sessions</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
import base64
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
import copy
|
import copy
|
||||||
import logging
|
import logging
|
||||||
import tarfile
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from rest_framework import viewsets, serializers
|
from rest_framework import viewsets, serializers
|
||||||
|
@ -18,7 +16,7 @@ from common.utils import get_object_or_none
|
||||||
from .models import Terminal, Status, Session, Task
|
from .models import Terminal, Status, Session, Task
|
||||||
from .serializers import TerminalSerializer, StatusSerializer, \
|
from .serializers import TerminalSerializer, StatusSerializer, \
|
||||||
SessionSerializer, TaskSerializer
|
SessionSerializer, TaskSerializer
|
||||||
from .hands import IsSuperUserOrAppUser, IsAppUser, ProxyLog, \
|
from .hands import IsSuperUserOrAppUser, IsAppUser, \
|
||||||
IsSuperUserOrAppUserOrUserReadonly
|
IsSuperUserOrAppUserOrUserReadonly
|
||||||
from .backends import get_command_store, get_replay_store, SessionCommandSerializer
|
from .backends import get_command_store, get_replay_store, SessionCommandSerializer
|
||||||
|
|
||||||
|
@ -221,7 +219,9 @@ class CommandViewSet(viewsets.ViewSet):
|
||||||
else:
|
else:
|
||||||
return Response("Save error", status=500)
|
return Response("Save error", status=500)
|
||||||
else:
|
else:
|
||||||
return Response({"msg": "Not valid: {}".format(serializer.errors)}, status=401)
|
msg = "Not valid: {}".format(serializer.errors)
|
||||||
|
logger.error(msg)
|
||||||
|
return Response({"msg": msg}, status=401)
|
||||||
|
|
||||||
def list(self, request, *args, **kwargs):
|
def list(self, request, *args, **kwargs):
|
||||||
queryset = list(self.command_store.all())
|
queryset = list(self.command_store.all())
|
||||||
|
|
|
@ -12,6 +12,6 @@ def get_command_store():
|
||||||
|
|
||||||
|
|
||||||
def get_replay_store():
|
def get_replay_store():
|
||||||
replay_engine = import_module(settings.RECORD_STORE_BACKEND)
|
replay_engine = import_module(settings.REPLAY_STORE_BACKEND)
|
||||||
replay_store = replay_engine.RecordStore()
|
replay_store = replay_engine.ReplayStore()
|
||||||
return replay_store
|
return replay_store
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
import abc
|
import abc
|
||||||
|
|
||||||
|
|
||||||
class RecordBase(object):
|
class ReplayBase(object):
|
||||||
__metaclass__ = abc.ABCMeta
|
__metaclass__ = abc.ABCMeta
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
|
|
|
@ -1,31 +1,8 @@
|
||||||
# ~*~ coding: utf-8 ~*~
|
# ~*~ coding: utf-8 ~*~
|
||||||
|
|
||||||
from .base import RecordBase
|
from .base import ReplayBase
|
||||||
from audits.models import RecordLog
|
|
||||||
|
|
||||||
|
|
||||||
class RecordStore(RecordBase):
|
class ReplayStore(ReplayBase):
|
||||||
model = RecordLog
|
pass
|
||||||
queryset = []
|
|
||||||
|
|
||||||
def save(self, proxy_log_id, output, timestamp):
|
|
||||||
return self.model.objects.create(
|
|
||||||
proxy_log_id=proxy_log_id, output=output, timestamp=timestamp
|
|
||||||
)
|
|
||||||
|
|
||||||
def filter(self, date_from_ts=None, proxy_log_id=''):
|
|
||||||
filter_kwargs = {}
|
|
||||||
|
|
||||||
if date_from_ts:
|
|
||||||
filter_kwargs['timestamp__gte'] = date_from_ts
|
|
||||||
if proxy_log_id:
|
|
||||||
filter_kwargs['proxy_log_id'] = proxy_log_id
|
|
||||||
|
|
||||||
if filter_kwargs:
|
|
||||||
self.queryset = self.model.objects.filter(**filter_kwargs)
|
|
||||||
return self.queryset
|
|
||||||
|
|
||||||
def all(self):
|
|
||||||
"""返回所有数据"""
|
|
||||||
return self.model.objects.all()
|
|
||||||
|
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
# ~*~ coding: utf-8 ~*~
|
|
||||||
import base64
|
|
||||||
from rest_framework import serializers
|
|
||||||
from audits.models import RecordLog
|
|
||||||
from audits.backends import record_store
|
|
||||||
|
|
||||||
|
|
||||||
class RecordSerializer(serializers.ModelSerializer):
|
|
||||||
"""使用这个类作为基础Command Log Serializer类, 用来序列化"""
|
|
||||||
class Meta:
|
|
||||||
model = RecordLog
|
|
||||||
fields = '__all__'
|
|
||||||
|
|
||||||
def create(self, validated_data):
|
|
||||||
try:
|
|
||||||
output = validated_data['output']
|
|
||||||
validated_data['output'] = base64.b64decode(output)
|
|
||||||
except IndexError:
|
|
||||||
pass
|
|
||||||
return record_store.save(**dict(validated_data))
|
|
|
@ -4,5 +4,4 @@
|
||||||
from users.models import User
|
from users.models import User
|
||||||
from users.permissions import IsSuperUserOrAppUser, IsAppUser, \
|
from users.permissions import IsSuperUserOrAppUser, IsAppUser, \
|
||||||
IsSuperUserOrAppUserOrUserReadonly
|
IsSuperUserOrAppUserOrUserReadonly
|
||||||
from audits.models import ProxyLog
|
|
||||||
from users.utils import AdminUserRequiredMixin
|
from users.utils import AdminUserRequiredMixin
|
|
@ -13,6 +13,7 @@ ASSETS_CACHE_KEY = "terminal__session__assets"
|
||||||
USERS_CACHE_KEY = "terminal__session__users"
|
USERS_CACHE_KEY = "terminal__session__users"
|
||||||
SYSTEM_USER_CACHE_KEY = "terminal__session__system_users"
|
SYSTEM_USER_CACHE_KEY = "terminal__session__system_users"
|
||||||
CACHE_REFRESH_INTERVAL = 10
|
CACHE_REFRESH_INTERVAL = 10
|
||||||
|
RUNNING = False
|
||||||
|
|
||||||
|
|
||||||
# Todo: 定期清理上报history
|
# Todo: 定期清理上报history
|
||||||
|
@ -46,7 +47,16 @@ def set_cache():
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
global RUNNING
|
||||||
|
if RUNNING:
|
||||||
|
return
|
||||||
|
threads = []
|
||||||
thread = threading.Thread(target=set_cache)
|
thread = threading.Thread(target=set_cache)
|
||||||
thread.start()
|
threads.append(thread)
|
||||||
|
|
||||||
|
for t in threads:
|
||||||
|
t.daemon = True
|
||||||
|
t.start()
|
||||||
|
RUNNING = True
|
||||||
|
|
||||||
main()
|
main()
|
||||||
|
|
|
@ -9,7 +9,7 @@ from rest_framework_bulk import BulkModelViewSet
|
||||||
from django_filters.rest_framework import DjangoFilterBackend
|
from django_filters.rest_framework import DjangoFilterBackend
|
||||||
|
|
||||||
from . import serializers
|
from . import serializers
|
||||||
from .hands import write_login_log_async
|
from .tasks import write_login_log_async
|
||||||
from .models import User, UserGroup
|
from .models import User, UserGroup
|
||||||
from .permissions import IsSuperUser, IsValidUser, IsCurrentUserOrReadOnly
|
from .permissions import IsSuperUser, IsValidUser, IsCurrentUserOrReadOnly
|
||||||
from .utils import check_user_valid, generate_token
|
from .utils import check_user_valid, generate_token
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
:license: GPL v2, see LICENSE for more details.
|
:license: GPL v2, see LICENSE for more details.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from terminal.models import Terminal
|
# from terminal.models import Terminal
|
||||||
from audits.tasks import write_login_log_async
|
# from audits.tasks import write_login_log_async
|
||||||
from users.models import User
|
# from users.models import User
|
||||||
# from perms.models import AssetPermission
|
# from perms.models import AssetPermission
|
||||||
# from perms.utils import get_user_granted_assets, get_user_granted_asset_groups
|
# from perms.utils import get_user_granted_assets, get_user_granted_asset_groups
|
||||||
|
|
|
@ -8,7 +8,7 @@ from django.utils.translation import ugettext_lazy as _
|
||||||
from rest_framework.authtoken.models import Token
|
from rest_framework.authtoken.models import Token
|
||||||
from . import User
|
from . import User
|
||||||
|
|
||||||
__all__ = ['AccessKey', 'PrivateToken']
|
__all__ = ['AccessKey', 'PrivateToken', 'LoginLog']
|
||||||
|
|
||||||
|
|
||||||
class AccessKey(models.Model):
|
class AccessKey(models.Model):
|
||||||
|
@ -34,3 +34,22 @@ class PrivateToken(Token):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _('Private Token')
|
verbose_name = _('Private Token')
|
||||||
|
|
||||||
|
|
||||||
|
class LoginLog(models.Model):
|
||||||
|
LOGIN_TYPE_CHOICE = (
|
||||||
|
('W', 'Web'),
|
||||||
|
('ST', 'SSH Terminal'),
|
||||||
|
('WT', 'Web Terminal')
|
||||||
|
)
|
||||||
|
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
||||||
|
username = models.CharField(max_length=20, verbose_name=_('Username'))
|
||||||
|
type = models.CharField(choices=LOGIN_TYPE_CHOICE, max_length=2, verbose_name=_('Login type'))
|
||||||
|
ip = models.GenericIPAddressField(verbose_name=_('Login ip'))
|
||||||
|
city = models.CharField(max_length=254, blank=True, null=True, verbose_name=_('Login city'))
|
||||||
|
user_agent = models.CharField(max_length=254, blank=True, null=True, verbose_name=_('User agent'))
|
||||||
|
datetime = models.DateTimeField(auto_now_add=True, verbose_name=_('Date login'))
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
db_table = 'login_log'
|
||||||
|
ordering = ['-datetime', 'username']
|
||||||
|
|
|
@ -24,9 +24,8 @@ class UserGroup(NoDeleteModelMixin):
|
||||||
verbose_name=_('Date created'))
|
verbose_name=_('Date created'))
|
||||||
created_by = models.CharField(max_length=100)
|
created_by = models.CharField(max_length=100)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
__str__ = __unicode__
|
|
||||||
|
|
||||||
def delete(self, using=None, keep_parents=False):
|
def delete(self, using=None, keep_parents=False):
|
||||||
if self.name != 'Default':
|
if self.name != 'Default':
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/env python
|
# -*- coding: utf-8 -*-
|
||||||
# ~*~ coding: utf-8 ~*~
|
|
||||||
#
|
#
|
||||||
|
|
||||||
from celery import shared_task
|
from celery import shared_task
|
|
@ -5,7 +5,8 @@ import base64
|
||||||
import logging
|
import logging
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from paramiko.rsakey import RSAKey
|
import requests
|
||||||
|
import ipaddress
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.mixins import UserPassesTestMixin
|
from django.contrib.auth.mixins import UserPassesTestMixin
|
||||||
from django.contrib.auth import authenticate
|
from django.contrib.auth import authenticate
|
||||||
|
@ -14,13 +15,7 @@ from django.core.cache import cache
|
||||||
|
|
||||||
from common.tasks import send_mail_async
|
from common.tasks import send_mail_async
|
||||||
from common.utils import reverse, get_object_or_none
|
from common.utils import reverse, get_object_or_none
|
||||||
from .models import User
|
from .models import User, LoginLog
|
||||||
|
|
||||||
|
|
||||||
# try:
|
|
||||||
# from io import StringIO
|
|
||||||
# except ImportError:
|
|
||||||
# from StringIO import StringIO
|
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger('jumpserver')
|
logger = logging.getLogger('jumpserver')
|
||||||
|
@ -172,3 +167,40 @@ def generate_token(request, user):
|
||||||
return token
|
return token
|
||||||
|
|
||||||
|
|
||||||
|
def validate_ip(ip):
|
||||||
|
try:
|
||||||
|
ipaddress.ip_address(ip)
|
||||||
|
return True
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def write_login_log(username, type='', ip='', user_agent=''):
|
||||||
|
if not (ip and validate_ip(ip)):
|
||||||
|
ip = '0.0.0.0'
|
||||||
|
city = get_ip_city(ip)
|
||||||
|
LoginLog.objects.create(
|
||||||
|
username=username, type=type,
|
||||||
|
ip=ip, city=city, user_agent=user_agent
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_ip_city(ip, timeout=10):
|
||||||
|
# Taobao ip api: http://ip.taobao.com//service/getIpInfo.php?ip=8.8.8.8
|
||||||
|
# Sina ip api: http://int.dpool.sina.com.cn/iplookup/iplookup.php?ip=8.8.8.8&format=json
|
||||||
|
|
||||||
|
url = 'http://int.dpool.sina.com.cn/iplookup/iplookup.php?ip=%s&format=json' % ip
|
||||||
|
try:
|
||||||
|
r = requests.get(url, timeout=timeout)
|
||||||
|
except requests.Timeout:
|
||||||
|
r = None
|
||||||
|
city = 'Unknown'
|
||||||
|
if r and r.status_code == 200:
|
||||||
|
try:
|
||||||
|
data = r.json()
|
||||||
|
if not isinstance(data, int) and data['ret'] == 1:
|
||||||
|
city = data['country'] + ' ' + data['city']
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
return city
|
||||||
|
|
|
@ -21,7 +21,7 @@ from django.conf import settings
|
||||||
from common.utils import get_object_or_none
|
from common.utils import get_object_or_none
|
||||||
from ..models import User
|
from ..models import User
|
||||||
from ..utils import send_reset_password_mail
|
from ..utils import send_reset_password_mail
|
||||||
from ..hands import write_login_log_async
|
from ..tasks import write_login_log_async
|
||||||
from .. import forms
|
from .. import forms
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue