diff --git a/apps/applications/api.py b/apps/applications/api.py index 3a58ed8e2..4933246b0 100644 --- a/apps/applications/api.py +++ b/apps/applications/api.py @@ -3,12 +3,10 @@ from collections import OrderedDict import copy -from rest_framework.generics import ListCreateAPIView from rest_framework import viewsets from rest_framework.views import APIView, Response from rest_framework.permissions import AllowAny from django.shortcuts import get_object_or_404 -from rest_framework.decorators import api_view from .models import Terminal, TerminalHeatbeat from .serializers import TerminalSerializer, TerminalHeatbeatSerializer @@ -17,21 +15,25 @@ from .hands import IsSuperUserOrAppUser, IsAppUser, ProxyLog, \ from common.utils import get_object_or_none -class TerminalRegisterView(ListCreateAPIView): +class TerminalViewSet(viewsets.ModelViewSet): queryset = Terminal.objects.all() serializer_class = TerminalSerializer - permission_classes = (AllowAny,) + permission_classes = (IsSuperUserOrAppUserOrUserReadonly,) def create(self, request, *args, **kwargs): - name = request.data.get('name', '') - remote_addr = request.META.get('X-Real-IP') or \ - request.META.get('REMOTE_ADDR') - serializer = self.serializer_class( - data={'name': name, 'remote_addr': remote_addr}) + name = request.data.get('name') + remote_ip = request.META.get('REMOTE_ADDR') + x_real_ip = request.META.get('X-Real-IP') + remote_addr = x_real_ip or remote_ip - if get_object_or_none(Terminal, name=name): - return Response({'msg': 'Already register, Need ' - 'administrator active it'}, status=200) + terminal = get_object_or_none(Terminal, name=name) + if terminal: + msg = 'Terminal name %s already used' % name + return Response({'msg': msg}, status=409) + + serializer = self.serializer_class(data={ + 'name': name, 'remote_addr': remote_addr + }) if serializer.is_valid(): terminal = serializer.save() @@ -39,30 +41,19 @@ class TerminalRegisterView(ListCreateAPIView): data = OrderedDict() data['terminal'] = copy.deepcopy(serializer.data) data['user'] = app_user.to_json() - data['access_key_id'] = access_key.id - data['access_key_secret'] = access_key.secret + data['access_key'] = {'id': access_key.id, + 'secret': access_key.secret} return Response(data, status=201) else: - data = {'msg': 'Not valid', 'detail': ';'.join(serializer.errors)} + data = serializer.errors return Response(data, status=400) - def list(self, request, *args, **kwargs): - return Response('', status=404) + def get_permissions(self): + if self.action == "create": + self.permission_classes = (AllowAny,) + return super().get_permissions() -class TerminalViewSet(viewsets.ModelViewSet): - queryset = Terminal.objects.all() - serializer_class = TerminalSerializer - permission_classes = (IsSuperUserOrAppUserOrUserReadonly,) - - def create(self, request, *args, **kwargs): - return Response({'msg': 'Use register view except that'}, status=404) - - # def destroy(self, request, *args, **kwargs): - # instance = self.get_object() - # if instance.user is not None: - # instance.user.delete() - # return super(TerminalViewSet, self).destroy(request, *args, **kwargs) tasks = OrderedDict() # tasks = {1: [{'name': 'kill_proxy', 'proxy_log_id': 23}]} diff --git a/apps/applications/forms.py b/apps/applications/forms.py index b6a20eafa..6ef787594 100644 --- a/apps/applications/forms.py +++ b/apps/applications/forms.py @@ -2,6 +2,7 @@ # from django import forms +from django.utils.translation import ugettext_lazy as _ from .models import Terminal @@ -9,10 +10,12 @@ from .models import Terminal class TerminalForm(forms.ModelForm): class Meta: model = Terminal - fields = ['name', 'remote_addr', 'type', 'url', 'comment'] + fields = ['name', 'remote_addr', 'ssh_port', 'http_port', 'comment'] help_texts = { - 'url': 'Example: ssh://192.168.1.1:22 or http://jms.jumpserver.org, that user login' + 'remote_addr': _('A unique addr of every terminal, user browser can arrive it'), + 'ssh_port': _("Coco ssh listen port"), + 'http_port': _("Coco http/ws listen port"), } widgets = { 'name': forms.TextInput(attrs={'readonly': 'readonly'}) - } \ No newline at end of file + } diff --git a/apps/applications/models.py b/apps/applications/models.py index 29adecdae..0d1cb1bc9 100644 --- a/apps/applications/models.py +++ b/apps/applications/models.py @@ -7,16 +7,11 @@ from users.models import User class Terminal(models.Model): - TYPE_CHOICES = ( - ('SSH', 'SSH Terminal'), - ('Web', 'Web Terminal') - ) - name = models.CharField(max_length=30, unique=True, verbose_name=_('Name')) - remote_addr = models.GenericIPAddressField(verbose_name=_('Remote address'), blank=True, null=True) - type = models.CharField(choices=TYPE_CHOICES, max_length=3, blank=True, verbose_name=_('Terminal type')) - user = models.OneToOneField(User, related_name='terminal', verbose_name='Application user', - null=True, on_delete=models.CASCADE) - url = models.CharField(max_length=100, blank=True, verbose_name=_('URL to login')) + name = models.CharField(max_length=32, unique=True, verbose_name=_('Name')) + remote_addr = models.CharField(max_length=128, verbose_name=_('Remote Address')) + ssh_port = models.IntegerField(verbose_name=_('SSH Port'), default=2222) + http_port = models.IntegerField(verbose_name=_('HTTP Port'), default=5000) + user = models.OneToOneField(User, related_name='terminal', verbose_name='Application User', null=True, on_delete=models.CASCADE) is_accepted = models.BooleanField(default=False, verbose_name='Is Accepted') date_created = models.DateTimeField(auto_now_add=True) comment = models.TextField(blank=True, verbose_name=_('Comment')) @@ -44,12 +39,10 @@ class Terminal(models.Model): self.user.delete() return super(Terminal, self).delete(using=using, keep_parents=keep_parents) - def __unicode__(self): + def __str__(self): active = 'Active' if self.user and self.user.is_active else 'Disabled' return '%s: %s' % (self.name, active) - __str__ = __unicode__ - class Meta: ordering = ('is_accepted',) diff --git a/apps/applications/serializers.py b/apps/applications/serializers.py index 56f05e67c..fcb43adb9 100644 --- a/apps/applications/serializers.py +++ b/apps/applications/serializers.py @@ -9,17 +9,17 @@ from .hands import ProxyLog class TerminalSerializer(serializers.ModelSerializer): - proxy_online = serializers.SerializerMethodField() + session_connected = serializers.SerializerMethodField() is_alive = serializers.SerializerMethodField() class Meta: model = Terminal - fields = ['id', 'name', 'remote_addr', 'type', 'url', 'comment', - 'is_accepted', 'is_active', 'get_type_display', - 'proxy_online', 'is_alive'] + fields = ['id', 'name', 'remote_addr', 'http_port', 'ssh_port', + 'comment', 'is_accepted', + 'session_connected', 'is_alive'] @staticmethod - def get_proxy_online(obj): + def get_session_connected(obj): return ProxyLog.objects.filter(terminal=obj.name, is_finished=False).count() @staticmethod @@ -33,9 +33,10 @@ class TerminalSerializer(serializers.ModelSerializer): class TerminalHeatbeatSerializer(serializers.ModelSerializer): date_start = serializers.DateTimeField + class Meta: model = TerminalHeatbeat -if __name__ == '__main__': - pass + + diff --git a/apps/applications/templates/applications/terminal_list.html b/apps/applications/templates/applications/terminal_list.html index fa0f32396..bd3f72c0c 100644 --- a/apps/applications/templates/applications/terminal_list.html +++ b/apps/applications/templates/applications/terminal_list.html @@ -27,9 +27,10 @@ {% trans 'Name' %} - {% trans 'IP' %} - {% trans 'Type' %} - {% trans 'Session online' %} + {% trans 'Addr' %} + {% trans 'SSH Port' %} + {% trans 'Http Port' %} + {% trans 'Connected' %} {% trans 'Active' %} {% trans 'Alive' %} {% trans 'Action' %} @@ -53,21 +54,21 @@ $(document).ready(function(){ var detail_btn = '' + cellData + ''; $(td).html(detail_btn.replace('99991937', rowData.id)); }}, - {targets: 5, createdCell: function (td, cellData) { + {targets: 6, createdCell: function (td, cellData) { if (!cellData) { $(td).html('') } else { $(td).html('') } }}, - {targets: 6, createdCell: function (td, cellData) { + {targets: 7, createdCell: function (td, cellData) { if (!cellData) { $(td).html('') } else { $(td).html('') } }}, - {targets: 7, createdCell: function (td, cellData, rowData) { + {targets: 8, createdCell: function (td, cellData, rowData) { var update_btn = '{% trans "Update" %}' .replace('99991937', cellData); var delete_btn = '{% trans "Delete" %}' @@ -94,8 +95,8 @@ $(document).ready(function(){ }} ], ajax_url: '{% url "api-applications:terminal-list" %}', - columns: [{data: function(){return ""}}, {data: "name" }, {data: "remote_addr" }, {data: "get_type_display" }, - {data: "proxy_online"}, {data: "is_active" }, {data: 'is_active'}, {data: "id"}], + columns: [{data: function(){return ""}}, {data: "name" }, {data: "remote_addr" }, {data: "ssh_port"}, {data: "http_port"}, + {data: "session_connected"}, {data: "is_alive" }, {data: 'is_alive'}, {data: "id"}], op_html: $('#actions').html() }; jumpserver.initDataTable(options); @@ -131,7 +132,6 @@ $(document).ready(function(){ success: function (data) { $('#id_name').val(data.name); $('#id_remote_addr').val(data.remote_addr); - $('#id_type').val(data.type); $('#id_url').val(data.url); $('#id_comment').val(data.comment); $('#form_terminal_accept').attr('action', post_url) diff --git a/apps/applications/templates/applications/terminal_modal_accept.html b/apps/applications/templates/applications/terminal_modal_accept.html index 7e9c7fac7..50789a3a0 100644 --- a/apps/applications/templates/applications/terminal_modal_accept.html +++ b/apps/applications/templates/applications/terminal_modal_accept.html @@ -10,8 +10,8 @@ {% bootstrap_field form.name layout="horizontal" %} {% bootstrap_field form.remote_addr layout="horizontal" %} - {% bootstrap_field form.type layout="horizontal" %} - {% bootstrap_field form.url layout="horizontal" %} + {% bootstrap_field form.ssh_port layout="horizontal" %} + {% bootstrap_field form.http_port layout="horizontal" %} {% bootstrap_field form.comment layout="horizontal" %} diff --git a/apps/applications/urls/api_urls.py b/apps/applications/urls/api_urls.py index ed0e42c32..7eb6e8b43 100644 --- a/apps/applications/urls/api_urls.py +++ b/apps/applications/urls/api_urls.py @@ -14,11 +14,8 @@ router.register(r'v1/terminal/heatbeat', api.TerminalHeatbeatViewSet, 'terminal- router.register(r'v1/terminal', api.TerminalViewSet, 'terminal') urlpatterns = [ - url(r'^v1/terminal/register/$', api.TerminalRegisterView.as_view(), - name='terminal-register'), url(r'^v1/terminate/connection/$', api.TerminateConnectionView.as_view(), name='terminate-connection') - # url(r'^v1/terminal/heatbeat/$', api.TestHeatbeat.as_view()) ] urlpatterns += router.urls diff --git a/apps/applications/views.py b/apps/applications/views.py index 90874d382..7cac6f575 100644 --- a/apps/applications/views.py +++ b/apps/applications/views.py @@ -66,7 +66,6 @@ class TerminalModelAccept(AdminUserRequiredMixin, JSONResponseMixin, UpdateView) template_name = 'applications/terminal_modal_test.html' def post(self, request, *args, **kwargs): - print(request.POST) return super(TerminalModelAccept, self).post(request, *args, **kwargs) def form_valid(self, form): @@ -81,7 +80,7 @@ class TerminalModelAccept(AdminUserRequiredMixin, JSONResponseMixin, UpdateView) return self.render_json_response(data) def form_invalid(self, form): - print('form.data') + print(form.data) data = { 'success': False, 'msg': str(form.errors), diff --git a/apps/common/utils.py b/apps/common/utils.py index de8e995bd..fb9bc6937 100644 --- a/apps/common/utils.py +++ b/apps/common/utils.py @@ -274,8 +274,10 @@ def content_md5(data): 返回值可以直接作为HTTP Content-Type头部的值 """ - m = hashlib.md5(to_bytes(data)) - return to_string(base64.b64encode(m.digest())) + if isinstance(data, str): + data = hashlib.md5(data.encode('utf-8')) + value = base64.b64encode(data.digest()) + return value.decode('utf-8') _STRPTIME_LOCK = threading.Lock() @@ -330,8 +332,6 @@ def encrypt_password(password): return None - - def capacity_convert(size, expect='auto', rate=1000): """ :param size: '100MB', '1G' diff --git a/apps/static/css/plugins/inputTags.css b/apps/static/css/plugins/inputTags.css index 085ea19fa..365454272 100644 --- a/apps/static/css/plugins/inputTags.css +++ b/apps/static/css/plugins/inputTags.css @@ -1,5 +1,5 @@ -@import url("https://fonts.css.network/css?family=Open+Sans:300,400,600,700"); -@import url("https://fonts.css.network/css?family=Roboto:400,300,500,700"); +/*@import url("https://fonts.css.network/css?family=Open+Sans:300,400,600,700");*/ +/*@import url("https://fonts.css.network/css?family=Roboto:400,300,500,700");*/ /** {*/ /*box-sizing: border-box;*/ /*}*/ diff --git a/apps/static/css/style.css b/apps/static/css/style.css index 637517e34..a4c62fe97 100644 --- a/apps/static/css/style.css +++ b/apps/static/css/style.css @@ -1,5 +1,5 @@ -@import url("https://fonts.css.network/css?family=Open+Sans:300,400,600,700"); -@import url("https://fonts.css.network/css?family=Roboto:400,300,500,700"); +/*@import url("https://fonts.css.network/css?family=Open+Sans:300,400,600,700");*/ +/*@import url("https://fonts.css.network/css?family=Roboto:400,300,500,700");*/ /* * * INSPINIA - Responsive Admin Theme diff --git a/apps/users/authentication.py b/apps/users/authentication.py index b8e2601e6..09321953e 100644 --- a/apps/users/authentication.py +++ b/apps/users/authentication.py @@ -49,7 +49,6 @@ class AccessKeyAuthentication(authentication.BaseAuthentication): def authenticate(self, request): auth = authentication.get_authorization_header(request).split() - if not auth or auth[0].lower() != self.keyword.lower().encode(): return None @@ -80,7 +79,8 @@ class AccessKeyAuthentication(authentication.BaseAuthentication): request_signature = sign[1] return self.authenticate_credentials( - request, access_key_id, request_signature) + request, access_key_id, request_signature + ) @staticmethod def authenticate_credentials(request, access_key_id, request_signature): diff --git a/apps/users/models/authentication.py b/apps/users/models/authentication.py index 917bc1114..954c7e5bc 100644 --- a/apps/users/models/authentication.py +++ b/apps/users/models/authentication.py @@ -25,11 +25,9 @@ class AccessKey(models.Model): def get_secret(self): return str(self.secret) - def __unicode__(self): + def __str__(self): return str(self.id) - __str__ = __unicode__ - class PrivateToken(Token): """Inherit from auth token, otherwise migration is boring""" diff --git a/apps/users/models/user.py b/apps/users/models/user.py index e6f5724c4..cf9a51034 100644 --- a/apps/users/models/user.py +++ b/apps/users/models/user.py @@ -23,9 +23,9 @@ __all__ = ['User'] class User(AbstractUser): ROLE_CHOICES = ( - ('Admin', _('Administrator')), - ('User', _('User')), - ('App', _('Application')) + ('Admin', 'Administrator'), + ('User', 'User'), + ('App', 'Application') ) username = models.CharField(max_length=20, unique=True, verbose_name=_('Username')) diff --git a/apps/users/serializers.py b/apps/users/serializers.py index 880d3b21e..fd52d99c7 100644 --- a/apps/users/serializers.py +++ b/apps/users/serializers.py @@ -36,8 +36,6 @@ class UserPKUpdateSerializer(serializers.ModelSerializer): @staticmethod def validate__public_key(value): if not validate_ssh_public_key(value): - print('Not a valid key') - print(value) raise serializers.ValidationError(_('Not a valid ssh public key')) return value