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
6f4273c6
Unverified
Commit
6f4273c6
authored
Nov 11, 2018
by
老广
Committed by
GitHub
Nov 11, 2018
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #124 from jumpserver/dev
Dev
parents
5f8d1227
88a9e2d3
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
322 additions
and
103 deletions
+322
-103
connection.py
coco/connection.py
+3
-3
connector.py
coco/httpd/elfinder/connector.py
+0
-1
interactive.py
coco/interactive.py
+194
-34
coco.mo
locale/en/LC_MESSAGES/coco.mo
+0
-0
coco.po
locale/en/LC_MESSAGES/coco.po
+58
-30
coco.mo
locale/zh_CN/LC_MESSAGES/coco.mo
+0
-0
coco.po
locale/zh_CN/LC_MESSAGES/coco.po
+63
-33
requirements.txt
requirements/requirements.txt
+4
-2
No files found.
coco/connection.py
View file @
6f4273c6
...
@@ -183,13 +183,13 @@ class TelnetConnection:
...
@@ -183,13 +183,13 @@ class TelnetConnection:
r'incorrect|failed|失败|错误'
,
re
.
I
r'incorrect|failed|失败|错误'
,
re
.
I
)
)
self
.
username_pattern
=
re
.
compile
(
self
.
username_pattern
=
re
.
compile
(
r'login:
\s*$|username:\s*$|用户名:\s*$|账\s*号:
\s*$'
,
re
.
I
r'login:
?\s*$|username:?\s*$|用户名:?\s*$|账\s*号:?
\s*$'
,
re
.
I
)
)
self
.
password_pattern
=
re
.
compile
(
self
.
password_pattern
=
re
.
compile
(
r'
password:\s*$|passwd:\s*$|密\s*码:
\s*$'
,
re
.
I
r'
Password:?\s*$|passwd:?\s*$|密\s*码:?
\s*$'
,
re
.
I
)
)
self
.
success_pattern
=
re
.
compile
(
self
.
success_pattern
=
re
.
compile
(
r'Last\s*login|success|成功'
,
re
.
I
r'Last\s*login|success|成功
|#|\$
'
,
re
.
I
)
)
def
get_socket
(
self
):
def
get_socket
(
self
):
...
...
coco/httpd/elfinder/connector.py
View file @
6f4273c6
...
@@ -40,7 +40,6 @@ class ElFinderConnector:
...
@@ -40,7 +40,6 @@ class ElFinderConnector:
'uplMaxSize'
:
'10M'
,
'uplMaxSize'
:
'10M'
,
'options'
:
{
'options'
:
{
'separator'
:
'/'
,
'separator'
:
'/'
,
'disabled'
:
[],
'archivers'
:
{
'archivers'
:
{
'create'
:
[],
'create'
:
[],
'extract'
:
[]
'extract'
:
[]
...
...
coco/interactive.py
View file @
6f4273c6
...
@@ -5,6 +5,9 @@
...
@@ -5,6 +5,9 @@
import
socket
import
socket
import
threading
import
threading
import
os
import
os
import
math
import
time
from
treelib
import
Tree
from
.
import
char
from
.
import
char
from
.config
import
config
from
.config
import
config
...
@@ -17,19 +20,35 @@ from .proxy import ProxyServer
...
@@ -17,19 +20,35 @@ from .proxy import ProxyServer
logger
=
get_logger
(
__file__
)
logger
=
get_logger
(
__file__
)
PAGE_DOWN
=
'down'
PAGE_UP
=
'up'
BACK
=
'back'
PROXY
=
'proxy'
class
InteractiveServer
:
class
InteractiveServer
:
_sentinel
=
object
()
_sentinel
=
object
()
def
__init__
(
self
,
client
):
def
__init__
(
self
,
client
):
self
.
client
=
client
self
.
client
=
client
self
.
assets
=
None
self
.
closed
=
False
self
.
closed
=
False
self
.
_search_result
=
None
self
.
_search_result
=
None
self
.
nodes
=
None
self
.
nodes
=
None
self
.
get_user_assets_async
()
self
.
offset
=
0
self
.
limit
=
100
self
.
assets_list
=
[]
self
.
finish
=
False
self
.
page
=
1
self
.
total_assets
=
0
self
.
total_count
=
0
# 分页展示中用来存放数目总条数
self
.
nodes_tree
=
None
# 授权节点树
self
.
get_user_assets_paging_async
()
self
.
get_user_nodes_async
()
self
.
get_user_nodes_async
()
@property
def
page_size
(
self
):
return
self
.
client
.
request
.
meta
[
'height'
]
-
8
@property
@property
def
search_result
(
self
):
def
search_result
(
self
):
if
self
.
_search_result
:
if
self
.
_search_result
:
...
@@ -64,7 +83,7 @@ class InteractiveServer:
...
@@ -64,7 +83,7 @@ class InteractiveServer:
_
(
"{T}2) Enter {green}/{end} + {green}IP, Hostname{end} or {green}Comment {end} search, such as: /ip.{R}"
),
_
(
"{T}2) Enter {green}/{end} + {green}IP, Hostname{end} or {green}Comment {end} search, such as: /ip.{R}"
),
_
(
"{T}3) Enter {green}p{end} to display the host you have permission.{R}"
),
_
(
"{T}3) Enter {green}p{end} to display the host you have permission.{R}"
),
_
(
"{T}4) Enter {green}g{end} to display the node that you have permission.{R}"
),
_
(
"{T}4) Enter {green}g{end} to display the node that you have permission.{R}"
),
_
(
"{T}5) Enter {green}g{end} + {green}
Group
ID{end} to display the host under the node, such as g1.{R}"
),
_
(
"{T}5) Enter {green}g{end} + {green}
Node
ID{end} to display the host under the node, such as g1.{R}"
),
_
(
"{T}6) Enter {green}s{end} Chinese-english switch.{R}"
),
_
(
"{T}6) Enter {green}s{end} Chinese-english switch.{R}"
),
_
(
"{T}7) Enter {green}h{end} help.{R}"
),
_
(
"{T}7) Enter {green}h{end} help.{R}"
),
_
(
"{T}0) Enter {green}q{end} exit.{R}"
)
_
(
"{T}0) Enter {green}q{end} exit.{R}"
)
...
@@ -87,7 +106,7 @@ class InteractiveServer:
...
@@ -87,7 +106,7 @@ class InteractiveServer:
elif
opt
in
[
'p'
,
'P'
,
''
]:
elif
opt
in
[
'p'
,
'P'
,
''
]:
self
.
display_assets
()
self
.
display_assets
()
elif
opt
in
[
'g'
,
'G'
]:
elif
opt
in
[
'g'
,
'G'
]:
self
.
display_nodes
()
self
.
display_nodes
_tree
()
elif
opt
.
startswith
(
"g"
)
and
opt
.
lstrip
(
"g"
)
.
isdigit
():
elif
opt
.
startswith
(
"g"
)
and
opt
.
lstrip
(
"g"
)
.
isdigit
():
self
.
display_node_assets
(
int
(
opt
.
lstrip
(
"g"
)))
self
.
display_node_assets
(
int
(
opt
.
lstrip
(
"g"
)))
elif
opt
in
[
'q'
,
'Q'
,
'exit'
,
'quit'
]:
elif
opt
in
[
'q'
,
'Q'
,
'exit'
,
'quit'
]:
...
@@ -101,38 +120,36 @@ class InteractiveServer:
...
@@ -101,38 +120,36 @@ class InteractiveServer:
self
.
search_and_proxy
(
opt
)
self
.
search_and_proxy
(
opt
)
def
search_assets
(
self
,
q
):
def
search_assets
(
self
,
q
):
if
self
.
assets
is
None
:
if
not
self
.
finish
:
self
.
get_user_assets
()
assets
=
app_service
.
get_search_user_granted_assets
(
self
.
client
.
user
,
q
)
return
assets
assets
=
self
.
assets_list
result
=
[]
result
=
[]
# 所有的
# 所有的
if
q
in
(
''
,
None
):
if
q
in
(
''
,
None
):
result
=
self
.
assets
result
=
assets
# 用户输入的是数字,可能想使用id唯一键搜索
elif
q
.
isdigit
()
and
self
.
search_result
and
\
len
(
self
.
search_result
)
>=
int
(
q
):
result
=
[
self
.
search_result
[
int
(
q
)
-
1
]]
# 全匹配到则直接返回全匹配的
# 全匹配到则直接返回全匹配的
if
len
(
result
)
==
0
:
if
len
(
result
)
==
0
:
_result
=
[
asset
for
asset
in
self
.
assets
_result
=
[
asset
for
asset
in
assets
if
is_obj_attr_eq
(
asset
,
q
)]
if
is_obj_attr_eq
(
asset
,
q
)]
if
len
(
_result
)
==
1
:
if
len
(
_result
)
==
1
:
result
=
_result
result
=
_result
# 最后模糊匹配
# 最后模糊匹配
if
len
(
result
)
==
0
:
if
len
(
result
)
==
0
:
result
=
[
asset
for
asset
in
self
.
assets
result
=
[
asset
for
asset
in
assets
if
is_obj_attr_has
(
asset
,
q
)]
if
is_obj_attr_has
(
asset
,
q
)]
self
.
search_result
=
result
return
result
def
display_assets
(
self
):
def
display_assets
(
self
):
"""
"""
Display user all assets
Display user all assets
:return:
:return:
"""
"""
self
.
search_and_display
(
''
)
self
.
display_result_paging
(
self
.
assets_list
)
def
display_nodes
(
self
):
def
display_nodes
(
self
):
if
self
.
nodes
is
None
:
if
self
.
nodes
is
None
:
...
@@ -154,17 +171,31 @@ class InteractiveServer:
...
@@ -154,17 +171,31 @@ class InteractiveServer:
self
.
client
.
send
(
wr
(
format_with_zh
(
size_list
,
*
data
)))
self
.
client
.
send
(
wr
(
format_with_zh
(
size_list
,
*
data
)))
self
.
client
.
send
(
wr
(
_
(
"Total: {}"
)
.
format
(
len
(
self
.
nodes
)),
before
=
1
))
self
.
client
.
send
(
wr
(
_
(
"Total: {}"
)
.
format
(
len
(
self
.
nodes
)),
before
=
1
))
def
display_nodes_tree
(
self
):
if
self
.
nodes
is
None
:
self
.
get_user_nodes
()
if
not
self
.
nodes
:
self
.
client
.
send
(
wr
(
_
(
'No Nodes'
),
before
=
1
))
return
self
.
nodes_tree
.
show
(
key
=
lambda
node
:
node
.
identifier
)
self
.
client
.
send
(
wr
(
title
(
_
(
"Node: [ ID.Name(Asset amount) ]"
)),
before
=
1
))
self
.
client
.
send
(
wr
(
self
.
nodes_tree
.
_reader
.
replace
(
'
\n
'
,
'
\r\n
'
),
before
=
1
))
prompt
=
_
(
"Tips: Enter g+NodeID to display the host under the node, such as g1"
)
self
.
client
.
send
(
wr
(
title
(
prompt
),
before
=
1
))
def
display_node_assets
(
self
,
_id
):
def
display_node_assets
(
self
,
_id
):
if
self
.
nodes
is
None
:
if
self
.
nodes
is
None
:
self
.
get_user_nodes
()
self
.
get_user_nodes
()
if
_id
>
len
(
self
.
nodes
)
or
_id
<=
0
:
if
_id
>
len
(
self
.
nodes
)
or
_id
<=
0
:
msg
=
wr
(
warning
(
_
(
"There is no matched node, please re-enter"
)))
msg
=
wr
(
warning
(
_
(
"There is no matched node, please re-enter"
)))
self
.
client
.
send
(
msg
)
self
.
client
.
send
(
msg
)
self
.
display_nodes
()
self
.
display_nodes
_tree
()
return
return
self
.
search_result
=
self
.
nodes
[
_id
-
1
]
.
assets_granted
assets
=
self
.
nodes
[
_id
-
1
]
.
assets_granted
self
.
display_
search_result
(
)
self
.
display_
result_paging
(
assets
)
def
display_search_result
(
self
):
def
display_search_result
(
self
):
sort_by
=
config
[
"ASSET_LIST_SORT_BY"
]
sort_by
=
config
[
"ASSET_LIST_SORT_BY"
]
...
@@ -191,16 +222,31 @@ class InteractiveServer:
...
@@ -191,16 +222,31 @@ class InteractiveServer:
asset
.
system_users_name_list
,
asset
.
comment
asset
.
system_users_name_list
,
asset
.
comment
]
]
self
.
client
.
send
(
wr
(
format_with_zh
(
size_list
,
*
data
)))
self
.
client
.
send
(
wr
(
format_with_zh
(
size_list
,
*
data
)))
self
.
client
.
send
(
wr
(
_
(
"Total: {} Match: {}"
)
.
format
(
len
(
self
.
assets
),
len
(
self
.
search_result
)),
before
=
1
)
total_page
=
math
.
ceil
(
self
.
total_count
/
self
.
page_size
)
self
.
client
.
send
(
wr
(
title
(
_
(
"Page: {}, Count: {}, Total Page: {}, Total Count: {}"
)
.
format
(
self
.
page
,
len
(
self
.
search_result
),
total_page
,
self
.
total_count
)),
before
=
1
)
)
)
def
search_and_display
(
self
,
q
):
def
search_and_display
(
self
,
q
):
self
.
search_assets
(
q
)
assets
=
self
.
search_assets
(
q
)
self
.
display_
search_result
(
)
self
.
display_
result_paging
(
assets
)
def
get_user_nodes
(
self
):
def
get_user_nodes
(
self
):
self
.
nodes
=
app_service
.
get_user_asset_groups
(
self
.
client
.
user
)
self
.
nodes
=
app_service
.
get_user_asset_groups
(
self
.
client
.
user
)
self
.
sort_nodes
()
self
.
construct_nodes_tree
()
def
sort_nodes
(
self
):
self
.
nodes
=
sorted
(
self
.
nodes
,
key
=
lambda
node
:
node
.
key
)
def
construct_nodes_tree
(
self
):
self
.
nodes_tree
=
Tree
()
for
index
,
node
in
enumerate
(
self
.
nodes
):
tag
=
"{}.{}({})"
.
format
(
index
+
1
,
node
.
name
,
node
.
assets_amount
)
key
=
node
.
key
parent_key
=
key
[:
node
.
key
.
rfind
(
':'
)]
or
None
self
.
nodes_tree
.
create_node
(
tag
=
tag
,
identifier
=
key
,
data
=
node
,
parent
=
parent_key
)
def
get_user_nodes_async
(
self
):
def
get_user_nodes_async
(
self
):
thread
=
threading
.
Thread
(
target
=
self
.
get_user_nodes
)
thread
=
threading
.
Thread
(
target
=
self
.
get_user_nodes
)
...
@@ -217,14 +263,24 @@ class InteractiveServer:
...
@@ -217,14 +263,24 @@ class InteractiveServer:
asset
.
system_users_granted
=
system_users_cleaned
asset
.
system_users_granted
=
system_users_cleaned
return
assets
return
assets
def
get_user_assets
(
self
):
def
get_user_assets_paging
(
self
):
self
.
assets
=
app_service
.
get_user_assets
(
self
.
client
.
user
)
while
not
self
.
closed
:
logger
.
debug
(
"Get user {} assets total: {}"
.
format
(
assets
,
total
=
app_service
.
get_user_assets_paging
(
self
.
client
.
user
,
len
(
self
.
assets
))
self
.
client
.
user
,
offset
=
self
.
offset
,
limit
=
self
.
limit
)
)
logger
.
info
(
'Get user assets paging async: {}'
.
format
(
len
(
assets
)))
def
get_user_assets_async
(
self
):
if
not
assets
:
thread
=
threading
.
Thread
(
target
=
self
.
get_user_assets
)
logger
.
info
(
'Get user assets paging async finished.'
)
self
.
finish
=
True
return
if
not
self
.
total_assets
:
self
.
total_assets
=
total
self
.
total_count
=
total
self
.
assets_list
.
extend
(
assets
)
self
.
offset
+=
self
.
limit
def
get_user_assets_paging_async
(
self
):
thread
=
threading
.
Thread
(
target
=
self
.
get_user_assets_paging
)
thread
.
start
()
thread
.
start
()
def
choose_system_user
(
self
,
system_users
):
def
choose_system_user
(
self
,
system_users
):
...
@@ -251,9 +307,9 @@ class InteractiveServer:
...
@@ -251,9 +307,9 @@ class InteractiveServer:
self
.
client
.
send
(
wr
(
"{} {}"
.
format
(
index
,
system_user
.
name
)))
self
.
client
.
send
(
wr
(
"{} {}"
.
format
(
index
,
system_user
.
name
)))
def
search_and_proxy
(
self
,
opt
):
def
search_and_proxy
(
self
,
opt
):
self
.
search_assets
(
opt
)
assets
=
self
.
search_assets
(
opt
)
if
self
.
search_result
and
len
(
self
.
search_result
)
==
1
:
if
assets
and
len
(
assets
)
==
1
:
asset
=
self
.
search_result
[
0
]
asset
=
assets
[
0
]
self
.
search_result
=
None
self
.
search_result
=
None
if
asset
.
platform
==
"Windows"
:
if
asset
.
platform
==
"Windows"
:
self
.
client
.
send
(
warning
(
self
.
client
.
send
(
warning
(
...
@@ -263,7 +319,111 @@ class InteractiveServer:
...
@@ -263,7 +319,111 @@ class InteractiveServer:
return
return
self
.
proxy
(
asset
)
self
.
proxy
(
asset
)
else
:
else
:
self
.
display_search_result
()
self
.
display_result_paging
(
assets
)
def
display_result_paging
(
self
,
result_list
):
if
result_list
is
self
.
assets_list
:
self
.
total_count
=
self
.
total_assets
else
:
if
len
(
result_list
)
==
0
:
return
self
.
total_count
=
len
(
result_list
)
action
=
PAGE_DOWN
gen_result
=
self
.
get_result_page_down_or_up
(
result_list
)
while
True
:
try
:
page
,
result
=
gen_result
.
send
(
action
)
except
TypeError
:
try
:
page
,
result
=
next
(
gen_result
)
except
StopIteration
:
logger
.
info
(
'No Assets'
)
self
.
display_banner
()
self
.
client
.
send
(
wr
(
_
(
"No Assets"
),
before
=
1
))
return
None
except
StopIteration
:
logger
.
info
(
'Back display result paging.'
)
self
.
display_banner
()
return
None
self
.
display_result_of_page
(
page
,
result
)
action
=
self
.
get_user_action
()
def
get_result_page_down_or_up
(
self
,
result_list
):
left
=
0
page
=
1
page_up_size
=
0
# 记录上一页大小
while
True
:
right
=
left
+
self
.
page_size
result
=
result_list
[
left
:
right
]
if
not
result
and
(
result_list
is
self
.
assets_list
)
and
self
.
finish
and
self
.
total_assets
==
0
:
# 无授权资产
return
None
,
None
elif
not
result
and
(
result_list
is
self
.
assets_list
)
and
self
.
finish
:
# 上一页是最后一页
left
-=
page_up_size
page
-=
1
continue
elif
not
result
and
(
result_list
is
self
.
assets_list
)
and
not
self
.
finish
:
# 还有下一页(暂时没有加载完),需要等待
time
.
sleep
(
1
)
continue
elif
not
result
and
(
result_list
is
not
self
.
assets_list
):
# 上一页是最后一页
left
-=
page_up_size
page
-=
1
continue
else
:
# 其他4中情况,返回assets
action
=
yield
(
page
,
result
)
if
action
==
BACK
:
return
None
,
None
elif
action
==
PAGE_UP
:
if
page
<=
1
:
# 已经是第一页了
page
=
1
left
=
0
else
:
page
-=
1
left
-=
self
.
page_size
else
:
# PAGE_DOWN
page
+=
1
left
+=
len
(
result
)
page_up_size
=
len
(
result
)
def
display_result_of_page
(
self
,
page
,
result
):
self
.
client
.
send
(
char
.
CLEAR_CHAR
)
self
.
page
=
page
self
.
search_result
=
result
self
.
display_search_result
()
self
.
display_prompt_of_page
()
def
display_prompt_of_page
(
self
):
self
.
client
.
send
(
wr
(
_
(
'Tips: Enter the asset ID and log directly into the asset.'
),
before
=
1
))
prompt_page_up
=
_
(
"Page up: P/p"
)
prompt_page_down
=
_
(
"Page down: Enter|N/n"
)
prompt_back
=
_
(
"BACK: b/q"
)
prompts
=
[
prompt_page_up
,
prompt_page_down
,
prompt_back
]
prompt
=
'
\t
'
.
join
(
prompts
)
self
.
client
.
send
(
wr
(
prompt
,
before
=
1
))
def
get_user_action
(
self
):
opt
=
net_input
(
self
.
client
,
prompt
=
':'
)
if
opt
in
(
'p'
,
'P'
):
return
PAGE_UP
elif
opt
in
(
'b'
,
'q'
):
return
BACK
elif
opt
.
isdigit
()
and
self
.
search_result
and
0
<
int
(
opt
)
<=
len
(
self
.
search_result
):
self
.
proxy
(
self
.
search_result
[
int
(
opt
)
-
1
])
return
BACK
else
:
# PAGE_DOWN
return
PAGE_DOWN
def
proxy
(
self
,
asset
):
def
proxy
(
self
,
asset
):
system_user
=
self
.
choose_system_user
(
asset
.
system_users_granted
)
system_user
=
self
.
choose_system_user
(
asset
.
system_users_granted
)
...
...
locale/en/LC_MESSAGES/coco.mo
View file @
6f4273c6
No preview for this file type
locale/en/LC_MESSAGES/coco.po
View file @
6f4273c6
...
@@ -7,7 +7,7 @@ msgid ""
...
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-10-
10 15:22
+0800\n"
"POT-Creation-Date: 2018-10-
31 11:49
+0800\n"
"PO-Revision-Date: 2018-08-10 10:42+0800\n"
"PO-Revision-Date: 2018-08-10 10:42+0800\n"
"Last-Translator: BaiJiangjie <bugatti_it@163.com>\n"
"Last-Translator: BaiJiangjie <bugatti_it@163.com>\n"
"Language-Team: Language locale/en/LC\n"
"Language-Team: Language locale/en/LC\n"
...
@@ -16,11 +16,11 @@ msgstr ""
...
@@ -16,11 +16,11 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Content-Transfer-Encoding: 8bit\n"
#: coco/app.py:1
41
#: coco/app.py:1
35
msgid "Connect idle more than {} minutes, disconnect"
msgid "Connect idle more than {} minutes, disconnect"
msgstr ""
msgstr ""
#: coco/interactive.py:
61
#: coco/interactive.py:
80
#, python-brace-format
#, python-brace-format
msgid ""
msgid ""
"\n"
"\n"
...
@@ -28,115 +28,143 @@ msgid ""
...
@@ -28,115 +28,143 @@ msgid ""
"{end}{R}{R}"
"{end}{R}{R}"
msgstr ""
msgstr ""
#: coco/interactive.py:
63
#: coco/interactive.py:
82
#, python-brace-format
#, python-brace-format
msgid ""
msgid ""
"{T}1) Enter {green}ID{end} directly login or enter {green}part IP, Hostname, "
"{T}1) Enter {green}ID{end} directly login or enter {green}part IP, Hostname, "
"Comment{end} to search login(if unique).{R}"
"Comment{end} to search login(if unique).{R}"
msgstr ""
msgstr ""
#: coco/interactive.py:
64
#: coco/interactive.py:
83
#, python-brace-format
#, python-brace-format
msgid ""
msgid ""
"{T}2) Enter {green}/{end} + {green}IP, Hostname{end} or {green}Comment {end} "
"{T}2) Enter {green}/{end} + {green}IP, Hostname{end} or {green}Comment {end} "
"search, such as: /ip.{R}"
"search, such as: /ip.{R}"
msgstr ""
msgstr ""
#: coco/interactive.py:
65
#: coco/interactive.py:
84
#, python-brace-format
#, python-brace-format
msgid "{T}3) Enter {green}p{end} to display the host you have permission.{R}"
msgid "{T}3) Enter {green}p{end} to display the host you have permission.{R}"
msgstr ""
msgstr ""
#: coco/interactive.py:
66
#: coco/interactive.py:
85
#, python-brace-format
#, python-brace-format
msgid ""
msgid ""
"{T}4) Enter {green}g{end} to display the node that you have permission.{R}"
"{T}4) Enter {green}g{end} to display the node that you have permission.{R}"
msgstr ""
msgstr ""
#: coco/interactive.py:
67
#: coco/interactive.py:
86
#, python-brace-format
#, python-brace-format
msgid ""
msgid ""
"{T}5) Enter {green}g{end} + {green}
Group ID{end} to display the host under
"
"{T}5) Enter {green}g{end} + {green}
NodeID{end} to display the host under the
"
"
the
node, such as g1.{R}"
"node, such as g1.{R}"
msgstr ""
msgstr ""
#: coco/interactive.py:
68
#: coco/interactive.py:
87
#, python-brace-format
#, python-brace-format
msgid "{T}6) Enter {green}s{end} Chinese-english switch.{R}"
msgid "{T}6) Enter {green}s{end} Chinese-english switch.{R}"
msgstr ""
msgstr ""
#: coco/interactive.py:
69
#: coco/interactive.py:
88
#, python-brace-format
#, python-brace-format
msgid "{T}7) Enter {green}h{end} help.{R}"
msgid "{T}7) Enter {green}h{end} help.{R}"
msgstr ""
msgstr ""
#: coco/interactive.py:
70
#: coco/interactive.py:
89
#, python-brace-format
#, python-brace-format
msgid "{T}0) Enter {green}q{end} exit.{R}"
msgid "{T}0) Enter {green}q{end} exit.{R}"
msgstr ""
msgstr ""
#: coco/interactive.py:1
42
#: coco/interactive.py:1
59
msgid "No"
msgid "No"
msgstr ""
msgstr ""
#: coco/interactive.py:1
49
#: coco/interactive.py:1
66
msgid "Name"
msgid "Name"
msgstr ""
msgstr ""
#: coco/interactive.py:1
49
#: coco/interactive.py:1
66
msgid "Assets"
msgid "Assets"
msgstr ""
msgstr ""
#: coco/interactive.py:1
55
#: coco/interactive.py:1
72
msgid "Total: {}"
msgid "Total: {}"
msgstr ""
msgstr ""
#: coco/interactive.py:161
#: coco/interactive.py:177
msgid "Node [ ID.Name(Asset) ]"
msgstr ""
#: coco/interactive.py:179
msgid "Enter g+NodeID to display the host under the node, such as g1."
msgstr ""
#: coco/interactive.py:186
msgid "There is no matched node, please re-enter"
msgid "There is no matched node, please re-enter"
msgstr ""
msgstr ""
#: coco/interactive.py:1
72
#: coco/interactive.py:1
97
msgid "ID"
msgid "ID"
msgstr ""
msgstr ""
#: coco/interactive.py:1
72
#: coco/interactive.py:1
97
msgid "Hostname"
msgid "Hostname"
msgstr ""
msgstr ""
#: coco/interactive.py:1
72
#: coco/interactive.py:1
97
msgid "IP"
msgid "IP"
msgstr ""
msgstr ""
#: coco/interactive.py:1
72
#: coco/interactive.py:1
97
msgid "LoginAs"
msgid "LoginAs"
msgstr ""
msgstr ""
#: coco/interactive.py:
186
#: coco/interactive.py:
211
msgid "Comment"
msgid "Comment"
msgstr ""
msgstr ""
#: coco/interactive.py:
194
#: coco/interactive.py:
221
msgid "
Total: {} Match
: {}"
msgid "
Page: {}, Count: {}, Total Page: {}, Total Count
: {}"
msgstr ""
msgstr ""
#: coco/interactive.py:2
37
#: coco/interactive.py:2
96
msgid "Select a login:: "
msgid "Select a login:: "
msgstr ""
msgstr ""
#: coco/interactive.py:
260
#: coco/interactive.py:
319
msgid ""
msgid ""
"Terminal does not support login Windows, please use web terminal to access"
"Terminal does not support login Windows, please use web terminal to access"
msgstr ""
msgstr ""
#: coco/interactive.py:271
#: coco/interactive.py:401
msgid "Tips: Enter the asset ID and log directly into the asset."
msgstr ""
#: coco/interactive.py:402
msgid "Page up: P/p"
msgstr ""
#: coco/interactive.py:403
msgid "Page down: Enter|N/n"
msgstr ""
#: coco/interactive.py:404
msgid "BACK: B/b"
msgstr ""
#: coco/interactive.py:425
msgid "No system user"
msgid "No system user"
msgstr ""
msgstr ""
#: coco/proxy.py:88
#: coco/models.py:247
msgid "Command `{}` is forbidden ........"
msgstr ""
#: coco/proxy.py:89
msgid "No permission"
msgid "No permission"
msgstr ""
msgstr ""
#: coco/proxy.py:13
0
#: coco/proxy.py:13
1
msgid "Connecting to {}@{} {:.1f}"
msgid "Connecting to {}@{} {:.1f}"
msgstr ""
msgstr ""
...
...
locale/zh_CN/LC_MESSAGES/coco.mo
View file @
6f4273c6
No preview for this file type
locale/zh_CN/LC_MESSAGES/coco.po
View file @
6f4273c6
...
@@ -7,7 +7,7 @@ msgid ""
...
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-10-
10 15:22
+0800\n"
"POT-Creation-Date: 2018-10-
31 11:49
+0800\n"
"PO-Revision-Date: 2018-08-10 10:42+0800\n"
"PO-Revision-Date: 2018-08-10 10:42+0800\n"
"Last-Translator: BaiJiangjie <bugatti_it@163.com>\n"
"Last-Translator: BaiJiangjie <bugatti_it@163.com>\n"
"Language-Team: Language locale/zh\n"
"Language-Team: Language locale/zh\n"
...
@@ -16,11 +16,11 @@ msgstr ""
...
@@ -16,11 +16,11 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Content-Transfer-Encoding: 8bit\n"
#: coco/app.py:1
41
#: coco/app.py:1
35
msgid "Connect idle more than {} minutes, disconnect"
msgid "Connect idle more than {} minutes, disconnect"
msgstr "空闲时间超过 {} 分钟,断开连接"
msgstr "空闲时间超过 {} 分钟,断开连接"
#: coco/interactive.py:
61
#: coco/interactive.py:
80
#, python-brace-format
#, python-brace-format
msgid ""
msgid ""
"\n"
"\n"
...
@@ -30,7 +30,7 @@ msgstr ""
...
@@ -30,7 +30,7 @@ msgstr ""
"\n"
"\n"
"{T}{T}{title} {user}, 欢迎使用Jumpserver开源跳板机系统 {end}{R}{R}"
"{T}{T}{title} {user}, 欢迎使用Jumpserver开源跳板机系统 {end}{R}{R}"
#: coco/interactive.py:
63
#: coco/interactive.py:
82
#, python-brace-format
#, python-brace-format
msgid ""
msgid ""
"{T}1) Enter {green}ID{end} directly login or enter {green}part IP, Hostname, "
"{T}1) Enter {green}ID{end} directly login or enter {green}part IP, Hostname, "
...
@@ -39,7 +39,7 @@ msgstr ""
...
@@ -39,7 +39,7 @@ msgstr ""
"{T}1) 输入 {green}ID{end} 直接登录 或 输入{green}部分 IP,主机名,备注{end} 进"
"{T}1) 输入 {green}ID{end} 直接登录 或 输入{green}部分 IP,主机名,备注{end} 进"
"行搜索登录(如果唯一).{R}"
"行搜索登录(如果唯一).{R}"
#: coco/interactive.py:
64
#: coco/interactive.py:
83
#, python-brace-format
#, python-brace-format
msgid ""
msgid ""
"{T}2) Enter {green}/{end} + {green}IP, Hostname{end} or {green}Comment {end} "
"{T}2) Enter {green}/{end} + {green}IP, Hostname{end} or {green}Comment {end} "
...
@@ -48,104 +48,134 @@ msgstr ""
...
@@ -48,104 +48,134 @@ msgstr ""
"{T}2) 输入 {green}/{end} + {green}IP, 主机名{end} or {green}备注 {end}搜索. "
"{T}2) 输入 {green}/{end} + {green}IP, 主机名{end} or {green}备注 {end}搜索. "
"如: /ip{R}"
"如: /ip{R}"
#: coco/interactive.py:
65
#: coco/interactive.py:
84
#, python-brace-format
#, python-brace-format
msgid "{T}3) Enter {green}p{end} to display the host you have permission.{R}"
msgid "{T}3) Enter {green}p{end} to display the host you have permission.{R}"
msgstr "{T}3) 输入 {green}p{end} 显示您有权限的主机.{R}"
msgstr "{T}3) 输入 {green}p{end} 显示您有权限的主机.{R}"
#: coco/interactive.py:
66
#: coco/interactive.py:
85
#, python-brace-format
#, python-brace-format
msgid ""
msgid ""
"{T}4) Enter {green}g{end} to display the node that you have permission.{R}"
"{T}4) Enter {green}g{end} to display the node that you have permission.{R}"
msgstr "{T}4) 输入 {green}g{end} 显示您有权限的节点.{R}"
msgstr "{T}4) 输入 {green}g{end} 显示您有权限的节点.{R}"
#: coco/interactive.py:67
#: coco/interactive.py:86
#, python-brace-format
msgid ""
msgid ""
"{T}5) Enter {green}g{end} + {green}
Group ID{end} to display the host under
"
"{T}5) Enter {green}g{end} + {green}
NodeID{end} to display the host under the
"
"
the
node, such as g1.{R}"
"node, such as g1.{R}"
msgstr "{T}5) 输入 {green}g{end} + {green}
组
ID{end} 显示节点下主机. 如: g1{R}"
msgstr "{T}5) 输入 {green}g{end} + {green}
节点
ID{end} 显示节点下主机. 如: g1{R}"
#: coco/interactive.py:
68
#: coco/interactive.py:
87
#, python-brace-format
#, python-brace-format
msgid "{T}6) Enter {green}s{end} Chinese-english switch.{R}"
msgid "{T}6) Enter {green}s{end} Chinese-english switch.{R}"
msgstr "{T}6) 输入 {green}s{end} 中/英文切换.{R}"
msgstr "{T}6) 输入 {green}s{end} 中/英文切换.{R}"
#: coco/interactive.py:
69
#: coco/interactive.py:
88
#, python-brace-format
#, python-brace-format
msgid "{T}7) Enter {green}h{end} help.{R}"
msgid "{T}7) Enter {green}h{end} help.{R}"
msgstr "{T}7) 输入 {green}h{end} 帮助.{R}"
msgstr "{T}7) 输入 {green}h{end} 帮助.{R}"
#: coco/interactive.py:
70
#: coco/interactive.py:
89
#, python-brace-format
#, python-brace-format
msgid "{T}0) Enter {green}q{end} exit.{R}"
msgid "{T}0) Enter {green}q{end} exit.{R}"
msgstr "{T}0) 输入 {green}q{end} 退出.{R}"
msgstr "{T}0) 输入 {green}q{end} 退出.{R}"
#: coco/interactive.py:1
42
#: coco/interactive.py:1
59
msgid "No"
msgid "No"
msgstr "无"
msgstr "无"
#: coco/interactive.py:1
49
#: coco/interactive.py:1
66
msgid "Name"
msgid "Name"
msgstr "名称"
msgstr "名称"
#: coco/interactive.py:1
49
#: coco/interactive.py:1
66
msgid "Assets"
msgid "Assets"
msgstr "资产"
msgstr "资产"
#: coco/interactive.py:1
55
#: coco/interactive.py:1
72
msgid "Total: {}"
msgid "Total: {}"
msgstr "总共: {}"
msgstr "总共: {}"
#: coco/interactive.py:161
#: coco/interactive.py:177
msgid "Node: [ ID.Name(Asset amount) ]"
msgstr "节点: [ ID.名称(资产数量) ]"
#: coco/interactive.py:179
msgid "Tips: Enter g+NodeID to display the host under the node, such as g1"
msgstr "提示: 输入 g+节点ID 显示节点下主机. 如: g1"
#: coco/interactive.py:186
msgid "There is no matched node, please re-enter"
msgid "There is no matched node, please re-enter"
msgstr "没有匹配分组,请重新输入"
msgstr "没有匹配分组,请重新输入"
#: coco/interactive.py:1
72
#: coco/interactive.py:1
97
msgid "ID"
msgid "ID"
msgstr ""
msgstr ""
#: coco/interactive.py:1
72
#: coco/interactive.py:1
97
msgid "Hostname"
msgid "Hostname"
msgstr "主机名"
msgstr "主机名"
#: coco/interactive.py:1
72
#: coco/interactive.py:1
97
msgid "IP"
msgid "IP"
msgstr ""
msgstr ""
#: coco/interactive.py:1
72
#: coco/interactive.py:1
97
msgid "LoginAs"
msgid "LoginAs"
msgstr "登录用户"
msgstr "登录用户"
#: coco/interactive.py:
186
#: coco/interactive.py:
211
msgid "Comment"
msgid "Comment"
msgstr "备注"
msgstr "备注"
#: coco/interactive.py:
194
#: coco/interactive.py:
221
msgid "
Total: {} Match
: {}"
msgid "
Page: {}, Count: {}, Total Page: {}, Total Count
: {}"
msgstr "
总共: {} 匹配
: {}"
msgstr "
页码: {}, 数量: {}, 总页数: {}, 总数量
: {}"
#: coco/interactive.py:2
37
#: coco/interactive.py:2
96
msgid "Select a login:: "
msgid "Select a login:: "
msgstr "选择一个登录:"
msgstr "选择一个登录:"
#: coco/interactive.py:
260
#: coco/interactive.py:
319
msgid ""
msgid ""
"Terminal does not support login Windows, please use web terminal to access"
"Terminal does not support login Windows, please use web terminal to access"
msgstr "终端不支持登录windows, 请使用web terminal访问"
msgstr "终端不支持登录windows, 请使用web terminal访问"
#: coco/interactive.py:271
#: coco/interactive.py:401
msgid "Tips: Enter the asset ID and log directly into the asset."
msgstr "提示: 输入资产ID,直接登录资产."
#: coco/interactive.py:402
msgid "Page up: P/p"
msgstr "上一页: P/p"
#: coco/interactive.py:403
msgid "Page down: Enter|N/n"
msgstr "下一页: Enter|N/n"
#: coco/interactive.py:404
msgid "BACK: B/b"
msgstr "返回: B/b"
#: coco/interactive.py:425
msgid "No system user"
msgid "No system user"
msgstr "没有系统用户"
msgstr "没有系统用户"
#: coco/proxy.py:88
#: coco/models.py:247
msgid "Command `{}` is forbidden ........"
msgstr ""
#: coco/proxy.py:89
msgid "No permission"
msgid "No permission"
msgstr "没有权限"
msgstr "没有权限"
#: coco/proxy.py:13
0
#: coco/proxy.py:13
1
msgid "Connecting to {}@{} {:.1f}"
msgid "Connecting to {}@{} {:.1f}"
msgstr "开始连接到 {}@{} {:.1f}"
msgstr "开始连接到 {}@{} {:.1f}"
#: coco/session.py:143
#: coco/session.py:143
msgid "Terminated by administrator"
msgid "Terminated by administrator"
msgstr "被管理员中断"
msgstr "被管理员中断"
#~ msgid "Total: {} Match: {}"
#~ msgstr "总共: {} 匹配: {}"
requirements/requirements.txt
View file @
6f4273c6
...
@@ -18,8 +18,8 @@ idna==2.6
...
@@ -18,8 +18,8 @@ idna==2.6
itsdangerous==0.24
itsdangerous==0.24
Jinja2==2.10
Jinja2==2.10
jmespath==0.9.3
jmespath==0.9.3
jms-storage==0.0.
19
jms-storage==0.0.
20
jumpserver-python-sdk==0.0.5
0
jumpserver-python-sdk==0.0.5
1
MarkupSafe==1.0
MarkupSafe==1.0
oss2==2.4.0
oss2==2.4.0
paramiko==2.4.1
paramiko==2.4.1
...
@@ -42,3 +42,5 @@ urllib3==1.22
...
@@ -42,3 +42,5 @@ urllib3==1.22
wcwidth==0.1.7
wcwidth==0.1.7
eventlet==0.24.1
eventlet==0.24.1
Werkzeug==0.14.1
Werkzeug==0.14.1
treelib==1.5.3
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