From 6035d1f130efaa3ba845c6620876c64343bba615 Mon Sep 17 00:00:00 2001 From: chnliyong Date: Sat, 10 Mar 2018 10:46:28 +0800 Subject: [PATCH 001/112] python-gssapi libkrb5-dev for gssapi/gssapi.h --- requirements/deb_requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/deb_requirements.txt b/requirements/deb_requirements.txt index a0ddb7642..f4131a3ea 100644 --- a/requirements/deb_requirements.txt +++ b/requirements/deb_requirements.txt @@ -1 +1 @@ -libtiff5-dev libjpeg8-dev zlib1g-dev libfreetype6-dev liblcms2-dev libwebp-dev tcl8.5-dev tk8.5-dev python-tk python-dev openssl libssl-dev libldap2-dev libsasl2-dev sqlite gcc automake +libtiff5-dev libjpeg8-dev zlib1g-dev libfreetype6-dev liblcms2-dev libwebp-dev tcl8.5-dev tk8.5-dev python-tk python-dev openssl libssl-dev libldap2-dev libsasl2-dev sqlite gcc automake libkrb5-dev From 4fd83bd5be712dbe4b152137f052d50245062323 Mon Sep 17 00:00:00 2001 From: Nidhoggur1993 Date: Tue, 3 Apr 2018 16:02:51 +0800 Subject: [PATCH 002/112] Update make_migrations.sh MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 增加自动合并而不是在弹出warning结束 --- utils/make_migrations.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/utils/make_migrations.sh b/utils/make_migrations.sh index fdf1f6efb..b6068a1ca 100755 --- a/utils/make_migrations.sh +++ b/utils/make_migrations.sh @@ -4,3 +4,5 @@ python3 ../apps/manage.py makemigrations python3 ../apps/manage.py migrate + +python3 ../apps/manage.py makemigrations –merge From 0962a16b2247d027d175dacecca4652c00426411 Mon Sep 17 00:00:00 2001 From: BaiJiangjie Date: Thu, 26 Apr 2018 19:49:09 +0800 Subject: [PATCH 003/112] =?UTF-8?q?[Bugfix]=20=E4=BF=AE=E5=A4=8D=E9=A6=96?= =?UTF-8?q?=E6=AC=A1=E7=99=BB=E5=BD=95=E6=9D=A1=E6=AC=BE=E9=97=AE=E9=A2=98?= =?UTF-8?q?=E5=8F=8A=E5=BC=95=E5=AF=BC=E9=A1=B5=E9=9D=A2MFA=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/i18n/zh/LC_MESSAGES/django.mo | Bin 32826 -> 32913 bytes apps/i18n/zh/LC_MESSAGES/django.po | 269 ++++++++++++-------- apps/users/templates/users/first_login.html | 20 +- apps/users/views/login.py | 10 + 4 files changed, 181 insertions(+), 118 deletions(-) diff --git a/apps/i18n/zh/LC_MESSAGES/django.mo b/apps/i18n/zh/LC_MESSAGES/django.mo index ebfffbfe748496f4dfd19f8c4ebf42f48a27d9ce..4da36e76e728971c74b595652700d37f1d8eae61 100644 GIT binary patch delta 10727 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 delta 10648 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 fr+og_Hl4$Yq*Y68lHMRSzevyf\n" "Language-Team: Jumpserver team\n" @@ -128,9 +128,9 @@ msgstr "资产" #: assets/templates/assets/domain_list.html:14 #: 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 +#: assets/templates/assets/system_user_list.html:26 common/forms.py:179 +#: common/models.py:26 common/templates/common/terminal_setting.html:70 +#: common/templates/common/terminal_setting.html:88 ops/models/adhoc.py:36 #: ops/templates/ops/task_detail.html:59 ops/templates/ops/task_list.html:35 #: perms/models.py:19 perms/templates/perms/asset_permission_detail.html:62 #: perms/templates/perms/asset_permission_list.html:53 @@ -154,8 +154,8 @@ msgstr "名称" #: assets/templates/assets/system_user_detail.html:62 #: assets/templates/assets/system_user_list.html:27 #: perms/templates/perms/asset_permission_user.html:55 users/forms.py:13 -#: users/forms.py:22 users/models/authentication.py:45 users/models/user.py:40 -#: users/templates/users/_select_user_modal.html:14 +#: 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/templates/users/login.html:56 #: users/templates/users/login_log_list.html:49 #: users/templates/users/user_detail.html:67 @@ -168,8 +168,8 @@ msgstr "用户名" msgid "Password or private key passphrase" msgstr "密码或密钥密码" -#: assets/forms/user.py:25 assets/models/base.py:22 common/forms.py:113 -#: users/forms.py:15 users/forms.py:24 users/forms.py:36 +#: assets/forms/user.py:25 assets/models/base.py:22 common/forms.py:114 +#: 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/user_create.html:10 @@ -209,7 +209,7 @@ msgstr "高优先级的系统用户将会作为默认登录用户" #: 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 +#: assets/templates/assets/user_asset_list.html:46 common/forms.py:145 #: perms/templates/perms/asset_permission_asset.html:55 #: users/templates/users/login_log_list.html:52 #: users/templates/users/user_granted_asset.html:45 @@ -222,7 +222,7 @@ msgstr "IP" #: assets/templates/assets/asset_detail.html:57 #: 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 +#: assets/templates/assets/user_asset_list.html:45 common/forms.py:144 #: perms/templates/perms/asset_permission_asset.html:54 #: users/templates/users/user_granted_asset.html:44 #: users/templates/users/user_group_granted_asset.html:44 @@ -430,7 +430,7 @@ msgstr "默认资产组" #: terminal/templates/terminal/command_list.html:32 #: terminal/templates/terminal/command_list.html:72 #: terminal/templates/terminal/session_list.html:33 -#: terminal/templates/terminal/session_list.html:71 users/forms.py:273 +#: terminal/templates/terminal/session_list.html:71 users/forms.py:281 #: users/models/user.py:30 users/models/user.py:318 #: users/templates/users/user_group_detail.html:78 #: users/templates/users/user_group_list.html:13 users/views/user.py:339 @@ -630,10 +630,11 @@ 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/cloud_setting.html:74 +#: common/templates/common/email_setting.html:62 +#: common/templates/common/ldap_setting.html:62 +#: common/templates/common/terminal_setting.html:104 #: perms/templates/perms/asset_permission_create_update.html:69 #: terminal/templates/terminal/terminal_update.html:47 #: users/templates/users/_user.html:46 @@ -655,10 +656,11 @@ msgstr "重置" #: 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/cloud_setting.html:76 +#: common/templates/common/email_setting.html:63 +#: common/templates/common/ldap_setting.html:63 +#: common/templates/common/terminal_setting.html:106 #: perms/templates/perms/asset_permission_create_update.html:70 #: terminal/templates/terminal/session_list.html:120 #: terminal/templates/terminal/terminal_update.html:48 @@ -792,7 +794,7 @@ msgstr "选择节点" #: users/templates/users/user_detail.html:410 #: users/templates/users/user_group_create_update.html:32 #: users/templates/users/user_group_list.html:86 -#: users/templates/users/user_list.html:196 +#: users/templates/users/user_list.html:199 #: users/templates/users/user_profile.html:215 msgid "Confirm" msgstr "确认" @@ -973,7 +975,7 @@ msgstr "存在资产,不能删除" #: users/templates/users/user_detail.html:357 #: users/templates/users/user_detail.html:382 #: users/templates/users/user_group_list.html:81 -#: users/templates/users/user_list.html:191 +#: users/templates/users/user_list.html:194 msgid "Are you sure?" msgstr "你确认吗?" @@ -1025,8 +1027,8 @@ msgid "Create gateway" msgstr "创建网关" #: assets/templates/assets/domain_gateway_list.html:87 -#: 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 "测试连接" @@ -1123,7 +1125,7 @@ msgstr "批量更新资产" msgid "Update asset" msgstr "更新资产" -#: assets/views/asset.py:311 +#: assets/views/asset.py:314 msgid "already exists" msgstr "已经存在" @@ -1246,84 +1248,84 @@ msgstr "不是字符类型" msgid "Encrypt field using Secret Key" msgstr "" -#: common/forms.py:70 +#: common/forms.py:71 msgid "Current SITE URL" msgstr "当前站点URL" -#: common/forms.py:74 +#: common/forms.py:75 msgid "User Guide URL" msgstr "用户向导URL" -#: common/forms.py:75 +#: common/forms.py:76 msgid "User first login update profile done redirect to it" msgstr "用户第一次登录,修改profile后重定向到地址" -#: common/forms.py:78 +#: common/forms.py:79 msgid "Email Subject Prefix" msgstr "Email主题前缀" -#: common/forms.py:85 +#: common/forms.py:86 msgid "SMTP host" msgstr "SMTP主机" -#: common/forms.py:87 +#: common/forms.py:88 msgid "SMTP port" msgstr "SMTP端口" -#: common/forms.py:89 +#: common/forms.py:90 msgid "SMTP user" msgstr "SMTP账号" -#: common/forms.py:92 +#: common/forms.py:93 msgid "SMTP password" msgstr "SMTP密码" -#: common/forms.py:93 +#: common/forms.py:94 msgid "Some provider use token except password" msgstr "一些邮件提供商需要输入的是Token" -#: common/forms.py:96 common/forms.py:136 +#: common/forms.py:97 common/forms.py:137 msgid "Use SSL" msgstr "使用SSL" -#: common/forms.py:97 +#: common/forms.py:98 msgid "If SMTP port is 465, may be select" msgstr "如果SMTP端口是465,通常需要启用SSL" -#: common/forms.py:100 +#: common/forms.py:101 msgid "Use TLS" msgstr "使用TLS" -#: common/forms.py:101 +#: common/forms.py:102 msgid "If SMTP port is 587, may be select" msgstr "如果SMTP端口是587,通常需要启用TLS" -#: common/forms.py:107 +#: common/forms.py:108 msgid "LDAP server" msgstr "LDAP地址" -#: common/forms.py:110 +#: common/forms.py:111 msgid "Bind DN" msgstr "绑定DN" -#: common/forms.py:117 +#: common/forms.py:118 msgid "User OU" msgstr "用户OU" -#: common/forms.py:120 +#: common/forms.py:121 msgid "User search filter" msgstr "用户过滤器" -#: common/forms.py:121 +#: common/forms.py:122 #, python-format msgid "Choice may be (cn|uid|sAMAccountName)=%(user)s)" msgstr "可能的选项是(cn或uid或sAMAccountName=%(user)s)" -#: common/forms.py:124 +#: common/forms.py:125 msgid "User attr map" msgstr "LDAP属性映射" -#: common/forms.py:131 +#: common/forms.py:132 msgid "" "User attr map present how to map LDAP user attr to jumpserver, username,name," "email is jumpserver attr" @@ -1331,52 +1333,80 @@ msgstr "" "用户属性映射代表怎样将LDAP中用户属性映射到jumpserver用户上,username, name," "email 是jumpserver的属性" -#: common/forms.py:138 +#: common/forms.py:139 msgid "Enable LDAP auth" msgstr "启用LDAP认证" -#: common/forms.py:147 +#: common/forms.py:148 msgid "List sort by" msgstr "资产列表排序" -#: common/forms.py:150 +#: common/forms.py:151 msgid "Heartbeat interval" msgstr "心跳间隔" -#: common/forms.py:150 ops/models/adhoc.py:37 +#: common/forms.py:151 ops/models/adhoc.py:37 msgid "Units: seconds" msgstr "单位: 秒" -#: common/forms.py:153 +#: common/forms.py:154 msgid "Password auth" msgstr "密码认证" -#: common/forms.py:156 +#: common/forms.py:157 msgid "Public key auth" msgstr "密钥认证" -#: common/forms.py:159 common/templates/common/terminal_setting.html:63 +#: common/forms.py:160 common/templates/common/terminal_setting.html:66 #: terminal/forms.py:30 terminal/models.py:20 msgid "Command storage" msgstr "命令存储" -#: common/forms.py:160 +#: common/forms.py:161 msgid "" "Set terminal storage setting, `default` is the using as default,You can set " "other storage and some terminal using" msgstr "设置终端命令存储,default是默认用的存储方式" -#: common/forms.py:165 common/templates/common/terminal_setting.html:81 +#: common/forms.py:166 common/templates/common/terminal_setting.html:84 #: terminal/forms.py:35 terminal/models.py:21 msgid "Replay storage" msgstr "录像存储" -#: common/forms.py:166 +#: common/forms.py:167 msgid "" "Set replay storage setting, `default` is the using as default,You can set " "other storage and some terminal using" msgstr "设置终端录像存储,default是默认用的存储方式" +#: common/forms.py:175 +msgid "Aliyun" +msgstr "" + +#: common/forms.py:176 +msgid "AWS" +msgstr "" + +#: common/forms.py:183 +msgid "Cloud provider" +msgstr "" + +#: common/forms.py:186 +msgid "Access key id" +msgstr "" + +#: common/forms.py:187 +msgid "Enter the access key id for the cloud service" +msgstr "" + +#: common/forms.py:190 +msgid "Access key secret" +msgstr "" + +#: common/forms.py:191 +msgid "Enter the access key secret for the cloud service" +msgstr "" + #: common/mixins.py:29 msgid "is discard" msgstr "" @@ -1390,46 +1420,62 @@ msgid "Enabled" msgstr "启用" #: common/templates/common/basic_setting.html:15 +#: common/templates/common/cloud_setting.html:16 +#: common/templates/common/cloud_setting.html:49 #: common/templates/common/email_setting.html:15 #: common/templates/common/ldap_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:45 common/views.py:34 msgid "Basic setting" msgstr "基本设置" #: common/templates/common/basic_setting.html:18 +#: common/templates/common/cloud_setting.html:20 #: common/templates/common/email_setting.html:18 #: common/templates/common/ldap_setting.html:18 -#: common/templates/common/terminal_setting.html:20 common/views.py:48 +#: common/templates/common/terminal_setting.html:20 common/views.py:60 msgid "Email setting" msgstr "邮件设置" #: common/templates/common/basic_setting.html:21 +#: common/templates/common/cloud_setting.html:24 #: common/templates/common/email_setting.html:21 #: common/templates/common/ldap_setting.html:21 -#: common/templates/common/terminal_setting.html:24 common/views.py:74 +#: common/templates/common/terminal_setting.html:24 common/views.py:86 msgid "LDAP setting" msgstr "LDAP设置" #: common/templates/common/basic_setting.html:24 +#: common/templates/common/cloud_setting.html:28 #: common/templates/common/email_setting.html:24 #: common/templates/common/ldap_setting.html:24 -#: common/templates/common/terminal_setting.html:28 common/views.py:104 +#: common/templates/common/terminal_setting.html:28 common/views.py:116 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/cloud_setting.html:32 +#: common/templates/common/email_setting.html:27 +#: common/templates/common/ldap_setting.html:27 +#: common/templates/common/terminal_setting.html:31 common/views.py:144 +#, fuzzy +#| msgid "Email setting" +msgid "Cloud setting" +msgstr "邮件设置" + +#: common/templates/common/terminal_setting.html:71 +#: common/templates/common/terminal_setting.html:89 #: users/templates/users/login_log_list.html:50 msgid "Type" msgstr "类型" -#: common/views.py:21 common/views.py:47 common/views.py:73 common/views.py:103 -#: templates/_nav.html:81 +#: common/views.py:33 common/views.py:59 common/views.py:85 common/views.py:115 +#: common/views.py:143 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:44 common/views.py:70 common/views.py:98 common/views.py:128 +#: common/views.py:155 msgid "Update setting successfully, please restart program" msgstr "更新设置成功, 请手动重启程序" @@ -1703,8 +1749,8 @@ msgstr "任务列表" msgid "Task run history" msgstr "执行历史" -#: perms/forms.py:18 users/forms.py:230 users/forms.py:235 users/forms.py:247 -#: users/forms.py:277 +#: perms/forms.py:18 users/forms.py:238 users/forms.py:243 users/forms.py:255 +#: users/forms.py:285 msgid "Select users" msgstr "选择用户" @@ -1852,7 +1898,7 @@ msgstr "商业支持" msgid "Docs" msgstr "文档" -#: templates/_header_bar.html:37 templates/_nav_user.html:9 users/forms.py:113 +#: 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 @@ -1916,7 +1962,7 @@ 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:241 users/views/login.py:289 users/views/user.py:64 +#: users/views/login.py:264 users/views/login.py:325 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 msgid "Users" @@ -2228,11 +2274,11 @@ msgstr "" msgid "Invalid token or cache refreshed." msgstr "" -#: users/forms.py:30 +#: users/forms.py:38 msgid "MFA code" msgstr "MFA 验证码" -#: users/forms.py:41 users/models/user.py:52 +#: users/forms.py:49 users/models/user.py:52 #: users/templates/users/_select_user_modal.html:15 #: users/templates/users/user_detail.html:87 #: users/templates/users/user_list.html:25 @@ -2240,31 +2286,31 @@ msgstr "MFA 验证码" msgid "Role" msgstr "角色" -#: users/forms.py:44 users/forms.py:193 +#: users/forms.py:52 users/forms.py:201 msgid "ssh public key" msgstr "ssh公钥" -#: users/forms.py:45 users/forms.py:194 +#: users/forms.py:53 users/forms.py:202 msgid "ssh-rsa AAAA..." msgstr "" -#: users/forms.py:46 +#: users/forms.py:54 msgid "Paste user id_rsa.pub here." msgstr "复制用户公钥到这里" -#: users/forms.py:64 users/templates/users/user_detail.html:196 +#: users/forms.py:72 users/templates/users/user_detail.html:196 msgid "Join user groups" msgstr "添加到用户组" -#: users/forms.py:75 users/forms.py:208 +#: users/forms.py:83 users/forms.py:216 msgid "Public key should not be the same as your old one." msgstr "不能和原来的密钥相同" -#: users/forms.py:79 users/forms.py:212 users/serializers.py:45 +#: users/forms.py:87 users/forms.py:220 users/serializers.py:45 msgid "Not a valid ssh public key" msgstr "ssh密钥不合法" -#: users/forms.py:119 +#: users/forms.py:127 msgid "" "Tip: when enabled, you will enter the MFA binding process the next time you " "log in. you can also directly bind in \"personal information -> quick " @@ -2273,16 +2319,16 @@ msgstr "" "提示:启用之后您将会在下次登录时进入MFA绑定流程;您也可以在(个人信息->快速修" "改->更改MFA设置)中直接绑定!" -#: users/forms.py:129 +#: users/forms.py:137 msgid "* Enable MFA authentication to make the account more secure." msgstr "* 启用MFA认证,使账号更加安全." -#: users/forms.py:134 users/models/user.py:64 +#: users/forms.py:142 users/models/user.py:64 #: users/templates/users/first_login.html:45 msgid "MFA" msgstr "MFA" -#: users/forms.py:139 +#: users/forms.py:147 msgid "" "In order to protect you and your company, please keep your account, password " "and key sensitive information properly. (for example: setting complex " @@ -2291,40 +2337,41 @@ msgstr "" "为了保护您和公司的安全,请妥善保管您的账户、密码和密钥等重要敏感信息;(如:" "设置复杂密码,启用MFA认证)" -#: users/forms.py:146 users/templates/users/first_login.html:48 -#: users/templates/users/first_login.html:110 +#: users/forms.py:154 users/templates/users/first_login.html:48 +#: users/templates/users/first_login.html:107 +#: users/templates/users/first_login.html:130 msgid "Finish" msgstr "完成" -#: users/forms.py:152 +#: users/forms.py:160 msgid "Old password" msgstr "原来密码" -#: users/forms.py:157 +#: users/forms.py:165 msgid "New password" msgstr "新密码" -#: users/forms.py:162 +#: users/forms.py:170 msgid "Confirm password" msgstr "确认密码" -#: users/forms.py:172 +#: users/forms.py:180 msgid "Old password error" msgstr "原来密码错误" -#: users/forms.py:180 +#: users/forms.py:188 msgid "Password does not match" msgstr "密码不一致" -#: users/forms.py:191 +#: users/forms.py:199 msgid "Automatically configure and download the SSH key" msgstr "自动配置并下载SSH密钥" -#: users/forms.py:195 +#: users/forms.py:203 msgid "Paste your id_rsa.pub here." msgstr "复制你的公钥到这里" -#: users/forms.py:223 users/models/user.py:72 +#: users/forms.py:231 users/models/user.py:72 #: users/templates/users/first_login.html:42 #: users/templates/users/user_password_update.html:43 #: users/templates/users/user_profile.html:68 @@ -2443,11 +2490,15 @@ msgstr "首次登陆" msgid "I agree with the terms and conditions." msgstr "我同意条款和条件" -#: users/templates/users/first_login.html:100 +#: users/templates/users/first_login.html:73 +msgid "Please choose the terms and conditions." +msgstr "请选择同意条款和条件" + +#: users/templates/users/first_login.html:101 msgid "Previous" msgstr "上一步" -#: users/templates/users/first_login.html:108 +#: users/templates/users/first_login.html:105 #: users/templates/users/login_otp.html:66 #: users/templates/users/user_otp_authentication.html:22 #: users/templates/users/user_otp_enable_bind.html:19 @@ -2643,20 +2694,20 @@ msgstr "用户组删除" msgid "UserGroup Deleting failed." msgstr "用户组删除失败" -#: users/templates/users/user_list.html:192 +#: users/templates/users/user_list.html:195 msgid "This will delete the selected users !!!" msgstr "删除选中用户 !!!" -#: users/templates/users/user_list.html:200 +#: users/templates/users/user_list.html:203 msgid "User Deleted." msgstr "已被删除" -#: users/templates/users/user_list.html:201 -#: users/templates/users/user_list.html:206 +#: users/templates/users/user_list.html:204 +#: users/templates/users/user_list.html:209 msgid "User Delete" msgstr "删除" -#: users/templates/users/user_list.html:205 +#: users/templates/users/user_list.html:208 msgid "User Deleting failed." msgstr "用户删除失败" @@ -2847,56 +2898,56 @@ msgstr "更新用户组" msgid "User group granted asset" msgstr "用户组授权资产" -#: users/views/login.py:56 +#: users/views/login.py:60 msgid "Please enable cookies and try again." msgstr "设置你的浏览器支持cookie" -#: users/views/login.py:107 users/views/user.py:464 users/views/user.py:489 +#: users/views/login.py:126 users/views/user.py:464 users/views/user.py:489 msgid "MFA code invalid" msgstr "MFA码认证失败" -#: users/views/login.py:133 +#: users/views/login.py:152 msgid "Logout success" msgstr "退出登录成功" -#: users/views/login.py:134 +#: users/views/login.py:153 msgid "Logout success, return login page" msgstr "退出登录成功,返回到登录页面" -#: users/views/login.py:150 +#: users/views/login.py:169 msgid "Email address invalid, please input again" msgstr "邮箱地址错误,重新输入" -#: users/views/login.py:163 +#: users/views/login.py:182 msgid "Send reset password message" msgstr "发送重置密码邮件" -#: users/views/login.py:164 +#: users/views/login.py:183 msgid "Send reset password mail success, login your mail box and follow it " msgstr "" "发送重置邮件成功, 请登录邮箱查看, 按照提示操作 (如果没收到,请等待3-5分钟)" -#: users/views/login.py:177 +#: users/views/login.py:196 msgid "Reset password success" msgstr "重置密码成功" -#: users/views/login.py:178 +#: users/views/login.py:197 msgid "Reset password success, return to login page" msgstr "重置密码成功,返回到登录页面" -#: users/views/login.py:195 users/views/login.py:208 +#: users/views/login.py:214 users/views/login.py:227 msgid "Token invalid or expired" msgstr "Token错误或失效" -#: users/views/login.py:204 +#: users/views/login.py:223 msgid "Password not same" msgstr "密码不一致" -#: users/views/login.py:241 +#: users/views/login.py:264 msgid "First login" msgstr "首次登陆" -#: users/views/login.py:290 +#: users/views/login.py:326 msgid "Login log list" msgstr "登录日志" diff --git a/apps/users/templates/users/first_login.html b/apps/users/templates/users/first_login.html index 7138199a3..170bfdd32 100644 --- a/apps/users/templates/users/first_login.html +++ b/apps/users/templates/users/first_login.html @@ -70,6 +70,7 @@
+ {% endif %} {% bootstrap_form wizard.form %} @@ -99,11 +100,7 @@ {% if wizard.steps.prev %}
  • {% trans "Previous" %}
  • {% endif %} - {#{% if wizard.steps.next %}#} - {#
  • {% trans "Next" %}
  • #} - {#{% endif %}#} - {#
  • {% trans "Submit" %}
  • #} - {#将原来的下一页-替换为提交;修复 每页都提交,最后才能成功问题#} + {% if wizard.steps.next %}
  • {% trans "Next" %}
  • {% else %} @@ -124,16 +121,21 @@ {% block custom_foot_js %} + + -
    -
    +
    -
    - - {% endblock %} \ No newline at end of file diff --git a/apps/assets/templates/assets/system_user_detail.html b/apps/assets/templates/assets/system_user_detail.html index 1e180f0ab..96ed7bb93 100644 --- a/apps/assets/templates/assets/system_user_detail.html +++ b/apps/assets/templates/assets/system_user_detail.html @@ -64,14 +64,14 @@ {% trans 'Protocol' %}: - {{ system_user.protocol }} + {{ system_user.protocol }} - + {% trans 'Sudo' %}: {{ system_user.sudo }} {% if system_user.shell %} - + {% trans 'Shell' %}: {{ system_user.shell }} @@ -107,7 +107,7 @@
    -
    +
    {% trans 'Quick update' %}
    @@ -236,6 +236,12 @@ function updateSystemUserNode(nodes) { } jumpserver.nodes_selected = {}; $(document).ready(function () { + if($('#id_protocol_type').text() === 'rdp'){ + $('#id_quick_update').addClass('hidden'); + $('#id_sudo').addClass('hidden'); + $('#id_shell').addClass('hidden'); + } + $('.select2').select2() .on('select2:select', function(evt) { var data = evt.params.data; diff --git a/apps/assets/templates/assets/system_user_update.html b/apps/assets/templates/assets/system_user_update.html index 46ef8d6a3..a8a5c7483 100644 --- a/apps/assets/templates/assets/system_user_update.html +++ b/apps/assets/templates/assets/system_user_update.html @@ -15,10 +15,9 @@
    {% endblock %} -{% block custom_foot_js %} - -{% endblock %} \ No newline at end of file + protocolChange(); + }); +{% endblock %} From cb4afabc9117eff1847ca945ddb73d6b65dd1721 Mon Sep 17 00:00:00 2001 From: ibuler Date: Tue, 15 May 2018 14:44:02 +0800 Subject: [PATCH 036/112] =?UTF-8?q?[Bugfix]=20=E4=BF=AE=E5=A4=8D=E5=88=9B?= =?UTF-8?q?=E5=BB=BAnode=E8=8A=82=E7=82=B9=E7=9A=84=E9=97=AE=E9=A2=98?= =?UTF-8?q?=EF=BC=8C=E4=BF=AE=E5=A4=8Dwindows=20session=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/assets/api/node.py | 8 ++++---- apps/terminal/api.py | 3 +++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/apps/assets/api/node.py b/apps/assets/api/node.py index b8b2707e6..bc78e408a 100644 --- a/apps/assets/api/node.py +++ b/apps/assets/api/node.py @@ -51,10 +51,10 @@ class NodeViewSet(BulkModelViewSet): else: return serializers.NodeSerializer - # def perform_create(self, serializer): - # child_key = Node.root().get_next_child_key() - # serializer.validated_data["key"] = child_key - # serializer.save() + def perform_create(self, serializer): + child_key = Node.root().get_next_child_key() + serializer.validated_data["key"] = child_key + serializer.save() class NodeWithAssetsApi(generics.ListAPIView): diff --git a/apps/terminal/api.py b/apps/terminal/api.py index eb4b6400a..c9bb68ed6 100644 --- a/apps/terminal/api.py +++ b/apps/terminal/api.py @@ -108,6 +108,9 @@ class StatusViewSet(viewsets.ModelViewSet): task_serializer_class = TaskSerializer def create(self, request, *args, **kwargs): + if self.request.query_params.get("from_guacamole", None): + return Response({"msg": "From guacamole, not support now"}) + self.handle_sessions() super().create(request, *args, **kwargs) tasks = self.request.user.terminal.task_set.filter(is_finished=False) From ed18cb317f754432439d48823d91138315863ea3 Mon Sep 17 00:00:00 2001 From: ibuler Date: Tue, 15 May 2018 15:05:49 +0800 Subject: [PATCH 037/112] =?UTF-8?q?[Bugfix]=20=E4=BF=AE=E5=A4=8D=E5=88=9B?= =?UTF-8?q?=E5=BB=BAnode=20api=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/assets/serializers/node.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/apps/assets/serializers/node.py b/apps/assets/serializers/node.py index bee350591..b191b0a4f 100644 --- a/apps/assets/serializers/node.py +++ b/apps/assets/serializers/node.py @@ -53,14 +53,13 @@ class NodeSerializer(serializers.ModelSerializer): def validate(self, data): value = data.get('value') - instance = self.instance - if not instance.is_root(): - children = instance.parent.get_children().exclude(key=instance.key) - values = [child.value for child in children] - if value in values: - raise serializers.ValidationError( - 'The same level node name cannot be the same' - ) + instance = self.instance if self.instance else Node.root() + children = instance.parent.get_children().exclude(key=instance.key) + values = [child.value for child in children] + if value in values: + raise serializers.ValidationError( + 'The same level node name cannot be the same' + ) return data @staticmethod From 599431f402e868c69aa59de8bd3ba24fc5a55373 Mon Sep 17 00:00:00 2001 From: BaiJiangJie Date: Tue, 15 May 2018 17:32:20 +0800 Subject: [PATCH 038/112] =?UTF-8?q?[Update]=20=E5=8E=BB=E6=8E=89=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0windows=E7=9B=B8=E5=85=B3=E9=85=8D=E7=BD=AE=E6=97=B6?= =?UTF-8?q?=E7=9A=84=E4=B8=80=E4=BA=9B=E6=97=A0=E7=94=A8=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=EF=BC=8C=E7=BD=91=E5=9F=9F=E7=BD=91=E5=85=B3/=E4=BC=9A?= =?UTF-8?q?=E8=AF=9D=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/assets/api/node.py | 2 +- apps/assets/models/node.py | 2 +- .../assets/templates/assets/_system_user.html | 20 +++++++------- .../templates/assets/domain_gateway_list.html | 6 +++-- .../assets/gateway_create_update.html | 26 +++++++++++++++++++ .../templates/terminal/session_list.html | 6 ++++- 6 files changed, 47 insertions(+), 15 deletions(-) diff --git a/apps/assets/api/node.py b/apps/assets/api/node.py index 30d661a29..5a3197288 100644 --- a/apps/assets/api/node.py +++ b/apps/assets/api/node.py @@ -186,7 +186,7 @@ class NodeAddChildrenApi(generics.UpdateAPIView): continue # node.parent = instance # node.save() - node.move(instance) + node.set_parent(instance) return Response("OK") diff --git a/apps/assets/models/node.py b/apps/assets/models/node.py index bb83035c0..5ee97af9b 100644 --- a/apps/assets/models/node.py +++ b/apps/assets/models/node.py @@ -39,7 +39,7 @@ class Node(models.Model): def level(self): return len(self.key.split(':')) - def move(self, instance): + def set_parent(self, instance): children = self.get_all_children() old_key = self.key with transaction.atomic(): diff --git a/apps/assets/templates/assets/_system_user.html b/apps/assets/templates/assets/_system_user.html index 6e3b81658..98d1b6098 100644 --- a/apps/assets/templates/assets/_system_user.html +++ b/apps/assets/templates/assets/_system_user.html @@ -87,6 +87,16 @@ var sudo_id = '#' + '{{ form.sudo.id_for_label }}'; var shell_id = '#' + '{{ form.shell.id_for_label }}'; + var div_auto_generate_key = $(auto_generate_key).parent().parent(); + var div_ssh_private_key = $(private_key_id).parent().parent().parent().parent(); + var div_auto_push = $(auto_push_id).parent().parent(); + var div_sudo = $(sudo_id).parent().parent(); + var div_shell = $(shell_id).parent().parent(); + var need_change_div = [ + div_auto_generate_key, div_ssh_private_key, + div_auto_push, div_sudo, div_shell + ]; + function authFieldsDisplay() { if ($(auto_generate_key).prop('checked')) { $('.auth-fields').addClass('hidden'); @@ -96,16 +106,6 @@ } function protocolChange() { - var div_auto_generate_key = $(auto_generate_key).parent().parent(); - var div_ssh_private_key = $(private_key_id).parent().parent().parent().parent(); - var div_auto_push = $(auto_push_id).parent().parent(); - var div_sudo = $(sudo_id).parent().parent(); - var div_shell = $(shell_id).parent().parent(); - var need_change_div = [ - div_auto_generate_key, div_ssh_private_key, - div_auto_push, div_sudo, div_shell - ]; - if ($(protocol_id + " option:selected").text() === 'rdp') { $('.auth-fields').removeClass('hidden'); $.each(need_change_div, function (index, value) { diff --git a/apps/assets/templates/assets/domain_gateway_list.html b/apps/assets/templates/assets/domain_gateway_list.html index 581f6c08a..c2d5528ee 100644 --- a/apps/assets/templates/assets/domain_gateway_list.html +++ b/apps/assets/templates/assets/domain_gateway_list.html @@ -85,6 +85,9 @@ function initTable() { var update_btn = '{% trans "Update" %}'.replace('{{ DEFAULT_PK }}', cellData); var del_btn = '{% trans "Delete" %}'.replace('{{ DEFAULT_PK }}', cellData); var test_btn = '{% trans "Test connection" %}'.replace('{{ DEFAULT_PK }}', cellData); + if(rowData.protocol === 'rdp'){ + test_btn = '{% trans "Test connection" %}'.replace('{{ DEFAULT_PK }}', cellData); + } $(td).html(update_btn + test_btn + del_btn) }} ], @@ -120,7 +123,6 @@ $(document).ready(function(){ success_message: "可连接", fail_message: "连接失败" }) - -}) +}); {% endblock %} diff --git a/apps/assets/templates/assets/gateway_create_update.html b/apps/assets/templates/assets/gateway_create_update.html index 7d6800c41..e57d8ed5c 100644 --- a/apps/assets/templates/assets/gateway_create_update.html +++ b/apps/assets/templates/assets/gateway_create_update.html @@ -66,3 +66,29 @@
    {% endblock %} + +{% block custom_foot_js %} + +{% endblock %} \ No newline at end of file diff --git a/apps/terminal/templates/terminal/session_list.html b/apps/terminal/templates/terminal/session_list.html index eaaa89ce1..8cea8e217 100644 --- a/apps/terminal/templates/terminal/session_list.html +++ b/apps/terminal/templates/terminal/session_list.html @@ -102,7 +102,11 @@ {% trans "Replay" %} {% else %} - {% trans "Terminate" %} + {% if session.protocol == 'rdp' %} + {% trans "Terminate" %} + {% else %} + {% trans "Terminate" %} + {% endif %} {% endif %} From ac67c231fccb9ed80d57b3d73ba9dff8b88bcfd1 Mon Sep 17 00:00:00 2001 From: BaiJiangJie Date: Wed, 16 May 2018 12:31:13 +0800 Subject: [PATCH 039/112] =?UTF-8?q?[Update]=20=E4=BF=AE=E6=94=B9=E5=89=8D?= =?UTF-8?q?=E7=AB=AFrdp=E7=9B=B8=E5=85=B3=E9=85=8D=E7=BD=AE=E7=9A=84?= =?UTF-8?q?=E9=80=89=E6=8B=A9=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../assets/templates/assets/_system_user.html | 95 +++++++++---------- .../assets/gateway_create_update.html | 39 ++++---- .../templates/assets/system_user_detail.html | 11 +-- .../templates/assets/system_user_update.html | 6 -- 4 files changed, 66 insertions(+), 85 deletions(-) diff --git a/apps/assets/templates/assets/_system_user.html b/apps/assets/templates/assets/_system_user.html index 98d1b6098..314967d22 100644 --- a/apps/assets/templates/assets/_system_user.html +++ b/apps/assets/templates/assets/_system_user.html @@ -79,59 +79,50 @@ {% endblock %} {% block custom_foot_js %} - + } +} + +function authFieldsDisplay() { + if ($(auto_generate_key).prop('checked')) { + $('.auth-fields').addClass('hidden'); + } else { + $('.auth-fields').removeClass('hidden'); + } +} + +$(document).ready(function () { + $('.select2').select2(); + authFieldsDisplay(); + protocolChange(); +}) +.on('change', protocol_id, function(){ + protocolChange(); +}) +.on('change', auto_generate_key, function(){ + authFieldsDisplay(); +}); + + {% endblock %} \ No newline at end of file diff --git a/apps/assets/templates/assets/gateway_create_update.html b/apps/assets/templates/assets/gateway_create_update.html index e57d8ed5c..e0b10ba73 100644 --- a/apps/assets/templates/assets/gateway_create_update.html +++ b/apps/assets/templates/assets/gateway_create_update.html @@ -68,27 +68,26 @@ {% endblock %} {% block custom_foot_js %} - +$(document).ready(function(){ + protocolChange(); +}) +.on('change', protocol_id, function(){ + protocolChange(); +}); + {% endblock %} \ No newline at end of file diff --git a/apps/assets/templates/assets/system_user_detail.html b/apps/assets/templates/assets/system_user_detail.html index 96ed7bb93..cc686a62b 100644 --- a/apps/assets/templates/assets/system_user_detail.html +++ b/apps/assets/templates/assets/system_user_detail.html @@ -66,12 +66,12 @@ {% trans 'Protocol' %}: {{ system_user.protocol }} - + {% trans 'Sudo' %}: {{ system_user.sudo }} {% if system_user.shell %} - + {% trans 'Shell' %}: {{ system_user.shell }} @@ -107,7 +107,7 @@
    -
    +
    {% trans 'Quick update' %}
    @@ -237,11 +237,8 @@ function updateSystemUserNode(nodes) { jumpserver.nodes_selected = {}; $(document).ready(function () { if($('#id_protocol_type').text() === 'rdp'){ - $('#id_quick_update').addClass('hidden'); - $('#id_sudo').addClass('hidden'); - $('#id_shell').addClass('hidden'); + $('.only-ssh').addClass('hidden') } - $('.select2').select2() .on('select2:select', function(evt) { var data = evt.params.data; diff --git a/apps/assets/templates/assets/system_user_update.html b/apps/assets/templates/assets/system_user_update.html index a8a5c7483..7e1590db5 100644 --- a/apps/assets/templates/assets/system_user_update.html +++ b/apps/assets/templates/assets/system_user_update.html @@ -15,9 +15,3 @@
    {% endblock %} -{% block document_ready %} - $(document).ready(function () { - $('.select2').select2(); - protocolChange(); - }); -{% endblock %} From c1db33713f68de225b38d0f8910e4cae47269993 Mon Sep 17 00:00:00 2001 From: BaiJiangJie Date: Wed, 16 May 2018 16:12:27 +0800 Subject: [PATCH 040/112] =?UTF-8?q?[Bugfix]=20=E4=BF=AE=E5=A4=8D=E8=B5=84?= =?UTF-8?q?=E4=BA=A7=E6=8E=88=E6=9D=83=E6=A0=91root=E8=8A=82=E7=82=B9bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/assets/api/node.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/assets/api/node.py b/apps/assets/api/node.py index b0e974f5c..a6d00b44a 100644 --- a/apps/assets/api/node.py +++ b/apps/assets/api/node.py @@ -123,7 +123,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 @@ -133,7 +133,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() @@ -184,8 +185,6 @@ class NodeAddChildrenApi(generics.UpdateAPIView): for node in children: if not node: continue - # node.parent = instance - # node.save() node.set_parent(instance) return Response("OK") From 4b7af1457d14e5779d47fb4b6b65dc5b9f382d24 Mon Sep 17 00:00:00 2001 From: ibuler Date: Thu, 17 May 2018 11:39:04 +0800 Subject: [PATCH 041/112] =?UTF-8?q?[Update]=20=E7=B3=BB=E7=BB=9F=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E6=96=B0=E5=A2=9E=E6=B8=85=E9=99=A4=E8=AE=A4=E8=AF=81?= =?UTF-8?q?=E7=9A=84=E6=93=8D=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/assets/api/system_user.py | 7 +- apps/assets/models/base.py | 1 + .../templates/assets/system_user_detail.html | 25 +++++-- apps/i18n/zh/LC_MESSAGES/django.mo | Bin 33242 -> 33388 bytes apps/i18n/zh/LC_MESSAGES/django.po | 61 +++++++++++------- apps/users/models/group.py | 2 +- 6 files changed, 67 insertions(+), 29 deletions(-) diff --git a/apps/assets/api/system_user.py b/apps/assets/api/system_user.py index 1be316567..66d62232d 100644 --- a/apps/assets/api/system_user.py +++ b/apps/assets/api/system_user.py @@ -40,7 +40,7 @@ class SystemUserViewSet(BulkModelViewSet): permission_classes = (IsSuperUserOrAppUser,) -class SystemUserAuthInfoApi(generics.RetrieveUpdateAPIView): +class SystemUserAuthInfoApi(generics.RetrieveUpdateDestroyAPIView): """ Get system user auth info """ @@ -48,6 +48,11 @@ class SystemUserAuthInfoApi(generics.RetrieveUpdateAPIView): permission_classes = (IsSuperUserOrAppUser,) serializer_class = serializers.SystemUserAuthSerializer + def destroy(self, request, *args, **kwargs): + instance = self.get_object() + instance.clear_auth() + return Response(status=204) + class SystemUserPushApi(generics.RetrieveAPIView): """ diff --git a/apps/assets/models/base.py b/apps/assets/models/base.py index 11afd92cf..cb9bb96ae 100644 --- a/apps/assets/models/base.py +++ b/apps/assets/models/base.py @@ -107,6 +107,7 @@ class AssetUser(models.Model): def clear_auth(self): self._password = '' self._private_key = '' + self._public_key = '' self.save() def auto_gen_auth(self): diff --git a/apps/assets/templates/assets/system_user_detail.html b/apps/assets/templates/assets/system_user_detail.html index cc686a62b..9a7bc255a 100644 --- a/apps/assets/templates/assets/system_user_detail.html +++ b/apps/assets/templates/assets/system_user_detail.html @@ -107,14 +107,14 @@
    -
    +
    {% trans 'Quick update' %}
    - + - {% if system_user.auto_push %} + - {% endif %} + + + + + + {# #} {# #} {# ?u2HiM1)~BF{rI$5KGhZ{8VJPiu zQMcd|)PlY;52Lp9xS4NWH=VIw{}5EaNVCdV-haK{b*w{YEKT0sI*dSF$pj3?`B({8 zpkA-t7>#GJHWnV|ec;5S#z{k+KM1w(Y-;UX1!Na~LFR@wx$(w4Xw z(=ZbAt^O`*2LdN}_dE>sB@~50SOzs-460vU)B+OCWV2f}3ceMhCd{^m=~lnc>eu8< zu2j-hk36e6WnRMS)Zena%0zF(I;j4w%uc8!^hPahs5u(7MAw{dzKlBmb<_%1Oyp*1 zfDftAhv`1lK;NLA`|nXV=@jxm=L&x`z_aYJ9E&=C1~$b-sDTfo#`)FS|1ck*UWc$r z-gz;TtYbqeG++y}qjl(M`C!Y(paz(3`4V$2YQpWPaSossas;)&d{p~Q)J=6Jd%3?$ zL0c7yIx)(Ow)(neB5HtUmbb&2-JJNqrHbGNB96ahCFY;vnU=xEbdV-6%hf z{(k)7SYL?yf15%J8gwLLI`$_z5r2`thgDJU%3VUo??e|nM|mltK5?4RbF+bnCA9UY zh-ub0fU=Gd7El^jGQaPbPKTc;4MzQ6P#O>+U@7+Cm(K|E>IIl>?I$Ke-fWjZisvi zJD*d2iijqL5jrjrZxQ#%`AOxxgWqBk;!WZ!;%`F7@4Ekd>^Wc2sWx$s@?|2L7)kyk zF^MQaX%UNVEHNX&#YWPcM4BX|1ObBxrCqH|8CafR~$p5 zj$&93%M%f7SHZF0+S9QYQNbD}TKy;3g1TGyowc>cYvjIn-|E(2p5}kkPAqGxy}FfK zQVwSFaPkI}{~>g|MqU#$3H>tIK%PYC({dv&CUhJ!U!=T>NG7^cSIz3(1r+{6{6d3{ zjvoL1Jx$xgWKsBlD9K{Rk$-AEex~jQvDESp@m2DI<2lNokgO$k5FN=~q7mi2-t+G` zyX=Gj{ELPQI05St^C-WMM+hAUhzitwK>UZY9}7B+G2{iuqgI%UpHjb+(3kXkcn-G` ztthwDKh{1)@;!-;Gej)qAj^LsuSfY0%l~Wsf)8kW-13DcRn9AvU&s4amutpj3F=dc z_bE>x7HKP*64R+{hB{7q`2PMx-5{bbSt2o$a!LH!`i`VLoAP6*V<^#yd@2@aXZlz_ zwdwecd<4$1diNH|L}D!!^RNt2o^nMTkDH0zghPxY&J+I1IsP~9h%gqkkvvL`9IN&I>&T<=zrGUpl5%@uCozQ3|BLWp{Fb;%JVU=Xh;r6{1a)_a z#>5mtM=@eC5lr+WbY#>?QjdR!}6=t%^+HH(!*B@Pf2E_ee!}FAj5~;)coxUdSnRQaypYmnm8>>5l z>#W=l(}-8-7esWRJXbEjIVL7@XPMmnvB@walu=;t#xFKBeDQoyLu0|pEnH7aLL_a1@q zjVi~-H*HXV^X2aSg39E7JndrcD#zo(x>Xm}Pd>MEMgHXVn^OnOuNaU&bN;WhmpT6f DXY(YG delta 11471 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 diff --git a/apps/i18n/zh/LC_MESSAGES/django.po b/apps/i18n/zh/LC_MESSAGES/django.po index 8f95f9291..196c3fb36 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-08 17:24+0800\n" +"POT-Creation-Date: 2018-05-17 11:32+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: ibuler \n" "Language-Team: Jumpserver team\n" @@ -17,22 +17,22 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: assets/api/node.py:96 +#: assets/api/node.py:106 msgid "New node {}" msgstr "新节点 {}" -#: assets/api/node.py:225 +#: assets/api/node.py:242 msgid "更新节点资产硬件信息: {}" msgstr "" -#: assets/api/node.py:238 +#: assets/api/node.py:255 msgid "测试节点下资产是否可连接: {}" msgstr "" #: assets/forms/asset.py:24 assets/models/asset.py:66 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:166 perms/models.py:33 +#: assets/templates/assets/system_user_detail.html:175 perms/models.py:33 msgid "Nodes" msgstr "节点管理" @@ -438,7 +438,7 @@ msgstr "默认资产组" msgid "User" msgstr "用户" -#: assets/models/label.py:18 assets/models/node.py:15 +#: assets/models/label.py:18 assets/models/node.py:18 #: assets/templates/assets/label_list.html:15 common/models.py:27 msgid "Value" msgstr "值" @@ -535,7 +535,7 @@ msgstr "测试系统用户可连接性: {}" msgid "定期测试系统用户可连接性: {}" msgstr "" -#: assets/tasks.py:401 +#: assets/tasks.py:402 msgid "推送系统用户到入资产: {}" msgstr "" @@ -660,7 +660,7 @@ msgstr "重置" #: common/templates/common/ldap_setting.html:60 #: common/templates/common/terminal_setting.html:103 #: perms/templates/perms/asset_permission_create_update.html:70 -#: terminal/templates/terminal/session_list.html:120 +#: 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 @@ -782,8 +782,8 @@ msgstr "选择节点" #: assets/templates/assets/admin_user_detail.html:100 #: assets/templates/assets/asset_detail.html:200 -#: assets/templates/assets/asset_list.html:634 -#: assets/templates/assets/system_user_detail.html:183 +#: assets/templates/assets/asset_list.html:636 +#: 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 @@ -963,19 +963,19 @@ msgstr "仅显示当前节点资产" msgid "Displays all child node assets" msgstr "显示所有子节点资产" -#: assets/templates/assets/asset_list.html:215 +#: assets/templates/assets/asset_list.html:217 msgid "Create node failed" msgstr "创建节点失败" -#: assets/templates/assets/asset_list.html:227 +#: assets/templates/assets/asset_list.html:229 msgid "Have child node, cancel" msgstr "存在子节点,不能删除" -#: assets/templates/assets/asset_list.html:229 +#: assets/templates/assets/asset_list.html:231 msgid "Have assets, cancel" msgstr "存在资产,不能删除" -#: assets/templates/assets/asset_list.html:629 +#: assets/templates/assets/asset_list.html:631 #: assets/templates/assets/system_user_list.html:133 #: users/templates/users/user_detail.html:357 #: users/templates/users/user_detail.html:382 @@ -984,20 +984,20 @@ msgstr "存在资产,不能删除" msgid "Are you sure?" msgstr "你确认吗?" -#: assets/templates/assets/asset_list.html:630 +#: assets/templates/assets/asset_list.html:632 msgid "This will delete the selected assets !!!" msgstr "删除选择资产" -#: assets/templates/assets/asset_list.html:638 +#: assets/templates/assets/asset_list.html:640 msgid "Asset Deleted." msgstr "已被删除" -#: assets/templates/assets/asset_list.html:639 -#: assets/templates/assets/asset_list.html:644 +#: assets/templates/assets/asset_list.html:641 +#: assets/templates/assets/asset_list.html:646 msgid "Asset Delete" msgstr "删除" -#: assets/templates/assets/asset_list.html:643 +#: assets/templates/assets/asset_list.html:645 msgid "Asset Deleting failed." msgstr "删除失败" @@ -1032,6 +1032,7 @@ msgid "Create gateway" 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 msgid "Test connection" @@ -1080,10 +1081,23 @@ msgstr "家目录" msgid "Uid" msgstr "Uid" -#: assets/templates/assets/system_user_detail.html:174 +#: assets/templates/assets/system_user_detail.html:153 +#: assets/templates/assets/system_user_detail.html:339 +msgid "Clear auth" +msgstr "清除认证信息" + +#: assets/templates/assets/system_user_detail.html:156 +msgid "Clear" +msgstr "清除" + +#: assets/templates/assets/system_user_detail.html:183 msgid "Add to node" msgstr "添加到节点" +#: assets/templates/assets/system_user_detail.html:339 +msgid "success" +msgstr "成功" + #: assets/templates/assets/system_user_list.html:18 #: assets/views/system_user.py:45 msgid "Create system user" @@ -2113,15 +2127,16 @@ msgstr "时长" msgid "Monitor" msgstr "监控" -#: terminal/templates/terminal/session_list.html:105 +#: terminal/templates/terminal/session_list.html:106 +#: terminal/templates/terminal/session_list.html:108 msgid "Terminate" msgstr "终断" -#: terminal/templates/terminal/session_list.html:116 +#: terminal/templates/terminal/session_list.html:120 msgid "Terminate selected" msgstr "终断所选" -#: terminal/templates/terminal/session_list.html:136 +#: terminal/templates/terminal/session_list.html:140 msgid "Terminate task send, waiting ..." msgstr "终断任务已发送,请等待" diff --git a/apps/users/models/group.py b/apps/users/models/group.py index 128fbdbcb..48ed2e949 100644 --- a/apps/users/models/group.py +++ b/apps/users/models/group.py @@ -11,7 +11,7 @@ __all__ = ['UserGroup'] class UserGroup(NoDeleteModelMixin): id = models.UUIDField(default=uuid.uuid4, primary_key=True) - name = models.CharField(max_length=128, verbose_name=_('Name')) + name = models.CharField(max_length=128, unique=True, verbose_name=_('Name')) comment = models.TextField(blank=True, verbose_name=_('Comment')) date_created = models.DateTimeField(auto_now_add=True, null=True, verbose_name=_('Date created')) From 46520287d940daee4444e1a217adf609fe4bc7e6 Mon Sep 17 00:00:00 2001 From: ibuler Date: Thu, 17 May 2018 15:26:22 +0800 Subject: [PATCH 042/112] =?UTF-8?q?[Update]=20=E6=B7=BB=E5=8A=A0=E6=B8=85?= =?UTF-8?q?=E7=90=86=E9=87=8D=E5=A4=8D=E7=94=A8=E6=88=B7=E7=BB=84=E8=84=9A?= =?UTF-8?q?=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utils/clean_duplicate_user_groups.py | 70 ++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 utils/clean_duplicate_user_groups.py diff --git a/utils/clean_duplicate_user_groups.py b/utils/clean_duplicate_user_groups.py new file mode 100644 index 000000000..be8b2d9ec --- /dev/null +++ b/utils/clean_duplicate_user_groups.py @@ -0,0 +1,70 @@ +#!/usr/bin/python +# + +import os +import sys +from collections import Counter +import django +from django.db.models import Count + + +if os.path.exists('../apps'): + sys.path.insert(0, '../apps') +elif os.path.exists('./apps'): + sys.path.insert(0, './apps') + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "jumpserver.settings") +django.setup() + +from users.models import UserGroup + + +def clean_group(interactive=True): + groups = UserGroup.objects.all() + groups_name_list = groups.values_list('name', flat=True) + groups_with_info = groups.annotate(Count('users'))\ + .annotate(Count('asset_permissions')) + + counter = Counter(groups_name_list) + for name, count in counter.items(): + if count == 0: + continue + groups_duplicate = groups_with_info.filter(name=name) + need_clean_count = groups_duplicate.count() + + for group in groups_duplicate: + need_clean = True + if group.users__count > 0: + need_clean = False + elif group.asset_permissions__count > 0: + need_clean = False + elif need_clean_count == 1: + need_clean = False + + if need_clean: + confirm = True + if interactive: + confirm = False + while True: + confirm = input( + "Delete user group <{}>, create at {}? ([y]/n)".format( + name, group.date_created) + ) + if confirm.lower() == "y": + confirm = True + break + elif confirm.lower() == "n": + confirm = False + break + else: + print("No valid input") + continue + if confirm: + group.delete() + print("Delete success: {}".format(name)) + need_clean_count -= 1 + else: + continue + +if __name__ == '__main__': + clean_group() From d615eb80b5672948a59aaa19d92095c5a5912a9c Mon Sep 17 00:00:00 2001 From: ibuler Date: Tue, 22 May 2018 18:22:06 +0800 Subject: [PATCH 043/112] =?UTF-8?q?[Update]=20=E4=BC=98=E5=8C=96=E4=BD=BF?= =?UTF-8?q?=E7=94=A8storage=20sdk?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/terminal/api.py | 54 +++++++-------------- apps/terminal/backends/__init__.py | 16 +++--- apps/terminal/backends/command/es.py | 31 +++--------- apps/terminal/serializers.py | 4 +- apps/terminal/templatetags/terminal_tags.py | 4 +- apps/terminal/views/command.py | 4 +- apps/terminal/views/session.py | 4 +- requirements/requirements.txt | 3 +- 8 files changed, 41 insertions(+), 79 deletions(-) diff --git a/apps/terminal/api.py b/apps/terminal/api.py index c9bb68ed6..924a30dfd 100644 --- a/apps/terminal/api.py +++ b/apps/terminal/api.py @@ -9,6 +9,7 @@ from django.core.cache import cache from django.shortcuts import get_object_or_404, redirect from django.utils import timezone from django.core.files.storage import default_storage +from django.http.response import HttpResponseRedirectBase from django.http import HttpResponseNotFound from django.conf import settings @@ -25,7 +26,7 @@ from .serializers import TerminalSerializer, StatusSerializer, \ SessionSerializer, TaskSerializer, ReplaySerializer from .hands import IsSuperUserOrAppUser, IsAppUser, \ IsSuperUserOrAppUserOrUserReadonly -from .backends import get_command_store, get_multi_command_store, \ +from .backends import get_command_storage, get_multi_command_storage, \ SessionCommandSerializer logger = logging.getLogger(__file__) @@ -227,8 +228,8 @@ class CommandViewSet(viewsets.ViewSet): } """ - command_store = get_command_store() - multi_command_storage = get_multi_command_store() + command_store = get_command_storage() + multi_command_storage = get_multi_command_storage() serializer_class = SessionCommandSerializer permission_classes = (IsSuperUserOrAppUser,) @@ -291,19 +292,20 @@ class SessionReplayViewSet(viewsets.ViewSet): url = default_storage.url(path) return redirect(url) else: - configs = settings.TERMINAL_REPLAY_STORAGE.items() + configs = settings.TERMINAL_REPLAY_STORAGE + configs = [cfg for cfg in configs if cfg['TYPE'] != 'server'] if not configs: return HttpResponseNotFound() - for name, config in configs: - client = jms_storage.init(config) - date = self.session.date_start.strftime('%Y-%m-%d') - file_path = os.path.join(date, str(self.session.id) + '.replay.gz') - target_path = default_storage.base_location + '/' + path - - if client and client.has_file(file_path) and \ - client.download_file(file_path, target_path): - return redirect(default_storage.url(path)) + date = self.session.date_start.strftime('%Y-%m-%d') + file_path = os.path.join(date, str(self.session.id) + '.replay.gz') + target_path = default_storage.base_location + '/' + path + storage = jms_storage.get_multi_object_storage(configs) + ok, err = storage.download(file_path, target_path) + if ok: + return redirect(default_storage.url(path)) + else: + logger.error("Failed download replay file: {}".format(err)) return HttpResponseNotFound() @@ -313,34 +315,14 @@ class SessionReplayV2ViewSet(SessionReplayViewSet): session = None def retrieve(self, request, *args, **kwargs): - session_id = kwargs.get('pk') - self.session = get_object_or_404(Session, id=session_id) - path = self.gen_session_path() + response = super().retrieve(request, *args, **kwargs) data = { 'type': 'guacamole' if self.session.protocol == 'rdp' else 'json', 'src': '', } - - if default_storage.exists(path): - url = default_storage.url(path) - data['src'] = url + if isinstance(response, HttpResponseRedirectBase): + data['src'] = response.url return Response(data) - else: - configs = settings.TERMINAL_REPLAY_STORAGE.items() - if not configs: - return HttpResponseNotFound() - - for name, config in configs: - client = jms_storage.init(config) - date = self.session.date_start.strftime('%Y-%m-%d') - file_path = os.path.join(date, str(self.session.id) + '.replay.gz') - target_path = default_storage.base_location + '/' + path - - if client and client.has_file(file_path) and \ - client.download_file(file_path, target_path): - url = default_storage.url(path) - data['src'] = url - return Response(data) return HttpResponseNotFound() diff --git a/apps/terminal/backends/__init__.py b/apps/terminal/backends/__init__.py index ef1ba56a9..9a1c338f5 100644 --- a/apps/terminal/backends/__init__.py +++ b/apps/terminal/backends/__init__.py @@ -7,19 +7,19 @@ TYPE_ENGINE_MAPPING = { } -def get_command_store(): - params = settings.COMMAND_STORAGE - engine_class = import_module(params['ENGINE']) - storage = engine_class.CommandStore(params) +def get_command_storage(): + config = settings.COMMAND_STORAGE + engine_class = import_module(config['ENGINE']) + storage = engine_class.CommandStore(config) return storage -def get_terminal_command_store(): +def get_terminal_command_storages(): storage_list = {} for name, params in settings.TERMINAL_COMMAND_STORAGE.items(): tp = params['TYPE'] if tp == 'server': - storage = get_command_store() + storage = get_command_storage() else: if not TYPE_ENGINE_MAPPING.get(tp): continue @@ -29,9 +29,9 @@ def get_terminal_command_store(): return storage_list -def get_multi_command_store(): +def get_multi_command_storage(): from .command.multi import CommandStore - storage_list = get_terminal_command_store().values() + storage_list = get_terminal_command_storages().values() storage = CommandStore(storage_list) return storage diff --git a/apps/terminal/backends/command/es.py b/apps/terminal/backends/command/es.py index 9c75fc978..dde8e1e95 100644 --- a/apps/terminal/backends/command/es.py +++ b/apps/terminal/backends/command/es.py @@ -1,41 +1,22 @@ # -*- coding: utf-8 -*- # -from jms_es_sdk import ESStore +from jms_storage.es import ESStorage from .base import CommandBase from .models import AbstractSessionCommand -class CommandStore(CommandBase, ESStore): +class CommandStore(ESStorage, CommandBase): def __init__(self, params): - hosts = params.get('HOSTS', ['http://localhost']) - ESStore.__init__(self, hosts=hosts) - - def save(self, command): - return ESStore.save(self, command) - - def bulk_save(self, commands): - return ESStore.bulk_save(self, commands) + super().__init__(params) def filter(self, date_from=None, date_to=None, user=None, asset=None, system_user=None, input=None, session=None): - data = ESStore.filter( - self, date_from=date_from, date_to=date_to, - user=user, asset=asset, system_user=system_user, - input=input, session=session - ) + data = super().filter(date_from=date_from, date_to=date_to, + user=user, asset=asset, system_user=system_user, + input=input, session=session) return AbstractSessionCommand.from_multi_dict( [item["_source"] for item in data["hits"] if item] ) - - def count(self, date_from=None, date_to=None, - user=None, asset=None, system_user=None, - input=None, session=None): - amount = ESStore.count( - self, date_from=date_from, date_to=date_to, - user=user, asset=asset, system_user=system_user, - input=input, session=session - ) - return amount diff --git a/apps/terminal/serializers.py b/apps/terminal/serializers.py index 8c40315a7..c18c5023d 100644 --- a/apps/terminal/serializers.py +++ b/apps/terminal/serializers.py @@ -9,7 +9,7 @@ from rest_framework_bulk.serializers import BulkListSerializer from common.mixins import BulkSerializerMixin from common.utils import get_object_or_none from .models import Terminal, Status, Session, Task -from .backends import get_multi_command_store +from .backends import get_multi_command_storage class TerminalSerializer(serializers.ModelSerializer): @@ -47,7 +47,7 @@ class TerminalSerializer(serializers.ModelSerializer): class SessionSerializer(serializers.ModelSerializer): command_amount = serializers.SerializerMethodField() - command_store = get_multi_command_store() + command_store = get_multi_command_storage() class Meta: model = Session diff --git a/apps/terminal/templatetags/terminal_tags.py b/apps/terminal/templatetags/terminal_tags.py index cd7120fec..c5643c67b 100644 --- a/apps/terminal/templatetags/terminal_tags.py +++ b/apps/terminal/templatetags/terminal_tags.py @@ -1,10 +1,10 @@ # ~*~ coding: utf-8 ~*~ from django import template -from ..backends import get_multi_command_store +from ..backends import get_multi_command_storage register = template.Library() -command_store = get_multi_command_store() +command_store = get_multi_command_storage() @register.filter diff --git a/apps/terminal/views/command.py b/apps/terminal/views/command.py index 0af0b5bfd..748261414 100644 --- a/apps/terminal/views/command.py +++ b/apps/terminal/views/command.py @@ -9,10 +9,10 @@ from django.utils.translation import ugettext as _ from common.mixins import DatetimeSearchMixin, AdminUserRequiredMixin from ..models import Command from .. import utils -from ..backends import get_multi_command_store +from ..backends import get_multi_command_storage __all__ = ['CommandListView'] -common_storage = get_multi_command_store() +common_storage = get_multi_command_storage() class CommandListView(DatetimeSearchMixin, AdminUserRequiredMixin, ListView): diff --git a/apps/terminal/views/session.py b/apps/terminal/views/session.py index 3b66baff7..71caeae48 100644 --- a/apps/terminal/views/session.py +++ b/apps/terminal/views/session.py @@ -10,7 +10,7 @@ from django.conf import settings from users.utils import AdminUserRequiredMixin from common.mixins import DatetimeSearchMixin from ..models import Session, Command, Terminal -from ..backends import get_multi_command_store +from ..backends import get_multi_command_storage from .. import utils @@ -19,7 +19,7 @@ __all__ = [ 'SessionDetailView', ] -command_store = get_multi_command_store() +command_store = get_multi_command_storage() class SessionListView(AdminUserRequiredMixin, DatetimeSearchMixin, ListView): diff --git a/requirements/requirements.txt b/requirements/requirements.txt index e0ecc634e..5fb844181 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -40,7 +40,6 @@ itsdangerous==0.24 itypes==1.1.0 Jinja2==2.10 jmespath==0.9.3 -jms-es-sdk kombu==4.0.2 ldap3==2.4 MarkupSafe==1.0 @@ -62,7 +61,7 @@ pytz==2017.3 PyYAML==3.12 redis==2.10.6 requests==2.18.4 -jms-storage==0.0.13 +jms-storage==0.0.15 s3transfer==0.1.13 simplejson==3.13.2 six==1.11.0 From 092b33d4d1ca10a3dbe7c9c93b8db467796cdce2 Mon Sep 17 00:00:00 2001 From: ibuler Date: Tue, 22 May 2018 19:30:15 +0800 Subject: [PATCH 044/112] =?UTF-8?q?[Update]=20=E6=9B=B4=E6=96=B0requiremen?= =?UTF-8?q?ts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- requirements/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 5fb844181..f3905f018 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -61,7 +61,7 @@ pytz==2017.3 PyYAML==3.12 redis==2.10.6 requests==2.18.4 -jms-storage==0.0.15 +jms-storage==0.0.16 s3transfer==0.1.13 simplejson==3.13.2 six==1.11.0 From dc1d228e07e5b17022044f4bb0984372c954761d Mon Sep 17 00:00:00 2001 From: ibuler Date: Tue, 22 May 2018 19:44:13 +0800 Subject: [PATCH 045/112] =?UTF-8?q?[Update]=20=E6=9B=B4=E6=96=B0requiremen?= =?UTF-8?q?ts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- requirements/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/requirements.txt b/requirements/requirements.txt index f3905f018..af682f5ca 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -61,7 +61,7 @@ pytz==2017.3 PyYAML==3.12 redis==2.10.6 requests==2.18.4 -jms-storage==0.0.16 +jms-storage==0.0.17 s3transfer==0.1.13 simplejson==3.13.2 six==1.11.0 From f8384973a1be85cac0df6e63630f1ec15a6be386 Mon Sep 17 00:00:00 2001 From: ibuler Date: Wed, 23 May 2018 15:15:27 +0800 Subject: [PATCH 046/112] =?UTF-8?q?[Update]=20=E8=B0=83=E6=95=B4Luna?= =?UTF-8?q?=E7=9A=84=E6=A0=91=E5=BD=A2=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/assets/models/node.py | 8 ++++++-- apps/perms/api.py | 9 +++++++-- apps/perms/utils.py | 34 +++++++++++++++++++++++++++++++--- 3 files changed, 44 insertions(+), 7 deletions(-) diff --git a/apps/assets/models/node.py b/apps/assets/models/node.py index 5ee97af9b..fed8980ed 100644 --- a/apps/assets/models/node.py +++ b/apps/assets/models/node.py @@ -61,10 +61,14 @@ class Node(models.Model): return child def get_children(self): - return self.__class__.objects.filter(key__regex=r'^{}:[0-9]+$'.format(self.key)) + return self.__class__.objects.filter( + key__regex=r'^{}:[0-9]+$'.format(self.key) + ) def get_all_children(self): - return self.__class__.objects.filter(key__startswith='{}:'.format(self.key)) + return self.__class__.objects.filter( + key__startswith='{}:'.format(self.key) + ) def get_family(self): children = list(self.get_all_children()) diff --git a/apps/perms/api.py b/apps/perms/api.py index be69d6158..8f663a0f4 100644 --- a/apps/perms/api.py +++ b/apps/perms/api.py @@ -6,7 +6,7 @@ from rest_framework.views import APIView, Response from rest_framework.generics import ListAPIView, get_object_or_404, RetrieveUpdateAPIView from rest_framework import viewsets -from common.utils import set_or_append_attr_bulk +from common.utils import set_or_append_attr_bulk, get_object_or_none from users.permissions import IsValidUser, IsSuperUser, IsSuperUserOrAppUser from .utils import AssetPermissionUtil from .models import AssetPermission @@ -147,8 +147,13 @@ class UserGrantedNodeAssetsApi(ListAPIView): user = get_object_or_404(User, id=user_id) else: user = self.request.user - node = get_object_or_404(Node, id=node_id) nodes = AssetPermissionUtil.get_user_nodes_with_assets(user) + node = get_object_or_none(Node, id=node_id) + + if not node: + unnode = [node for node in nodes if node.name == 'Unnode'] + node = unnode[0] if unnode else None + assets = nodes.get(node, []) for asset, system_users in assets.items(): asset.system_users_granted = system_users diff --git a/apps/perms/utils.py b/apps/perms/utils.py index b23b1cb7c..abcd2e17e 100644 --- a/apps/perms/utils.py +++ b/apps/perms/utils.py @@ -13,7 +13,6 @@ logger = get_logger(__file__) class AssetPermissionUtil: - @staticmethod def get_user_permissions(user): return AssetPermission.objects.all().valid().filter(users=user) @@ -122,6 +121,24 @@ class AssetPermissionUtil: nodes[node].update(set(_system_users)) return nodes + @classmethod + def get_user_nodes_inherit_group(cls, user): + nodes = defaultdict(set) + groups = user.groups.all() + for group in groups: + _nodes = cls.get_user_group_nodes(group) + for node, system_users in _nodes.items(): + nodes[node].update(set(system_users)) + return nodes + + @classmethod + def get_user_nodes(cls, user): + nodes = cls.get_user_nodes_direct(user) + nodes_inherit = cls.get_user_nodes_inherit_group(user) + for node, system_users in nodes_inherit.items(): + nodes[node].update(set(system_users)) + return nodes + @classmethod def get_user_nodes_assets_direct(cls, user): assets = defaultdict(set) @@ -164,15 +181,26 @@ class AssetPermissionUtil: :param user: :return: {node: {asset: set(su1, su2)}} """ + from assets.models import Node + unnode = Node(value='Unnode') nodes = defaultdict(dict) + for _node in cls.get_user_nodes(user): + children = _node.get_family() + for node in children: + nodes[node] = defaultdict(set) _assets = cls.get_user_assets(user) for asset, _system_users in _assets.items(): _nodes = asset.get_nodes() + in_node = False for node in _nodes: - if asset in nodes[node]: + if node in nodes: + in_node = True nodes[node][asset].update(_system_users) + if not in_node: + if unnode in nodes: + nodes[unnode][asset].update(_system_users) else: - nodes[node][asset] = _system_users + nodes[unnode][asset] = _system_users return nodes @classmethod From fe52c57a1133976c585d9db0acf0331c142a8c6e Mon Sep 17 00:00:00 2001 From: ibuler Date: Thu, 24 May 2018 11:13:22 +0800 Subject: [PATCH 047/112] =?UTF-8?q?[Bugfix]=20=E4=BF=AE=E5=A4=8D=E6=8E=88?= =?UTF-8?q?=E6=9D=83uitls=E7=9A=84=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/perms/utils.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/perms/utils.py b/apps/perms/utils.py index abcd2e17e..36349b982 100644 --- a/apps/perms/utils.py +++ b/apps/perms/utils.py @@ -197,10 +197,8 @@ class AssetPermissionUtil: in_node = True nodes[node][asset].update(_system_users) if not in_node: - if unnode in nodes: - nodes[unnode][asset].update(_system_users) - else: - nodes[unnode][asset] = _system_users + nodes[unnode] = defaultdict(set) + nodes[unnode][asset].update(_system_users) return nodes @classmethod From c529061ee0ade5494d4f1e0947f8e12c3ef41792 Mon Sep 17 00:00:00 2001 From: ibuler Date: Thu, 24 May 2018 11:18:20 +0800 Subject: [PATCH 048/112] =?UTF-8?q?[Bugfix]=20=E4=BF=AE=E5=A4=8D=E6=8E=88?= =?UTF-8?q?=E6=9D=83uitls=E7=9A=84=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/perms/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/perms/utils.py b/apps/perms/utils.py index 36349b982..7899cc5cb 100644 --- a/apps/perms/utils.py +++ b/apps/perms/utils.py @@ -188,6 +188,7 @@ class AssetPermissionUtil: children = _node.get_family() for node in children: nodes[node] = defaultdict(set) + nodes[unnode] = defaultdict(set) _assets = cls.get_user_assets(user) for asset, _system_users in _assets.items(): _nodes = asset.get_nodes() @@ -197,7 +198,6 @@ class AssetPermissionUtil: in_node = True nodes[node][asset].update(_system_users) if not in_node: - nodes[unnode] = defaultdict(set) nodes[unnode][asset].update(_system_users) return nodes From 486793ddcddfc1884f9c6e9d913fe57414191d36 Mon Sep 17 00:00:00 2001 From: BaiJiangJie Date: Thu, 24 May 2018 12:41:48 +0800 Subject: [PATCH 049/112] =?UTF-8?q?[Bugfix]=20=E4=BF=AE=E5=A4=8D=E5=8F=96?= =?UTF-8?q?=E6=B6=88LDAP=E8=AE=A4=E8=AF=81=E4=B8=8D=E6=88=90=E5=8A=9Fbug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/common/signals_handler.py | 2 +- apps/common/views.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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/views.py b/apps/common/views.py index ee7a2225f..c701df407 100644 --- a/apps/common/views.py +++ b/apps/common/views.py @@ -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') From 5a7192e035e3f6b1c08bf909641f1063d36e681d Mon Sep 17 00:00:00 2001 From: ibuler Date: Thu, 24 May 2018 13:30:15 +0800 Subject: [PATCH 050/112] =?UTF-8?q?[Update]=20=E4=BF=AE=E6=94=B9=E5=BF=83?= =?UTF-8?q?=E8=B7=B3bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/terminal/api.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/terminal/api.py b/apps/terminal/api.py index 924a30dfd..fbbae5e22 100644 --- a/apps/terminal/api.py +++ b/apps/terminal/api.py @@ -109,10 +109,9 @@ class StatusViewSet(viewsets.ModelViewSet): task_serializer_class = TaskSerializer def create(self, request, *args, **kwargs): - if self.request.query_params.get("from_guacamole", None): - return Response({"msg": "From guacamole, not support now"}) - - self.handle_sessions() + from_gua = self.request.query_params.get("from_guacamole", None) + if not from_gua: + self.handle_sessions() super().create(request, *args, **kwargs) tasks = self.request.user.terminal.task_set.filter(is_finished=False) serializer = self.task_serializer_class(tasks, many=True) From b9d0d89f66f6b578b9112a5d64c532cd66918696 Mon Sep 17 00:00:00 2001 From: ibuler Date: Thu, 24 May 2018 13:32:20 +0800 Subject: [PATCH 051/112] =?UTF-8?q?[Update]=20=E6=9B=B4=E6=94=B9=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E5=A5=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/__init__.py | 2 +- apps/templates/_footer.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/__init__.py b/apps/__init__.py index 90767858b..c6491d9fa 100644 --- a/apps/__init__.py +++ b/apps/__init__.py @@ -2,4 +2,4 @@ # -*- coding: utf-8 -*- # -__version__ = "1.3.0" +__version__ = "1.3.1" diff --git a/apps/templates/_footer.html b/apps/templates/_footer.html index 8a723646d..10e607fa3 100644 --- a/apps/templates/_footer.html +++ b/apps/templates/_footer.html @@ -1,6 +1,6 @@
    @@ -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" %}

    {% trans 'Auto push' %}: @@ -130,8 +130,8 @@
    {% trans 'Push system user now' %}: @@ -139,8 +139,8 @@
    {% trans 'Test assets connective' %}: @@ -149,6 +149,15 @@
    {% trans 'Clear auth' %}: + + + +
    {% trans 'Change auth period' %}:#} @@ -239,6 +248,7 @@ $(document).ready(function () { if($('#id_protocol_type').text() === 'rdp'){ $('.only-ssh').addClass('hidden') } + $(".panel-body .table tr:visible:first").addClass('no-borders-tr'); $('.select2').select2() .on('select2:select', function(evt) { var data = evt.params.data; @@ -321,6 +331,13 @@ $(document).ready(function () { success: success, flash_message: false }); +}).on('click', '.btn-clear-auth', function () { + var the_url = '{% url "api-assets:system-user-auth-info" pk=system_user.id %}'; + APIUpdateAttr({ + url: the_url, + method: 'DELETE', + success_message: "{% trans 'Clear auth' %}" + " {% trans 'success' %}" + }); }) {% endblock %} diff --git a/apps/i18n/zh/LC_MESSAGES/django.mo b/apps/i18n/zh/LC_MESSAGES/django.mo index 36220e3219e13e2f33a24be9281b1ef120ef808e..6b02da8fad05df4e52dd43f5833a98e2ab222cc0 100644 GIT binary patch delta 11602 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
    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 c701df407..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 @@ -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 b764117a297c394ce044245ec712ffa3ee379e26..78705cf79573f6cf34877f0304ae523bc3b6dafc 100644 GIT binary patch delta 13328 zcmbW-2Xs}%zQ^&M5JG@Z6Cm^>y$ggMl#T&GnjlRegaDx=A%&)L=u#C4h#=BbK!ukOZ?F6JGyj>{GqY#*IXTyR@80t}Imh4o zec^zG4p(J=$0>zR7jm2nl;@OFt>c8%a-3OM94F#i_?4gIRD2Z4f3NL0Mes-+$0>^! zuqo!K>o|0En&V>_k5zEJ`85VQj@S8%f+h|Ocbr^U9%*o@n{}}Od1K6h?NI$YVqqMH zLHGie#Oat9S6O`;>RGm+?mLA6_$%gOe&;TQf>Z?5bDU5tf_bo-Ss&RHr#WgNT`?aH z#7dZeRdEp};U4UY_3JxMH=JRfLDko8;5a#P3f5wNXC?)$cq@kBKGX!?pjMiRy5R~2 z<4w$u_pvDEYv|rz0aafc)vp<9oDSCB8}(p=QT;}tH#dce6m-KZ)J`lyZRJ|j+3v#< zcnWnix3L)BMJ+tEkvp&leMg5{cwN-aHAKzR4$ELSf z)qV)|ZX83s11C`fo<>cOfnoS7s=Z)iw>{J>V^%TiqTZRNjoE+7P8-zZkE$eU$HGzbJcb(I`y>T*?2Y<3 z4M7bs-tsx9371>_d#ESgiCVxR)B=yACOD7Up)06yZ=e=<&+ZEV-~wx3VfF8$?%RSIZx`ymL#PFw!QA@%pQoS& zTtN@sLA|BL_}Ws(2B?W5P+Qj$HBe{N#Dh>1Bw#fhXZc&GcVs>4=+dz&9zuV%cB7xK5tnP^Tyeb-Mn-$8xRe2$v% z9=5}pE!>?L)57acFo6o~#BAJ#i%<*c($bx{2Wo)6sD;fj7ov7-8S07Gp%%CsHQr&= zk$!FYdCRY&#{bPrK_8!c)**i@cR?jkPh1%_Kuy%yHL|=JY9Z}WU(wxAM-_|un=lUb z`JRW`!R4s&)}hARh`QgqlY%-Pu!a-nIn;z#to;@~Lhjev{faG*CCMwJj<6MK!0xCA z>WA8qc+^o%LA?X-Vny7E?2y;FKtVTLM@{IoaknlPYQ-U_m#;YL2_HcXTnF{?wZSqt z5X<5ub0z91_Fw>hhB}hts2w@utLOYLQ&7iis3-W%*T9pub+;-Ib5dUj^`ym63$BVK zunGEOcho|AqPBPdYNFw&Cm)O2>Dj1$OE8G}omCWa;Ct4v0d>O`)WnA|5Rao4coH?x zIn+ye9rY5HeZt+Dny8Om3)Dh;Sw0N)0F$vCEnszIN=tCjO2JZB+*9iSA$^7HaQq zbr@=)l~EtJaLe0a74q(={u8h_PD9@jnb%PZxQ|+3z>|!D#k~~Nu_Nkp+ZStK5|+jl zs3-dv^^WXCO>_|Tghw$io<PR+nzT#WiSu11~dcB?;R^(RmZyo_4lZEFwe=zB1)Q-p%fq6D_aaMa5; z7WEb{zU-2XbPG%C^B>gN zov;#Wi|d-LQCrpn3t}t=<9O5pUqrn`saPEkqR#kd^Bxu?&(+1fFAVdMS42H%IC{0h z#uQ{rEPzj-lOmFv#_>$|%$75aEpLv^Ty+TzDhXV(rxurn6HL8$ME@u(+Th&q}zSQs~< zUfzSKoji*g_bRI2UDOWc_V#cGD2}SAj^P-Ap%{-EaH_R0LM?0!YT|U%lkYc=ppNPU z>PXI_`d>sXZq-2i@Ko;#$bP|-;WybIBI}1s0Cj^?NHgC z?)~AYcjs}`LOWp?Mxh>bJTi{gnMFY>eib$03e>=9R=*Rq0|!wHJcSzYHfq9Lz3k(Q zzK<{J39F&TX^xt(lePCp9cc{uKK~;qsADo}z$vIt!y?pKtuWW4ZrqOgCA0_I;RV#f zYW8-=iA42#2B%;@tN#IYR5!7sAOGeA$LaI`1iy(V;~v~kL+fYxlT4nczx(8$U|I4L zSPgHZ{x*09a4$ZN`Xw~od=s^R-RRpn%TJl-Q9FJKy?Vl16m-L1s5~&r-NF!5Ue#=X z+R9dzce8we9UNEPcv(5Ra@fMq_qd0%9Fr5l{0JXAju>xMeDi}17KSWpuo8f%( zOS5paTi+G6fcdE3go{xVZbcpKe$+emEvjEuwAU?Mvx?iO8}6F92f2As)RULDJlyi; zs0DYn`rhUcGufPEzJy`)e;xI}o4i(W&^ny6hO3tAv!|8jLoF=S@<&huRI&O9e1tp_ z_2k1)_sultnTt^4EVJDE9tFMa8!-SsvJSgZ6C6RU_#EcI-%(F|&&)O0%?p_&Q4?3h zdRW8qDAavJQ9GIF)_a}F6dF)5)2(oJn+H(~IBNNM^OAWT<7mHw>K8M_eX_CUGz_GE zzPZ?3VeM;ta{ikrXhnNaEBwMdjT#^WHNj8jU#KlCJk+f(i@L8as=le&&g_A@KiV8^ z&Qv?|J4-2O0q>v&+J?DsuhoBM^{3IdAk;)ZnZKKXv2J|`YC@0Y;bwEx{T(fT8ojEB zqM(n(P}D+3qw1%lCYoz5vHCS;nzIYdq$4o{2Em(qj``4kyIcn{vQGbMfz})z=)!#$)3m9&n|3bsv z6@{S&EQ`9K4yt1WYD*)nz7J~QG3E#}3DtkR`J%bNT#0(XG|NBsQqVx3S;d!@pT%m_ zXJQ^KG{Wsy3bmExQJ?c>7>xa}F%C!V#M`I^AH-lhg?gYY^CoH`-ajd50eMHd6BR~% z-b)Ob@c7-w0&2p5wtv%FEfub_OiZ~0cNLjEc0iEp9)>fJ*Zel^)RT8M zW6jCt>!>5xgc@j%<%duUK4G4<`pf1WRR0`F?)`a^*nbUFjEcfo0rlh!EswO0eaxX| zia8l|-^*A4SD_}@h+4=t)cAX?{y6H>bJFsklkD^VhgJ9`y8{Mcc{-Lv4baT$JD?`& zkJ_Pl48a*zztrm2p>}e=)t^RXx@h-S7-*fPPj#%A8>B zvr*&BNA1i~tKW>eZwG4JV^)6+na}Iob_FjsD*xIp0oC= zsH6D>8(_d#w_gNm0gkFV3QUbLj)y#V4<7OoK{{4Sf3YxH&IoM1>O+3-^RC9&ZueW?RYQiIye}~$!A2AGX zB0mwFJmcLw$()0}|NZZ63c6tfY9Sw*d(GqKcjk}guV%n=?*GPH$n1m~Z!T)Q1(*|8 zqIPZ#*1(O=vHx1(S?l;4>c*VUy9T2M2*D!gLH$T=VD%BG{*kDi>SXl;QRBv2KEv{b zsD5eYp65A#Rs6>~W|_aBesK7`;J!3fQ44w6j56aeKlRU{j$jsQK}*b)sQcEMo6S$m zV_pin;fz&WFmIqf=l86=>;(6TDxn5!hFW+B)Hh~-EQ<+P2IpZp+<-OlODu_c;k7fR z?7_YDDQM-9SQL9=B*tSK+=_aO@1qtPG|^o^0ep?T6o%qv)WQy<`kh3b`S++lY8Npt zUP6uc3)0W)+^3)g)yG)oDAW4mHqh)WQ~`7P89PH(UFD%t8Gz%fCYH)OV=+E}A#3{=S)W8vCyaf~UDR z6vgV~rBQEfJJee{1~pKsxdQd_tw-J8cDj3iXY?aKMzo>ekC(9q(UtN#Lf0q6dg>bL z{C}o!)K~5PqZyQ??rS2MI81(pc-(DvZs0`f^D_E}lrK^Kfw)WjLO#R#iQM#AO#NS! zSD>y}h@8|vgROP`1BsTz0P9eS#@v)k5-X{H*Xk$XaN;a=dg?Ni2U#1b@9Ip>ZyDzl zQH#*;#_X#c(_xh1!P+6X2nKkUOJM_&q(CWUy>O`33pVFrP&(P2Kq1BC` ze3RfehEtHbw}}YKx{ATbKHB{Iu)tdPDLH!MMBq0L@gUs`5VM{$PQb$z`@pho}A}tN9wWLk?HT7+Y?CTosCrKW)e)Y|<<{{dS5G5?H#5hGL>+9>m z>wA*^)IUaK`o3AMHPGCM`Dk2=1#B^iluHrYsINx^5q-(a6WLc5g*wz{U!Plf4_=_M zC}VwxA^6tc{dkoUED6MK>~8*&ImPI>6yLYHAm#MgOI{n_Bi^*O49dEWnVsF#IYi#g z%KBF7Lw>;W+m!En?S{Ej1~7rHP1H>w5{b*?qls|Jf8uM%FB9LVw5Q~Hfx6G|5>bwL zia1Z5uBq4^+Y_6K63j7|x{rw%!rMy!ph5p~^)CKML{MH!5l;Rtk&|*>qB!Lp#DnjjbC2`~;s_nW z7;Ki>?W%^Gsn5RtL-`$&NFvTE_hY=3FVbGr`fsCd73HDCL964t+;m23fBn_-0&HR@7*~C#|9q}eHgtjR}Ys$B97!e@JC!>zu znM_g?OJNtHCZTJ(i|?<>P|EwLFHJm7R3g7d3?d#QW>NPXkx5i0&w;xMU7x!+@8LbG z`x0~c+xeHV4hN`Avku4cX`()DJ5{9loLMCf|QZWx8B#2BJB_4JcyN{B^A$o+Vx(zixHa@EKx+<@0b6F`bB_Zx7T}9t+}sh$)nh<1Qlm zDr1YNV*T5hAJf76E6Ml7M?@&`3(=3zF9=;rh$!;xYm^mMQ>R}O0T_xytWRNUFF+nc zxw_@OFq*nGmK$DYJ*Dw>b4xS3&rAx9sq2DciR;$T2xF;#+wx-O2X_A>Sef|B@+)|n zKCP@@3tUDl^yB>huuflKQ!A_AYT^$0G-5vGC#~%?<{|bHAw(N>=JI2ki<9drXj}d* z<@c#8;-zP#F7!+07N5ogFBVIh(D6L}C3O1{AQkvcnxM(T&X@eZaF zsf4ahL?HL%um^JJGs7>nOU0tz*J*m5v@C`ZUlMhRSE-wTy@@|5?n3!Zw^3WJhV$7(N*u%RB>5FO?^bhM6lbjqIHzdh3 zI6g5t#?!HF3(tu7A+d3(uhp&L9h@AK=!s8=iK9mi-vB8|)c87hMy4bsd&qtFB*jF> z#|?@~9OsEjVWPO?*yyO_*!Vb4mC;cnVh3q-Pt=GJ>YtcY!xI}9JtAcgqk5tSjf{

    DvE!OSt&5n*qOpYCFd!0J4`Kmme9~-12P4#cl)2lPe-lpiNgxF-( zmc2xH9eEehpKUS9FHiK)nCRi2#FP;+sry=n=huOcOc}{K z;)Wy-O}*N3U=Zi;OVZo4S{{%;IwdhSd0h5$q@RCcVZIU%zuCTbFNrrSY4Eu8lQ;cBW1cV%o}?MWRsvTbg?H``ZV-?1cp p>&WK=f-}-)W=vb_t~EV8F=y~YFQU7?%#T)H`Y@eaQX5X#|6hC5COZHC delta 11582 zcmZA73w+PjAII_UF2-!O*_h=z7B&sJ%&nO_Vc1wMxsACqhS`Mt+?9KVrXoT~7k`#p zx!-b0p^FldZYV`1g#2Ic-}mG3=+XDlXU}s!=X}pO-}C)`f4{9dGtc+leIL(-aQ~$a zM+slYDT_P99On?_UKN#foUC}qnS-No3f{v{eH`c6>PS7crsI^v%8xrv1$+V%u_rdh ze2m2}%m)}iJ+_v2K95tALSYigsD?DNCx%k*kA64?wZI$<$2=^8uVWe9h(UPV@@KFT z^^2(U{AxRnKSrbGtBhfe$8oAtC_y3#i((hE4;H6B6t$3vSPbW494^N~cmQkQQPcu% zV+8uwar;N1Ca!|&{}={iEev6PCy7ENc0dggYjDJkQ!+LM`-lRKHCah|LG8?C)GhL_>o}#cG-{_4&{K*+A_YyHh8j5CIt)jxd<<$Qa#0gKkL58Bxt-2t z)PUbv`&HDH{)t-n-_~9v!QJ{$)HtOQ*nbUNkwg^MLEYyTnTZ4NL;qVD~8Y=~1) z3-|zaZ}+2a*)deVv&eJme22QAhbxLNeRrS;)V(T;+K~pR3EN>Q?1tL1QK*TY zK}|3l)o&Sw;~LcYTdjTsHR0Em{|R-$cTfxP_&0D@7>t^r9BPZIq6UsfU1>wBH%ATF z33X*XQ3H-Jb5Z@Lp%yY1HPH&x&aJ};+=ARPk8_lQ20UpU&bbZFFQ^m$Kn-{ob)r8v zTnmgs?}AYasEW~88})E@LGQzhdNy)VJ2x3M&O8j#`@f2UCU_gG;TEf3L_NhJDn0fG6CoFM-Gcu?j9tWdHfDadwiBdr+U* z`^_IvA23DuCeefqu`Lco?L+};g7;Ai_z-vCr>KR@PjV+-j5r-o{6ET1!r4*B5EPCJQPY& zSctk;>o5|xpx*C~Py>FA8t^h|z+X`V+(Gs8ZR+NWn`KcGRzK?5@-TPx$8PB8o`89JVD1q9UGN=VsMLlfQQ5Tee8m|>{&(t>5+j9uD z!1JgD|B98+X@Sh|#8A*ywZ<~o)f|JGaDll5HQ`IBD_w(H*lw(fr|?m{gWBTqE#3Yx zW;|+P38-7v0zJC&P876&Zm0Kjr0zr?5U8`OD? zTD!KzLe#sX7T5>t;8<&aqc!`l*KI3_cszmS@Nd+WMYVCCg>o1`y&~!gV^IrBK;437 zs4Gk}`=GXZh}Cn)}D&GpgyQukb&GK$1{n79=d&~r}aE);G0+&{o1+<3NlNh78-}z(uS7r zh+05zEP|tP6i&d=coj8XuXb+x0OZzqoJi9@Gloz@oSpwG+ot1DrSd zE2t|AZ|@FV3e`UvwVF}t0~mxSu@0WY z$1p6}z2}K$Yt(ru7>xZ;J2?{d5Kcnv%rtW@hU)!aLO~tZqIY5pq<#RkpcANP;37uj z@2D$|=-@uQQK(x|(`4DnP=gdv0TXGib zqi-kfH#S1uifq(ECSg&Wid%6W>K3+0ac@;GRKMZqi&^N0V^i4w5DK{@w8gVf_ii!j z-YrMnyLV8Z4+l_Jb^(L&I%BDRb;bM(b)w%>?r$zdk*`Ka0Xz8c0OK>XkL$*( zhri(=@?*O56|MKb0pA?qG+f6D=-1QzJ0J$zQ16IkahX|wn)oE@yfaq6YTiI?@om%v z`Sx=Ahob6{SQ2AY*Zbel8d{^au8Y+(te$1{DX59(n@h}>&DT&9ylHMlE%1Q(1!`ee zP_OwP=+S^>d-DWi3~GSpsC(TB^^jzs`i(Znn;umES!SNO3UwjxSbdk(kD(TD*7D!? zX8$$74NLrE2K8|VjzT@fl~GrcWc5^QA7=SntIt6#^hK+$wEA19^EX@m5LTpqx)1wb zp2D9bbYetb*V1N1)BHA2Mf8pkb&9Mw>HG=f7z6wW#y9S$?0Z$NAV2U!w-NY~D3P`nv;F zL@l5OYM><42g;L{PqBPDdKZLRz-V)_IoHg`aJ~QQEV11@gc{(q)xWa(kEpld8fqbT zEgzKOP84odK%F0N)-fBQ&TD4%RP?_8-BqArAeO-~<^t3}8_Z3pe%nz49kTl8)_w`A zlD}g0;sf0Cqfj5=6|f@KLXFb}z3+cI1$}u8Ms4kQ)Wp+J9iO-QGIIrLz_qCUTT%V? zqHf^{%U?u|bJe_I-bVF*Fu>mbV7~H{c*LxNy23hEZ-E*p#p>OxJ^-tcACCGKTxR*z zsGVGodc6;##{UlW3(R%YPE;Gj{nv_<2e}>kqONF!nS)x$6b!&csEJ-gz3;D~FMeR| z#v0W3nb)x?^$LSs(~*?38UwJ1XNWs-C@N7Fmt&08cbNyV8TsQ@FE-TeUjntjGN=oA z%<@U7D{f_WwtQc!53;&vECro70d-~b&3x;y1~t$IbDMe4JcZhc3#bdYW%Yloz0@#w z{6|sk^-<#`VG(`*x3@%^+0PtlPDCy6Ijn{+qaPl|Ks<(eEk8r`yM%g}Z(?N(81B~N zF_wB`)R)^J4AA>Ofr3^v)tlhYZF8yl3hMiM4XWP`%OAG-3DiQ)n%`UgSMx4<@AU}x z{7|zjhBLntM?ou2R02C#hjcU3oM6sI^;?3v_ivyk*oIojZVbjFmj4{}Hk`BiZSw(o z-~WJ2cfev8L&s8Oe4pax!H`JJe74wxq~l=^w|8fu*T9txTu zGRyrfwjAoj)#kgX_76}4>_`0`aN61fN4pD%#A@W@Py?r-&dW5j&55Y-r_D=w}Thtv(es z(E_WlL=E^B>Iyd_ABN6xtJfXt<~yJkHVD-}3$=h;bB6hXSML8xOT1-nHxFTBPCRXf zWxE4*L=E^97Q+6h9UFr2I2N_QRj7VDPzyP1p0NC9SW@r*w-o&GmNnc%oe((A-KsFu zKryI+AGdm2t9Qk4@}taY=2Fyo>&-2w-w*bqo|UWUQHPQ_ZpTVyO$;HQh`I&sQ48v6 z_D7vJ)XXubn~PBWS6F?mxe4`p@3!`fIlTY6qMxjTlj~kdF$^OgjTNvK>h(&+N|=S! zF%R{Dvkx`SdDKq)g<5#vc=z9sJc3VBe;ixkGpJ`|&v<+PkCM<8oy2@Rk0mgNzZ{jH zi@KtG)IEO{^(C|pgYZq%fLl=g_MjGU*!;r$5xomUjT`8h;C75eHB>=0G&EbAUCeYd z)0}{D^q+0@O{j5pTm6)I0kxo?Q476mdJ0W+R~%|an&nUnc@#BZEz|%lQ6H^osDXN; zc4RQ>mSy5(oQyjEzFBmVdwwZwM7}CAuE*(5K?9Am4jywMmL&hG)wiJf9YPKKiFwZ2 zuUP$#)dQY&&yPecJl;%1jgySQ`u^`qL06bz9dfM0EYv+-Wc4Med%F^~fOY0(%kMD{ zqb4|E^)vVw^$VznwkX@9^BYLL|E(zKq3et~@n_UTH_-=myhQM&k(BUc!8G$q=rz)_Rj2RNVbe8rFT#B(H{CCX6Nhs3Kyc|u2X7w0-^ zVgDl*5iM47V3S? zr0i>L`X5wugi-&D*h|zP8W1}EHvO!ha;M3ChwD_~h$22A*BzHDq4{rn3+|7{VLctT z*P?6%lR->nX}V6Vuhm@wSWe1>PjS zqpctA#QM7ban?a>AQFgsH0roW^rHMSW)V4*i(o$SIOY4O<2vQ9h!jFcY3xocq}-VB zp?r)eP@^52Fi=nAw=_IF+EQLb)X2LLAF;T)zx$6zzaHe1PJGzUTubgl%4_hyM;~%W ziNF5Spbym$VlQ!vIA!M!#d?Gu$;;%Uu>`^4abn$q^D6cy^Cmult?^OhcO+*50~=neYi_oty0lC>0j;gCF(t%pghyc zVj1x_QO5czrz4yCRiZ2LJoR6QP5C$1nIP9wg2Yi-`-w03wIjK|5b(-lHAmuPI$3exzIhR}*Ck9c9Vsir>XH zI7avXuv$1mS>cB?d_s9Q@g-$nayn|dIPa5NOguvUTjEb*JoS0RHOl|PWDFx79<8l# z75!+}@j5<3%+qRgoTqZfEjp)g0Wpi*k2sf@LUbX*$&JG_JdQeUP##GfCZ-ZPRuErP z-iNc5;P4|(So=4o=OoDq#9HDV;y4X`QO6<5J&5OtgTyX!x9}rxD?iwsnbg}+ypLyy z->j`7MiT+#w25_z7l=m0U2>I(blr`fB<@hzi8>0~mVZuexSMi*$6`b`tBaqB3?iKV zxwxPHI({Jhtz3fg_rw+ISwv~d!w4P8-ahRAYgA&WoWKS|m@R;!_xPNjn~6~ROmb7s zUzG1!d6X%tk^g`=`mfv;>N;LA`%vyh{HeO`{{jmC5Tl3+#B?H@{8NNKi}?eC$vr%p zQNCdHRrrpTkI|tr(UAI*hn?|DBAB>DzAq6;R3$bOo>#16TRcOQBfg-a7Ezp-PYfmZ zJqECtH&Dj_Gl}vZEAPfQ!iRo?$@io@$J%sGWy;0zS>l|V_c%+btRx)kSOp`f7Q;t~ zF_ceY9-(6(KEUn7(?mT&M=9cM+7gJ5y&1l2DDS7dgSbXH25;k3YoDVR^#+yRL?p4y zry#OMynn&y+QoeH*3~UnFr!|YZ^5|+or3b(v|N#Qy=B*e{jIWn^4hhD%bVM#d%?{% zOZ^L8PF`HB;K`>0d;$}y*G`D8)u2(Wf^I#J`xi7#U*nTkq<^)7yo^}ig1rNu3(D&; odU@Xc(OnAO8?(|UZ(w#@-fP)S3T|YN^Dh|tjDK)m-pqsl2Q7;xvj6}9 diff --git a/apps/i18n/zh/LC_MESSAGES/django.po b/apps/i18n/zh/LC_MESSAGES/django.po index 31654aa11..eb42e1bef 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-05 17:03+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: ibuler \n" "Language-Team: Jumpserver team\n" @@ -21,15 +21,15 @@ msgstr "" msgid "New node {}" msgstr "新节点 {}" -#: assets/api/node.py:242 +#: assets/api/node.py:241 msgid "更新节点资产硬件信息: {}" msgstr "" -#: assets/api/node.py:255 +#: assets/api/node.py:254 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:74 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:79 #: 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:70 #: 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:66 #: 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:229 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,8 +129,8 @@ 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 @@ -171,10 +171,10 @@ 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" @@ -202,11 +202,11 @@ msgid "" "than 2 system user" msgstr "高优先级的系统用户将会作为默认登录用户" -#: assets/models/asset.py:61 assets/models/domain.py:43 +#: assets/models/asset.py:62 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:65 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:68 assets/templates/assets/asset_detail.html:97 msgid "Platform" msgstr "系统平台" -#: assets/models/asset.py:67 assets/models/domain.py:48 +#: assets/models/asset.py:75 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:84 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:86 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:90 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:92 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:94 assets/templates/assets/asset_detail.html:109 msgid "Serial number" msgstr "序列号" -#: assets/models/asset.py:81 +#: assets/models/asset.py:97 msgid "CPU model" msgstr "CPU型号" -#: assets/models/asset.py:82 +#: assets/models/asset.py:98 msgid "CPU count" msgstr "CPU数量" -#: assets/models/asset.py:83 +#: assets/models/asset.py:99 msgid "CPU cores" msgstr "CPU核数" -#: assets/models/asset.py:84 assets/templates/assets/asset_detail.html:89 +#: assets/models/asset.py:101 assets/templates/assets/asset_detail.html:89 msgid "Memory" msgstr "内存" -#: assets/models/asset.py:85 +#: assets/models/asset.py:103 msgid "Disk total" msgstr "硬盘大小" -#: assets/models/asset.py:86 +#: assets/models/asset.py:105 msgid "Disk info" msgstr "硬盘信息" -#: assets/models/asset.py:88 assets/templates/assets/asset_detail.html:101 +#: assets/models/asset.py:108 assets/templates/assets/asset_detail.html:101 msgid "OS" msgstr "操作系统" -#: assets/models/asset.py:89 +#: assets/models/asset.py:110 msgid "OS version" msgstr "系统版本" -#: assets/models/asset.py:90 +#: assets/models/asset.py:112 msgid "OS arch" msgstr "系统架构" -#: assets/models/asset.py:91 +#: assets/models/asset.py:114 msgid "Hostname raw" msgstr "主机名原始" -#: assets/models/asset.py:93 assets/templates/assets/asset_create.html:33 +#: assets/models/asset.py:118 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:120 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 @@ -316,7 +316,7 @@ msgstr "标签管理" msgid "Created by" msgstr "创建者" -#: assets/models/asset.py:95 assets/models/cluster.py:26 +#: assets/models/asset.py:123 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 @@ -329,7 +329,7 @@ msgstr "创建者" msgid "Date created" msgstr "创建日期" -#: assets/models/asset.py:96 assets/models/base.py:26 +#: assets/models/asset.py:125 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 @@ -346,7 +346,7 @@ msgstr "创建日期" #: users/models/user.py:75 users/templates/users/user_detail.html:119 #: 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:126 msgid "Comment" msgstr "备注" @@ -434,11 +434,11 @@ msgstr "默认资产组" #: terminal/templates/terminal/session_list.html:71 users/forms.py:281 #: users/models/user.py:30 users/models/user.py:318 #: 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:360 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:184 #: 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,15 +651,16 @@ 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 @@ -666,7 +668,7 @@ msgstr "重置" #: 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_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 @@ -743,15 +745,15 @@ msgstr "测试" #: 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_profile.html:147 +#: users/templates/users/user_profile.html:176 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 @@ -782,7 +784,7 @@ 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:639 #: 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 @@ -792,7 +794,7 @@ msgstr "选择节点" #: 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_profile.html:218 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 @@ -843,19 +845,19 @@ 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_profile.html:100 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_profile.html:138 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 @@ -885,97 +887,97 @@ msgstr "刷新" 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 +#: assets/templates/assets/asset_list.html:100 #: users/templates/users/user_list.html:37 msgid "Delete selected" msgstr "批量删除" -#: assets/templates/assets/asset_list.html:100 +#: assets/templates/assets/asset_list.html:101 #: users/templates/users/user_list.html:38 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 +#: assets/templates/assets/asset_list.html:103 #: users/templates/users/user_list.html:39 msgid "Deactive selected" msgstr "禁用所选" -#: assets/templates/assets/asset_list.html:103 +#: assets/templates/assets/asset_list.html:104 #: users/templates/users/user_list.html:40 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:634 #: assets/templates/assets/system_user_list.html:133 #: users/templates/users/user_detail.html:357 #: users/templates/users/user_detail.html:382 @@ -984,20 +986,20 @@ msgstr "存在资产,不能删除" msgid "Are you sure?" msgstr "你确认吗?" -#: assets/templates/assets/asset_list.html:632 +#: assets/templates/assets/asset_list.html:635 msgid "This will delete the selected assets !!!" msgstr "删除选择资产" -#: assets/templates/assets/asset_list.html:640 +#: assets/templates/assets/asset_list.html:643 msgid "Asset Deleted." msgstr "已被删除" -#: assets/templates/assets/asset_list.html:641 -#: assets/templates/assets/asset_list.html:646 +#: assets/templates/assets/asset_list.html:644 +#: assets/templates/assets/asset_list.html:649 msgid "Asset Delete" msgstr "删除" -#: assets/templates/assets/asset_list.html:645 +#: assets/templates/assets/asset_list.html:648 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 "测试连接" @@ -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:190 +msgid "Must contain capital letters" +msgstr "必须包含大写字母" + +#: common/forms.py:192 +msgid "" +"After opening, the user password changes and resets must contain uppercase " +"letters" +msgstr "开启后,用户密码修改、重置必须包含大写字母" + +#: common/forms.py:198 +msgid "Must contain lowercase letters" +msgstr "必须包含小写字母" + +#: common/forms.py:199 +msgid "" +"After opening, the user password changes and resets must contain lowercase " +"letters" +msgstr "开启后,用户密码修改、重置必须包含小写字母" + +#: common/forms.py:205 +msgid "Must contain numeric characters" +msgstr "必须包含数字字符" + +#: common/forms.py:206 +msgid "" +"After opening, the user password changes and resets must contain numeric " +"characters" +msgstr "开启后,用户密码修改、重置必须包含数字字符" + +#: common/forms.py:212 +msgid "Must contain special characters" +msgstr "必须包含特殊字符" + +#: common/forms.py:213 +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 "更新设置成功, 请手动重启程序" @@ -1754,7 +1831,7 @@ 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/templates/users/user_profile.html:108 msgid "Date expired" 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:342 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:284 users/views/login.py:342 users/views/user.py:65 +#: users/views/user.py:80 users/views/user.py:102 users/views/user.py:173 +#: users/views/user.py:328 users/views/user.py:379 users/views/user.py:414 msgid "Users" msgstr "用户管理" -#: templates/_nav.html:13 users/views/user.py:65 +#: templates/_nav.html:13 users/views/user.py:66 msgid "User list" msgstr "用户列表" @@ -2356,7 +2433,7 @@ msgstr "复制你的公钥到这里" #: users/forms.py:231 users/models/user.py:72 #: 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 @@ -2396,13 +2473,13 @@ 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/templates/users/user_profile.html:162 msgid "Disable" msgstr "禁用" #: users/models/user.py:35 users/templates/users/user_profile.html:90 -#: users/templates/users/user_profile.html:163 +#: users/templates/users/user_profile.html:166 msgid "Enable" msgstr "启用" @@ -2539,22 +2616,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:348 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:80 msgid "Create user" msgstr "创建用户" @@ -2563,7 +2652,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:174 msgid "User detail" msgstr "用户详情" @@ -2583,7 +2672,7 @@ msgid "Disabled" msgstr "禁用" #: users/templates/users/user_detail.html:115 -#: users/templates/users/user_profile.html:101 +#: users/templates/users/user_profile.html:104 msgid "Last login" msgstr "最后登录" @@ -2631,14 +2720,14 @@ 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_profile.html:207 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_profile.html:208 +#: users/templates/users/user_profile.html:213 msgid "User SSH public key update" msgstr "ssh密钥" @@ -2694,28 +2783,32 @@ msgstr "删除" 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:112 users/views/user.py:203 +#: users/views/user.py:257 msgid "User groups" msgstr "用户组" -#: users/templates/users/user_profile.html:141 +#: users/templates/users/user_profile.html:144 msgid "Update password" msgstr "更改密码" -#: users/templates/users/user_profile.html:149 +#: users/templates/users/user_profile.html:152 msgid "Update MFA settings" msgstr "更改MFA设置" -#: users/templates/users/user_profile.html:170 +#: users/templates/users/user_profile.html:173 msgid "Update SSH public key" msgstr "更改SSH密钥" -#: users/templates/users/user_profile.html:178 +#: users/templates/users/user_profile.html:181 msgid "Reset public key and download" msgstr "重置并下载SSH密钥" -#: users/templates/users/user_profile.html:208 +#: users/templates/users/user_profile.html:211 msgid "Failed to update SSH public key." msgstr "更新密钥失败" @@ -2735,15 +2828,15 @@ msgstr "更新密钥" msgid "Or reset by server" msgstr "或者重置并下载密钥" -#: users/templates/users/user_update.html:4 users/views/user.py:99 +#: users/templates/users/user_update.html:4 users/views/user.py:103 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 +2881,7 @@ msgstr "" "
    \n" " " -#: users/utils.py:78 +#: users/utils.py:82 #, python-format msgid "" "\n" @@ -2832,11 +2925,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 +2954,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 +2982,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:135 users/views/user.py:499 users/views/user.py:524 msgid "MFA code invalid" msgstr "MFA码认证失败" -#: users/views/login.py:151 +#: users/views/login.py:161 msgid "Logout success" msgstr "退出登录成功" -#: users/views/login.py:152 +#: users/views/login.py:162 msgid "Logout success, return login page" msgstr "退出登录成功,返回到登录页面" -#: users/views/login.py:168 +#: users/views/login.py:178 msgid "Email address invalid, please input again" msgstr "邮箱地址错误,重新输入" -#: users/views/login.py:181 +#: users/views/login.py:191 msgid "Send reset password message" msgstr "发送重置密码邮件" -#: users/views/login.py:182 +#: users/views/login.py:192 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:205 msgid "Reset password success" msgstr "重置密码成功" -#: users/views/login.py:196 +#: users/views/login.py:206 msgid "Reset password success, return to login page" msgstr "重置密码成功,返回到登录页面" -#: users/views/login.py:213 users/views/login.py:226 +#: users/views/login.py:227 users/views/login.py:240 msgid "Token invalid or expired" msgstr "Token错误或失效" -#: users/views/login.py:222 +#: users/views/login.py:236 msgid "Password not same" msgstr "密码不一致" -#: users/views/login.py:263 +#: users/views/login.py:246 users/views/user.py:115 users/views/user.py:397 +msgid "* Your password does not meet the requirements" +msgstr "* 您的密码不符合要求" + +#: users/views/login.py:284 msgid "First login" msgstr "首次登陆" -#: users/views/login.py:322 +#: users/views/login.py:343 msgid "Login log list" msgstr "登录日志" -#: users/views/user.py:109 +#: users/views/user.py:127 msgid "Bulk update user success" msgstr "批量更新用户成功" -#: users/views/user.py:214 +#: users/views/user.py:232 msgid "Invalid file." msgstr "文件不合法" -#: users/views/user.py:311 +#: users/views/user.py:329 msgid "User granted assets" msgstr "用户授权资产" -#: users/views/user.py:340 +#: users/views/user.py:361 msgid "Profile setting" msgstr "个人信息设置" -#: users/views/user.py:358 +#: users/views/user.py:380 msgid "Password update" msgstr "密码更新" -#: users/views/user.py:380 +#: users/views/user.py:415 msgid "Public key update" msgstr "密钥更新" -#: users/views/user.py:421 +#: users/views/user.py:456 msgid "Password invalid" msgstr "用户名或密码无效" -#: users/views/user.py:515 +#: users/views/user.py:550 msgid "MFA enable success" msgstr "MFA 绑定成功" -#: users/views/user.py:516 +#: users/views/user.py:551 msgid "MFA enable success, return login page" msgstr "MFA 绑定成功,返回到登录页面" -#: users/views/user.py:518 +#: users/views/user.py:553 msgid "MFA disable success" msgstr "MFA 解绑成功" -#: users/views/user.py:519 +#: users/views/user.py:554 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/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 = "
    "; + + if (options.ui.showVerdictsInsideProgressBar) { + progressbar += ""; + } + + progressbar += "
    "; + + 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, "", + options.ui.viewports.verdict); + }; + + ui.initErrorList = function (options, $el) { + ui.initHelper(options, $el, "
      ", + options.ui.viewports.errors); + }; + + ui.initScore = function (options, $el) { + ui.initHelper(options, $el, "", + 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 += "
    • " + err + "
    • "; + }); + } + $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 = "
      " + verdictText + + "
      "; + 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 diff --git a/apps/templates/_base_create_update.html b/apps/templates/_base_create_update.html index a38a6133d..ec14da79b 100644 --- a/apps/templates/_base_create_update.html +++ b/apps/templates/_base_create_update.html @@ -5,6 +5,7 @@ {% block custom_head_css_js %} + {% block custom_head_css_js_create %} {% endblock %} {% endblock %} diff --git a/apps/users/forms.py b/apps/users/forms.py index f777e0dd7..06c544383 100644 --- a/apps/users/forms.py +++ b/apps/users/forms.py @@ -72,7 +72,7 @@ class UserCreateUpdateForm(forms.ModelForm): 'data-placeholder': _('Join user groups') } ), - 'otp_level': forms.RadioSelect() + 'otp_level': forms.RadioSelect(), } def clean_public_key(self): diff --git a/apps/users/templates/users/_user.html b/apps/users/templates/users/_user.html index f973f3344..5090e825f 100644 --- a/apps/users/templates/users/_user.html +++ b/apps/users/templates/users/_user.html @@ -48,6 +48,7 @@
      + {% endblock %} {% block custom_foot_js %} diff --git a/apps/users/templates/users/reset_password.html b/apps/users/templates/users/reset_password.html index 0bab32809..3d669a1e5 100644 --- a/apps/users/templates/users/reset_password.html +++ b/apps/users/templates/users/reset_password.html @@ -11,6 +11,7 @@ {% include '_head_css_js.html' %} + @@ -49,10 +50,20 @@

      {{ errors }}

      {% endif %}
      - + + {# 密码popover #} +
      + +
      - +
      @@ -79,4 +90,33 @@ + diff --git a/apps/users/templates/users/user_password_update.html b/apps/users/templates/users/user_password_update.html index 3dbe727a7..50c428ee6 100644 --- a/apps/users/templates/users/user_password_update.html +++ b/apps/users/templates/users/user_password_update.html @@ -7,6 +7,8 @@ + +