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.utils import timezone
|
||||
from django.utils.html import escape
|
||||
from audits.backends import command_store
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
@ -70,6 +69,6 @@ def to_html(s):
|
|||
return escape(s).replace('\n', '<br />')
|
||||
|
||||
|
||||
@register.filter
|
||||
def proxy_log_commands(log_id):
|
||||
return command_store.filter(proxy_log_id=log_id)
|
||||
# @register.filter
|
||||
# def proxy_log_commands(log_id):
|
||||
# return 1
|
||||
|
|
|
@ -1,4 +1,2 @@
|
|||
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", "")
|
||||
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):
|
||||
|
|
|
@ -59,7 +59,7 @@ INSTALLED_APPS = [
|
|||
'assets.apps.AssetsConfig',
|
||||
'perms.apps.PermsConfig',
|
||||
'ops.apps.OpsConfig',
|
||||
'audits.apps.AuditsConfig',
|
||||
# 'audits.apps.AuditsConfig',
|
||||
'common.apps.CommonConfig',
|
||||
'terminal.apps.ApplicationsConfig',
|
||||
'rest_framework',
|
||||
|
@ -364,7 +364,7 @@ CAPTCHA_NOISE_FUNCTIONS = ('captcha.helpers.noise_dots',)
|
|||
CAPTCHA_TEST_MODE = CONFIG.CAPTCHA_TEST_MODE
|
||||
|
||||
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
|
||||
|
|
|
@ -16,7 +16,7 @@ urlpatterns = [
|
|||
url(r'^users/', include('users.urls.views_urls', namespace='users')),
|
||||
url(r'^assets/', include('assets.urls.views_urls', namespace='assets')),
|
||||
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'^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/assets/', include('assets.urls.api_urls', namespace='api-assets')),
|
||||
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/ops/', include('ops.urls.api_urls', namespace='api-ops')),
|
||||
url(r'^captcha/', include('captcha.urls')),
|
||||
|
|
|
@ -6,70 +6,146 @@ from django.shortcuts import redirect
|
|||
|
||||
from users.models import User
|
||||
from assets.models import Asset
|
||||
from audits.models import ProxyLog
|
||||
from terminal.models import Session
|
||||
|
||||
|
||||
class IndexView(LoginRequiredMixin, TemplateView):
|
||||
template_name = 'index.html'
|
||||
|
||||
session_week = None
|
||||
session_month = None
|
||||
session_month_dates = []
|
||||
session_month_dates_archive = []
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
if not request.user.is_superuser:
|
||||
return redirect('assets:user-asset-list')
|
||||
return super(IndexView, self).get(request, *args, **kwargs)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
seven_days_ago = timezone.now() - timezone.timedelta(days=7)
|
||||
month_ago = timezone.now() - timezone.timedelta(days=30)
|
||||
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)
|
||||
month_dates = proxy_log_month.dates('date_start', 'day')
|
||||
month_total_visit = [ProxyLog.objects.filter(date_start__date=d) for d in month_dates]
|
||||
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]
|
||||
month_user = [p.values('user').distinct().count() for p in month_total_visit] or [0]
|
||||
month_asset = [p.values('asset').distinct().count() for p in month_total_visit] or [0]
|
||||
month_user_active = User.objects.filter(last_login__gt=month_ago).count()
|
||||
month_user_inactive = User.objects.filter(last_login__lt=month_ago).count()
|
||||
month_user_disabled = User.objects.filter(is_active=False).count()
|
||||
month_asset_active = proxy_log_month.values('asset').distinct().count()
|
||||
month_asset_inactive = Asset.objects.all().count() - month_asset_active
|
||||
month_asset_disabled = Asset.objects.filter(is_active=False).count()
|
||||
week_asset_hot_ten = list(proxy_log_seven_days.values('asset').annotate(total=Count('asset')).order_by('-total')[:10])
|
||||
for p in week_asset_hot_ten:
|
||||
last_login = ProxyLog.objects.filter(asset=p['asset']).order_by('date_start').last()
|
||||
p['last'] = last_login
|
||||
last_login_ten = ProxyLog.objects.all().order_by('-date_start')[:10]
|
||||
for p in last_login_ten:
|
||||
@staticmethod
|
||||
def get_user_count():
|
||||
return User.objects.filter(role__in=('Admin', 'User')).count()
|
||||
|
||||
@staticmethod
|
||||
def get_asset_count():
|
||||
return Asset.objects.all().count()
|
||||
|
||||
@staticmethod
|
||||
def get_online_user_count():
|
||||
return len(set(Session.objects.filter(is_finished=False).values_list('user', flat=True)))
|
||||
|
||||
@staticmethod
|
||||
def get_online_session_count():
|
||||
return Session.objects.filter(is_finished=False).count()
|
||||
|
||||
def get_top5_user_a_week(self):
|
||||
return self.session_week.values('user').annotate(total=Count('user')).order_by('-total')[:5]
|
||||
|
||||
def get_week_login_user_count(self):
|
||||
return self.session_week.values('user').distinct().count()
|
||||
|
||||
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:
|
||||
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:
|
||||
p.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])
|
||||
for p in week_user_hot_ten:
|
||||
last_login = ProxyLog.objects.filter(user=p['user']).order_by('date_start').last()
|
||||
p['last'] = last_login
|
||||
session.avatar_url = User.objects.first().avatar_url()
|
||||
return sessions
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
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 = {
|
||||
'assets_count': Asset.objects.count(),
|
||||
'users_count': User.objects.filter(role__in=('Admin', 'User')).count(),
|
||||
'online_user_count': ProxyLog.objects.filter(is_finished=False).values('user').distinct().count(),
|
||||
'online_asset_count': ProxyLog.objects.filter(is_finished=False).values('asset').distinct().count(),
|
||||
'user_visit_count_weekly': proxy_log_seven_days.values('user').distinct().count(),
|
||||
'asset_visit_count_weekly': proxy_log_seven_days.count(),
|
||||
'user_visit_count_top_five': proxy_log_seven_days.values('user').annotate(total=Count('user')).order_by('-total')[:5],
|
||||
'month_str': month_str,
|
||||
'month_total_visit_count': month_total_visit_count,
|
||||
'month_user': month_user,
|
||||
'mouth_asset': month_asset,
|
||||
'month_user_active': month_user_active,
|
||||
'month_user_inactive': month_user_inactive,
|
||||
'month_user_disabled': month_user_disabled,
|
||||
'month_asset_active': month_asset_active,
|
||||
'month_asset_inactive': month_asset_inactive,
|
||||
'month_asset_disabled': month_asset_disabled,
|
||||
'week_asset_hot_ten': week_asset_hot_ten,
|
||||
'last_login_ten': last_login_ten,
|
||||
'week_user_hot_ten': week_user_hot_ten,
|
||||
'assets_count': self.get_asset_count(),
|
||||
'users_count': self.get_user_count(),
|
||||
'online_user_count': self.get_online_user_count(),
|
||||
'online_asset_count': self.get_online_session_count(),
|
||||
'user_visit_count_weekly': self.get_week_login_user_count(),
|
||||
'asset_visit_count_weekly': self.get_week_login_asset_count(),
|
||||
'user_visit_count_top_five': self.get_top5_user_a_week(),
|
||||
'month_str': self.get_month_day_metrics(),
|
||||
'month_total_visit_count': self.get_month_login_metrics(),
|
||||
'month_user': self.get_month_active_user_metrics(),
|
||||
'mouth_asset': self.get_month_active_asset_metrics(),
|
||||
'month_user_active': self.get_month_active_user_total(),
|
||||
'month_user_inactive': self.get_month_inactive_user_total(),
|
||||
'month_user_disabled': self.get_user_disabled_total(),
|
||||
'month_asset_active': self.get_month_active_asset_total(),
|
||||
'month_asset_inactive': self.get_month_inactive_asset_total(),
|
||||
'month_asset_disabled': self.get_asset_disabled_total(),
|
||||
'week_asset_hot_ten': self.get_week_top10_asset(),
|
||||
'last_login_ten': self.get_last10_sessions(),
|
||||
'week_user_hot_ten': self.get_week_top10_user(),
|
||||
}
|
||||
|
||||
kwargs.update(context)
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
<h5>在线用户</h5>
|
||||
</div>
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -45,11 +45,11 @@
|
|||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<span class="label label-danger pull-right">Connected</span>
|
||||
<h5>已连接服务器</h5>
|
||||
<h5>在线会话</h5>
|
||||
</div>
|
||||
<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>
|
||||
<small>Connected host</small>
|
||||
<h1 class="no-margins"><a href="{% url 'terminal:session-online-list' %}"> <span id="online_hosts"></span>{{ online_asset_count }}</a></h1>
|
||||
<small>Online sessions</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
import base64
|
||||
from collections import OrderedDict
|
||||
import copy
|
||||
import logging
|
||||
import tarfile
|
||||
|
||||
import os
|
||||
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 .serializers import TerminalSerializer, StatusSerializer, \
|
||||
SessionSerializer, TaskSerializer
|
||||
from .hands import IsSuperUserOrAppUser, IsAppUser, ProxyLog, \
|
||||
from .hands import IsSuperUserOrAppUser, IsAppUser, \
|
||||
IsSuperUserOrAppUserOrUserReadonly
|
||||
from .backends import get_command_store, get_replay_store, SessionCommandSerializer
|
||||
|
||||
|
@ -221,7 +219,9 @@ class CommandViewSet(viewsets.ViewSet):
|
|||
else:
|
||||
return Response("Save error", status=500)
|
||||
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):
|
||||
queryset = list(self.command_store.all())
|
||||
|
|
|
@ -12,6 +12,6 @@ def get_command_store():
|
|||
|
||||
|
||||
def get_replay_store():
|
||||
replay_engine = import_module(settings.RECORD_STORE_BACKEND)
|
||||
replay_store = replay_engine.RecordStore()
|
||||
replay_engine = import_module(settings.REPLAY_STORE_BACKEND)
|
||||
replay_store = replay_engine.ReplayStore()
|
||||
return replay_store
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
import abc
|
||||
|
||||
|
||||
class RecordBase(object):
|
||||
class ReplayBase(object):
|
||||
__metaclass__ = abc.ABCMeta
|
||||
|
||||
@abc.abstractmethod
|
||||
|
|
|
@ -1,31 +1,8 @@
|
|||
# ~*~ coding: utf-8 ~*~
|
||||
|
||||
from .base import RecordBase
|
||||
from audits.models import RecordLog
|
||||
from .base import ReplayBase
|
||||
|
||||
|
||||
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()
|
||||
class ReplayStore(ReplayBase):
|
||||
pass
|
||||
|
||||
|
|
|
@ -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.permissions import IsSuperUserOrAppUser, IsAppUser, \
|
||||
IsSuperUserOrAppUserOrUserReadonly
|
||||
from audits.models import ProxyLog
|
||||
from users.utils import AdminUserRequiredMixin
|
|
@ -13,6 +13,7 @@ ASSETS_CACHE_KEY = "terminal__session__assets"
|
|||
USERS_CACHE_KEY = "terminal__session__users"
|
||||
SYSTEM_USER_CACHE_KEY = "terminal__session__system_users"
|
||||
CACHE_REFRESH_INTERVAL = 10
|
||||
RUNNING = False
|
||||
|
||||
|
||||
# Todo: 定期清理上报history
|
||||
|
@ -46,7 +47,16 @@ def set_cache():
|
|||
|
||||
|
||||
def main():
|
||||
global RUNNING
|
||||
if RUNNING:
|
||||
return
|
||||
threads = []
|
||||
thread = threading.Thread(target=set_cache)
|
||||
thread.start()
|
||||
threads.append(thread)
|
||||
|
||||
for t in threads:
|
||||
t.daemon = True
|
||||
t.start()
|
||||
RUNNING = True
|
||||
|
||||
main()
|
||||
|
|
|
@ -9,7 +9,7 @@ from rest_framework_bulk import BulkModelViewSet
|
|||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
|
||||
from . import serializers
|
||||
from .hands import write_login_log_async
|
||||
from .tasks import write_login_log_async
|
||||
from .models import User, UserGroup
|
||||
from .permissions import IsSuperUser, IsValidUser, IsCurrentUserOrReadOnly
|
||||
from .utils import check_user_valid, generate_token
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
:license: GPL v2, see LICENSE for more details.
|
||||
"""
|
||||
|
||||
from terminal.models import Terminal
|
||||
from audits.tasks import write_login_log_async
|
||||
from users.models import User
|
||||
# from terminal.models import Terminal
|
||||
# from audits.tasks import write_login_log_async
|
||||
# from users.models import User
|
||||
# from perms.models import AssetPermission
|
||||
# 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 . import User
|
||||
|
||||
__all__ = ['AccessKey', 'PrivateToken']
|
||||
__all__ = ['AccessKey', 'PrivateToken', 'LoginLog']
|
||||
|
||||
|
||||
class AccessKey(models.Model):
|
||||
|
@ -34,3 +34,22 @@ class PrivateToken(Token):
|
|||
|
||||
class Meta:
|
||||
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'))
|
||||
created_by = models.CharField(max_length=100)
|
||||
|
||||
def __unicode__(self):
|
||||
def __str__(self):
|
||||
return self.name
|
||||
__str__ = __unicode__
|
||||
|
||||
def delete(self, using=None, keep_parents=False):
|
||||
if self.name != 'Default':
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#!/usr/bin/env python
|
||||
# ~*~ coding: utf-8 ~*~
|
||||
#
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
|
||||
from celery import shared_task
|
||||
from .utils import write_login_log
|
|
@ -5,7 +5,8 @@ import base64
|
|||
import logging
|
||||
import uuid
|
||||
|
||||
from paramiko.rsakey import RSAKey
|
||||
import requests
|
||||
import ipaddress
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.mixins import UserPassesTestMixin
|
||||
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.utils import reverse, get_object_or_none
|
||||
from .models import User
|
||||
|
||||
|
||||
# try:
|
||||
# from io import StringIO
|
||||
# except ImportError:
|
||||
# from StringIO import StringIO
|
||||
from .models import User, LoginLog
|
||||
|
||||
|
||||
logger = logging.getLogger('jumpserver')
|
||||
|
@ -172,3 +167,40 @@ def generate_token(request, user):
|
|||
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 ..models import User
|
||||
from ..utils import send_reset_password_mail
|
||||
from ..hands import write_login_log_async
|
||||
from ..tasks import write_login_log_async
|
||||
from .. import forms
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue