Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
J
jumpserver
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ops
jumpserver
Commits
6db76423
Commit
6db76423
authored
Nov 09, 2015
by
liuzheng712
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'dev' of
https://git.coding.net/jumpserver/jumpserver
into NormalUserPageLZ
parents
cab34668
91b5d039
Show whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
340 additions
and
212 deletions
+340
-212
connect.py
connect.py
+141
-102
views.py
jlog/views.py
+7
-2
jumpserver.conf
jumpserver.conf
+2
-2
models.py
jumpserver/models.py
+1
-0
settings.py
jumpserver/settings.py
+3
-3
views.py
jumpserver/views.py
+17
-5
user_api.py
juser/user_api.py
+1
-1
views.py
juser/views.py
+2
-1
run_websocket.py
run_websocket.py
+101
-31
log_online.html
templates/jlog/log_online.html
+27
-19
paginator.html
templates/paginator.html
+27
-43
setting.html
templates/setting.html
+11
-3
No files found.
connect.py
View file @
6db76423
...
@@ -201,7 +201,43 @@ def deal_command(str_r, ssh):
...
@@ -201,7 +201,43 @@ def deal_command(str_r, ssh):
else
:
else
:
return
''
return
''
def
remove_control_char
(
str_r
):
def
newline_code_in
(
strings
):
for
i
in
[
'
\r
'
,
'
\r\n
'
,
'
\n
'
]:
if
i
in
strings
:
#print "new line"
return
True
return
False
class
Tty
(
object
):
"""
A virtual tty class
一个虚拟终端类,实现连接ssh和记录日志,基类
"""
def
__init__
(
self
,
username
,
asset_name
):
self
.
username
=
username
self
.
asset_name
=
asset_name
self
.
ip
=
None
self
.
port
=
22
self
.
channel
=
None
self
.
user
=
None
self
.
asset
=
None
self
.
role
=
None
self
.
ssh
=
None
self
.
connect_info
=
None
self
.
login_type
=
'ssh'
@staticmethod
def
is_output
(
strings
):
newline_char
=
[
'
\n
'
,
'
\r
'
,
'
\r\n
'
]
for
char
in
newline_char
:
if
char
in
strings
:
return
True
return
False
@staticmethod
def
remove_control_char
(
str_r
):
"""
"""
处理日志特殊字符
处理日志特殊字符
"""
"""
...
@@ -221,26 +257,96 @@ def remove_control_char(str_r):
...
@@ -221,26 +257,96 @@ def remove_control_char(str_r):
return
line_filtered
return
line_filtered
def
get_log_file
(
self
):
"""
Logging user command and output.
记录用户的日志
"""
tty_log_dir
=
os
.
path
.
join
(
log_dir
,
'tty'
)
timestamp_start
=
int
(
time
.
time
())
date_start
=
time
.
strftime
(
'
%
Y
%
m
%
d'
,
time
.
localtime
(
timestamp_start
))
time_start
=
time
.
strftime
(
'
%
H
%
M
%
S'
,
time
.
localtime
(
timestamp_start
))
today_connect_log_dir
=
os
.
path
.
join
(
tty_log_dir
,
date_start
)
log_file_path
=
os
.
path
.
join
(
today_connect_log_dir
,
'
%
s_
%
s_
%
s'
%
(
self
.
username
,
self
.
asset_name
,
time_start
))
def
newline_code_in
(
strings
):
try
:
for
i
in
[
'
\r
'
,
'
\r\n
'
,
'
\n
'
]:
is_dir
(
today_connect_log_dir
,
mode
=
0777
)
if
i
in
strings
:
except
OSError
:
#print "new line"
raise
ServerError
(
'Create
%
s failed, Please modify
%
s permission.'
%
(
today_connect_log_dir
,
tty_log_dir
))
return
True
return
False
try
:
log_file_f
=
open
(
log_file_path
+
'.log'
,
'a'
)
log_time_f
=
open
(
log_file_path
+
'.time'
,
'a'
)
except
IOError
:
raise
ServerError
(
'Create logfile failed, Please modify
%
s permission.'
%
today_connect_log_dir
)
if
self
.
login_type
==
'ssh'
:
pid
=
os
.
getpid
()
remote_ip
=
os
.
popen
(
"who -m | awk '{ print $5 }'"
)
.
read
()
.
strip
(
'()
\n
'
)
log
=
Log
(
user
=
self
.
username
,
host
=
self
.
asset_name
,
remote_ip
=
remote_ip
,
log_path
=
log_file_path
,
start_time
=
datetime
.
datetime
.
now
(),
pid
=
pid
)
else
:
remote_ip
=
'Web'
log
=
Log
(
user
=
self
.
username
,
host
=
self
.
asset_name
,
remote_ip
=
remote_ip
,
log_path
=
log_file_path
,
start_time
=
datetime
.
datetime
.
now
(),
pid
=
0
)
log
.
save
()
log
.
pid
=
log
.
id
log
.
save
()
log_file_f
.
write
(
'Start at
%
s
\n
'
%
datetime
.
datetime
.
now
())
log
.
save
()
return
log_file_f
,
log_time_f
,
log
def
get_connect_info
(
self
):
"""
获取需要登陆的主机的信息和映射用户的账号密码
"""
# 1. get ip, port
# 2. get 映射用户
# 3. get 映射用户的账号,密码或者key
# self.connect_info = {'user': '', 'asset': '', 'ip': '', 'port': 0, 'role_name': '', 'role_pass': '', 'role_key': ''}
self
.
connect_info
=
{
'user'
:
'a'
,
'asset'
:
'b'
,
'ip'
:
'127.0.0.1'
,
'port'
:
22
,
'role_name'
:
'root'
,
'role_pass'
:
''
,
'role_key'
:
'/root/.ssh/id_rsa.bak'
}
return
self
.
connect_info
def
get_connection
(
self
):
"""
获取连接成功后的ssh
"""
connect_info
=
self
.
get_connect_info
()
# 发起ssh连接请求 Make a ssh connection
ssh
=
paramiko
.
SSHClient
()
ssh
.
load_system_host_keys
()
ssh
.
set_missing_host_key_policy
(
paramiko
.
AutoAddPolicy
())
try
:
if
connect_info
.
get
(
'role_pass'
):
ssh
.
connect
(
connect_info
.
get
(
'ip'
),
port
=
connect_info
.
get
(
'port'
),
username
=
connect_info
.
get
(
'role_name'
),
password
=
connect_info
.
get
(
'role_pass'
),
look_for_keys
=
False
)
else
:
ssh
.
connect
(
connect_info
.
get
(
'ip'
),
port
=
connect_info
.
get
(
'port'
),
username
=
connect_info
.
get
(
'role_name'
),
key_filename
=
connect_info
.
get
(
'role_key'
),
look_for_keys
=
False
)
except
paramiko
.
ssh_exception
.
AuthenticationException
,
paramiko
.
ssh_exception
.
SSHException
:
raise
ServerError
(
'认证失败 Authentication Error.'
)
except
socket
.
error
:
raise
ServerError
(
'端口可能不对 Connect SSH Socket Port Error, Please Correct it.'
)
else
:
self
.
ssh
=
ssh
return
ssh
class
Jtty
(
object
):
class
SshTty
(
Tty
):
"""
"""
A virtual tty class
A virtual tty class
一个虚拟终端类,实现连接ssh和记录日志
一个虚拟终端类,实现连接ssh和记录日志
"""
"""
def
__init__
(
self
,
username
,
ip
):
self
.
chan
=
None
self
.
username
=
username
self
.
ip
=
ip
# self.user = user
# self.asset = asset
@staticmethod
@staticmethod
def
get_win_size
():
def
get_win_size
():
...
@@ -263,49 +369,16 @@ class Jtty(object):
...
@@ -263,49 +369,16 @@ class Jtty(object):
"""
"""
try
:
try
:
win_size
=
self
.
get_win_size
()
win_size
=
self
.
get_win_size
()
self
.
chan
.
resize_pty
(
height
=
win_size
[
0
],
width
=
win_size
[
1
])
self
.
chan
nel
.
resize_pty
(
height
=
win_size
[
0
],
width
=
win_size
[
1
])
except
Exception
:
except
Exception
:
pass
pass
def
log_record
(
self
):
def
posix_shell
(
self
):
"""
Logging user command and output.
记录用户的日志
"""
tty_log_dir
=
os
.
path
.
join
(
log_dir
,
'tty'
)
timestamp_start
=
int
(
time
.
time
())
date_start
=
time
.
strftime
(
'
%
Y
%
m
%
d'
,
time
.
localtime
(
timestamp_start
))
time_start
=
time
.
strftime
(
'
%
H
%
M
%
S'
,
time
.
localtime
(
timestamp_start
))
today_connect_log_dir
=
os
.
path
.
join
(
tty_log_dir
,
date_start
)
log_file_path
=
os
.
path
.
join
(
today_connect_log_dir
,
'
%
s_
%
s_
%
s'
%
(
self
.
username
,
self
.
ip
,
time_start
))
pid
=
os
.
getpid
()
pts
=
os
.
popen
(
"ps axu | grep
%
s | grep -v grep | awk '{ print $7 }'"
%
pid
)
.
read
()
.
strip
()
ip_list
=
os
.
popen
(
"who | grep
%
s | awk '{ print $5 }'"
%
pts
)
.
read
()
.
strip
(
'()
\n
'
)
try
:
is_dir
(
today_connect_log_dir
)
except
OSError
:
raise
ServerError
(
'Create
%
s failed, Please modify
%
s permission.'
%
(
today_connect_log_dir
,
tty_log_dir
))
try
:
# log_file_f = open('/opt/jumpserver/logs/tty/20151102/a_b_191034.log', 'a')
log_file_f
=
open
(
log_file_path
+
'.log'
,
'a'
)
log_time_f
=
open
(
log_file_path
+
'.time'
,
'a'
)
except
IOError
:
raise
ServerError
(
'Create logfile failed, Please modify
%
s permission.'
%
today_connect_log_dir
)
log
=
Log
(
user
=
self
.
username
,
host
=
self
.
ip
,
remote_ip
=
ip_list
,
log_path
=
log_file_path
,
start_time
=
datetime
.
datetime
.
now
(),
pid
=
pid
)
log_file_f
.
write
(
'Start time is
%
s
\n
'
%
datetime
.
datetime
.
now
())
log
.
save
()
return
log_file_f
,
log_time_f
,
ip_list
,
log
def
posix_shell
(
self
,
ssh
):
"""
"""
Use paramiko channel connect server interactive.
Use paramiko channel connect server interactive.
使用paramiko模块的channel,连接后端,进入交互式
使用paramiko模块的channel,连接后端,进入交互式
"""
"""
log_file_f
,
log_time_f
,
ip_list
,
log
=
self
.
log_record
()
log_file_f
,
log_time_f
,
log
=
self
.
get_log_file
()
old_tty
=
termios
.
tcgetattr
(
sys
.
stdin
)
old_tty
=
termios
.
tcgetattr
(
sys
.
stdin
)
pre_timestamp
=
time
.
time
()
pre_timestamp
=
time
.
time
()
input_r
=
''
input_r
=
''
...
@@ -314,29 +387,29 @@ class Jtty(object):
...
@@ -314,29 +387,29 @@ class Jtty(object):
try
:
try
:
tty
.
setraw
(
sys
.
stdin
.
fileno
())
tty
.
setraw
(
sys
.
stdin
.
fileno
())
tty
.
setcbreak
(
sys
.
stdin
.
fileno
())
tty
.
setcbreak
(
sys
.
stdin
.
fileno
())
self
.
chan
.
settimeout
(
0.0
)
self
.
chan
nel
.
settimeout
(
0.0
)
while
True
:
while
True
:
try
:
try
:
r
,
w
,
e
=
select
.
select
([
self
.
chan
,
sys
.
stdin
],
[],
[])
r
,
w
,
e
=
select
.
select
([
self
.
chan
nel
,
sys
.
stdin
],
[],
[])
except
Exception
:
except
Exception
:
pass
pass
if
self
.
chan
in
r
:
if
self
.
chan
nel
in
r
:
try
:
try
:
x
=
self
.
chan
.
recv
(
1024
)
x
=
self
.
chan
nel
.
recv
(
1024
)
if
len
(
x
)
==
0
:
if
len
(
x
)
==
0
:
break
break
sys
.
stdout
.
write
(
x
)
sys
.
stdout
.
write
(
x
)
sys
.
stdout
.
flush
()
sys
.
stdout
.
flush
()
log_file_f
.
write
(
x
)
now_timestamp
=
time
.
time
()
now_timestamp
=
time
.
time
()
log_time_f
.
write
(
'
%
s
%
s
\n
'
%
(
round
(
now_timestamp
-
pre_timestamp
,
4
),
len
(
x
)))
log_time_f
.
write
(
'
%
s
%
s
\n
'
%
(
round
(
now_timestamp
-
pre_timestamp
,
4
),
len
(
x
)))
log_file_f
.
write
(
x
)
pre_timestamp
=
now_timestamp
pre_timestamp
=
now_timestamp
log_file_f
.
flush
()
log_file_f
.
flush
()
log_time_f
.
flush
()
log_time_f
.
flush
()
if
input_mode
and
not
newline_code_in
(
x
):
if
input_mode
and
not
self
.
is_output
(
x
):
input_r
+=
x
input_r
+=
x
except
socket
.
timeout
:
except
socket
.
timeout
:
...
@@ -348,14 +421,16 @@ class Jtty(object):
...
@@ -348,14 +421,16 @@ class Jtty(object):
input_mode
=
True
input_mode
=
True
if
str
(
x
)
in
[
'
\r
'
,
'
\n
'
,
'
\r\n
'
]:
if
str
(
x
)
in
[
'
\r
'
,
'
\n
'
,
'
\r\n
'
]:
input_r
=
deal_command
(
input_r
,
ssh
)
# input_r = deal_command(input_r,ssh)
input_r
=
self
.
remove_control_char
(
input_r
)
TtyLog
(
log
=
log
,
datetime
=
datetime
.
datetime
.
now
(),
cmd
=
input_r
)
.
save
()
TtyLog
(
log
=
log
,
datetime
=
datetime
.
datetime
.
now
(),
cmd
=
input_r
)
.
save
()
input_r
=
''
input_r
=
''
input_mode
=
False
input_mode
=
False
if
len
(
x
)
==
0
:
if
len
(
x
)
==
0
:
break
break
self
.
chan
.
send
(
x
)
self
.
chan
nel
.
send
(
x
)
finally
:
finally
:
termios
.
tcsetattr
(
sys
.
stdin
,
termios
.
TCSADRAIN
,
old_tty
)
termios
.
tcsetattr
(
sys
.
stdin
,
termios
.
TCSADRAIN
,
old_tty
)
...
@@ -365,42 +440,6 @@ class Jtty(object):
...
@@ -365,42 +440,6 @@ class Jtty(object):
log
.
end_time
=
datetime
.
datetime
.
now
()
log
.
end_time
=
datetime
.
datetime
.
now
()
log
.
save
()
log
.
save
()
def
get_connect_item
(
self
):
"""
get args for connect: ip, port, username, passwd
获取连接需要的参数,也就是服务ip, 端口, 用户账号和密码
"""
# if not self.asset.is_active:
# raise ServerError('该主机被禁用 Host %s is not active.' % self.ip)
#
# if not self.user.is_active:
# raise ServerError('该用户被禁用 User %s is not active.' % self.username)
# password = CRYPTOR.decrypt(self.])
# return self.username, password, self.ip, int(self.asset.port)
return
'root'
,
'redhat'
,
'127.0.0.1'
,
22
def
get_connection
(
self
):
"""
Get the ssh connection for reuse
获取连接套接字
"""
username
,
password
,
ip
,
port
=
self
.
get_connect_item
()
logger
.
debug
(
"username:
%
s, password:
%
s, ip:
%
s, port:
%
s"
%
(
username
,
password
,
ip
,
port
))
# 发起ssh连接请求 Make a ssh connection
ssh
=
paramiko
.
SSHClient
()
ssh
.
load_system_host_keys
()
ssh
.
set_missing_host_key_policy
(
paramiko
.
AutoAddPolicy
())
try
:
ssh
.
connect
(
ip
,
port
=
port
,
username
=
username
,
password
=
password
)
except
paramiko
.
ssh_exception
.
AuthenticationException
,
paramiko
.
ssh_exception
.
SSHException
:
raise
ServerError
(
'认证错误 Authentication Error.'
)
except
socket
.
error
:
raise
ServerError
(
'端口可能不对 Connect SSH Socket Port Error, Please Correct it.'
)
else
:
return
ssh
def
connect
(
self
):
def
connect
(
self
):
"""
"""
Connect server.
Connect server.
...
@@ -415,7 +454,7 @@ class Jtty(object):
...
@@ -415,7 +454,7 @@ class Jtty(object):
# 获取连接的隧道并设置窗口大小 Make a channel and set windows size
# 获取连接的隧道并设置窗口大小 Make a channel and set windows size
global
channel
global
channel
win_size
=
self
.
get_win_size
()
win_size
=
self
.
get_win_size
()
self
.
chan
=
channel
=
ssh
.
invoke_shell
(
height
=
win_size
[
0
],
width
=
win_size
[
1
]
)
self
.
chan
nel
=
channel
=
ssh
.
invoke_shell
(
height
=
win_size
[
0
],
width
=
win_size
[
1
],
term
=
'xterm'
)
try
:
try
:
signal
.
signal
(
signal
.
SIGWINCH
,
self
.
set_win_size
)
signal
.
signal
(
signal
.
SIGWINCH
,
self
.
set_win_size
)
except
:
except
:
...
@@ -424,17 +463,17 @@ class Jtty(object):
...
@@ -424,17 +463,17 @@ class Jtty(object):
# 设置PS1并提示 Set PS1 and msg it
# 设置PS1并提示 Set PS1 and msg it
#channel.send(ps1)
#channel.send(ps1)
#channel.send(login_msg)
#channel.send(login_msg)
channel
.
send
(
'echo ${SSH_TTY}
\n
'
)
#
channel.send('echo ${SSH_TTY}\n')
global
SSH_TTY
#
global SSH_TTY
while
not
channel
.
recv_ready
():
#
while not channel.recv_ready():
time
.
sleep
(
1
)
#
time.sleep(1)
tmp
=
channel
.
recv
(
1024
)
#
tmp = channel.recv(1024)
#print 'ok'+tmp+'ok'
#print 'ok'+tmp+'ok'
# SSH_TTY = re.search(r'(?<=/dev/).*', tmp).group().strip()
# SSH_TTY = re.search(r'(?<=/dev/).*', tmp).group().strip()
SSH_TTY
=
''
#
SSH_TTY = ''
channel
.
send
(
'clear
\n
'
)
channel
.
send
(
'clear
\n
'
)
# Make ssh interactive tunnel
# Make ssh interactive tunnel
self
.
posix_shell
(
ssh
)
self
.
posix_shell
()
# Shutdown channel socket
# Shutdown channel socket
channel
.
close
()
channel
.
close
()
...
...
jlog/views.py
View file @
6db76423
...
@@ -48,7 +48,8 @@ def log_list(request, offset):
...
@@ -48,7 +48,8 @@ def log_list(request, offset):
contact_list
,
p
,
contacts
,
page_range
,
current_page
,
show_first
,
show_end
=
pages
(
posts
,
request
)
contact_list
,
p
,
contacts
,
page_range
,
current_page
,
show_first
,
show_end
=
pages
(
posts
,
request
)
web_monitor_uri
=
'
%
s/monitor'
%
web_socket_host
web_monitor_uri
=
'ws://
%
s/monitor'
%
web_socket_host
web_kill_uri
=
'http://
%
s/kill'
%
web_socket_host
return
render_to_response
(
'jlog/log_
%
s.html'
%
offset
,
locals
(),
context_instance
=
RequestContext
(
request
))
return
render_to_response
(
'jlog/log_
%
s.html'
%
offset
,
locals
(),
context_instance
=
RequestContext
(
request
))
...
@@ -103,6 +104,10 @@ def log_record(request):
...
@@ -103,6 +104,10 @@ def log_record(request):
def
web_terminal
(
request
):
def
web_terminal
(
request
):
web_terminal_uri
=
'
%
s/terminal'
%
web_socket_host
#username = get_session.get('username', '')
token
=
request
.
COOKIES
.
get
(
'sessionid'
)
username
=
request
.
user
.
username
asset_name
=
'127.0.0.1'
web_terminal_uri
=
'ws://
%
s/terminal?username=
%
s&asset_name=
%
s&token=
%
s'
%
(
web_socket_host
,
username
,
asset_name
,
token
)
return
render_to_response
(
'jlog/web_terminal.html'
,
locals
())
return
render_to_response
(
'jlog/web_terminal.html'
,
locals
())
jumpserver.conf
View file @
6db76423
...
@@ -23,7 +23,7 @@ root_pw = secret234
...
@@ -23,7 +23,7 @@ root_pw = secret234
[
websocket
]
[
websocket
]
web_socket_host
=
ws
://
192
.
168
.
244
.
129
:
3000
web_socket_host
=
192
.
168
.
244
.
129
:
3000
[
mail
]
[
mail
]
...
@@ -32,4 +32,4 @@ email_host = smtp.exmail.qq.com
...
@@ -32,4 +32,4 @@ email_host = smtp.exmail.qq.com
email_port
=
25
email_port
=
25
email_host_user
=
noreply
@
jumpserver
.
org
email_host_user
=
noreply
@
jumpserver
.
org
email_host_password
=
jumpserver1234
email_host_password
=
jumpserver1234
email_use_tls
=
Fals
e
email_use_tls
=
Tru
e
jumpserver/models.py
View file @
6db76423
...
@@ -7,6 +7,7 @@ class Setting(models.Model):
...
@@ -7,6 +7,7 @@ class Setting(models.Model):
name
=
models
.
CharField
(
max_length
=
100
)
name
=
models
.
CharField
(
max_length
=
100
)
default_user
=
models
.
CharField
(
max_length
=
100
,
null
=
True
,
blank
=
True
)
default_user
=
models
.
CharField
(
max_length
=
100
,
null
=
True
,
blank
=
True
)
default_port
=
models
.
IntegerField
(
max_length
=
10
,
null
=
True
,
blank
=
True
)
default_port
=
models
.
IntegerField
(
max_length
=
10
,
null
=
True
,
blank
=
True
)
default_password
=
models
.
CharField
(
max_length
=
100
,
null
=
True
,
blank
=
True
)
default_pri_key_path
=
models
.
CharField
(
max_length
=
100
,
null
=
True
,
blank
=
True
)
default_pri_key_path
=
models
.
CharField
(
max_length
=
100
,
null
=
True
,
blank
=
True
)
class
Meta
:
class
Meta
:
...
...
jumpserver/settings.py
View file @
6db76423
...
@@ -15,7 +15,7 @@ import getpass
...
@@ -15,7 +15,7 @@ import getpass
config
=
ConfigParser
.
ConfigParser
()
config
=
ConfigParser
.
ConfigParser
()
BASE_DIR
=
os
.
path
.
dirname
(
os
.
path
.
dirname
(
__file__
))
BASE_DIR
=
os
.
path
.
abspath
(
os
.
path
.
dirname
(
os
.
path
.
dirname
(
__file__
)
))
config
.
read
(
os
.
path
.
join
(
BASE_DIR
,
'jumpserver.conf'
))
config
.
read
(
os
.
path
.
join
(
BASE_DIR
,
'jumpserver.conf'
))
DB_HOST
=
config
.
get
(
'db'
,
'host'
)
DB_HOST
=
config
.
get
(
'db'
,
'host'
)
...
@@ -25,11 +25,13 @@ DB_PASSWORD = config.get('db', 'password')
...
@@ -25,11 +25,13 @@ DB_PASSWORD = config.get('db', 'password')
DB_DATABASE
=
config
.
get
(
'db'
,
'database'
)
DB_DATABASE
=
config
.
get
(
'db'
,
'database'
)
AUTH_USER_MODEL
=
'juser.User'
AUTH_USER_MODEL
=
'juser.User'
# mail config
# mail config
MAIL_ENABLE
=
config
.
get
(
'mail'
,
'mail_enable'
)
EMAIL_HOST
=
config
.
get
(
'mail'
,
'email_host'
)
EMAIL_HOST
=
config
.
get
(
'mail'
,
'email_host'
)
EMAIL_PORT
=
config
.
get
(
'mail'
,
'email_port'
)
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'
)
EMAIL_TIMEOUT
=
5
# ======== Log ==========
# ======== Log ==========
LOG
=
False
LOG
=
False
...
@@ -41,8 +43,6 @@ KEY = config.get('base', 'key')
...
@@ -41,8 +43,6 @@ KEY = config.get('base', 'key')
LOGIN_NAME
=
getpass
.
getuser
()
LOGIN_NAME
=
getpass
.
getuser
()
# LDAP_ENABLE = CONF.getint('ldap', 'ldap_enable')
# LDAP_ENABLE = CONF.getint('ldap', 'ldap_enable')
URL
=
config
.
get
(
'base'
,
'url'
)
URL
=
config
.
get
(
'base'
,
'url'
)
MAIL_ENABLE
=
config
.
get
(
'mail'
,
'mail_enable'
)
MAIL_FROM
=
config
.
get
(
'mail'
,
'email_host_user'
)
log_dir
=
os
.
path
.
join
(
BASE_DIR
,
'logs'
)
log_dir
=
os
.
path
.
join
(
BASE_DIR
,
'logs'
)
log_level
=
config
.
get
(
'base'
,
'log'
)
log_level
=
config
.
get
(
'base'
,
'log'
)
web_socket_host
=
config
.
get
(
'websocket'
,
'web_socket_host'
)
web_socket_host
=
config
.
get
(
'websocket'
,
'web_socket_host'
)
...
...
jumpserver/views.py
View file @
6db76423
...
@@ -246,26 +246,38 @@ def Logout(request):
...
@@ -246,26 +246,38 @@ def Logout(request):
def
setting
(
request
):
def
setting
(
request
):
header_title
,
path1
=
'项目设置'
,
'设置'
header_title
,
path1
=
'项目设置'
,
'设置'
setting_
r
=
get_object
(
Setting
,
name
=
'default'
)
setting_
default
=
get_object
(
Setting
,
name
=
'default'
)
if
request
.
method
==
"POST"
:
if
request
.
method
==
"POST"
:
setting_raw
=
request
.
POST
.
get
(
'setting'
,
''
)
if
setting_raw
==
'default'
:
username
=
request
.
POST
.
get
(
'username'
,
''
)
username
=
request
.
POST
.
get
(
'username'
,
''
)
port
=
request
.
POST
.
get
(
'port'
,
''
)
port
=
request
.
POST
.
get
(
'port'
,
''
)
password
=
request
.
POST
.
get
(
'password'
,
''
)
private_key
=
request
.
POST
.
get
(
'key'
,
''
)
private_key
=
request
.
POST
.
get
(
'key'
,
''
)
if
''
in
[
username
,
port
,
private_key
]
:
if
''
in
[
username
,
port
]
and
(
''
in
password
or
''
in
private_key
)
:
return
HttpResponse
(
'所填内容不能为空
'
)
return
HttpResponse
(
'所填内容不能为空, 且密码和私钥填一个
'
)
else
:
else
:
settings
=
get_object
(
Setting
,
id
=
1
)
private_key_path
=
os
.
path
.
join
(
BASE_DIR
,
'keys'
,
'default'
,
'default_private_key.pem'
)
private_key_path
=
os
.
path
.
join
(
BASE_DIR
,
'keys'
,
'default'
,
'default_private_key.pem'
)
if
private_key
:
with
open
(
private_key_path
,
'w'
)
as
f
:
with
open
(
private_key_path
,
'w'
)
as
f
:
f
.
write
(
private_key
)
f
.
write
(
private_key
)
os
.
chmod
(
private_key_path
,
0600
)
os
.
chmod
(
private_key_path
,
0600
)
if
settings
:
if
setting_default
:
if
password
!=
setting_default
.
default_password
:
password_encode
=
CRYPTOR
.
encrypt
(
password
)
else
:
password_encode
=
password
Setting
.
objects
.
filter
(
name
=
'default'
)
.
update
(
default_user
=
username
,
default_port
=
port
,
Setting
.
objects
.
filter
(
name
=
'default'
)
.
update
(
default_user
=
username
,
default_port
=
port
,
default_password
=
password_encode
,
default_pri_key_path
=
private_key_path
)
default_pri_key_path
=
private_key_path
)
else
:
else
:
password_encode
=
CRYPTOR
.
encrypt
(
password
)
setting_r
=
Setting
(
name
=
'default'
,
default_user
=
username
,
default_port
=
port
,
setting_r
=
Setting
(
name
=
'default'
,
default_user
=
username
,
default_port
=
port
,
default_password
=
password_encode
,
default_pri_key_path
=
private_key_path
)
.
save
()
default_pri_key_path
=
private_key_path
)
.
save
()
msg
=
"设置成功"
msg
=
"设置成功"
...
...
juser/user_api.py
View file @
6db76423
...
@@ -5,7 +5,7 @@ from subprocess import call
...
@@ -5,7 +5,7 @@ from subprocess import call
from
juser.models
import
AdminGroup
from
juser.models
import
AdminGroup
from
jumpserver.api
import
*
from
jumpserver.api
import
*
from
jumpserver.settings
import
BASE_DIR
from
jumpserver.settings
import
BASE_DIR
,
EMAIL_HOST_USER
as
MAIL_FROM
def
group_add_user
(
group
,
user_id
=
None
,
username
=
None
):
def
group_add_user
(
group
,
user_id
=
None
,
username
=
None
):
...
...
juser/views.py
View file @
6db76423
...
@@ -10,10 +10,11 @@ from django.contrib.auth.decorators import login_required
...
@@ -10,10 +10,11 @@ from django.contrib.auth.decorators import login_required
from
django.db.models
import
Q
from
django.db.models
import
Q
from
django.template
import
RequestContext
from
django.template
import
RequestContext
from
django.db.models
import
ObjectDoesNotExist
from
django.db.models
import
ObjectDoesNotExist
from
jumpserver.settings
import
MAIL_FROM
,
MAIL_ENABLE
from
jumpserver.settings
import
EMAIL_HOST_USER
from
juser.user_api
import
*
from
juser.user_api
import
*
from
jperm.perm_api
import
_public_perm_api
,
perm_user_api
,
user_permed
from
jperm.perm_api
import
_public_perm_api
,
perm_user_api
,
user_permed
MAIL_FROM
=
EMAIL_HOST_USER
def
chg_role
(
request
):
def
chg_role
(
request
):
role
=
{
'SU'
:
2
,
'GA'
:
1
,
'CU'
:
0
}
role
=
{
'SU'
:
2
,
'GA'
:
1
,
'CU'
:
0
}
...
...
run_websocket.py
View file @
6db76423
# coding: utf-8
# coding: utf-8
import
time
import
time
import
datetime
import
json
import
json
import
os
import
os
import
sys
import
sys
import
os.path
import
os.path
import
threading
import
threading
import
urllib
import
tornado.ioloop
import
tornado.ioloop
import
tornado.options
import
tornado.options
...
@@ -13,6 +15,7 @@ import tornado.web
...
@@ -13,6 +15,7 @@ import tornado.web
import
tornado.websocket
import
tornado.websocket
import
tornado.httpserver
import
tornado.httpserver
import
tornado.gen
import
tornado.gen
import
tornado.httpclient
from
tornado.websocket
import
WebSocketClosedError
from
tornado.websocket
import
WebSocketClosedError
from
tornado.options
import
define
,
options
from
tornado.options
import
define
,
options
...
@@ -21,9 +24,12 @@ from pyinotify import WatchManager, Notifier, ProcessEvent, IN_DELETE, IN_CREATE
...
@@ -21,9 +24,12 @@ from pyinotify import WatchManager, Notifier, ProcessEvent, IN_DELETE, IN_CREATE
# from gevent import monkey
# from gevent import monkey
# monkey.patch_all()
# monkey.patch_all()
# import gevent
# import gevent
from
gevent.socket
import
wait_read
,
wait_write
# from gevent.socket import wait_read, wait_write
import
struct
,
fcntl
,
signal
,
socket
,
select
,
fnmatch
import
paramiko
import
paramiko
from
connect
import
Tty
from
connect
import
TtyLog
,
Log
try
:
try
:
import
simplejson
as
json
import
simplejson
as
json
...
@@ -35,6 +41,20 @@ define("port", default=3000, help="run on the given port", type=int)
...
@@ -35,6 +41,20 @@ define("port", default=3000, help="run on the given port", type=int)
define
(
"host"
,
default
=
'0.0.0.0'
,
help
=
"run port on"
,
type
=
str
)
define
(
"host"
,
default
=
'0.0.0.0'
,
help
=
"run port on"
,
type
=
str
)
def
require_auth
(
func
):
def
_deco
(
request
,
*
args
,
**
kwargs
):
username
=
request
.
get_argument
(
'username'
,
''
)
asset_name
=
request
.
get_argument
(
'asset_name'
,
''
)
token
=
request
.
get_argument
(
'token'
,
''
)
print
username
,
asset_name
,
token
client
=
tornado
.
httpclient
.
HTTPClient
()
# response = client.fetch('http://some/url') + urllib.urlencode({'username': username,
# 'asset_name': asset_name, 'token': token})
# return request.close()
return
func
(
request
,
*
args
,
**
kwargs
)
return
_deco
class
MyThread
(
threading
.
Thread
):
class
MyThread
(
threading
.
Thread
):
def
__init__
(
self
,
*
args
,
**
kwargs
):
def
__init__
(
self
,
*
args
,
**
kwargs
):
super
(
MyThread
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
super
(
MyThread
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
...
@@ -92,6 +112,7 @@ class Application(tornado.web.Application):
...
@@ -92,6 +112,7 @@ class Application(tornado.web.Application):
handlers
=
[
handlers
=
[
(
r'/monitor'
,
MonitorHandler
),
(
r'/monitor'
,
MonitorHandler
),
(
r'/terminal'
,
WebTerminalHandler
),
(
r'/terminal'
,
WebTerminalHandler
),
(
r'/kill'
,
WebTerminalKillHandler
),
]
]
setting
=
{
setting
=
{
...
@@ -115,6 +136,7 @@ class MonitorHandler(tornado.websocket.WebSocketHandler):
...
@@ -115,6 +136,7 @@ class MonitorHandler(tornado.websocket.WebSocketHandler):
def
check_origin
(
self
,
origin
):
def
check_origin
(
self
,
origin
):
return
True
return
True
@require_auth
def
open
(
self
):
def
open
(
self
):
# 获取监控的path
# 获取监控的path
self
.
file_path
=
self
.
get_argument
(
'file_path'
,
''
)
self
.
file_path
=
self
.
get_argument
(
'file_path'
,
''
)
...
@@ -123,12 +145,6 @@ class MonitorHandler(tornado.websocket.WebSocketHandler):
...
@@ -123,12 +145,6 @@ class MonitorHandler(tornado.websocket.WebSocketHandler):
MonitorHandler
.
threads
.
append
(
thread
)
MonitorHandler
.
threads
.
append
(
thread
)
self
.
stream
.
set_nodelay
(
True
)
self
.
stream
.
set_nodelay
(
True
)
print
len
(
MonitorHandler
.
threads
),
len
(
MonitorHandler
.
clients
)
def
on_message
(
self
,
message
):
self
.
write_message
(
'Connect WebSocket Success. <br/>'
)
# 监控日志,发生变动发向客户端
try
:
try
:
for
t
in
MonitorHandler
.
threads
:
for
t
in
MonitorHandler
.
threads
:
if
t
.
is_alive
():
if
t
.
is_alive
():
...
@@ -142,6 +158,12 @@ class MonitorHandler(tornado.websocket.WebSocketHandler):
...
@@ -142,6 +158,12 @@ class MonitorHandler(tornado.websocket.WebSocketHandler):
MonitorHandler
.
clients
.
remove
(
self
)
MonitorHandler
.
clients
.
remove
(
self
)
MonitorHandler
.
threads
.
remove
(
MonitorHandler
.
threads
[
client_index
])
MonitorHandler
.
threads
.
remove
(
MonitorHandler
.
threads
[
client_index
])
print
len
(
MonitorHandler
.
threads
),
len
(
MonitorHandler
.
clients
)
def
on_message
(
self
,
message
):
# 监控日志,发生变动发向客户端
pass
def
on_close
(
self
):
def
on_close
(
self
):
# 客户端主动关闭
# 客户端主动关闭
# self.close()
# self.close()
...
@@ -152,28 +174,55 @@ class MonitorHandler(tornado.websocket.WebSocketHandler):
...
@@ -152,28 +174,55 @@ class MonitorHandler(tornado.websocket.WebSocketHandler):
MonitorHandler
.
threads
.
remove
(
MonitorHandler
.
threads
[
client_index
])
MonitorHandler
.
threads
.
remove
(
MonitorHandler
.
threads
[
client_index
])
class
WebTty
(
Tty
):
def
__init__
(
self
,
*
args
,
**
kwargs
):
super
(
WebTty
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
self
.
login_type
=
'web'
self
.
ws
=
None
self
.
input_r
=
''
self
.
input_mode
=
False
class
WebTerminalKillHandler
(
tornado
.
web
.
RequestHandler
):
def
get
(
self
):
ws_id
=
self
.
get_argument
(
'id'
)
Log
.
objects
.
filter
(
id
=
ws_id
)
.
update
(
is_finished
=
True
)
for
ws
in
WebTerminalHandler
.
clients
:
print
ws
.
id
if
ws
.
id
==
int
(
ws_id
):
print
"killed"
ws
.
log
.
save
()
ws
.
close
()
print
len
(
WebTerminalHandler
.
clients
)
class
WebTerminalHandler
(
tornado
.
websocket
.
WebSocketHandler
):
class
WebTerminalHandler
(
tornado
.
websocket
.
WebSocketHandler
):
tasks
=
[]
tasks
=
[]
clients
=
[]
def
__init__
(
self
,
*
args
,
**
kwargs
):
def
__init__
(
self
,
*
args
,
**
kwargs
):
self
.
chan
=
None
self
.
term
=
None
self
.
ssh
=
None
self
.
channel
=
None
self
.
log_file_f
=
None
self
.
log_time_f
=
None
self
.
log
=
None
self
.
id
=
0
super
(
WebTerminalHandler
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
super
(
WebTerminalHandler
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
def
check_origin
(
self
,
origin
):
def
check_origin
(
self
,
origin
):
return
True
return
True
@require_auth
def
open
(
self
):
def
open
(
self
):
self
.
ssh
=
paramiko
.
SSHClient
()
asset_name
=
self
.
get_argument
(
'asset_name'
,
''
)
self
.
ssh
.
set_missing_host_key_policy
(
paramiko
.
AutoAddPolicy
())
username
=
self
.
get_argument
(
'username'
,
''
)
try
:
token
=
self
.
get_argument
(
'token'
,
''
)
self
.
ssh
.
connect
(
'127.0.0.1'
,
22
,
'root'
,
'redhat'
)
print
asset_name
,
username
,
token
except
:
self
.
term
=
WebTty
(
'a'
,
'b'
)
self
.
write_message
(
json
.
loads
({
'data'
:
'Connect server Error'
}))
self
.
term
.
get_connection
()
self
.
close
()
self
.
channel
=
self
.
term
.
ssh
.
invoke_shell
(
term
=
'xterm'
)
WebTerminalHandler
.
tasks
.
append
(
MyThread
(
target
=
self
.
forward_outbound
))
self
.
chan
=
self
.
ssh
.
invoke_shell
(
term
=
'xterm'
)
WebTerminalHandler
.
clients
.
append
(
self
)
WebTerminalHandler
.
tasks
.
append
(
threading
.
Thread
(
target
=
self
.
_forward_outbound
))
for
t
in
WebTerminalHandler
.
tasks
:
for
t
in
WebTerminalHandler
.
tasks
:
if
t
.
is_alive
():
if
t
.
is_alive
():
...
@@ -185,35 +234,56 @@ class WebTerminalHandler(tornado.websocket.WebSocketHandler):
...
@@ -185,35 +234,56 @@ class WebTerminalHandler(tornado.websocket.WebSocketHandler):
data
=
json
.
loads
(
message
)
data
=
json
.
loads
(
message
)
if
not
data
:
if
not
data
:
return
return
if
'resize'
in
data
:
if
data
.
get
(
'data'
):
self
.
chan
.
resize_pty
(
self
.
term
.
input_mode
=
True
data
[
'resize'
]
.
get
(
'width'
,
80
),
if
str
(
data
[
'data'
])
in
[
'
\r
'
,
'
\n
'
,
'
\r\n
'
]:
data
[
'resize'
]
.
get
(
'height'
,
24
))
TtyLog
(
log
=
self
.
log
,
datetime
=
datetime
.
datetime
.
now
(),
cmd
=
self
.
term
.
remove_control_char
(
self
.
term
.
input_r
))
.
save
()
if
'data'
in
data
:
self
.
term
.
input_r
=
''
self
.
chan
.
send
(
data
[
'data'
])
self
.
term
.
input_mode
=
False
self
.
channel
.
send
(
data
[
'data'
])
def
on_close
(
self
):
def
on_close
(
self
):
self
.
write_message
(
json
.
dumps
({
'data'
:
'close websocket'
}))
print
'On_close'
if
self
in
WebTerminalHandler
.
clients
:
WebTerminalHandler
.
clients
.
remove
(
self
)
try
:
self
.
log_file_f
.
write
(
'End time is
%
s'
%
datetime
.
datetime
.
now
())
self
.
log
.
is_finished
=
True
self
.
log
.
end_time
=
datetime
.
datetime
.
now
()
self
.
log
.
save
()
self
.
close
()
except
AttributeError
:
pass
def
_forward_outbound
(
self
):
def
forward_outbound
(
self
):
""" Forward outbound traffic (ssh -> websockets) """
self
.
log_file_f
,
self
.
log_time_f
,
self
.
log
=
self
.
term
.
get_log_file
()
self
.
id
=
self
.
log
.
id
try
:
try
:
data
=
''
data
=
''
pre_timestamp
=
time
.
time
()
while
True
:
while
True
:
wait_read
(
self
.
chan
.
fileno
())
r
,
w
,
e
=
select
.
select
([
self
.
channel
,
sys
.
stdin
],
[],
[])
recv
=
self
.
chan
.
recv
(
1024
)
if
self
.
channel
in
r
:
recv
=
self
.
channel
.
recv
(
1024
)
if
not
len
(
recv
):
if
not
len
(
recv
):
return
return
data
+=
recv
data
+=
recv
try
:
try
:
self
.
write_message
(
json
.
dumps
({
'data'
:
data
}))
self
.
write_message
(
json
.
dumps
({
'data'
:
data
}))
now_timestamp
=
time
.
time
()
self
.
log_time_f
.
write
(
'
%
s
%
s
\n
'
%
(
round
(
now_timestamp
-
pre_timestamp
,
4
),
len
(
data
)))
self
.
log_file_f
.
write
(
data
)
pre_timestamp
=
now_timestamp
self
.
log_file_f
.
flush
()
self
.
log_time_f
.
flush
()
if
self
.
term
.
input_mode
and
not
self
.
term
.
is_output
(
data
):
self
.
term
.
input_r
+=
data
data
=
''
data
=
''
except
UnicodeDecodeError
:
except
UnicodeDecodeError
:
pass
pass
finally
:
finally
:
self
.
close
()
self
.
close
()
if
__name__
==
'__main__'
:
if
__name__
==
'__main__'
:
tornado
.
options
.
parse_command_line
()
tornado
.
options
.
parse_command_line
()
app
=
Application
()
app
=
Application
()
...
...
templates/jlog/log_online.html
View file @
6db76423
...
@@ -50,7 +50,7 @@
...
@@ -50,7 +50,7 @@
<div
class=
"col-lg-12"
>
<div
class=
"col-lg-12"
>
<div
class=
"ibox float-e-margins"
>
<div
class=
"ibox float-e-margins"
>
<div
id=
"ibox-content"
class=
"ibox-title"
>
<div
id=
"ibox-content"
class=
"ibox-title"
>
<h5>
用户日志详细信息列表
</h5>
<h5>
用户日志详细信息列表
<
input
type=
"button"
id=
"test_connect"
class=
"btn btn-primary"
value=
"测试连接 web terminal"
/>
<
/h5>
<div
class=
"ibox-tools"
>
<div
class=
"ibox-tools"
>
<a
class=
"collapse-link"
>
<a
class=
"collapse-link"
>
<i
class=
"fa fa-chevron-up"
></i>
<i
class=
"fa fa-chevron-up"
></i>
...
@@ -97,7 +97,7 @@
...
@@ -97,7 +97,7 @@
{% ifnotequal session_role_id 0 %}
{% ifnotequal session_role_id 0 %}
<td
class=
"text-center"
><a
href=
"/jlog/history/?id={{ post.id }}"
class=
"log_command"
>
命令统计
</a></td>
<td
class=
"text-center"
><a
href=
"/jlog/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"
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 }}")'
/></td>
<td
class=
"text-center"
><input
type=
"button"
id=
"cut"
class=
"btn btn-danger btn-xs"
name=
"cut"
value=
"阻断"
onclick=
'cut("{{ post.pid }}"
, "{{ post.remote_ip }}"
)'
/></td>
{% endifnotequal %}
{% endifnotequal %}
<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>
...
@@ -127,8 +127,20 @@
...
@@ -127,8 +127,20 @@
var
file_path
=
obj
.
attr
(
'file_path'
);
var
file_path
=
obj
.
attr
(
'file_path'
);
var
wsUri
=
'{{ web_monitor_uri }}'
;
var
wsUri
=
'{{ web_monitor_uri }}'
;
var
socket
=
new
WebSocket
(
wsUri
+
'?file_path='
+
file_path
);
var
socket
=
new
WebSocket
(
wsUri
+
'?file_path='
+
file_path
);
var
term
=
new
Terminal
({
cols
:
80
,
rows
:
24
,
screenKeys
:
false
});
var
tag
=
$
(
'<div id="term" style="height:500px; overflow: auto;background-color: rgba(0, 0, 0, 0);border: none"></div>'
);
term
.
open
();
term
.
resize
(
80
,
24
);
socket
.
onopen
=
function
(
evt
){
socket
.
onopen
=
function
(
evt
){
socket
.
send
(
file_path
)
socket
.
send
(
'hello'
);
term
.
write
(
'~.~ Connect WebSocket Success.~.~
\
r
\
n'
);
};
};
window
.
onbeforeunload
=
function
(){
window
.
onbeforeunload
=
function
(){
...
@@ -138,29 +150,15 @@
...
@@ -138,29 +150,15 @@
var
username
=
obj
.
closest
(
'tr'
).
find
(
'#username'
).
text
();
var
username
=
obj
.
closest
(
'tr'
).
find
(
'#username'
).
text
();
var
ip
=
obj
.
closest
(
'tr'
).
find
(
'#ip'
).
text
();
var
ip
=
obj
.
closest
(
'tr'
).
find
(
'#ip'
).
text
();
BootstrapDialog
.
show
({
message
:
function
(){
BootstrapDialog
.
show
({
message
:
function
(){
//服务器端认证
//服务器端认证
{
#
socket
.
send
(
'login'
,
{
userid
:
message
.
id
,
filename
:
message
.
filename
,
username
:
username
,
seed
:
seed
});
#
}
{
#
socket
.
send
(
'login'
,
{
userid
:
message
.
id
,
filename
:
message
.
filename
,
username
:
username
,
seed
:
seed
});
#
}
var
term
=
new
Terminal
({
cols
:
80
,
rows
:
24
,
screenKeys
:
false
});
var
tag
=
$
(
'<div id="term" style="height:500px; overflow: auto;background-color: rgba(0, 0, 0, 0);border: none"></div>'
);
term
.
open
();
term
.
resize
(
80
,
24
);
window
.
setTimeout
(
function
(){
window
.
setTimeout
(
function
(){
$
(
'.terminal'
).
detach
().
appendTo
(
'#term'
);
$
(
'.terminal'
).
detach
().
appendTo
(
'#term'
);
socket
.
onmessage
=
function
(
evt
){
socket
.
onmessage
=
function
(
evt
){
term
.
write
(
evt
.
data
);
term
.
write
(
evt
.
data
);
}},
1000
);
}},
1000
);
tag
[
0
].
style
.
color
=
"#00FF00"
;
return
tag
[
0
];
return
tag
[
0
];
}
,
}
,
title
:
'Jumpserver实时监控 '
+
' 登录用户名: '
+
'<span class="text-info">'
+
username
+
'</span>'
+
' 登录主机: '
+
'<span class="text-info">'
+
ip
,
title
:
'Jumpserver实时监控 '
+
' 登录用户名: '
+
'<span class="text-info">'
+
username
+
'</span>'
+
' 登录主机: '
+
'<span class="text-info">'
+
ip
,
...
@@ -190,6 +188,10 @@
...
@@ -190,6 +188,10 @@
}});
}});
return
false
;
return
false
;
});
});
$
(
'#test_connect'
).
click
(
function
(){
window
.
open
(
'/jlog/web_terminal/?asset_name="hello'
,
'播放'
,
'height=400, width=600, top=89px, left=99px,toolbar=no,menubar=no,scrollbars=auto,resizeable=no,location=no,status=no'
);
});
});
});
{
#
function
log_search
(){
#
}
{
#
function
log_search
(){
#
}
...
@@ -204,8 +206,14 @@
...
@@ -204,8 +206,14 @@
{
#
}
#
}
{
#
}
#
}
function
cut
(
num
){
function
cut
(
num
,
host
){
var
g_url
=
"/jlog/log_kill/?id="
+
num
;
console
.
log
(
host
);
if
(
host
==
'Web'
){
var
g_url
=
'{{ web_kill_uri }}'
+
'?id='
+
num
;
}
else
{
g_url
=
"/jlog/log_kill/?id="
+
num
;
}
$
.
ajax
({
$
.
ajax
({
type
:
"GET"
,
type
:
"GET"
,
url
:
g_url
,
url
:
g_url
,
...
...
templates/paginator.html
View file @
6db76423
<div
class=
"col-sm-6"
>
<div
class=
"col-sm-6"
>
<div
class=
"dataTables_paginate paging_simple_numbers"
id=
"editable_paginate"
>
<div
class=
"dataTables_paginate paging_simple_numbers"
id=
"editable_paginate"
>
<ul
class=
"pagination"
style=
"margin-top: 0; float: right"
>
<ul
class=
"pagination"
style=
"margin-top: 0; float: right"
>
{% if keyword %}
{% if contacts.has_previous %}
{% if contacts.has_previous %}
<li
class=
"paginate_button previous"
aria-controls=
"editable"
tabindex=
"0"
id=
"editable_previous"
>
<li
class=
"paginate_button previous"
aria-controls=
"editable"
tabindex=
"0"
id=
"editable_previous"
>
<a
href=
"?keyword={{ keyword }}&
page={{ contacts.previous_page_number }}"
>
Previous
</a>
<a
class=
"page"
href=
"?
page={{ contacts.previous_page_number }}"
>
Previous
</a>
</li>
</li>
{% else %}
{% else %}
<li
class=
"paginate_button previous disabled"
aria-controls=
"editable"
tabindex=
"0"
id=
"editable_previous"
>
<li
class=
"paginate_button previous disabled"
aria-controls=
"editable"
tabindex=
"0"
id=
"editable_previous"
>
<a
href=
"#"
>
Previous
</a>
<a
class=
"page"
href=
"#"
>
Previous
</a>
</li>
</li>
{% endif %}
{% endif %}
{% ifequal show_first 1 %}
{% ifequal show_first 1 %}
<li
class=
"paginate_button"
aria-controls=
"editable"
tabindex=
"0"
><a
href=
"?keyword={{ keyword }}&
page=1"
title=
"第1页"
>
1...
</a></li>
<li
class=
"paginate_button"
aria-controls=
"editable"
tabindex=
"0"
><a
class=
"page"
href=
"?
page=1"
title=
"第1页"
>
1...
</a></li>
{% endifequal %}
{% endifequal %}
{% for page in page_range %}
{% for page in page_range %}
{% ifequal current_page page %}
{% ifequal current_page page %}
<li
class=
"paginate_button active"
aria-controls=
"editable"
tabindex=
"0"
><a
href=
"?keyword={{ keyword }}&
page={{ page }}"
title=
"第{{ page }}页"
>
{{ page }}
</a></li>
<li
class=
"paginate_button active"
aria-controls=
"editable"
tabindex=
"0"
><a
class=
"page"
href=
"?
page={{ page }}"
title=
"第{{ page }}页"
>
{{ page }}
</a></li>
{% else %}
{% else %}
<li
class=
"paginate_button"
aria-controls=
"editable"
tabindex=
"0"
><a
href=
"?keyword={{ keyword }}&
page={{ page }}"
title=
"第{{ page }}页"
>
{{ page }}
</a></li>
<li
class=
"paginate_button"
aria-controls=
"editable"
tabindex=
"0"
><a
class=
"page"
href=
"?
page={{ page }}"
title=
"第{{ page }}页"
>
{{ page }}
</a></li>
{% endifequal %}
{% endifequal %}
{% endfor %}
{% endfor %}
{% ifequal show_end 1 %}
{% ifequal show_end 1 %}
<li
class=
"paginate_button"
aria-controls=
"editable"
tabindex=
"0"
><a
href=
"?keyword={{ keyword }}&
page={{ p.num_pages }}"
title=
"第{{ page }}页"
>
...{{ p.num_pages }}
</a></li>
<li
class=
"paginate_button"
aria-controls=
"editable"
tabindex=
"0"
><a
class=
"page"
href=
"?
page={{ p.num_pages }}"
title=
"第{{ page }}页"
>
...{{ p.num_pages }}
</a></li>
{% endifequal %}
{% endifequal %}
{% if contacts.has_next %}
{% if contacts.has_next %}
<li
class=
"paginate_button next"
aria-controls=
"editable"
tabindex=
"0"
id=
"editable_next"
>
<li
class=
"paginate_button next"
aria-controls=
"editable"
tabindex=
"0"
id=
"editable_next"
>
<a
href=
"?keyword={{ keyword }}&
page={{ contacts.next_page_number }}"
>
Next
</a>
<a
class=
"page"
href=
"?
page={{ contacts.next_page_number }}"
>
Next
</a>
</li>
</li>
{% else %}
{% else %}
<li
class=
"paginate_button next disabled"
aria-controls=
"editable"
tabindex=
"0"
id=
"editable_next"
>
<li
class=
"paginate_button next disabled"
aria-controls=
"editable"
tabindex=
"0"
id=
"editable_next"
>
<a
href=
"#"
>
Next
</a>
<a
class=
"page"
href=
"#"
>
Next
</a>
</li>
</li>
{% endif %}
{% endif %}
{% else %}
{% if contacts.has_previous %}
<li
class=
"paginate_button previous"
aria-controls=
"editable"
tabindex=
"0"
id=
"editable_previous"
>
<a
href=
"?page={{ contacts.previous_page_number }}"
>
Previous
</a>
</li>
{% else %}
<li
class=
"paginate_button previous disabled"
aria-controls=
"editable"
tabindex=
"0"
id=
"editable_previous"
>
<a
href=
"#"
>
Previous
</a>
</li>
{% endif %}
{% ifequal show_first 1 %}
<li
class=
"paginate_button"
aria-controls=
"editable"
tabindex=
"0"
><a
href=
"?page=1"
title=
"第1页"
>
1...
</a></li>
{% endifequal %}
{% for page in page_range %}
{% ifequal current_page page %}
<li
class=
"paginate_button active"
aria-controls=
"editable"
tabindex=
"0"
><a
href=
"?page={{ page }}"
title=
"第{{ page }}页"
>
{{ page }}
</a></li>
{% else %}
<li
class=
"paginate_button"
aria-controls=
"editable"
tabindex=
"0"
><a
href=
"?page={{ page }}"
title=
"第{{ page }}页"
>
{{ page }}
</a></li>
{% endifequal %}
{% endfor %}
{% ifequal show_end 1 %}
<li
class=
"paginate_button"
aria-controls=
"editable"
tabindex=
"0"
><a
href=
"?page={{ p.num_pages }}"
title=
"第{{ page }}页"
>
...{{ p.num_pages }}
</a></li>
{% endifequal %}
{% if contacts.has_next %}
<li
class=
"paginate_button next"
aria-controls=
"editable"
tabindex=
"0"
id=
"editable_next"
>
<a
href=
"?page={{ contacts.next_page_number }}"
>
Next
</a>
</li>
{% else %}
<li
class=
"paginate_button next disabled"
aria-controls=
"editable"
tabindex=
"0"
id=
"editable_next"
>
<a
href=
"#"
>
Next
</a>
</li>
{% endif %}
{% endif %}
</ul>
</ul>
</div>
</div>
</div>
</div>
<script>
$
(
document
).
ready
(
function
(){
$
(
'.page'
).
click
(
function
(){
var
searchStr
=
location
.
search
;
var
old_href
=
$
(
this
).
attr
(
'href'
).
replace
(
'?'
,
''
);
var
searchArray
=
searchStr
.
split
(
'&'
);
if
(
searchStr
.
indexOf
(
'page'
)){
searchArray
.
pop
();
}
searchArray
.
push
(
old_href
);
if
(
searchArray
.
length
>
2
){
$
(
this
).
attr
(
'href'
,
searchArray
.
join
(
'&'
));
}
})
});
</script>
templates/setting.html
View file @
6db76423
...
@@ -46,20 +46,28 @@
...
@@ -46,20 +46,28 @@
{% 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>
<input
name=
"setting"
value=
"default"
style=
"display: none"
>
<div
class=
"col-sm-8"
>
<div
class=
"col-sm-8"
>
<input
id=
"username"
name=
"username"
placeholder=
"Username"
type=
"text"
value=
"{{ setting_
r
.default_user }}"
class=
"form-control"
>
<input
id=
"username"
name=
"username"
placeholder=
"Username"
type=
"text"
value=
"{{ setting_
default
.default_user }}"
class=
"form-control"
>
</div>
</div>
</div>
</div>
<div
class=
"hr-line-dashed"
></div>
<div
class=
"hr-line-dashed"
></div>
<div
class=
"form-group"
>
<div
class=
"form-group"
>
<label
for=
"port"
class=
"col-sm-2 control-label"
>
默认ssh端口
<span
class=
"red-fonts"
>
*
</span></label>
<label
for=
"port"
class=
"col-sm-2 control-label"
>
默认ssh端口
<span
class=
"red-fonts"
>
*
</span></label>
<div
class=
"col-sm-8"
>
<div
class=
"col-sm-8"
>
<input
id=
"port"
name=
"port"
placeholder=
"Port"
type=
"text"
value=
"{{ setting_
r
.default_port }}"
class=
"form-control"
>
<input
id=
"port"
name=
"port"
placeholder=
"Port"
type=
"text"
value=
"{{ setting_
default
.default_port }}"
class=
"form-control"
>
</div>
</div>
</div>
</div>
<div
class=
"hr-line-dashed"
></div>
<div
class=
"hr-line-dashed"
></div>
<div
class=
"form-group"
>
<div
class=
"form-group"
>
<label
for=
"key"
class=
"col-sm-2 control-label"
>
默认密钥
<span
class=
"red-fonts"
>
*
</span></label>
<label
for=
"key"
class=
"col-sm-2 control-label"
>
默认密码
</label>
<div
class=
"col-sm-8"
>
<input
id=
"password"
name=
"password"
placeholder=
"Password"
type=
"password"
value=
"{{ setting_default.default_password }}"
class=
"form-control"
>
</div>
</div>
<div
class=
"hr-line-dashed"
></div>
<div
class=
"form-group"
>
<label
for=
"key"
class=
"col-sm-2 control-label"
>
默认密钥
</label>
<div
class=
"col-sm-8"
>
<div
class=
"col-sm-8"
>
<textarea
class=
"form-control"
name=
"key"
placeholder=
"请复制粘贴私钥(原来的因为安全原因不被显示)"
rows=
"10"
style=
"font-size: 9px;"
></textarea>
<textarea
class=
"form-control"
name=
"key"
placeholder=
"请复制粘贴私钥(原来的因为安全原因不被显示)"
rows=
"10"
style=
"font-size: 9px;"
></textarea>
</div>
</div>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment