Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
C
coco
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
coco
Commits
0755d134
Commit
0755d134
authored
May 16, 2018
by
ibuler
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[Update] 移除app依赖
parent
e418ebf4
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
134 additions
and
232 deletions
+134
-232
app.py
coco/app.py
+5
-5
connection.py
coco/connection.py
+3
-10
ctx.py
coco/ctx.py
+19
-2
httpd.py
coco/httpd.py
+12
-16
interactive.py
coco/interactive.py
+18
-80
interface.py
coco/interface.py
+6
-10
models.py
coco/models.py
+1
-0
proxy.py
coco/proxy.py
+9
-14
recorder.py
coco/recorder.py
+19
-18
sshd.py
coco/sshd.py
+24
-50
tasks.py
coco/tasks.py
+12
-14
utils.py
coco/utils.py
+6
-13
No files found.
coco/app.py
View file @
0755d134
...
@@ -50,6 +50,7 @@ class Coco:
...
@@ -50,6 +50,7 @@ class Coco:
'HEARTBEAT_INTERVAL'
:
5
,
'HEARTBEAT_INTERVAL'
:
5
,
'MAX_CONNECTIONS'
:
500
,
'MAX_CONNECTIONS'
:
500
,
'ADMINS'
:
''
,
'ADMINS'
:
''
,
'WORKERS'
:
4
,
'COMMAND_STORAGE'
:
{
'TYPE'
:
'server'
},
# server
'COMMAND_STORAGE'
:
{
'TYPE'
:
'server'
},
# server
'REPLAY_STORAGE'
:
{
'TYPE'
:
'server'
},
'REPLAY_STORAGE'
:
{
'TYPE'
:
'server'
},
}
}
...
@@ -92,13 +93,13 @@ class Coco:
...
@@ -92,13 +93,13 @@ class Coco:
@property
@property
def
httpd
(
self
):
def
httpd
(
self
):
if
self
.
_httpd
is
None
:
if
self
.
_httpd
is
None
:
self
.
_httpd
=
HttpServer
(
self
)
self
.
_httpd
=
HttpServer
()
return
self
.
_httpd
return
self
.
_httpd
@property
@property
def
task_handler
(
self
):
def
task_handler
(
self
):
if
self
.
_task_handler
is
None
:
if
self
.
_task_handler
is
None
:
self
.
_task_handler
=
TaskHandler
(
self
)
self
.
_task_handler
=
TaskHandler
()
return
self
.
_task_handler
return
self
.
_task_handler
def
make_logger
(
self
):
def
make_logger
(
self
):
...
@@ -116,11 +117,10 @@ class Coco:
...
@@ -116,11 +117,10 @@ class Coco:
self
.
command_recorder_class
=
get_command_recorder_class
(
self
.
config
)
self
.
command_recorder_class
=
get_command_recorder_class
(
self
.
config
)
def
new_command_recorder
(
self
):
def
new_command_recorder
(
self
):
recorder
=
self
.
command_recorder_class
(
self
)
return
self
.
command_recorder_class
()
return
recorder
def
new_replay_recorder
(
self
):
def
new_replay_recorder
(
self
):
return
self
.
replay_recorder_class
(
self
)
return
self
.
replay_recorder_class
()
def
bootstrap
(
self
):
def
bootstrap
(
self
):
self
.
make_logger
()
self
.
make_logger
()
...
...
coco/connection.py
View file @
0755d134
# -*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
#
#
import
weakref
import
os
import
os
import
socket
import
socket
import
paramiko
import
paramiko
from
paramiko.ssh_exception
import
SSHException
from
paramiko.ssh_exception
import
SSHException
from
.ctx
import
app_service
from
.utils
import
get_logger
,
get_private_key_fingerprint
from
.utils
import
get_logger
,
get_private_key_fingerprint
logger
=
get_logger
(
__file__
)
logger
=
get_logger
(
__file__
)
...
@@ -15,20 +15,13 @@ TIMEOUT = 10
...
@@ -15,20 +15,13 @@ TIMEOUT = 10
class
SSHConnection
:
class
SSHConnection
:
def
__init__
(
self
,
app
):
self
.
_app
=
weakref
.
ref
(
app
)
@property
def
app
(
self
):
return
self
.
_app
()
def
get_system_user_auth
(
self
,
system_user
):
def
get_system_user_auth
(
self
,
system_user
):
"""
"""
获取系统用户的认证信息,密码或秘钥
获取系统用户的认证信息,密码或秘钥
:return: system user have full info
:return: system user have full info
"""
"""
password
,
private_key
=
\
password
,
private_key
=
\
self
.
app
.
service
.
get_system_user_auth_info
(
system_user
)
app_
service
.
get_system_user_auth_info
(
system_user
)
system_user
.
password
=
password
system_user
.
password
=
password
system_user
.
private_key
=
private_key
system_user
.
private_key
=
private_key
...
@@ -97,7 +90,7 @@ class SSHConnection:
...
@@ -97,7 +90,7 @@ class SSHConnection:
def
get_proxy_sock
(
self
,
asset
):
def
get_proxy_sock
(
self
,
asset
):
sock
=
None
sock
=
None
domain
=
self
.
app
.
service
.
get_domain_detail_with_gateway
(
domain
=
app_
service
.
get_domain_detail_with_gateway
(
asset
.
domain
asset
.
domain
)
)
if
not
domain
.
has_ssh_gateway
():
if
not
domain
.
has_ssh_gateway
():
...
...
coco/ctx.py
View file @
0755d134
# -*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
#
#
current_app
=
[]
from
werkzeug.local
import
LocalProxy
current_service
=
[]
from
functools
import
partial
stack
=
{}
def
_find
(
name
):
if
stack
.
get
(
name
):
return
stack
[
name
]
else
:
raise
ValueError
(
"Not found in stack: {}"
.
format
(
name
))
current_app
=
LocalProxy
(
partial
(
_find
,
'app'
))
app_service
=
LocalProxy
(
partial
(
_find
,
'service'
))
# current_app = []
# current_service = []
coco/httpd.py
View file @
0755d134
...
@@ -11,6 +11,7 @@ from flask import Flask, request, current_app, redirect
...
@@ -11,6 +11,7 @@ from flask import Flask, request, current_app, redirect
from
.models
import
Request
,
Client
,
WSProxy
from
.models
import
Request
,
Client
,
WSProxy
from
.proxy
import
ProxyServer
from
.proxy
import
ProxyServer
from
.utils
import
get_logger
from
.utils
import
get_logger
from
.ctx
import
current_app
,
app_service
BASE_DIR
=
os
.
path
.
dirname
(
os
.
path
.
dirname
(
__file__
))
BASE_DIR
=
os
.
path
.
dirname
(
os
.
path
.
dirname
(
__file__
))
...
@@ -21,11 +22,6 @@ class BaseNamespace(Namespace):
...
@@ -21,11 +22,6 @@ class BaseNamespace(Namespace):
clients
=
None
clients
=
None
current_user
=
None
current_user
=
None
@property
def
app
(
self
):
app
=
current_app
.
config
[
'coco'
]
return
app
def
on_connect
(
self
):
def
on_connect
(
self
):
self
.
current_user
=
self
.
get_current_user
()
self
.
current_user
=
self
.
get_current_user
()
if
self
.
current_user
is
None
:
if
self
.
current_user
is
None
:
...
@@ -38,9 +34,9 @@ class BaseNamespace(Namespace):
...
@@ -38,9 +34,9 @@ class BaseNamespace(Namespace):
token
=
request
.
headers
.
get
(
"Authorization"
)
token
=
request
.
headers
.
get
(
"Authorization"
)
user
=
None
user
=
None
if
session_id
and
csrf_token
:
if
session_id
and
csrf_token
:
user
=
self
.
app
.
service
.
check_user_cookie
(
session_id
,
csrf_token
)
user
=
app_
service
.
check_user_cookie
(
session_id
,
csrf_token
)
if
token
:
if
token
:
user
=
self
.
app
.
service
.
check_user_with_token
(
token
)
user
=
app_
service
.
check_user_with_token
(
token
)
return
user
return
user
def
close
(
self
):
def
close
(
self
):
...
@@ -143,8 +139,8 @@ class ProxyNamespace(BaseNamespace):
...
@@ -143,8 +139,8 @@ class ProxyNamespace(BaseNamespace):
# self.on_connect()
# self.on_connect()
return
return
asset
=
self
.
app
.
service
.
get_asset
(
asset_id
)
asset
=
app_
service
.
get_asset
(
asset_id
)
system_user
=
self
.
app
.
service
.
get_system_user
(
user_id
)
system_user
=
app_
service
.
get_system_user
(
user_id
)
if
not
asset
or
not
system_user
:
if
not
asset
or
not
system_user
:
self
.
on_connect
()
self
.
on_connect
()
...
@@ -152,7 +148,7 @@ class ProxyNamespace(BaseNamespace):
...
@@ -152,7 +148,7 @@ class ProxyNamespace(BaseNamespace):
child
,
parent
=
socket
.
socketpair
()
child
,
parent
=
socket
.
socketpair
()
client
=
Client
(
parent
,
room
[
"request"
])
client
=
Client
(
parent
,
room
[
"request"
])
forwarder
=
ProxyServer
(
self
.
app
,
client
)
forwarder
=
ProxyServer
(
client
)
room
[
"client"
]
=
client
room
[
"client"
]
=
client
room
[
"forwarder"
]
=
forwarder
room
[
"forwarder"
]
=
forwarder
room
[
"proxy"
]
=
WSProxy
(
self
,
child
,
room
[
"id"
])
room
[
"proxy"
]
=
WSProxy
(
self
,
child
,
room
[
"id"
])
...
@@ -187,7 +183,7 @@ class ProxyNamespace(BaseNamespace):
...
@@ -187,7 +183,7 @@ class ProxyNamespace(BaseNamespace):
self
.
emit
(
'disconnect'
)
self
.
emit
(
'disconnect'
)
return
None
return
None
info
=
self
.
app
.
service
.
get_token_asset
(
token
)
info
=
app_
service
.
get_token_asset
(
token
)
logger
.
debug
(
info
)
logger
.
debug
(
info
)
if
not
info
:
if
not
info
:
logger
.
debug
(
"Token info is None"
)
logger
.
debug
(
"Token info is None"
)
...
@@ -197,7 +193,7 @@ class ProxyNamespace(BaseNamespace):
...
@@ -197,7 +193,7 @@ class ProxyNamespace(BaseNamespace):
return
None
return
None
user_id
=
info
.
get
(
'user'
,
None
)
user_id
=
info
.
get
(
'user'
,
None
)
self
.
current_user
=
self
.
app
.
service
.
get_user_profile
(
user_id
)
self
.
current_user
=
app_
service
.
get_user_profile
(
user_id
)
room
[
"request"
]
.
user
=
self
.
current_user
room
[
"request"
]
.
user
=
self
.
current_user
logger
.
debug
(
self
.
current_user
)
logger
.
debug
(
self
.
current_user
)
self
.
on_host
({
self
.
on_host
({
...
@@ -250,20 +246,20 @@ class ProxyNamespace(BaseNamespace):
...
@@ -250,20 +246,20 @@ class ProxyNamespace(BaseNamespace):
class
HttpServer
:
class
HttpServer
:
# prepare may be rewrite it
# prepare may be rewrite it
config
=
{
config
=
{
'SECRET_KEY'
:
''
,
'SECRET_KEY'
:
'
someWOrkSD20KMS9330)&#
'
,
'coco'
:
None
,
'coco'
:
None
,
'LOGIN_URL'
:
'/login'
'LOGIN_URL'
:
'/login'
}
}
init_kwargs
=
dict
(
init_kwargs
=
dict
(
# async_mode="gevent",
async_mode
=
"threading"
,
async_mode
=
"threading"
,
ping_timeout
=
20
,
ping_timeout
=
20
,
ping_interval
=
10
ping_interval
=
10
)
)
def
__init__
(
self
,
coco
):
def
__init__
(
self
):
config
=
coco
.
config
config
=
{
k
:
v
for
k
,
v
in
current_app
.
config
.
items
()}
config
.
update
(
self
.
config
)
config
.
update
(
self
.
config
)
config
[
'coco'
]
=
coco
self
.
flask_app
=
Flask
(
__name__
,
template_folder
=
'dist'
)
self
.
flask_app
=
Flask
(
__name__
,
template_folder
=
'dist'
)
self
.
flask_app
.
config
.
update
(
config
)
self
.
flask_app
.
config
.
update
(
config
)
self
.
socket_io
=
SocketIO
()
self
.
socket_io
=
SocketIO
()
...
...
coco/interactive.py
View file @
0755d134
...
@@ -4,16 +4,16 @@
...
@@ -4,16 +4,16 @@
import
socket
import
socket
import
threading
import
threading
import
weakref
import
os
import
os
from
jms.models
import
Asset
,
AssetGroup
from
jms.models
import
Asset
,
AssetGroup
from
.
import
char
from
.
import
char
from
.utils
import
wrap_with_line_feed
as
wr
,
wrap_with_title
as
title
,
\
from
.utils
import
wrap_with_line_feed
as
wr
,
wrap_with_title
as
title
,
\
wrap_with_primary
as
primary
,
wrap_with_warning
as
warning
,
\
wrap_with_warning
as
warning
,
is_obj_attr_has
,
\
is_obj_attr_has
,
is_obj_attr_eq
,
sort_assets
,
TtyIOParser
,
\
is_obj_attr_eq
,
sort_assets
,
TtyIOParser
,
\
ugettext
as
_
,
get_logger
ugettext
as
_
,
get_logger
,
net_input
from
.ctx
import
current_app
,
app_service
from
.proxy
import
ProxyServer
from
.proxy
import
ProxyServer
logger
=
get_logger
(
__file__
)
logger
=
get_logger
(
__file__
)
...
@@ -22,19 +22,14 @@ logger = get_logger(__file__)
...
@@ -22,19 +22,14 @@ logger = get_logger(__file__)
class
InteractiveServer
:
class
InteractiveServer
:
_sentinel
=
object
()
_sentinel
=
object
()
def
__init__
(
self
,
app
,
client
):
def
__init__
(
self
,
client
):
self
.
_app
=
weakref
.
ref
(
app
)
self
.
client
=
client
self
.
client
=
client
self
.
request
=
client
.
request
self
.
request
=
client
.
request
self
.
assets
=
None
self
.
assets
=
None
self
.
_search_result
=
None
self
.
_search_result
=
None
self
.
asset_groups
=
None
self
.
asset_groups
=
None
self
.
get_user_assets_async
()
self
.
get_user_assets_async
()
self
.
get_user_asset_groups_async
()
self
.
get_user_nodes_async
()
@property
def
app
(
self
):
return
self
.
_app
()
@property
@property
def
search_result
(
self
):
def
search_result
(
self
):
...
@@ -50,7 +45,7 @@ class InteractiveServer:
...
@@ -50,7 +45,7 @@ class InteractiveServer:
def
display_banner
(
self
):
def
display_banner
(
self
):
self
.
client
.
send
(
char
.
CLEAR_CHAR
)
self
.
client
.
send
(
char
.
CLEAR_CHAR
)
logo_path
=
os
.
path
.
join
(
self
.
app
.
root_path
,
"logo.txt"
)
logo_path
=
os
.
path
.
join
(
current_
app
.
root_path
,
"logo.txt"
)
if
os
.
path
.
isfile
(
logo_path
):
if
os
.
path
.
isfile
(
logo_path
):
with
open
(
logo_path
,
'rb'
)
as
f
:
with
open
(
logo_path
,
'rb'
)
as
f
:
for
i
in
f
:
for
i
in
f
:
...
@@ -71,63 +66,6 @@ class InteractiveServer:
...
@@ -71,63 +66,6 @@ class InteractiveServer:
)
)
self
.
client
.
send
(
banner
)
self
.
client
.
send
(
banner
)
def
get_option
(
self
,
prompt
=
'Opt> '
):
"""实现了一个ssh input, 提示用户输入, 获取并返回
:return user input string
"""
# Todo: 实现自动hostname或IP补全
input_data
=
[]
parser
=
TtyIOParser
()
self
.
client
.
send
(
wr
(
prompt
,
before
=
1
,
after
=
0
))
while
True
:
data
=
self
.
client
.
recv
(
10
)
if
len
(
data
)
==
0
:
self
.
app
.
remove_client
(
self
.
client
)
break
# Client input backspace
if
data
in
char
.
BACKSPACE_CHAR
:
# If input words less than 0, should send 'BELL'
if
len
(
input_data
)
>
0
:
data
=
char
.
BACKSPACE_CHAR
[
data
]
input_data
.
pop
()
else
:
data
=
char
.
BELL_CHAR
self
.
client
.
send
(
data
)
continue
if
data
.
startswith
(
b
'
\x03
'
):
# Ctrl-C
self
.
client
.
send
(
b
'^C
\r\n
Opt> '
)
input_data
=
[]
continue
elif
data
.
startswith
(
b
'
\x04
'
):
# Ctrl-D
return
'q'
# Todo: Move x1b to char
if
data
.
startswith
(
b
'
\x1b
'
)
or
data
in
char
.
UNSUPPORTED_CHAR
:
self
.
client
.
send
(
b
''
)
continue
# handle shell expect
multi_char_with_enter
=
False
if
len
(
data
)
>
1
and
data
[
-
1
]
in
char
.
ENTER_CHAR_ORDER
:
self
.
client
.
send
(
data
)
input_data
.
append
(
data
[:
-
1
])
multi_char_with_enter
=
True
# If user type ENTER we should get user input
if
data
in
char
.
ENTER_CHAR
or
multi_char_with_enter
:
self
.
client
.
send
(
wr
(
b
''
,
after
=
2
))
option
=
parser
.
parse_input
(
input_data
)
del
input_data
[:]
return
option
.
strip
()
else
:
self
.
client
.
send
(
data
)
input_data
.
append
(
data
)
def
dispatch
(
self
,
opt
):
def
dispatch
(
self
,
opt
):
if
opt
is
None
:
if
opt
is
None
:
return
self
.
_sentinel
return
self
.
_sentinel
...
@@ -179,7 +117,7 @@ class InteractiveServer:
...
@@ -179,7 +117,7 @@ class InteractiveServer:
def
display_asset_groups
(
self
):
def
display_asset_groups
(
self
):
if
self
.
asset_groups
is
None
:
if
self
.
asset_groups
is
None
:
self
.
get_user_
asset_group
s
()
self
.
get_user_
node
s
()
if
len
(
self
.
asset_groups
)
==
0
:
if
len
(
self
.
asset_groups
)
==
0
:
self
.
client
.
send
(
warning
(
_
(
"无"
)))
self
.
client
.
send
(
warning
(
_
(
"无"
)))
...
@@ -208,7 +146,7 @@ class InteractiveServer:
...
@@ -208,7 +146,7 @@ class InteractiveServer:
self
.
display_search_result
()
self
.
display_search_result
()
def
display_search_result
(
self
):
def
display_search_result
(
self
):
self
.
search_result
=
sort_assets
(
self
.
search_result
,
self
.
app
.
config
[
"ASSET_LIST_SORT_BY"
])
self
.
search_result
=
sort_assets
(
self
.
search_result
,
current_
app
.
config
[
"ASSET_LIST_SORT_BY"
])
fake_asset
=
Asset
(
hostname
=
_
(
"Hostname"
),
ip
=
_
(
"IP"
),
_system_users_name_list
=
_
(
"LoginAs"
),
fake_asset
=
Asset
(
hostname
=
_
(
"Hostname"
),
ip
=
_
(
"IP"
),
_system_users_name_list
=
_
(
"LoginAs"
),
comment
=
_
(
"Comment"
))
comment
=
_
(
"Comment"
))
id_max_length
=
max
(
len
(
str
(
len
(
self
.
search_result
))),
3
)
id_max_length
=
max
(
len
(
str
(
len
(
self
.
search_result
))),
3
)
...
@@ -231,11 +169,11 @@ class InteractiveServer:
...
@@ -231,11 +169,11 @@ class InteractiveServer:
self
.
search_assets
(
q
)
self
.
search_assets
(
q
)
self
.
display_search_result
()
self
.
display_search_result
()
def
get_user_
asset_group
s
(
self
):
def
get_user_
node
s
(
self
):
self
.
asset_groups
=
self
.
app
.
service
.
get_user_asset_groups
(
self
.
client
.
user
)
self
.
asset_groups
=
app_
service
.
get_user_asset_groups
(
self
.
client
.
user
)
def
get_user_
asset_group
s_async
(
self
):
def
get_user_
node
s_async
(
self
):
thread
=
threading
.
Thread
(
target
=
self
.
get_user_
asset_group
s
)
thread
=
threading
.
Thread
(
target
=
self
.
get_user_
node
s
)
thread
.
start
()
thread
.
start
()
@staticmethod
@staticmethod
...
@@ -248,7 +186,7 @@ class InteractiveServer:
...
@@ -248,7 +186,7 @@ class InteractiveServer:
return
assets
return
assets
def
get_user_assets
(
self
):
def
get_user_assets
(
self
):
self
.
assets
=
self
.
app
.
service
.
get_user_assets
(
self
.
client
.
user
)
self
.
assets
=
app_
service
.
get_user_assets
(
self
.
client
.
user
)
logger
.
debug
(
"Get user {} assets total: {}"
.
format
(
self
.
client
.
user
,
len
(
self
.
assets
)))
logger
.
debug
(
"Get user {} assets total: {}"
.
format
(
self
.
client
.
user
,
len
(
self
.
assets
)))
def
get_user_assets_async
(
self
):
def
get_user_assets_async
(
self
):
...
@@ -267,7 +205,7 @@ class InteractiveServer:
...
@@ -267,7 +205,7 @@ class InteractiveServer:
while
True
:
while
True
:
self
.
client
.
send
(
wr
(
_
(
"选择一个登陆: "
),
after
=
1
))
self
.
client
.
send
(
wr
(
_
(
"选择一个登陆: "
),
after
=
1
))
self
.
display_system_users
(
system_users
)
self
.
display_system_users
(
system_users
)
opt
=
self
.
get_option
(
"ID> "
)
opt
=
net_input
(
self
.
client
,
prompt
=
"ID> "
)
if
opt
.
isdigit
()
and
len
(
system_users
)
>
int
(
opt
):
if
opt
.
isdigit
()
and
len
(
system_users
)
>
int
(
opt
):
return
system_users
[
int
(
opt
)]
return
system_users
[
int
(
opt
)]
elif
opt
in
[
'q'
,
'Q'
]:
elif
opt
in
[
'q'
,
'Q'
]:
...
@@ -297,14 +235,14 @@ class InteractiveServer:
...
@@ -297,14 +235,14 @@ class InteractiveServer:
if
system_user
is
None
:
if
system_user
is
None
:
self
.
client
.
send
(
_
(
"没有系统用户"
))
self
.
client
.
send
(
_
(
"没有系统用户"
))
return
return
forwarder
=
ProxyServer
(
self
.
app
,
self
.
client
)
forwarder
=
ProxyServer
(
self
.
client
)
forwarder
.
proxy
(
asset
,
system_user
)
forwarder
.
proxy
(
asset
,
system_user
)
def
interact
(
self
):
def
interact
(
self
):
self
.
display_banner
()
self
.
display_banner
()
while
True
:
while
True
:
try
:
try
:
opt
=
self
.
get_option
(
)
opt
=
net_input
(
self
.
client
)
rv
=
self
.
dispatch
(
opt
)
rv
=
self
.
dispatch
(
opt
)
if
rv
is
self
.
_sentinel
:
if
rv
is
self
.
_sentinel
:
break
break
...
@@ -318,7 +256,7 @@ class InteractiveServer:
...
@@ -318,7 +256,7 @@ class InteractiveServer:
thread
.
start
()
thread
.
start
()
def
close
(
self
):
def
close
(
self
):
self
.
app
.
remove_client
(
self
.
client
)
current_
app
.
remove_client
(
self
.
client
)
# def __del__(self):
# def __del__(self):
# print("GC: Interactive class been gc")
# print("GC: Interactive class been gc")
coco/interface.py
View file @
0755d134
...
@@ -7,6 +7,7 @@ import threading
...
@@ -7,6 +7,7 @@ import threading
import
weakref
import
weakref
from
.utils
import
get_logger
from
.utils
import
get_logger
from
.ctx
import
current_app
,
app_service
logger
=
get_logger
(
__file__
)
logger
=
get_logger
(
__file__
)
...
@@ -19,18 +20,13 @@ class SSHInterface(paramiko.ServerInterface):
...
@@ -19,18 +20,13 @@ class SSHInterface(paramiko.ServerInterface):
https://github.com/paramiko/paramiko/blob/master/demos/demo_server.py
https://github.com/paramiko/paramiko/blob/master/demos/demo_server.py
"""
"""
def
__init__
(
self
,
app
,
request
):
def
__init__
(
self
,
request
):
self
.
_app
=
weakref
.
ref
(
app
)
self
.
_request
=
weakref
.
ref
(
request
)
self
.
_request
=
weakref
.
ref
(
request
)
self
.
event
=
threading
.
Event
()
self
.
event
=
threading
.
Event
()
self
.
auth_valid
=
False
self
.
auth_valid
=
False
self
.
otp_auth
=
False
self
.
otp_auth
=
False
self
.
info
=
None
self
.
info
=
None
@property
def
app
(
self
):
return
self
.
_app
()
@property
@property
def
request
(
self
):
def
request
(
self
):
return
self
.
_request
()
return
self
.
_request
()
...
@@ -55,7 +51,7 @@ class SSHInterface(paramiko.ServerInterface):
...
@@ -55,7 +51,7 @@ class SSHInterface(paramiko.ServerInterface):
if
not
seed
:
if
not
seed
:
return
paramiko
.
AUTH_FAILED
return
paramiko
.
AUTH_FAILED
is_valid
=
self
.
app
.
service
.
authenticate_otp
(
seed
,
otp_code
)
is_valid
=
app_
service
.
authenticate_otp
(
seed
,
otp_code
)
if
is_valid
:
if
is_valid
:
return
paramiko
.
AUTH_SUCCESSFUL
return
paramiko
.
AUTH_SUCCESSFUL
return
paramiko
.
AUTH_FAILED
return
paramiko
.
AUTH_FAILED
...
@@ -67,9 +63,9 @@ class SSHInterface(paramiko.ServerInterface):
...
@@ -67,9 +63,9 @@ class SSHInterface(paramiko.ServerInterface):
supported
=
[]
supported
=
[]
if
self
.
otp_auth
:
if
self
.
otp_auth
:
return
'keyboard-interactive'
return
'keyboard-interactive'
if
self
.
app
.
config
[
"PASSWORD_AUTH"
]:
if
current_
app
.
config
[
"PASSWORD_AUTH"
]:
supported
.
append
(
"password"
)
supported
.
append
(
"password"
)
if
self
.
app
.
config
[
"PUBLIC_KEY_AUTH"
]:
if
current_
app
.
config
[
"PUBLIC_KEY_AUTH"
]:
supported
.
append
(
"publickey"
)
supported
.
append
(
"publickey"
)
return
","
.
join
(
supported
)
return
","
.
join
(
supported
)
...
@@ -100,7 +96,7 @@ class SSHInterface(paramiko.ServerInterface):
...
@@ -100,7 +96,7 @@ class SSHInterface(paramiko.ServerInterface):
return
paramiko
.
AUTH_SUCCESSFUL
return
paramiko
.
AUTH_SUCCESSFUL
def
validate_auth
(
self
,
username
,
password
=
""
,
public_key
=
""
):
def
validate_auth
(
self
,
username
,
password
=
""
,
public_key
=
""
):
info
=
self
.
app
.
service
.
authenticate
(
info
=
app_
service
.
authenticate
(
username
,
password
=
password
,
public_key
=
public_key
,
username
,
password
=
password
,
public_key
=
public_key
,
remote_addr
=
self
.
request
.
remote_ip
remote_addr
=
self
.
request
.
remote_ip
)
)
...
...
coco/models.py
View file @
0755d134
...
@@ -251,6 +251,7 @@ class WSProxy:
...
@@ -251,6 +251,7 @@ class WSProxy:
if
len
(
data
)
==
0
:
if
len
(
data
)
==
0
:
self
.
close
()
self
.
close
()
data
=
data
.
decode
(
errors
=
"ignore"
)
data
=
data
.
decode
(
errors
=
"ignore"
)
print
(
"Send data: {}"
.
format
(
data
))
self
.
ws
.
emit
(
"data"
,
{
'data'
:
data
,
'room'
:
self
.
room_id
},
self
.
ws
.
emit
(
"data"
,
{
'data'
:
data
,
'room'
:
self
.
room_id
},
room
=
self
.
room_id
)
room
=
self
.
room_id
)
if
len
(
data
)
==
BUF_SIZE
:
if
len
(
data
)
==
BUF_SIZE
:
...
...
coco/proxy.py
View file @
0755d134
...
@@ -4,13 +4,13 @@
...
@@ -4,13 +4,13 @@
import
threading
import
threading
import
time
import
time
import
weakref
from
paramiko.ssh_exception
import
SSHException
from
paramiko.ssh_exception
import
SSHException
from
.session
import
Session
from
.session
import
Session
from
.models
import
Server
from
.models
import
Server
from
.connection
import
SSHConnection
from
.connection
import
SSHConnection
from
.ctx
import
current_app
,
app_service
from
.utils
import
wrap_with_line_feed
as
wr
,
wrap_with_warning
as
warning
,
\
from
.utils
import
wrap_with_line_feed
as
wr
,
wrap_with_warning
as
warning
,
\
get_logger
,
net_input
get_logger
,
net_input
...
@@ -21,24 +21,19 @@ BUF_SIZE = 4096
...
@@ -21,24 +21,19 @@ BUF_SIZE = 4096
class
ProxyServer
:
class
ProxyServer
:
def
__init__
(
self
,
app
,
client
):
def
__init__
(
self
,
client
):
self
.
_app
=
weakref
.
ref
(
app
)
self
.
client
=
client
self
.
client
=
client
self
.
server
=
None
self
.
server
=
None
self
.
connecting
=
True
self
.
connecting
=
True
self
.
stop_event
=
threading
.
Event
()
self
.
stop_event
=
threading
.
Event
()
@property
def
app
(
self
):
return
self
.
_app
()
def
get_system_user_auth
(
self
,
system_user
):
def
get_system_user_auth
(
self
,
system_user
):
"""
"""
获取系统用户的认证信息,密码或秘钥
获取系统用户的认证信息,密码或秘钥
:return: system user have full info
:return: system user have full info
"""
"""
password
,
private_key
=
\
password
,
private_key
=
\
self
.
app
.
service
.
get_system_user_auth_info
(
system_user
)
app_
service
.
get_system_user_auth_info
(
system_user
)
if
not
password
and
not
private_key
:
if
not
password
and
not
private_key
:
prompt
=
"{}'s password: "
.
format
(
system_user
.
username
)
prompt
=
"{}'s password: "
.
format
(
system_user
.
username
)
password
=
net_input
(
self
.
client
,
prompt
=
prompt
,
sensitive
=
True
)
password
=
net_input
(
self
.
client
,
prompt
=
prompt
,
sensitive
=
True
)
...
@@ -51,26 +46,26 @@ class ProxyServer:
...
@@ -51,26 +46,26 @@ class ProxyServer:
self
.
server
=
self
.
get_server_conn
(
asset
,
system_user
)
self
.
server
=
self
.
get_server_conn
(
asset
,
system_user
)
if
self
.
server
is
None
:
if
self
.
server
is
None
:
return
return
command_recorder
=
self
.
app
.
new_command_recorder
()
command_recorder
=
current_
app
.
new_command_recorder
()
replay_recorder
=
self
.
app
.
new_replay_recorder
()
replay_recorder
=
current_
app
.
new_replay_recorder
()
session
=
Session
(
session
=
Session
(
self
.
client
,
self
.
server
,
self
.
client
,
self
.
server
,
command_recorder
=
command_recorder
,
command_recorder
=
command_recorder
,
replay_recorder
=
replay_recorder
,
replay_recorder
=
replay_recorder
,
)
)
self
.
app
.
add_session
(
session
)
current_
app
.
add_session
(
session
)
self
.
watch_win_size_change_async
()
self
.
watch_win_size_change_async
()
session
.
bridge
()
session
.
bridge
()
self
.
stop_event
.
set
()
self
.
stop_event
.
set
()
self
.
end_watch_win_size_change
()
self
.
end_watch_win_size_change
()
self
.
app
.
remove_session
(
session
)
current_
app
.
remove_session
(
session
)
def
validate_permission
(
self
,
asset
,
system_user
):
def
validate_permission
(
self
,
asset
,
system_user
):
"""
"""
验证用户是否有连接改资产的权限
验证用户是否有连接改资产的权限
:return: True or False
:return: True or False
"""
"""
return
self
.
app
.
service
.
validate_user_asset_permission
(
return
app_
service
.
validate_user_asset_permission
(
self
.
client
.
user
.
id
,
asset
.
id
,
system_user
.
id
self
.
client
.
user
.
id
,
asset
.
id
,
system_user
.
id
)
)
...
@@ -90,11 +85,11 @@ class ProxyServer:
...
@@ -90,11 +85,11 @@ class ProxyServer:
pass
pass
def
get_ssh_server_conn
(
self
,
asset
,
system_user
):
def
get_ssh_server_conn
(
self
,
asset
,
system_user
):
ssh
=
SSHConnection
(
self
.
app
)
request
=
self
.
client
.
request
request
=
self
.
client
.
request
term
=
request
.
meta
.
get
(
'term'
,
'xterm'
)
term
=
request
.
meta
.
get
(
'term'
,
'xterm'
)
width
=
request
.
meta
.
get
(
'width'
,
80
)
width
=
request
.
meta
.
get
(
'width'
,
80
)
height
=
request
.
meta
.
get
(
'height'
,
24
)
height
=
request
.
meta
.
get
(
'height'
,
24
)
ssh
=
SSHConnection
()
chan
,
msg
=
ssh
.
get_channel
(
asset
,
system_user
,
term
=
term
,
chan
,
msg
=
ssh
.
get_channel
(
asset
,
system_user
,
term
=
term
,
width
=
width
,
height
=
height
)
width
=
width
,
height
=
height
)
if
not
chan
:
if
not
chan
:
...
...
coco/recorder.py
View file @
0755d134
...
@@ -13,14 +13,14 @@ import jms_storage
...
@@ -13,14 +13,14 @@ import jms_storage
from
.utils
import
get_logger
,
Singleton
from
.utils
import
get_logger
,
Singleton
from
.alignment
import
MemoryQueue
from
.alignment
import
MemoryQueue
from
.ctx
import
current_app
,
app_service
logger
=
get_logger
(
__file__
)
logger
=
get_logger
(
__file__
)
BUF_SIZE
=
1024
BUF_SIZE
=
1024
class
ReplayRecorder
(
metaclass
=
abc
.
ABCMeta
):
class
ReplayRecorder
(
metaclass
=
abc
.
ABCMeta
):
def
__init__
(
self
,
app
,
session
=
None
):
def
__init__
(
self
,
session
=
None
):
self
.
app
=
app
self
.
session
=
session
self
.
session
=
session
@abc.abstractmethod
@abc.abstractmethod
...
@@ -47,8 +47,7 @@ class ReplayRecorder(metaclass=abc.ABCMeta):
...
@@ -47,8 +47,7 @@ class ReplayRecorder(metaclass=abc.ABCMeta):
class
CommandRecorder
:
class
CommandRecorder
:
def
__init__
(
self
,
app
,
session
=
None
):
def
__init__
(
self
,
session
=
None
):
self
.
app
=
app
self
.
session
=
session
self
.
session
=
session
def
record
(
self
,
data
):
def
record
(
self
,
data
):
...
@@ -78,8 +77,8 @@ class ServerReplayRecorder(ReplayRecorder):
...
@@ -78,8 +77,8 @@ class ServerReplayRecorder(ReplayRecorder):
time_start
=
None
time_start
=
None
storage
=
None
storage
=
None
def
__init__
(
self
,
app
):
def
__init__
(
self
):
super
()
.
__init__
(
app
)
super
()
.
__init__
()
self
.
file
=
None
self
.
file
=
None
self
.
file_path
=
None
self
.
file_path
=
None
...
@@ -100,8 +99,8 @@ class ServerReplayRecorder(ReplayRecorder):
...
@@ -100,8 +99,8 @@ class ServerReplayRecorder(ReplayRecorder):
def
session_start
(
self
,
session_id
):
def
session_start
(
self
,
session_id
):
self
.
time_start
=
time
.
time
()
self
.
time_start
=
time
.
time
()
filename
=
session_id
+
'.replay.gz'
filename
=
session_id
+
'.replay.gz'
self
.
file_path
=
os
.
path
.
join
(
self
.
app
.
config
[
'LOG_DIR'
],
filename
)
self
.
file_path
=
os
.
path
.
join
(
current_
app
.
config
[
'LOG_DIR'
],
filename
)
self
.
file
=
gzip
.
open
(
self
.
file_path
,
'at'
)
self
.
file
=
gzip
.
open
(
self
.
file_path
,
'at'
)
self
.
file
.
write
(
'{'
)
self
.
file
.
write
(
'{'
)
...
@@ -114,11 +113,11 @@ class ServerReplayRecorder(ReplayRecorder):
...
@@ -114,11 +113,11 @@ class ServerReplayRecorder(ReplayRecorder):
logger
.
error
(
"Failed to push {}'s {}"
.
format
(
session_id
,
"record"
))
logger
.
error
(
"Failed to push {}'s {}"
.
format
(
session_id
,
"record"
))
def
upload_replay
(
self
,
session_id
):
def
upload_replay
(
self
,
session_id
):
configs
=
self
.
app
.
service
.
load_config_from_server
()
configs
=
app_
service
.
load_config_from_server
()
logger
.
debug
(
"upload_replay print config: {}"
.
format
(
configs
))
logger
.
debug
(
"upload_replay print config: {}"
.
format
(
configs
))
self
.
storage
=
jms_storage
.
init
(
configs
[
"REPLAY_STORAGE"
])
self
.
storage
=
jms_storage
.
init
(
configs
[
"REPLAY_STORAGE"
])
if
not
self
.
storage
:
if
not
self
.
storage
:
self
.
storage
=
jms_storage
.
jms
(
self
.
app
.
service
)
self
.
storage
=
jms_storage
.
jms
(
app_
service
)
if
self
.
push_file
(
3
,
session_id
):
if
self
.
push_file
(
3
,
session_id
):
os
.
unlink
(
self
.
file_path
)
os
.
unlink
(
self
.
file_path
)
return
True
return
True
...
@@ -137,7 +136,7 @@ class ServerReplayRecorder(ReplayRecorder):
...
@@ -137,7 +136,7 @@ class ServerReplayRecorder(ReplayRecorder):
else
:
else
:
msg
=
"Failed push session {}'s replay log to storage"
.
format
(
session_id
)
msg
=
"Failed push session {}'s replay log to storage"
.
format
(
session_id
)
logger
.
error
(
msg
)
logger
.
error
(
msg
)
self
.
storage
=
jms_storage
.
jms
(
self
.
app
.
service
)
self
.
storage
=
jms_storage
.
jms
(
app_
service
)
return
self
.
push_file
(
3
,
session_id
)
return
self
.
push_file
(
3
,
session_id
)
if
self
.
push_to_storage
(
session_id
):
if
self
.
push_to_storage
(
session_id
):
...
@@ -153,7 +152,7 @@ class ServerReplayRecorder(ReplayRecorder):
...
@@ -153,7 +152,7 @@ class ServerReplayRecorder(ReplayRecorder):
logger
.
error
(
"Failed finished session {}'s replay"
.
format
(
session_id
))
logger
.
error
(
"Failed finished session {}'s replay"
.
format
(
session_id
))
return
False
return
False
if
self
.
app
.
service
.
finish_replay
(
session_id
):
if
app_
service
.
finish_replay
(
session_id
):
logger
.
info
(
"Success finish session {}'s replay "
.
format
(
session_id
))
logger
.
info
(
"Success finish session {}'s replay "
.
format
(
session_id
))
return
True
return
True
else
:
else
:
...
@@ -166,8 +165,8 @@ class ServerCommandRecorder(CommandRecorder, metaclass=Singleton):
...
@@ -166,8 +165,8 @@ class ServerCommandRecorder(CommandRecorder, metaclass=Singleton):
timeout
=
5
timeout
=
5
no
=
0
no
=
0
def
__init__
(
self
,
app
):
def
__init__
(
self
):
super
()
.
__init__
(
app
)
super
()
.
__init__
()
self
.
queue
=
MemoryQueue
()
self
.
queue
=
MemoryQueue
()
self
.
stop_evt
=
threading
.
Event
()
self
.
stop_evt
=
threading
.
Event
()
self
.
push_to_server_async
()
self
.
push_to_server_async
()
...
@@ -190,7 +189,7 @@ class ServerCommandRecorder(CommandRecorder, metaclass=Singleton):
...
@@ -190,7 +189,7 @@ class ServerCommandRecorder(CommandRecorder, metaclass=Singleton):
if
not
data_set
:
if
not
data_set
:
continue
continue
logger
.
debug
(
"Send {} commands to server"
.
format
(
len
(
data_set
)))
logger
.
debug
(
"Send {} commands to server"
.
format
(
len
(
data_set
)))
ok
=
self
.
app
.
service
.
push_session_command
(
data_set
)
ok
=
app_
service
.
push_session_command
(
data_set
)
if
not
ok
:
if
not
ok
:
self
.
queue
.
mput
(
data_set
)
self
.
queue
.
mput
(
data_set
)
...
@@ -214,13 +213,15 @@ class ESCommandRecorder(CommandRecorder, metaclass=Singleton):
...
@@ -214,13 +213,15 @@ class ESCommandRecorder(CommandRecorder, metaclass=Singleton):
no
=
0
no
=
0
default_hosts
=
[
"http://localhost"
]
default_hosts
=
[
"http://localhost"
]
def
__init__
(
self
,
app
):
def
__init__
(
self
):
super
()
.
__init__
(
app
)
super
()
.
__init__
()
self
.
queue
=
MemoryQueue
()
self
.
queue
=
MemoryQueue
()
self
.
stop_evt
=
threading
.
Event
()
self
.
stop_evt
=
threading
.
Event
()
self
.
push_to_es_async
()
self
.
push_to_es_async
()
self
.
__class__
.
no
+=
1
self
.
__class__
.
no
+=
1
self
.
store
=
jms_storage
.
ESStore
(
app
.
config
[
"COMMAND_STORAGE"
]
.
get
(
"HOSTS"
,
self
.
default_hosts
))
self
.
store
=
jms_storage
.
ESStore
(
current_app
.
config
[
"COMMAND_STORAGE"
]
.
get
(
"HOSTS"
,
self
.
default_hosts
)
)
if
not
self
.
store
.
ping
():
if
not
self
.
store
.
ping
():
raise
AssertionError
(
"ESCommand storage init error"
)
raise
AssertionError
(
"ESCommand storage init error"
)
...
...
coco/sshd.py
View file @
0755d134
...
@@ -5,16 +5,14 @@
...
@@ -5,16 +5,14 @@
import
os
import
os
import
socket
import
socket
import
threading
import
threading
import
random
import
paramiko
import
paramiko
from
multiprocessing.reduction
import
recv_handle
,
send_handle
from
multiprocessing
import
Process
,
Pipe
from
.utils
import
ssh_key_gen
,
get_logger
,
get_app
from
.utils
import
ssh_key_gen
,
get_logger
from
.interface
import
SSHInterface
from
.interface
import
SSHInterface
from
.interactive
import
InteractiveServer
from
.interactive
import
InteractiveServer
from
.models
import
Client
,
Request
from
.models
import
Client
,
Request
from
.sftp
import
SFTPServer
from
.sftp
import
SFTPServer
from
.ctx
import
current_app
logger
=
get_logger
(
__file__
)
logger
=
get_logger
(
__file__
)
BACKLOG
=
5
BACKLOG
=
5
...
@@ -24,64 +22,40 @@ class SSHServer:
...
@@ -24,64 +22,40 @@ class SSHServer:
def
__init__
(
self
):
def
__init__
(
self
):
self
.
stop_evt
=
threading
.
Event
()
self
.
stop_evt
=
threading
.
Event
()
self
.
host_key_path
=
os
.
path
.
join
(
self
.
app
.
root_path
,
'keys'
,
'host_rsa_key'
)
self
.
workers
=
[]
self
.
workers
=
[]
self
.
pipe
=
None
self
.
pipe
=
None
@property
def
app
(
self
):
return
get_app
()
@property
@property
def
host_key
(
self
):
def
host_key
(
self
):
if
not
os
.
path
.
isfile
(
self
.
host_key_path
):
host_key_path
=
os
.
path
.
join
(
current_app
.
root_path
,
'keys'
,
'host_rsa_key'
)
self
.
gen_host_key
()
if
not
os
.
path
.
isfile
(
host_key_path
):
return
paramiko
.
RSAKey
(
filename
=
self
.
host_key_path
)
self
.
gen_host_key
(
host_key_path
)
return
paramiko
.
RSAKey
(
filename
=
host_key_path
)
def
gen_host_key
(
self
):
@staticmethod
def
gen_host_key
(
key_path
):
ssh_key
,
_
=
ssh_key_gen
()
ssh_key
,
_
=
ssh_key_gen
()
with
open
(
self
.
host_
key_path
,
'w'
)
as
f
:
with
open
(
key_path
,
'w'
)
as
f
:
f
.
write
(
ssh_key
)
f
.
write
(
ssh_key
)
def
start_worker
(
self
,
in_pipe
,
out_pipe
):
def
run
(
self
):
print
(
"APP: {}"
.
format
(
self
.
app
))
host
=
current_app
.
config
[
"BIND_HOST"
]
print
(
"APP sessions: {}"
.
format
(
self
.
app
))
port
=
current_app
.
config
[
"SSHD_PORT"
]
out_pipe
.
close
()
while
not
self
.
stop_evt
.
is_set
():
fd
=
recv_handle
(
in_pipe
)
sock
=
socket
.
socket
(
socket
.
AF_INET
,
socket
.
SOCK_STREAM
,
fileno
=
fd
)
addr
=
sock
.
getpeername
()
thread
=
threading
.
Thread
(
target
=
self
.
handle_connection
,
args
=
(
sock
,
addr
))
thread
.
daemon
=
True
thread
.
start
()
def
start_server
(
self
,
in_pipe
,
out_pipe
,
workers
):
in_pipe
.
close
()
host
=
self
.
app
.
config
[
"BIND_HOST"
]
port
=
self
.
app
.
config
[
"SSHD_PORT"
]
print
(
'Starting ssh server at {}:{}'
.
format
(
host
,
port
))
print
(
'Starting ssh server at {}:{}'
.
format
(
host
,
port
))
sock
=
socket
.
socket
(
socket
.
AF_INET
,
socket
.
SOCK_STREAM
)
sock
=
socket
.
socket
(
socket
.
AF_INET
,
socket
.
SOCK_STREAM
)
sock
.
setsockopt
(
socket
.
SOL_SOCKET
,
socket
.
SO_REUSEADDR
,
1
)
sock
.
setsockopt
(
socket
.
SOL_SOCKET
,
socket
.
SO_REUSEADDR
,
1
)
sock
.
bind
((
host
,
port
))
sock
.
bind
((
host
,
port
))
sock
.
listen
(
BACKLOG
)
sock
.
listen
(
BACKLOG
)
while
not
self
.
stop_evt
.
is_set
():
while
not
self
.
stop_evt
.
is_set
():
client
,
addr
=
sock
.
accept
()
try
:
logger
.
info
(
"Get ssh request from {}"
.
format
(
addr
))
client
,
addr
=
sock
.
accept
()
send_handle
(
out_pipe
,
client
.
fileno
(),
random
.
choice
(
workers
)
.
pid
)
logger
.
info
(
"Get ssh request from {}: {}"
.
format
(
*
addr
))
client
.
close
()
thread
=
threading
.
Thread
(
target
=
self
.
handle_connection
,
args
=
(
client
,
addr
))
def
run
(
self
):
thread
.
daemon
=
True
in_pipe
,
out_pipe
=
Pipe
()
thread
.
start
()
self
.
pipe
=
(
in_pipe
,
out_pipe
)
except
IndexError
as
e
:
workers
=
[]
logger
.
error
(
"Start SSH server error: {}"
.
format
(
e
))
for
i
in
range
(
4
):
worker
=
Process
(
target
=
self
.
start_worker
,
args
=
(
in_pipe
,
out_pipe
))
worker
.
start
()
workers
.
append
(
worker
)
self
.
start_server
(
in_pipe
,
out_pipe
,
workers
)
in_pipe
.
close
()
out_pipe
.
close
()
def
handle_connection
(
self
,
sock
,
addr
):
def
handle_connection
(
self
,
sock
,
addr
):
transport
=
paramiko
.
Transport
(
sock
,
gss_kex
=
False
)
transport
=
paramiko
.
Transport
(
sock
,
gss_kex
=
False
)
...
@@ -95,7 +69,7 @@ class SSHServer:
...
@@ -95,7 +69,7 @@ class SSHServer:
'sftp'
,
paramiko
.
SFTPServer
,
SFTPServer
'sftp'
,
paramiko
.
SFTPServer
,
SFTPServer
)
)
request
=
Request
(
addr
)
request
=
Request
(
addr
)
server
=
SSHInterface
(
self
.
app
,
request
)
server
=
SSHInterface
(
request
)
try
:
try
:
transport
.
start_server
(
server
=
server
)
transport
.
start_server
(
server
=
server
)
except
paramiko
.
SSHException
:
except
paramiko
.
SSHException
:
...
@@ -126,7 +100,7 @@ class SSHServer:
...
@@ -126,7 +100,7 @@ class SSHServer:
def
handle_chan
(
self
,
chan
,
request
):
def
handle_chan
(
self
,
chan
,
request
):
client
=
Client
(
chan
,
request
)
client
=
Client
(
chan
,
request
)
self
.
app
.
add_client
(
client
)
current_
app
.
add_client
(
client
)
self
.
dispatch
(
client
)
self
.
dispatch
(
client
)
def
dispatch
(
self
,
client
):
def
dispatch
(
self
,
client
):
...
@@ -134,7 +108,7 @@ class SSHServer:
...
@@ -134,7 +108,7 @@ class SSHServer:
request_type
=
set
(
client
.
request
.
type
)
request_type
=
set
(
client
.
request
.
type
)
if
supported
&
request_type
:
if
supported
&
request_type
:
logger
.
info
(
"Request type `pty`, dispatch to interactive mode"
)
logger
.
info
(
"Request type `pty`, dispatch to interactive mode"
)
InteractiveServer
(
self
.
app
,
client
)
.
interact
()
InteractiveServer
(
client
)
.
interact
()
elif
'subsystem'
in
request_type
:
elif
'subsystem'
in
request_type
:
pass
pass
else
:
else
:
...
...
coco/tasks.py
View file @
0755d134
#!/usr/bin/env python3
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
#
#
import
weakref
from
.ctx
import
current_app
,
app_service
from
.utils
import
get_logger
from
.utils
import
get_logger
logger
=
get_logger
(
__file__
)
logger
=
get_logger
(
__file__
)
class
TaskHandler
:
class
TaskHandler
:
routes
=
None
def
__init__
(
self
,
app
):
def
init
(
self
):
self
.
_app
=
weakref
.
ref
(
app
)
self
.
routes
=
{
'kill_session'
:
self
.
handle_kill_session
}
@property
@staticmethod
def
app
(
self
):
def
handle_kill_session
(
task
):
return
self
.
_app
()
def
handle_kill_session
(
self
,
task
):
logger
.
info
(
"Handle kill session task: {}"
.
format
(
task
.
args
))
logger
.
info
(
"Handle kill session task: {}"
.
format
(
task
.
args
))
session_id
=
task
.
args
session_id
=
task
.
args
session
=
None
session
=
None
for
s
in
self
.
app
.
sessions
:
for
s
in
current_
app
.
sessions
:
if
s
.
id
==
session_id
:
if
s
.
id
==
session_id
:
session
=
s
session
=
s
break
break
if
session
:
if
session
:
session
.
terminate
()
session
.
terminate
()
self
.
app
.
service
.
finish_task
(
task
.
id
)
app_
service
.
finish_task
(
task
.
id
)
def
handle
(
self
,
task
):
def
handle
(
self
,
task
):
if
task
.
name
==
"kill_session"
:
func
=
self
.
routes
.
get
(
task
.
name
)
self
.
handle_kill_session
(
task
)
return
func
(
task
)
else
:
logger
.
error
(
"No handler for this task: {}"
.
format
(
task
.
name
))
coco/utils.py
View file @
0755d134
...
@@ -15,7 +15,7 @@ import paramiko
...
@@ -15,7 +15,7 @@ import paramiko
import
pyte
import
pyte
from
.
import
char
from
.
import
char
from
.ctx
import
current_app
,
current_service
from
.ctx
import
stack
BASE_DIR
=
os
.
path
.
abspath
(
os
.
path
.
dirname
(
os
.
path
.
dirname
(
__file__
)))
BASE_DIR
=
os
.
path
.
abspath
(
os
.
path
.
dirname
(
os
.
path
.
dirname
(
__file__
)))
...
@@ -370,25 +370,18 @@ def net_input(client, prompt='Opt> ', sensitive=False):
...
@@ -370,25 +370,18 @@ def net_input(client, prompt='Opt> ', sensitive=False):
def
register_app
(
app
):
def
register_app
(
app
):
current_app
.
insert
(
0
,
app
)
stack
[
'app'
]
=
app
def
register_service
(
service
):
def
register_service
(
service
):
current_service
.
insert
(
0
,
service
)
stack
[
'service'
]
=
service
def
get_app
():
def
get_app
():
if
current_app
:
if
stack
.
get
(
"app"
)
:
return
current_app
[
0
]
return
stack
[
"app"
]
else
:
else
:
raise
ValueError
(
"App not found"
)
return
ValueError
(
"No app found"
)
def
get_service
():
if
current_service
:
return
current_app
[
0
]
else
:
raise
ValueError
(
"Service not found"
)
ugettext
=
_gettext
()
ugettext
=
_gettext
()
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