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
1ecdcc2a
Unverified
Commit
1ecdcc2a
authored
Oct 12, 2018
by
老广
Committed by
GitHub
Oct 12, 2018
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #106 from jumpserver/dev
支持命令过滤
parents
021a70ac
d7ba5b58
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
155 additions
and
370 deletions
+155
-370
app.py
coco/app.py
+1
-6
char.py
coco/char.py
+1
-0
auth.py
coco/httpd/auth.py
+3
-2
view.py
coco/httpd/view.py
+2
-0
models.py
coco/models.py
+101
-41
session.py
coco/session.py
+4
-0
sshd.py
coco/sshd.py
+1
-1
cocod
cocod
+8
-6
coco.mo
locale/en/LC_MESSAGES/coco.mo
+0
-0
coco.po
locale/en/LC_MESSAGES/coco.po
+12
-12
coco.po~
locale/en/LC_MESSAGES/coco.po~
+0
-137
coco.mo
locale/zh_CN/LC_MESSAGES/coco.mo
+0
-0
coco.po
locale/zh_CN/LC_MESSAGES/coco.po
+15
-15
coco.po~
locale/zh_CN/LC_MESSAGES/coco.po~
+0
-143
requirements.txt
requirements/requirements.txt
+1
-1
messages.sh
utils/messages.sh
+6
-6
No files found.
coco/app.py
View file @
1ecdcc2a
...
...
@@ -2,11 +2,6 @@
# -*- coding: utf-8 -*-
#
import
eventlet
from
eventlet.debug
import
hub_prevent_multiple_readers
eventlet
.
monkey_patch
()
hub_prevent_multiple_readers
(
False
)
import
datetime
import
os
import
time
...
...
@@ -26,7 +21,7 @@ from .session import Session
from
.models
import
Connection
__version__
=
'1.4.
2
'
__version__
=
'1.4.
3
'
BASE_DIR
=
os
.
path
.
dirname
(
os
.
path
.
dirname
(
__file__
))
logger
=
get_logger
(
__file__
)
...
...
coco/char.py
View file @
1ecdcc2a
...
...
@@ -5,6 +5,7 @@
BACKSPACE_CHAR
=
{
b
'
\x08
'
:
b
'
\x08\x1b
[K'
,
b
'
\x7f
'
:
b
'
\x08\x1b
[K'
}
ENTER_CHAR
=
[
b
'
\r
'
,
b
'
\n
'
,
b
'
\r\n
'
]
ENTER_CHAR_ORDER
=
[
ord
(
b
'
\r
'
),
ord
(
b
'
\n
'
)]
CLEAR_LINE_CHAR
=
b
'
\x15
'
UNSUPPORTED_CHAR
=
{
b
'
\x15
'
:
'Ctrl-U'
,
b
'
\x0c
'
:
'Ctrl-L'
,
b
'
\x05
'
:
'Ctrl-E'
}
CLEAR_CHAR
=
b
'
\x1b
[H
\x1b
[2J'
BELL_CHAR
=
b
'
\x07
'
...
...
coco/httpd/auth.py
View file @
1ecdcc2a
...
...
@@ -2,7 +2,7 @@
#
from
functools
import
wraps
from
flask
import
request
,
abort
from
flask
import
request
,
abort
,
redirect
from
..ctx
import
app_service
...
...
@@ -23,7 +23,8 @@ def login_required(func):
user
=
app_service
.
check_user_cookie
(
session_id
,
csrf_token
)
request
.
current_user
=
user
if
not
hasattr
(
request
,
'current_user'
)
or
not
request
.
current_user
:
return
abort
(
403
)
url
=
'/users/login/?next={}'
.
format
(
request
.
path
)
return
redirect
(
url
)
response
=
func
(
*
args
,
**
kwargs
)
return
response
return
wrapper
coco/httpd/view.py
View file @
1ecdcc2a
...
...
@@ -50,11 +50,13 @@ def sftp_host_connector_view(host):
@app.route
(
'/coco/elfinder/sftp/<host>/'
)
@login_required
def
sftp_host_finder
(
host
):
return
render_template
(
'elfinder/file_manager.html'
,
host
=
host
)
@app.route
(
'/coco/elfinder/sftp/'
)
@login_required
def
sftp_finder
():
return
render_template
(
'elfinder/file_manager.html'
,
host
=
'_'
)
...
...
coco/models.py
View file @
1ecdcc2a
...
...
@@ -4,7 +4,10 @@ import weakref
import
uuid
import
socket
from
.service
import
app_service
from
.struct
import
SizedList
,
SelectEvent
from
.utils
import
wrap_with_line_feed
as
wr
,
wrap_with_warning
as
warning
,
\
ugettext
as
_
from
.
import
char
from
.
import
utils
...
...
@@ -140,6 +143,11 @@ class Client:
return
"<
%
s from
%
s:
%
s>"
%
(
self
.
user
,
self
.
addr
[
0
],
self
.
addr
[
1
])
class
ServerFilter
:
def
run
(
self
,
data
):
pass
class
BaseServer
:
"""
Base Server
...
...
@@ -147,18 +155,23 @@ class BaseServer:
sub-class: Server, Telnet Server
"""
def
__init__
(
self
):
self
.
chan
=
None
def
__init__
(
self
,
chan
=
None
):
self
.
chan
=
chan
self
.
_session_ref
=
None
self
.
input_data
=
SizedList
(
maxsize
=
1024
)
self
.
output_data
=
SizedList
(
maxsize
=
1024
)
self
.
_pre_input_state
=
True
self
.
_in_input_state
=
True
self
.
_input_initial
=
False
self
.
_enter_vim_mark
=
b
'
\x1b
[?25l
\x1b
[37;1H
\x1b
[1m'
self
.
_exit_vim_mark
=
b
'
\x1b
[37;1H
\x1b
[K
\x1b
'
self
.
_in_vim_state
=
False
self
.
input_data
=
SizedList
(
maxsize
=
1024
)
self
.
output_data
=
SizedList
(
maxsize
=
1024
)
self
.
_input
=
""
self
.
_output
=
""
self
.
_session_ref
=
None
self
.
_zmodem_recv_start_mark
=
b
'rz waiting to receive.**
\x18
B0100'
self
.
_zmodem_send_start_mark
=
b
'**
\x18
B00000000000000'
self
.
_zmodem_cancel_mark
=
b
'
\x18\x18\x18\x18\x18
'
...
...
@@ -167,6 +180,15 @@ class BaseServer:
self
.
_zmodem_state_recv
=
'recv'
self
.
_zmodem_state
=
''
self
.
_cmd_parser
=
utils
.
TtyIOParser
()
self
.
_cmd_filter_rules
=
self
.
get_system_user_cmd_filter_rules
()
def
get_system_user_cmd_filter_rules
(
self
):
rules
=
app_service
.
get_system_user_cmd_filter_rules
(
self
.
system_user
.
id
)
return
rules
def
set_session
(
self
,
session
):
self
.
_session_ref
=
weakref
.
ref
(
session
)
...
...
@@ -177,51 +199,82 @@ class BaseServer:
else
:
return
None
def
initial_filter
(
self
):
def
s_initial_filter
(
self
,
data
):
if
not
self
.
_input_initial
:
self
.
_input_initial
=
True
return
data
def
parse_cmd
_filter
(
self
,
data
):
# 输入了回车键, 开始计算输入的内容
if
self
.
_
have_enter_char
(
data
)
:
def
s_input_state
_filter
(
self
,
data
):
self
.
_pre_input_state
=
self
.
_in_input_state
if
self
.
_
in_vim_state
:
self
.
_in_input_state
=
False
self
.
_input
=
self
.
_parse_input
()
return
data
# 用户输入了内容,但是如果没在输入状态,也就是用户刚开始输入了,结算上次输出内容
# 输入了回车键
elif
self
.
_have_enter_char
(
data
):
self
.
_in_input_state
=
False
else
:
self
.
_in_input_state
=
True
return
data
def
s_parse_input_output_filter
(
self
,
data
):
# 输入了回车键, 计算输入的命令
if
not
self
.
_in_input_state
:
self
.
_input
=
self
.
_parse_input
()
# 用户输入了内容,但是上次没在输入状态,也就是用户刚开始输入了,结算上次输出内容
if
not
self
.
_pre_input_state
and
self
.
_in_input_state
:
self
.
_output
=
self
.
_parse_output
()
logger
.
debug
(
"
\n
{}
\n
Input: {}
\n
Output: {}
\n
{}"
.
format
(
"#"
*
30
+
" Command "
+
"#"
*
30
,
self
.
_input
,
self
.
_output
,
"#"
*
30
+
" End "
+
"#"
*
30
,
))
#
logger.debug("\n{}\nInput: {}\nOutput: {}\n{}".format(
#
"#" * 30 + " Command " + "#" * 30,
#
self._input, self._output,
#
"#" * 30 + " End " + "#" * 30,
#
))
if
self
.
_input
:
self
.
session
.
put_command
(
self
.
_input
,
self
.
_output
)
self
.
input_data
.
clean
()
self
.
output_data
.
clean
()
self
.
_in_input_state
=
True
return
data
def
send
(
self
,
data
):
self
.
initial_filter
()
self
.
parse_cmd_filter
(
data
)
return
self
.
chan
.
send
(
data
)
def
s_filter_cmd_filter
(
self
,
data
):
if
self
.
_in_input_state
:
return
data
for
rule
in
self
.
_cmd_filter_rules
:
action
,
cmd
=
rule
.
match
(
self
.
_input
)
if
action
==
rule
.
ALLOW
:
break
elif
action
==
rule
.
DENY
:
data
=
char
.
CLEAR_LINE_CHAR
+
b
'
\r\n
'
msg
=
_
(
"Command `{}` is forbidden ........"
)
.
format
(
cmd
)
msg
=
wr
(
warning
(
msg
.
encode
()),
before
=
1
,
after
=
1
)
self
.
output_data
.
append
(
msg
)
self
.
session
.
send_to_clients
(
msg
)
self
.
session
.
put_replay
(
msg
)
break
return
data
def
replay_filter
(
self
,
data
):
def
r
_r
eplay_filter
(
self
,
data
):
if
not
self
.
_zmodem_state
:
self
.
session
.
put_replay
(
data
)
def
input_output_filter
(
self
,
data
):
def
r_vim_state_filter
(
self
,
data
):
if
self
.
_zmodem_state
:
return
data
if
self
.
_in_vim_state
and
data
[:
11
]
==
self
.
_exit_vim_mark
:
self
.
_in_vim_state
=
False
elif
not
self
.
_in_vim_state
and
data
[:
17
]
==
self
.
_enter_vim_mark
:
self
.
_in_vim_state
=
True
return
data
def
r_input_output_data_filter
(
self
,
data
):
if
not
self
.
_input_initial
:
return
return
data
if
self
.
_zmodem_state
:
return
return
data
if
self
.
_in_input_state
:
self
.
input_data
.
append
(
data
)
else
:
self
.
output_data
.
append
(
data
)
return
data
def
zmodem_state_filter
(
self
,
data
):
def
r_
zmodem_state_filter
(
self
,
data
):
if
not
self
.
_zmodem_state
:
if
data
[:
50
]
.
find
(
self
.
_zmodem_recv_start_mark
)
!=
-
1
:
logger
.
debug
(
"Zmodem state => recv"
)
...
...
@@ -237,18 +290,29 @@ class BaseServer:
logger
.
debug
(
"Zmodem state => cancel"
)
self
.
_zmodem_state
=
''
def
zmodem_cancel_filter
(
self
):
def
r_zmodem_disable_filter
(
self
,
data
=
''
):
if
self
.
_zmodem_state
:
pass
# self.chan.send(self._zmodem_cancel_mark)
# self.chan.send("Zmodem disabled")
def
send
(
self
,
data
):
self
.
s_initial_filter
(
data
)
self
.
s_input_state_filter
(
data
)
try
:
self
.
s_parse_input_output_filter
(
data
)
data
=
self
.
s_filter_cmd_filter
(
data
)
except
Exception
as
e
:
logger
.
exception
(
e
)
return
self
.
chan
.
send
(
data
)
def
recv
(
self
,
size
):
data
=
self
.
chan
.
recv
(
size
)
self
.
zmodem_state_filter
(
data
)
self
.
zmodem_cancel_filter
()
self
.
replay_filter
(
data
)
self
.
input_output_filter
(
data
)
self
.
r_zmodem_state_filter
(
data
)
self
.
r_vim_state_filter
(
data
)
self
.
r_zmodem_disable_filter
(
data
)
self
.
r_replay_filter
(
data
)
self
.
r_input_output_data_filter
(
data
)
return
data
@staticmethod
...
...
@@ -261,21 +325,19 @@ class BaseServer:
def
_parse_output
(
self
):
if
not
self
.
output_data
:
return
''
parser
=
utils
.
TtyIOParser
()
return
parser
.
parse_output
(
self
.
output_data
)
return
self
.
_cmd_parser
.
parse_output
(
self
.
output_data
)
def
_parse_input
(
self
):
if
not
self
.
input_data
:
return
parser
=
utils
.
TtyIOParser
()
return
parser
.
parse_input
(
self
.
input_data
)
return
self
.
_cmd_parser
.
parse_input
(
self
.
input_data
)
def
fileno
(
self
):
return
self
.
chan
.
fileno
()
def
close
(
self
):
logger
.
info
(
"Closed server {}"
.
format
(
self
))
self
.
input_output
_filter
(
b
''
)
self
.
r_input_output_data
_filter
(
b
''
)
self
.
chan
.
close
()
def
__getattr__
(
self
,
item
):
...
...
@@ -290,10 +352,9 @@ class TelnetServer(BaseServer):
Telnet server
"""
def
__init__
(
self
,
sock
,
asset
,
system_user
):
super
(
TelnetServer
,
self
)
.
__init__
()
self
.
chan
=
sock
self
.
asset
=
asset
self
.
system_user
=
system_user
super
(
TelnetServer
,
self
)
.
__init__
(
chan
=
sock
)
class
Server
(
BaseServer
):
...
...
@@ -306,11 +367,10 @@ class Server(BaseServer):
# Todo: Server name is not very suitable
def
__init__
(
self
,
chan
,
sock
,
asset
,
system_user
):
super
(
Server
,
self
)
.
__init__
()
self
.
chan
=
chan
self
.
sock
=
sock
self
.
asset
=
asset
self
.
system_user
=
system_user
super
(
Server
,
self
)
.
__init__
(
chan
=
chan
)
def
close
(
self
):
super
()
.
close
()
...
...
coco/session.py
View file @
1ecdcc2a
...
...
@@ -147,6 +147,10 @@ class Session:
pass
self
.
stop_evt
.
set
()
def
send_to_clients
(
self
,
data
):
for
watcher
in
[
self
.
client
]
+
self
.
_watchers
+
self
.
_sharers
:
watcher
.
send
(
data
)
def
bridge
(
self
):
"""
Bridge clients with server
...
...
coco/sshd.py
View file @
1ecdcc2a
...
...
@@ -90,7 +90,7 @@ class SSHServer:
continue
if
not
server
.
event
.
is_set
():
logger
.
warning
(
"Client not request
a valid request
, exiting"
)
logger
.
warning
(
"Client not request
invalid
, exiting"
)
sock
.
close
()
return
else
:
...
...
cocod
View file @
1ecdcc2a
...
...
@@ -2,6 +2,11 @@
# -*- coding: utf-8 -*-
#
import
eventlet
from
eventlet.debug
import
hub_prevent_multiple_readers
eventlet
.
monkey_patch
()
hub_prevent_multiple_readers
(
False
)
import
os
import
sys
import
argparse
...
...
@@ -16,12 +21,9 @@ except ImportError:
print
(
"Please prepare config file `cp conf_example.py conf.py`"
)
sys
.
exit
(
1
)
try
:
os
.
mkdir
(
"logs"
)
os
.
mkdir
(
"keys"
)
os
.
mkdir
(
"sessions"
)
except
:
pass
dirs
=
(
'logs'
,
'keys'
)
for
d
in
dirs
:
os
.
makedirs
(
d
,
exist_ok
=
True
)
BASE_DIR
=
os
.
path
.
dirname
(
os
.
path
.
abspath
(
__file__
))
DAEMON
=
False
...
...
locale/en/LC_MESSAGES/coco.mo
View file @
1ecdcc2a
No preview for this file type
locale/en/LC_MESSAGES/coco.po
View file @
1ecdcc2a
...
...
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-
09-03 10:39
+0800\n"
"POT-Creation-Date: 2018-
10-10 15:22
+0800\n"
"PO-Revision-Date: 2018-08-10 10:42+0800\n"
"Last-Translator: BaiJiangjie <bugatti_it@163.com>\n"
"Language-Team: Language locale/en/LC\n"
...
...
@@ -16,7 +16,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: coco/app.py:14
7
#: coco/app.py:14
1
msgid "Connect idle more than {} minutes, disconnect"
msgstr ""
...
...
@@ -91,44 +91,44 @@ msgstr ""
msgid "Total: {}"
msgstr ""
#: coco/interactive.py:1
59
#: coco/interactive.py:1
61
msgid "There is no matched node, please re-enter"
msgstr ""
#: coco/interactive.py:17
0
#: coco/interactive.py:17
2
msgid "ID"
msgstr ""
#: coco/interactive.py:17
0
#: coco/interactive.py:17
2
msgid "Hostname"
msgstr ""
#: coco/interactive.py:17
0
#: coco/interactive.py:17
2
msgid "IP"
msgstr ""
#: coco/interactive.py:17
0
#: coco/interactive.py:17
2
msgid "LoginAs"
msgstr ""
#: coco/interactive.py:18
4
#: coco/interactive.py:18
6
msgid "Comment"
msgstr ""
#: coco/interactive.py:19
2
#: coco/interactive.py:19
4
msgid "Total: {} Match: {}"
msgstr ""
#: coco/interactive.py:23
5
#: coco/interactive.py:23
7
msgid "Select a login:: "
msgstr ""
#: coco/interactive.py:2
58
#: coco/interactive.py:2
60
msgid ""
"Terminal does not support login Windows, please use web terminal to access"
msgstr ""
#: coco/interactive.py:2
69
#: coco/interactive.py:2
71
msgid "No system user"
msgstr ""
...
...
locale/en/LC_MESSAGES/coco.po~
deleted
100644 → 0
View file @
021a70ac
# Language locale/en/LC translations for PACKAGE package.
# Copyright (C) 2018 THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# BaiJiangjie <bugatti_it@163.com>, 2018.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-09-03 10:36+0800\n"
"PO-Revision-Date: 2018-08-10 10:42+0800\n"
"Last-Translator: BaiJiangjie <bugatti_it@163.com>\n"
"Language-Team: Language locale/en/LC\n"
"Language: locale/en/LC_MESSAGES/coco\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: coco/app.py:147
msgid "Connect idle more than {} minutes, disconnect"
msgstr ""
#: coco/interactive.py:61
#, python-brace-format
msgid ""
"\n"
"{T}{T}{title} {user}, Welcome to use Jumpserver open source fortress system "
"{end}{R}{R}"
msgstr ""
#: coco/interactive.py:63
#, python-brace-format
msgid ""
"{T}1) Enter {green}ID{end} directly login or enter {green}part IP, Hostname, "
"Comment{end} to search login(if unique).{R}"
msgstr ""
#: coco/interactive.py:64
#, python-brace-format
msgid ""
"{T}2) Enter {green}/{end} + {green}IP, Hostname{end} or {green}Comment {end} "
"search, such as: /ip.{R}"
msgstr ""
#: coco/interactive.py:65
#, python-brace-format
msgid "{T}3) Enter {green}p{end} to display the host you have permission.{R}"
msgstr ""
#: coco/interactive.py:66
#, python-brace-format
msgid ""
"{T}4) Enter {green}g{end} to display the node that you have permission.{R}"
msgstr ""
#: coco/interactive.py:67
#, python-brace-format
msgid ""
"{T}5) Enter {green}g{end} + {green}Group ID{end} to display the host under "
"the node, such as g1.{R}"
msgstr ""
#: coco/interactive.py:68
#, python-brace-format
msgid "{T}6) Enter {green}s{end} Chinese-english switch.{R}"
msgstr ""
#: coco/interactive.py:69
#, python-brace-format
msgid "{T}7) Enter {green}h{end} help.{R}"
msgstr ""
#: coco/interactive.py:70
#, python-brace-format
msgid "{T}0) Enter {green}q{end} exit.{R}"
msgstr ""
#: coco/interactive.py:142
msgid "No"
msgstr ""
#: coco/interactive.py:149
msgid "Name"
msgstr ""
#: coco/interactive.py:149
msgid "Assets"
msgstr ""
#: coco/interactive.py:155
msgid "Total: {}"
msgstr ""
#: coco/interactive.py:159
msgid "There is no matched node, please re-enter"
msgstr ""
#: coco/interactive.py:170
msgid "ID"
msgstr ""
#: coco/interactive.py:170
msgid "Hostname"
msgstr ""
#: coco/interactive.py:170
msgid "IP"
msgstr ""
#: coco/interactive.py:170
msgid "LoginAs"
msgstr ""
#: coco/interactive.py:184
msgid "Comment"
msgstr ""
#: coco/interactive.py:192
msgid "Total: {} Match: {}"
msgstr ""
#: coco/interactive.py:235
msgid "Select a login:: "
msgstr ""
#: coco/interactive.py:258
msgid ""
"Terminal does not support login Windows, please use web terminal to access"
msgstr ""
#: coco/interactive.py:269
msgid "No system user"
msgstr ""
#: coco/session.py:143
msgid "Terminated by administrator"
msgstr ""
locale/zh_CN/LC_MESSAGES/coco.mo
View file @
1ecdcc2a
No preview for this file type
locale/zh_CN/LC_MESSAGES/coco.po
View file @
1ecdcc2a
...
...
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-
09-03 10:39
+0800\n"
"POT-Creation-Date: 2018-
10-10 15:22
+0800\n"
"PO-Revision-Date: 2018-08-10 10:42+0800\n"
"Last-Translator: BaiJiangjie <bugatti_it@163.com>\n"
"Language-Team: Language locale/zh\n"
...
...
@@ -16,7 +16,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: coco/app.py:14
7
#: coco/app.py:14
1
msgid "Connect idle more than {} minutes, disconnect"
msgstr "空闲时间超过 {} 分钟,断开连接"
...
...
@@ -77,9 +77,9 @@ msgid "{T}7) Enter {green}h{end} help.{R}"
msgstr "{T}7) 输入 {green}h{end} 帮助.{R}"
#: coco/interactive.py:70
#,
fuzzy,
python-brace-format
#, python-brace-format
msgid "{T}0) Enter {green}q{end} exit.{R}"
msgstr "{T}0) 输入 {green}q{end} 退出.{R}
\n
"
msgstr "{T}0) 输入 {green}q{end} 退出.{R}"
#: coco/interactive.py:142
msgid "No"
...
...
@@ -97,44 +97,44 @@ msgstr "资产"
msgid "Total: {}"
msgstr "总共: {}"
#: coco/interactive.py:1
59
#: coco/interactive.py:1
61
msgid "There is no matched node, please re-enter"
msgstr "没有匹配分组,请重新输入"
#: coco/interactive.py:17
0
#: coco/interactive.py:17
2
msgid "ID"
msgstr ""
#: coco/interactive.py:17
0
#: coco/interactive.py:17
2
msgid "Hostname"
msgstr "主机名"
#: coco/interactive.py:17
0
#: coco/interactive.py:17
2
msgid "IP"
msgstr ""
#: coco/interactive.py:17
0
#: coco/interactive.py:17
2
msgid "LoginAs"
msgstr ""
msgstr "
登录用户
"
#: coco/interactive.py:18
4
#: coco/interactive.py:18
6
msgid "Comment"
msgstr "备注"
#: coco/interactive.py:19
2
#: coco/interactive.py:19
4
msgid "Total: {} Match: {}"
msgstr "总共: {} 匹配: {}"
#: coco/interactive.py:23
5
#: coco/interactive.py:23
7
msgid "Select a login:: "
msgstr "选择一个登录:"
#: coco/interactive.py:2
58
#: coco/interactive.py:2
60
msgid ""
"Terminal does not support login Windows, please use web terminal to access"
msgstr "终端不支持登录windows, 请使用web terminal访问"
#: coco/interactive.py:2
69
#: coco/interactive.py:2
71
msgid "No system user"
msgstr "没有系统用户"
...
...
locale/zh_CN/LC_MESSAGES/coco.po~
deleted
100644 → 0
View file @
021a70ac
# Language locale/zh translations for PACKAGE package.
# Copyright (C) 2018 THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# BaiJiangjie <bugatti_it@163.com>, 2018.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-09-03 10:36+0800\n"
"PO-Revision-Date: 2018-08-10 10:42+0800\n"
"Last-Translator: BaiJiangjie <bugatti_it@163.com>\n"
"Language-Team: Language locale/zh\n"
"Language: locale/zh_CN/LC_MESSAGES/coco\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: coco/app.py:147
msgid "Connect idle more than {} minutes, disconnect"
msgstr "空闲时间超过 {} 分钟,断开连接"
#: coco/interactive.py:61
#, python-brace-format
msgid ""
"\n"
"{T}{T}{title} {user}, Welcome to use Jumpserver open source fortress system "
"{end}{R}{R}"
msgstr ""
"\n"
"{T}{T}{title} {user}, 欢迎使用Jumpserver开源跳板机系统 {end}{R}{R}"
#: coco/interactive.py:63
#, python-brace-format
msgid ""
"{T}1) Enter {green}ID{end} directly login or enter {green}part IP, Hostname, "
"Comment{end} to search login(if unique).{R}"
msgstr ""
"{T}1) 输入 {green}ID{end} 直接登录 或 输入{green}部分 IP,主机名,备注{end} 进"
"行搜索登录(如果唯一).{R}"
#: coco/interactive.py:64
#, python-brace-format
msgid ""
"{T}2) Enter {green}/{end} + {green}IP, Hostname{end} or {green}Comment {end} "
"search, such as: /ip.{R}"
msgstr ""
"{T}2) 输入 {green}/{end} + {green}IP, 主机名{end} or {green}备注 {end}搜索. "
"如: /ip{R}"
#: coco/interactive.py:65
#, python-brace-format
msgid "{T}3) Enter {green}p{end} to display the host you have permission.{R}"
msgstr "{T}3) 输入 {green}p{end} 显示您有权限的主机.{R}"
#: coco/interactive.py:66
#, python-brace-format
msgid ""
"{T}4) Enter {green}g{end} to display the node that you have permission.{R}"
msgstr "{T}4) 输入 {green}g{end} 显示您有权限的节点.{R}"
#: coco/interactive.py:67
#, python-brace-format
msgid ""
"{T}5) Enter {green}g{end} + {green}Group ID{end} to display the host under "
"the node, such as g1.{R}"
msgstr "{T}5) 输入 {green}g{end} + {green}组ID{end} 显示节点下主机. 如: g1{R}"
#: coco/interactive.py:68
#, python-brace-format
msgid "{T}6) Enter {green}s{end} Chinese-english switch.{R}"
msgstr "{T}6) 输入 {green}s{end} 中/英文切换.{R}"
#: coco/interactive.py:69
#, python-brace-format
msgid "{T}7) Enter {green}h{end} help.{R}"
msgstr "{T}7) 输入 {green}h{end} 帮助.{R}"
#: coco/interactive.py:70
#, fuzzy, python-brace-format
msgid "{T}0) Enter {green}q{end} exit.{R}"
msgstr "{T}0) 输入 {green}q{end} 退出.{R}\n"
#: coco/interactive.py:142
msgid "No"
msgstr "无"
#: coco/interactive.py:149
msgid "Name"
msgstr "名称"
#: coco/interactive.py:149
msgid "Assets"
msgstr "资产"
#: coco/interactive.py:155
msgid "Total: {}"
msgstr "总共: {}"
#: coco/interactive.py:159
msgid "There is no matched node, please re-enter"
msgstr "没有匹配分组,请重新输入"
#: coco/interactive.py:170
msgid "ID"
msgstr ""
#: coco/interactive.py:170
msgid "Hostname"
msgstr "主机名"
#: coco/interactive.py:170
msgid "IP"
msgstr ""
#: coco/interactive.py:170
msgid "LoginAs"
msgstr ""
#: coco/interactive.py:184
msgid "Comment"
msgstr "备注"
#: coco/interactive.py:192
msgid "Total: {} Match: {}"
msgstr "总共: {} 匹配: {}"
#: coco/interactive.py:235
msgid "Select a login:: "
msgstr "选择一个登录:"
#: coco/interactive.py:258
msgid ""
"Terminal does not support login Windows, please use web terminal to access"
msgstr "终端不支持登录windows, 请使用web terminal访问"
#: coco/interactive.py:269
msgid "No system user"
msgstr "没有系统用户"
#: coco/session.py:143
msgid "Terminated by administrator"
msgstr "被管理员中断"
requirements/requirements.txt
View file @
1ecdcc2a
...
...
@@ -19,7 +19,7 @@ itsdangerous==0.24
Jinja2==2.10
jmespath==0.9.3
jms-storage==0.0.18
jumpserver-python-sdk==0.0.
48
jumpserver-python-sdk==0.0.
50
MarkupSafe==1.0
oss2==2.4.0
paramiko==2.4.1
...
...
utils/messages.sh
View file @
1ecdcc2a
...
...
@@ -2,15 +2,15 @@
#
function
init_message
()
{
xgettext
-k_
-o
pot
/coco.pot
--from-code
=
UTF-8 coco/
*
.py
msginit
-l
locale/zh_CN/LC_MESSAGES/coco
-i
pot
/coco.pot
msginit
-l
locale/en/LC_MESSAGES/coco
-i
pot
/coco.pot
xgettext
-k_
-o
/tmp
/coco.pot
--from-code
=
UTF-8 coco/
*
.py
msginit
-l
locale/zh_CN/LC_MESSAGES/coco
-i
/tmp
/coco.pot
msginit
-l
locale/en/LC_MESSAGES/coco
-i
/tmp
/coco.pot
}
function
make_message
()
{
xgettext
-k_
-o
pot
/coco.pot
--from-code
=
UTF-8 coco/
*
.py
msgmerge
-U
locale/zh_CN/LC_MESSAGES/coco.po
pot
/coco.pot
msgmerge
-U
locale/en/LC_MESSAGES/coco.po
pot
/coco.pot
xgettext
-k_
-o
/tmp
/coco.pot
--from-code
=
UTF-8 coco/
*
.py
msgmerge
-U
locale/zh_CN/LC_MESSAGES/coco.po
/tmp
/coco.pot
msgmerge
-U
locale/en/LC_MESSAGES/coco.po
/tmp
/coco.pot
}
function
compile_message
()
{
...
...
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