Frontend for password strength

This commit is contained in:
Ozzie Isaacs 2022-06-16 08:33:39 +02:00
parent b206b7a5d8
commit 73d48e4ac1
30 changed files with 1683 additions and 12 deletions

View File

@ -98,10 +98,6 @@ updater_thread = Updater()
def create_app(): def create_app():
lm.login_view = 'web.login'
lm.anonymous_user = ub.Anonymous
lm.session_protection = 'strong'
if csrf: if csrf:
csrf.init_app(app) csrf.init_app(app)
@ -112,6 +108,10 @@ def create_app():
# pylint: disable=no-member # pylint: disable=no-member
config_sql.load_configuration(config, ub.session, cli_param) config_sql.load_configuration(config, ub.session, cli_param)
lm.login_view = 'web.login'
lm.anonymous_user = ub.Anonymous
lm.session_protection = 'strong' if config.config_session == 1 else "basic"
db.CalibreDB.update_config(config) db.CalibreDB.update_config(config)
db.CalibreDB.setup_db(config.config_calibre_dir, cli_param.settings_path) db.CalibreDB.setup_db(config.config_calibre_dir, cli_param.settings_path)
calibre_db.init_db() calibre_db.init_db()

View File

@ -1765,10 +1765,21 @@ def _configuration_update_helper():
if config.config_login_type == constants.LOGIN_OAUTH: if config.config_login_type == constants.LOGIN_OAUTH:
reboot_required |= _configuration_oauth_helper(to_save) reboot_required |= _configuration_oauth_helper(to_save)
# logfile configuration
reboot, message = _configuration_logfile_helper(to_save) reboot, message = _configuration_logfile_helper(to_save)
if message: if message:
return message return message
reboot_required |= reboot reboot_required |= reboot
# security configuration
_config_checkbox(to_save, "config_password_policy")
_config_checkbox(to_save, "config_password_number")
_config_checkbox(to_save, "config_password_lower")
_config_checkbox(to_save, "config_password_upper")
_config_checkbox(to_save, "config_password_special")
_config_int(to_save, "config_password_min_length")
_config_int(to_save, "config_session")
# Rarfile Content configuration # Rarfile Content configuration
_config_string(to_save, "config_rarfile_location") _config_string(to_save, "config_rarfile_location")
if "config_rarfile_location" in to_save: if "config_rarfile_location" in to_save:

View File

@ -75,7 +75,6 @@ class _Settings(_Base):
config_authors_max = Column(Integer, default=0) config_authors_max = Column(Integer, default=0)
config_read_column = Column(Integer, default=0) config_read_column = Column(Integer, default=0)
config_title_regex = Column(String, default=r'^(A|The|An|Der|Die|Das|Den|Ein|Eine|Einen|Dem|Des|Einem|Eines)\s+') config_title_regex = Column(String, default=r'^(A|The|An|Der|Die|Das|Den|Ein|Eine|Einen|Dem|Des|Einem|Eines)\s+')
# config_mature_content_tags = Column(String, default='')
config_theme = Column(Integer, default=0) config_theme = Column(Integer, default=0)
config_log_level = Column(SmallInteger, default=logger.DEFAULT_LOG_LEVEL) config_log_level = Column(SmallInteger, default=logger.DEFAULT_LOG_LEVEL)
@ -148,6 +147,14 @@ class _Settings(_Base):
schedule_generate_series_covers = Column(Boolean, default=False) schedule_generate_series_covers = Column(Boolean, default=False)
schedule_reconnect = Column(Boolean, default=False) schedule_reconnect = Column(Boolean, default=False)
config_password_policy = Column(Boolean, default=True)
config_password_min_length = Column(Integer, default=8)
config_password_number = Column(Boolean, default=True)
config_password_lower = Column(Boolean, default=True)
config_password_upper = Column(Boolean, default=True)
config_password_special = Column(Boolean, default=True)
config_session = Column(Integer, default=1)
def __repr__(self): def __repr__(self):
return self.__class__.__name__ return self.__class__.__name__

View File

