Commit 26804b40 authored by ibuler's avatar ibuler

Merge pull request #174 from jumpserver/dev

Release 0.3.1 version, Fix most bugs
parents d7442b48 8ebcd475
This diff is collapsed.
#!/bin/bash
#
trap '' SIGINT
base_dir=$(dirname $0)
export LANG='zh_CN.UTF-8'
python $base_dir/connect.py
exit
This diff is collapsed.
This diff is collapsed.
...@@ -5,9 +5,11 @@ import sys ...@@ -5,9 +5,11 @@ import sys
import os import os
import django import django
from django.core.management import execute_from_command_line from django.core.management import execute_from_command_line
import shutil import shlex
import urllib import urllib
import socket import socket
import subprocess
jms_dir = os.path.dirname(os.path.abspath(os.path.dirname(__file__))) jms_dir = os.path.dirname(os.path.abspath(os.path.dirname(__file__)))
sys.path.append(jms_dir) sys.path.append(jms_dir)
...@@ -41,9 +43,6 @@ class Setup(object): ...@@ -41,9 +43,6 @@ class Setup(object):
version = urllib.urlopen('http://jumpserver.org/version/?id=%s' % mac) version = urllib.urlopen('http://jumpserver.org/version/?id=%s' % mac)
except: except:
pass pass
os.chdir(jms_dir)
os.chmod('logs', 0777)
os.chmod('keys', 0777)
def _input_admin(self): def _input_admin(self):
while True: while True:
...@@ -78,27 +77,34 @@ class Setup(object): ...@@ -78,27 +77,34 @@ class Setup(object):
user.delete() user.delete()
db_add_user(username=self.admin_user, password=self.admin_pass, role='SU', name='admin', groups='', db_add_user(username=self.admin_user, password=self.admin_pass, role='SU', name='admin', groups='',
admin_groups='', email='admin@jumpserver.org', uuid='MayBeYouAreTheFirstUser', is_active=True) admin_groups='', email='admin@jumpserver.org', uuid='MayBeYouAreTheFirstUser', is_active=True)
os.system('id %s &> /dev/null || useradd %s' % (self.admin_user, self.admin_user)) cmd = 'id %s 2> /dev/null 1> /dev/null || useradd %s' % (self.admin_user, self.admin_user)
shlex.os.system(cmd)
@staticmethod @staticmethod
def _cp_zzsh(): def _chmod_file():
os.chdir(os.path.join(jms_dir, 'install')) os.chdir(jms_dir)
shutil.copy('zzjumpserver.sh', '/etc/profile.d/') os.chmod('init.sh', 0755)
bash("sed -i 's#/opt/jumpserver#%s#g' /etc/profile.d/zzjumpserver.sh" % jms_dir) os.chmod('connect.py', 0755)
os.chmod('manage.py', 0755)
os.chmod('run_server.py', 0755)
os.chmod('service.sh', 0755)
os.chmod('logs', 0777)
os.chmod('keys', 0777)
@staticmethod @staticmethod
def _run_service(): def _run_service():
os.system('sh %s start' % os.path.join(jms_dir, 'service.sh')) cmd = 'bash %s start' % os.path.join(jms_dir, 'service.sh')
shlex.os.system(cmd)
print print
color_print('安装成功,请访问web, 祝你使用愉快。\n请访问 https://github.com/ibuler/jumpserver 查看文档', 'green') color_print('安装成功,请访问web, 祝你使用愉快。\n请访问 https://github.com/jumpserver/jumpserver/wiki 查看文档', 'green')
def start(self): def start(self):
print "开始安装Jumpserver, 要求环境为 CentOS 6.5 x86_64" print "开始安装Jumpserver ..."
self._pull() self._pull()
self._sync_db() self._sync_db()
self._input_admin() self._input_admin()
self._create_admin() self._create_admin()
self._cp_zzsh() self._chmod_file()
self._run_service() self._run_service()
......
...@@ -14,4 +14,6 @@ ansible==1.9.4 ...@@ -14,4 +14,6 @@ ansible==1.9.4
pyinotify==0.9.6 pyinotify==0.9.6
passlib==1.6.5 passlib==1.6.5
argparse==1.4.0 argparse==1.4.0
django_crontab==0.6.0 django_crontab==0.6.0
\ No newline at end of file django-smtp-ssl==1.0
pyte==0.5.2
\ No newline at end of file
#!/bin/bash
export LANG='zh_CN.UTF-8'
if [ "$USER" != "admin" ] && [ "$USER" != "root" ];then
python /opt/jumpserver/connect.py
if [ $USER == 'guanghongwei' ];then
echo
else
exit 3
echo
fi
fi
...@@ -9,6 +9,8 @@ from jperm.ansible_api import MyRunner ...@@ -9,6 +9,8 @@ from jperm.ansible_api import MyRunner
from jperm.perm_api import gen_resource from jperm.perm_api import gen_resource
from jumpserver.templatetags.mytags import get_disk_info from jumpserver.templatetags.mytags import get_disk_info
import traceback
def group_add_asset(group, asset_id=None, asset_ip=None): def group_add_asset(group, asset_id=None, asset_ip=None):
""" """
...@@ -333,9 +335,11 @@ def get_ansible_asset_info(asset_ip, setup_info): ...@@ -333,9 +335,11 @@ def get_ansible_asset_info(asset_ip, setup_info):
# ip = setup_info.get("ansible_default_ipv4").get("address") # ip = setup_info.get("ansible_default_ipv4").get("address")
mac = setup_info.get("ansible_default_ipv4").get("macaddress") mac = setup_info.get("ansible_default_ipv4").get("macaddress")
brand = setup_info.get("ansible_product_name") brand = setup_info.get("ansible_product_name")
cpu_type = setup_info.get("ansible_processor")[1] try:
cpu_cores = setup_info.get("ansible_processor_vcpus") cpu_type = setup_info.get("ansible_processor")[1]
cpu = cpu_type + ' * ' + unicode(cpu_cores) except IndexError:
cpu_type = ' '.join(setup_info.get("ansible_processor")[0].split(' ')[:6])
memory = setup_info.get("ansible_memtotal_mb") memory = setup_info.get("ansible_memtotal_mb")
try: try:
memory_format = int(round((int(memory) / 1000), 0)) memory_format = int(round((int(memory) / 1000), 0))
...@@ -343,7 +347,13 @@ def get_ansible_asset_info(asset_ip, setup_info): ...@@ -343,7 +347,13 @@ def get_ansible_asset_info(asset_ip, setup_info):
memory_format = memory memory_format = memory
disk = disk_need disk = disk_need
system_type = setup_info.get("ansible_distribution") system_type = setup_info.get("ansible_distribution")
system_version = setup_info.get("ansible_distribution_version") if system_type.lower() == "freebsd":
system_version = setup_info.get("ansible_distribution_release")
cpu_cores = setup_info.get("ansible_processor_count")
else:
system_version = setup_info.get("ansible_distribution_version")
cpu_cores = setup_info.get("ansible_processor_vcpus")
cpu = cpu_type + ' * ' + unicode(cpu_cores)
system_arch = setup_info.get("ansible_architecture") system_arch = setup_info.get("ansible_architecture")
# asset_type = setup_info.get("ansible_system") # asset_type = setup_info.get("ansible_system")
sn = setup_info.get("ansible_product_serial") sn = setup_info.get("ansible_product_serial")
...@@ -359,24 +369,31 @@ def asset_ansible_update(obj_list, name=''): ...@@ -359,24 +369,31 @@ def asset_ansible_update(obj_list, name=''):
for asset in obj_list: for asset in obj_list:
try: try:
setup_info = ansible_asset_info['contacted'][asset.hostname]['ansible_facts'] setup_info = ansible_asset_info['contacted'][asset.hostname]['ansible_facts']
except KeyError: logger.debug("setup_info: %s" % setup_info)
except KeyError, e:
logger.error("获取setup_info失败: %s" % e)
continue continue
else: else:
asset_info = get_ansible_asset_info(asset.ip, setup_info) try:
other_ip, mac, cpu, memory, disk, sn, system_type, system_version, brand, system_arch = asset_info asset_info = get_ansible_asset_info(asset.ip, setup_info)
asset_dic = {"other_ip": other_ip, print asset_info
"mac": mac, other_ip, mac, cpu, memory, disk, sn, system_type, system_version, brand, system_arch = asset_info
"cpu": cpu, asset_dic = {"other_ip": other_ip,
"memory": memory, "mac": mac,
"disk": disk, "cpu": cpu,
"sn": sn, "memory": memory,
"system_type": system_type, "disk": disk,
"system_version": system_version, "sn": sn,
"system_arch": system_arch, "system_type": system_type,
"brand": brand "system_version": system_version,
} "system_arch": system_arch,
"brand": brand
ansible_record(asset, asset_dic, name) }
ansible_record(asset, asset_dic, name)
except Exception as e:
logger.error("save setup info failed! %s" % e)
traceback.print_exc()
def asset_ansible_update_all(): def asset_ansible_update_all():
......
...@@ -15,12 +15,11 @@ from struct import unpack ...@@ -15,12 +15,11 @@ from struct import unpack
from subprocess import Popen from subprocess import Popen
from sys import platform, prefix, stderr from sys import platform, prefix, stderr
from tempfile import NamedTemporaryFile from tempfile import NamedTemporaryFile
from jumpserver.api import logger
from jinja2 import FileSystemLoader, Template from jinja2 import FileSystemLoader, Template
from jinja2.environment import Environment from jinja2.environment import Environment
from jumpserver.api import BASE_DIR from jumpserver.api import BASE_DIR, logger
from jlog.models import Log from jlog.models import Log
...@@ -104,3 +103,4 @@ def kill_invalid_connection(): ...@@ -104,3 +103,4 @@ def kill_invalid_connection():
log.end_time = now log.end_time = now
log.save() log.save()
logger.warn('kill log %s' % log.log_path) logger.warn('kill log %s' % log.log_path)
from django.db import models from django.db import models
from juser.models import User
import time
class Log(models.Model): class Log(models.Model):
...@@ -11,6 +13,20 @@ class Log(models.Model): ...@@ -11,6 +13,20 @@ class Log(models.Model):
pid = models.IntegerField() pid = models.IntegerField()
is_finished = models.BooleanField(default=False) is_finished = models.BooleanField(default=False)
end_time = models.DateTimeField(null=True) end_time = models.DateTimeField(null=True)
filename = models.CharField(max_length=40)
'''
add by liuzheng
'''
# userMM = models.ManyToManyField(User)
# logPath = models.TextField()
# filename = models.CharField(max_length=40)
# logPWD = models.TextField() # log zip file's
# nick = models.TextField(null=True) # log's nick name
# log = models.TextField(null=True)
# history = models.TextField(null=True)
# timestamp = models.IntegerField(default=int(time.time()))
# datetimestamp = models.DateTimeField(auto_now_add=True)
def __unicode__(self): def __unicode__(self):
return self.log_path return self.log_path
...@@ -47,3 +63,13 @@ class FileLog(models.Model): ...@@ -47,3 +63,13 @@ class FileLog(models.Model):
datetime = models.DateTimeField(auto_now=True) datetime = models.DateTimeField(auto_now=True)
class TermLog(models.Model):
user = models.ManyToManyField(User)
logPath = models.TextField()
filename = models.CharField(max_length=40)
logPWD = models.TextField() # log zip file's
nick = models.TextField(null=True) # log's nick name
log = models.TextField(null=True)
history = models.TextField(null=True)
timestamp = models.IntegerField(default=int(time.time()))
datetimestamp = models.DateTimeField(auto_now_add=True)
This diff is collapsed.
...@@ -26,7 +26,7 @@ class PermSudo(models.Model): ...@@ -26,7 +26,7 @@ class PermSudo(models.Model):
class PermRole(models.Model): class PermRole(models.Model):
name = models.CharField(max_length=100, unique=True) name = models.CharField(max_length=100, unique=True)
comment = models.CharField(max_length=100, null=True, blank=True, default='') comment = models.CharField(max_length=100, null=True, blank=True, default='')
password = models.CharField(max_length=100) password = models.CharField(max_length=128)
key_path = models.CharField(max_length=100) key_path = models.CharField(max_length=100)
date_added = models.DateTimeField(auto_now=True) date_added = models.DateTimeField(auto_now=True)
sudo = models.ManyToManyField(PermSudo, related_name='perm_role') sudo = models.ManyToManyField(PermSudo, related_name='perm_role')
......
...@@ -182,8 +182,9 @@ def gen_resource(ob, perm=None): ...@@ -182,8 +182,9 @@ def gen_resource(ob, perm=None):
info = {'hostname': asset.hostname, info = {'hostname': asset.hostname,
'ip': asset.ip, 'ip': asset.ip,
'port': asset_info.get('port', 22), 'port': asset_info.get('port', 22),
'ansible_ssh_private_key_file': role_key,
'username': role.name, 'username': role.name,
'password': CRYPTOR.decrypt(role.password) # 'password': CRYPTOR.decrypt(role.password)
} }
if os.path.isfile(role_key): if os.path.isfile(role_key):
......
...@@ -68,6 +68,12 @@ def gen_keys(key="", key_path_dir=""): ...@@ -68,6 +68,12 @@ def gen_keys(key="", key_path_dir=""):
return key_path_dir return key_path_dir
def trans_all(str):
if str.strip().lower() == "all":
return str.upper()
else:
return str
if __name__ == "__main__": if __name__ == "__main__":
print gen_keys() print gen_keys()
......
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db.models import Q from django.db.models import Q
from django.http import HttpResponseBadRequest, HttpResponseNotAllowed from django.http import HttpResponseBadRequest, HttpResponseNotAllowed
...@@ -10,7 +11,7 @@ from jasset.models import Asset, AssetGroup ...@@ -10,7 +11,7 @@ from jasset.models import Asset, AssetGroup
from jperm.models import PermRole, PermRule, PermSudo, PermPush from jperm.models import PermRole, PermRule, PermSudo, PermPush
from jumpserver.models import Setting from jumpserver.models import Setting
from jperm.utils import gen_keys from jperm.utils import gen_keys, trans_all
from jperm.ansible_api import MyTask from jperm.ansible_api import MyTask
from jperm.perm_api import get_role_info, get_role_push_host from jperm.perm_api import get_role_info, get_role_push_host
from jumpserver.api import my_render, get_object, CRYPTOR from jumpserver.api import my_render, get_object, CRYPTOR
...@@ -512,18 +513,18 @@ def perm_role_push(request): ...@@ -512,18 +513,18 @@ def perm_role_push(request):
task = MyTask(push_resource) task = MyTask(push_resource)
ret = {} ret = {}
# 因为要先建立用户,所以password 是必选项,而push key是在 password也完成的情况下的 可选项 # 因为要先建立用户,而push key是在 password也完成的情况下的 可选项
# 1. 以秘钥 方式推送角色 # 1. 以秘钥 方式推送角色
if key_push: if key_push:
ret["pass_push"] = task.add_user(role.name, CRYPTOR.decrypt(role.password)) ret["pass_push"] = task.add_user(role.name)
ret["key_push"] = task.push_key(role.name, os.path.join(role.key_path, 'id_rsa.pub')) ret["key_push"] = task.push_key(role.name, os.path.join(role.key_path, 'id_rsa.pub'))
# 2. 推送账号密码 # 2. 推送账号密码 <为了安全 系统用户统一使用秘钥进行通信, 不再提供密码方式的推送>
elif password_push: # elif password_push:
ret["pass_push"] = task.add_user(role.name, CRYPTOR.decrypt(role.password)) # ret["pass_push"] = task.add_user(role.name, CRYPTOR.decrypt(role.password))
# 3. 推送sudo配置文件 # 3. 推送sudo配置文件
if password_push or key_push: if key_push:
sudo_list = set([sudo for sudo in role.sudo.all()]) # set(sudo1, sudo2, sudo3) sudo_list = set([sudo for sudo in role.sudo.all()]) # set(sudo1, sudo2, sudo3)
if sudo_list: if sudo_list:
ret['sudo'] = task.push_sudo_file([role], sudo_list) ret['sudo'] = task.push_sudo_file([role], sudo_list)
...@@ -619,7 +620,9 @@ def perm_sudo_add(request): ...@@ -619,7 +620,9 @@ def perm_sudo_add(request):
raise ServerError(u"sudo name 和 commands是必填项!") raise ServerError(u"sudo name 和 commands是必填项!")
pattern = re.compile(r'[\n,\r]') pattern = re.compile(r'[\n,\r]')
commands = ', '.join(list_drop_str(pattern.split(commands), u'')) deal_space_commands = list_drop_str(pattern.split(commands), u'')
deal_all_commands = map(trans_all, deal_space_commands)
commands = ', '.join(deal_all_commands)
logger.debug(u'添加sudo %s: %s' % (name, commands)) logger.debug(u'添加sudo %s: %s' % (name, commands))
if get_object(PermSudo, name=name): if get_object(PermSudo, name=name):
...@@ -656,7 +659,9 @@ def perm_sudo_edit(request): ...@@ -656,7 +659,9 @@ def perm_sudo_edit(request):
raise ServerError(u"sudo name 和 commands是必填项!") raise ServerError(u"sudo name 和 commands是必填项!")
pattern = re.compile(r'[\n,\r]') pattern = re.compile(r'[\n,\r]')
commands = ', '.join(list_drop_str(pattern.split(commands), u'')).strip() deal_space_commands = list_drop_str(pattern.split(commands), u'')
deal_all_commands = map(trans_all, deal_space_commands)
commands = ', '.join(deal_all_commands).strip()
logger.debug(u'添加sudo %s: %s' % (name, commands)) logger.debug(u'添加sudo %s: %s' % (name, commands))
sudo.name = name.strip() sudo.name = name.strip()
...@@ -701,8 +706,14 @@ def perm_role_recycle(request): ...@@ -701,8 +706,14 @@ def perm_role_recycle(request):
recycle_assets.append(asset) recycle_assets.append(asset)
recycle_resource = gen_resource(recycle_assets) recycle_resource = gen_resource(recycle_assets)
task = MyTask(recycle_resource) task = MyTask(recycle_resource)
# TODO: 判断返回结果,处理异常 try:
msg = task.del_user(get_object(PermRole, id=role_id).name) msg_del_user = task.del_user(get_object(PermRole, id=role_id).name)
msg_del_sudo = task.del_user_sudo(get_object(PermRole, id=role_id).name)
logger.info("recycle user msg: %s" % msg_del_user)
logger.info("recycle sudo msg: %s" % msg_del_sudo)
except Exception, e:
logger.warning("Recycle Role failed: %s" % e)
raise ServerError(u"回收已推送的系统用户失败: %s" % e)
for asset_id in asset_ids: for asset_id in asset_ids:
asset = get_object(Asset, id=asset_id) asset = get_object(Asset, id=asset_id)
......
[base] [base]
url = http://192.168.244.129 url = http://127.0.0.1
key = 88aaaf7ffe3c6c04 key = 941enj9neshd1wes
ip = 0.0.0.0
port = 8000
log = debug log = debug
[db] [db]
...@@ -10,14 +12,11 @@ user = jumpserver ...@@ -10,14 +12,11 @@ user = jumpserver
password = mysql234 password = mysql234
database = jumpserver database = jumpserver
[websocket]
web_socket_host = 192.168.244.129:3000
[mail] [mail]
mail_enable = 1 mail_enable = 1
email_host = smtp.qq.com email_host =
email_port = 25 email_port = 587
email_host_user = xxxxxxxx@qq.com email_host_user =
email_host_password = xxxxxx email_host_password =
email_use_tls = False email_use_tls = True
email_use_ssl = False
...@@ -484,7 +484,8 @@ def my_render(template, data, request): ...@@ -484,7 +484,8 @@ def my_render(template, data, request):
def get_tmp_dir(): def get_tmp_dir():
dir_name = os.path.join('/tmp', uuid.uuid4().hex) seed = uuid.uuid4().hex[:4]
dir_name = os.path.join('/tmp', '%s-%s' % (datetime.datetime.now().strftime('%Y%m%d-%H%M%S'), seed))
mkdir(dir_name, mode=0777) mkdir(dir_name, mode=0777)
return dir_name return dir_name
......
...@@ -33,6 +33,11 @@ EMAIL_PORT = config.get('mail', 'email_port') ...@@ -33,6 +33,11 @@ EMAIL_PORT = config.get('mail', 'email_port')
EMAIL_HOST_USER = config.get('mail', 'email_host_user') EMAIL_HOST_USER = config.get('mail', 'email_host_user')
EMAIL_HOST_PASSWORD = config.get('mail', 'email_host_password') EMAIL_HOST_PASSWORD = config.get('mail', 'email_host_password')
EMAIL_USE_TLS = config.getboolean('mail', 'email_use_tls') EMAIL_USE_TLS = config.getboolean('mail', 'email_use_tls')
try:
EMAIL_USE_SSL = config.getboolean('mail', 'email_use_ssl')
except ConfigParser.NoOptionError:
EMAIL_USE_SSL = False
EMAIL_BACKEND = 'django_smtp_ssl.SSLEmailBackend' if EMAIL_USE_SSL else 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_TIMEOUT = 5 EMAIL_TIMEOUT = 5
# ======== Log ========== # ======== Log ==========
...@@ -41,7 +46,8 @@ SSH_KEY_DIR = os.path.join(BASE_DIR, 'keys/role_keys') ...@@ -41,7 +46,8 @@ SSH_KEY_DIR = os.path.join(BASE_DIR, 'keys/role_keys')
KEY = config.get('base', 'key') KEY = config.get('base', 'key')
URL = config.get('base', 'url') URL = config.get('base', 'url')
LOG_LEVEL = config.get('base', 'log') LOG_LEVEL = config.get('base', 'log')
WEB_SOCKET_HOST = config.get('websocket', 'web_socket_host') IP = config.get('base', 'ip')
PORT = config.get('base', 'port')
# Quick-start development settings - unsuitable for production # Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/ # See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/
......
...@@ -286,7 +286,7 @@ def upload(request): ...@@ -286,7 +286,7 @@ def upload(request):
res = gen_resource({'user': user, 'asset': asset_select}) res = gen_resource({'user': user, 'asset': asset_select})
runner = MyRunner(res) runner = MyRunner(res)
runner.run('copy', module_args='src=%s dest=%s directory_mode' runner.run('copy', module_args='src=%s dest=%s directory_mode'
% (upload_dir, upload_dir), pattern='*') % (upload_dir, '/tmp'), pattern='*')
ret = runner.results ret = runner.results
logger.debug(ret) logger.debug(ret)
FileLog(user=request.user.username, host=' '.join([asset.hostname for asset in asset_select]), FileLog(user=request.user.username, host=' '.join([asset.hostname for asset in asset_select]),
...@@ -344,7 +344,7 @@ def download(request): ...@@ -344,7 +344,7 @@ def download(request):
def exec_cmd(request): def exec_cmd(request):
role = request.GET.get('role') role = request.GET.get('role')
check_assets = request.GET.get('check_assets', '') check_assets = request.GET.get('check_assets', '')
web_terminal_uri = '%s/exec?role=%s' % (WEB_SOCKET_HOST, role) web_terminal_uri = '/ws/exec?role=%s' % (role)
return my_render('exec_cmd.html', locals(), request) return my_render('exec_cmd.html', locals(), request)
...@@ -354,9 +354,7 @@ def web_terminal(request): ...@@ -354,9 +354,7 @@ def web_terminal(request):
role_name = request.GET.get('role') role_name = request.GET.get('role')
asset = get_object(Asset, id=asset_id) asset = get_object(Asset, id=asset_id)
if asset: if asset:
print asset
hostname = asset.hostname hostname = asset.hostname
web_terminal_uri = '%s/terminal?id=%s&role=%s' % (WEB_SOCKET_HOST, asset_id, role_name)
return render_to_response('jlog/web_terminal.html', locals()) return render_to_response('jlog/web_terminal.html', locals())
...@@ -87,12 +87,12 @@ def db_update_user(**kwargs): ...@@ -87,12 +87,12 @@ def db_update_user(**kwargs):
admin_groups_post = kwargs.pop('admin_groups') admin_groups_post = kwargs.pop('admin_groups')
user_id = kwargs.pop('user_id') user_id = kwargs.pop('user_id')
user = User.objects.filter(id=user_id) user = User.objects.filter(id=user_id)
user_get = User.objects.get(id=user_id)
if user: if user:
pwd = kwargs.pop('password') user_get = user[0]
password = kwargs.pop('password')
user.update(**kwargs) user.update(**kwargs)
if pwd != '': if password.strip():
user_get.set_password(pwd) user_get.set_password(password)
user_get.save() user_get.save()
else: else:
return None return None
...@@ -137,7 +137,7 @@ def gen_ssh_key(username, password='', ...@@ -137,7 +137,7 @@ def gen_ssh_key(username, password='',
if authorized_keys: if authorized_keys:
auth_key_dir = os.path.join(home, username, '.ssh') auth_key_dir = os.path.join(home, username, '.ssh')
mkdir(auth_key_dir, username=username , mode=0700) mkdir(auth_key_dir, username=username, mode=0700)
authorized_key_file = os.path.join(auth_key_dir, 'authorized_keys') authorized_key_file = os.path.join(auth_key_dir, 'authorized_keys')
with open(private_key_file+'.pub') as pub_f: with open(private_key_file+'.pub') as pub_f:
with open(authorized_key_file, 'w') as auth_f: with open(authorized_key_file, 'w') as auth_f:
...@@ -146,15 +146,13 @@ def gen_ssh_key(username, password='', ...@@ -146,15 +146,13 @@ def gen_ssh_key(username, password='',
chown(authorized_key_file, username) chown(authorized_key_file, username)
def server_add_user(username, password, ssh_key_pwd='', ssh_key_login_need=True): def server_add_user(username, ssh_key_pwd=''):
""" """
add a system user in jumpserver add a system user in jumpserver
在jumpserver服务器上添加一个用户 在jumpserver服务器上添加一个用户
""" """
bash("useradd '%s'; echo '%s'; echo '%s:%s' | chpasswd " % bash("useradd -s '%s' '%s'" % (os.path.join(BASE_DIR, 'init.sh'), username))
(username, password, username, password)) gen_ssh_key(username, ssh_key_pwd)
if ssh_key_login_need:
gen_ssh_key(username, ssh_key_pwd)
def user_add_mail(user, kwargs): def user_add_mail(user, kwargs):
...@@ -171,7 +169,7 @@ def user_add_mail(user, kwargs): ...@@ -171,7 +169,7 @@ def user_add_mail(user, kwargs):
您的web登录密码: %s 您的web登录密码: %s
您的ssh密钥文件密码: %s 您的ssh密钥文件密码: %s
密钥下载地址: %s/juser/key/down/?uuid=%s 密钥下载地址: %s/juser/key/down/?uuid=%s
说明: 请登陆后再下载密钥 说明: 请登陆跳板机后台下载密钥, 然后使用密钥登陆跳板机
""" % (user.name, user.username, user_role.get(user.role, u'普通用户'), """ % (user.name, user.username, user_role.get(user.role, u'普通用户'),
kwargs.get('password'), kwargs.get('ssh_key_pwd'), URL, user.uuid) kwargs.get('password'), kwargs.get('ssh_key_pwd'), URL, user.uuid)
send_mail(mail_title, mail_msg, MAIL_FROM, [user.email], fail_silently=False) send_mail(mail_title, mail_msg, MAIL_FROM, [user.email], fail_silently=False)
...@@ -182,30 +180,20 @@ def server_del_user(username): ...@@ -182,30 +180,20 @@ def server_del_user(username):
delete a user from jumpserver linux system delete a user from jumpserver linux system
删除系统上的某用户 删除系统上的某用户
""" """
bash('userdel -r %s' % username) bash('userdel -r -f %s' % username)
def get_display_msg(user, password, ssh_key_pwd, ssh_key_login_need, send_mail_need): def get_display_msg(user, password='', ssh_key_pwd='', send_mail_need=False):
if send_mail_need: if send_mail_need:
msg = u'添加用户 %s 成功! 用户密码已发送到 %s 邮箱!' % (user.name, user.email) msg = u'添加用户 %s 成功! 用户密码已发送到 %s 邮箱!' % (user.name, user.email)
return msg
if ssh_key_login_need:
msg = u"""
跳板机地址: %s
用户名:%s
密码:%s
密钥密码:%s
密钥下载url: %s/juser/key/down/?uuid=%s
该账号密码可以登陆web和跳板机。
""" % (URL, user.username, password, ssh_key_pwd, URL, user.uuid)
else: else:
msg = u""" msg = u"""
跳板机地址: %s \n 跳板机地址: %s <br />
用户名:%s \n 用户名:%s <br />
密码:%s \n 密码:%s <br />
密钥密码:%s <br />
密钥下载url: %s/juser/key/down/?uuid=%s <br />
该账号密码可以登陆web和跳板机。 该账号密码可以登陆web和跳板机。
""" % (URL, user.username, password) """ % (URL, user.username, password, ssh_key_pwd, URL, user.uuid)
return msg return msg
...@@ -153,8 +153,7 @@ def user_add(request): ...@@ -153,8 +153,7 @@ def user_add(request):
ssh_key_pwd = PyCrypt.gen_rand_pass(16) ssh_key_pwd = PyCrypt.gen_rand_pass(16)
extra = request.POST.getlist('extra', []) extra = request.POST.getlist('extra', [])
is_active = False if '0' in extra else True is_active = False if '0' in extra else True
ssh_key_login_need = True send_mail_need = True if '1' in extra else False
send_mail_need = True if '2' in extra else False
try: try:
if '' in [username, password, ssh_key_pwd, name, role]: if '' in [username, password, ssh_key_pwd, name, role]:
...@@ -176,7 +175,7 @@ def user_add(request): ...@@ -176,7 +175,7 @@ def user_add(request):
ssh_key_pwd=ssh_key_pwd, ssh_key_pwd=ssh_key_pwd,
is_active=is_active, is_active=is_active,
date_joined=datetime.datetime.now()) date_joined=datetime.datetime.now())
server_add_user(username, password, ssh_key_pwd, ssh_key_login_need) server_add_user(username=username, ssh_key_pwd=ssh_key_pwd)
user = get_object(User, username=username) user = get_object(User, username=username)
if groups: if groups:
user_groups = [] user_groups = []
...@@ -193,7 +192,7 @@ def user_add(request): ...@@ -193,7 +192,7 @@ def user_add(request):
else: else:
if MAIL_ENABLE and send_mail_need: if MAIL_ENABLE and send_mail_need:
user_add_mail(user, kwargs=locals()) user_add_mail(user, kwargs=locals())
msg = get_display_msg(user, password, ssh_key_pwd, ssh_key_login_need, send_mail_need) msg = get_display_msg(user, password=password, ssh_key_pwd=ssh_key_pwd, send_mail_need=send_mail_need)
return my_render('juser/user_add.html', locals(), request) return my_render('juser/user_add.html', locals(), request)
...@@ -361,7 +360,7 @@ def user_edit(request): ...@@ -361,7 +360,7 @@ def user_edit(request):
admin_groups = request.POST.getlist('admin_groups', []) admin_groups = request.POST.getlist('admin_groups', [])
extra = request.POST.getlist('extra', []) extra = request.POST.getlist('extra', [])
is_active = True if '0' in extra else False is_active = True if '0' in extra else False
email_need = True if '2' in extra else False email_need = True if '1' in extra else False
user_role = {'SU': u'超级管理员', 'GA': u'部门管理员', 'CU': u'普通用户'} user_role = {'SU': u'超级管理员', 'GA': u'部门管理员', 'CU': u'普通用户'}
if user_id: if user_id:
...@@ -369,11 +368,6 @@ def user_edit(request): ...@@ -369,11 +368,6 @@ def user_edit(request):
else: else:
return HttpResponseRedirect(reverse('user_list')) return HttpResponseRedirect(reverse('user_list'))
if password != '':
password_decode = password
else:
password_decode = None
db_update_user(user_id=user_id, db_update_user(user_id=user_id,
password=password, password=password,
name=name, name=name,
...@@ -392,7 +386,7 @@ def user_edit(request): ...@@ -392,7 +386,7 @@ def user_edit(request):
密码:%s (如果密码为None代表密码为原密码) 密码:%s (如果密码为None代表密码为原密码)
权限::%s 权限::%s
""" % (user.name, URL, user.username, password_decode, user_role.get(role_post, u'')) """ % (user.name, URL, user.username, password, user_role.get(role_post, u''))
send_mail('您的信息已修改', msg, MAIL_FROM, [email], fail_silently=False) send_mail('您的信息已修改', msg, MAIL_FROM, [email], fail_silently=False)
return HttpResponseRedirect(reverse('user_list')) return HttpResponseRedirect(reverse('user_list'))
...@@ -453,7 +447,6 @@ def down_key(request): ...@@ -453,7 +447,6 @@ def down_key(request):
uuid_r = request.GET.get('uuid', '') uuid_r = request.GET.get('uuid', '')
else: else:
uuid_r = request.user.uuid uuid_r = request.user.uuid
if uuid_r: if uuid_r:
user = get_object(User, uuid=uuid_r) user = get_object(User, uuid=uuid_r)
if user: if user:
...@@ -466,6 +459,8 @@ def down_key(request): ...@@ -466,6 +459,8 @@ def down_key(request):
f.close() f.close()
response = HttpResponse(data, content_type='application/octet-stream') response = HttpResponse(data, content_type='application/octet-stream')
response['Content-Disposition'] = 'attachment; filename=%s' % os.path.basename(private_key_file) response['Content-Disposition'] = 'attachment; filename=%s' % os.path.basename(private_key_file)
if request.user.role == 'CU':
os.unlink(private_key_file)
return response return response
return HttpResponse('No Key File. Contact Admin.') return HttpResponse('No Key File. Contact Admin.')
This diff is collapsed.
...@@ -4,70 +4,88 @@ ...@@ -4,70 +4,88 @@
# chkconfig: - 85 12 # chkconfig: - 85 12
# description: Open source detecting system # description: Open source detecting system
# processname: jumpserver # processname: jumpserver
# Date: 2015-04-12 # Date: 2016-02-27
# Version: 2.0.0 # Version: 3.0.1
# Site: http://www.jumpserver.org # Site: http://www.jumpserver.org
# Author: Jumpserver Team # Author: Jumpserver Team
. /etc/init.d/functions jumpserver_dir=
export PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/opt/node/bin
base_dir=$(dirname $0) base_dir=$(dirname $0)
jumpserver_dir=${jumpserver_dir:-$base_dir}
PROC_NAME="jumpsever" export PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
if [ -f ${jumpserver_dir}/install/functions ];then
. ${jumpserver_dir}/install/functions
elif [ -f /etc/init.d/functions ];then
. /etc/init.d/functions
else
echo "No functions script found in [./functions, ./install/functions, /etc/init.d/functions]"
exit 1
fi
PROC_NAME="jumpserver"
lockfile=/var/lock/subsys/${PROC_NAME} lockfile=/var/lock/subsys/${PROC_NAME}
start() { start() {
jump_start=$"Starting ${PROC_NAME} service:" jump_start=$"Starting ${PROC_NAME} service:"
if [ -f $lockfile ];then
if [ -f $lockfile ];then echo -n "jumpserver is running..."
echo "jumpserver is running..." success "$jump_start"
success "$jump_start" echo
else else
daemon python $base_dir/manage.py runserver 0.0.0.0:80 &>> /tmp/jumpserver.log 2>&1 & daemon python $jumpserver_dir/manage.py crontab add &>> /var/log/jumpserver.log 2>&1
daemon python $base_dir/run_websocket.py &> /dev/null 2>&1 & daemon python $jumpserver_dir/run_server.py &> /dev/null 2>&1 &
sleep 4 sleep 1
echo -n "$jump_start"
echo -n "$jump_start" ps axu | grep 'run_server' | grep -v 'grep' &> /dev/null
nums=0 if [ $? == '0' ];then
for i in manage.py run_websocket.py;do success "$jump_start"
ps aux | grep "$i" | grep -v 'grep' &> /dev/null && let nums+=1 || echo "$i not running" if [ ! -e $lockfile ]; then
done lockfile_dir=`dirname $lockfile`
mkdir -pv $lockfile_dir
if [ "x$nums" == "x2" ];then fi
success "$jump_start" touch "$lockfile"
touch "$lockfile" echo
echo else
else failure "$jump_start"
failure "$jump_start" echo
echo fi
fi fi
fi
} }
stop() { stop() {
echo -n $"Stopping ${PROC_NAME} service:"
echo -n $"Stopping ${PROC_NAME} service:" daemon python $jumpserver_dir/manage.py crontab remove &>> /var/log/jumpserver.log 2>&1
ps aux | grep -E 'run_server.py' | grep -v grep | awk '{print $2}' | xargs kill -9 &> /dev/null
ps aux | grep -E 'manage.py|run_websocket.py' | grep -v grep | awk '{print $2}' | xargs kill -9 &> /dev/null ret=$?
ret=$? if [ $ret -eq 0 ]; then
echo_success
if [ $ret -eq 0 ]; then echo
echo_success
echo
rm -f "$lockfile" rm -f "$lockfile"
else else
echo_failure echo_failure
echo echo
rm -f "$lockfile" rm -f "$lockfile"
fi fi
} }
status(){
ps axu | grep 'run_server' | grep -v 'grep' &> /dev/null
if [ $? == '0' ];then
echo -n "jumpserver is running..."
success
touch "$lockfile"
echo
else
echo -n "jumpserver is not running."
failure
echo
fi
}
restart(){ restart(){
...@@ -76,22 +94,22 @@ restart(){ ...@@ -76,22 +94,22 @@ restart(){
} }
# See how we were called. # See how we were called.
case "$1" in case "$1" in
start) start)
start start
;; ;;
stop) stop)
stop stop
;; ;;
restart) restart)
restart restart
;; ;;
*) status)
echo $"Usage: $0 {start|stop|restart}" status
exit 2 ;;
esac *)
echo $"Usage: $0 {start|stop|restart|status}"
exit 2
esac
/*
AngularJS v1.2.5
(c) 2010-2014 Google, Inc. http://angularjs.org
License: MIT
*/
(function(h,e,A){'use strict';function u(w,q,k){return{restrict:"ECA",terminal:!0,priority:400,transclude:"element",link:function(a,c,b,f,n){function y(){l&&(l.$destroy(),l=null);g&&(k.leave(g),g=null)}function v(){var b=w.current&&w.current.locals;if(b&&b.$template){var b=a.$new(),f=w.current;g=n(b,function(d){k.enter(d,null,g||c,function(){!e.isDefined(t)||t&&!a.$eval(t)||q()});y()});l=f.scope=b;l.$emit("$viewContentLoaded");l.$eval(h)}else y()}var l,g,t=b.autoscroll,h=b.onload||"";a.$on("$routeChangeSuccess",
v);v()}}}function z(e,h,k){return{restrict:"ECA",priority:-400,link:function(a,c){var b=k.current,f=b.locals;c.html(f.$template);var n=e(c.contents());b.controller&&(f.$scope=a,f=h(b.controller,f),b.controllerAs&&(a[b.controllerAs]=f),c.data("$ngControllerController",f),c.children().data("$ngControllerController",f));n(a)}}}h=e.module("ngRoute",["ng"]).provider("$route",function(){function h(a,c){return e.extend(new (e.extend(function(){},{prototype:a})),c)}function q(a,e){var b=e.caseInsensitiveMatch,
f={originalPath:a,regexp:a},h=f.keys=[];a=a.replace(/([().])/g,"\\$1").replace(/(\/)?:(\w+)([\?|\*])?/g,function(a,e,b,c){a="?"===c?c:null;c="*"===c?c:null;h.push({name:b,optional:!!a});e=e||"";return""+(a?"":e)+"(?:"+(a?e:"")+(c&&"(.+?)"||"([^/]+)")+(a||"")+")"+(a||"")}).replace(/([\/$\*])/g,"\\$1");f.regexp=RegExp("^"+a+"$",b?"i":"");return f}var k={};this.when=function(a,c){k[a]=e.extend({reloadOnSearch:!0},c,a&&q(a,c));if(a){var b="/"==a[a.length-1]?a.substr(0,a.length-1):a+"/";k[b]=e.extend({redirectTo:a},
q(b,c))}return this};this.otherwise=function(a){this.when(null,a);return this};this.$get=["$rootScope","$location","$routeParams","$q","$injector","$http","$templateCache","$sce",function(a,c,b,f,n,q,v,l){function g(){var d=t(),m=r.current;if(d&&m&&d.$$route===m.$$route&&e.equals(d.pathParams,m.pathParams)&&!d.reloadOnSearch&&!x)m.params=d.params,e.copy(m.params,b),a.$broadcast("$routeUpdate",m);else if(d||m)x=!1,a.$broadcast("$routeChangeStart",d,m),(r.current=d)&&d.redirectTo&&(e.isString(d.redirectTo)?
c.path(u(d.redirectTo,d.params)).search(d.params).replace():c.url(d.redirectTo(d.pathParams,c.path(),c.search())).replace()),f.when(d).then(function(){if(d){var a=e.extend({},d.resolve),c,b;e.forEach(a,function(d,c){a[c]=e.isString(d)?n.get(d):n.invoke(d)});e.isDefined(c=d.template)?e.isFunction(c)&&(c=c(d.params)):e.isDefined(b=d.templateUrl)&&(e.isFunction(b)&&(b=b(d.params)),b=l.getTrustedResourceUrl(b),e.isDefined(b)&&(d.loadedTemplateUrl=b,c=q.get(b,{cache:v}).then(function(a){return a.data})));
e.isDefined(c)&&(a.$template=c);return f.all(a)}}).then(function(c){d==r.current&&(d&&(d.locals=c,e.copy(d.params,b)),a.$broadcast("$routeChangeSuccess",d,m))},function(c){d==r.current&&a.$broadcast("$routeChangeError",d,m,c)})}function t(){var a,b;e.forEach(k,function(f,k){var p;if(p=!b){var s=c.path();p=f.keys;var l={};if(f.regexp)if(s=f.regexp.exec(s)){for(var g=1,q=s.length;g<q;++g){var n=p[g-1],r="string"==typeof s[g]?decodeURIComponent(s[g]):s[g];n&&r&&(l[n.name]=r)}p=l}else p=null;else p=null;
p=a=p}p&&(b=h(f,{params:e.extend({},c.search(),a),pathParams:a}),b.$$route=f)});return b||k[null]&&h(k[null],{params:{},pathParams:{}})}function u(a,c){var b=[];e.forEach((a||"").split(":"),function(a,d){if(0===d)b.push(a);else{var e=a.match(/(\w+)(.*)/),f=e[1];b.push(c[f]);b.push(e[2]||"");delete c[f]}});return b.join("")}var x=!1,r={routes:k,reload:function(){x=!0;a.$evalAsync(g)}};a.$on("$locationChangeSuccess",g);return r}]});h.provider("$routeParams",function(){this.$get=function(){return{}}});
h.directive("ngView",u);h.directive("ngView",z);u.$inject=["$route","$anchorScroll","$animate"];z.$inject=["$compile","$controller","$route"]})(window,window.angular);
This source diff could not be displayed because it is too large. You can view the blob instead.
/**
* Created by liuzheng on 3/25/16.
*/
'use strict';
var NgApp = angular.module('NgApp', ['ngRoute']);
NgApp.config(['$httpProvider', function ($httpProvider) {
$httpProvider.defaults.transformRequest = function (obj) {
var str = [];
for (var p in obj) {
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
}
return str.join("&");
};
$httpProvider.defaults.xsrfCookieName = 'csrftoken';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
$httpProvider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
$httpProvider.defaults.headers.post = {
'Content-Type': 'application/x-www-form-urlencoded'
}
}]);
NgApp.controller('TerminalRecordCtrl', function ($scope, $http) {
$http.post(window.location.href).success(function (data) {
var toggle = true;
var totalTime = 0;
var TICK = 33;
var TIMESTEP = 33;
var time = 33;
var timer;
var pos = 0;
// Thanks http://stackoverflow.com/a/2998822
function zeroPad(num, size) {
var s = "0" + num;
return s.substr(s.length - size);
}
$scope.scrub = function () {
var setPercent = document.getElementById('scrubber').value;
time = (setPercent / 100) * totalTime;
$scope.restart(time);
};
function buildTimeString(millis) {
var hours = zeroPad(Math.floor(millis / (1000 * 60 * 60)), 2);
millis -= hours * (1000 * 60 * 60);
var minutes = zeroPad(Math.floor(millis / (1000 * 60)), 2);
millis -= minutes * (1000 * 60);
var seconds = zeroPad(Math.floor(millis / 1000), 2);
return hours + ':' + minutes + ':' + seconds;
}
function advance() {
document.getElementById('scrubber').value =
Math.ceil((time / totalTime) * 100);
document.getElementById("beforeScrubberText").innerHTML = buildTimeString(time);
for (; pos < timelist.length; pos++) {
if (timelist[pos] * 1000 <= time) {
term.write(data[timelist[pos]]);
} else {
break;
}
}
if (pos >= timelist.length) {
clearInterval(timer);
}
time += TIMESTEP;
}
$scope.pause = function (test) {
if (!toggle && test) {
return;
}
if (toggle) {
clearInterval(timer);
toggle = !toggle;
} else {
timer = setInterval(advance, TICK);
toggle = !toggle;
}
};
$scope.setSpeed = function () {
var speed = document.getElementById('speed').value;
if (speed == 0) {
TIMESTEP = TICK;
} else if (speed < 0) {
TIMESTEP = TICK / -speed;
} else {
TIMESTEP = TICK * speed;
}
};
$scope.restart = function (millis) {
clearInterval(timer);
term.reset();
time = millis;
pos = 0;
toggle = true;
timer = setInterval(advance, TICK);
};
var term = new Terminal({
rows: 24,
cols: 80,
useStyle: true,
screenKeys: true
});
var timelist = [];
for (var i in data) {
totalTime = Math.max(totalTime, i);
timelist.push(i);
}
timelist = timelist.sort(function(a, b){return a-b});
totalTime = totalTime * 1000;
document.getElementById("afterScrubberText").innerHTML = buildTimeString(totalTime);
term.open(document.getElementById('terminal'));
timer = setInterval(advance, TICK);
})
})
\ No newline at end of file
This diff is collapsed.
/**
* Created by liuzheng on 3/3/16.
*/
var rowHeight = 1;
var colWidth = 1;
function WSSHClient() {
}
WSSHClient.prototype._generateEndpoint = function (options) {
console.log(options);
if (window.location.protocol == 'https:') {
var protocol = 'wss://';
} else {
var protocol = 'ws://';
}
var endpoint = protocol + document.URL.match(RegExp('//(.*?)/'))[1] + '/ws/terminal' + document.URL.match(/(\?.*)/);
return endpoint;
};
WSSHClient.prototype.connect = function (options) {
var endpoint = this._generateEndpoint(options);
if (window.WebSocket) {
this._connection = new WebSocket(endpoint);
}
else if (window.MozWebSocket) {
this._connection = MozWebSocket(endpoint);
}
else {
options.onError('WebSocket Not Supported');
return;
}
this._connection.onopen = function () {
options.onConnect();
};
this._connection.onmessage = function (evt) {
try{
options.onData(evt.data);
} catch (e) {
var data = JSON.parse(evt.data.toString());
options.onError(data.error);
}
};
this._connection.onclose = function (evt) {
options.onClose();
};
};
WSSHClient.prototype.send = function (data) {
this._connection.send(JSON.stringify({'data': data}));
};
function openTerminal(options) {
var client = new WSSHClient();
var term = new Terminal({
rows: rowHeight,
cols: colWidth,
useStyle: true,
screenKeys: true
});
term.open();
term.on('data', function (data) {
client.send(data)
});
$('.terminal').detach().appendTo('#term');
term.resize(80, 24);
term.write('Connecting...');
client.connect($.extend(options, {
onError: function (error) {
term.write('Error: ' + error + '\r\n');
},
onConnect: function () {
// Erase our connecting message
term.write('\r');
},
onClose: function () {
term.write('Connection Reset By Peer');
},
onData: function (data) {
term.write(data);
}
}));
rowHeight = 0.0 + 1.00 * $('.terminal').height() / 24;
colWidth = 0.0 + 1.00 * $('.terminal').width() / 80;
return {'term': term, 'client': client};
}
function resize() {
$('.terminal').css('width', window.innerWidth - 25);
console.log(window.innerWidth);
console.log(window.innerWidth - 10);
var rows = Math.floor(window.innerHeight / rowHeight) - 2;
var cols = Math.floor(window.innerWidth / colWidth) - 1;
return {rows: rows, cols: cols};
}
$(document).ready(function () {
var options = {};
$('#ssh').show();
var term_client = openTerminal(options);
console.log(rowHeight);
// by liuzheng712 because it will bring record bug
//window.onresize = function () {
// var geom = resize();
// console.log(geom);
// term_client.term.resize(geom.cols, geom.rows);
// term_client.client.send({'resize': {'rows': geom.rows, 'cols': geom.cols}});
// $('#ssh').show();
//}
});
\ No newline at end of file
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
protocol = 'wss://'; protocol = 'wss://';
} }
var wsUri = protocol + "{{ web_terminal_uri }}"; //请求的websocket url var wsUri = protocol + document.URL.match(RegExp('//(.*?)/'))[1] + "{{ web_terminal_uri }}"; //请求的websocket url
var ws = new WebSocket(wsUri); var ws = new WebSocket(wsUri);
function createSystemMessage(message) { function createSystemMessage(message) {
...@@ -82,7 +82,7 @@ ...@@ -82,7 +82,7 @@
<style type="text/css"> <style type="text/css">
* { * {
font-family: "Monaco", "DejaVu Sans Mono", "Liberation Mono", monospace; font-family: "Monaco", "Microsoft Yahei", "DejaVu Sans Mono", "Liberation Mono", monospace;
font-size: 11px; font-size: 11px;
} }
......
...@@ -36,6 +36,5 @@ ...@@ -36,6 +36,5 @@
} else { } else {
$("#"+s1).addClass('active'); $("#"+s1).addClass('active');
$('#'+s1+' .'+s2).addClass('active'); $('#'+s1+' .'+s2).addClass('active');
console.log(s1)
} }
</script> </script>
<div class="footer fixed"> <div class="footer fixed">
<div class="pull-right"> <div class="pull-right">
Version <strong>0.3.0</strong> GPL. Version <strong>0.3.1</strong> GPL.
</div> </div>
<div> <div>
<strong>Copyright</strong> Jumpserver.org Team &copy; 2014-2015 <strong>Copyright</strong> Jumpserver.org Team &copy; 2014-2015
......
...@@ -210,7 +210,7 @@ ...@@ -210,7 +210,7 @@
{% if login_10 %} {% if login_10 %}
{% for login in login_10 %} {% for login in login_10 %}
<div class="feed-element"> <div class="feed-element">
<a href="profile.html" class="pull-left"> <a href="#" class="pull-left">
<img alt="image" class="img-circle" src="/static/img/root.png"> <img alt="image" class="img-circle" src="/static/img/root.png">
</a> </a>
<div class="media-body "> <div class="media-body ">
...@@ -232,7 +232,7 @@ ...@@ -232,7 +232,7 @@
<div class="feed-activity-list"> <div class="feed-activity-list">
{% for login in login_more_10 %} {% for login in login_more_10 %}
<div class="feed-element"> <div class="feed-element">
<a href="profile.html" class="pull-left"> <a href="#" class="pull-left">
<img alt="image" class="img-circle" src="/static/img/root.png"> <img alt="image" class="img-circle" src="/static/img/root.png">
</a> </a>
<div class="media-body "> <div class="media-body ">
......
...@@ -50,24 +50,23 @@ ...@@ -50,24 +50,23 @@
<div class="hr-line-dashed"></div> <div class="hr-line-dashed"></div>
<div class="form-group"> <div class="form-group">
<label for="j_group" class="col-sm-2 control-label">管理账号<span class="red-fonts"> *</span></label> <label for="j_group" class="col-sm-2 control-label">管理用户<span class="red-fonts"> *</span></label>
<div class="col-sm-2"> <div class="col-sm-2">
<div class="radio i-checks"> <div class="radio i-checks">
<label> <label style="padding-left: 0">
<input type="checkbox" checked="checked" id="id_use_default_auth" name="use_default_auth"><span> 使用默认 </span> <input type="checkbox" checked="checked" id="id_use_default_auth" name="use_default_auth"><span> 使用默认 </span>
</label> </label>
</div> </div>
</div> </div>
</div> </div>
<p class="col-sm-offset-2">Tips: 管理账号是服务器存在的root等高权限账号,用来推送新建系统用户</p> <p class="col-sm-offset-2">Tips: 管理用户是服务器存在的root或拥有sudo的用户,用来推送系统用户</p>
<div class="form-group" id="admin_account" style="display: none"> <div class="form-group" id="admin_account" style="display: none">
<div class="hr-line-dashed"></div> <label class="col-sm-2 control-label"> <span class="red-fonts"></span> </label>
<label class="col-sm-2 control-label"> 管理用户名<span class="red-fonts">*</span> </label>
<div class="col-sm-3"> <div class="col-sm-3">
<input type="text" placeholder="Username" name="username" class="form-control"> <input type="text" placeholder="Username" name="username" class="form-control">
</div> </div>
<label class="col-sm-1 control-label"> 密码<span class="red-fonts">*</span> </label> <label class="col-sm-1 control-label"> <span class="red-fonts"></span> </label>
<div class="col-sm-4"> <div class="col-sm-4">
<input type="password" placeholder="Password" name="password" class="form-control"> <input type="password" placeholder="Password" name="password" class="form-control">
</div> </div>
......
...@@ -57,20 +57,19 @@ ...@@ -57,20 +57,19 @@
<label for="j_group" class="col-sm-2 control-label">管理账号 <span class="red-fonts">*</span></label> <label for="j_group" class="col-sm-2 control-label">管理账号 <span class="red-fonts">*</span></label>
<div class="col-sm-2"> <div class="col-sm-2">
<div class="radio i-checks"> <div class="radio i-checks">
<label> <label style="padding-left: 0">
<input type="checkbox" {% if asset.use_default_auth %} checked="checked" {% endif %} id="id_use_default_auth" name="use_default_auth"><span> 使用默认 </span> <input type="checkbox" {% if asset.use_default_auth %} checked="checked" {% endif %} id="id_use_default_auth" name="use_default_auth"><span> 使用默认 </span>
</label> </label>
</div> </div>
</div> </div>
</div> </div>
<div class="form-group" id="admin_account" {% if asset.use_default_auth %} style="display: none" {% endif %}> <div class="form-group" id="admin_account" {% if asset.use_default_auth %} style="display: none" {% endif %}>
<div class="hr-line-dashed"></div> <label class="col-sm-2 control-label"> </label>
<label class="col-sm-2 control-label"> 管理用户名 <span class="red-fonts">*</span> </label>
<div class="col-sm-3"> <div class="col-sm-3">
<input type="text" value="{{ asset.username }}" name="username" class="form-control"> <input type="text" value="{{ asset.username }}" name="username" class="form-control">
</div> </div>
<label class="col-sm-1 control-label"> 密码<span class="red-fonts">*</span> </label> <label class="col-sm-1 control-label"> </label>
<div class="col-sm-4"> <div class="col-sm-4">
<input type="password" value="" name="password" placeholder="不填写即不更改密码." class="form-control"> <input type="password" value="" name="password" placeholder="不填写即不更改密码." class="form-control">
</div> </div>
......
...@@ -8,6 +8,11 @@ ...@@ -8,6 +8,11 @@
{% include 'nav_cat_bar.html' %} {% include 'nav_cat_bar.html' %}
<style> <style>
iframe {
overflow:hidden;
}
.bootstrap-dialog-body { .bootstrap-dialog-body {
background-color: rgba(0, 0, 0, 0); background-color: rgba(0, 0, 0, 0);
} }
...@@ -133,7 +138,7 @@ ...@@ -133,7 +138,7 @@
</div> </div>
{% include 'paginator.html' %} {% include 'paginator.html' %}
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
...@@ -157,7 +162,7 @@ ...@@ -157,7 +162,7 @@
title: title, title: title,
maxmin: true, maxmin: true,
shade: false, shade: false,
area: ['800px', '520px'], area: ['620px', '450px'],
content: url content: url
}); });
return false; return false;
......
...@@ -3,14 +3,16 @@ ...@@ -3,14 +3,16 @@
<style> <style>
.terminal { .terminal {
border: #000 solid 5px; border: #000 solid 5px;
font-family: "Monaco", "DejaVu Sans Mono", "Liberation Mono", monospace; font-family: "Monaco", "Microsoft Yahei", "DejaVu Sans Mono", "Liberation Mono", monospace;
font-size: 11px; font-size: 11px;
color: #f0f0f0; color: #f0f0f0;
background: rgba(0, 0, 0, 0.6); background: rgba(0, 0, 0, 0.6);
width: 600px; width: 600px;
box-shadow: rgba(0, 0, 0, 0.6) 2px 2px 20px; box-shadow: rgba(0, 0, 0, 0.6) 2px 2px 20px;
} white-space: nowrap;
display: inline-block;
}
.reverse-video { .reverse-video {
color: #000; color: #000;
background: #f0f0f0; background: #f0f0f0;
...@@ -109,7 +111,7 @@ ...@@ -109,7 +111,7 @@
<td id="remote_ip" class="text-center"> {{ post.remote_ip }} </td> <td id="remote_ip" class="text-center"> {{ post.remote_ip }} </td>
<td class="text-center"> {{ post.login_type }} </td> <td class="text-center"> {{ post.login_type }} </td>
<td class="text-center"><a href="{% url 'log_history' %}?id={{ post.id }}" class="log_command"> 统计 </a></td> <td class="text-center"><a href="{% url 'log_history' %}?id={{ post.id }}" class="log_command"> 统计 </a></td>
<td class="text-center"><a class="monitor" file_path="{{ post.log_path }}"> 监控 </a></td> <td class="text-center"><a class="monitor" monitor-id="{{ post.id }}" file_path="{{ post.log_path }}"> 监控 </a></td>
<td class="text-center"><input type="button" id="cut" class="btn btn-danger btn-xs" name="cut" value="阻断" onclick='cut("{{ post.pid }}", "{{ post.login_type }}")' /></td> <td class="text-center"><input type="button" id="cut" class="btn btn-danger btn-xs" name="cut" value="阻断" onclick='cut("{{ post.pid }}", "{{ post.login_type }}")' /></td>
<td class="text-center" id="start_time"> {{ post.start_time|date:"Y-m-d H:i:s" }} </td> <td class="text-center" id="start_time"> {{ post.start_time|date:"Y-m-d H:i:s" }} </td>
</tr> </tr>
...@@ -128,36 +130,33 @@ ...@@ -128,36 +130,33 @@
</div> </div>
{#<script src="http://{{ web_socket_host }}/socket.io/socket.io.js"></script>#}
<script> <script>
{# $(document).ready(function(){#}
{# $('.monitor').click(function(){#}
{# window.open('/jlog/monitor/', '监控', 'height=500, width=910, top=89px, left=99px,toolbar=no,menubar=no,scrollbars=auto,resizeable=no,location=no,status=no');#}
{# })#}
{# });#}
function init(obj){ function init(obj){
var protocol = "ws://";
if (window.location.protocol == 'https:') { if (window.location.protocol == 'https:') {
protocol = 'wss://'; var protocol = 'wss://';
} else {
var protocol = 'ws://';
} }
var endpoint = protocol + document.URL.match(RegExp('//(.*?)/'))[1] + '/ws/monitor';
var monitorid = obj.attr('monitor-id');
var file_path = obj.attr('file_path'); var file_path = obj.attr('file_path');
var wsUri = protocol + '{{ web_monitor_uri }}'; {# var socket = new WebSocket(endpoint + '?id=' + monitorid);#}
var socket = new WebSocket(wsUri + '?file_path=' + file_path); var socket = new WebSocket(endpoint + '?file_path=' + file_path);
var term = new Terminal({ var term = new Terminal({
cols: 80, cols: 98,
rows: 24, rows: 28,
screenKeys: false, screenKeys: false,
handler: function(){return false} handler: function(){return false}
}); });
var tag = $('<div id="term" style="height:500px; overflow: auto;background-color: rgba(0, 0, 0, 0);border: none"></div>'); var tag = $('<div id="term" style="height:500px; overflow: auto;background-color: rgba(0, 0, 0, 0);border: none"></div>');
term.open(); term.open();
term.resize(80, 24); $('.terminal').hide();
term.resize(98, 28);
socket.onopen = function(evt){ socket.onopen = function(evt){
socket.send('hello'); {# socket.send('hello');#}
term.write('~.~ Connect WebSocket Success.~.~ \r\n'); term.write('~.~ Connect WebSocket Success.~.~ \r\n');
}; };
...@@ -170,11 +169,11 @@ ...@@ -170,11 +169,11 @@
BootstrapDialog.show({message: function(){ BootstrapDialog.show({message: function(){
//服务器端认证 //服务器端认证
{# socket.send('login', {userid:message.id, filename:message.filename,username:username,seed:seed});#}
window.setTimeout(function(){ window.setTimeout(function(){
$('.terminal').detach().appendTo('#term'); $('.terminal').detach().appendTo('#term');
$('.terminal').show();
socket.onmessage = function(evt){ socket.onmessage = function(evt){
term.write(evt.data); term.write(evt.data);
}}, 1000); }}, 1000);
return tag[0]; return tag[0];
...@@ -209,19 +208,18 @@ ...@@ -209,19 +208,18 @@
}); });
function cut(num, login_type){ function cut(num, login_type){
console.log(login_type); var protocol = window.location.protocol;
var endpoint = protocol + '//' + document.URL.match(RegExp('//(.*?)/'))[1] + '/kill';
if (login_type=='web'){ if (login_type=='web'){
var g_url = '{{ web_kill_uri }}' + '?id=' + num; var g_url = endpoint + '?id=' + num;
console.log(g_url);
} else { } else {
var g_url = "{% url 'log_kill' %} }?id=" + num; var g_url = "{% url 'log_kill' %}?id=" + num;
} }
$.ajax({ $.get(g_url+"&sessionid={{ session_id }}", function () {
type: "GET", window.open("{% url 'log_list' 'online' %}", "_self")
url: g_url+"&sessionid={{ session_id }}", })
success: window.open("{% url 'log_list' 'online' %}", "_self")
});
} }
</script> </script>
{% endblock %} {% endblock %}
\ No newline at end of file
<!DOCTYPE html>
<html ng-app="NgApp" style=" overflow:hidden;">
<head lang="en">
<title>Jumpserver 录像回放</title>
<script type="application/javascript" src='/static/js/jquery-2.1.1.js'></script>
<script type="application/javascript" src='/static/js/angular.min.js'></script>
<script type="application/javascript" src='/static/js/angular-route.min.js'></script>
<script type="application/javascript" src='/static/js/term.js'></script>
</head>
<body>
{% csrf_token %}
<div ng-controller="TerminalRecordCtrl">
<input type="button" value="Play/Pause" ng-click="pause(false);"/>
<input type="button" value="Restart" ng-click="restart(1);"/>
<span id="beforeScrubberText"></span>
<input id="scrubber" type="range" value="0" min=0 max=100
ng-mousedown="pause(true);" ng-mouseup="scrub();"/>
<span id="afterScrubberText"></span>
-5x <input id="speed" type="range" value="0" min=-5 max=5
ng-mouseup="setSpeed();"/> +5x
<div id="terminal"></div>
</div>
<script type="application/javascript" src='/static/js/record.js'></script>
</body>
</html>
\ No newline at end of file
This diff is collapsed.
...@@ -11,12 +11,14 @@ ...@@ -11,12 +11,14 @@
.terminal { .terminal {
border: #000 solid 5px; border: #000 solid 5px;
font-family: "Monaco", "DejaVu Sans Mono", "Liberation Mono", monospace; font-family: "Monaco", "Microsoft Yahei", "DejaVu Sans Mono", "Liberation Mono", monospace;
font-size: 11px; font-size: 11px;
color: #f0f0f0; color: #f0f0f0;
background: #000; background: #000;
width: 600px; width: 600px;
box-shadow: rgba(0, 0, 0, 0.8) 2px 2px 20px; box-shadow: rgba(0, 0, 0, 0.8) 2px 2px 20px;
white-space: nowrap;
display: inline-block;
} }
.reverse-video { .reverse-video {
...@@ -36,114 +38,6 @@ ...@@ -36,114 +38,6 @@
</script> </script>
<script type="application/javascript" src="/static/js/term.js"> <script type="application/javascript" src="/static/js/term.js">
</script> </script>
<script type="application/javascript"> <script type="application/javascript" src="/static/js/webterminal.js"></script>
var rowHeight = 1;
var colWidth = 1;
function WSSHClient() {
}
WSSHClient.prototype.connect = function(options) {
var protocol = "ws://";
if (window.location.protocol == 'https:') {
protocol = 'wss://';
}
var endpoint = protocol + '{{ web_terminal_uri }}';
if (window.WebSocket) {
this._connection = new WebSocket(endpoint);
}
else if (window.MozWebSocket) {
this._connection = MozWebSocket(endpoint);
}
else {
options.onError('WebSocket Not Supported');
return ;
}
this._connection.onopen = function() {
options.onConnect();
};
this._connection.onmessage = function (evt) {
var data = JSON.parse(evt.data.toString());
if (data.error !== undefined) {
options.onError(data.error);
}
else {
options.onData(data.data);
}
};
this._connection.onclose = function(evt) {
options.onClose();
};
};
WSSHClient.prototype.send = function(data) {
this._connection.send(JSON.stringify({'data': data}));
};
function openTerminal(options) {
var client = new WSSHClient();
var term = new Terminal(80, 24, function(key) {
client.send(key);
});
term.open();
$('.terminal').detach().appendTo('#term');
term.resize(80, 24);
term.write('Connecting...');
client.connect($.extend(options, {
onError: function(error) {
term.write('Error: ' + error + '\r\n');
},
onConnect: function() {
// Erase our connecting message
term.write('\r');
},
onClose: function() {
term.write('Connection Reset By Peer');
},
onData: function(data) {
term.write(data);
}
}));
rowHeight = 0.0 + 1.00 * $('.terminal').height() / 24 ;
colWidth = 0.0 + 1.00 * $('.terminal').width() / 80;
return {'term': term, 'client': client};
}
function resize(){
$('.terminal').css('width', window.innerWidth-25);
console.log(window.innerWidth);
console.log(window.innerWidth-10);
var rows = Math.floor(window.innerHeight/rowHeight) - 2;
var cols = Math.floor(window.innerWidth/colWidth) - 1;
return {rows: rows, cols: cols};
}
</script>
<script type='application/javascript'>
$(document).ready(function() {
var options = {
};
$('#ssh').show();
var term_client = openTerminal(options);
console.log(rowHeight);
window.onresize = function(){
var geom = resize();
console.log(geom);
term_client.term.resize(geom.cols, geom.rows);
term_client.client.send({'resize': {'roles': geom.rows, 'cols': geom.cols}});
$('#ssh').show();
}
});
</script>
</body> </body>
</html> </html>
...@@ -104,6 +104,10 @@ $('#roleForm').validator({ ...@@ -104,6 +104,10 @@ $('#roleForm').validator({
ok: "", ok: "",
msg: {required: "系统用户名称必填"} msg: {required: "系统用户名称必填"}
}, },
"role_password": {
rule: "length[0~64]",
tip: "系统密码"
},
"role_key": { "role_key": {
rule: "check_begin", rule: "check_begin",
ok: "", ok: "",
......
...@@ -105,12 +105,16 @@ $('#roleForm').validator({ ...@@ -105,12 +105,16 @@ $('#roleForm').validator({
tip: "输入系统用户名称", tip: "输入系统用户名称",
ok: "", ok: "",
msg: {required: "系统用户名称必填"} msg: {required: "系统用户名称必填"}
},
"role_password": {
rule: "length[0~64]",
tip: "系统密码"
}, },
"role_key": { "role_key": {
rule: "check_begin", rule: "check_begin",
ok: "", ok: "",
empty: true empty: true
}, }
}, },
valid: function(form) { valid: function(form) {
......
...@@ -74,16 +74,6 @@ ...@@ -74,16 +74,6 @@
</div> </div>
</div> </div>
</div> </div>
<div class="form-group">
<label for="j_group" class="col-sm-2 control-label">使用密码</label>
<div class="col-sm-1">
<div class="radio i-checks">
<label>
<input type="checkbox" value="1" id="use_password" name="use_password">
</label>
</div>
</div>
</div>
</div> </div>
<div class="hr-line-dashed"></div> <div class="hr-line-dashed"></div>
<div class="form-group"> <div class="form-group">
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
<div class="alert alert-warning text-center">{{ error }}</div> <div class="alert alert-warning text-center">{{ error }}</div>
{% endif %} {% endif %}
{% if msg %} {% if msg %}
<div class="alert alert-success text-center">{{ msg }}</div> <div class="alert alert-success">{{ msg | safe }}</div>
{% endif %} {% endif %}
<div class="form-group"> <div class="form-group">
<label for="username" class="col-sm-2 control-label">用户名<span class="red-fonts">*</span></label> <label for="username" class="col-sm-2 control-label">用户名<span class="red-fonts">*</span></label>
...@@ -99,14 +99,9 @@ ...@@ -99,14 +99,9 @@
<label><input type="checkbox" value="0" name="extra" >禁用 </label> <label><input type="checkbox" value="0" name="extra" >禁用 </label>
</div> </div>
</div> </div>
{# <div class="col-sm-2">#}
{# <div class="checkbox i-checks">#}
{# <label><input type="checkbox" value="1" name="extra">ssh key登录 </label>#}
{# </div>#}
{# </div>#}
<div class="col-sm-2"> <div class="col-sm-2">
<div class="checkbox i-checks"> <div class="checkbox i-checks">
<label><input type="checkbox" value="2" name="extra">发送邮件 </label> <label><input type="checkbox" value="1" name="extra" checked>发送邮件 </label>
</div> </div>
</div> </div>
</div> </div>
......
...@@ -116,7 +116,7 @@ ...@@ -116,7 +116,7 @@
</div> </div>
<div class="col-sm-2"> <div class="col-sm-2">
<div class="checkbox i-checks"> <div class="checkbox i-checks">
<label><input type="checkbox" value="2" name="extra">发送邮件 </label> <label><input type="checkbox" value="1" name="extra">发送邮件 </label>
</div> </div>
</div> </div>
</div> </div>
......
...@@ -70,7 +70,7 @@ ...@@ -70,7 +70,7 @@
{% if user.username|key_exist %} {% if user.username|key_exist %}
<a href="{% url 'key_down' %}?uuid={{ user.uuid }}" >下载</a> <a href="{% url 'key_down' %}?uuid={{ user.uuid }}" >下载</a>
{% else %} {% else %}
<span style="color: #586b7d">NoKey</span> <a href="#" onclick="genSSH('{{ user.username }}','{% url 'key_gen' %}?uuid={{ user.uuid }}')">NoKey GenOne?</a>
{% endif %} {% endif %}
</td> </td>
<td class="text-center"> <td class="text-center">
...@@ -150,5 +150,13 @@ ...@@ -150,5 +150,13 @@
}); });
$('.shiftCheckbox').shiftcheckbox(); $('.shiftCheckbox').shiftcheckbox();
}); });
function genSSH(username, url) {
if (confirm('Are you sure to gen a sshkey for user ' + username)) {
$.get(url, function (data) {
alert(data);
location.reload()
})
}
}
</script> </script>
{% endblock %} {% endblock %}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment