diff --git a/apps/__init__.py b/apps/__init__.py
index c6491d9fa..7e96164aa 100644
--- a/apps/__init__.py
+++ b/apps/__init__.py
@@ -2,4 +2,4 @@
# -*- coding: utf-8 -*-
#
-__version__ = "1.3.1"
+__version__ = "1.3.2"
diff --git a/apps/assets/api/node.py b/apps/assets/api/node.py
index 1d8a4f497..e5ace021e 100644
--- a/apps/assets/api/node.py
+++ b/apps/assets/api/node.py
@@ -116,7 +116,7 @@ class NodeChildrenApi(mixins.ListModelMixin, generics.CreateAPIView):
def get_object(self):
pk = self.kwargs.get('pk') or self.request.query_params.get('id')
if not pk:
- node = Node.root()
+ node = None
else:
node = get_object_or_404(Node, pk=pk)
return node
@@ -126,7 +126,8 @@ class NodeChildrenApi(mixins.ListModelMixin, generics.CreateAPIView):
query_all = self.request.query_params.get("all")
query_assets = self.request.query_params.get('assets')
node = self.get_object()
- if node == Node.root():
+ if node is None:
+ node = Node.root()
queryset.append(node)
if query_all:
children = node.get_all_children()
diff --git a/apps/assets/utils.py b/apps/assets/utils.py
index 367c5e5f7..cc4942ade 100644
--- a/apps/assets/utils.py
+++ b/apps/assets/utils.py
@@ -51,7 +51,6 @@ def test_gateway_connectability(gateway):
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
proxy = paramiko.SSHClient()
- proxy.load_host_keys(os.path.expanduser('~/.ssh/known_hosts'))
proxy.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
diff --git a/apps/common/forms.py b/apps/common/forms.py
index 02af6e47a..87b2f4f12 100644
--- a/apps/common/forms.py
+++ b/apps/common/forms.py
@@ -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')
+ )
diff --git a/apps/common/signals_handler.py b/apps/common/signals_handler.py
index df2ea5a5e..bff3a2193 100644
--- a/apps/common/signals_handler.py
+++ b/apps/common/signals_handler.py
@@ -34,7 +34,7 @@ def refresh_all_settings_on_django_ready(sender, **kwargs):
def ldap_auth_on_changed(sender, enabled=True, **kwargs):
if enabled:
logger.debug("Enable LDAP auth")
- if settings.AUTH_LDAP_BACKEND not in settings.AUTH_LDAP_BACKEND:
+ if settings.AUTH_LDAP_BACKEND not in settings.AUTHENTICATION_BACKENDS:
settings.AUTHENTICATION_BACKENDS.insert(0, settings.AUTH_LDAP_BACKEND)
else:
diff --git a/apps/common/templates/common/basic_setting.html b/apps/common/templates/common/basic_setting.html
index 496eca977..9c9258e33 100644
--- a/apps/common/templates/common/basic_setting.html
+++ b/apps/common/templates/common/basic_setting.html
@@ -23,6 +23,9 @@
{% trans 'Terminal setting' %}
+
+ {% trans 'Security setting' %}
+
diff --git a/apps/common/templates/common/email_setting.html b/apps/common/templates/common/email_setting.html
index 1fd772db1..2f0951e00 100644
--- a/apps/common/templates/common/email_setting.html
+++ b/apps/common/templates/common/email_setting.html
@@ -23,6 +23,9 @@
{% trans 'Terminal setting' %}
+
+ {% trans 'Security setting' %}
+
diff --git a/apps/common/templates/common/ldap_setting.html b/apps/common/templates/common/ldap_setting.html
index f0569f873..e55da5a8f 100644
--- a/apps/common/templates/common/ldap_setting.html
+++ b/apps/common/templates/common/ldap_setting.html
@@ -23,6 +23,9 @@
{% trans 'Terminal setting' %}
+
+ {% trans 'Security setting' %}
+
diff --git a/apps/common/templates/common/security_setting.html b/apps/common/templates/common/security_setting.html
new file mode 100644
index 000000000..2260b76b9
--- /dev/null
+++ b/apps/common/templates/common/security_setting.html
@@ -0,0 +1,87 @@
+{% extends 'base.html' %}
+{% load static %}
+{% load bootstrap3 %}
+{% load i18n %}
+{% load common_tags %}
+
+{% block content %}
+
+
+{% endblock %}
+{% block custom_foot_js %}
+
+{% endblock %}
diff --git a/apps/common/templates/common/terminal_setting.html b/apps/common/templates/common/terminal_setting.html
index 16927c05a..320f628b0 100644
--- a/apps/common/templates/common/terminal_setting.html
+++ b/apps/common/templates/common/terminal_setting.html
@@ -27,6 +27,9 @@
{% trans 'Terminal setting' %}
+
+ {% trans 'Security setting' %}
+
@@ -39,6 +42,7 @@
{% endif %}
{% csrf_token %}
+
{% trans "Basic setting" %}
{% for field in form %}
{% if not field.field|is_bool_field %}
@@ -60,6 +64,7 @@
{% endfor %}
+
{% trans "Command storage" %}
diff --git a/apps/common/urls/view_urls.py b/apps/common/urls/view_urls.py
index 466f7c49c..e7ccddd06 100644
--- a/apps/common/urls/view_urls.py
+++ b/apps/common/urls/view_urls.py
@@ -11,4 +11,5 @@ urlpatterns = [
url(r'^email/$', views.EmailSettingView.as_view(), name='email-setting'),
url(r'^ldap/$', views.LDAPSettingView.as_view(), name='ldap-setting'),
url(r'^terminal/$', views.TerminalSettingView.as_view(), name='terminal-setting'),
+ url(r'^security/$', views.SecuritySettingView.as_view(), name='security-setting'),
]
diff --git a/apps/common/views.py b/apps/common/views.py
index ee7a2225f..6a7d37f49 100644
--- a/apps/common/views.py
+++ b/apps/common/views.py
@@ -7,7 +7,7 @@ from django.utils.translation import ugettext as _
from django.conf import settings
from .forms import EmailSettingForm, LDAPSettingForm, BasicSettingForm, \
- TerminalSettingForm
+ TerminalSettingForm, SecuritySettingForm
from .mixins import AdminUserRequiredMixin
from .signals import ldap_auth_enable
@@ -82,7 +82,7 @@ class LDAPSettingView(AdminUserRequiredMixin, TemplateView):
if form.is_valid():
form.save()
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")
messages.success(request, msg)
return redirect('settings:ldap-setting')
@@ -122,3 +122,27 @@ class TerminalSettingView(AdminUserRequiredMixin, TemplateView):
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)
diff --git a/apps/i18n/zh/LC_MESSAGES/django.mo b/apps/i18n/zh/LC_MESSAGES/django.mo
index b764117a2..7d2f547cd 100644
Binary files a/apps/i18n/zh/LC_MESSAGES/django.mo and b/apps/i18n/zh/LC_MESSAGES/django.mo differ
diff --git a/apps/i18n/zh/LC_MESSAGES/django.po b/apps/i18n/zh/LC_MESSAGES/django.po
index 31654aa11..705f611dc 100644
--- a/apps/i18n/zh/LC_MESSAGES/django.po
+++ b/apps/i18n/zh/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Jumpserver 0.3.3\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-05-25 18:11+0800\n"
+"POT-Creation-Date: 2018-06-07 11:34+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: ibuler \n"
"Language-Team: Jumpserver team\n"
@@ -17,19 +17,19 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: assets/api/node.py:106
+#: assets/api/node.py:99
msgid "New node {}"
msgstr "新节点 {}"
-#: assets/api/node.py:242
+#: assets/api/node.py:234
msgid "更新节点资产硬件信息: {}"
msgstr ""
-#: assets/api/node.py:255
+#: assets/api/node.py:247
msgid "测试节点下资产是否可连接: {}"
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:191
#: assets/templates/assets/system_user_detail.html:175 perms/models.py:33
@@ -37,7 +37,7 @@ msgid "Nodes"
msgstr "节点管理"
#: assets/forms/asset.py:27 assets/forms/asset.py:66 assets/forms/asset.py:109
-#: assets/forms/asset.py:113 assets/models/asset.py:70
+#: assets/forms/asset.py:113 assets/models/asset.py:80
#: assets/models/cluster.py:19 assets/models/user.py:72
#: assets/templates/assets/asset_detail.html:73 templates/_nav.html:25
msgid "Admin user"
@@ -46,14 +46,14 @@ msgstr "管理用户"
#: 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:37
-#: assets/templates/assets/asset_list.html:74
+#: assets/templates/assets/asset_list.html:75
#: assets/templates/assets/asset_update.html:40
#: assets/templates/assets/asset_update.html:42
#: assets/templates/assets/user_asset_list.html:34
msgid "Label"
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
msgid "Domain"
msgstr "网域"
@@ -90,7 +90,7 @@ msgstr "如果有多个的互相隔离的网络,设置资产属于的网域,
msgid "Select assets"
msgstr "选择资产"
-#: assets/forms/asset.py:105 assets/models/asset.py:63
+#: assets/forms/asset.py:105 assets/models/asset.py:67
#: assets/models/domain.py:44 assets/templates/assets/admin_user_assets.html:53
#: assets/templates/assets/asset_detail.html:69
#: assets/templates/assets/domain_gateway_list.html:58
@@ -99,7 +99,7 @@ msgid "Port"
msgstr "端口"
#: assets/forms/domain.py:14 assets/forms/label.py:13
-#: assets/models/asset.py:183 assets/templates/assets/admin_user_list.html:25
+#: assets/models/asset.py:223 assets/templates/assets/admin_user_list.html:25
#: assets/templates/assets/domain_detail.html:60
#: assets/templates/assets/domain_list.html:15
#: assets/templates/assets/label_list.html:16
@@ -129,15 +129,15 @@ msgstr "资产"
#: assets/templates/assets/label_list.html:14
#: assets/templates/assets/system_user_detail.html:58
#: 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:85 ops/models/adhoc.py:36
+#: common/templates/common/terminal_setting.html:72
+#: 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
#: 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_user.html:54 terminal/models.py:16
#: terminal/models.py:154 terminal/templates/terminal/terminal_detail.html:43
-#: terminal/templates/terminal/terminal_list.html:29 users/models/group.py:14
-#: users/models/user.py:42 users/templates/users/_select_user_modal.html:13
+#: terminal/templates/terminal/terminal_list.html:29 users/models/group.py:12
+#: users/models/user.py:49 users/templates/users/_select_user_modal.html:13
#: users/templates/users/user_detail.html:63
#: users/templates/users/user_group_detail.html:55
#: users/templates/users/user_group_list.html:12
@@ -155,7 +155,7 @@ msgstr "名称"
#: assets/templates/assets/system_user_list.html:27
#: 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/models/user.py:40 users/templates/users/_select_user_modal.html:14
+#: users/models/user.py:47 users/templates/users/_select_user_modal.html:14
#: users/templates/users/login.html:56
#: users/templates/users/login_log_list.html:49
#: users/templates/users/user_detail.html:67
@@ -171,16 +171,16 @@ msgstr "密码或密钥密码"
#: 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/templates/users/login.html:59
-#: users/templates/users/reset_password.html:52
+#: users/templates/users/reset_password.html:53
#: users/templates/users/user_create.html:10
#: users/templates/users/user_password_authentication.html:14
-#: users/templates/users/user_password_update.html:40
+#: users/templates/users/user_password_update.html:42
#: users/templates/users/user_profile_update.html:40
#: users/templates/users/user_pubkey_update.html:40
msgid "Password"
msgstr "密码"
-#: assets/forms/user.py:28 users/models/user.py:69
+#: assets/forms/user.py:28 users/models/user.py:76
msgid "Private key"
msgstr "ssh私钥"
@@ -202,11 +202,11 @@ msgid ""
"than 2 system user"
msgstr "高优先级的系统用户将会作为默认登录用户"
-#: assets/models/asset.py:61 assets/models/domain.py:43
+#: assets/models/asset.py:63 assets/models/domain.py:43
#: assets/templates/assets/_asset_list_modal.html:46
#: assets/templates/assets/admin_user_assets.html:52
#: assets/templates/assets/asset_detail.html:61
-#: assets/templates/assets/asset_list.html:86
+#: assets/templates/assets/asset_list.html:87
#: assets/templates/assets/domain_gateway_list.html:57
#: assets/templates/assets/system_user_asset.html:50
#: assets/templates/assets/user_asset_list.html:46 common/forms.py:144
@@ -217,10 +217,10 @@ msgstr "高优先级的系统用户将会作为默认登录用户"
msgid "IP"
msgstr "IP"
-#: assets/models/asset.py:62 assets/templates/assets/_asset_list_modal.html:45
+#: assets/models/asset.py:66 assets/templates/assets/_asset_list_modal.html:45
#: assets/templates/assets/admin_user_assets.html:51
#: assets/templates/assets/asset_detail.html:57
-#: assets/templates/assets/asset_list.html:85
+#: assets/templates/assets/asset_list.html:86
#: assets/templates/assets/system_user_asset.html:49
#: assets/templates/assets/user_asset_list.html:45 common/forms.py:143
#: perms/templates/perms/asset_permission_asset.html:54
@@ -229,82 +229,82 @@ msgstr "IP"
msgid "Hostname"
msgstr "主机名"
-#: assets/models/asset.py:64 assets/templates/assets/asset_detail.html:97
+#: assets/models/asset.py:69 assets/templates/assets/asset_detail.html:97
msgid "Platform"
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
msgid "Is active"
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"
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"
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"
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"
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"
msgstr "序列号"
-#: assets/models/asset.py:81
+#: assets/models/asset.py:98
msgid "CPU model"
msgstr "CPU型号"
-#: assets/models/asset.py:82
+#: assets/models/asset.py:99
msgid "CPU count"
msgstr "CPU数量"
-#: assets/models/asset.py:83
+#: assets/models/asset.py:100
msgid "CPU cores"
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"
msgstr "内存"
-#: assets/models/asset.py:85
+#: assets/models/asset.py:104
msgid "Disk total"
msgstr "硬盘大小"
-#: assets/models/asset.py:86
+#: assets/models/asset.py:106
msgid "Disk info"
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"
msgstr "操作系统"
-#: assets/models/asset.py:89
+#: assets/models/asset.py:111
msgid "OS version"
msgstr "系统版本"
-#: assets/models/asset.py:90
+#: assets/models/asset.py:113
msgid "OS arch"
msgstr "系统架构"
-#: assets/models/asset.py:91
+#: assets/models/asset.py:115
msgid "Hostname raw"
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_update.html:38 templates/_nav.html:27
msgid "Labels"
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/templates/assets/admin_user_detail.html:68
#: assets/templates/assets/asset_detail.html:117
@@ -312,11 +312,11 @@ msgstr "标签管理"
#: assets/templates/assets/system_user_detail.html:96
#: ops/templates/ops/adhoc_detail.html:86 perms/models.py:38 perms/models.py:81
#: 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"
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/label.py:23 assets/templates/assets/admin_user_detail.html:64
#: assets/templates/assets/domain_detail.html:68
@@ -324,12 +324,12 @@ msgstr "创建者"
#: ops/templates/ops/adhoc_detail.html:90 ops/templates/ops/task_detail.html:63
#: perms/models.py:39 perms/models.py:82
#: perms/templates/perms/asset_permission_detail.html:94
-#: terminal/templates/terminal/terminal_detail.html:59 users/models/group.py:17
+#: terminal/templates/terminal/terminal_detail.html:59 users/models/group.py:15
#: users/templates/users/user_group_detail.html:63
msgid "Date created"
msgstr "创建日期"
-#: assets/models/asset.py:96 assets/models/base.py:26
+#: assets/models/asset.py:126 assets/models/base.py:26
#: assets/models/cluster.py:29 assets/models/domain.py:18
#: assets/models/domain.py:47 assets/models/group.py:23
#: assets/models/label.py:21 assets/templates/assets/admin_user_detail.html:72
@@ -342,11 +342,11 @@ msgstr "创建日期"
#: 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
#: perms/templates/perms/asset_permission_detail.html:102 terminal/models.py:26
-#: terminal/templates/terminal/terminal_detail.html:63 users/models/group.py:15
-#: users/models/user.py:75 users/templates/users/user_detail.html:119
+#: terminal/templates/terminal/terminal_detail.html:63 users/models/group.py:13
+#: 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_list.html:14
-#: users/templates/users/user_profile.html:123
+#: users/templates/users/user_profile.html:130
msgid "Comment"
msgstr "备注"
@@ -366,7 +366,7 @@ msgstr "带宽"
msgid "Contact"
msgstr "联系人"
-#: assets/models/cluster.py:22 users/models/user.py:61
+#: assets/models/cluster.py:22 users/models/user.py:68
#: users/templates/users/user_detail.html:76
msgid "Phone"
msgstr "手机"
@@ -392,7 +392,7 @@ msgid "Default"
msgstr "默认"
#: assets/models/cluster.py:36 assets/models/label.py:13
-#: users/models/user.py:330
+#: users/models/user.py:343
msgid "System"
msgstr "系统"
@@ -432,13 +432,13 @@ msgstr "默认资产组"
#: terminal/templates/terminal/command_list.html:72
#: terminal/templates/terminal/session_list.html:33
#: terminal/templates/terminal/session_list.html:71 users/forms.py:281
-#: users/models/user.py:30 users/models/user.py:318
+#: users/models/user.py:31 users/models/user.py:331
#: users/templates/users/user_group_detail.html:78
-#: users/templates/users/user_group_list.html:13 users/views/user.py:339
+#: users/templates/users/user_group_list.html:13 users/views/user.py:362
msgid "User"
msgstr "用户"
-#: assets/models/label.py:18 assets/models/node.py:18
+#: assets/models/label.py:18 assets/models/node.py:16
#: assets/templates/assets/label_list.html:15 common/models.py:27
msgid "Value"
msgstr "值"
@@ -447,7 +447,7 @@ msgstr "值"
msgid "Category"
msgstr "分类"
-#: assets/models/node.py:14
+#: assets/models/node.py:15
msgid "Key"
msgstr ""
@@ -630,16 +630,17 @@ msgstr "其它"
#: assets/templates/assets/domain_create_update.html:16
#: assets/templates/assets/gateway_create_update.html:58
#: assets/templates/assets/label_create_update.html:18
-#: common/templates/common/basic_setting.html:58
-#: common/templates/common/email_setting.html:59
-#: common/templates/common/ldap_setting.html:59
-#: common/templates/common/terminal_setting.html:101
+#: common/templates/common/basic_setting.html:61
+#: common/templates/common/email_setting.html:62
+#: common/templates/common/ldap_setting.html:62
+#: common/templates/common/security_setting.html:70
+#: common/templates/common/terminal_setting.html:106
#: perms/templates/perms/asset_permission_create_update.html:69
#: terminal/templates/terminal/terminal_update.html:47
#: users/templates/users/_user.html:46
#: users/templates/users/user_bulk_update.html:23
-#: users/templates/users/user_password_update.html:58
-#: users/templates/users/user_profile.html:181
+#: users/templates/users/user_password_update.html:70
+#: users/templates/users/user_profile.html:188
#: users/templates/users/user_profile_update.html:63
#: users/templates/users/user_pubkey_update.html:70
#: users/templates/users/user_pubkey_update.html:76
@@ -650,23 +651,24 @@ msgstr "重置"
#: assets/templates/assets/admin_user_create_update.html:46
#: assets/templates/assets/asset_bulk_update.html:24
#: assets/templates/assets/asset_create.html:67
-#: assets/templates/assets/asset_list.html:107
+#: assets/templates/assets/asset_list.html:108
#: assets/templates/assets/asset_update.html:71
#: assets/templates/assets/domain_create_update.html:17
#: assets/templates/assets/gateway_create_update.html:59
#: assets/templates/assets/label_create_update.html:19
-#: common/templates/common/basic_setting.html:59
-#: common/templates/common/email_setting.html:60
-#: common/templates/common/ldap_setting.html:60
-#: common/templates/common/terminal_setting.html:103
+#: common/templates/common/basic_setting.html:62
+#: common/templates/common/email_setting.html:63
+#: common/templates/common/ldap_setting.html:63
+#: common/templates/common/security_setting.html:71
+#: common/templates/common/terminal_setting.html:108
#: perms/templates/perms/asset_permission_create_update.html:70
#: terminal/templates/terminal/session_list.html:124
#: terminal/templates/terminal/terminal_update.html:48
#: users/templates/users/_user.html:47
#: users/templates/users/forgot_password.html:44
#: users/templates/users/user_bulk_update.html:24
-#: users/templates/users/user_list.html:44
-#: users/templates/users/user_password_update.html:59
+#: users/templates/users/user_list.html:45
+#: users/templates/users/user_password_update.html:71
#: users/templates/users/user_profile_update.html:64
#: users/templates/users/user_pubkey_update.html:77
msgid "Submit"
@@ -727,7 +729,7 @@ msgstr "测试"
#: assets/templates/assets/admin_user_detail.html:24
#: assets/templates/assets/admin_user_list.html:85
#: assets/templates/assets/asset_detail.html:24
-#: assets/templates/assets/asset_list.html:174
+#: assets/templates/assets/asset_list.html:175
#: assets/templates/assets/domain_detail.html:24
#: assets/templates/assets/domain_detail.html:103
#: assets/templates/assets/domain_gateway_list.html:85
@@ -742,16 +744,16 @@ msgstr "测试"
#: users/templates/users/user_detail.html:25
#: users/templates/users/user_group_detail.html:28
#: users/templates/users/user_group_list.html:43
-#: users/templates/users/user_list.html:76
-#: users/templates/users/user_profile.html:144
-#: users/templates/users/user_profile.html:173
+#: users/templates/users/user_list.html:77
+#: users/templates/users/user_profile.html:151
+#: users/templates/users/user_profile.html:180
msgid "Update"
msgstr "更新"
#: assets/templates/assets/admin_user_detail.html:28
#: assets/templates/assets/admin_user_list.html:86
#: assets/templates/assets/asset_detail.html:28
-#: assets/templates/assets/asset_list.html:175
+#: assets/templates/assets/asset_list.html:176
#: assets/templates/assets/domain_detail.html:28
#: assets/templates/assets/domain_detail.html:104
#: assets/templates/assets/domain_gateway_list.html:86
@@ -766,8 +768,8 @@ msgstr "更新"
#: users/templates/users/user_detail.html:30
#: users/templates/users/user_group_detail.html:32
#: users/templates/users/user_group_list.html:45
-#: users/templates/users/user_list.html:80
-#: users/templates/users/user_list.html:84
+#: users/templates/users/user_list.html:81
+#: users/templates/users/user_list.html:85
msgid "Delete"
msgstr "删除"
@@ -782,17 +784,17 @@ msgstr "选择节点"
#: assets/templates/assets/admin_user_detail.html:100
#: assets/templates/assets/asset_detail.html:200
-#: assets/templates/assets/asset_list.html:636
+#: assets/templates/assets/asset_list.html:638
#: assets/templates/assets/system_user_detail.html:192
#: assets/templates/assets/system_user_list.html:138 templates/_modal.html:22
#: terminal/templates/terminal/session_detail.html:108
-#: users/templates/users/user_detail.html:362
-#: users/templates/users/user_detail.html:387
-#: users/templates/users/user_detail.html:410
+#: users/templates/users/user_detail.html:366
+#: users/templates/users/user_detail.html:391
+#: users/templates/users/user_detail.html:414
#: users/templates/users/user_group_create_update.html:32
#: users/templates/users/user_group_list.html:86
-#: users/templates/users/user_list.html:199
-#: users/templates/users/user_profile.html:215
+#: users/templates/users/user_list.html:200
+#: users/templates/users/user_profile.html:222
msgid "Confirm"
msgstr "确认"
@@ -814,7 +816,7 @@ msgid "Ratio"
msgstr "比例"
#: assets/templates/assets/admin_user_list.html:30
-#: assets/templates/assets/asset_list.html:90
+#: assets/templates/assets/asset_list.html:91
#: assets/templates/assets/domain_gateway_list.html:62
#: assets/templates/assets/domain_list.html:18
#: assets/templates/assets/label_list.html:17
@@ -825,7 +827,7 @@ msgstr "比例"
#: terminal/templates/terminal/session_list.html:80
#: terminal/templates/terminal/terminal_list.html:36
#: users/templates/users/user_group_list.html:15
-#: users/templates/users/user_list.html:28
+#: users/templates/users/user_list.html:29
msgid "Action"
msgstr "动作"
@@ -842,20 +844,20 @@ msgid "Disk"
msgstr "硬盘"
#: assets/templates/assets/asset_detail.html:121
-#: users/templates/users/user_detail.html:111
-#: users/templates/users/user_profile.html:97
+#: users/templates/users/user_detail.html:115
+#: users/templates/users/user_profile.html:104
msgid "Date joined"
msgstr "创建日期"
#: assets/templates/assets/asset_detail.html:137
#: terminal/templates/terminal/session_detail.html:81
-#: users/templates/users/user_detail.html:130
-#: users/templates/users/user_profile.html:135
+#: users/templates/users/user_detail.html:134
+#: users/templates/users/user_profile.html:142
msgid "Quick modify"
msgstr "快速修改"
#: assets/templates/assets/asset_detail.html:143
-#: assets/templates/assets/asset_list.html:88
+#: assets/templates/assets/asset_list.html:89
#: assets/templates/assets/user_asset_list.html:47 perms/models.py:35
#: perms/models.py:79
#: perms/templates/perms/asset_permission_create_update.html:47
@@ -863,10 +865,10 @@ msgstr "快速修改"
#: perms/templates/perms/asset_permission_list.html:59
#: terminal/templates/terminal/terminal_list.html:34
#: users/templates/users/_select_user_modal.html:18
-#: users/templates/users/user_detail.html:136
+#: users/templates/users/user_detail.html:140
#: users/templates/users/user_granted_asset.html:46
#: users/templates/users/user_group_granted_asset.html:46
-#: users/templates/users/user_list.html:27
+#: users/templates/users/user_list.html:28
#: users/templates/users/user_profile.html:63
msgid "Active"
msgstr "激活中"
@@ -880,124 +882,124 @@ msgid "Refresh"
msgstr "刷新"
#: assets/templates/assets/asset_detail.html:300
-#: users/templates/users/user_detail.html:282
-#: users/templates/users/user_detail.html:309
+#: users/templates/users/user_detail.html:286
+#: users/templates/users/user_detail.html:313
msgid "Update successfully!"
msgstr "更新成功"
-#: assets/templates/assets/asset_list.html:62 assets/views/asset.py:97
+#: assets/templates/assets/asset_list.html:63 assets/views/asset.py:97
msgid "Create asset"
msgstr "创建资产"
-#: assets/templates/assets/asset_list.html:66
+#: assets/templates/assets/asset_list.html:67
#: users/templates/users/user_list.html:7
msgid "Import"
msgstr "导入"
-#: assets/templates/assets/asset_list.html:69
+#: assets/templates/assets/asset_list.html:70
#: users/templates/users/user_list.html:10
msgid "Export"
msgstr "导出"
-#: assets/templates/assets/asset_list.html:87
+#: assets/templates/assets/asset_list.html:88
msgid "Hardware"
msgstr "硬件"
-#: assets/templates/assets/asset_list.html:99
-#: users/templates/users/user_list.html:37
+#: assets/templates/assets/asset_list.html:100
+#: users/templates/users/user_list.html:38
msgid "Delete selected"
msgstr "批量删除"
-#: assets/templates/assets/asset_list.html:100
-#: users/templates/users/user_list.html:38
+#: assets/templates/assets/asset_list.html:101
+#: users/templates/users/user_list.html:39
msgid "Update selected"
msgstr "批量更新"
-#: assets/templates/assets/asset_list.html:101
+#: assets/templates/assets/asset_list.html:102
msgid "Remove from this node"
msgstr "从节点移除"
-#: assets/templates/assets/asset_list.html:102
-#: users/templates/users/user_list.html:39
+#: assets/templates/assets/asset_list.html:103
+#: users/templates/users/user_list.html:40
msgid "Deactive selected"
msgstr "禁用所选"
-#: assets/templates/assets/asset_list.html:103
-#: users/templates/users/user_list.html:40
+#: assets/templates/assets/asset_list.html:104
+#: users/templates/users/user_list.html:41
msgid "Active selected"
msgstr "激活所选"
-#: assets/templates/assets/asset_list.html:120
+#: assets/templates/assets/asset_list.html:121
msgid "Add node"
msgstr "新建节点"
-#: assets/templates/assets/asset_list.html:121
+#: assets/templates/assets/asset_list.html:122
msgid "Rename node"
msgstr "重命名节点"
-#: assets/templates/assets/asset_list.html:122
+#: assets/templates/assets/asset_list.html:123
msgid "Delete node"
msgstr "删除节点"
-#: assets/templates/assets/asset_list.html:124
+#: assets/templates/assets/asset_list.html:125
msgid "Add assets to node"
msgstr "添加资产到节点"
-#: assets/templates/assets/asset_list.html:125
+#: assets/templates/assets/asset_list.html:126
msgid "Move assets to node"
msgstr "移动资产到节点"
-#: assets/templates/assets/asset_list.html:127
+#: assets/templates/assets/asset_list.html:128
msgid "Refresh node hardware info"
msgstr "更新节点资产硬件信息"
-#: assets/templates/assets/asset_list.html:128
+#: assets/templates/assets/asset_list.html:129
msgid "Test node connective"
msgstr "测试节点资产可连接性"
-#: assets/templates/assets/asset_list.html:130
+#: assets/templates/assets/asset_list.html:131
msgid "Display only current node assets"
msgstr "仅显示当前节点资产"
-#: assets/templates/assets/asset_list.html:131
+#: assets/templates/assets/asset_list.html:132
msgid "Displays all child node assets"
msgstr "显示所有子节点资产"
-#: assets/templates/assets/asset_list.html:217
+#: assets/templates/assets/asset_list.html:218
msgid "Create node failed"
msgstr "创建节点失败"
-#: assets/templates/assets/asset_list.html:229
+#: assets/templates/assets/asset_list.html:230
msgid "Have child node, cancel"
msgstr "存在子节点,不能删除"
-#: assets/templates/assets/asset_list.html:231
+#: assets/templates/assets/asset_list.html:232
msgid "Have assets, cancel"
msgstr "存在资产,不能删除"
-#: assets/templates/assets/asset_list.html:631
+#: assets/templates/assets/asset_list.html:633
#: assets/templates/assets/system_user_list.html:133
-#: users/templates/users/user_detail.html:357
-#: users/templates/users/user_detail.html:382
+#: users/templates/users/user_detail.html:361
+#: users/templates/users/user_detail.html:386
#: users/templates/users/user_group_list.html:81
-#: users/templates/users/user_list.html:194
+#: users/templates/users/user_list.html:195
msgid "Are you sure?"
msgstr "你确认吗?"
-#: assets/templates/assets/asset_list.html:632
+#: assets/templates/assets/asset_list.html:634
msgid "This will delete the selected assets !!!"
msgstr "删除选择资产"
-#: assets/templates/assets/asset_list.html:640
+#: assets/templates/assets/asset_list.html:642
msgid "Asset Deleted."
msgstr "已被删除"
-#: assets/templates/assets/asset_list.html:641
-#: assets/templates/assets/asset_list.html:646
+#: assets/templates/assets/asset_list.html:643
+#: assets/templates/assets/asset_list.html:648
msgid "Asset Delete"
msgstr "删除"
-#: assets/templates/assets/asset_list.html:645
+#: assets/templates/assets/asset_list.html:647
msgid "Asset Deleting failed."
msgstr "删除失败"
@@ -1033,8 +1035,8 @@ msgstr "创建网关"
#: assets/templates/assets/domain_gateway_list.html:87
#: assets/templates/assets/domain_gateway_list.html:89
-#: common/templates/common/email_setting.html:58
-#: common/templates/common/ldap_setting.html:58
+#: common/templates/common/email_setting.html:61
+#: common/templates/common/ldap_setting.html:61
msgid "Test connection"
msgstr "测试连接"
@@ -1237,11 +1239,11 @@ msgstr "FTP日志"
msgid "Test mail sent to {}, please check"
msgstr "邮件已经发送{}, 请检查"
-#: common/api.py:52
+#: common/api.py:42
msgid "Test ldap success"
msgstr "连接LDAP成功"
-#: common/api.py:90
+#: common/api.py:80
msgid "Match {} s users"
msgstr "匹配 {} 个用户"
@@ -1376,7 +1378,7 @@ msgstr "密码认证"
msgid "Public key auth"
msgstr "密钥认证"
-#: common/forms.py:159 common/templates/common/terminal_setting.html:63
+#: common/forms.py:159 common/templates/common/terminal_setting.html:68
#: terminal/forms.py:30 terminal/models.py:20
msgid "Command storage"
msgstr "命令存储"
@@ -1387,7 +1389,7 @@ msgid ""
"other storage and some terminal using"
msgstr "设置终端命令存储,default是默认用的存储方式"
-#: common/forms.py:165 common/templates/common/terminal_setting.html:81
+#: common/forms.py:165 common/templates/common/terminal_setting.html:86
#: terminal/forms.py:35 terminal/models.py:21
msgid "Replay storage"
msgstr "录像存储"
@@ -1398,6 +1400,60 @@ msgid ""
"other storage and some terminal using"
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
msgid "is discard"
msgstr ""
@@ -1413,14 +1469,16 @@ msgstr "启用"
#: common/templates/common/basic_setting.html:15
#: common/templates/common/email_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:42 common/views.py:22
+#: common/templates/common/terminal_setting.html:46 common/views.py:22
msgid "Basic setting"
msgstr "基本设置"
#: common/templates/common/basic_setting.html:18
#: common/templates/common/email_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
msgid "Email setting"
msgstr "邮件设置"
@@ -1428,6 +1486,7 @@ msgstr "邮件设置"
#: common/templates/common/basic_setting.html:21
#: common/templates/common/email_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
msgid "LDAP setting"
msgstr "LDAP设置"
@@ -1435,12 +1494,29 @@ msgstr "LDAP设置"
#: common/templates/common/basic_setting.html:24
#: common/templates/common/email_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
msgid "Terminal setting"
msgstr "终端设置"
-#: common/templates/common/terminal_setting.html:68
-#: common/templates/common/terminal_setting.html:86
+#: common/templates/common/basic_setting.html:27
+#: 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
msgid "Type"
msgstr "类型"
@@ -1450,11 +1526,12 @@ msgid "Special char not allowed"
msgstr "不能包含特殊字符"
#: 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"
msgstr "系统设置"
#: 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"
msgstr "更新设置成功, 请手动重启程序"
@@ -1736,9 +1813,9 @@ msgstr "选择用户"
#: 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:136 templates/_nav.html:14
-#: users/models/group.py:25 users/models/user.py:48
+#: users/models/group.py:23 users/models/user.py:55
#: users/templates/users/_select_user_modal.html:16
-#: users/templates/users/user_detail.html:188
+#: users/templates/users/user_detail.html:192
#: users/templates/users/user_list.html:26
msgid "User group"
msgstr "用户组"
@@ -1753,8 +1830,8 @@ msgstr ""
#: perms/models.py:37 perms/models.py:80
#: perms/templates/perms/asset_permission_detail.html:90
-#: users/models/user.py:80 users/templates/users/user_detail.html:103
-#: users/templates/users/user_profile.html:105
+#: users/models/user.py:87 users/templates/users/user_detail.html:107
+#: users/templates/users/user_profile.html:112
msgid "Date expired"
msgstr "失效日期"
@@ -1791,7 +1868,7 @@ msgid "Add node to this permission"
msgstr "添加节点"
#: perms/templates/perms/asset_permission_asset.html:125
-#: users/templates/users/user_detail.html:205
+#: users/templates/users/user_detail.html:209
msgid "Join"
msgstr "加入"
@@ -1884,11 +1961,11 @@ msgstr "文档"
#: templates/_header_bar.html:37 templates/_nav_user.html:9 users/forms.py:121
#: users/templates/users/_user.html:39
#: users/templates/users/first_login.html:39
-#: users/templates/users/user_password_update.html:37
+#: users/templates/users/user_password_update.html:39
#: users/templates/users/user_profile.html:17
#: users/templates/users/user_profile_update.html:37
#: users/templates/users/user_profile_update.html:57
-#: users/templates/users/user_pubkey_update.html:37 users/views/user.py:322
+#: users/templates/users/user_pubkey_update.html:37 users/views/user.py:344
msgid "Profile"
msgstr "个人信息"
@@ -1945,13 +2022,13 @@ msgstr "关闭"
#: 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/login.py:263 users/views/login.py:321 users/views/user.py:64
-#: users/views/user.py:79 users/views/user.py:99 users/views/user.py:155
-#: users/views/user.py:310 users/views/user.py:357 users/views/user.py:379
+#: users/views/login.py:277 users/views/login.py:335 users/views/user.py:66
+#: users/views/user.py:81 users/views/user.py:103 users/views/user.py:174
+#: users/views/user.py:329 users/views/user.py:381 users/views/user.py:416
msgid "Users"
msgstr "用户管理"
-#: templates/_nav.html:13 users/views/user.py:65
+#: templates/_nav.html:13 users/views/user.py:67
msgid "User list"
msgstr "用户列表"
@@ -2261,7 +2338,7 @@ msgstr ""
msgid "MFA code"
msgstr "MFA 验证码"
-#: users/forms.py:49 users/models/user.py:52
+#: users/forms.py:49 users/models/user.py:59
#: users/templates/users/_select_user_modal.html:15
#: users/templates/users/user_detail.html:87
#: users/templates/users/user_list.html:25
@@ -2281,7 +2358,7 @@ msgstr ""
msgid "Paste user id_rsa.pub here."
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"
msgstr "添加到用户组"
@@ -2289,7 +2366,7 @@ msgstr "添加到用户组"
msgid "Public key should not be the same as your old one."
msgstr "不能和原来的密钥相同"
-#: users/forms.py:87 users/forms.py:220 users/serializers.py:45
+#: users/forms.py:87 users/forms.py:220 users/serializers.py:48
msgid "Not a valid ssh public key"
msgstr "ssh密钥不合法"
@@ -2306,7 +2383,7 @@ msgstr ""
msgid "* Enable MFA authentication to make the account more secure."
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
msgid "MFA"
msgstr "MFA"
@@ -2354,9 +2431,9 @@ msgstr "自动配置并下载SSH密钥"
msgid "Paste your id_rsa.pub here."
msgstr "复制你的公钥到这里"
-#: users/forms.py:231 users/models/user.py:72
+#: users/forms.py:231 users/models/user.py:79
#: users/templates/users/first_login.html:42
-#: users/templates/users/user_password_update.html:43
+#: users/templates/users/user_password_update.html:45
#: users/templates/users/user_profile.html:68
#: users/templates/users/user_profile_update.html:43
#: users/templates/users/user_pubkey_update.html:43
@@ -2387,43 +2464,49 @@ msgstr "Agent"
msgid "Date login"
msgstr "登录日期"
-#: users/models/user.py:29 users/models/user.py:326
+#: users/models/user.py:30 users/models/user.py:339
msgid "Administrator"
msgstr "管理员"
-#: users/models/user.py:31
+#: users/models/user.py:32
msgid "Application"
msgstr "应用程序"
-#: users/models/user.py:34 users/templates/users/user_profile.html:92
-#: users/templates/users/user_profile.html:156
-#: users/templates/users/user_profile.html:159
+#: users/models/user.py:35 users/templates/users/user_profile.html:92
+#: users/templates/users/user_profile.html:163
+#: users/templates/users/user_profile.html:166
msgid "Disable"
msgstr "禁用"
-#: users/models/user.py:35 users/templates/users/user_profile.html:90
-#: users/templates/users/user_profile.html:163
+#: users/models/user.py:36 users/templates/users/user_profile.html:90
+#: users/templates/users/user_profile.html:170
msgid "Enable"
msgstr "启用"
-#: users/models/user.py:36 users/templates/users/user_profile.html:88
+#: users/models/user.py:37 users/templates/users/user_profile.html:88
msgid "Force enable"
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
msgid "Email"
msgstr "邮件"
-#: users/models/user.py:55
+#: users/models/user.py:62
msgid "Avatar"
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"
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"
msgstr "Administrator是初始的超级管理员"
@@ -2539,22 +2622,34 @@ msgstr "6位数字"
msgid "Can't provide security? Please contact the administrator!"
msgstr "如果不能提供MFA验证码,请联系管理员!"
-#: users/templates/users/reset_password.html:45
-#: users/templates/users/user_detail.html:348 users/utils.py:76
+#: users/templates/users/reset_password.html:46
+#: users/templates/users/user_detail.html:352 users/utils.py:80
msgid "Reset password"
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"
msgstr "再次输入密码"
-#: users/templates/users/reset_password.html:57
+#: users/templates/users/reset_password.html:68
#: users/templates/users/user_profile.html:20
msgid "Setting"
msgstr "设置"
#: 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"
msgstr "创建用户"
@@ -2563,7 +2658,7 @@ msgid "Reset link will be generated and sent to the user. "
msgstr "生成重置密码连接,通过邮件发送给用户"
#: users/templates/users/user_detail.html:19
-#: users/templates/users/user_granted_asset.html:18 users/views/user.py:156
+#: users/templates/users/user_granted_asset.html:18 users/views/user.py:175
msgid "User detail"
msgstr "用户详情"
@@ -2582,63 +2677,63 @@ msgstr "强制启用"
msgid "Disabled"
msgstr "禁用"
-#: users/templates/users/user_detail.html:115
-#: users/templates/users/user_profile.html:101
+#: users/templates/users/user_detail.html:119
+#: users/templates/users/user_profile.html:108
msgid "Last login"
msgstr "最后登录"
-#: users/templates/users/user_detail.html:151
+#: users/templates/users/user_detail.html:155
msgid "Force enabled MFA"
msgstr "强制启用MFA"
-#: users/templates/users/user_detail.html:166
+#: users/templates/users/user_detail.html:170
msgid "Send reset password mail"
msgstr "发送重置密码邮件"
-#: users/templates/users/user_detail.html:169
-#: users/templates/users/user_detail.html:177
+#: users/templates/users/user_detail.html:173
+#: users/templates/users/user_detail.html:181
msgid "Send"
msgstr "发送"
-#: users/templates/users/user_detail.html:174
+#: users/templates/users/user_detail.html:178
msgid "Send reset ssh key mail"
msgstr "发送重置密钥邮件"
-#: users/templates/users/user_detail.html:291
+#: users/templates/users/user_detail.html:295
msgid "Goto profile page enable MFA"
msgstr "请去个人信息页面启用自己的MFA"
-#: users/templates/users/user_detail.html:347
+#: users/templates/users/user_detail.html:351
msgid "An e-mail has been sent to the user`s mailbox."
msgstr "已发送邮件到用户邮箱"
-#: users/templates/users/user_detail.html:358
+#: users/templates/users/user_detail.html:362
msgid "This will reset the user password and send a reset mail"
msgstr "将失效用户当前密码,并发送重设密码邮件到用户邮箱"
-#: users/templates/users/user_detail.html:372
+#: users/templates/users/user_detail.html:376
msgid ""
"The reset-ssh-public-key E-mail has been sent successfully. Please inform "
"the user to update his new ssh public key."
msgstr "重设密钥邮件将会发送到用户邮箱"
-#: users/templates/users/user_detail.html:373
+#: users/templates/users/user_detail.html:377
msgid "Reset SSH public key"
msgstr "重置SSH密钥"
-#: users/templates/users/user_detail.html:383
+#: users/templates/users/user_detail.html:387
msgid "This will reset the user public key and send a reset mail"
msgstr "将会失效用户当前密钥,并发送重置邮件到用户邮箱"
-#: users/templates/users/user_detail.html:400
-#: users/templates/users/user_profile.html:204
+#: users/templates/users/user_detail.html:404
+#: users/templates/users/user_profile.html:211
msgid "Successfully updated the SSH public key."
msgstr "更新ssh密钥成功"
-#: users/templates/users/user_detail.html:401
#: users/templates/users/user_detail.html:405
-#: users/templates/users/user_profile.html:205
-#: users/templates/users/user_profile.html:210
+#: users/templates/users/user_detail.html:409
+#: users/templates/users/user_profile.html:212
+#: users/templates/users/user_profile.html:217
msgid "User SSH public key update"
msgstr "ssh密钥"
@@ -2677,45 +2772,49 @@ msgstr "用户组删除"
msgid "UserGroup Deleting failed."
msgstr "用户组删除失败"
-#: users/templates/users/user_list.html:195
+#: users/templates/users/user_list.html:196
msgid "This will delete the selected users !!!"
msgstr "删除选中用户 !!!"
-#: users/templates/users/user_list.html:203
+#: users/templates/users/user_list.html:204
msgid "User Deleted."
msgstr "已被删除"
-#: users/templates/users/user_list.html:204
-#: users/templates/users/user_list.html:209
+#: users/templates/users/user_list.html:205
+#: users/templates/users/user_list.html:210
msgid "User Delete"
msgstr "删除"
-#: users/templates/users/user_list.html:208
+#: users/templates/users/user_list.html:209
msgid "User Deleting failed."
msgstr "用户删除失败"
-#: users/templates/users/user_profile.html:109 users/views/user.py:185
-#: users/views/user.py:239
+#: users/templates/users/user_profile.html:95
+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"
msgstr "用户组"
-#: users/templates/users/user_profile.html:141
+#: users/templates/users/user_profile.html:148
msgid "Update password"
msgstr "更改密码"
-#: users/templates/users/user_profile.html:149
+#: users/templates/users/user_profile.html:156
msgid "Update MFA settings"
msgstr "更改MFA设置"
-#: users/templates/users/user_profile.html:170
+#: users/templates/users/user_profile.html:177
msgid "Update SSH public key"
msgstr "更改SSH密钥"
-#: users/templates/users/user_profile.html:178
+#: users/templates/users/user_profile.html:185
msgid "Reset public key and download"
msgstr "重置并下载SSH密钥"
-#: users/templates/users/user_profile.html:208
+#: users/templates/users/user_profile.html:215
msgid "Failed to update SSH public key."
msgstr "更新密钥失败"
@@ -2735,15 +2834,21 @@ msgstr "更新密钥"
msgid "Or reset by server"
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"
msgstr "更新用户"
-#: users/utils.py:37
+#: users/utils.py:41
msgid "Create account successfully"
msgstr "创建账户成功"
-#: users/utils.py:39
+#: users/utils.py:43
#, fuzzy, python-format
msgid ""
"\n"
@@ -2788,7 +2893,7 @@ msgstr ""
" \n"
" "
-#: users/utils.py:78
+#: users/utils.py:82
#, python-format
msgid ""
"\n"
@@ -2832,11 +2937,11 @@ msgstr ""
" \n"
" "
-#: users/utils.py:109
+#: users/utils.py:113
msgid "SSH Key Reset"
msgstr "重置ssh密钥"
-#: users/utils.py:111
+#: users/utils.py:115
#, python-format
msgid ""
"\n"
@@ -2861,18 +2966,22 @@ msgstr ""
" \n"
" "
-#: users/utils.py:144
+#: users/utils.py:148
msgid "User not exist"
msgstr "用户不存在"
-#: users/utils.py:146
+#: users/utils.py:150
msgid "Disabled or expired"
msgstr "禁用或失效"
-#: users/utils.py:159
+#: users/utils.py:163
msgid "Password or SSH public key invalid"
msgstr "密码或密钥不合法"
+#: users/utils.py:290 users/utils.py:300
+msgid "Bit"
+msgstr " 位"
+
#: users/views/group.py:29
msgid "User group list"
msgstr "用户组列表"
@@ -2885,99 +2994,103 @@ msgstr "更新用户组"
msgid "User group granted asset"
msgstr "用户组授权资产"
-#: users/views/login.py:59
+#: users/views/login.py:62
msgid "Please enable cookies and try again."
msgstr "设置你的浏览器支持cookie"
-#: users/views/login.py:125 users/views/user.py:464 users/views/user.py:489
+#: users/views/login.py:128 users/views/user.py:501 users/views/user.py:526
msgid "MFA code invalid"
msgstr "MFA码认证失败"
-#: users/views/login.py:151
+#: users/views/login.py:154
msgid "Logout success"
msgstr "退出登录成功"
-#: users/views/login.py:152
+#: users/views/login.py:155
msgid "Logout success, return login page"
msgstr "退出登录成功,返回到登录页面"
-#: users/views/login.py:168
+#: users/views/login.py:171
msgid "Email address invalid, please input again"
msgstr "邮箱地址错误,重新输入"
-#: users/views/login.py:181
+#: users/views/login.py:184
msgid "Send reset password message"
msgstr "发送重置密码邮件"
-#: users/views/login.py:182
+#: users/views/login.py:185
msgid "Send reset password mail success, login your mail box and follow it "
msgstr ""
"发送重置邮件成功, 请登录邮箱查看, 按照提示操作 (如果没收到,请等待3-5分钟)"
-#: users/views/login.py:195
+#: users/views/login.py:198
msgid "Reset password success"
msgstr "重置密码成功"
-#: users/views/login.py:196
+#: users/views/login.py:199
msgid "Reset password success, return to login page"
msgstr "重置密码成功,返回到登录页面"
-#: users/views/login.py:213 users/views/login.py:226
+#: users/views/login.py:220 users/views/login.py:233
msgid "Token invalid or expired"
msgstr "Token错误或失效"
-#: users/views/login.py:222
+#: users/views/login.py:229
msgid "Password not same"
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"
msgstr "首次登陆"
-#: users/views/login.py:322
+#: users/views/login.py:336
msgid "Login log list"
msgstr "登录日志"
-#: users/views/user.py:109
+#: users/views/user.py:128
msgid "Bulk update user success"
msgstr "批量更新用户成功"
-#: users/views/user.py:214
+#: users/views/user.py:233
msgid "Invalid file."
msgstr "文件不合法"
-#: users/views/user.py:311
+#: users/views/user.py:330
msgid "User granted assets"
msgstr "用户授权资产"
-#: users/views/user.py:340
+#: users/views/user.py:363
msgid "Profile setting"
msgstr "个人信息设置"
-#: users/views/user.py:358
+#: users/views/user.py:382
msgid "Password update"
msgstr "密码更新"
-#: users/views/user.py:380
+#: users/views/user.py:417
msgid "Public key update"
msgstr "密钥更新"
-#: users/views/user.py:421
+#: users/views/user.py:458
msgid "Password invalid"
msgstr "用户名或密码无效"
-#: users/views/user.py:515
+#: users/views/user.py:552
msgid "MFA enable success"
msgstr "MFA 绑定成功"
-#: users/views/user.py:516
+#: users/views/user.py:553
msgid "MFA enable success, return login page"
msgstr "MFA 绑定成功,返回到登录页面"
-#: users/views/user.py:518
+#: users/views/user.py:555
msgid "MFA disable success"
msgstr "MFA 解绑成功"
-#: users/views/user.py:519
+#: users/views/user.py:556
msgid "MFA disable success, return login page"
msgstr "MFA 解绑成功,返回登录页面"
diff --git a/apps/jumpserver/settings.py b/apps/jumpserver/settings.py
index b81188b9d..6fd9f0fdd 100644
--- a/apps/jumpserver/settings.py
+++ b/apps/jumpserver/settings.py
@@ -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
BOOTSTRAP3 = {
'horizontal_label_class': 'col-md-2',
diff --git a/apps/ops/inventory.py b/apps/ops/inventory.py
index 6230e8167..b7d3ef487 100644
--- a/apps/ops/inventory.py
+++ b/apps/ops/inventory.py
@@ -86,6 +86,7 @@ class JMSInventory(BaseInventory):
gateway = asset.domain.random_gateway()
proxy_command_list = [
"ssh", "-p", str(gateway.port),
+ "-o", "StrictHostKeyChecking=no",
"{}@{}".format(gateway.username, gateway.ip),
"-W", "%h:%p", "-q",
]
diff --git a/apps/static/js/jumpserver.js b/apps/static/js/jumpserver.js
index 461455085..0000a3ccf 100644
--- a/apps/static/js/jumpserver.js
+++ b/apps/static/js/jumpserver.js
@@ -609,3 +609,91 @@ function setUrlParam(url, name, value) {
}
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 += " " + rules.label + "";
+ });
+ //$('#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);
+}
diff --git a/apps/static/js/pwstrength-bootstrap.js b/apps/static/js/pwstrength-bootstrap.js
new file mode 100755
index 000000000..957df08ea
--- /dev/null
+++ b/apps/static/js/pwstrength-bootstrap.js
@@ -0,0 +1,976 @@
+/*!
+* 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 '' + text + '';
+};
+defaultOptions.ui.popoverError = function (options) {
+ "use strict";
+ var errors = options.instances.errors,
+ errorsTitle = options.i18n.t("errorList"),
+ message = "" + errorsTitle + "
";
+
+ jQuery.each(errors, function (idx, err) {
+ message += "- " + err + "
";
+ });
+ message += "
";
+ 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 = "