@ -433,3 +433,7 @@ div.log {
#detailcover:-moz-full-screen { cursor:zoom-out; border: 0; } #detailcover:-moz-full-screen { cursor:zoom-out; border: 0; }
#detailcover:-ms-fullscreen { cursor:zoom-out; border: 0; } #detailcover:-ms-fullscreen { cursor:zoom-out; border: 0; }
#detailcover:fullscreen { cursor:zoom-out; border: 0; } #detailcover:fullscreen { cursor:zoom-out; border: 0; }
.error-list {
margin-top: 5px;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,17 @@
{
"wordMinLength": "كلمة المرور قصيرة جداً",
"wordMaxLength": "كلمة المرور طويلة جدا",
"wordInvalidChar": "تحتوي كلمة المرور على رموز غير صالحة",
"wordNotEmail": "لا تستخدم بريدك الإلكتروني ككلمة مرور",
"wordSimilarToUsername": "لا يمكن ان تحتوي كلمة المرور على إسم المستخدم",
"wordTwoCharacterClasses": "إستخدم فئات أحرف مختلفة",
"wordRepetitions": "تكرارات كثيرة",
"wordSequences": "تحتوي كلمة المرور على أنماط متتابعة",
"errorList": "الأخطاء:",
"veryWeak": "ضعيفة جداً",
"weak": "ضعيفة",
"normal": "عادية",
"medium": "متوسطة",
"strong": "قوية",
"veryStrong": "قوية جداً"
}

View File

@ -0,0 +1,17 @@
{
"wordMinLength": "Vaše heslo je příliš krátké",
"wordMaxLength": "Vaše heslo je příliš dlouhé",
"wordInvalidChar": "Vaše heslo obsahuje neplatný znak",
"wordNotEmail": "Nepoužívejte Váš email jako Vaše heslo",
"wordSimilarToUsername": "Vaše heslo nesmí obsahovat přihlašovací jméno",
"wordTwoCharacterClasses": "Použijte různé druhy znaků",
"wordRepetitions": "Příliš mnoho opakování",
"wordSequences": "Vaše heslo obsahuje postupnost",
"errorList": "Chyby:",
"veryWeak": "Velmi slabé",
"weak": "Slabé",
"normal": "Normální",
"medium": "Středně silné",
"strong": "Silné",
"veryStrong": "Velmi silné"
}

View File

@ -0,0 +1,21 @@
{
"wordMinLength": "Das Passwort ist zu kurz",
"wordMaxLength": "Das Passwort ist zu lang",
"wordInvalidChar": "Das Passwort enthält ein ungültiges Zeichen",
"wordNotEmail": "Das Passwort darf die E-Mail Adresse nicht enthalten",
"wordSimilarToUsername": "Das Passwort darf den Benutzernamen nicht enthalten",
"wordTwoCharacterClasses": "Bitte Buchstaben und Ziffern verwenden",
"wordRepetitions": "Zu viele Wiederholungen",
"wordSequences": "Das Passwort enthält Buchstabensequenzen",
"wordLowercase": "Bitte mindestens einen Kleinbuchstaben verwenden",
"wordUppercase": "Bitte mindestens einen Großbuchstaben verwenden",
"wordOneNumber": "Bitte mindestens eine Ziffern verwenden",
"wordOneSpecialChar": "Bitte mindestens ein Sonderzeichen verwenden",
"errorList": "Fehler:",
"veryWeak": "Sehr schwach",
"weak": "Schwach",
"normal": "Normal",
"medium": "Mittel",
"strong": "Stark",
"veryStrong": "Sehr stark"
}

View File

@ -0,0 +1,17 @@
{
"wordMinLength": "Ο κωδικός πρόσβασης δεν έχει τον ελάχιστο αριθμό χαρακτήρων",
"wordMaxLength": "Ο κωδικός πρόσβασής σας είναι πολύ μεγάλος",
"wordInvalidChar": "Ο κωδικός πρόσβασής σας περιέχει έναν μη έγκυρο χαρακτήρα",
"wordNotEmail": "Μη χρησιμοποιείτε το email ως κωδικό",
"wordSimilarToUsername": "Ο κωδικός πρόσβασης δεν πρέπει να περιέχει το username",
"wordTwoCharacterClasses": "Χρησιμοποιήστε διαφορετικές κλάσεις χαρακτήρων",
"wordRepetitions": "Πολλές επαναλήψεις",
"wordSequences": "Ο κωδικός πρόσβασης περιέχει επαναλήψεις",
"errorList": "Σφάλματα:",
"veryWeak": "Πολύ Αδύνατος",
"weak": "Αδύνατος",
"normal": "Κανονικός",
"medium": "Μέτριος",
"strong": "Δυνατός",
"veryStrong": "Πολύ Δυνατός"
}

View File

@ -0,0 +1,21 @@
{
"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",
"wordLowercase": "Use at least one lowercase character",
"wordUppercase": "Use at least one uppercase character",
"wordOneNumber": "Use at least one number",
"wordOneSpecialChar": "Use at least one special character",
"errorList": "Errors:",
"veryWeak": "Very Weak",
"weak": "Weak",
"normal": "Normal",
"medium": "Medium",
"strong": "Strong",
"veryStrong": "Very Strong"
}

View File

@ -0,0 +1,17 @@
{
"wordMinLength": "Via pasvorto estas tro mallonga",
"wordMaxLength": "Via pasvorto estas tro longa",
"wordInvalidChar": "Via pasvorto enhavas nevalidan karaktero",
"wordNotEmail": "Ne uzu vian retpoŝtadreson kiel la pasvorton",
"wordSimilarToUsername": "Via pasvorto enhavas vian uzanto-nomon",
"wordTwoCharacterClasses": "Uzu signojn de diversaj tipoj (ekz., literoj kaj ciferoj)",
"wordRepetitions": "Tro multaj ripetiĝantaj signoj",
"wordSequences": "Via pasvorto enhavas simplan sinsekvon de signoj",
"errorList": "Eraroj:",
"veryWeak": "Trosimpla",
"weak": "Malforta",
"normal": "Mezforta",
"medium": "Akceptebla",
"strong": "Forta",
"veryStrong": "Elstare Forta"
}

View File

@ -0,0 +1,17 @@
{
"wordMinLength": "Tu contraseña es demasiado corta",
"wordMaxLength": "Tu contraseña es muy larga",
"wordInvalidChar": "Tu contraseña contiene un carácter no válido",
"wordNotEmail": "No uses tu email como tu contraseña",
"wordSimilarToUsername": "Tu contraseña no puede contener tu nombre de usuario",
"wordTwoCharacterClasses": "Mezcla diferentes clases de caracteres",
"wordRepetitions": "Demasiadas repeticiones",
"wordSequences": "Tu contraseña contiene secuencias",
"errorList": "Errores:",
"veryWeak": "Muy Débil",
"weak": "Débil",
"normal": "Normal",
"medium": "Media",
"strong": "Fuerte",
"veryStrong": "Muy Fuerte"
}

View File

@ -0,0 +1,17 @@
{
"wordMinLength": "Votre mot de passe est trop court",
"wordMaxLength": "Votre mot de passe est trop long",
"wordInvalidChar": "Votre mot de passe contient un caractère invalide",
"wordNotEmail": "Ne pas utiliser votre adresse e-mail comme mot de passe",
"wordSimilarToUsername": "Votre mot de passe ne peut pas contenir votre nom d'utilisateur",
"wordTwoCharacterClasses": "Utilisez différents type de caractères",
"wordRepetitions": "Trop de répétitions",
"wordSequences": "Votre mot de passe contient des séquences",
"errorList": "Erreurs:",
"veryWeak": "Très Faible",
"weak": "Faible",
"normal": "Normal",
"medium": "Moyen",
"strong": "Fort",
"veryStrong": "Très Fort"
}

View File

@ -0,0 +1,17 @@
{
"wordMinLength": "La tua password è troppo corta",
"wordMaxLength": "La tua password è troppo lunga",
"wordInvalidChar": "La tua password contiene un carattere non valido",
"wordNotEmail": "Non usare la tua e-mail come password",
"wordSimilarToUsername": "La tua password non può contenere il tuo nome",
"wordTwoCharacterClasses": "Usa classi di caratteri diversi",
"wordRepetitions": "Troppe ripetizioni",
"wordSequences": "La tua password contiene sequenze",
"errorList": "Errori:",
"veryWeak": "Molto debole",
"weak": "Debole",
"normal": "Normale",
"medium": "Media",
"strong": "Forte",
"veryStrong": "Molto forte"
}

View File

@ -0,0 +1,17 @@
{
"wordMinLength": "Ditt passord er for kort",
"wordMaxLength": "Ditt passord er for langt",
"wordInvalidChar": "Ditt passord inneholder et ugyldig tegn",
"wordNotEmail": "Ikke bruk din epost som ditt passord",
"wordSimilarToUsername": "Ditt passord er for likt ditt brukernavn",
"wordTwoCharacterClasses": "Bruk en kombinasjon av bokstaver, tall og andre tegn",
"wordRepetitions": "For mange repitisjoner",
"wordSequences": "Ditt passord inneholder repeterende tegn",
"errorList": "Feil:",
"veryWeak": "Veldig Svakt",
"weak": "Svakt",
"normal": "Normal",
"medium": "Medium",
"strong": "Sterkt",
"veryStrong": "Veldig Sterkt"
}

View File

@ -0,0 +1,17 @@
{
"wordMinLength": "Hasło jest zbyt krótkie",
"wordMaxLength": "Hasło jest za długie",
"wordInvalidChar": "Hasło zawiera nieprawidłowy znak",
"wordNotEmail": "Hasło nie może być Twoim emailem",
"wordSimilarToUsername": "Hasło nie może zawierać nazwy użytkownika",
"wordTwoCharacterClasses": "Użyj innych klas znaków",
"wordRepetitions": "Zbyt wiele powtórzeń",
"wordSequences": "Hasło zawiera sekwencje",
"errorList": "Błędy:",
"veryWeak": "Bardzo słabe",
"weak": "Słabe",
"normal": "Normalne",
"medium": "Średnie",
"strong": "Silne",
"veryStrong": "Bardzo silne"
}

View File

@ -0,0 +1,17 @@
{
"wordMinLength": "Sua senha é muito curta",
"wordMaxLength": "Sua senha é muito longa",
"wordInvalidChar": "Sua senha contém um caractere inválido",
"wordNotEmail": "Não use seu e-mail como senha",
"wordSimilarToUsername": "Sua senha não pode conter o seu nome de usuário",
"wordTwoCharacterClasses": "Use diferentes classes de caracteres",
"wordRepetitions": "Muitas repetições",
"wordSequences": "Sua senha contém sequências",
"errorList": "Erros:",
"veryWeak": "Muito Fraca",
"weak": "Fraca",
"normal": "Normal",
"medium": "Média",
"strong": "Forte",
"veryStrong": "Muito Forte"
}

View File

@ -0,0 +1,17 @@
{
"wordMinLength": "Слишком короткий пароль",
"wordMaxLength": "Ваш пароль слишком длинный",
"wordInvalidChar": "Ваш пароль содержит недопустимый символ",
"wordNotEmail": "Не используйте e-mail в качестве пароля",
"wordSimilarToUsername": "Пароль не должен содержать логин",
"wordTwoCharacterClasses": "Используйте разные классы символов",
"wordRepetitions": "Слишком много повторений",
"wordSequences": "Пароль содержит последовательности",
"errorList": "Ошибки:",
"veryWeak": "Очень слабый",
"weak": "Слабый",
"normal": "Нормальный",
"medium": "Средний",
"strong": "Сильный",
"veryStrong": "Очень сильный"
}

View File

@ -0,0 +1,17 @@
{
"wordMinLength": "Vaše heslo je príliž krátke",
"wordMaxLength": "Vaše heslo je príliš dlhé",
"wordInvalidChar": "Vaše heslo obsahuje neplatný znak",
"wordNotEmail": "Nepoužívajte Váš email ako Vaše heslo",
"wordSimilarToUsername": "Vaše heslo nesmie obsahovať prihlasovacie meno",
"wordTwoCharacterClasses": "Použite rôzne druhy znakov",
"wordRepetitions": "Príliš veľa opakovaní",
"wordSequences": "Vaše heslo obsahuje postupnosť",
"errorList": "Chyby:",
"veryWeak": "Veľmi slabé",
"weak": "Slabé",
"normal": "Normálne",
"medium": "Stredne silné",
"strong": "Silné",
"veryStrong": "Veľmi silné"
}

View File

@ -0,0 +1,17 @@
{
"wordMinLength": "รหัสผ่านของคุณสั้นเกินไป",
"wordMaxLength": "รหัสผ่านของคุณยาวเกินไป",
"wordInvalidChar": "รหัสผ่านของคุณมีอักษรที่ไม่ถูกต้อง",
"wordNotEmail": "คุณไม่สามารถใช้รหัสผ่านเหมือนกับอีเมล์ของคุณได้",
"wordSimilarToUsername": "รหัสผ่านไม่ควรประกอบด้วยคำที่เป็น username",
"wordTwoCharacterClasses": "ลองเป็นกลุ่มคำใหม่",
"wordRepetitions": "มีอักษรซ้ำเยอะเกินไป",
"wordSequences": "รหัสผ่านของคุณเดาง่ายเกินไป",
"errorList": "Errors:",
"veryWeak": "เดาง่ายมาก",
"weak": "เดาง่าย",
"normal": "พอใช้",
"medium": "กำลังดี",
"strong": "ค่อนข้างดี",
"veryStrong": "ดีมาก"
}

View File

@ -0,0 +1,17 @@
{
"wordMinLength": "Girdiğiniz şifre çok Kısa",
"wordMaxLength": "Parolanız çok uzun",
"wordInvalidChar": "Şifreniz geçersiz bir karakter içeriyor",
"wordNotEmail": "E-mail adresinizi şifreniz içerisinde kullanmayınız",
"wordSimilarToUsername": "Kullanıcı Adınızı şifreniz içerisinde kullanmayınız",
"wordTwoCharacterClasses": "Başka karakter sınıfı kullanınız",
"wordRepetitions": "Çok fazla tekrar var",
"wordSequences": "Şifreniz Dizi içermektedir",
"errorList": "Hatalar:",
"veryWeak": "Çok Zayıf",
"weak": "Zayıf",
"normal": "Normal",
"medium": "Orta",
"strong": "Güçlü",
"veryStrong": "Çok Güçlü"
}

View File

@ -0,0 +1,17 @@
{
"wordMinLength": "您的密碼太短",
"wordMaxLength": "您的密碼太長",
"wordInvalidChar": "您的密碼包含無效字符",
"wordNotEmail": "不要使用電子郵件作為密碼",
"wordSimilarToUsername": "您的密碼不能包含您的用戶名",
"wordTwoCharacterClasses": "使用不同的字元類型 例如: 大小寫混合",
"wordRepetitions": "太多的重複。例如:1111",
"wordSequences": "你的密碼包含連續英/數字 例如:123 or abc",
"errorList": "錯誤:",
"veryWeak": "非常弱",
"weak": "弱",
"normal": "普通",
"medium": "中等",
"strong": "強",
"veryStrong": "非常強"
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -151,13 +151,13 @@ $("#form-upload").uploadprogress({
}); });
$(document).ready(function() { $(document).ready(function() {
var inp = $('#query').first() var inp = $('#query').first()
if (inp.length) { if (inp.length) {
var val = inp.val() var val = inp.val()
if (val.length) { if (val.length) {
inp.val('').blur().focus().val(val) inp.val('').blur().focus().val(val)
}
} }
}
}); });
$(".session").click(function() { $(".session").click(function() {

58
cps/static/js/password.js Normal file
View File

@ -0,0 +1,58 @@
/* This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
* Copyright (C) 2022 OzzieIsaacs
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
$(document).ready(function() {
i18next.use(i18nextHttpBackend).init({
lng: $('#password').data("lang"),
debug: false,
fallbackLng: 'en',
backend: {
loadPath: getPath() + "/static/js/libs/pwstrength/locales/{{lng}}.json",
},
}, function () {
// Initialized and ready to go
var options = {};
options.ui = {
bootstrap3: true,
showProgressBar: false,
showErrors: true,
showVerdicts: false,
}
options.rules= {
activated: {
wordNotEmail: false,
wordMinLength: true,
// wordMaxLength: false,
// wordInvalidChar: true,
wordSimilarToUsername: false,
wordSequences: false,
wordTwoCharacterClasses: false,
wordRepetitions: false,
//wordLowercase: true,
//wordUppercase: true,
wordOneNumber: true,
wordThreeNumbers: false,
wordOneSpecialChar: true,
// wordTwoSpecialChar: true,
wordUpperLowerCombo: false,
wordLetterNumberCombo: false,
wordLetterNumberCharCombo: false
}
}
$('#password').pwstrength(options);
});
});

View File

@ -352,6 +352,53 @@
{% endif %} {% endif %}
</div> </div>
</div> </div>
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a class="accordion-toggle" data-toggle="collapse" href="#collapsesix">
<span class="glyphicon glyphicon-plus"></span>
{{_('Securitiy Settings')}}
</a>
</h4>
</div>
<div id="collapsesix" class="panel-collapse collapse">
<div class="panel-body">
<div class="form-group">
<label for="config_session">{{_('Session protection')}}</label>
<select name="config_session" id="config_session" class="form-control">
<option value="0" {% if config.config_session == 0 %}selected{% endif %}>{{_('Basic')}}</option>
<option value="1" {% if config.config_session == 1 %}selected{% endif %}>{{_('Strong')}}</option>
</select>
</div>
<div class="form-group">
<input type="checkbox" id="config_password_policy" data-control="password_settings" name="config_password_policy" {% if config.config_password %}checked{% endif %}>
<label for="config_password_policy">{{_('User Password policy')}}</label>
</div>
<div data-related="password_settings">
<div class="form-group" style="margin-left:10px;">
<label for="config_password_min_length">{{_('Minimum password length')}}</label>
<input type="number" min="0" max="40" class="form-control" name="config_password_min_length" id="config_password_min_length" value="{% if config.config_password_min_length != None %}{{ config.config_password_min_length }}{% endif %}" autocomplete="off" required>
</div>
<div class="form-group" style="margin-left:10px;">
<input type="checkbox" id="config_password_number" name="config_password_number" {% if config.config_password_number %}checked{% endif %}>
<label for="config_password_number">{{_('Enforce number')}}</label>
</div>
<div class="form-group" style="margin-left:10px;">
<input type="checkbox" id="config_password_lower" name="config_password_lower" {% if config.config_password_lower %}checked{% endif %}>
<label for="config_password_lower">{{_('Enforce lowercase characters')}}</label>
</div>
<div class="form-group" style="margin-left:10px;">
<input type="checkbox" id="config_password_lower" name="config_password_upper" {% if config.config_password_upper %}checked{% endif %}>
<label for="config_password_upper">{{_('Enforce uppercase characters')}}</label>
</div>
<div class="form-group" style="margin-left:10px;">
<input type="checkbox" id="config_password_special" name="config_password_special" {% if config.config_kobo_proxy %}checked{% endif %}>
<label for="config_password_special">{{_('Enforce special characters')}}</label>
</div>
</div>
</div>
</div>
</div> </div>
</div> </div>
<div class="col-sm-12"> <div class="col-sm-12">

View File

@ -0,0 +1,10 @@
{
"input": {
"placeholder": "a placeholder"
},
"nav": {
"home": "Home",
"page1": "Page One",
"page2": "Page Two"
}
}

View File

@ -21,7 +21,7 @@
{% endif %} {% endif %}
<div class="form-group"> <div class="form-group">
<label for="password">{{_('Password')}}</label> <label for="password">{{_('Password')}}</label>
<input type="password" class="form-control" name="password" id="password" value="" autocomplete="off"> <input type="password" class="form-control" name="password" id="password" data-lang="{{ g.user.locale }}" value="" autocomplete="off">
</div> </div>
{% endif %} {% endif %}
<div class="form-group"> <div class="form-group">
@ -175,5 +175,9 @@
<script src="{{ url_for('static', filename='js/libs/bootstrap-table/bootstrap-table.min.js') }}"></script> <script src="{{ url_for('static', filename='js/libs/bootstrap-table/bootstrap-table.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/libs/bootstrap-table/bootstrap-table-editable.min.js') }}"></script> <script src="{{ url_for('static', filename='js/libs/bootstrap-table/bootstrap-table-editable.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/libs/bootstrap-table/bootstrap-editable.min.js') }}"></script> <script src="{{ url_for('static', filename='js/libs/bootstrap-table/bootstrap-editable.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/libs/pwstrength/i18next.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/libs/pwstrength/i18nextHttpBackend.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/libs/pwstrength/pwstrength-bootstrap.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/password.js') }}"></script>
<script src="{{ url_for('static', filename='js/table.js') }}"></script> <script src="{{ url_for('static', filename='js/table.js') }}"></script>
{% endblock %} {% endblock %}