Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
J
jumpserver
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ops
jumpserver
Commits
0a2ff83c
Commit
0a2ff83c
authored
Jun 26, 2018
by
ibuler
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'origin/dev' into dev
parents
7276bd0b
73f9f546
Hide whitespace changes
Inline
Side-by-side
Showing
40 changed files
with
1963 additions
and
291 deletions
+1963
-291
__init__.py
apps/__init__.py
+1
-1
node.py
apps/assets/api/node.py
+3
-2
utils.py
apps/assets/utils.py
+0
-1
forms.py
apps/common/forms.py
+46
-0
signals_handler.py
apps/common/signals_handler.py
+1
-1
basic_setting.html
apps/common/templates/common/basic_setting.html
+3
-0
email_setting.html
apps/common/templates/common/email_setting.html
+3
-0
ldap_setting.html
apps/common/templates/common/ldap_setting.html
+3
-0
security_setting.html
apps/common/templates/common/security_setting.html
+87
-0
terminal_setting.html
apps/common/templates/common/terminal_setting.html
+5
-0
view_urls.py
apps/common/urls/view_urls.py
+1
-0
views.py
apps/common/views.py
+26
-2
django.mo
apps/i18n/zh/LC_MESSAGES/django.mo
+0
-0
django.po
apps/i18n/zh/LC_MESSAGES/django.po
+346
-233
settings.py
apps/jumpserver/settings.py
+3
-0
inventory.py
apps/ops/inventory.py
+1
-0
utils.py
apps/perms/utils.py
+48
-11
jumpserver.js
apps/static/js/jumpserver.js
+88
-0
pwstrength-bootstrap.js
apps/static/js/pwstrength-bootstrap.js
+977
-0
_base_create_update.html
apps/templates/_base_create_update.html
+1
-0
_footer.html
apps/templates/_footer.html
+2
-2
forms.py
apps/users/forms.py
+8
-7
group.py
apps/users/models/group.py
+1
-3
user.py
apps/users/models/user.py
+17
-2
serializers.py
apps/users/serializers.py
+4
-1
signals_handler.py
apps/users/signals_handler.py
+9
-0
_user.html
apps/users/templates/users/_user.html
+1
-0
first_login.html
apps/users/templates/users/first_login.html
+8
-7
reset_password.html
apps/users/templates/users/reset_password.html
+43
-3
user_detail.html
apps/users/templates/users/user_detail.html
+4
-0
user_list.html
apps/users/templates/users/user_list.html
+4
-3
user_password_update.html
apps/users/templates/users/user_password_update.html
+41
-0
user_profile.html
apps/users/templates/users/user_profile.html
+7
-0
user_pubkey_update.html
apps/users/templates/users/user_pubkey_update.html
+6
-1
user_update.html
apps/users/templates/users/user_update.html
+45
-0
utils.py
apps/users/utils.py
+61
-0
login.py
apps/users/views/login.py
+15
-3
user.py
apps/users/views/user.py
+38
-2
config_example.py
config_example.py
+0
-5
clean_duplicate_user_groups.py
utils/clean_duplicate_user_groups.py
+6
-1
No files found.
apps/__init__.py
View file @
0a2ff83c
...
@@ -2,4 +2,4 @@
...
@@ -2,4 +2,4 @@
# -*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
#
#
__version__
=
"1.3.
1
"
__version__
=
"1.3.
2
"
apps/assets/api/node.py
View file @
0a2ff83c
...
@@ -116,7 +116,7 @@ class NodeChildrenApi(mixins.ListModelMixin, generics.CreateAPIView):
...
@@ -116,7 +116,7 @@ class NodeChildrenApi(mixins.ListModelMixin, generics.CreateAPIView):
def
get_object
(
self
):
def
get_object
(
self
):
pk
=
self
.
kwargs
.
get
(
'pk'
)
or
self
.
request
.
query_params
.
get
(
'id'
)
pk
=
self
.
kwargs
.
get
(
'pk'
)
or
self
.
request
.
query_params
.
get
(
'id'
)
if
not
pk
:
if
not
pk
:
node
=
No
de
.
root
()
node
=
No
ne
else
:
else
:
node
=
get_object_or_404
(
Node
,
pk
=
pk
)
node
=
get_object_or_404
(
Node
,
pk
=
pk
)
return
node
return
node
...
@@ -126,7 +126,8 @@ class NodeChildrenApi(mixins.ListModelMixin, generics.CreateAPIView):
...
@@ -126,7 +126,8 @@ class NodeChildrenApi(mixins.ListModelMixin, generics.CreateAPIView):
query_all
=
self
.
request
.
query_params
.
get
(
"all"
)
query_all
=
self
.
request
.
query_params
.
get
(
"all"
)
query_assets
=
self
.
request
.
query_params
.
get
(
'assets'
)
query_assets
=
self
.
request
.
query_params
.
get
(
'assets'
)
node
=
self
.
get_object
()
node
=
self
.
get_object
()
if
node
==
Node
.
root
():
if
node
is
None
:
node
=
Node
.
root
()
queryset
.
append
(
node
)
queryset
.
append
(
node
)
if
query_all
:
if
query_all
:
children
=
node
.
get_all_children
()
children
=
node
.
get_all_children
()
...
...
apps/assets/utils.py
View file @
0a2ff83c
...
@@ -51,7 +51,6 @@ def test_gateway_connectability(gateway):
...
@@ -51,7 +51,6 @@ def test_gateway_connectability(gateway):
client
=
paramiko
.
SSHClient
()
client
=
paramiko
.
SSHClient
()
client
.
set_missing_host_key_policy
(
paramiko
.
AutoAddPolicy
())
client
.
set_missing_host_key_policy
(
paramiko
.
AutoAddPolicy
())
proxy
=
paramiko
.
SSHClient
()
proxy
=
paramiko
.
SSHClient
()
proxy
.
load_host_keys
(
os
.
path
.
expanduser
(
'~/.ssh/known_hosts'
))
proxy
.
set_missing_host_key_policy
(
paramiko
.
AutoAddPolicy
())
proxy
.
set_missing_host_key_policy
(
paramiko
.
AutoAddPolicy
())
try
:
try
:
...
...
apps/common/forms.py
View file @
0a2ff83c
...
@@ -168,3 +168,49 @@ class TerminalSettingForm(BaseForm):
...
@@ -168,3 +168,49 @@ class TerminalSettingForm(BaseForm):
)
)
)
)
class
SecuritySettingForm
(
BaseForm
):
# MFA全局设置
SECURITY_MFA_AUTH
=
forms
.
BooleanField
(
initial
=
False
,
required
=
False
,
label
=
_
(
"MFA Secondary certification"
),
help_text
=
_
(
'After opening, the user login must use MFA secondary '
'authentication (valid for all users, including administrators)'
)
)
# 最小长度
SECURITY_PASSWORD_MIN_LENGTH
=
forms
.
IntegerField
(
initial
=
6
,
label
=
_
(
"Password minimum length"
),
min_value
=
6
)
# 大写字母
SECURITY_PASSWORD_UPPER_CASE
=
forms
.
BooleanField
(
initial
=
False
,
required
=
False
,
label
=
_
(
"Must contain capital letters"
),
help_text
=
_
(
'After opening, the user password changes '
'and resets must contain uppercase letters'
)
)
# 小写字母
SECURITY_PASSWORD_LOWER_CASE
=
forms
.
BooleanField
(
initial
=
False
,
required
=
False
,
label
=
_
(
"Must contain lowercase letters"
),
help_text
=
_
(
'After opening, the user password changes '
'and resets must contain lowercase letters'
)
)
# 数字
SECURITY_PASSWORD_NUMBER
=
forms
.
BooleanField
(
initial
=
False
,
required
=
False
,
label
=
_
(
"Must contain numeric characters"
),
help_text
=
_
(
'After opening, the user password changes '
'and resets must contain numeric characters'
)
)
# 特殊字符
SECURITY_PASSWORD_SPECIAL_CHAR
=
forms
.
BooleanField
(
initial
=
False
,
required
=
False
,
label
=
_
(
"Must contain special characters"
),
help_text
=
_
(
'After opening, the user password changes '
'and resets must contain special characters'
)
)
apps/common/signals_handler.py
View file @
0a2ff83c
...
@@ -34,7 +34,7 @@ def refresh_all_settings_on_django_ready(sender, **kwargs):
...
@@ -34,7 +34,7 @@ def refresh_all_settings_on_django_ready(sender, **kwargs):
def
ldap_auth_on_changed
(
sender
,
enabled
=
True
,
**
kwargs
):
def
ldap_auth_on_changed
(
sender
,
enabled
=
True
,
**
kwargs
):
if
enabled
:
if
enabled
:
logger
.
debug
(
"Enable LDAP auth"
)
logger
.
debug
(
"Enable LDAP auth"
)
if
settings
.
AUTH_LDAP_BACKEND
not
in
settings
.
AUTH
_LDAP_BACKEND
:
if
settings
.
AUTH_LDAP_BACKEND
not
in
settings
.
AUTH
ENTICATION_BACKENDS
:
settings
.
AUTHENTICATION_BACKENDS
.
insert
(
0
,
settings
.
AUTH_LDAP_BACKEND
)
settings
.
AUTHENTICATION_BACKENDS
.
insert
(
0
,
settings
.
AUTH_LDAP_BACKEND
)
else
:
else
:
...
...
apps/common/templates/common/basic_setting.html
View file @
0a2ff83c
...
@@ -23,6 +23,9 @@
...
@@ -23,6 +23,9 @@
<li>
<li>
<a
href=
"{% url 'settings:terminal-setting' %}"
class=
"text-center"
><i
class=
"fa fa-hdd-o"
></i>
{% trans 'Terminal setting' %}
</a>
<a
href=
"{% url 'settings:terminal-setting' %}"
class=
"text-center"
><i
class=
"fa fa-hdd-o"
></i>
{% trans 'Terminal setting' %}
</a>
</li>
</li>
<li>
<a
href=
"{% url 'settings:security-setting' %}"
class=
"text-center"
><i
class=
"fa fa-lock"
></i>
{% trans 'Security setting' %}
</a>
</li>
</ul>
</ul>
</div>
</div>
<div
class=
"tab-content"
>
<div
class=
"tab-content"
>
...
...
apps/common/templates/common/email_setting.html
View file @
0a2ff83c
...
@@ -23,6 +23,9 @@
...
@@ -23,6 +23,9 @@
<li>
<li>
<a
href=
"{% url 'settings:terminal-setting' %}"
class=
"text-center"
><i
class=
"fa fa-hdd-o"
></i>
{% trans 'Terminal setting' %}
</a>
<a
href=
"{% url 'settings:terminal-setting' %}"
class=
"text-center"
><i
class=
"fa fa-hdd-o"
></i>
{% trans 'Terminal setting' %}
</a>
</li>
</li>
<li>
<a
href=
"{% url 'settings:security-setting' %}"
class=
"text-center"
><i
class=
"fa fa-lock"
></i>
{% trans 'Security setting' %}
</a>
</li>
</ul>
</ul>
</div>
</div>
<div
class=
"tab-content"
>
<div
class=
"tab-content"
>
...
...
apps/common/templates/common/ldap_setting.html
View file @
0a2ff83c
...
@@ -23,6 +23,9 @@
...
@@ -23,6 +23,9 @@
<li>
<li>
<a
href=
"{% url 'settings:terminal-setting' %}"
class=
"text-center"
><i
class=
"fa fa-hdd-o"
></i>
{% trans 'Terminal setting' %}
</a>
<a
href=
"{% url 'settings:terminal-setting' %}"
class=
"text-center"
><i
class=
"fa fa-hdd-o"
></i>
{% trans 'Terminal setting' %}
</a>
</li>
</li>
<li>
<a
href=
"{% url 'settings:security-setting' %}"
class=
"text-center"
><i
class=
"fa fa-lock"
></i>
{% trans 'Security setting' %}
</a>
</li>
</ul>
</ul>
</div>
</div>
<div
class=
"tab-content"
>
<div
class=
"tab-content"
>
...
...
apps/common/templates/common/security_setting.html
0 → 100644
View file @
0a2ff83c
{% extends 'base.html' %}
{% load static %}
{% load bootstrap3 %}
{% load i18n %}
{% load common_tags %}
{% block content %}
<div
class=
"wrapper wrapper-content animated fadeInRight"
>
<div
class=
"row"
>
<div
class=
"col-sm-12"
>
<div
class=
"ibox float-e-margins"
>
<div
class=
"panel-options"
>
<ul
class=
"nav nav-tabs"
>
<li>
<a
href=
"{% url 'settings:basic-setting' %}"
class=
"text-center"
><i
class=
"fa fa-cubes"
></i>
{% trans 'Basic setting' %}
</a>
</li>
<li>
<a
href=
"{% url 'settings:email-setting' %}"
class=
"text-center"
><i
class=
"fa fa-envelope"
></i>
{% trans 'Email setting' %}
</a>
</li>
<li>
<a
href=
"{% url 'settings:ldap-setting' %}"
class=
"text-center"
><i
class=
"fa fa-archive"
></i>
{% trans 'LDAP setting' %}
</a>
</li>
<li>
<a
href=
"{% url 'settings:terminal-setting' %}"
class=
"text-center"
><i
class=
"fa fa-hdd-o"
></i>
{% trans 'Terminal setting' %}
</a>
</li>
<li
class=
"active"
>
<a
href=
"{% url 'settings:security-setting' %}"
class=
"text-center"
><i
class=
"fa fa-lock"
></i>
{% trans 'Security setting' %}
</a>
</li>
</ul>
</div>
<div
class=
"tab-content"
>
<div
class=
"col-sm-12"
style=
"padding-left:0"
>
<div
class=
"ibox-content"
style=
"border-width: 0;padding-top: 40px;"
>
<form
action=
""
method=
"post"
class=
"form-horizontal"
>
{% if form.non_field_errors %}
<div
class=
"alert alert-danger"
>
{{ form.non_field_errors }}
</div>
{% endif %}
{% csrf_token %}
<h3>
{% trans "MFA setting" %}
</h3>
{% for field in form %}
{% if forloop.counter == 2 %}
<div
class=
"hr-line-dashed"
></div>
<h3>
{% trans "Password check rule" %}
</h3>
{% endif %}
{% if not field.field|is_bool_field %}
{% bootstrap_field field layout="horizontal" %}
{% else %}
<div
class=
"form-group"
>
<label
for=
"{{ field.id_for_label }}"
class=
"col-sm-2 control-label"
>
{{ field.label }}
</label>
<div
class=
"col-sm-8"
>
<div
class=
"col-sm-1"
>
{{ field }}
</div>
<div
class=
"col-sm-9"
>
<span
class=
"help-block"
>
{{ field.help_text }}
</span>
</div>
</div>
</div>
{% endif %}
{% endfor %}
<div
class=
"hr-line-dashed"
></div>
<div
class=
"form-group"
>
<div
class=
"col-sm-4 col-sm-offset-2"
>
<button
class=
"btn btn-default"
type=
"reset"
>
{% trans 'Reset' %}
</button>
<button
id=
"submit_button"
class=
"btn btn-primary"
type=
"submit"
>
{% trans 'Submit' %}
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block custom_foot_js %}
<script>
</script>
{% endblock %}
apps/common/templates/common/terminal_setting.html
View file @
0a2ff83c
...
@@ -27,6 +27,9 @@
...
@@ -27,6 +27,9 @@
<a
href=
"{% url 'settings:terminal-setting' %}"
class=
"text-center"
><i
<a
href=
"{% url 'settings:terminal-setting' %}"
class=
"text-center"
><i
class=
"fa fa-hdd-o"
></i>
{% trans 'Terminal setting' %}
</a>
class=
"fa fa-hdd-o"
></i>
{% trans 'Terminal setting' %}
</a>
</li>
</li>
<li>
<a
href=
"{% url 'settings:security-setting' %}"
class=
"text-center"
><i
class=
"fa fa-lock"
></i>
{% trans 'Security setting' %}
</a>
</li>
</ul>
</ul>
</div>
</div>
<div
class=
"tab-content"
>
<div
class=
"tab-content"
>
...
@@ -39,6 +42,7 @@
...
@@ -39,6 +42,7 @@
</div>
</div>
{% endif %}
{% endif %}
{% csrf_token %}
{% csrf_token %}
<h3>
{% trans "Basic setting" %}
</h3>
<h3>
{% trans "Basic setting" %}
</h3>
{% for field in form %}
{% for field in form %}
{% if not field.field|is_bool_field %}
{% if not field.field|is_bool_field %}
...
@@ -60,6 +64,7 @@
...
@@ -60,6 +64,7 @@
{% endfor %}
{% endfor %}
<div
class=
"hr-line-dashed"
></div>
<div
class=
"hr-line-dashed"
></div>
<h3>
{% trans "Command storage" %}
</h3>
<h3>
{% trans "Command storage" %}
</h3>
<table
class=
"table table-hover "
id=
"task-history-list-table"
>
<table
class=
"table table-hover "
id=
"task-history-list-table"
>
<thead>
<thead>
...
...
apps/common/urls/view_urls.py
View file @
0a2ff83c
...
@@ -11,4 +11,5 @@ urlpatterns = [
...
@@ -11,4 +11,5 @@ urlpatterns = [
url
(
r'^email/$'
,
views
.
EmailSettingView
.
as_view
(),
name
=
'email-setting'
),
url
(
r'^email/$'
,
views
.
EmailSettingView
.
as_view
(),
name
=
'email-setting'
),
url
(
r'^ldap/$'
,
views
.
LDAPSettingView
.
as_view
(),
name
=
'ldap-setting'
),
url
(
r'^ldap/$'
,
views
.
LDAPSettingView
.
as_view
(),
name
=
'ldap-setting'
),
url
(
r'^terminal/$'
,
views
.
TerminalSettingView
.
as_view
(),
name
=
'terminal-setting'
),
url
(
r'^terminal/$'
,
views
.
TerminalSettingView
.
as_view
(),
name
=
'terminal-setting'
),
url
(
r'^security/$'
,
views
.
SecuritySettingView
.
as_view
(),
name
=
'security-setting'
),
]
]
apps/common/views.py
View file @
0a2ff83c
...
@@ -7,7 +7,7 @@ from django.utils.translation import ugettext as _
...
@@ -7,7 +7,7 @@ from django.utils.translation import ugettext as _
from
django.conf
import
settings
from
django.conf
import
settings
from
.forms
import
EmailSettingForm
,
LDAPSettingForm
,
BasicSettingForm
,
\
from
.forms
import
EmailSettingForm
,
LDAPSettingForm
,
BasicSettingForm
,
\
TerminalSettingForm
TerminalSettingForm
,
SecuritySettingForm
from
.mixins
import
AdminUserRequiredMixin
from
.mixins
import
AdminUserRequiredMixin
from
.signals
import
ldap_auth_enable
from
.signals
import
ldap_auth_enable
...
@@ -82,7 +82,7 @@ class LDAPSettingView(AdminUserRequiredMixin, TemplateView):
...
@@ -82,7 +82,7 @@ class LDAPSettingView(AdminUserRequiredMixin, TemplateView):
if
form
.
is_valid
():
if
form
.
is_valid
():
form
.
save
()
form
.
save
()
if
"AUTH_LDAP"
in
form
.
cleaned_data
:
if
"AUTH_LDAP"
in
form
.
cleaned_data
:
ldap_auth_enable
.
send
(
form
.
cleaned_data
[
"AUTH_LDAP"
])
ldap_auth_enable
.
send
(
sender
=
self
.
__class__
,
enabled
=
form
.
cleaned_data
[
"AUTH_LDAP"
])
msg
=
_
(
"Update setting successfully, please restart program"
)
msg
=
_
(
"Update setting successfully, please restart program"
)
messages
.
success
(
request
,
msg
)
messages
.
success
(
request
,
msg
)
return
redirect
(
'settings:ldap-setting'
)
return
redirect
(
'settings:ldap-setting'
)
...
@@ -122,3 +122,27 @@ class TerminalSettingView(AdminUserRequiredMixin, TemplateView):
...
@@ -122,3 +122,27 @@ class TerminalSettingView(AdminUserRequiredMixin, TemplateView):
return
render
(
request
,
self
.
template_name
,
context
)
return
render
(
request
,
self
.
template_name
,
context
)
class
SecuritySettingView
(
AdminUserRequiredMixin
,
TemplateView
):
form_class
=
SecuritySettingForm
template_name
=
"common/security_setting.html"
def
get_context_data
(
self
,
**
kwargs
):
context
=
{
'app'
:
_
(
'Settings'
),
'action'
:
_
(
'Security setting'
),
'form'
:
self
.
form_class
(),
}
kwargs
.
update
(
context
)
return
super
()
.
get_context_data
(
**
kwargs
)
def
post
(
self
,
request
):
form
=
self
.
form_class
(
request
.
POST
)
if
form
.
is_valid
():
form
.
save
()
msg
=
_
(
"Update setting successfully, please restart program"
)
messages
.
success
(
request
,
msg
)
return
redirect
(
'settings:security-setting'
)
else
:
context
=
self
.
get_context_data
()
context
.
update
({
"form"
:
form
})
return
render
(
request
,
self
.
template_name
,
context
)
apps/i18n/zh/LC_MESSAGES/django.mo
View file @
0a2ff83c
No preview for this file type
apps/i18n/zh/LC_MESSAGES/django.po
View file @
0a2ff83c
...
@@ -8,7 +8,7 @@ msgid ""
...
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
msgstr ""
"Project-Id-Version: Jumpserver 0.3.3\n"
"Project-Id-Version: Jumpserver 0.3.3\n"
"Report-Msgid-Bugs-To: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-0
5-25 18:11
+0800\n"
"POT-Creation-Date: 2018-0
6-07 11:34
+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: ibuler <ibuler@qq.com>\n"
"Last-Translator: ibuler <ibuler@qq.com>\n"
"Language-Team: Jumpserver team<ibuler@qq.com>\n"
"Language-Team: Jumpserver team<ibuler@qq.com>\n"
...
@@ -17,19 +17,19 @@ msgstr ""
...
@@ -17,19 +17,19 @@ 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"
#: assets/api/node.py:
106
#: assets/api/node.py:
99
msgid "New node {}"
msgid "New node {}"
msgstr "新节点 {}"
msgstr "新节点 {}"
#: assets/api/node.py:2
42
#: assets/api/node.py:2
34
msgid "更新节点资产硬件信息: {}"
msgid "更新节点资产硬件信息: {}"
msgstr ""
msgstr ""
#: assets/api/node.py:2
55
#: assets/api/node.py:2
47
msgid "测试节点下资产是否可连接: {}"
msgid "测试节点下资产是否可连接: {}"
msgstr ""
msgstr ""
#: assets/forms/asset.py:24 assets/models/asset.py:
66
assets/models/user.py:103
#: assets/forms/asset.py:24 assets/models/asset.py:
75
assets/models/user.py:103
#: assets/templates/assets/asset_detail.html:183
#: assets/templates/assets/asset_detail.html:183
#: assets/templates/assets/asset_detail.html:191
#: assets/templates/assets/asset_detail.html:191
#: assets/templates/assets/system_user_detail.html:175 perms/models.py:33
#: assets/templates/assets/system_user_detail.html:175 perms/models.py:33
...
@@ -37,7 +37,7 @@ msgid "Nodes"
...
@@ -37,7 +37,7 @@ msgid "Nodes"
msgstr "节点管理"
msgstr "节点管理"
#: assets/forms/asset.py:27 assets/forms/asset.py:66 assets/forms/asset.py:109
#: assets/forms/asset.py:27 assets/forms/asset.py:66 assets/forms/asset.py:109
#: assets/forms/asset.py:113 assets/models/asset.py:
7
0
#: assets/forms/asset.py:113 assets/models/asset.py:
8
0
#: assets/models/cluster.py:19 assets/models/user.py:72
#: assets/models/cluster.py:19 assets/models/user.py:72
#: assets/templates/assets/asset_detail.html:73 templates/_nav.html:25
#: assets/templates/assets/asset_detail.html:73 templates/_nav.html:25
msgid "Admin user"
msgid "Admin user"
...
@@ -46,14 +46,14 @@ msgstr "管理用户"
...
@@ -46,14 +46,14 @@ msgstr "管理用户"
#: assets/forms/asset.py:30 assets/forms/asset.py:69 assets/forms/asset.py:125
#: assets/forms/asset.py:30 assets/forms/asset.py:69 assets/forms/asset.py:125
#: assets/templates/assets/asset_create.html:35
#: assets/templates/assets/asset_create.html:35
#: assets/templates/assets/asset_create.html:37
#: assets/templates/assets/asset_create.html:37
#: assets/templates/assets/asset_list.html:7
4
#: assets/templates/assets/asset_list.html:7
5
#: assets/templates/assets/asset_update.html:40
#: assets/templates/assets/asset_update.html:40
#: assets/templates/assets/asset_update.html:42
#: assets/templates/assets/asset_update.html:42
#: assets/templates/assets/user_asset_list.html:34
#: assets/templates/assets/user_asset_list.html:34
msgid "Label"
msgid "Label"
msgstr "标签"
msgstr "标签"
#: assets/forms/asset.py:34 assets/forms/asset.py:73 assets/models/asset.py:
65
#: assets/forms/asset.py:34 assets/forms/asset.py:73 assets/models/asset.py:
71
#: assets/models/domain.py:46
#: assets/models/domain.py:46
msgid "Domain"
msgid "Domain"
msgstr "网域"
msgstr "网域"
...
@@ -90,7 +90,7 @@ msgstr "如果有多个的互相隔离的网络,设置资产属于的网域,
...
@@ -90,7 +90,7 @@ msgstr "如果有多个的互相隔离的网络,设置资产属于的网域,
msgid "Select assets"
msgid "Select assets"
msgstr "选择资产"
msgstr "选择资产"
#: assets/forms/asset.py:105 assets/models/asset.py:6
3
#: assets/forms/asset.py:105 assets/models/asset.py:6
7
#: assets/models/domain.py:44 assets/templates/assets/admin_user_assets.html:53
#: assets/models/domain.py:44 assets/templates/assets/admin_user_assets.html:53
#: assets/templates/assets/asset_detail.html:69
#: assets/templates/assets/asset_detail.html:69
#: assets/templates/assets/domain_gateway_list.html:58
#: assets/templates/assets/domain_gateway_list.html:58
...
@@ -99,7 +99,7 @@ msgid "Port"
...
@@ -99,7 +99,7 @@ msgid "Port"
msgstr "端口"
msgstr "端口"
#: assets/forms/domain.py:14 assets/forms/label.py:13
#: assets/forms/domain.py:14 assets/forms/label.py:13
#: assets/models/asset.py:
18
3 assets/templates/assets/admin_user_list.html:25
#: assets/models/asset.py:
22
3 assets/templates/assets/admin_user_list.html:25
#: assets/templates/assets/domain_detail.html:60
#: assets/templates/assets/domain_detail.html:60
#: assets/templates/assets/domain_list.html:15
#: assets/templates/assets/domain_list.html:15
#: assets/templates/assets/label_list.html:16
#: assets/templates/assets/label_list.html:16
...
@@ -129,15 +129,15 @@ msgstr "资产"
...
@@ -129,15 +129,15 @@ msgstr "资产"
#: assets/templates/assets/label_list.html:14
#: assets/templates/assets/label_list.html:14
#: assets/templates/assets/system_user_detail.html:58
#: assets/templates/assets/system_user_detail.html:58
#: assets/templates/assets/system_user_list.html:26 common/models.py:26
#: assets/templates/assets/system_user_list.html:26 common/models.py:26
#: common/templates/common/terminal_setting.html:
67
#: common/templates/common/terminal_setting.html:
72
#: common/templates/common/terminal_setting.html:
85
ops/models/adhoc.py:36
#: common/templates/common/terminal_setting.html:
90
ops/models/adhoc.py:36
#: ops/templates/ops/task_detail.html:59 ops/templates/ops/task_list.html:35
#: ops/templates/ops/task_detail.html:59 ops/templates/ops/task_list.html:35
#: perms/models.py:29 perms/templates/perms/asset_permission_detail.html:62
#: perms/models.py:29 perms/templates/perms/asset_permission_detail.html:62
#: perms/templates/perms/asset_permission_list.html:53
#: perms/templates/perms/asset_permission_list.html:53
#: perms/templates/perms/asset_permission_user.html:54 terminal/models.py:16
#: perms/templates/perms/asset_permission_user.html:54 terminal/models.py:16
#: terminal/models.py:154 terminal/templates/terminal/terminal_detail.html:43
#: terminal/models.py:154 terminal/templates/terminal/terminal_detail.html:43
#: terminal/templates/terminal/terminal_list.html:29 users/models/group.py:1
4
#: terminal/templates/terminal/terminal_list.html:29 users/models/group.py:1
2
#: users/models/user.py:4
2
users/templates/users/_select_user_modal.html:13
#: users/models/user.py:4
9
users/templates/users/_select_user_modal.html:13
#: users/templates/users/user_detail.html:63
#: users/templates/users/user_detail.html:63
#: users/templates/users/user_group_detail.html:55
#: users/templates/users/user_group_detail.html:55
#: users/templates/users/user_group_list.html:12
#: users/templates/users/user_group_list.html:12
...
@@ -155,7 +155,7 @@ msgstr "名称"
...
@@ -155,7 +155,7 @@ msgstr "名称"
#: assets/templates/assets/system_user_list.html:27
#: assets/templates/assets/system_user_list.html:27
#: perms/templates/perms/asset_permission_user.html:55 users/forms.py:13
#: perms/templates/perms/asset_permission_user.html:55 users/forms.py:13
#: users/forms.py:21 users/forms.py:30 users/models/authentication.py:45
#: users/forms.py:21 users/forms.py:30 users/models/authentication.py:45
#: users/models/user.py:4
0
users/templates/users/_select_user_modal.html:14
#: users/models/user.py:4
7
users/templates/users/_select_user_modal.html:14
#: users/templates/users/login.html:56
#: users/templates/users/login.html:56
#: users/templates/users/login_log_list.html:49
#: users/templates/users/login_log_list.html:49
#: users/templates/users/user_detail.html:67
#: users/templates/users/user_detail.html:67
...
@@ -171,16 +171,16 @@ msgstr "密码或密钥密码"
...
@@ -171,16 +171,16 @@ msgstr "密码或密钥密码"
#: assets/forms/user.py:25 assets/models/base.py:23 common/forms.py:113
#: assets/forms/user.py:25 assets/models/base.py:23 common/forms.py:113
#: users/forms.py:15 users/forms.py:23 users/forms.py:32 users/forms.py:44
#: users/forms.py:15 users/forms.py:23 users/forms.py:32 users/forms.py:44
#: users/templates/users/login.html:59
#: users/templates/users/login.html:59
#: users/templates/users/reset_password.html:5
2
#: users/templates/users/reset_password.html:5
3
#: users/templates/users/user_create.html:10
#: users/templates/users/user_create.html:10
#: users/templates/users/user_password_authentication.html:14
#: users/templates/users/user_password_authentication.html:14
#: users/templates/users/user_password_update.html:4
0
#: users/templates/users/user_password_update.html:4
2
#: users/templates/users/user_profile_update.html:40
#: users/templates/users/user_profile_update.html:40
#: users/templates/users/user_pubkey_update.html:40
#: users/templates/users/user_pubkey_update.html:40
msgid "Password"
msgid "Password"
msgstr "密码"
msgstr "密码"
#: assets/forms/user.py:28 users/models/user.py:
69
#: assets/forms/user.py:28 users/models/user.py:
76
msgid "Private key"
msgid "Private key"
msgstr "ssh私钥"
msgstr "ssh私钥"
...
@@ -202,11 +202,11 @@ msgid ""
...
@@ -202,11 +202,11 @@ msgid ""
"than 2 system user"
"than 2 system user"
msgstr "高优先级的系统用户将会作为默认登录用户"
msgstr "高优先级的系统用户将会作为默认登录用户"
#: assets/models/asset.py:6
1
assets/models/domain.py:43
#: assets/models/asset.py:6
3
assets/models/domain.py:43
#: assets/templates/assets/_asset_list_modal.html:46
#: assets/templates/assets/_asset_list_modal.html:46
#: assets/templates/assets/admin_user_assets.html:52
#: assets/templates/assets/admin_user_assets.html:52
#: assets/templates/assets/asset_detail.html:61
#: assets/templates/assets/asset_detail.html:61
#: assets/templates/assets/asset_list.html:8
6
#: assets/templates/assets/asset_list.html:8
7
#: assets/templates/assets/domain_gateway_list.html:57
#: assets/templates/assets/domain_gateway_list.html:57
#: assets/templates/assets/system_user_asset.html:50
#: assets/templates/assets/system_user_asset.html:50
#: assets/templates/assets/user_asset_list.html:46 common/forms.py:144
#: assets/templates/assets/user_asset_list.html:46 common/forms.py:144
...
@@ -217,10 +217,10 @@ msgstr "高优先级的系统用户将会作为默认登录用户"
...
@@ -217,10 +217,10 @@ msgstr "高优先级的系统用户将会作为默认登录用户"
msgid "IP"
msgid "IP"
msgstr "IP"
msgstr "IP"
#: assets/models/asset.py:6
2
assets/templates/assets/_asset_list_modal.html:45
#: assets/models/asset.py:6
6
assets/templates/assets/_asset_list_modal.html:45
#: assets/templates/assets/admin_user_assets.html:51
#: assets/templates/assets/admin_user_assets.html:51
#: assets/templates/assets/asset_detail.html:57
#: assets/templates/assets/asset_detail.html:57
#: assets/templates/assets/asset_list.html:8
5
#: assets/templates/assets/asset_list.html:8
6
#: assets/templates/assets/system_user_asset.html:49
#: assets/templates/assets/system_user_asset.html:49
#: assets/templates/assets/user_asset_list.html:45 common/forms.py:143
#: assets/templates/assets/user_asset_list.html:45 common/forms.py:143
#: perms/templates/perms/asset_permission_asset.html:54
#: perms/templates/perms/asset_permission_asset.html:54
...
@@ -229,82 +229,82 @@ msgstr "IP"
...
@@ -229,82 +229,82 @@ msgstr "IP"
msgid "Hostname"
msgid "Hostname"
msgstr "主机名"
msgstr "主机名"
#: assets/models/asset.py:6
4
assets/templates/assets/asset_detail.html:97
#: assets/models/asset.py:6
9
assets/templates/assets/asset_detail.html:97
msgid "Platform"
msgid "Platform"
msgstr "系统平台"
msgstr "系统平台"
#: assets/models/asset.py:
67
assets/models/domain.py:48
#: assets/models/asset.py:
76
assets/models/domain.py:48
#: assets/models/label.py:20 assets/templates/assets/asset_detail.html:105
#: assets/models/label.py:20 assets/templates/assets/asset_detail.html:105
msgid "Is active"
msgid "Is active"
msgstr "激活"
msgstr "激活"
#: assets/models/asset.py:
73
assets/templates/assets/asset_detail.html:65
#: assets/models/asset.py:
85
assets/templates/assets/asset_detail.html:65
msgid "Public IP"
msgid "Public IP"
msgstr "公网IP"
msgstr "公网IP"
#: assets/models/asset.py:
74
assets/templates/assets/asset_detail.html:113
#: assets/models/asset.py:
87
assets/templates/assets/asset_detail.html:113
msgid "Asset number"
msgid "Asset number"
msgstr "资产编号"
msgstr "资产编号"
#: assets/models/asset.py:
77
assets/templates/assets/asset_detail.html:77
#: assets/models/asset.py:
91
assets/templates/assets/asset_detail.html:77
msgid "Vendor"
msgid "Vendor"
msgstr "制造商"
msgstr "制造商"
#: assets/models/asset.py:
78
assets/templates/assets/asset_detail.html:81
#: assets/models/asset.py:
93
assets/templates/assets/asset_detail.html:81
msgid "Model"
msgid "Model"
msgstr "型号"
msgstr "型号"
#: assets/models/asset.py:
79
assets/templates/assets/asset_detail.html:109
#: assets/models/asset.py:
95
assets/templates/assets/asset_detail.html:109
msgid "Serial number"
msgid "Serial number"
msgstr "序列号"
msgstr "序列号"
#: assets/models/asset.py:
81
#: assets/models/asset.py:
98
msgid "CPU model"
msgid "CPU model"
msgstr "CPU型号"
msgstr "CPU型号"
#: assets/models/asset.py:
82
#: assets/models/asset.py:
99
msgid "CPU count"
msgid "CPU count"
msgstr "CPU数量"
msgstr "CPU数量"
#: assets/models/asset.py:
83
#: assets/models/asset.py:
100
msgid "CPU cores"
msgid "CPU cores"
msgstr "CPU核数"
msgstr "CPU核数"
#: assets/models/asset.py:
84
assets/templates/assets/asset_detail.html:89
#: assets/models/asset.py:
102
assets/templates/assets/asset_detail.html:89
msgid "Memory"
msgid "Memory"
msgstr "内存"
msgstr "内存"
#: assets/models/asset.py:
85
#: assets/models/asset.py:
104
msgid "Disk total"
msgid "Disk total"
msgstr "硬盘大小"
msgstr "硬盘大小"
#: assets/models/asset.py:
8
6
#: assets/models/asset.py:
10
6
msgid "Disk info"
msgid "Disk info"
msgstr "硬盘信息"
msgstr "硬盘信息"
#: assets/models/asset.py:
88
assets/templates/assets/asset_detail.html:101
#: assets/models/asset.py:
109
assets/templates/assets/asset_detail.html:101
msgid "OS"
msgid "OS"
msgstr "操作系统"
msgstr "操作系统"
#: assets/models/asset.py:
89
#: assets/models/asset.py:
111
msgid "OS version"
msgid "OS version"
msgstr "系统版本"
msgstr "系统版本"
#: assets/models/asset.py:
90
#: assets/models/asset.py:
113
msgid "OS arch"
msgid "OS arch"
msgstr "系统架构"
msgstr "系统架构"
#: assets/models/asset.py:
91
#: assets/models/asset.py:
115
msgid "Hostname raw"
msgid "Hostname raw"
msgstr "主机名原始"
msgstr "主机名原始"
#: assets/models/asset.py:
93
assets/templates/assets/asset_create.html:33
#: assets/models/asset.py:
119
assets/templates/assets/asset_create.html:33
#: assets/templates/assets/asset_detail.html:220
#: assets/templates/assets/asset_detail.html:220
#: assets/templates/assets/asset_update.html:38 templates/_nav.html:27
#: assets/templates/assets/asset_update.html:38 templates/_nav.html:27
msgid "Labels"
msgid "Labels"
msgstr "标签管理"
msgstr "标签管理"
#: assets/models/asset.py:
94
assets/models/base.py:29
#: assets/models/asset.py:
121
assets/models/base.py:29
#: assets/models/cluster.py:28 assets/models/group.py:21
#: assets/models/cluster.py:28 assets/models/group.py:21
#: assets/templates/assets/admin_user_detail.html:68
#: assets/templates/assets/admin_user_detail.html:68
#: assets/templates/assets/asset_detail.html:117
#: assets/templates/assets/asset_detail.html:117
...
@@ -312,11 +312,11 @@ msgstr "标签管理"
...
@@ -312,11 +312,11 @@ msgstr "标签管理"
#: assets/templates/assets/system_user_detail.html:96
#: assets/templates/assets/system_user_detail.html:96
#: ops/templates/ops/adhoc_detail.html:86 perms/models.py:38 perms/models.py:81
#: ops/templates/ops/adhoc_detail.html:86 perms/models.py:38 perms/models.py:81
#: perms/templates/perms/asset_permission_detail.html:98
#: perms/templates/perms/asset_permission_detail.html:98
#: users/models/user.py:
83 users/templates/users/user_detail.html:107
#: users/models/user.py:
90 users/templates/users/user_detail.html:111
msgid "Created by"
msgid "Created by"
msgstr "创建者"
msgstr "创建者"
#: assets/models/asset.py:
95
assets/models/cluster.py:26
#: assets/models/asset.py:
124
assets/models/cluster.py:26
#: assets/models/domain.py:20 assets/models/group.py:22
#: assets/models/domain.py:20 assets/models/group.py:22
#: assets/models/label.py:23 assets/templates/assets/admin_user_detail.html:64
#: assets/models/label.py:23 assets/templates/assets/admin_user_detail.html:64
#: assets/templates/assets/domain_detail.html:68
#: assets/templates/assets/domain_detail.html:68
...
@@ -324,12 +324,12 @@ msgstr "创建者"
...
@@ -324,12 +324,12 @@ msgstr "创建者"
#: ops/templates/ops/adhoc_detail.html:90 ops/templates/ops/task_detail.html:63
#: ops/templates/ops/adhoc_detail.html:90 ops/templates/ops/task_detail.html:63
#: perms/models.py:39 perms/models.py:82
#: perms/models.py:39 perms/models.py:82
#: perms/templates/perms/asset_permission_detail.html:94
#: perms/templates/perms/asset_permission_detail.html:94
#: terminal/templates/terminal/terminal_detail.html:59 users/models/group.py:1
7
#: terminal/templates/terminal/terminal_detail.html:59 users/models/group.py:1
5
#: users/templates/users/user_group_detail.html:63
#: users/templates/users/user_group_detail.html:63
msgid "Date created"
msgid "Date created"
msgstr "创建日期"
msgstr "创建日期"
#: assets/models/asset.py:
9
6 assets/models/base.py:26
#: assets/models/asset.py:
12
6 assets/models/base.py:26
#: assets/models/cluster.py:29 assets/models/domain.py:18
#: assets/models/cluster.py:29 assets/models/domain.py:18
#: assets/models/domain.py:47 assets/models/group.py:23
#: assets/models/domain.py:47 assets/models/group.py:23
#: assets/models/label.py:21 assets/templates/assets/admin_user_detail.html:72
#: assets/models/label.py:21 assets/templates/assets/admin_user_detail.html:72
...
@@ -342,11 +342,11 @@ msgstr "创建日期"
...
@@ -342,11 +342,11 @@ msgstr "创建日期"
#: assets/templates/assets/system_user_list.html:33 common/models.py:30
#: assets/templates/assets/system_user_list.html:33 common/models.py:30
#: ops/models/adhoc.py:42 perms/models.py:40 perms/models.py:83
#: ops/models/adhoc.py:42 perms/models.py:40 perms/models.py:83
#: perms/templates/perms/asset_permission_detail.html:102 terminal/models.py:26
#: perms/templates/perms/asset_permission_detail.html:102 terminal/models.py:26
#: terminal/templates/terminal/terminal_detail.html:63 users/models/group.py:1
5
#: terminal/templates/terminal/terminal_detail.html:63 users/models/group.py:1
3
#: users/models/user.py:
75 users/templates/users/user_detail.html:119
#: users/models/user.py:
82 users/templates/users/user_detail.html:123
#: users/templates/users/user_group_detail.html:67
#: users/templates/users/user_group_detail.html:67
#: users/templates/users/user_group_list.html:14
#: users/templates/users/user_group_list.html:14
#: users/templates/users/user_profile.html:1
23
#: users/templates/users/user_profile.html:1
30
msgid "Comment"
msgid "Comment"
msgstr "备注"
msgstr "备注"
...
@@ -366,7 +366,7 @@ msgstr "带宽"
...
@@ -366,7 +366,7 @@ msgstr "带宽"
msgid "Contact"
msgid "Contact"
msgstr "联系人"
msgstr "联系人"
#: assets/models/cluster.py:22 users/models/user.py:6
1
#: assets/models/cluster.py:22 users/models/user.py:6
8
#: users/templates/users/user_detail.html:76
#: users/templates/users/user_detail.html:76
msgid "Phone"
msgid "Phone"
msgstr "手机"
msgstr "手机"
...
@@ -392,7 +392,7 @@ msgid "Default"
...
@@ -392,7 +392,7 @@ msgid "Default"
msgstr "默认"
msgstr "默认"
#: assets/models/cluster.py:36 assets/models/label.py:13
#: assets/models/cluster.py:36 assets/models/label.py:13
#: users/models/user.py:3
30
#: users/models/user.py:3
43
msgid "System"
msgid "System"
msgstr "系统"
msgstr "系统"
...
@@ -432,13 +432,13 @@ msgstr "默认资产组"
...
@@ -432,13 +432,13 @@ msgstr "默认资产组"
#: terminal/templates/terminal/command_list.html:72
#: terminal/templates/terminal/command_list.html:72
#: terminal/templates/terminal/session_list.html:33
#: terminal/templates/terminal/session_list.html:33
#: terminal/templates/terminal/session_list.html:71 users/forms.py:281
#: terminal/templates/terminal/session_list.html:71 users/forms.py:281
#: users/models/user.py:3
0 users/models/user.py:318
#: users/models/user.py:3
1 users/models/user.py:331
#: users/templates/users/user_group_detail.html:78
#: users/templates/users/user_group_detail.html:78
#: users/templates/users/user_group_list.html:13 users/views/user.py:3
39
#: users/templates/users/user_group_list.html:13 users/views/user.py:3
62
msgid "User"
msgid "User"
msgstr "用户"
msgstr "用户"
#: assets/models/label.py:18 assets/models/node.py:1
8
#: assets/models/label.py:18 assets/models/node.py:1
6
#: assets/templates/assets/label_list.html:15 common/models.py:27
#: assets/templates/assets/label_list.html:15 common/models.py:27
msgid "Value"
msgid "Value"
msgstr "值"
msgstr "值"
...
@@ -447,7 +447,7 @@ msgstr "值"
...
@@ -447,7 +447,7 @@ msgstr "值"
msgid "Category"
msgid "Category"
msgstr "分类"
msgstr "分类"
#: assets/models/node.py:1
4
#: assets/models/node.py:1
5
msgid "Key"
msgid "Key"
msgstr ""
msgstr ""
...
@@ -630,16 +630,17 @@ msgstr "其它"
...
@@ -630,16 +630,17 @@ msgstr "其它"
#: assets/templates/assets/domain_create_update.html:16
#: assets/templates/assets/domain_create_update.html:16
#: assets/templates/assets/gateway_create_update.html:58
#: assets/templates/assets/gateway_create_update.html:58
#: assets/templates/assets/label_create_update.html:18
#: assets/templates/assets/label_create_update.html:18
#: common/templates/common/basic_setting.html:58
#: common/templates/common/basic_setting.html:61
#: common/templates/common/email_setting.html:59
#: common/templates/common/email_setting.html:62
#: common/templates/common/ldap_setting.html:59
#: common/templates/common/ldap_setting.html:62
#: common/templates/common/terminal_setting.html:101
#: common/templates/common/security_setting.html:70
#: common/templates/common/terminal_setting.html:106
#: perms/templates/perms/asset_permission_create_update.html:69
#: perms/templates/perms/asset_permission_create_update.html:69
#: terminal/templates/terminal/terminal_update.html:47
#: terminal/templates/terminal/terminal_update.html:47
#: users/templates/users/_user.html:46
#: users/templates/users/_user.html:46
#: users/templates/users/user_bulk_update.html:23
#: users/templates/users/user_bulk_update.html:23
#: users/templates/users/user_password_update.html:
58
#: users/templates/users/user_password_update.html:
70
#: users/templates/users/user_profile.html:18
1
#: users/templates/users/user_profile.html:18
8
#: users/templates/users/user_profile_update.html:63
#: users/templates/users/user_profile_update.html:63
#: users/templates/users/user_pubkey_update.html:70
#: users/templates/users/user_pubkey_update.html:70
#: users/templates/users/user_pubkey_update.html:76
#: users/templates/users/user_pubkey_update.html:76
...
@@ -650,23 +651,24 @@ msgstr "重置"
...
@@ -650,23 +651,24 @@ msgstr "重置"
#: assets/templates/assets/admin_user_create_update.html:46
#: assets/templates/assets/admin_user_create_update.html:46
#: assets/templates/assets/asset_bulk_update.html:24
#: assets/templates/assets/asset_bulk_update.html:24
#: assets/templates/assets/asset_create.html:67
#: assets/templates/assets/asset_create.html:67
#: assets/templates/assets/asset_list.html:10
7
#: assets/templates/assets/asset_list.html:10
8
#: assets/templates/assets/asset_update.html:71
#: assets/templates/assets/asset_update.html:71
#: assets/templates/assets/domain_create_update.html:17
#: assets/templates/assets/domain_create_update.html:17
#: assets/templates/assets/gateway_create_update.html:59
#: assets/templates/assets/gateway_create_update.html:59
#: assets/templates/assets/label_create_update.html:19
#: assets/templates/assets/label_create_update.html:19
#: common/templates/common/basic_setting.html:59
#: common/templates/common/basic_setting.html:62
#: common/templates/common/email_setting.html:60
#: common/templates/common/email_setting.html:63
#: common/templates/common/ldap_setting.html:60
#: common/templates/common/ldap_setting.html:63
#: common/templates/common/terminal_setting.html:103
#: common/templates/common/security_setting.html:71
#: common/templates/common/terminal_setting.html:108
#: perms/templates/perms/asset_permission_create_update.html:70
#: perms/templates/perms/asset_permission_create_update.html:70
#: terminal/templates/terminal/session_list.html:124
#: terminal/templates/terminal/session_list.html:124
#: terminal/templates/terminal/terminal_update.html:48
#: terminal/templates/terminal/terminal_update.html:48
#: users/templates/users/_user.html:47
#: users/templates/users/_user.html:47
#: users/templates/users/forgot_password.html:44
#: users/templates/users/forgot_password.html:44
#: users/templates/users/user_bulk_update.html:24
#: users/templates/users/user_bulk_update.html:24
#: users/templates/users/user_list.html:4
4
#: users/templates/users/user_list.html:4
5
#: users/templates/users/user_password_update.html:
59
#: users/templates/users/user_password_update.html:
71
#: users/templates/users/user_profile_update.html:64
#: users/templates/users/user_profile_update.html:64
#: users/templates/users/user_pubkey_update.html:77
#: users/templates/users/user_pubkey_update.html:77
msgid "Submit"
msgid "Submit"
...
@@ -727,7 +729,7 @@ msgstr "测试"
...
@@ -727,7 +729,7 @@ msgstr "测试"
#: assets/templates/assets/admin_user_detail.html:24
#: assets/templates/assets/admin_user_detail.html:24
#: assets/templates/assets/admin_user_list.html:85
#: assets/templates/assets/admin_user_list.html:85
#: assets/templates/assets/asset_detail.html:24
#: assets/templates/assets/asset_detail.html:24
#: assets/templates/assets/asset_list.html:17
4
#: assets/templates/assets/asset_list.html:17
5
#: assets/templates/assets/domain_detail.html:24
#: assets/templates/assets/domain_detail.html:24
#: assets/templates/assets/domain_detail.html:103
#: assets/templates/assets/domain_detail.html:103
#: assets/templates/assets/domain_gateway_list.html:85
#: assets/templates/assets/domain_gateway_list.html:85
...
@@ -742,16 +744,16 @@ msgstr "测试"
...
@@ -742,16 +744,16 @@ msgstr "测试"
#: users/templates/users/user_detail.html:25
#: users/templates/users/user_detail.html:25
#: users/templates/users/user_group_detail.html:28
#: users/templates/users/user_group_detail.html:28
#: users/templates/users/user_group_list.html:43
#: users/templates/users/user_group_list.html:43
#: users/templates/users/user_list.html:7
6
#: users/templates/users/user_list.html:7
7
#: users/templates/users/user_profile.html:1
44
#: users/templates/users/user_profile.html:1
51
#: users/templates/users/user_profile.html:1
73
#: users/templates/users/user_profile.html:1
80
msgid "Update"
msgid "Update"
msgstr "更新"
msgstr "更新"
#: assets/templates/assets/admin_user_detail.html:28
#: assets/templates/assets/admin_user_detail.html:28
#: assets/templates/assets/admin_user_list.html:86
#: assets/templates/assets/admin_user_list.html:86
#: assets/templates/assets/asset_detail.html:28
#: assets/templates/assets/asset_detail.html:28
#: assets/templates/assets/asset_list.html:17
5
#: assets/templates/assets/asset_list.html:17
6
#: assets/templates/assets/domain_detail.html:28
#: assets/templates/assets/domain_detail.html:28
#: assets/templates/assets/domain_detail.html:104
#: assets/templates/assets/domain_detail.html:104
#: assets/templates/assets/domain_gateway_list.html:86
#: assets/templates/assets/domain_gateway_list.html:86
...
@@ -766,8 +768,8 @@ msgstr "更新"
...
@@ -766,8 +768,8 @@ msgstr "更新"
#: users/templates/users/user_detail.html:30
#: users/templates/users/user_detail.html:30
#: users/templates/users/user_group_detail.html:32
#: users/templates/users/user_group_detail.html:32
#: users/templates/users/user_group_list.html:45
#: users/templates/users/user_group_list.html:45
#: users/templates/users/user_list.html:8
0
#: users/templates/users/user_list.html:8
1
#: users/templates/users/user_list.html:8
4
#: users/templates/users/user_list.html:8
5
msgid "Delete"
msgid "Delete"
msgstr "删除"
msgstr "删除"
...
@@ -782,17 +784,17 @@ msgstr "选择节点"
...
@@ -782,17 +784,17 @@ msgstr "选择节点"
#: assets/templates/assets/admin_user_detail.html:100
#: assets/templates/assets/admin_user_detail.html:100
#: assets/templates/assets/asset_detail.html:200
#: assets/templates/assets/asset_detail.html:200
#: assets/templates/assets/asset_list.html:63
6
#: assets/templates/assets/asset_list.html:63
8
#: assets/templates/assets/system_user_detail.html:192
#: assets/templates/assets/system_user_detail.html:192
#: assets/templates/assets/system_user_list.html:138 templates/_modal.html:22
#: assets/templates/assets/system_user_list.html:138 templates/_modal.html:22
#: terminal/templates/terminal/session_detail.html:108
#: terminal/templates/terminal/session_detail.html:108
#: users/templates/users/user_detail.html:36
2
#: users/templates/users/user_detail.html:36
6
#: users/templates/users/user_detail.html:3
87
#: users/templates/users/user_detail.html:3
91
#: users/templates/users/user_detail.html:41
0
#: users/templates/users/user_detail.html:41
4
#: users/templates/users/user_group_create_update.html:32
#: users/templates/users/user_group_create_update.html:32
#: users/templates/users/user_group_list.html:86
#: users/templates/users/user_group_list.html:86
#: users/templates/users/user_list.html:
199
#: users/templates/users/user_list.html:
200
#: users/templates/users/user_profile.html:2
15
#: users/templates/users/user_profile.html:2
22
msgid "Confirm"
msgid "Confirm"
msgstr "确认"
msgstr "确认"
...
@@ -814,7 +816,7 @@ msgid "Ratio"
...
@@ -814,7 +816,7 @@ msgid "Ratio"
msgstr "比例"
msgstr "比例"
#: assets/templates/assets/admin_user_list.html:30
#: assets/templates/assets/admin_user_list.html:30
#: assets/templates/assets/asset_list.html:9
0
#: assets/templates/assets/asset_list.html:9
1
#: assets/templates/assets/domain_gateway_list.html:62
#: assets/templates/assets/domain_gateway_list.html:62
#: assets/templates/assets/domain_list.html:18
#: assets/templates/assets/domain_list.html:18
#: assets/templates/assets/label_list.html:17
#: assets/templates/assets/label_list.html:17
...
@@ -825,7 +827,7 @@ msgstr "比例"
...
@@ -825,7 +827,7 @@ msgstr "比例"
#: terminal/templates/terminal/session_list.html:80
#: terminal/templates/terminal/session_list.html:80
#: terminal/templates/terminal/terminal_list.html:36
#: terminal/templates/terminal/terminal_list.html:36
#: users/templates/users/user_group_list.html:15
#: users/templates/users/user_group_list.html:15
#: users/templates/users/user_list.html:2
8
#: users/templates/users/user_list.html:2
9
msgid "Action"
msgid "Action"
msgstr "动作"
msgstr "动作"
...
@@ -842,20 +844,20 @@ msgid "Disk"
...
@@ -842,20 +844,20 @@ msgid "Disk"
msgstr "硬盘"
msgstr "硬盘"
#: assets/templates/assets/asset_detail.html:121
#: assets/templates/assets/asset_detail.html:121
#: users/templates/users/user_detail.html:11
1
#: users/templates/users/user_detail.html:11
5
#: users/templates/users/user_profile.html:
97
#: users/templates/users/user_profile.html:
104
msgid "Date joined"
msgid "Date joined"
msgstr "创建日期"
msgstr "创建日期"
#: assets/templates/assets/asset_detail.html:137
#: assets/templates/assets/asset_detail.html:137
#: terminal/templates/terminal/session_detail.html:81
#: terminal/templates/terminal/session_detail.html:81
#: users/templates/users/user_detail.html:13
0
#: users/templates/users/user_detail.html:13
4
#: users/templates/users/user_profile.html:1
35
#: users/templates/users/user_profile.html:1
42
msgid "Quick modify"
msgid "Quick modify"
msgstr "快速修改"
msgstr "快速修改"
#: assets/templates/assets/asset_detail.html:143
#: assets/templates/assets/asset_detail.html:143
#: assets/templates/assets/asset_list.html:8
8
#: assets/templates/assets/asset_list.html:8
9
#: assets/templates/assets/user_asset_list.html:47 perms/models.py:35
#: assets/templates/assets/user_asset_list.html:47 perms/models.py:35
#: perms/models.py:79
#: perms/models.py:79
#: perms/templates/perms/asset_permission_create_update.html:47
#: perms/templates/perms/asset_permission_create_update.html:47
...
@@ -863,10 +865,10 @@ msgstr "快速修改"
...
@@ -863,10 +865,10 @@ msgstr "快速修改"
#: perms/templates/perms/asset_permission_list.html:59
#: perms/templates/perms/asset_permission_list.html:59
#: terminal/templates/terminal/terminal_list.html:34
#: terminal/templates/terminal/terminal_list.html:34
#: users/templates/users/_select_user_modal.html:18
#: users/templates/users/_select_user_modal.html:18
#: users/templates/users/user_detail.html:1
36
#: users/templates/users/user_detail.html:1
40
#: users/templates/users/user_granted_asset.html:46
#: users/templates/users/user_granted_asset.html:46
#: users/templates/users/user_group_granted_asset.html:46
#: users/templates/users/user_group_granted_asset.html:46
#: users/templates/users/user_list.html:2
7
#: users/templates/users/user_list.html:2
8
#: users/templates/users/user_profile.html:63
#: users/templates/users/user_profile.html:63
msgid "Active"
msgid "Active"
msgstr "激活中"
msgstr "激活中"
...
@@ -880,124 +882,124 @@ msgid "Refresh"
...
@@ -880,124 +882,124 @@ msgid "Refresh"
msgstr "刷新"
msgstr "刷新"
#: assets/templates/assets/asset_detail.html:300
#: assets/templates/assets/asset_detail.html:300
#: users/templates/users/user_detail.html:28
2
#: users/templates/users/user_detail.html:28
6
#: users/templates/users/user_detail.html:3
09
#: users/templates/users/user_detail.html:3
13
msgid "Update successfully!"
msgid "Update successfully!"
msgstr "更新成功"
msgstr "更新成功"
#: assets/templates/assets/asset_list.html:6
2
assets/views/asset.py:97
#: assets/templates/assets/asset_list.html:6
3
assets/views/asset.py:97
msgid "Create asset"
msgid "Create asset"
msgstr "创建资产"
msgstr "创建资产"
#: assets/templates/assets/asset_list.html:6
6
#: assets/templates/assets/asset_list.html:6
7
#: users/templates/users/user_list.html:7
#: users/templates/users/user_list.html:7
msgid "Import"
msgid "Import"
msgstr "导入"
msgstr "导入"
#: assets/templates/assets/asset_list.html:
69
#: assets/templates/assets/asset_list.html:
70
#: users/templates/users/user_list.html:10
#: users/templates/users/user_list.html:10
msgid "Export"
msgid "Export"
msgstr "导出"
msgstr "导出"
#: assets/templates/assets/asset_list.html:8
7
#: assets/templates/assets/asset_list.html:8
8
msgid "Hardware"
msgid "Hardware"
msgstr "硬件"
msgstr "硬件"
#: assets/templates/assets/asset_list.html:
99
#: assets/templates/assets/asset_list.html:
100
#: users/templates/users/user_list.html:3
7
#: users/templates/users/user_list.html:3
8
msgid "Delete selected"
msgid "Delete selected"
msgstr "批量删除"
msgstr "批量删除"
#: assets/templates/assets/asset_list.html:10
0
#: assets/templates/assets/asset_list.html:10
1
#: users/templates/users/user_list.html:3
8
#: users/templates/users/user_list.html:3
9
msgid "Update selected"
msgid "Update selected"
msgstr "批量更新"
msgstr "批量更新"
#: assets/templates/assets/asset_list.html:10
1
#: assets/templates/assets/asset_list.html:10
2
msgid "Remove from this node"
msgid "Remove from this node"
msgstr "从节点移除"
msgstr "从节点移除"
#: assets/templates/assets/asset_list.html:10
2
#: assets/templates/assets/asset_list.html:10
3
#: users/templates/users/user_list.html:
39
#: users/templates/users/user_list.html:
40
msgid "Deactive selected"
msgid "Deactive selected"
msgstr "禁用所选"
msgstr "禁用所选"
#: assets/templates/assets/asset_list.html:10
3
#: assets/templates/assets/asset_list.html:10
4
#: users/templates/users/user_list.html:4
0
#: users/templates/users/user_list.html:4
1
msgid "Active selected"
msgid "Active selected"
msgstr "激活所选"
msgstr "激活所选"
#: assets/templates/assets/asset_list.html:12
0
#: assets/templates/assets/asset_list.html:12
1
msgid "Add node"
msgid "Add node"
msgstr "新建节点"
msgstr "新建节点"
#: assets/templates/assets/asset_list.html:12
1
#: assets/templates/assets/asset_list.html:12
2
msgid "Rename node"
msgid "Rename node"
msgstr "重命名节点"
msgstr "重命名节点"
#: assets/templates/assets/asset_list.html:12
2
#: assets/templates/assets/asset_list.html:12
3
msgid "Delete node"
msgid "Delete node"
msgstr "删除节点"
msgstr "删除节点"
#: assets/templates/assets/asset_list.html:12
4
#: assets/templates/assets/asset_list.html:12
5
msgid "Add assets to node"
msgid "Add assets to node"
msgstr "添加资产到节点"
msgstr "添加资产到节点"
#: assets/templates/assets/asset_list.html:12
5
#: assets/templates/assets/asset_list.html:12
6
msgid "Move assets to node"
msgid "Move assets to node"
msgstr "移动资产到节点"
msgstr "移动资产到节点"
#: assets/templates/assets/asset_list.html:12
7
#: assets/templates/assets/asset_list.html:12
8
msgid "Refresh node hardware info"
msgid "Refresh node hardware info"
msgstr "更新节点资产硬件信息"
msgstr "更新节点资产硬件信息"
#: assets/templates/assets/asset_list.html:12
8
#: assets/templates/assets/asset_list.html:12
9
msgid "Test node connective"
msgid "Test node connective"
msgstr "测试节点资产可连接性"
msgstr "测试节点资产可连接性"
#: assets/templates/assets/asset_list.html:13
0
#: assets/templates/assets/asset_list.html:13
1
msgid "Display only current node assets"
msgid "Display only current node assets"
msgstr "仅显示当前节点资产"
msgstr "仅显示当前节点资产"
#: assets/templates/assets/asset_list.html:13
1
#: assets/templates/assets/asset_list.html:13
2
msgid "Displays all child node assets"
msgid "Displays all child node assets"
msgstr "显示所有子节点资产"
msgstr "显示所有子节点资产"
#: assets/templates/assets/asset_list.html:21
7
#: assets/templates/assets/asset_list.html:21
8
msgid "Create node failed"
msgid "Create node failed"
msgstr "创建节点失败"
msgstr "创建节点失败"
#: assets/templates/assets/asset_list.html:2
29
#: assets/templates/assets/asset_list.html:2
30
msgid "Have child node, cancel"
msgid "Have child node, cancel"
msgstr "存在子节点,不能删除"
msgstr "存在子节点,不能删除"
#: assets/templates/assets/asset_list.html:23
1
#: assets/templates/assets/asset_list.html:23
2
msgid "Have assets, cancel"
msgid "Have assets, cancel"
msgstr "存在资产,不能删除"
msgstr "存在资产,不能删除"
#: assets/templates/assets/asset_list.html:63
1
#: assets/templates/assets/asset_list.html:63
3
#: assets/templates/assets/system_user_list.html:133
#: assets/templates/assets/system_user_list.html:133
#: users/templates/users/user_detail.html:3
57
#: users/templates/users/user_detail.html:3
61
#: users/templates/users/user_detail.html:38
2
#: users/templates/users/user_detail.html:38
6
#: users/templates/users/user_group_list.html:81
#: users/templates/users/user_group_list.html:81
#: users/templates/users/user_list.html:19
4
#: users/templates/users/user_list.html:19
5
msgid "Are you sure?"
msgid "Are you sure?"
msgstr "你确认吗?"
msgstr "你确认吗?"
#: assets/templates/assets/asset_list.html:63
2
#: assets/templates/assets/asset_list.html:63
4
msgid "This will delete the selected assets !!!"
msgid "This will delete the selected assets !!!"
msgstr "删除选择资产"
msgstr "删除选择资产"
#: assets/templates/assets/asset_list.html:64
0
#: assets/templates/assets/asset_list.html:64
2
msgid "Asset Deleted."
msgid "Asset Deleted."
msgstr "已被删除"
msgstr "已被删除"
#: assets/templates/assets/asset_list.html:64
1
#: assets/templates/assets/asset_list.html:64
3
#: assets/templates/assets/asset_list.html:64
6
#: assets/templates/assets/asset_list.html:64
8
msgid "Asset Delete"
msgid "Asset Delete"
msgstr "删除"
msgstr "删除"
#: assets/templates/assets/asset_list.html:64
5
#: assets/templates/assets/asset_list.html:64
7
msgid "Asset Deleting failed."
msgid "Asset Deleting failed."
msgstr "删除失败"
msgstr "删除失败"
...
@@ -1033,8 +1035,8 @@ msgstr "创建网关"
...
@@ -1033,8 +1035,8 @@ msgstr "创建网关"
#: assets/templates/assets/domain_gateway_list.html:87
#: assets/templates/assets/domain_gateway_list.html:87
#: assets/templates/assets/domain_gateway_list.html:89
#: assets/templates/assets/domain_gateway_list.html:89
#: common/templates/common/email_setting.html:
58
#: common/templates/common/email_setting.html:
61
#: common/templates/common/ldap_setting.html:
58
#: common/templates/common/ldap_setting.html:
61
msgid "Test connection"
msgid "Test connection"
msgstr "测试连接"
msgstr "测试连接"
...
@@ -1237,11 +1239,11 @@ msgstr "FTP日志"
...
@@ -1237,11 +1239,11 @@ msgstr "FTP日志"
msgid "Test mail sent to {}, please check"
msgid "Test mail sent to {}, please check"
msgstr "邮件已经发送{}, 请检查"
msgstr "邮件已经发送{}, 请检查"
#: common/api.py:
5
2
#: common/api.py:
4
2
msgid "Test ldap success"
msgid "Test ldap success"
msgstr "连接LDAP成功"
msgstr "连接LDAP成功"
#: common/api.py:
9
0
#: common/api.py:
8
0
msgid "Match {} s users"
msgid "Match {} s users"
msgstr "匹配 {} 个用户"
msgstr "匹配 {} 个用户"
...
@@ -1376,7 +1378,7 @@ msgstr "密码认证"
...
@@ -1376,7 +1378,7 @@ msgstr "密码认证"
msgid "Public key auth"
msgid "Public key auth"
msgstr "密钥认证"
msgstr "密钥认证"
#: common/forms.py:159 common/templates/common/terminal_setting.html:6
3
#: common/forms.py:159 common/templates/common/terminal_setting.html:6
8
#: terminal/forms.py:30 terminal/models.py:20
#: terminal/forms.py:30 terminal/models.py:20
msgid "Command storage"
msgid "Command storage"
msgstr "命令存储"
msgstr "命令存储"
...
@@ -1387,7 +1389,7 @@ msgid ""
...
@@ -1387,7 +1389,7 @@ msgid ""
"other storage and some terminal using"
"other storage and some terminal using"
msgstr "设置终端命令存储,default是默认用的存储方式"
msgstr "设置终端命令存储,default是默认用的存储方式"
#: common/forms.py:165 common/templates/common/terminal_setting.html:8
1
#: common/forms.py:165 common/templates/common/terminal_setting.html:8
6
#: terminal/forms.py:35 terminal/models.py:21
#: terminal/forms.py:35 terminal/models.py:21
msgid "Replay storage"
msgid "Replay storage"
msgstr "录像存储"
msgstr "录像存储"
...
@@ -1398,6 +1400,60 @@ msgid ""
...
@@ -1398,6 +1400,60 @@ msgid ""
"other storage and some terminal using"
"other storage and some terminal using"
msgstr "设置终端录像存储,default是默认用的存储方式"
msgstr "设置终端录像存储,default是默认用的存储方式"
#: common/forms.py:176
msgid "MFA Secondary certification"
msgstr "MFA 二次认证"
#: common/forms.py:178
msgid ""
"After opening, the user login must use MFA secondary authentication (valid "
"for all users, including administrators)"
msgstr "开启后,用户登录必须使用MFA二次认证(对所有用户有效,包括管理员)"
#: common/forms.py:184
msgid "Password minimum length"
msgstr "密码最小长度 "
#: common/forms.py:191
msgid "Must contain capital letters"
msgstr "必须包含大写字母"
#: common/forms.py:193
msgid ""
"After opening, the user password changes and resets must contain uppercase "
"letters"
msgstr "开启后,用户密码修改、重置必须包含大写字母"
#: common/forms.py:199
msgid "Must contain lowercase letters"
msgstr "必须包含小写字母"
#: common/forms.py:200
msgid ""
"After opening, the user password changes and resets must contain lowercase "
"letters"
msgstr "开启后,用户密码修改、重置必须包含小写字母"
#: common/forms.py:206
msgid "Must contain numeric characters"
msgstr "必须包含数字字符"
#: common/forms.py:207
msgid ""
"After opening, the user password changes and resets must contain numeric "
"characters"
msgstr "开启后,用户密码修改、重置必须包含数字字符"
#: common/forms.py:213
msgid "Must contain special characters"
msgstr "必须包含特殊字符"
#: common/forms.py:214
msgid ""
"After opening, the user password changes and resets must contain special "
"characters"
msgstr "开启后,用户密码修改、重置必须包含特殊字符"
#: common/mixins.py:29
#: common/mixins.py:29
msgid "is discard"
msgid "is discard"
msgstr ""
msgstr ""
...
@@ -1413,14 +1469,16 @@ msgstr "启用"
...
@@ -1413,14 +1469,16 @@ msgstr "启用"
#: common/templates/common/basic_setting.html:15
#: common/templates/common/basic_setting.html:15
#: common/templates/common/email_setting.html:15
#: common/templates/common/email_setting.html:15
#: common/templates/common/ldap_setting.html:15
#: common/templates/common/ldap_setting.html:15
#: common/templates/common/security_setting.html:15
#: common/templates/common/terminal_setting.html:16
#: common/templates/common/terminal_setting.html:16
#: common/templates/common/terminal_setting.html:4
2
common/views.py:22
#: common/templates/common/terminal_setting.html:4
6
common/views.py:22
msgid "Basic setting"
msgid "Basic setting"
msgstr "基本设置"
msgstr "基本设置"
#: common/templates/common/basic_setting.html:18
#: common/templates/common/basic_setting.html:18
#: common/templates/common/email_setting.html:18
#: common/templates/common/email_setting.html:18
#: common/templates/common/ldap_setting.html:18
#: common/templates/common/ldap_setting.html:18
#: common/templates/common/security_setting.html:18
#: common/templates/common/terminal_setting.html:20 common/views.py:48
#: common/templates/common/terminal_setting.html:20 common/views.py:48
msgid "Email setting"
msgid "Email setting"
msgstr "邮件设置"
msgstr "邮件设置"
...
@@ -1428,6 +1486,7 @@ msgstr "邮件设置"
...
@@ -1428,6 +1486,7 @@ msgstr "邮件设置"
#: common/templates/common/basic_setting.html:21
#: common/templates/common/basic_setting.html:21
#: common/templates/common/email_setting.html:21
#: common/templates/common/email_setting.html:21
#: common/templates/common/ldap_setting.html:21
#: common/templates/common/ldap_setting.html:21
#: common/templates/common/security_setting.html:21
#: common/templates/common/terminal_setting.html:24 common/views.py:74
#: common/templates/common/terminal_setting.html:24 common/views.py:74
msgid "LDAP setting"
msgid "LDAP setting"
msgstr "LDAP设置"
msgstr "LDAP设置"
...
@@ -1435,12 +1494,29 @@ msgstr "LDAP设置"
...
@@ -1435,12 +1494,29 @@ msgstr "LDAP设置"
#: common/templates/common/basic_setting.html:24
#: common/templates/common/basic_setting.html:24
#: common/templates/common/email_setting.html:24
#: common/templates/common/email_setting.html:24
#: common/templates/common/ldap_setting.html:24
#: common/templates/common/ldap_setting.html:24
#: common/templates/common/security_setting.html:24
#: common/templates/common/terminal_setting.html:28 common/views.py:104
#: common/templates/common/terminal_setting.html:28 common/views.py:104
msgid "Terminal setting"
msgid "Terminal setting"
msgstr "终端设置"
msgstr "终端设置"
#: common/templates/common/terminal_setting.html:68
#: common/templates/common/basic_setting.html:27
#: common/templates/common/terminal_setting.html:86
#: common/templates/common/email_setting.html:27
#: common/templates/common/ldap_setting.html:27
#: common/templates/common/security_setting.html:27
#: common/templates/common/terminal_setting.html:31 common/views.py:132
msgid "Security setting"
msgstr "安全设置"
#: common/templates/common/security_setting.html:42
msgid "MFA setting"
msgstr "MFA 设置"
#: common/templates/common/security_setting.html:46
msgid "Password check rule"
msgstr "密码校验规则"
#: common/templates/common/terminal_setting.html:73
#: common/templates/common/terminal_setting.html:91
#: users/templates/users/login_log_list.html:50
#: users/templates/users/login_log_list.html:50
msgid "Type"
msgid "Type"
msgstr "类型"
msgstr "类型"
...
@@ -1450,11 +1526,12 @@ msgid "Special char not allowed"
...
@@ -1450,11 +1526,12 @@ msgid "Special char not allowed"
msgstr "不能包含特殊字符"
msgstr "不能包含特殊字符"
#: common/views.py:21 common/views.py:47 common/views.py:73 common/views.py:103
#: common/views.py:21 common/views.py:47 common/views.py:73 common/views.py:103
#: templates/_nav.html:81
#:
common/views.py:131
templates/_nav.html:81
msgid "Settings"
msgid "Settings"
msgstr "系统设置"
msgstr "系统设置"
#: common/views.py:32 common/views.py:58 common/views.py:86 common/views.py:116
#: common/views.py:32 common/views.py:58 common/views.py:86 common/views.py:116
#: common/views.py:142
msgid "Update setting successfully, please restart program"
msgid "Update setting successfully, please restart program"
msgstr "更新设置成功, 请手动重启程序"
msgstr "更新设置成功, 请手动重启程序"
...
@@ -1736,9 +1813,9 @@ msgstr "选择用户"
...
@@ -1736,9 +1813,9 @@ msgstr "选择用户"
#: perms/forms.py:34 perms/models.py:31 perms/models.py:77
#: perms/forms.py:34 perms/models.py:31 perms/models.py:77
#: perms/templates/perms/asset_permission_list.html:55
#: perms/templates/perms/asset_permission_list.html:55
#: perms/templates/perms/asset_permission_list.html:136 templates/_nav.html:14
#: perms/templates/perms/asset_permission_list.html:136 templates/_nav.html:14
#: users/models/group.py:2
5 users/models/user.py:48
#: users/models/group.py:2
3 users/models/user.py:55
#: users/templates/users/_select_user_modal.html:16
#: users/templates/users/_select_user_modal.html:16
#: users/templates/users/user_detail.html:1
88
#: users/templates/users/user_detail.html:1
92
#: users/templates/users/user_list.html:26
#: users/templates/users/user_list.html:26
msgid "User group"
msgid "User group"
msgstr "用户组"
msgstr "用户组"
...
@@ -1753,8 +1830,8 @@ msgstr ""
...
@@ -1753,8 +1830,8 @@ msgstr ""
#: perms/models.py:37 perms/models.py:80
#: perms/models.py:37 perms/models.py:80
#: perms/templates/perms/asset_permission_detail.html:90
#: perms/templates/perms/asset_permission_detail.html:90
#: users/models/user.py:8
0 users/templates/users/user_detail.html:103
#: users/models/user.py:8
7 users/templates/users/user_detail.html:107
#: users/templates/users/user_profile.html:1
05
#: users/templates/users/user_profile.html:1
12
msgid "Date expired"
msgid "Date expired"
msgstr "失效日期"
msgstr "失效日期"
...
@@ -1791,7 +1868,7 @@ msgid "Add node to this permission"
...
@@ -1791,7 +1868,7 @@ msgid "Add node to this permission"
msgstr "添加节点"
msgstr "添加节点"
#: perms/templates/perms/asset_permission_asset.html:125
#: perms/templates/perms/asset_permission_asset.html:125
#: users/templates/users/user_detail.html:20
5
#: users/templates/users/user_detail.html:20
9
msgid "Join"
msgid "Join"
msgstr "加入"
msgstr "加入"
...
@@ -1884,11 +1961,11 @@ msgstr "文档"
...
@@ -1884,11 +1961,11 @@ msgstr "文档"
#: templates/_header_bar.html:37 templates/_nav_user.html:9 users/forms.py:121
#: templates/_header_bar.html:37 templates/_nav_user.html:9 users/forms.py:121
#: users/templates/users/_user.html:39
#: users/templates/users/_user.html:39
#: users/templates/users/first_login.html:39
#: users/templates/users/first_login.html:39
#: users/templates/users/user_password_update.html:3
7
#: users/templates/users/user_password_update.html:3
9
#: users/templates/users/user_profile.html:17
#: users/templates/users/user_profile.html:17
#: users/templates/users/user_profile_update.html:37
#: users/templates/users/user_profile_update.html:37
#: users/templates/users/user_profile_update.html:57
#: users/templates/users/user_profile_update.html:57
#: users/templates/users/user_pubkey_update.html:37 users/views/user.py:3
22
#: users/templates/users/user_pubkey_update.html:37 users/views/user.py:3
44
msgid "Profile"
msgid "Profile"
msgstr "个人信息"
msgstr "个人信息"
...
@@ -1945,13 +2022,13 @@ msgstr "关闭"
...
@@ -1945,13 +2022,13 @@ msgstr "关闭"
#: templates/_nav.html:10 users/views/group.py:28 users/views/group.py:44
#: templates/_nav.html:10 users/views/group.py:28 users/views/group.py:44
#: users/views/group.py:62 users/views/group.py:79 users/views/group.py:95
#: users/views/group.py:62 users/views/group.py:79 users/views/group.py:95
#: users/views/login.py:2
63 users/views/login.py:321 users/views/user.py:64
#: users/views/login.py:2
77 users/views/login.py:335 users/views/user.py:66
#: users/views/user.py:
79 users/views/user.py:99 users/views/user.py:155
#: users/views/user.py:
81 users/views/user.py:103 users/views/user.py:174
#: users/views/user.py:3
10 users/views/user.py:357 users/views/user.py:379
#: users/views/user.py:3
29 users/views/user.py:381 users/views/user.py:416
msgid "Users"
msgid "Users"
msgstr "用户管理"
msgstr "用户管理"
#: templates/_nav.html:13 users/views/user.py:6
5
#: templates/_nav.html:13 users/views/user.py:6
7
msgid "User list"
msgid "User list"
msgstr "用户列表"
msgstr "用户列表"
...
@@ -2261,7 +2338,7 @@ msgstr ""
...
@@ -2261,7 +2338,7 @@ msgstr ""
msgid "MFA code"
msgid "MFA code"
msgstr "MFA 验证码"
msgstr "MFA 验证码"
#: users/forms.py:49 users/models/user.py:5
2
#: users/forms.py:49 users/models/user.py:5
9
#: users/templates/users/_select_user_modal.html:15
#: users/templates/users/_select_user_modal.html:15
#: users/templates/users/user_detail.html:87
#: users/templates/users/user_detail.html:87
#: users/templates/users/user_list.html:25
#: users/templates/users/user_list.html:25
...
@@ -2281,7 +2358,7 @@ msgstr ""
...
@@ -2281,7 +2358,7 @@ msgstr ""
msgid "Paste user id_rsa.pub here."
msgid "Paste user id_rsa.pub here."
msgstr "复制用户公钥到这里"
msgstr "复制用户公钥到这里"
#: users/forms.py:72 users/templates/users/user_detail.html:
196
#: users/forms.py:72 users/templates/users/user_detail.html:
200
msgid "Join user groups"
msgid "Join user groups"
msgstr "添加到用户组"
msgstr "添加到用户组"
...
@@ -2289,7 +2366,7 @@ msgstr "添加到用户组"
...
@@ -2289,7 +2366,7 @@ msgstr "添加到用户组"
msgid "Public key should not be the same as your old one."
msgid "Public key should not be the same as your old one."
msgstr "不能和原来的密钥相同"
msgstr "不能和原来的密钥相同"
#: users/forms.py:87 users/forms.py:220 users/serializers.py:4
5
#: users/forms.py:87 users/forms.py:220 users/serializers.py:4
8
msgid "Not a valid ssh public key"
msgid "Not a valid ssh public key"
msgstr "ssh密钥不合法"
msgstr "ssh密钥不合法"
...
@@ -2306,7 +2383,7 @@ msgstr ""
...
@@ -2306,7 +2383,7 @@ msgstr ""
msgid "* Enable MFA authentication to make the account more secure."
msgid "* Enable MFA authentication to make the account more secure."
msgstr "* 启用MFA认证,使账号更加安全."
msgstr "* 启用MFA认证,使账号更加安全."
#: users/forms.py:142 users/models/user.py:
64
#: users/forms.py:142 users/models/user.py:
71
#: users/templates/users/first_login.html:45
#: users/templates/users/first_login.html:45
msgid "MFA"
msgid "MFA"
msgstr "MFA"
msgstr "MFA"
...
@@ -2354,9 +2431,9 @@ msgstr "自动配置并下载SSH密钥"
...
@@ -2354,9 +2431,9 @@ msgstr "自动配置并下载SSH密钥"
msgid "Paste your id_rsa.pub here."
msgid "Paste your id_rsa.pub here."
msgstr "复制你的公钥到这里"
msgstr "复制你的公钥到这里"
#: users/forms.py:231 users/models/user.py:7
2
#: users/forms.py:231 users/models/user.py:7
9
#: users/templates/users/first_login.html:42
#: users/templates/users/first_login.html:42
#: users/templates/users/user_password_update.html:4
3
#: users/templates/users/user_password_update.html:4
5
#: users/templates/users/user_profile.html:68
#: users/templates/users/user_profile.html:68
#: users/templates/users/user_profile_update.html:43
#: users/templates/users/user_profile_update.html:43
#: users/templates/users/user_pubkey_update.html:43
#: users/templates/users/user_pubkey_update.html:43
...
@@ -2387,43 +2464,49 @@ msgstr "Agent"
...
@@ -2387,43 +2464,49 @@ msgstr "Agent"
msgid "Date login"
msgid "Date login"
msgstr "登录日期"
msgstr "登录日期"
#: users/models/user.py:
29 users/models/user.py:326
#: users/models/user.py:
30 users/models/user.py:339
msgid "Administrator"
msgid "Administrator"
msgstr "管理员"
msgstr "管理员"
#: users/models/user.py:3
1
#: users/models/user.py:3
2
msgid "Application"
msgid "Application"
msgstr "应用程序"
msgstr "应用程序"
#: users/models/user.py:3
4
users/templates/users/user_profile.html:92
#: users/models/user.py:3
5
users/templates/users/user_profile.html:92
#: users/templates/users/user_profile.html:1
56
#: users/templates/users/user_profile.html:1
63
#: users/templates/users/user_profile.html:1
59
#: users/templates/users/user_profile.html:1
66
msgid "Disable"
msgid "Disable"
msgstr "禁用"
msgstr "禁用"
#: users/models/user.py:3
5
users/templates/users/user_profile.html:90
#: users/models/user.py:3
6
users/templates/users/user_profile.html:90
#: users/templates/users/user_profile.html:1
63
#: users/templates/users/user_profile.html:1
70
msgid "Enable"
msgid "Enable"
msgstr "启用"
msgstr "启用"
#: users/models/user.py:3
6
users/templates/users/user_profile.html:88
#: users/models/user.py:3
7
users/templates/users/user_profile.html:88
msgid "Force enable"
msgid "Force enable"
msgstr "强制启用"
msgstr "强制启用"
#: users/models/user.py:
44
users/templates/users/user_detail.html:71
#: users/models/user.py:
51
users/templates/users/user_detail.html:71
#: users/templates/users/user_profile.html:59
#: users/templates/users/user_profile.html:59
msgid "Email"
msgid "Email"
msgstr "邮件"
msgstr "邮件"
#: users/models/user.py:
55
#: users/models/user.py:
62
msgid "Avatar"
msgid "Avatar"
msgstr "头像"
msgstr "头像"
#: users/models/user.py:
58
users/templates/users/user_detail.html:82
#: users/models/user.py:
65
users/templates/users/user_detail.html:82
msgid "Wechat"
msgid "Wechat"
msgstr "微信"
msgstr "微信"
#: users/models/user.py:329
#: users/models/user.py:94 users/templates/users/user_detail.html:103
#: users/templates/users/user_list.html:27
#: users/templates/users/user_profile.html:100
msgid "Source"
msgstr "用户来源"
#: users/models/user.py:342
msgid "Administrator is the super user of system"
msgid "Administrator is the super user of system"
msgstr "Administrator是初始的超级管理员"
msgstr "Administrator是初始的超级管理员"
...
@@ -2539,22 +2622,34 @@ msgstr "6位数字"
...
@@ -2539,22 +2622,34 @@ msgstr "6位数字"
msgid "Can't provide security? Please contact the administrator!"
msgid "Can't provide security? Please contact the administrator!"
msgstr "如果不能提供MFA验证码,请联系管理员!"
msgstr "如果不能提供MFA验证码,请联系管理员!"
#: users/templates/users/reset_password.html:4
5
#: users/templates/users/reset_password.html:4
6
#: users/templates/users/user_detail.html:3
48 users/utils.py:76
#: users/templates/users/user_detail.html:3
52 users/utils.py:80
msgid "Reset password"
msgid "Reset password"
msgstr "重置密码"
msgstr "重置密码"
#: users/templates/users/reset_password.html:55
#: users/templates/users/reset_password.html:59
#: users/templates/users/user_password_update.html:60
#: users/templates/users/user_update.html:12
msgid "Your password must satisfy"
msgstr "您的密码必须满足:"
#: users/templates/users/reset_password.html:60
#: users/templates/users/user_password_update.html:61
#: users/templates/users/user_update.html:13
msgid "Password strength"
msgstr "密码强度:"
#: users/templates/users/reset_password.html:66
msgid "Password again"
msgid "Password again"
msgstr "再次输入密码"
msgstr "再次输入密码"
#: users/templates/users/reset_password.html:
57
#: users/templates/users/reset_password.html:
68
#: users/templates/users/user_profile.html:20
#: users/templates/users/user_profile.html:20
msgid "Setting"
msgid "Setting"
msgstr "设置"
msgstr "设置"
#: users/templates/users/user_create.html:4
#: users/templates/users/user_create.html:4
#: users/templates/users/user_list.html:16 users/views/user.py:
79
#: users/templates/users/user_list.html:16 users/views/user.py:
81
msgid "Create user"
msgid "Create user"
msgstr "创建用户"
msgstr "创建用户"
...
@@ -2563,7 +2658,7 @@ msgid "Reset link will be generated and sent to the user. "
...
@@ -2563,7 +2658,7 @@ msgid "Reset link will be generated and sent to the user. "
msgstr "生成重置密码连接,通过邮件发送给用户"
msgstr "生成重置密码连接,通过邮件发送给用户"
#: users/templates/users/user_detail.html:19
#: users/templates/users/user_detail.html:19
#: users/templates/users/user_granted_asset.html:18 users/views/user.py:1
56
#: users/templates/users/user_granted_asset.html:18 users/views/user.py:1
75
msgid "User detail"
msgid "User detail"
msgstr "用户详情"
msgstr "用户详情"
...
@@ -2582,63 +2677,63 @@ msgstr "强制启用"
...
@@ -2582,63 +2677,63 @@ msgstr "强制启用"
msgid "Disabled"
msgid "Disabled"
msgstr "禁用"
msgstr "禁用"
#: users/templates/users/user_detail.html:11
5
#: users/templates/users/user_detail.html:11
9
#: users/templates/users/user_profile.html:10
1
#: users/templates/users/user_profile.html:10
8
msgid "Last login"
msgid "Last login"
msgstr "最后登录"
msgstr "最后登录"
#: users/templates/users/user_detail.html:15
1
#: users/templates/users/user_detail.html:15
5
msgid "Force enabled MFA"
msgid "Force enabled MFA"
msgstr "强制启用MFA"
msgstr "强制启用MFA"
#: users/templates/users/user_detail.html:1
66
#: users/templates/users/user_detail.html:1
70
msgid "Send reset password mail"
msgid "Send reset password mail"
msgstr "发送重置密码邮件"
msgstr "发送重置密码邮件"
#: users/templates/users/user_detail.html:1
69
#: users/templates/users/user_detail.html:1
73
#: users/templates/users/user_detail.html:1
77
#: users/templates/users/user_detail.html:1
81
msgid "Send"
msgid "Send"
msgstr "发送"
msgstr "发送"
#: users/templates/users/user_detail.html:17
4
#: users/templates/users/user_detail.html:17
8
msgid "Send reset ssh key mail"
msgid "Send reset ssh key mail"
msgstr "发送重置密钥邮件"
msgstr "发送重置密钥邮件"
#: users/templates/users/user_detail.html:29
1
#: users/templates/users/user_detail.html:29
5
msgid "Goto profile page enable MFA"
msgid "Goto profile page enable MFA"
msgstr "请去个人信息页面启用自己的MFA"
msgstr "请去个人信息页面启用自己的MFA"
#: users/templates/users/user_detail.html:3
47
#: users/templates/users/user_detail.html:3
51
msgid "An e-mail has been sent to the user`s mailbox."
msgid "An e-mail has been sent to the user`s mailbox."
msgstr "已发送邮件到用户邮箱"
msgstr "已发送邮件到用户邮箱"
#: users/templates/users/user_detail.html:3
58
#: users/templates/users/user_detail.html:3
62
msgid "This will reset the user password and send a reset mail"
msgid "This will reset the user password and send a reset mail"
msgstr "将失效用户当前密码,并发送重设密码邮件到用户邮箱"
msgstr "将失效用户当前密码,并发送重设密码邮件到用户邮箱"
#: users/templates/users/user_detail.html:37
2
#: users/templates/users/user_detail.html:37
6
msgid ""
msgid ""
"The reset-ssh-public-key E-mail has been sent successfully. Please inform "
"The reset-ssh-public-key E-mail has been sent successfully. Please inform "
"the user to update his new ssh public key."
"the user to update his new ssh public key."
msgstr "重设密钥邮件将会发送到用户邮箱"
msgstr "重设密钥邮件将会发送到用户邮箱"
#: users/templates/users/user_detail.html:37
3
#: users/templates/users/user_detail.html:37
7
msgid "Reset SSH public key"
msgid "Reset SSH public key"
msgstr "重置SSH密钥"
msgstr "重置SSH密钥"
#: users/templates/users/user_detail.html:38
3
#: users/templates/users/user_detail.html:38
7
msgid "This will reset the user public key and send a reset mail"
msgid "This will reset the user public key and send a reset mail"
msgstr "将会失效用户当前密钥,并发送重置邮件到用户邮箱"
msgstr "将会失效用户当前密钥,并发送重置邮件到用户邮箱"
#: users/templates/users/user_detail.html:40
0
#: users/templates/users/user_detail.html:40
4
#: users/templates/users/user_profile.html:2
04
#: users/templates/users/user_profile.html:2
11
msgid "Successfully updated the SSH public key."
msgid "Successfully updated the SSH public key."
msgstr "更新ssh密钥成功"
msgstr "更新ssh密钥成功"
#: users/templates/users/user_detail.html:401
#: users/templates/users/user_detail.html:405
#: users/templates/users/user_detail.html:405
#: users/templates/users/user_profile.html:205
#: users/templates/users/user_detail.html:409
#: users/templates/users/user_profile.html:210
#: users/templates/users/user_profile.html:212
#: users/templates/users/user_profile.html:217
msgid "User SSH public key update"
msgid "User SSH public key update"
msgstr "ssh密钥"
msgstr "ssh密钥"
...
@@ -2677,45 +2772,49 @@ msgstr "用户组删除"
...
@@ -2677,45 +2772,49 @@ msgstr "用户组删除"
msgid "UserGroup Deleting failed."
msgid "UserGroup Deleting failed."
msgstr "用户组删除失败"
msgstr "用户组删除失败"
#: users/templates/users/user_list.html:19
5
#: users/templates/users/user_list.html:19
6
msgid "This will delete the selected users !!!"
msgid "This will delete the selected users !!!"
msgstr "删除选中用户 !!!"
msgstr "删除选中用户 !!!"
#: users/templates/users/user_list.html:20
3
#: users/templates/users/user_list.html:20
4
msgid "User Deleted."
msgid "User Deleted."
msgstr "已被删除"
msgstr "已被删除"
#: users/templates/users/user_list.html:20
4
#: users/templates/users/user_list.html:20
5
#: users/templates/users/user_list.html:2
09
#: users/templates/users/user_list.html:2
10
msgid "User Delete"
msgid "User Delete"
msgstr "删除"
msgstr "删除"
#: users/templates/users/user_list.html:20
8
#: users/templates/users/user_list.html:20
9
msgid "User Deleting failed."
msgid "User Deleting failed."
msgstr "用户删除失败"
msgstr "用户删除失败"
#: users/templates/users/user_profile.html:109 users/views/user.py:185
#: users/templates/users/user_profile.html:95
#: users/views/user.py:239
msgid "Administrator Settings force MFA login"
msgstr "管理员设置强制使用MFA登录"
#: users/templates/users/user_profile.html:116 users/views/user.py:204
#: users/views/user.py:258
msgid "User groups"
msgid "User groups"
msgstr "用户组"
msgstr "用户组"
#: users/templates/users/user_profile.html:14
1
#: users/templates/users/user_profile.html:14
8
msgid "Update password"
msgid "Update password"
msgstr "更改密码"
msgstr "更改密码"
#: users/templates/users/user_profile.html:1
49
#: users/templates/users/user_profile.html:1
56
msgid "Update MFA settings"
msgid "Update MFA settings"
msgstr "更改MFA设置"
msgstr "更改MFA设置"
#: users/templates/users/user_profile.html:17
0
#: users/templates/users/user_profile.html:17
7
msgid "Update SSH public key"
msgid "Update SSH public key"
msgstr "更改SSH密钥"
msgstr "更改SSH密钥"
#: users/templates/users/user_profile.html:1
78
#: users/templates/users/user_profile.html:1
85
msgid "Reset public key and download"
msgid "Reset public key and download"
msgstr "重置并下载SSH密钥"
msgstr "重置并下载SSH密钥"
#: users/templates/users/user_profile.html:2
08
#: users/templates/users/user_profile.html:2
15
msgid "Failed to update SSH public key."
msgid "Failed to update SSH public key."
msgstr "更新密钥失败"
msgstr "更新密钥失败"
...
@@ -2735,15 +2834,21 @@ msgstr "更新密钥"
...
@@ -2735,15 +2834,21 @@ msgstr "更新密钥"
msgid "Or reset by server"
msgid "Or reset by server"
msgstr "或者重置并下载密钥"
msgstr "或者重置并下载密钥"
#: users/templates/users/user_update.html:4 users/views/user.py:99
#: users/templates/users/user_pubkey_update.html:94
msgid ""
"The new public key has been set successfully, Please download the "
"corresponding private key."
msgstr "新的公钥已设置成功,请下载对应的私钥"
#: users/templates/users/user_update.html:4 users/views/user.py:104
msgid "Update user"
msgid "Update user"
msgstr "更新用户"
msgstr "更新用户"
#: users/utils.py:
37
#: users/utils.py:
41
msgid "Create account successfully"
msgid "Create account successfully"
msgstr "创建账户成功"
msgstr "创建账户成功"
#: users/utils.py:
39
#: users/utils.py:
43
#, fuzzy, python-format
#, fuzzy, python-format
msgid ""
msgid ""
"\n"
"\n"
...
@@ -2788,7 +2893,7 @@ msgstr ""
...
@@ -2788,7 +2893,7 @@ msgstr ""
" </br>\n"
" </br>\n"
" "
" "
#: users/utils.py:
78
#: users/utils.py:
82
#, python-format
#, python-format
msgid ""
msgid ""
"\n"
"\n"
...
@@ -2832,11 +2937,11 @@ msgstr ""
...
@@ -2832,11 +2937,11 @@ msgstr ""
" </br>\n"
" </br>\n"
" "
" "
#: users/utils.py:1
09
#: users/utils.py:1
13
msgid "SSH Key Reset"
msgid "SSH Key Reset"
msgstr "重置ssh密钥"
msgstr "重置ssh密钥"
#: users/utils.py:11
1
#: users/utils.py:11
5
#, python-format
#, python-format
msgid ""
msgid ""
"\n"
"\n"
...
@@ -2861,18 +2966,22 @@ msgstr ""
...
@@ -2861,18 +2966,22 @@ msgstr ""
" </br>\n"
" </br>\n"
" "
" "
#: users/utils.py:14
4
#: users/utils.py:14
8
msgid "User not exist"
msgid "User not exist"
msgstr "用户不存在"
msgstr "用户不存在"
#: users/utils.py:1
46
#: users/utils.py:1
50
msgid "Disabled or expired"
msgid "Disabled or expired"
msgstr "禁用或失效"
msgstr "禁用或失效"
#: users/utils.py:1
59
#: users/utils.py:1
63
msgid "Password or SSH public key invalid"
msgid "Password or SSH public key invalid"
msgstr "密码或密钥不合法"
msgstr "密码或密钥不合法"
#: users/utils.py:290 users/utils.py:300
msgid "Bit"
msgstr " 位"
#: users/views/group.py:29
#: users/views/group.py:29
msgid "User group list"
msgid "User group list"
msgstr "用户组列表"
msgstr "用户组列表"
...
@@ -2885,99 +2994,103 @@ msgstr "更新用户组"
...
@@ -2885,99 +2994,103 @@ msgstr "更新用户组"
msgid "User group granted asset"
msgid "User group granted asset"
msgstr "用户组授权资产"
msgstr "用户组授权资产"
#: users/views/login.py:
59
#: users/views/login.py:
62
msgid "Please enable cookies and try again."
msgid "Please enable cookies and try again."
msgstr "设置你的浏览器支持cookie"
msgstr "设置你的浏览器支持cookie"
#: users/views/login.py:12
5 users/views/user.py:464 users/views/user.py:489
#: users/views/login.py:12
8 users/views/user.py:501 users/views/user.py:526
msgid "MFA code invalid"
msgid "MFA code invalid"
msgstr "MFA码认证失败"
msgstr "MFA码认证失败"
#: users/views/login.py:15
1
#: users/views/login.py:15
4
msgid "Logout success"
msgid "Logout success"
msgstr "退出登录成功"
msgstr "退出登录成功"
#: users/views/login.py:15
2
#: users/views/login.py:15
5
msgid "Logout success, return login page"
msgid "Logout success, return login page"
msgstr "退出登录成功,返回到登录页面"
msgstr "退出登录成功,返回到登录页面"
#: users/views/login.py:1
68
#: users/views/login.py:1
71
msgid "Email address invalid, please input again"
msgid "Email address invalid, please input again"
msgstr "邮箱地址错误,重新输入"
msgstr "邮箱地址错误,重新输入"
#: users/views/login.py:18
1
#: users/views/login.py:18
4
msgid "Send reset password message"
msgid "Send reset password message"
msgstr "发送重置密码邮件"
msgstr "发送重置密码邮件"
#: users/views/login.py:18
2
#: users/views/login.py:18
5
msgid "Send reset password mail success, login your mail box and follow it "
msgid "Send reset password mail success, login your mail box and follow it "
msgstr ""
msgstr ""
"发送重置邮件成功, 请登录邮箱查看, 按照提示操作 (如果没收到,请等待3-5分钟)"
"发送重置邮件成功, 请登录邮箱查看, 按照提示操作 (如果没收到,请等待3-5分钟)"
#: users/views/login.py:19
5
#: users/views/login.py:19
8
msgid "Reset password success"
msgid "Reset password success"
msgstr "重置密码成功"
msgstr "重置密码成功"
#: users/views/login.py:19
6
#: users/views/login.py:19
9
msgid "Reset password success, return to login page"
msgid "Reset password success, return to login page"
msgstr "重置密码成功,返回到登录页面"
msgstr "重置密码成功,返回到登录页面"
#: users/views/login.py:2
13 users/views/login.py:226
#: users/views/login.py:2
20 users/views/login.py:233
msgid "Token invalid or expired"
msgid "Token invalid or expired"
msgstr "Token错误或失效"
msgstr "Token错误或失效"
#: users/views/login.py:22
2
#: users/views/login.py:22
9
msgid "Password not same"
msgid "Password not same"
msgstr "密码不一致"
msgstr "密码不一致"
#: users/views/login.py:263
#: users/views/login.py:239 users/views/user.py:116 users/views/user.py:399
msgid "* Your password does not meet the requirements"
msgstr "* 您的密码不符合要求"
#: users/views/login.py:277
msgid "First login"
msgid "First login"
msgstr "首次登陆"
msgstr "首次登陆"
#: users/views/login.py:3
22
#: users/views/login.py:3
36
msgid "Login log list"
msgid "Login log list"
msgstr "登录日志"
msgstr "登录日志"
#: users/views/user.py:1
09
#: users/views/user.py:1
28
msgid "Bulk update user success"
msgid "Bulk update user success"
msgstr "批量更新用户成功"
msgstr "批量更新用户成功"
#: users/views/user.py:2
14
#: users/views/user.py:2
33
msgid "Invalid file."
msgid "Invalid file."
msgstr "文件不合法"
msgstr "文件不合法"
#: users/views/user.py:3
11
#: users/views/user.py:3
30
msgid "User granted assets"
msgid "User granted assets"
msgstr "用户授权资产"
msgstr "用户授权资产"
#: users/views/user.py:3
40
#: users/views/user.py:3
63
msgid "Profile setting"
msgid "Profile setting"
msgstr "个人信息设置"
msgstr "个人信息设置"
#: users/views/user.py:3
58
#: users/views/user.py:3
82
msgid "Password update"
msgid "Password update"
msgstr "密码更新"
msgstr "密码更新"
#: users/views/user.py:
380
#: users/views/user.py:
417
msgid "Public key update"
msgid "Public key update"
msgstr "密钥更新"
msgstr "密钥更新"
#: users/views/user.py:4
21
#: users/views/user.py:4
58
msgid "Password invalid"
msgid "Password invalid"
msgstr "用户名或密码无效"
msgstr "用户名或密码无效"
#: users/views/user.py:5
15
#: users/views/user.py:5
52
msgid "MFA enable success"
msgid "MFA enable success"
msgstr "MFA 绑定成功"
msgstr "MFA 绑定成功"
#: users/views/user.py:5
16
#: users/views/user.py:5
53
msgid "MFA enable success, return login page"
msgid "MFA enable success, return login page"
msgstr "MFA 绑定成功,返回到登录页面"
msgstr "MFA 绑定成功,返回到登录页面"
#: users/views/user.py:5
18
#: users/views/user.py:5
55
msgid "MFA disable success"
msgid "MFA disable success"
msgstr "MFA 解绑成功"
msgstr "MFA 解绑成功"
#: users/views/user.py:5
19
#: users/views/user.py:5
56
msgid "MFA disable success, return login page"
msgid "MFA disable success, return login page"
msgstr "MFA 解绑成功,返回登录页面"
msgstr "MFA 解绑成功,返回登录页面"
apps/jumpserver/settings.py
View file @
0a2ff83c
...
@@ -401,6 +401,9 @@ TERMINAL_REPLAY_STORAGE = {
...
@@ -401,6 +401,9 @@ TERMINAL_REPLAY_STORAGE = {
},
},
}
}
DEFAULT_PASSWORD_MIN_LENGTH
=
6
# Django bootstrap3 setting, more see http://django-bootstrap3.readthedocs.io/en/latest/settings.html
# Django bootstrap3 setting, more see http://django-bootstrap3.readthedocs.io/en/latest/settings.html
BOOTSTRAP3
=
{
BOOTSTRAP3
=
{
'horizontal_label_class'
:
'col-md-2'
,
'horizontal_label_class'
:
'col-md-2'
,
...
...
apps/ops/inventory.py
View file @
0a2ff83c
...
@@ -86,6 +86,7 @@ class JMSInventory(BaseInventory):
...
@@ -86,6 +86,7 @@ class JMSInventory(BaseInventory):
gateway
=
asset
.
domain
.
random_gateway
()
gateway
=
asset
.
domain
.
random_gateway
()
proxy_command_list
=
[
proxy_command_list
=
[
"ssh"
,
"-p"
,
str
(
gateway
.
port
),
"ssh"
,
"-p"
,
str
(
gateway
.
port
),
"-o"
,
"StrictHostKeyChecking=no"
,
"{}@{}"
.
format
(
gateway
.
username
,
gateway
.
ip
),
"{}@{}"
.
format
(
gateway
.
username
,
gateway
.
ip
),
"-W"
,
"
%
h:
%
p"
,
"-q"
,
"-W"
,
"
%
h:
%
p"
,
"-q"
,
]
]
...
...
apps/perms/utils.py
View file @
0a2ff83c
...
@@ -11,10 +11,48 @@ from .hands import Node
...
@@ -11,10 +11,48 @@ from .hands import Node
logger
=
get_logger
(
__file__
)
logger
=
get_logger
(
__file__
)
class
Tree
:
def
__init__
(
self
):
self
.
__all_nodes
=
list
(
Node
.
objects
.
all
()
.
prefetch_related
(
'assets'
))
self
.
__node_asset_map
=
defaultdict
(
set
)
self
.
nodes
=
defaultdict
(
dict
)
self
.
root
=
Node
.
root
()
self
.
init_node_asset_map
()
def
init_node_asset_map
(
self
):
for
node
in
self
.
__all_nodes
:
assets
=
node
.
get_assets
()
.
values_list
(
'id'
,
flat
=
True
)
for
asset
in
assets
:
self
.
__node_asset_map
[
str
(
asset
)]
.
add
(
node
)
def
add_asset
(
self
,
asset
,
system_users
):
nodes
=
self
.
__node_asset_map
.
get
(
str
(
asset
.
id
),
[])
self
.
add_nodes
(
nodes
)
for
node
in
nodes
:
self
.
nodes
[
node
][
asset
]
.
update
(
system_users
)
def
add_node
(
self
,
node
):
if
node
in
self
.
nodes
:
return
else
:
self
.
nodes
[
node
]
=
defaultdict
(
set
)
if
node
.
key
==
self
.
root
.
key
:
return
parent_key
=
':'
.
join
(
node
.
key
.
split
(
':'
)[:
-
1
])
for
n
in
self
.
__all_nodes
:
if
n
.
key
==
parent_key
:
self
.
add_node
(
n
)
break
def
add_nodes
(
self
,
nodes
):
for
node
in
nodes
:
self
.
add_node
(
node
)
def
get_user_permissions
(
user
,
include_group
=
True
):
def
get_user_permissions
(
user
,
include_group
=
True
):
if
include_group
:
if
include_group
:
groups
=
user
.
groups
.
all
()
groups
=
user
.
groups
.
all
()
arg
=
Q
(
users
=
user
)
|
Q
(
user_groups
=
groups
)
arg
=
Q
(
users
=
user
)
|
Q
(
user_groups
__in
=
groups
)
else
:
else
:
arg
=
Q
(
users
=
user
)
arg
=
Q
(
users
=
user
)
return
AssetPermission
.
objects
.
all
()
.
valid
()
.
filter
(
arg
)
return
AssetPermission
.
objects
.
all
()
.
valid
()
.
filter
(
arg
)
...
@@ -29,7 +67,7 @@ def get_user_group_permissions(user_group):
...
@@ -29,7 +67,7 @@ def get_user_group_permissions(user_group):
def
get_asset_permissions
(
asset
,
include_node
=
True
):
def
get_asset_permissions
(
asset
,
include_node
=
True
):
if
include_node
:
if
include_node
:
nodes
=
asset
.
get_all_nodes
(
flat
=
True
)
nodes
=
asset
.
get_all_nodes
(
flat
=
True
)
arg
=
Q
(
assets
=
asset
)
|
Q
(
nodes
=
nodes
)
arg
=
Q
(
assets
=
asset
)
|
Q
(
nodes
__in
=
nodes
)
else
:
else
:
arg
=
Q
(
assets
=
asset
)
arg
=
Q
(
assets
=
asset
)
return
AssetPermission
.
objects
.
all
()
.
valid
()
.
filter
(
arg
)
return
AssetPermission
.
objects
.
all
()
.
valid
()
.
filter
(
arg
)
...
@@ -57,6 +95,7 @@ class AssetPermissionUtil:
...
@@ -57,6 +95,7 @@ class AssetPermissionUtil:
def
__init__
(
self
,
obj
):
def
__init__
(
self
,
obj
):
self
.
object
=
obj
self
.
object
=
obj
self
.
_permissions
=
None
self
.
_permissions
=
None
self
.
_assets
=
None
@property
@property
def
permissions
(
self
):
def
permissions
(
self
):
...
@@ -93,6 +132,8 @@ class AssetPermissionUtil:
...
@@ -93,6 +132,8 @@ class AssetPermissionUtil:
return
assets
return
assets
def
get_assets
(
self
):
def
get_assets
(
self
):
if
self
.
_assets
:
return
self
.
_assets
assets
=
self
.
get_assets_direct
()
assets
=
self
.
get_assets_direct
()
nodes
=
self
.
get_nodes_direct
()
nodes
=
self
.
get_nodes_direct
()
for
node
,
system_users
in
nodes
.
items
():
for
node
,
system_users
in
nodes
.
items
():
...
@@ -101,7 +142,8 @@ class AssetPermissionUtil:
...
@@ -101,7 +142,8 @@ class AssetPermissionUtil:
if
isinstance
(
asset
,
Node
):
if
isinstance
(
asset
,
Node
):
print
(
_assets
)
print
(
_assets
)
assets
[
asset
]
.
update
(
system_users
)
assets
[
asset
]
.
update
(
system_users
)
return
assets
self
.
_assets
=
assets
return
self
.
_assets
def
get_nodes_with_assets
(
self
):
def
get_nodes_with_assets
(
self
):
"""
"""
...
@@ -110,14 +152,9 @@ class AssetPermissionUtil:
...
@@ -110,14 +152,9 @@ class AssetPermissionUtil:
:return:
:return:
"""
"""
assets
=
self
.
get_assets
()
assets
=
self
.
get_assets
()
nodes
=
defaultdict
(
dict
)
tree
=
Tree
(
)
for
asset
,
system_users
in
assets
.
items
():
for
asset
,
system_users
in
assets
.
items
():
_nodes
=
asset
.
nodes
.
all
()
tree
.
add_asset
(
asset
,
system_users
)
for
node
in
_nodes
:
return
tree
.
nodes
if
asset
in
nodes
[
node
]:
nodes
[
node
][
asset
]
.
update
(
system_users
)
else
:
nodes
[
node
][
asset
]
=
system_users
return
nodes
apps/static/js/jumpserver.js
View file @
0a2ff83c
...
@@ -609,3 +609,91 @@ function setUrlParam(url, name, value) {
...
@@ -609,3 +609,91 @@ function setUrlParam(url, name, value) {
}
}
return
url
return
url
}
}
// 校验密码-改变规则颜色
function
checkPasswordRules
(
password
,
minLength
)
{
if
(
wordMinLength
(
password
,
minLength
))
{
$
(
'#rule_SECURITY_PASSWORD_MIN_LENGTH'
).
css
(
'color'
,
'green'
)
}
else
{
$
(
'#rule_SECURITY_PASSWORD_MIN_LENGTH'
).
css
(
'color'
,
'#908a8a'
)
}
if
(
wordUpperCase
(
password
))
{
$
(
'#rule_SECURITY_PASSWORD_UPPER_CASE'
).
css
(
'color'
,
'green'
);
}
else
{
$
(
'#rule_SECURITY_PASSWORD_UPPER_CASE'
).
css
(
'color'
,
'#908a8a'
)
}
if
(
wordLowerCase
(
password
))
{
$
(
'#rule_SECURITY_PASSWORD_LOWER_CASE'
).
css
(
'color'
,
'green'
)
}
else
{
$
(
'#rule_SECURITY_PASSWORD_LOWER_CASE'
).
css
(
'color'
,
'#908a8a'
)
}
if
(
wordNumber
(
password
))
{
$
(
'#rule_SECURITY_PASSWORD_NUMBER'
).
css
(
'color'
,
'green'
)
}
else
{
$
(
'#rule_SECURITY_PASSWORD_NUMBER'
).
css
(
'color'
,
'#908a8a'
)
}
if
(
wordSpecialChar
(
password
))
{
$
(
'#rule_SECURITY_PASSWORD_SPECIAL_CHAR'
).
css
(
'color'
,
'green'
)
}
else
{
$
(
'#rule_SECURITY_PASSWORD_SPECIAL_CHAR'
).
css
(
'color'
,
'#908a8a'
)
}
}
// 最小长度
function
wordMinLength
(
word
,
minLength
)
{
//var minLength = {{ min_length }};
var
re
=
new
RegExp
(
"^(.{"
+
minLength
+
",})$"
);
return
word
.
match
(
re
)
}
// 大写字母
function
wordUpperCase
(
word
)
{
return
word
.
match
(
/
([
A-Z
]
+
)
/
)
}
// 小写字母
function
wordLowerCase
(
word
)
{
return
word
.
match
(
/
([
a-z
]
+
)
/
)
}
// 数字字符
function
wordNumber
(
word
)
{
return
word
.
match
(
/
([\d]
+
)
/
)
}
// 特殊字符
function
wordSpecialChar
(
word
)
{
return
word
.
match
(
/
[
`,~,!,@,#,
\$
,%,
\^
,&,
\*
,
\(
,
\)
,
\-
,_,=,
\+
,
\{
,
\}
,
\[
,
\]
,
\|
,
\\
,;,',:,",
\,
,
\.
,<,>,
\/
,
\?]
+/
)
}
// 显示弹窗密码规则
function
popoverPasswordRules
(
password_check_rules
,
$el
)
{
var
message
=
""
;
jQuery
.
each
(
password_check_rules
,
function
(
idx
,
rules
)
{
message
+=
"<li id="
+
rules
.
id
+
" style='list-style-type:none;'> <i class='fa fa-check-circle-o' style='margin-right:10px;' ></i>"
+
rules
.
label
+
"</li>"
;
});
//$('#id_password_rules').html(message);
$el
.
html
(
message
)
}
// 初始化弹窗popover
function
initPopover
(
$container
,
$progress
,
$idPassword
,
$el
,
password_check_rules
){
options
=
{};
// User Interface
options
.
ui
=
{
container
:
$container
,
viewports
:
{
progress
:
$progress
//errors: $('.popover-content')
},
showProgressbar
:
true
,
showVerdictsInsideProgressBar
:
true
};
$idPassword
.
pwstrength
(
options
);
popoverPasswordRules
(
password_check_rules
,
$el
);
}
apps/static/js/pwstrength-bootstrap.js
0 → 100755
View file @
0a2ff83c
/*!
* jQuery Password Strength plugin for Twitter Bootstrap
* Version: 2.2.1
*
* Copyright (c) 2008-2013 Tane Piper
* Copyright (c) 2013 Alejandro Blanco
* Dual licensed under the MIT and GPL licenses.
*/
(
function
(
jQuery
)
{
// Source: src/i18n.js
var
i18n
=
{};
(
function
(
i18n
,
i18next
)
{
'use strict'
;
i18n
.
fallback
=
{
"wordMinLength"
:
"Your password is too short"
,
"wordMaxLength"
:
"Your password is too long"
,
"wordInvalidChar"
:
"Your password contains an invalid character"
,
"wordNotEmail"
:
"Do not use your email as your password"
,
"wordSimilarToUsername"
:
"Your password cannot contain your username"
,
"wordTwoCharacterClasses"
:
"Use different character classes"
,
"wordRepetitions"
:
"Too many repetitions"
,
"wordSequences"
:
"Your password contains sequences"
,
"errorList"
:
"Errors:"
,
"veryWeak"
:
"Very Weak"
,
"weak"
:
"Weak"
,
"normal"
:
"Normal"
,
"medium"
:
"Medium"
,
"strong"
:
"Strong"
,
"veryStrong"
:
"Very Strong"
};
i18n
.
t
=
function
(
key
)
{
var
result
=
''
;
// Try to use i18next.com
if
(
i18next
)
{
result
=
i18next
.
t
(
key
);
}
else
{
// Fallback to english
result
=
i18n
.
fallback
[
key
];
}
return
result
===
key
?
''
:
result
;
};
}(
i18n
,
window
.
i18next
));
// Source: src/rules.js
var
rulesEngine
=
{};
try
{
if
(
!
jQuery
&&
module
&&
module
.
exports
)
{
var
jQuery
=
require
(
"jquery"
),
jsdom
=
require
(
"jsdom"
).
jsdom
;
jQuery
=
jQuery
(
jsdom
().
defaultView
);
}
}
catch
(
ignore
)
{}
(
function
(
$
,
rulesEngine
)
{
"use strict"
;
var
validation
=
{};
rulesEngine
.
forbiddenSequences
=
[
"0123456789"
,
"abcdefghijklmnopqrstuvwxyz"
,
"qwertyuiop"
,
"asdfghjkl"
,
"zxcvbnm"
,
"!@#$%^&*()_+"
];
validation
.
wordNotEmail
=
function
(
options
,
word
,
score
)
{
if
(
word
.
match
(
/^
([\w\!\#
$
\%\&\'\*\+\-\/\=\?\^\`
{
\|\}\~]
+
\.)
*
[\w\!\#
$
\%\&\'\*\+\-\/\=\?\^\`
{
\|\}\~]
+@
((((([
a-z0-9
]{1}[
a-z0-9
\-]{0,62}[
a-z0-9
]{1})
|
[
a-z
])\.)
+
[
a-z
]{2,6})
|
(\d{1,3}\.){3}\d{1,3}(\:\d{1,5})?)
$/i
))
{
return
score
;
}
return
0
;
};
validation
.
wordMinLength
=
function
(
options
,
word
,
score
)
{
var
wordlen
=
word
.
length
,
lenScore
=
Math
.
pow
(
wordlen
,
options
.
rules
.
raisePower
);
if
(
wordlen
<
options
.
common
.
minChar
)
{
lenScore
=
(
lenScore
+
score
);
}
return
lenScore
;
};
validation
.
wordMaxLength
=
function
(
options
,
word
,
score
)
{
var
wordlen
=
word
.
length
,
lenScore
=
Math
.
pow
(
wordlen
,
options
.
rules
.
raisePower
);
if
(
wordlen
>
options
.
common
.
maxChar
)
{
return
score
;
}
return
lenScore
;
};
validation
.
wordInvalidChar
=
function
(
options
,
word
,
score
)
{
if
(
options
.
common
.
invalidCharsRegExp
.
test
(
word
))
{
return
score
;
}
return
0
;
};
validation
.
wordMinLengthStaticScore
=
function
(
options
,
word
,
score
)
{
return
word
.
length
<
options
.
common
.
minChar
?
0
:
score
;
};
validation
.
wordMaxLengthStaticScore
=
function
(
options
,
word
,
score
)
{
return
word
.
length
>
options
.
common
.
maxChar
?
0
:
score
;
};
validation
.
wordSimilarToUsername
=
function
(
options
,
word
,
score
)
{
var
username
=
$
(
options
.
common
.
usernameField
).
val
();
if
(
username
&&
word
.
toLowerCase
().
match
(
username
.
replace
(
/
[\-\[\]\/\{\}\(\)\*\+\=\?\:\.\\\^\$\|\!\,]
/g
,
"
\\
$&"
).
toLowerCase
()))
{
return
score
;
}
return
0
;
};
validation
.
wordTwoCharacterClasses
=
function
(
options
,
word
,
score
)
{
if
(
word
.
match
(
/
([
a-z
]
.*
[
A-Z
])
|
([
A-Z
]
.*
[
a-z
])
/
)
||
(
word
.
match
(
/
([
a-zA-Z
])
/
)
&&
word
.
match
(
/
([
0-9
])
/
))
||
(
word
.
match
(
/
(
.
[
!,@,#,$,%,
\^
,&,*,?,_,~
])
/
)
&&
word
.
match
(
/
[
a-zA-Z0-9_
]
/
)))
{
return
score
;
}
return
0
;
};
validation
.
wordRepetitions
=
function
(
options
,
word
,
score
)
{
if
(
word
.
match
(
/
(
.
)\1\1
/
))
{
return
score
;
}
return
0
;
};
validation
.
wordSequences
=
function
(
options
,
word
,
score
)
{
var
found
=
false
,
j
;
if
(
word
.
length
>
2
)
{
$
.
each
(
rulesEngine
.
forbiddenSequences
,
function
(
idx
,
seq
)
{
if
(
found
)
{
return
;
}
var
sequences
=
[
seq
,
seq
.
split
(
''
).
reverse
().
join
(
''
)];
$
.
each
(
sequences
,
function
(
idx
,
sequence
)
{
for
(
j
=
0
;
j
<
(
word
.
length
-
2
);
j
+=
1
)
{
// iterate the word trough a sliding window of size 3:
if
(
sequence
.
indexOf
(
word
.
toLowerCase
().
substring
(
j
,
j
+
3
))
>
-
1
)
{
found
=
true
;
}
}
});
});
if
(
found
)
{
return
score
;
}
}
return
0
;
};
validation
.
wordLowercase
=
function
(
options
,
word
,
score
)
{
return
word
.
match
(
/
[
a-z
]
/
)
&&
score
;
};
validation
.
wordUppercase
=
function
(
options
,
word
,
score
)
{
return
word
.
match
(
/
[
A-Z
]
/
)
&&
score
;
};
validation
.
wordOneNumber
=
function
(
options
,
word
,
score
)
{
return
word
.
match
(
/
\d
+/
)
&&
score
;
};
validation
.
wordThreeNumbers
=
function
(
options
,
word
,
score
)
{
return
word
.
match
(
/
(
.*
[
0-9
]
.*
[
0-9
]
.*
[
0-9
])
/
)
&&
score
;
};
validation
.
wordOneSpecialChar
=
function
(
options
,
word
,
score
)
{
return
word
.
match
(
/
[
!,@,#,$,%,
\^
,&,*,?,_,~
]
/
)
&&
score
;
};
validation
.
wordTwoSpecialChar
=
function
(
options
,
word
,
score
)
{
return
word
.
match
(
/
(
.*
[
!,@,#,$,%,
\^
,&,*,?,_,~
]
.*
[
!,@,#,$,%,
\^
,&,*,?,_,~
])
/
)
&&
score
;
};
validation
.
wordUpperLowerCombo
=
function
(
options
,
word
,
score
)
{
return
word
.
match
(
/
([
a-z
]
.*
[
A-Z
])
|
([
A-Z
]
.*
[
a-z
])
/
)
&&
score
;
};
validation
.
wordLetterNumberCombo
=
function
(
options
,
word
,
score
)
{
return
word
.
match
(
/
([
a-zA-Z
])
/
)
&&
word
.
match
(
/
([
0-9
])
/
)
&&
score
;
};
validation
.
wordLetterNumberCharCombo
=
function
(
options
,
word
,
score
)
{
return
word
.
match
(
/
([
a-zA-Z0-9
]
.*
[
!,@,#,$,%,
\^
,&,*,?,_,~
])
|
([
!,@,#,$,%,
\^
,&,*,?,_,~
]
.*
[
a-zA-Z0-9
])
/
)
&&
score
;
};
validation
.
wordIsACommonPassword
=
function
(
options
,
word
,
score
)
{
if
(
$
.
inArray
(
word
,
options
.
rules
.
commonPasswords
)
>=
0
)
{
return
score
;
}
return
0
;
};
rulesEngine
.
validation
=
validation
;
rulesEngine
.
executeRules
=
function
(
options
,
word
)
{
var
totalScore
=
0
;
$
.
each
(
options
.
rules
.
activated
,
function
(
rule
,
active
)
{
if
(
active
)
{
var
score
=
options
.
rules
.
scores
[
rule
],
funct
=
rulesEngine
.
validation
[
rule
],
result
,
errorMessage
;
if
(
!
$
.
isFunction
(
funct
))
{
funct
=
options
.
rules
.
extra
[
rule
];
}
if
(
$
.
isFunction
(
funct
))
{
result
=
funct
(
options
,
word
,
score
);
if
(
result
)
{
totalScore
+=
result
;
}
if
(
result
<
0
||
(
!
$
.
isNumeric
(
result
)
&&
!
result
))
{
errorMessage
=
options
.
ui
.
spanError
(
options
,
rule
);
if
(
errorMessage
.
length
>
0
)
{
options
.
instances
.
errors
.
push
(
errorMessage
);
}
}
}
}
});
return
totalScore
;
};
}(
jQuery
,
rulesEngine
));
try
{
if
(
module
&&
module
.
exports
)
{
module
.
exports
=
rulesEngine
;
}
}
catch
(
ignore
)
{}
// Source: src/options.js
var
defaultOptions
=
{};
defaultOptions
.
common
=
{};
defaultOptions
.
common
.
minChar
=
6
;
defaultOptions
.
common
.
maxChar
=
20
;
defaultOptions
.
common
.
usernameField
=
"#username"
;
defaultOptions
.
common
.
invalidCharsRegExp
=
new
RegExp
(
/
[\s
,'"
]
/
);
defaultOptions
.
common
.
userInputs
=
[
// Selectors for input fields with user input
];
defaultOptions
.
common
.
onLoad
=
undefined
;
defaultOptions
.
common
.
onKeyUp
=
undefined
;
defaultOptions
.
common
.
onScore
=
undefined
;
defaultOptions
.
common
.
zxcvbn
=
false
;
defaultOptions
.
common
.
zxcvbnTerms
=
[
// List of disrecommended words
];
defaultOptions
.
common
.
events
=
[
"keyup"
,
"change"
,
"paste"
];
defaultOptions
.
common
.
debug
=
false
;
defaultOptions
.
rules
=
{};
defaultOptions
.
rules
.
extra
=
{};
defaultOptions
.
rules
.
scores
=
{
wordNotEmail
:
-
100
,
wordMinLength
:
-
50
,
wordMaxLength
:
-
50
,
wordInvalidChar
:
-
100
,
wordSimilarToUsername
:
-
100
,
wordSequences
:
-
20
,
wordTwoCharacterClasses
:
2
,
wordRepetitions
:
-
25
,
wordLowercase
:
1
,
wordUppercase
:
3
,
wordOneNumber
:
3
,
wordThreeNumbers
:
5
,
wordOneSpecialChar
:
3
,
wordTwoSpecialChar
:
5
,
wordUpperLowerCombo
:
2
,
wordLetterNumberCombo
:
2
,
wordLetterNumberCharCombo
:
2
,
wordIsACommonPassword
:
-
100
};
defaultOptions
.
rules
.
activated
=
{
wordNotEmail
:
true
,
wordMinLength
:
true
,
wordMaxLength
:
false
,
wordInvalidChar
:
false
,
wordSimilarToUsername
:
true
,
wordSequences
:
true
,
wordTwoCharacterClasses
:
true
,
wordRepetitions
:
true
,
wordLowercase
:
true
,
wordUppercase
:
true
,
wordOneNumber
:
true
,
wordThreeNumbers
:
true
,
wordOneSpecialChar
:
true
,
wordTwoSpecialChar
:
true
,
wordUpperLowerCombo
:
true
,
wordLetterNumberCombo
:
true
,
wordLetterNumberCharCombo
:
true
,
wordIsACommonPassword
:
true
};
defaultOptions
.
rules
.
raisePower
=
1.4
;
// List taken from https://github.com/danielmiessler/SecLists (MIT License)
defaultOptions
.
rules
.
commonPasswords
=
[
'123456'
,
'password'
,
'12345678'
,
'qwerty'
,
'123456789'
,
'12345'
,
'1234'
,
'111111'
,
'1234567'
,
'dragon'
,
'123123'
,
'baseball'
,
'abc123'
,
'football'
,
'monkey'
,
'letmein'
,
'696969'
,
'shadow'
,
'master'
,
'666666'
,
'qwertyuiop'
,
'123321'
,
'mustang'
,
'1234567890'
,
'michael'
,
'654321'
,
'pussy'
,
'superman'
,
'1qaz2wsx'
,
'7777777'
,
'fuckyou'
,
'121212'
,
'000000'
,
'qazwsx'
,
'123qwe'
,
'killer'
,
'trustno1'
,
'jordan'
,
'jennifer'
,
'zxcvbnm'
,
'asdfgh'
,
'hunter'
,
'buster'
,
'soccer'
,
'harley'
,
'batman'
,
'andrew'
,
'tigger'
,
'sunshine'
,
'iloveyou'
,
'fuckme'
,
'2000'
,
'charlie'
,
'robert'
,
'thomas'
,
'hockey'
,
'ranger'
,
'daniel'
,
'starwars'
,
'klaster'
,
'112233'
,
'george'
,
'asshole'
,
'computer'
,
'michelle'
,
'jessica'
,
'pepper'
,
'1111'
,
'zxcvbn'
,
'555555'
,
'11111111'
,
'131313'
,
'freedom'
,
'777777'
,
'pass'
,
'fuck'
,
'maggie'
,
'159753'
,
'aaaaaa'
,
'ginger'
,
'princess'
,
'joshua'
,
'cheese'
,
'amanda'
,
'summer'
,
'love'
,
'ashley'
,
'6969'
,
'nicole'
,
'chelsea'
,
'biteme'
,
'matthew'
,
'access'
,
'yankees'
,
'987654321'
,
'dallas'
,
'austin'
,
'thunder'
,
'taylor'
,
'matrix'
];
defaultOptions
.
ui
=
{};
defaultOptions
.
ui
.
bootstrap2
=
false
;
defaultOptions
.
ui
.
bootstrap4
=
false
;
defaultOptions
.
ui
.
colorClasses
=
[
"danger"
,
"danger"
,
"danger"
,
"warning"
,
"warning"
,
"success"
];
defaultOptions
.
ui
.
showProgressBar
=
true
;
defaultOptions
.
ui
.
progressBarEmptyPercentage
=
1
;
defaultOptions
.
ui
.
progressBarMinPercentage
=
1
;
defaultOptions
.
ui
.
progressExtraCssClasses
=
''
;
defaultOptions
.
ui
.
progressBarExtraCssClasses
=
''
;
defaultOptions
.
ui
.
showPopover
=
false
;
defaultOptions
.
ui
.
popoverPlacement
=
"bottom"
;
defaultOptions
.
ui
.
showStatus
=
false
;
defaultOptions
.
ui
.
spanError
=
function
(
options
,
key
)
{
"use strict"
;
var
text
=
options
.
i18n
.
t
(
key
);
if
(
!
text
)
{
return
''
;
}
return
'<span style="color: #d52929">'
+
text
+
'</span>'
;
};
defaultOptions
.
ui
.
popoverError
=
function
(
options
)
{
"use strict"
;
var
errors
=
options
.
instances
.
errors
,
errorsTitle
=
options
.
i18n
.
t
(
"errorList"
),
message
=
"<div>"
+
errorsTitle
+
"<ul class='error-list' style='margin-bottom: 0;'>"
;
jQuery
.
each
(
errors
,
function
(
idx
,
err
)
{
message
+=
"<li>"
+
err
+
"</li>"
;
});
message
+=
"</ul></div>"
;
return
message
;
};
defaultOptions
.
ui
.
showVerdicts
=
true
;
defaultOptions
.
ui
.
showVerdictsInsideProgressBar
=
false
;
defaultOptions
.
ui
.
useVerdictCssClass
=
false
;
defaultOptions
.
ui
.
showErrors
=
false
;
defaultOptions
.
ui
.
showScore
=
false
;
defaultOptions
.
ui
.
container
=
undefined
;
defaultOptions
.
ui
.
viewports
=
{
progress
:
undefined
,
verdict
:
undefined
,
errors
:
undefined
,
score
:
undefined
};
defaultOptions
.
ui
.
scores
=
[
0
,
14
,
26
,
38
,
50
];
defaultOptions
.
i18n
=
{};
defaultOptions
.
i18n
.
t
=
i18n
.
t
;
// Source: src/ui.js
var
ui
=
{};
(
function
(
$
,
ui
)
{
"use strict"
;
var
statusClasses
=
[
"error"
,
"warning"
,
"success"
],
verdictKeys
=
[
"veryWeak"
,
"weak"
,
"normal"
,
"medium"
,
"strong"
,
"veryStrong"
];
ui
.
getContainer
=
function
(
options
,
$el
)
{
var
$container
;
$container
=
$
(
options
.
ui
.
container
);
if
(
!
(
$container
&&
$container
.
length
===
1
))
{
$container
=
$el
.
parent
();
}
return
$container
;
};
ui
.
findElement
=
function
(
$container
,
viewport
,
cssSelector
)
{
if
(
viewport
)
{
return
$container
.
find
(
viewport
).
find
(
cssSelector
);
}
return
$container
.
find
(
cssSelector
);
};
ui
.
getUIElements
=
function
(
options
,
$el
)
{
var
$container
,
result
;
if
(
options
.
instances
.
viewports
)
{
return
options
.
instances
.
viewports
;
}
$container
=
ui
.
getContainer
(
options
,
$el
);
result
=
{};
result
.
$progressbar
=
ui
.
findElement
(
$container
,
options
.
ui
.
viewports
.
progress
,
"div.progress"
);
if
(
options
.
ui
.
showVerdictsInsideProgressBar
)
{
result
.
$verdict
=
result
.
$progressbar
.
find
(
"span.password-verdict"
);
}
if
(
!
options
.
ui
.
showPopover
)
{
if
(
!
options
.
ui
.
showVerdictsInsideProgressBar
)
{
result
.
$verdict
=
ui
.
findElement
(
$container
,
options
.
ui
.
viewports
.
verdict
,
"span.password-verdict"
);
}
result
.
$errors
=
ui
.
findElement
(
$container
,
options
.
ui
.
viewports
.
errors
,
"ul.error-list"
);
}
result
.
$score
=
ui
.
findElement
(
$container
,
options
.
ui
.
viewports
.
score
,
"span.password-score"
);
options
.
instances
.
viewports
=
result
;
return
result
;
};
ui
.
initProgressBar
=
function
(
options
,
$el
)
{
var
$container
=
ui
.
getContainer
(
options
,
$el
),
progressbar
=
"<div class='progress "
;
if
(
options
.
ui
.
bootstrap2
)
{
// Boostrap 2
progressbar
+=
options
.
ui
.
progressBarExtraCssClasses
+
"'><div class='"
;
}
else
{
// Bootstrap 3 & 4
progressbar
+=
options
.
ui
.
progressExtraCssClasses
+
"'><div class='"
+
options
.
ui
.
progressBarExtraCssClasses
+
" progress-"
;
}
progressbar
+=
"bar'>"
;
if
(
options
.
ui
.
showVerdictsInsideProgressBar
)
{
progressbar
+=
"<span class='password-verdict'></span>"
;
}
progressbar
+=
"</div></div>"
;
if
(
options
.
ui
.
viewports
.
progress
)
{
$container
.
find
(
options
.
ui
.
viewports
.
progress
).
append
(
progressbar
);
}
else
{
$
(
progressbar
).
insertAfter
(
$el
);
}
};
ui
.
initHelper
=
function
(
options
,
$el
,
html
,
viewport
)
{
var
$container
=
ui
.
getContainer
(
options
,
$el
);
if
(
viewport
)
{
$container
.
find
(
viewport
).
append
(
html
);
}
else
{
$
(
html
).
insertAfter
(
$el
);
}
};
ui
.
initVerdict
=
function
(
options
,
$el
)
{
ui
.
initHelper
(
options
,
$el
,
"<span class='password-verdict'></span>"
,
options
.
ui
.
viewports
.
verdict
);
};
ui
.
initErrorList
=
function
(
options
,
$el
)
{
ui
.
initHelper
(
options
,
$el
,
"<ul class='error-list'></ul >"
,
options
.
ui
.
viewports
.
errors
);
};
ui
.
initScore
=
function
(
options
,
$el
)
{
ui
.
initHelper
(
options
,
$el
,
"<span class='password-score'></span>"
,
options
.
ui
.
viewports
.
score
);
};
ui
.
initPopover
=
function
(
options
,
$el
)
{
$el
.
popover
(
"destroy"
);
$el
.
popover
({
html
:
true
,
placement
:
options
.
ui
.
popoverPlacement
,
trigger
:
"manual"
,
content
:
" "
});
};
ui
.
initUI
=
function
(
options
,
$el
)
{
if
(
options
.
ui
.
showPopover
)
{
ui
.
initPopover
(
options
,
$el
);
}
else
{
if
(
options
.
ui
.
showErrors
)
{
ui
.
initErrorList
(
options
,
$el
);
}
if
(
options
.
ui
.
showVerdicts
&&
!
options
.
ui
.
showVerdictsInsideProgressBar
)
{
ui
.
initVerdict
(
options
,
$el
);
}
}
if
(
options
.
ui
.
showProgressBar
)
{
ui
.
initProgressBar
(
options
,
$el
);
}
if
(
options
.
ui
.
showScore
)
{
ui
.
initScore
(
options
,
$el
);
}
};
ui
.
updateProgressBar
=
function
(
options
,
$el
,
cssClass
,
percentage
)
{
var
$progressbar
=
ui
.
getUIElements
(
options
,
$el
).
$progressbar
,
$bar
=
$progressbar
.
find
(
".progress-bar"
),
cssPrefix
=
"progress-"
;
if
(
options
.
ui
.
bootstrap2
)
{
$bar
=
$progressbar
.
find
(
".bar"
);
cssPrefix
=
""
;
}
$
.
each
(
options
.
ui
.
colorClasses
,
function
(
idx
,
value
)
{
if
(
options
.
ui
.
bootstrap4
)
{
$bar
.
removeClass
(
"bg-"
+
value
);
}
else
{
$bar
.
removeClass
(
cssPrefix
+
"bar-"
+
value
);
}
});
if
(
options
.
ui
.
bootstrap4
)
{
$bar
.
addClass
(
"bg-"
+
options
.
ui
.
colorClasses
[
cssClass
]);
}
else
{
$bar
.
addClass
(
cssPrefix
+
"bar-"
+
options
.
ui
.
colorClasses
[
cssClass
]);
}
$bar
.
css
(
"width"
,
percentage
+
'%'
);
};
ui
.
updateVerdict
=
function
(
options
,
$el
,
cssClass
,
text
)
{
var
$verdict
=
ui
.
getUIElements
(
options
,
$el
).
$verdict
;
$verdict
.
removeClass
(
options
.
ui
.
colorClasses
.
join
(
' '
));
if
(
cssClass
>
-
1
)
{
$verdict
.
addClass
(
options
.
ui
.
colorClasses
[
cssClass
]);
}
if
(
options
.
ui
.
showVerdictsInsideProgressBar
)
{
$verdict
.
css
(
'white-space'
,
'nowrap'
);
}
$verdict
.
html
(
text
);
};
ui
.
updateErrors
=
function
(
options
,
$el
,
remove
)
{
var
$errors
=
ui
.
getUIElements
(
options
,
$el
).
$errors
,
html
=
""
;
if
(
!
remove
)
{
$
.
each
(
options
.
instances
.
errors
,
function
(
idx
,
err
)
{
html
+=
"<li style='list-style-type:none;'>"
+
err
+
"</li>"
;
});
}
$errors
.
html
(
html
);
};
ui
.
updateScore
=
function
(
options
,
$el
,
score
,
remove
)
{
var
$score
=
ui
.
getUIElements
(
options
,
$el
).
$score
,
html
=
""
;
if
(
!
remove
)
{
html
=
score
.
toFixed
(
2
);
}
$score
.
html
(
html
);
};
ui
.
updatePopover
=
function
(
options
,
$el
,
verdictText
,
remove
)
{
var
popover
=
$el
.
data
(
"bs.popover"
),
html
=
""
,
hide
=
true
;
if
(
options
.
ui
.
showVerdicts
&&
!
options
.
ui
.
showVerdictsInsideProgressBar
&&
verdictText
.
length
>
0
)
{
html
=
"<h5><span class='password-verdict'>"
+
verdictText
+
"</span></h5>"
;
hide
=
false
;
}
if
(
options
.
ui
.
showErrors
)
{
if
(
options
.
instances
.
errors
.
length
>
0
)
{
hide
=
false
;
}
html
+=
options
.
ui
.
popoverError
(
options
);
}
if
(
hide
||
remove
)
{
$el
.
popover
(
"hide"
);
return
;
}
if
(
options
.
ui
.
bootstrap2
)
{
popover
=
$el
.
data
(
"popover"
);
}
if
(
popover
.
$arrow
&&
popover
.
$arrow
.
parents
(
"body"
).
length
>
0
)
{
$el
.
find
(
"+ .popover .popover-content"
).
html
(
html
);
}
else
{
// It's hidden
popover
.
options
.
content
=
html
;
$el
.
popover
(
"show"
);
}
};
ui
.
updateFieldStatus
=
function
(
options
,
$el
,
cssClass
,
remove
)
{
var
targetClass
=
options
.
ui
.
bootstrap2
?
".control-group"
:
".form-group"
,
$container
=
$el
.
parents
(
targetClass
).
first
();
$
.
each
(
statusClasses
,
function
(
idx
,
css
)
{
if
(
!
options
.
ui
.
bootstrap2
)
{
css
=
"has-"
+
css
;
}
$container
.
removeClass
(
css
);
});
if
(
remove
)
{
return
;
}
cssClass
=
statusClasses
[
Math
.
floor
(
cssClass
/
2
)];
if
(
!
options
.
ui
.
bootstrap2
)
{
cssClass
=
"has-"
+
cssClass
;
}
$container
.
addClass
(
cssClass
);
};
ui
.
percentage
=
function
(
options
,
score
,
maximun
)
{
var
result
=
Math
.
floor
(
100
*
score
/
maximun
),
min
=
options
.
ui
.
progressBarMinPercentage
;
result
=
result
<=
min
?
min
:
result
;
result
=
result
>
100
?
100
:
result
;
return
result
;
};
ui
.
getVerdictAndCssClass
=
function
(
options
,
score
)
{
var
level
,
verdict
;
if
(
score
===
undefined
)
{
return
[
''
,
0
];
}
if
(
score
<=
options
.
ui
.
scores
[
0
])
{
level
=
0
;
}
else
if
(
score
<
options
.
ui
.
scores
[
1
])
{
level
=
1
;
}
else
if
(
score
<
options
.
ui
.
scores
[
2
])
{
level
=
2
;
}
else
if
(
score
<
options
.
ui
.
scores
[
3
])
{
level
=
3
;
}
else
if
(
score
<
options
.
ui
.
scores
[
4
])
{
level
=
4
;
}
else
{
level
=
5
;
}
verdict
=
verdictKeys
[
level
];
return
[
options
.
i18n
.
t
(
verdict
),
level
];
};
ui
.
updateUI
=
function
(
options
,
$el
,
score
)
{
var
cssClass
,
barPercentage
,
verdictText
,
verdictCssClass
;
cssClass
=
ui
.
getVerdictAndCssClass
(
options
,
score
);
verdictText
=
score
===
0
?
''
:
cssClass
[
0
];
cssClass
=
cssClass
[
1
];
verdictCssClass
=
options
.
ui
.
useVerdictCssClass
?
cssClass
:
-
1
;
if
(
options
.
ui
.
showProgressBar
)
{
if
(
score
===
undefined
)
{
barPercentage
=
options
.
ui
.
progressBarEmptyPercentage
;
}
else
{
barPercentage
=
ui
.
percentage
(
options
,
score
,
options
.
ui
.
scores
[
4
]);
}
ui
.
updateProgressBar
(
options
,
$el
,
cssClass
,
barPercentage
);
if
(
options
.
ui
.
showVerdictsInsideProgressBar
)
{
ui
.
updateVerdict
(
options
,
$el
,
verdictCssClass
,
verdictText
);
}
}
if
(
options
.
ui
.
showStatus
)
{
ui
.
updateFieldStatus
(
options
,
$el
,
cssClass
,
score
===
undefined
);
}
if
(
options
.
ui
.
showPopover
)
{
ui
.
updatePopover
(
options
,
$el
,
verdictText
,
score
===
undefined
);
}
else
{
if
(
options
.
ui
.
showVerdicts
&&
!
options
.
ui
.
showVerdictsInsideProgressBar
)
{
ui
.
updateVerdict
(
options
,
$el
,
verdictCssClass
,
verdictText
);
}
if
(
options
.
ui
.
showErrors
)
{
ui
.
updateErrors
(
options
,
$el
,
score
===
undefined
);
}
}
if
(
options
.
ui
.
showScore
)
{
ui
.
updateScore
(
options
,
$el
,
score
,
score
===
undefined
);
}
};
}(
jQuery
,
ui
));
// Source: src/methods.js
var
methods
=
{};
(
function
(
$
,
methods
)
{
"use strict"
;
var
onKeyUp
,
onPaste
,
applyToAll
;
onKeyUp
=
function
(
event
)
{
var
$el
=
$
(
event
.
target
),
options
=
$el
.
data
(
"pwstrength-bootstrap"
),
word
=
$el
.
val
(),
userInputs
,
verdictText
,
verdictLevel
,
score
;
if
(
options
===
undefined
)
{
return
;
}
options
.
instances
.
errors
=
[];
if
(
word
.
length
===
0
)
{
score
=
undefined
;
}
else
{
if
(
options
.
common
.
zxcvbn
)
{
userInputs
=
[];
$
.
each
(
options
.
common
.
userInputs
.
concat
([
options
.
common
.
usernameField
]),
function
(
idx
,
selector
)
{
var
value
=
$
(
selector
).
val
();
if
(
value
)
{
userInputs
.
push
(
value
);
}
});
userInputs
=
userInputs
.
concat
(
options
.
common
.
zxcvbnTerms
);
score
=
zxcvbn
(
word
,
userInputs
).
guesses
;
score
=
Math
.
log
(
score
)
*
Math
.
LOG2E
;
}
else
{
score
=
rulesEngine
.
executeRules
(
options
,
word
);
}
if
(
$
.
isFunction
(
options
.
common
.
onScore
))
{
score
=
options
.
common
.
onScore
(
options
,
word
,
score
);
}
}
ui
.
updateUI
(
options
,
$el
,
score
);
verdictText
=
ui
.
getVerdictAndCssClass
(
options
,
score
);
verdictLevel
=
verdictText
[
1
];
verdictText
=
verdictText
[
0
];
if
(
options
.
common
.
debug
)
{
console
.
log
(
score
+
' - '
+
verdictText
);
}
if
(
$
.
isFunction
(
options
.
common
.
onKeyUp
))
{
options
.
common
.
onKeyUp
(
event
,
{
score
:
score
,
verdictText
:
verdictText
,
verdictLevel
:
verdictLevel
});
}
};
onPaste
=
function
(
event
)
{
// This handler is necessary because the paste event fires before the
// content is actually in the input, so we cannot read its value right
// away. Therefore, the timeouts.
var
$el
=
$
(
event
.
target
),
word
=
$el
.
val
(),
tries
=
0
,
callback
;
callback
=
function
()
{
var
newWord
=
$el
.
val
();
if
(
newWord
!==
word
)
{
onKeyUp
(
event
);
}
else
if
(
tries
<
3
)
{
tries
+=
1
;
setTimeout
(
callback
,
100
);
}
};
setTimeout
(
callback
,
100
);
};
methods
.
init
=
function
(
settings
)
{
this
.
each
(
function
(
idx
,
el
)
{
// Make it deep extend (first param) so it extends also the
// rules and other inside objects
var
clonedDefaults
=
$
.
extend
(
true
,
{},
defaultOptions
),
localOptions
=
$
.
extend
(
true
,
clonedDefaults
,
settings
),
$el
=
$
(
el
);
localOptions
.
instances
=
{};
$el
.
data
(
"pwstrength-bootstrap"
,
localOptions
);
$
.
each
(
localOptions
.
common
.
events
,
function
(
idx
,
eventName
)
{
var
handler
=
eventName
===
"paste"
?
onPaste
:
onKeyUp
;
$el
.
on
(
eventName
,
handler
);
});
ui
.
initUI
(
localOptions
,
$el
);
$el
.
trigger
(
"keyup"
);
if
(
$
.
isFunction
(
localOptions
.
common
.
onLoad
))
{
localOptions
.
common
.
onLoad
();
}
});
return
this
;
};
methods
.
destroy
=
function
()
{
this
.
each
(
function
(
idx
,
el
)
{
var
$el
=
$
(
el
),
options
=
$el
.
data
(
"pwstrength-bootstrap"
),
elements
=
ui
.
getUIElements
(
options
,
$el
);
elements
.
$progressbar
.
remove
();
elements
.
$verdict
.
remove
();
elements
.
$errors
.
remove
();
$el
.
removeData
(
"pwstrength-bootstrap"
);
});
};
methods
.
forceUpdate
=
function
()
{
this
.
each
(
function
(
idx
,
el
)
{
var
event
=
{
target
:
el
};
onKeyUp
(
event
);
});
};
methods
.
addRule
=
function
(
name
,
method
,
score
,
active
)
{
this
.
each
(
function
(
idx
,
el
)
{
var
options
=
$
(
el
).
data
(
"pwstrength-bootstrap"
);
options
.
rules
.
activated
[
name
]
=
active
;
options
.
rules
.
scores
[
name
]
=
score
;
options
.
rules
.
extra
[
name
]
=
method
;
});
};
applyToAll
=
function
(
rule
,
prop
,
value
)
{
this
.
each
(
function
(
idx
,
el
)
{
$
(
el
).
data
(
"pwstrength-bootstrap"
).
rules
[
prop
][
rule
]
=
value
;
});
};
methods
.
changeScore
=
function
(
rule
,
score
)
{
applyToAll
.
call
(
this
,
rule
,
"scores"
,
score
);
};
methods
.
ruleActive
=
function
(
rule
,
active
)
{
applyToAll
.
call
(
this
,
rule
,
"activated"
,
active
);
};
methods
.
ruleIsMet
=
function
(
rule
)
{
if
(
$
.
isFunction
(
rulesEngine
.
validation
[
rule
]))
{
if
(
rule
===
"wordMinLength"
)
{
rule
=
"wordMinLengthStaticScore"
;
}
else
if
(
rule
===
"wordMaxLength"
)
{
rule
=
"wordMaxLengthStaticScore"
;
}
var
rulesMetCnt
=
0
;
this
.
each
(
function
(
idx
,
el
)
{
var
options
=
$
(
el
).
data
(
"pwstrength-bootstrap"
);
rulesMetCnt
+=
rulesEngine
.
validation
[
rule
](
options
,
$
(
el
).
val
(),
1
);
});
return
(
rulesMetCnt
===
this
.
length
);
}
$
.
error
(
"Rule "
+
rule
+
" does not exist on jQuery.pwstrength-bootstrap.validation"
);
};
$
.
fn
.
pwstrength
=
function
(
method
)
{
var
result
;
if
(
methods
[
method
])
{
result
=
methods
[
method
].
apply
(
this
,
Array
.
prototype
.
slice
.
call
(
arguments
,
1
));
}
else
if
(
typeof
method
===
"object"
||
!
method
)
{
result
=
methods
.
init
.
apply
(
this
,
arguments
);
}
else
{
$
.
error
(
"Method "
+
method
+
" does not exist on jQuery.pwstrength-bootstrap"
);
}
return
result
;
};
}(
jQuery
,
methods
));
}(
jQuery
));
\ No newline at end of file
apps/templates/_base_create_update.html
View file @
0a2ff83c
...
@@ -5,6 +5,7 @@
...
@@ -5,6 +5,7 @@
{% block custom_head_css_js %}
{% block custom_head_css_js %}
<link
href=
"{% static 'css/plugins/select2/select2.min.css' %}"
rel=
"stylesheet"
>
<link
href=
"{% static 'css/plugins/select2/select2.min.css' %}"
rel=
"stylesheet"
>
<script
src=
"{% static 'js/plugins/select2/select2.full.min.js' %}"
></script>
<script
src=
"{% static 'js/plugins/select2/select2.full.min.js' %}"
></script>
<script
type=
"text/javascript"
src=
"{% static 'js/pwstrength-bootstrap.js' %}"
></script>
{% block custom_head_css_js_create %} {% endblock %}
{% block custom_head_css_js_create %} {% endblock %}
{% endblock %}
{% endblock %}
...
...
apps/templates/_footer.html
View file @
0a2ff83c
<div
class=
"footer fixed"
>
<div
class=
"footer fixed"
>
<div
class=
"pull-right"
>
<div
class=
"pull-right"
>
Version
<strong>
1.3.
1
-{% include '_build.html' %}
</strong>
GPLv2.
Version
<strong>
1.3.
2
-{% include '_build.html' %}
</strong>
GPLv2.
<
img
style=
"display: none"
src=
"http://www.jumpserver.org/img/evaluate_avatar1.jpg"
>
<
!--<img style="display: none" src="http://www.jumpserver.org/img/evaluate_avatar1.jpg">--
>
</div>
</div>
<div>
<div>
<strong>
Copyright
</strong>
北京堆栈科技有限公司
©
2014-2018
<strong>
Copyright
</strong>
北京堆栈科技有限公司
©
2014-2018
...
...
apps/users/forms.py
View file @
0a2ff83c
...
@@ -16,13 +16,14 @@ class UserLoginForm(AuthenticationForm):
...
@@ -16,13 +16,14 @@ class UserLoginForm(AuthenticationForm):
max_length
=
128
,
strip
=
False
max_length
=
128
,
strip
=
False
)
)
def
confirm_login_allowed
(
self
,
user
):
if
not
user
.
is_staff
:
raise
forms
.
ValidationError
(
self
.
error_messages
[
'inactive'
],
code
=
'inactive'
,)
class
UserLoginCaptchaForm
(
AuthenticationForm
):
username
=
forms
.
CharField
(
label
=
_
(
'Username'
),
max_length
=
100
)
class
UserLoginCaptchaForm
(
UserLoginForm
):
password
=
forms
.
CharField
(
label
=
_
(
'Password'
),
widget
=
forms
.
PasswordInput
,
max_length
=
128
,
strip
=
False
)
captcha
=
CaptchaField
()
captcha
=
CaptchaField
()
...
@@ -72,7 +73,7 @@ class UserCreateUpdateForm(forms.ModelForm):
...
@@ -72,7 +73,7 @@ class UserCreateUpdateForm(forms.ModelForm):
'data-placeholder'
:
_
(
'Join user groups'
)
'data-placeholder'
:
_
(
'Join user groups'
)
}
}
),
),
'otp_level'
:
forms
.
RadioSelect
()
'otp_level'
:
forms
.
RadioSelect
()
,
}
}
def
clean_public_key
(
self
):
def
clean_public_key
(
self
):
...
...
apps/users/models/group.py
View file @
0a2ff83c
...
@@ -4,12 +4,10 @@ import uuid
...
@@ -4,12 +4,10 @@ import uuid
from
django.db
import
models
,
IntegrityError
from
django.db
import
models
,
IntegrityError
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.utils.translation
import
ugettext_lazy
as
_
from
common.mixins
import
NoDeleteModelMixin
__all__
=
[
'UserGroup'
]
__all__
=
[
'UserGroup'
]
class
UserGroup
(
NoDeleteModelMixin
):
class
UserGroup
(
models
.
Model
):
id
=
models
.
UUIDField
(
default
=
uuid
.
uuid4
,
primary_key
=
True
)
id
=
models
.
UUIDField
(
default
=
uuid
.
uuid4
,
primary_key
=
True
)
name
=
models
.
CharField
(
max_length
=
128
,
unique
=
True
,
verbose_name
=
_
(
'Name'
))
name
=
models
.
CharField
(
max_length
=
128
,
unique
=
True
,
verbose_name
=
_
(
'Name'
))
comment
=
models
.
TextField
(
blank
=
True
,
verbose_name
=
_
(
'Comment'
))
comment
=
models
.
TextField
(
blank
=
True
,
verbose_name
=
_
(
'Comment'
))
...
...
apps/users/models/user.py
View file @
0a2ff83c
...
@@ -14,6 +14,7 @@ from django.utils import timezone
...
@@ -14,6 +14,7 @@ from django.utils import timezone
from
django.shortcuts
import
reverse
from
django.shortcuts
import
reverse
from
common.utils
import
get_signer
,
date_expired_default
from
common.utils
import
get_signer
,
date_expired_default
from
common.models
import
Setting
__all__
=
[
'User'
]
__all__
=
[
'User'
]
...
@@ -35,6 +36,12 @@ class User(AbstractUser):
...
@@ -35,6 +36,12 @@ class User(AbstractUser):
(
1
,
_
(
'Enable'
)),
(
1
,
_
(
'Enable'
)),
(
2
,
_
(
"Force enable"
)),
(
2
,
_
(
"Force enable"
)),
)
)
SOURCE_LOCAL
=
'local'
SOURCE_LDAP
=
'ldap'
SOURCE_CHOICES
=
(
(
SOURCE_LOCAL
,
'Local'
),
(
SOURCE_LDAP
,
'LDAP/AD'
),
)
id
=
models
.
UUIDField
(
default
=
uuid
.
uuid4
,
primary_key
=
True
)
id
=
models
.
UUIDField
(
default
=
uuid
.
uuid4
,
primary_key
=
True
)
username
=
models
.
CharField
(
username
=
models
.
CharField
(
max_length
=
128
,
unique
=
True
,
verbose_name
=
_
(
'Username'
)
max_length
=
128
,
unique
=
True
,
verbose_name
=
_
(
'Username'
)
...
@@ -82,6 +89,10 @@ class User(AbstractUser):
...
@@ -82,6 +89,10 @@ class User(AbstractUser):
created_by
=
models
.
CharField
(
created_by
=
models
.
CharField
(
max_length
=
30
,
default
=
''
,
verbose_name
=
_
(
'Created by'
)
max_length
=
30
,
default
=
''
,
verbose_name
=
_
(
'Created by'
)
)
)
source
=
models
.
CharField
(
max_length
=
30
,
default
=
SOURCE_LOCAL
,
choices
=
SOURCE_CHOICES
,
verbose_name
=
_
(
'Source'
)
)
def
__str__
(
self
):
def
__str__
(
self
):
return
'{0.name}({0.username})'
.
format
(
self
)
return
'{0.name}({0.username})'
.
format
(
self
)
...
@@ -248,14 +259,17 @@ class User(AbstractUser):
...
@@ -248,14 +259,17 @@ class User(AbstractUser):
@property
@property
def
otp_enabled
(
self
):
def
otp_enabled
(
self
):
return
self
.
otp_level
>
0
return
self
.
otp_
force_enabled
or
self
.
otp_
level
>
0
@property
@property
def
otp_force_enabled
(
self
):
def
otp_force_enabled
(
self
):
mfa_setting
=
Setting
.
objects
.
filter
(
name
=
'SECURITY_MFA_AUTH'
)
.
first
()
if
mfa_setting
and
mfa_setting
.
cleaned_value
:
return
True
return
self
.
otp_level
==
2
return
self
.
otp_level
==
2
def
enable_otp
(
self
):
def
enable_otp
(
self
):
if
not
self
.
otp_
force_enabled
:
if
not
self
.
otp_
level
==
2
:
self
.
otp_level
=
1
self
.
otp_level
=
1
def
force_enable_otp
(
self
):
def
force_enable_otp
(
self
):
...
@@ -275,6 +289,7 @@ class User(AbstractUser):
...
@@ -275,6 +289,7 @@ class User(AbstractUser):
'is_superuser'
:
self
.
is_superuser
,
'is_superuser'
:
self
.
is_superuser
,
'role'
:
self
.
get_role_display
(),
'role'
:
self
.
get_role_display
(),
'groups'
:
[
group
.
name
for
group
in
self
.
groups
.
all
()],
'groups'
:
[
group
.
name
for
group
in
self
.
groups
.
all
()],
'source'
:
self
.
get_source_display
(),
'wechat'
:
self
.
wechat
,
'wechat'
:
self
.
wechat
,
'phone'
:
self
.
phone
,
'phone'
:
self
.
phone
,
'otp_level'
:
self
.
otp_level
,
'otp_level'
:
self
.
otp_level
,
...
...
apps/users/serializers.py
View file @
0a2ff83c
...
@@ -26,7 +26,10 @@ class UserSerializer(BulkSerializerMixin, serializers.ModelSerializer):
...
@@ -26,7 +26,10 @@ class UserSerializer(BulkSerializerMixin, serializers.ModelSerializer):
def
get_field_names
(
self
,
declared_fields
,
info
):
def
get_field_names
(
self
,
declared_fields
,
info
):
fields
=
super
(
UserSerializer
,
self
)
.
get_field_names
(
declared_fields
,
info
)
fields
=
super
(
UserSerializer
,
self
)
.
get_field_names
(
declared_fields
,
info
)
fields
.
extend
([
'groups_display'
,
'get_role_display'
,
'is_valid'
])
fields
.
extend
([
'groups_display'
,
'get_role_display'
,
'get_source_display'
,
'is_valid'
])
return
fields
return
fields
@staticmethod
@staticmethod
...
...
apps/users/signals_handler.py
View file @
0a2ff83c
...
@@ -2,6 +2,7 @@
...
@@ -2,6 +2,7 @@
#
#
from
django.dispatch
import
receiver
from
django.dispatch
import
receiver
from
django_auth_ldap.backend
import
populate_user
# from django.db.models.signals import post_save
# from django.db.models.signals import post_save
from
common.utils
import
get_logger
from
common.utils
import
get_logger
...
@@ -28,3 +29,11 @@ def on_user_create(sender, user=None, **kwargs):
...
@@ -28,3 +29,11 @@ def on_user_create(sender, user=None, **kwargs):
logger
.
info
(
" - Sending welcome mail ..."
.
format
(
user
.
name
))
logger
.
info
(
" - Sending welcome mail ..."
.
format
(
user
.
name
))
if
user
.
email
:
if
user
.
email
:
send_user_created_mail
(
user
)
send_user_created_mail
(
user
)
@receiver
(
populate_user
)
def
on_ldap_create_user
(
sender
,
user
,
ldap_user
,
**
kwargs
):
if
user
:
user
.
source
=
user
.
SOURCE_LDAP
user
.
save
()
apps/users/templates/users/_user.html
View file @
0a2ff83c
...
@@ -48,6 +48,7 @@
...
@@ -48,6 +48,7 @@
</div>
</div>
</div>
</div>
</form>
</form>
{% endblock %}
{% endblock %}
{% block custom_foot_js %}
{% block custom_foot_js %}
<script
src=
"{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"
></script>
<script
src=
"{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"
></script>
...
...
apps/users/templates/users/first_login.html
View file @
0a2ff83c
...
@@ -122,10 +122,10 @@
...
@@ -122,10 +122,10 @@
{% block custom_foot_js %}
{% block custom_foot_js %}
<script>
<script>
$
(
document
).
on
(
'click'
,
".fl_goto"
,
function
(){
$
(
document
).
on
(
'click'
,
".fl_goto"
,
function
(){
var
$form
=
$
(
'#fl_form'
);
var
$form
=
$
(
'#fl_form'
);
$
(
'<input />'
,
{
'name'
:
'wizard_goto_step'
,
'value'
:
$
(
this
).
data
(
'goto'
),
'type'
:
'hidden'
}).
appendTo
(
$form
);
$
(
'<input />'
,
{
'name'
:
'wizard_goto_step'
,
'value'
:
$
(
this
).
data
(
'goto'
),
'type'
:
'hidden'
}).
appendTo
(
$form
);
$form
.
submit
();
$form
.
submit
();
return
false
;
return
false
;
}).
on
(
'click'
,
'#fl_submit'
,
function
(){
}).
on
(
'click'
,
'#fl_submit'
,
function
(){
var
isFinish
=
$
(
'#fl_submit'
).
html
()
===
"{% trans 'Finish' %}"
;
var
isFinish
=
$
(
'#fl_submit'
).
html
()
===
"{% trans 'Finish' %}"
;
var
noChecked
=
!
$
(
'#acceptTerms'
).
prop
(
'checked'
);
var
noChecked
=
!
$
(
'#acceptTerms'
).
prop
(
'checked'
);
...
@@ -137,9 +137,10 @@
...
@@ -137,9 +137,10 @@
return
false
;
return
false
;
}
}
}).
on
(
'click'
,
'#btn-reset-pubkey'
,
function
()
{
}).
on
(
'click'
,
'#btn-reset-pubkey'
,
function
()
{
var
the_url
=
'{% url "users:user-pubkey-generate" %}'
;
var
the_url
=
'{% url "users:user-pubkey-generate" %}'
;
window
.
open
(
the_url
,
"_blank"
)
window
.
open
(
the_url
,
"_blank"
);
})
$
(
'#fl_form'
).
submit
();
})
</script>
</script>
{% endblock %}
{% endblock %}
apps/users/templates/users/reset_password.html
View file @
0a2ff83c
...
@@ -11,6 +11,7 @@
...
@@ -11,6 +11,7 @@
{% include '_head_css_js.html' %}
{% include '_head_css_js.html' %}
<link
href=
"{% static "
css
/
jumpserver
.
css
"
%}"
rel=
"stylesheet"
>
<link
href=
"{% static "
css
/
jumpserver
.
css
"
%}"
rel=
"stylesheet"
>
<script
src=
"{% static "
js
/
jumpserver
.
js
"
%}"
></script>
<script
src=
"{% static "
js
/
jumpserver
.
js
"
%}"
></script>
<script
type=
"text/javascript"
src=
"{% static 'js/pwstrength-bootstrap.js' %}"
></script>
</head>
</head>
...
@@ -49,10 +50,20 @@
...
@@ -49,10 +50,20 @@
<p
class=
"red-fonts"
>
{{ errors }}
</p>
<p
class=
"red-fonts"
>
{{ errors }}
</p>
{% endif %}
{% endif %}
<div
class=
"form-group"
>
<div
class=
"form-group"
>
<input
type=
"password"
class=
"form-control"
name=
"password"
placeholder=
"{% trans 'Password' %}"
required=
""
>
<input
type=
"password"
id=
"id_new_password"
class=
"form-control"
name=
"password"
placeholder=
"{% trans 'Password' %}"
required=
""
>
{# 密码popover #}
<div
id=
"container"
>
<div
class=
"popover fade bottom in"
role=
"tooltip"
id=
"popover777"
style=
" display: none; width:260px;"
>
<div
class=
"arrow"
style=
"left: 50%;"
></div>
<h3
class=
"popover-title"
style=
"display: none;"
></h3>
<h4>
{% trans 'Your password must satisfy' %}
</h4><div
id=
"id_password_rules"
style=
"color: #908a8a; margin-left:20px; font-size:15px;"
></div>
<h4
style=
"margin-top: 10px;"
>
{% trans 'Password strength' %}
</h4><div
id=
"id_progress"
></div>
<div
class=
"popover-content"
></div>
</div>
</div>
</div>
</div>
<div
class=
"form-group"
>
<div
class=
"form-group"
>
<input
type=
"password"
class=
"form-control"
name=
"password-confirm"
placeholder=
"{% trans 'Password again' %}"
required=
""
>
<input
type=
"password"
id=
"id_confirm_password"
class=
"form-control"
name=
"password-confirm"
placeholder=
"{% trans 'Password again' %}"
required=
""
>
</div>
</div>
<button
type=
"submit"
class=
"btn btn-primary block full-width m-b"
>
{% trans "Setting" %}
</button>
<button
type=
"submit"
class=
"btn btn-primary block full-width m-b"
>
{% trans "Setting" %}
</button>
...
@@ -79,4 +90,33 @@
...
@@ -79,4 +90,33 @@
</body>
</body>
</html>
</html>
<script>
$
(
document
).
ready
(
function
()
{
// 密码强度校验
var
el
=
$
(
'#id_password_rules'
),
idPassword
=
$
(
'#id_new_password'
),
idPopover
=
$
(
'#popover777'
),
container
=
$
(
'#container'
),
progress
=
$
(
'#id_progress'
),
password_check_rules
=
{{
password_check_rules
|
safe
}},
minLength
=
{{
min_length
}},
top
=
146
,
left
=
170
;
// 初始化popover
initPopover
(
container
,
progress
,
idPassword
,
el
,
password_check_rules
);
// 监听事件
idPassword
.
on
(
'focus'
,
function
()
{
idPopover
.
css
(
'top'
,
top
);
idPopover
.
css
(
'left'
,
left
);
idPopover
.
css
(
'display'
,
'block'
);
});
idPassword
.
on
(
'blur'
,
function
()
{
idPopover
.
css
(
'display'
,
'none'
);
});
idPassword
.
on
(
'keyup'
,
function
(){
var
password
=
idPassword
.
val
();
checkPasswordRules
(
password
,
minLength
);
})
})
</script>
apps/users/templates/users/user_detail.html
View file @
0a2ff83c
...
@@ -99,6 +99,10 @@
...
@@ -99,6 +99,10 @@
{% endif %}
{% endif %}
</b></td>
</b></td>
</tr>
</tr>
<tr>
<td>
{% trans 'Source' %}:
</td>
<td><b>
{{ user_object.get_source_display }}
</b></td>
</tr>
<tr>
<tr>
<td>
{% trans 'Date expired' %}:
</td>
<td>
{% trans 'Date expired' %}:
</td>
<td><b>
{{ user_object.date_expired|date:"Y-m-j H:i:s" }}
</b></td>
<td><b>
{{ user_object.date_expired|date:"Y-m-j H:i:s" }}
</b></td>
...
...
apps/users/templates/users/user_list.html
View file @
0a2ff83c
...
@@ -24,6 +24,7 @@
...
@@ -24,6 +24,7 @@
<th
class=
"text-center"
>
{% trans 'Username' %}
</th>
<th
class=
"text-center"
>
{% trans 'Username' %}
</th>
<th
class=
"text-center"
>
{% trans 'Role' %}
</th>
<th
class=
"text-center"
>
{% trans 'Role' %}
</th>
<th
class=
"text-center"
>
{% trans 'User group' %}
</th>
<th
class=
"text-center"
>
{% trans 'User group' %}
</th>
<th
class=
"text-center"
>
{% trans 'Source' %}
</th>
<th
class=
"text-center"
>
{% trans 'Active' %}
</th>
<th
class=
"text-center"
>
{% trans 'Active' %}
</th>
<th
class=
"text-center"
>
{% trans 'Action' %}
</th>
<th
class=
"text-center"
>
{% trans 'Action' %}
</th>
</tr>
</tr>
...
@@ -65,14 +66,14 @@ function initTable() {
...
@@ -65,14 +66,14 @@ function initTable() {
var
innerHtml
=
cellData
.
length
>
20
?
cellData
.
substring
(
0
,
20
)
+
'...'
:
cellData
;
var
innerHtml
=
cellData
.
length
>
20
?
cellData
.
substring
(
0
,
20
)
+
'...'
:
cellData
;
$
(
td
).
html
(
'<span href="javascript:void(0);" data-toggle="tooltip" title="'
+
cellData
+
'">'
+
innerHtml
+
'</span>'
);
$
(
td
).
html
(
'<span href="javascript:void(0);" data-toggle="tooltip" title="'
+
cellData
+
'">'
+
innerHtml
+
'</span>'
);
}},
}},
{
targets
:
5
,
createdCell
:
function
(
td
,
cellData
)
{
{
targets
:
6
,
createdCell
:
function
(
td
,
cellData
)
{
if
(
!
cellData
)
{
if
(
!
cellData
)
{
$
(
td
).
html
(
'<i class="fa fa-times text-danger"></i>'
)
$
(
td
).
html
(
'<i class="fa fa-times text-danger"></i>'
)
}
else
{
}
else
{
$
(
td
).
html
(
'<i class="fa fa-check text-navy"></i>'
)
$
(
td
).
html
(
'<i class="fa fa-check text-navy"></i>'
)
}
}
}},
}},
{
targets
:
6
,
createdCell
:
function
(
td
,
cellData
,
rowData
)
{
{
targets
:
7
,
createdCell
:
function
(
td
,
cellData
,
rowData
)
{
var
update_btn
=
'<a href="{% url "users:user-update" pk=DEFAULT_PK %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'
.
replace
(
'00000000-0000-0000-0000-000000000000'
,
cellData
);
var
update_btn
=
'<a href="{% url "users:user-update" pk=DEFAULT_PK %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'
.
replace
(
'00000000-0000-0000-0000-000000000000'
,
cellData
);
var
del_btn
=
""
;
var
del_btn
=
""
;
...
@@ -90,7 +91,7 @@ function initTable() {
...
@@ -90,7 +91,7 @@ function initTable() {
ajax_url
:
'{% url "api-users:user-list" %}'
,
ajax_url
:
'{% url "api-users:user-list" %}'
,
columns
:
[
columns
:
[
{
data
:
"id"
},
{
data
:
"name"
},
{
data
:
"username"
},
{
data
:
"get_role_display"
},
{
data
:
"id"
},
{
data
:
"name"
},
{
data
:
"username"
},
{
data
:
"get_role_display"
},
{
data
:
"groups_display"
},
{
data
:
"is_valid"
},
{
data
:
"id"
}
{
data
:
"groups_display"
},
{
data
:
"
get_source_display"
},
{
data
:
"
is_valid"
},
{
data
:
"id"
}
],
],
op_html
:
$
(
'#actions'
).
html
()
op_html
:
$
(
'#actions'
).
html
()
};
};
...
...
apps/users/templates/users/user_password_update.html
View file @
0a2ff83c
...
@@ -7,6 +7,8 @@
...
@@ -7,6 +7,8 @@
<link
href=
"{% static "
css
/
plugins
/
cropper
/
cropper
.
min
.
css
"
%}"
rel=
"stylesheet"
>
<link
href=
"{% static "
css
/
plugins
/
cropper
/
cropper
.
min
.
css
"
%}"
rel=
"stylesheet"
>
<link
href=
"{% static "
css
/
plugins
/
sweetalert
/
sweetalert
.
css
"
%}"
rel=
"stylesheet"
>
<link
href=
"{% static "
css
/
plugins
/
sweetalert
/
sweetalert
.
css
"
%}"
rel=
"stylesheet"
>
<script
src=
"{% static "
js
/
plugins
/
sweetalert
/
sweetalert
.
min
.
js
"
%}"
></script>
<script
src=
"{% static "
js
/
plugins
/
sweetalert
/
sweetalert
.
min
.
js
"
%}"
></script>
<script
type=
"text/javascript"
src=
"{% static 'js/pwstrength-bootstrap.js' %}"
></script>
<script
src=
"{% static "
js
/
jumpserver
.
js
"
%}"
></script>
<style>
<style>
.crop
{
.crop
{
...
@@ -50,6 +52,16 @@
...
@@ -50,6 +52,16 @@
{% csrf_token %}
{% csrf_token %}
{% bootstrap_field form.old_password layout="horizontal" %}
{% bootstrap_field form.old_password layout="horizontal" %}
{% bootstrap_field form.new_password layout="horizontal" %}
{% bootstrap_field form.new_password layout="horizontal" %}
{# 密码popover #}
<div
id=
"container"
>
<div
class=
"popover fade bottom in"
role=
"tooltip"
id=
"popover777"
style=
" display: none; width:260px;"
>
<div
class=
"arrow"
style=
"left: 50%;"
></div>
<h3
class=
"popover-title"
style=
"display: none;"
></h3>
<h4>
{% trans 'Your password must satisfy' %}
</h4><div
id=
"id_password_rules"
style=
"color: #908a8a; margin-left:20px; font-size:15px;"
></div>
<h4
style=
"margin-top: 10px;"
>
{% trans 'Password strength' %}
</h4><div
id=
"id_progress"
></div>
<div
class=
"popover-content"
></div>
</div>
</div>
{% bootstrap_field form.confirm_password layout="horizontal" %}
{% bootstrap_field form.confirm_password layout="horizontal" %}
<div
class=
"hr-line-dashed"
></div>
<div
class=
"hr-line-dashed"
></div>
...
@@ -71,5 +83,34 @@
...
@@ -71,5 +83,34 @@
{% block custom_foot_js %}
{% block custom_foot_js %}
<script
src=
"{% static 'js/plugins/cropper/cropper.min.js' %}"
></script>
<script
src=
"{% static 'js/plugins/cropper/cropper.min.js' %}"
></script>
<script>
<script>
$
(
document
).
ready
(
function
()
{
var
el
=
$
(
'#id_password_rules'
),
idPassword
=
$
(
'#id_new_password'
),
idPopover
=
$
(
'#popover777'
),
container
=
$
(
'#container'
),
progress
=
$
(
'#id_progress'
),
password_check_rules
=
{{
password_check_rules
|
safe
}},
minLength
=
{{
min_length
}},
top
=
idPassword
.
offset
().
top
-
$
(
'.navbar'
).
outerHeight
(
true
)
-
$
(
'.page-heading'
).
outerHeight
(
true
)
-
10
+
34
,
left
=
377
;
// 初始化popover
initPopover
(
container
,
progress
,
idPassword
,
el
,
password_check_rules
);
// 监听事件
idPassword
.
on
(
'focus'
,
function
()
{
idPopover
.
css
(
'top'
,
top
);
idPopover
.
css
(
'left'
,
left
);
idPopover
.
css
(
'display'
,
'block'
);
});
idPassword
.
on
(
'blur'
,
function
()
{
idPopover
.
css
(
'display'
,
'none'
);
});
idPassword
.
on
(
'keyup'
,
function
(){
var
password
=
idPassword
.
val
();
checkPasswordRules
(
password
,
minLength
);
});
})
</script>
</script>
{% endblock %}
{% endblock %}
apps/users/templates/users/user_profile.html
View file @
0a2ff83c
...
@@ -91,8 +91,15 @@
...
@@ -91,8 +91,15 @@
{% else %}
{% else %}
{% trans 'Disable' %}
{% trans 'Disable' %}
{% endif %}
{% endif %}
{% if mfa_setting %}
( {% trans 'Administrator Settings force MFA login' %} )
{% endif %}
</td>
</td>
</tr>
</tr>
<tr>
<td
class=
"text-navy"
>
{% trans 'Source' %}
</td>
<td>
{{ user.get_source_display }}
</td>
</tr>
<tr>
<tr>
<td
class=
"text-navy"
>
{% trans 'Date joined' %}
</td>
<td
class=
"text-navy"
>
{% trans 'Date joined' %}
</td>
<td>
{{ user.date_joined|date:"Y-m-d H:i:s" }}
</td>
<td>
{{ user.date_joined|date:"Y-m-d H:i:s" }}
</td>
...
...
apps/users/templates/users/user_pubkey_update.html
View file @
0a2ff83c
...
@@ -67,7 +67,7 @@
...
@@ -67,7 +67,7 @@
<div
class=
"form-group"
>
<div
class=
"form-group"
>
<label
class=
"control-label col-sm-2 col-lg-2"
style=
"padding-top: 0"
>
{% trans 'Or reset by server' %}
</label>
<label
class=
"control-label col-sm-2 col-lg-2"
style=
"padding-top: 0"
>
{% trans 'Or reset by server' %}
</label>
<div
class=
" col-sm-9 col-lg-9 "
>
<div
class=
" col-sm-9 col-lg-9 "
>
<a
href=
"{% url 'users:user-pubkey-generate' %}"
>
{% trans 'Reset' %}
</a>
<a
id=
"reset_pubkey"
href=
"{% url 'users:user-pubkey-generate' %}"
>
{% trans 'Reset' %}
</a>
</div>
</div>
</div>
</div>
<div
class=
"hr-line-dashed"
></div>
<div
class=
"hr-line-dashed"
></div>
...
@@ -89,5 +89,10 @@
...
@@ -89,5 +89,10 @@
{% block custom_foot_js %}
{% block custom_foot_js %}
<script
src=
"{% static 'js/plugins/cropper/cropper.min.js' %}"
></script>
<script
src=
"{% static 'js/plugins/cropper/cropper.min.js' %}"
></script>
<script>
<script>
$
(
document
).
ready
(
function
()
{
}).
on
(
'click'
,
'#reset_pubkey'
,
function
()
{
var
message
=
"{% trans 'The new public key has been set successfully, Please download the corresponding private key.' %}"
;
toastr
.
success
(
message
)
})
</script>
</script>
{% endblock %}
{% endblock %}
apps/users/templates/users/user_update.html
View file @
0a2ff83c
...
@@ -4,5 +4,50 @@
...
@@ -4,5 +4,50 @@
{% block user_template_title %}{% trans "Update user" %}{% endblock %}
{% block user_template_title %}{% trans "Update user" %}{% endblock %}
{% block password %}
{% block password %}
{% bootstrap_field form.password layout="horizontal" %}
{% bootstrap_field form.password layout="horizontal" %}
{# 密码popover #}
<div
id=
"container"
>
<div
class=
"popover fade bottom in"
role=
"tooltip"
id=
"popover777"
style=
" display: none; width:260px;"
>
<div
class=
"arrow"
style=
"left: 50%;"
></div>
<h3
class=
"popover-title"
style=
"display: none;"
></h3>
<h4>
{% trans 'Your password must satisfy' %}
</h4><div
id=
"id_password_rules"
style=
"color: #908a8a; margin-left:20px; font-size:15px;"
></div>
<h4
style=
"margin-top: 10px;"
>
{% trans 'Password strength' %}
</h4><div
id=
"id_progress"
></div>
<div
class=
"popover-content"
></div>
</div>
</div>
{% bootstrap_field form.public_key layout="horizontal" %}
{% bootstrap_field form.public_key layout="horizontal" %}
{% endblock %}
{% endblock %}
{% block custom_foot_js %}
{{ block.super }}
<script>
$
(
document
).
ready
(
function
(){
var
el
=
$
(
'#id_password_rules'
),
idPassword
=
$
(
'#id_password'
),
idPopover
=
$
(
'#popover777'
),
container
=
$
(
'#container'
),
progress
=
$
(
'#id_progress'
),
password_check_rules
=
{{
password_check_rules
|
safe
}},
minLength
=
{{
min_length
}},
top
=
idPassword
.
offset
().
top
-
$
(
'.navbar'
).
outerHeight
(
true
)
-
$
(
'.page-heading'
).
outerHeight
(
true
)
-
10
+
34
,
left
=
377
;
// 初始化popover
initPopover
(
container
,
progress
,
idPassword
,
el
,
password_check_rules
);
// 监听事件
idPassword
.
on
(
'focus'
,
function
()
{
idPopover
.
css
(
'top'
,
top
);
idPopover
.
css
(
'left'
,
left
);
idPopover
.
css
(
'display'
,
'block'
);
});
idPassword
.
on
(
'blur'
,
function
()
{
idPopover
.
css
(
'display'
,
'none'
);
});
idPassword
.
on
(
'keyup'
,
function
(){
var
password
=
idPassword
.
val
();
checkPasswordRules
(
password
,
minLength
);
});
})
</script>
{% endblock %}
apps/users/utils.py
View file @
0a2ff83c
...
@@ -2,6 +2,7 @@
...
@@ -2,6 +2,7 @@
#
#
from
__future__
import
unicode_literals
from
__future__
import
unicode_literals
import
os
import
os
import
re
import
pyotp
import
pyotp
import
base64
import
base64
import
logging
import
logging
...
@@ -18,8 +19,11 @@ from django.core.cache import cache
...
@@ -18,8 +19,11 @@ from django.core.cache import cache
from
common.tasks
import
send_mail_async
from
common.tasks
import
send_mail_async
from
common.utils
import
reverse
,
get_object_or_none
from
common.utils
import
reverse
,
get_object_or_none
from
common.models
import
Setting
from
common.forms
import
SecuritySettingForm
from
.models
import
User
,
LoginLog
from
.models
import
User
,
LoginLog
logger
=
logging
.
getLogger
(
'jumpserver'
)
logger
=
logging
.
getLogger
(
'jumpserver'
)
...
@@ -271,3 +275,60 @@ def generate_otp_uri(request, issuer="Jumpserver"):
...
@@ -271,3 +275,60 @@ def generate_otp_uri(request, issuer="Jumpserver"):
def
check_otp_code
(
otp_secret_key
,
otp_code
):
def
check_otp_code
(
otp_secret_key
,
otp_code
):
totp
=
pyotp
.
TOTP
(
otp_secret_key
)
totp
=
pyotp
.
TOTP
(
otp_secret_key
)
return
totp
.
verify
(
otp_code
)
return
totp
.
verify
(
otp_code
)
def
get_password_check_rules
():
check_rules
=
[]
min_length
=
settings
.
DEFAULT_PASSWORD_MIN_LENGTH
min_name
=
'SECURITY_PASSWORD_MIN_LENGTH'
base_filed
=
SecuritySettingForm
.
base_fields
password_setting
=
Setting
.
objects
.
filter
(
name__startswith
=
'SECURITY_PASSWORD'
)
if
not
password_setting
:
# 用户还没有设置过密码校验规则
label
=
base_filed
.
get
(
min_name
)
.
label
label
+=
' '
+
str
(
min_length
)
+
_
(
'Bit'
)
id
=
'rule_'
+
min_name
rules
=
{
'id'
:
id
,
'label'
:
label
}
check_rules
.
append
(
rules
)
for
setting
in
password_setting
:
if
setting
.
cleaned_value
:
id
=
'rule_'
+
setting
.
name
label
=
base_filed
.
get
(
setting
.
name
)
.
label
if
setting
.
name
==
min_name
:
label
+=
str
(
setting
.
cleaned_value
)
+
_
(
'Bit'
)
min_length
=
setting
.
cleaned_value
rules
=
{
'id'
:
id
,
'label'
:
label
}
check_rules
.
append
(
rules
)
return
check_rules
,
min_length
def
check_password_rules
(
password
):
min_field_name
=
'SECURITY_PASSWORD_MIN_LENGTH'
upper_field_name
=
'SECURITY_PASSWORD_UPPER_CASE'
lower_field_name
=
'SECURITY_PASSWORD_LOWER_CASE'
number_field_name
=
'SECURITY_PASSWORD_NUMBER'
special_field_name
=
'SECURITY_PASSWORD_SPECIAL_CHAR'
min_length_setting
=
Setting
.
objects
.
filter
(
name
=
min_field_name
)
.
first
()
min_length
=
min_length_setting
.
value
if
min_length_setting
else
settings
.
DEFAULT_PASSWORD_MIN_LENGTH
password_setting
=
Setting
.
objects
.
filter
(
name__startswith
=
'SECURITY_PASSWORD'
)
if
not
password_setting
:
pattern
=
r"^.{"
+
str
(
min_length
)
+
",}$"
else
:
pattern
=
r"^"
for
setting
in
password_setting
:
if
setting
.
cleaned_value
and
setting
.
name
==
upper_field_name
:
pattern
+=
'(?=.*[A-Z])'
elif
setting
.
cleaned_value
and
setting
.
name
==
lower_field_name
:
pattern
+=
'(?=.*[a-z])'
elif
setting
.
cleaned_value
and
setting
.
name
==
number_field_name
:
pattern
+=
'(?=.*
\
d)'
elif
setting
.
cleaned_value
and
setting
.
name
==
special_field_name
:
pattern
+=
'(?=.*[`~!@#
\
$
%
\
^&
\
*
\
(
\
)-=_
\
+
\
[
\
]
\
{
\
}
\
|;:
\'
",
\
.<>
\
/
\
?])'
pattern
+=
'[a-zA-Z
\
d`~!@#
\
$
%
\
^&
\
*
\
(
\
)-=_
\
+
\
[
\
]
\
{
\
}
\
|;:
\'
",
\
.<>
\
/
\
?]'
match_obj
=
re
.
match
(
pattern
,
password
)
return
bool
(
match_obj
)
apps/users/views/login.py
View file @
0a2ff83c
...
@@ -23,9 +23,10 @@ from django.conf import settings
...
@@ -23,9 +23,10 @@ from django.conf import settings
from
common.utils
import
get_object_or_none
from
common.utils
import
get_object_or_none
from
common.mixins
import
DatetimeSearchMixin
,
AdminUserRequiredMixin
from
common.mixins
import
DatetimeSearchMixin
,
AdminUserRequiredMixin
from
common.models
import
Setting
from
..models
import
User
,
LoginLog
from
..models
import
User
,
LoginLog
from
..utils
import
send_reset_password_mail
,
check_otp_code
,
get_login_ip
,
redirect_user_first_login_or_index
,
\
from
..utils
import
send_reset_password_mail
,
check_otp_code
,
get_login_ip
,
redirect_user_first_login_or_index
,
\
get_user_or_tmp_user
,
set_tmp_user_to_cache
get_user_or_tmp_user
,
set_tmp_user_to_cache
,
get_password_check_rules
,
check_password_rules
from
..tasks
import
write_login_log_async
from
..tasks
import
write_login_log_async
from
..
import
forms
from
..
import
forms
...
@@ -82,10 +83,10 @@ class UserLoginView(FormView):
...
@@ -82,10 +83,10 @@ class UserLoginView(FormView):
user
=
get_user_or_tmp_user
(
self
.
request
)
user
=
get_user_or_tmp_user
(
self
.
request
)
if
user
.
otp_enabled
and
user
.
otp_secret_key
:
if
user
.
otp_enabled
and
user
.
otp_secret_key
:
# 1,2 & T
# 1,2
,mfa_setting
& T
return
reverse
(
'users:login-otp'
)
return
reverse
(
'users:login-otp'
)
elif
user
.
otp_enabled
and
not
user
.
otp_secret_key
:
elif
user
.
otp_enabled
and
not
user
.
otp_secret_key
:
# 1,2 & F
# 1,2
,mfa_setting
& F
return
reverse
(
'users:user-otp-enable-authentication'
)
return
reverse
(
'users:user-otp-enable-authentication'
)
elif
not
user
.
otp_enabled
:
elif
not
user
.
otp_enabled
:
# 0 & T,F
# 0 & T,F
...
@@ -211,6 +212,10 @@ class UserResetPasswordView(TemplateView):
...
@@ -211,6 +212,10 @@ class UserResetPasswordView(TemplateView):
token
=
request
.
GET
.
get
(
'token'
)
token
=
request
.
GET
.
get
(
'token'
)
user
=
User
.
validate_reset_token
(
token
)
user
=
User
.
validate_reset_token
(
token
)
check_rules
,
min_length
=
get_password_check_rules
()
password_rules
=
{
'password_check_rules'
:
check_rules
,
'min_length'
:
min_length
}
kwargs
.
update
(
password_rules
)
if
not
user
:
if
not
user
:
kwargs
.
update
({
'errors'
:
_
(
'Token invalid or expired'
)})
kwargs
.
update
({
'errors'
:
_
(
'Token invalid or expired'
)})
return
super
()
.
get
(
request
,
*
args
,
**
kwargs
)
return
super
()
.
get
(
request
,
*
args
,
**
kwargs
)
...
@@ -227,6 +232,13 @@ class UserResetPasswordView(TemplateView):
...
@@ -227,6 +232,13 @@ class UserResetPasswordView(TemplateView):
if
not
user
:
if
not
user
:
return
self
.
get
(
request
,
errors
=
_
(
'Token invalid or expired'
))
return
self
.
get
(
request
,
errors
=
_
(
'Token invalid or expired'
))
is_ok
=
check_password_rules
(
password
)
if
not
is_ok
:
return
self
.
get
(
request
,
errors
=
_
(
'* Your password does not meet the requirements'
)
)
user
.
reset_password
(
password
)
user
.
reset_password
(
password
)
return
HttpResponseRedirect
(
reverse
(
'users:reset-password-success'
))
return
HttpResponseRedirect
(
reverse
(
'users:reset-password-success'
))
...
...
apps/users/views/user.py
View file @
0a2ff83c
...
@@ -33,9 +33,10 @@ from django.contrib.auth import logout as auth_logout
...
@@ -33,9 +33,10 @@ from django.contrib.auth import logout as auth_logout
from
common.const
import
create_success_msg
,
update_success_msg
from
common.const
import
create_success_msg
,
update_success_msg
from
common.mixins
import
JSONResponseMixin
from
common.mixins
import
JSONResponseMixin
from
common.utils
import
get_logger
,
get_object_or_none
,
is_uuid
,
ssh_key_gen
from
common.utils
import
get_logger
,
get_object_or_none
,
is_uuid
,
ssh_key_gen
from
common.models
import
Setting
from
..
import
forms
from
..
import
forms
from
..models
import
User
,
UserGroup
from
..models
import
User
,
UserGroup
from
..utils
import
AdminUserRequiredMixin
,
generate_otp_uri
,
check_otp_code
,
get_user_or_tmp_user
from
..utils
import
AdminUserRequiredMixin
,
generate_otp_uri
,
check_otp_code
,
get_user_or_tmp_user
,
get_password_check_rules
,
check_password_rules
from
..signals
import
post_user_create
from
..signals
import
post_user_create
from
..tasks
import
write_login_log_async
from
..tasks
import
write_login_log_async
...
@@ -96,10 +97,29 @@ class UserUpdateView(AdminUserRequiredMixin, SuccessMessageMixin, UpdateView):
...
@@ -96,10 +97,29 @@ class UserUpdateView(AdminUserRequiredMixin, SuccessMessageMixin, UpdateView):
success_message
=
update_success_msg
success_message
=
update_success_msg
def
get_context_data
(
self
,
**
kwargs
):
def
get_context_data
(
self
,
**
kwargs
):
context
=
{
'app'
:
_
(
'Users'
),
'action'
:
_
(
'Update user'
)}
check_rules
,
min_length
=
get_password_check_rules
()
context
=
{
'app'
:
_
(
'Users'
),
'action'
:
_
(
'Update user'
),
'password_check_rules'
:
check_rules
,
'min_length'
:
min_length
}
kwargs
.
update
(
context
)
kwargs
.
update
(
context
)
return
super
()
.
get_context_data
(
**
kwargs
)
return
super
()
.
get_context_data
(
**
kwargs
)
def
form_valid
(
self
,
form
):
password
=
form
.
cleaned_data
.
get
(
'password'
)
if
not
password
:
return
super
()
.
form_valid
(
form
)
is_ok
=
check_password_rules
(
password
)
if
not
is_ok
:
form
.
add_error
(
"password"
,
_
(
"* Your password does not meet the requirements"
)
)
return
self
.
form_invalid
(
form
)
return
super
()
.
form_valid
(
form
)
class
UserBulkUpdateView
(
AdminUserRequiredMixin
,
TemplateView
):
class
UserBulkUpdateView
(
AdminUserRequiredMixin
,
TemplateView
):
model
=
User
model
=
User
...
@@ -318,8 +338,10 @@ class UserProfileView(LoginRequiredMixin, TemplateView):
...
@@ -318,8 +338,10 @@ class UserProfileView(LoginRequiredMixin, TemplateView):
template_name
=
'users/user_profile.html'
template_name
=
'users/user_profile.html'
def
get_context_data
(
self
,
**
kwargs
):
def
get_context_data
(
self
,
**
kwargs
):
mfa_setting
=
Setting
.
objects
.
filter
(
name
=
'SECURITY_MFA_AUTH'
)
.
first
()
context
=
{
context
=
{
'action'
:
_
(
'Profile'
),
'action'
:
_
(
'Profile'
),
'mfa_setting'
:
mfa_setting
.
cleaned_value
if
mfa_setting
else
False
,
}
}
kwargs
.
update
(
context
)
kwargs
.
update
(
context
)
return
super
()
.
get_context_data
(
**
kwargs
)
return
super
()
.
get_context_data
(
**
kwargs
)
...
@@ -353,9 +375,12 @@ class UserPasswordUpdateView(LoginRequiredMixin, UpdateView):
...
@@ -353,9 +375,12 @@ class UserPasswordUpdateView(LoginRequiredMixin, UpdateView):
return
self
.
request
.
user
return
self
.
request
.
user
def
get_context_data
(
self
,
**
kwargs
):
def
get_context_data
(
self
,
**
kwargs
):
check_rules
,
min_length
=
get_password_check_rules
()
context
=
{
context
=
{
'app'
:
_
(
'Users'
),
'app'
:
_
(
'Users'
),
'action'
:
_
(
'Password update'
),
'action'
:
_
(
'Password update'
),
'password_check_rules'
:
check_rules
,
'min_length'
:
min_length
,
}
}
kwargs
.
update
(
context
)
kwargs
.
update
(
context
)
return
super
()
.
get_context_data
(
**
kwargs
)
return
super
()
.
get_context_data
(
**
kwargs
)
...
@@ -364,6 +389,17 @@ class UserPasswordUpdateView(LoginRequiredMixin, UpdateView):
...
@@ -364,6 +389,17 @@ class UserPasswordUpdateView(LoginRequiredMixin, UpdateView):
auth_logout
(
self
.
request
)
auth_logout
(
self
.
request
)
return
super
()
.
get_success_url
()
return
super
()
.
get_success_url
()
def
form_valid
(
self
,
form
):
password
=
form
.
cleaned_data
.
get
(
'new_password'
)
is_ok
=
check_password_rules
(
password
)
if
not
is_ok
:
form
.
add_error
(
"new_password"
,
_
(
"* Your password does not meet the requirements"
)
)
return
self
.
form_invalid
(
form
)
return
super
()
.
form_valid
(
form
)
class
UserPublicKeyUpdateView
(
LoginRequiredMixin
,
UpdateView
):
class
UserPublicKeyUpdateView
(
LoginRequiredMixin
,
UpdateView
):
template_name
=
'users/user_pubkey_update.html'
template_name
=
'users/user_pubkey_update.html'
...
...
config_example.py
View file @
0a2ff83c
...
@@ -51,11 +51,6 @@ class Config:
...
@@ -51,11 +51,6 @@ class Config:
REDIS_HOST
=
'127.0.0.1'
REDIS_HOST
=
'127.0.0.1'
REDIS_PORT
=
6379
REDIS_PORT
=
6379
REDIS_PASSWORD
=
''
REDIS_PASSWORD
=
''
BROKER_URL
=
'redis://
%(password)
s
%(host)
s:
%(port)
s/3'
%
{
'password'
:
REDIS_PASSWORD
,
'host'
:
REDIS_HOST
,
'port'
:
REDIS_PORT
,
}
def
__init__
(
self
):
def
__init__
(
self
):
pass
pass
...
...
utils/clean_duplicate_user_groups.py
View file @
0a2ff83c
...
@@ -17,9 +17,14 @@ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "jumpserver.settings")
...
@@ -17,9 +17,14 @@ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "jumpserver.settings")
django
.
setup
()
django
.
setup
()
from
users.models
import
UserGroup
from
users.models
import
UserGroup
from
django.core.exceptions
import
FieldError
def
clean_group
(
interactive
=
True
):
def
clean_group
(
interactive
=
True
):
try
:
UserGroup
.
objects
.
all
()
.
filter
(
is_discard
=
True
)
.
delete
()
except
FieldError
:
pass
groups
=
UserGroup
.
objects
.
all
()
groups
=
UserGroup
.
objects
.
all
()
groups_name_list
=
groups
.
values_list
(
'name'
,
flat
=
True
)
groups_name_list
=
groups
.
values_list
(
'name'
,
flat
=
True
)
groups_with_info
=
groups
.
annotate
(
Count
(
'users'
))
\
groups_with_info
=
groups
.
annotate
(
Count
(
'users'
))
\
...
@@ -50,7 +55,7 @@ def clean_group(interactive=True):
...
@@ -50,7 +55,7 @@ def clean_group(interactive=True):
"Delete user group <{}>, create at {}? ([y]/n)"
.
format
(
"Delete user group <{}>, create at {}? ([y]/n)"
.
format
(
name
,
group
.
date_created
)
name
,
group
.
date_created
)
)
)
if
confirm
.
lower
()
==
"y"
:
if
confirm
.
lower
()
in
[
"y"
,
""
]
:
confirm
=
True
confirm
=
True
break
break
elif
confirm
.
lower
()
==
"n"
:
elif
confirm
.
lower
()
==
"n"
:
...
...
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