mirror of
https://github.com/janeczku/calibre-web
synced 2024-12-18 06:00:32 +00:00
Improved js password strength check
Improved check of CJK-Characters
This commit is contained in:
parent
f987fb0aba
commit
c901ccbb01
@ -125,13 +125,6 @@ def create_app():
|
|||||||
|
|
||||||
ub.password_change(cli_param.user_credentials)
|
ub.password_change(cli_param.user_credentials)
|
||||||
|
|
||||||
if not limiter:
|
|
||||||
log.info('*** "flask-limiter" is needed for calibre-web to run. '
|
|
||||||
'Please install it using pip: "pip install flask-limiter" ***')
|
|
||||||
print('*** "flask-limiter" is needed for calibre-web to run. '
|
|
||||||
'Please install it using pip: "pip install flask-limiter" ***')
|
|
||||||
web_server.stop(True)
|
|
||||||
sys.exit(8)
|
|
||||||
if sys.version_info < (3, 0):
|
if sys.version_info < (3, 0):
|
||||||
log.info(
|
log.info(
|
||||||
'*** Python2 is EOL since end of 2019, this version of Calibre-Web is no longer supporting Python2, '
|
'*** Python2 is EOL since end of 2019, this version of Calibre-Web is no longer supporting Python2, '
|
||||||
@ -141,13 +134,6 @@ def create_app():
|
|||||||
'please update your installation to Python3 ***')
|
'please update your installation to Python3 ***')
|
||||||
web_server.stop(True)
|
web_server.stop(True)
|
||||||
sys.exit(5)
|
sys.exit(5)
|
||||||
if not wtf_present:
|
|
||||||
log.info('*** "flask-WTF" is needed for calibre-web to run. '
|
|
||||||
'Please install it using pip: "pip install flask-WTF" ***')
|
|
||||||
print('*** "flask-WTF" is needed for calibre-web to run. '
|
|
||||||
'Please install it using pip: "pip install flask-WTF" ***')
|
|
||||||
web_server.stop(True)
|
|
||||||
sys.exit(7)
|
|
||||||
|
|
||||||
lm.login_view = 'web.login'
|
lm.login_view = 'web.login'
|
||||||
lm.anonymous_user = ub.Anonymous
|
lm.anonymous_user = ub.Anonymous
|
||||||
@ -158,13 +144,21 @@ def create_app():
|
|||||||
calibre_db.init_db()
|
calibre_db.init_db()
|
||||||
|
|
||||||
updater_thread.init_updater(config, web_server)
|
updater_thread.init_updater(config, web_server)
|
||||||
# Perform dry run of updater and exit afterwards
|
# Perform dry run of updater and exit afterward
|
||||||
if cli_param.dry_run:
|
if cli_param.dry_run:
|
||||||
updater_thread.dry_run()
|
updater_thread.dry_run()
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
updater_thread.start()
|
updater_thread.start()
|
||||||
|
requirements = dependency_check()
|
||||||
for res in dependency_check() + dependency_check(True):
|
for res in requirements:
|
||||||
|
if res['found'] == "not installed":
|
||||||
|
message = ('Cannot import {name} module, it is needed to run calibre-web, '
|
||||||
|
'please install it using "pip install {name}"').format(name=res["name"])
|
||||||
|
log.info(message)
|
||||||
|
print("*** " + message + " ***")
|
||||||
|
web_server.stop(True)
|
||||||
|
sys.exit(8)
|
||||||
|
for res in requirements + dependency_check(True):
|
||||||
log.info('*** "{}" version does not meet the requirements. '
|
log.info('*** "{}" version does not meet the requirements. '
|
||||||
'Should: {}, Found: {}, please consider installing required version ***'
|
'Should: {}, Found: {}, please consider installing required version ***'
|
||||||
.format(res['name'],
|
.format(res['name'],
|
||||||
|
@ -1834,6 +1834,7 @@ def _configuration_update_helper():
|
|||||||
_config_checkbox(to_save, "config_password_number")
|
_config_checkbox(to_save, "config_password_number")
|
||||||
_config_checkbox(to_save, "config_password_lower")
|
_config_checkbox(to_save, "config_password_lower")
|
||||||
_config_checkbox(to_save, "config_password_upper")
|
_config_checkbox(to_save, "config_password_upper")
|
||||||
|
_config_checkbox(to_save, "config_password_character")
|
||||||
_config_checkbox(to_save, "config_password_special")
|
_config_checkbox(to_save, "config_password_special")
|
||||||
if 0 < int(to_save.get("config_password_min_length", "0")) < 41:
|
if 0 < int(to_save.get("config_password_min_length", "0")) < 41:
|
||||||
_config_int(to_save, "config_password_min_length")
|
_config_int(to_save, "config_password_min_length")
|
||||||
|
@ -165,6 +165,7 @@ class _Settings(_Base):
|
|||||||
config_password_number = Column(Boolean, default=True)
|
config_password_number = Column(Boolean, default=True)
|
||||||
config_password_lower = Column(Boolean, default=True)
|
config_password_lower = Column(Boolean, default=True)
|
||||||
config_password_upper = Column(Boolean, default=True)
|
config_password_upper = Column(Boolean, default=True)
|
||||||
|
config_password_character = Column(Boolean, default=True)
|
||||||
config_password_special = Column(Boolean, default=True)
|
config_password_special = Column(Boolean, default=True)
|
||||||
config_session = Column(Integer, default=1)
|
config_session = Column(Integer, default=1)
|
||||||
config_ratelimiter = Column(Boolean, default=True)
|
config_ratelimiter = Column(Boolean, default=True)
|
||||||
|
@ -22,6 +22,7 @@ import random
|
|||||||
import io
|
import io
|
||||||
import mimetypes
|
import mimetypes
|
||||||
import re
|
import re
|
||||||
|
import regex
|
||||||
import shutil
|
import shutil
|
||||||
import socket
|
import socket
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
@ -54,7 +55,8 @@ from . import calibre_db, cli_param
|
|||||||
from .tasks.convert import TaskConvert
|
from .tasks.convert import TaskConvert
|
||||||
from . import logger, config, db, ub, fs
|
from . import logger, config, db, ub, fs
|
||||||
from . import gdriveutils as gd
|
from . import gdriveutils as gd
|
||||||
from .constants import STATIC_DIR as _STATIC_DIR, CACHE_TYPE_THUMBNAILS, THUMBNAIL_TYPE_COVER, THUMBNAIL_TYPE_SERIES, SUPPORTED_CALIBRE_BINARIES
|
from .constants import (STATIC_DIR as _STATIC_DIR, CACHE_TYPE_THUMBNAILS, THUMBNAIL_TYPE_COVER, THUMBNAIL_TYPE_SERIES,
|
||||||
|
SUPPORTED_CALIBRE_BINARIES)
|
||||||
from .subproc_wrapper import process_wait
|
from .subproc_wrapper import process_wait
|
||||||
from .services.worker import WorkerThread
|
from .services.worker import WorkerThread
|
||||||
from .tasks.mail import TaskEmail
|
from .tasks.mail import TaskEmail
|
||||||
@ -694,14 +696,16 @@ def valid_password(check_password):
|
|||||||
if config.config_password_min_length > 0:
|
if config.config_password_min_length > 0:
|
||||||
verify += r"^(?=.{" + str(config.config_password_min_length) + ",}$)"
|
verify += r"^(?=.{" + str(config.config_password_min_length) + ",}$)"
|
||||||
if config.config_password_number:
|
if config.config_password_number:
|
||||||
verify += r"(?=.*?\d)"
|
verify += "(?=.*?\d)"
|
||||||
if config.config_password_lower:
|
if config.config_password_lower:
|
||||||
verify += r"(?=.*?[a-z])"
|
verify += "(?=.*?[\p{Ll}])"
|
||||||
if config.config_password_upper:
|
if config.config_password_upper:
|
||||||
verify += r"(?=.*?[A-Z])"
|
verify += "(?=.*?[\p{Lu}])"
|
||||||
|
if config.config_password_character:
|
||||||
|
verify += "(?=.*?[\p{Letter}])"
|
||||||
if config.config_password_special:
|
if config.config_password_special:
|
||||||
verify += r"(?=.*?[^A-Za-z\s0-9])"
|
verify += "(?=.*?[^\p{Letter}\s0-9])"
|
||||||
match = re.match(verify, unidecode.unidecode(check_password))
|
match = regex.match(verify, check_password)
|
||||||
if not match:
|
if not match:
|
||||||
raise Exception(_("Password doesn't comply with password validation rules"))
|
raise Exception(_("Password doesn't comply with password validation rules"))
|
||||||
return check_password
|
return check_password
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
"wordSequences": "Das Passwort enthält Buchstabensequenzen",
|
"wordSequences": "Das Passwort enthält Buchstabensequenzen",
|
||||||
"wordLowercase": "Bitte mindestens einen Kleinbuchstaben verwenden",
|
"wordLowercase": "Bitte mindestens einen Kleinbuchstaben verwenden",
|
||||||
"wordUppercase": "Bitte mindestens einen Großbuchstaben verwenden",
|
"wordUppercase": "Bitte mindestens einen Großbuchstaben verwenden",
|
||||||
|
"word": "Bitte mindestens einen Buchstaben verwenden",
|
||||||
"wordOneNumber": "Bitte mindestens eine Ziffern verwenden",
|
"wordOneNumber": "Bitte mindestens eine Ziffern verwenden",
|
||||||
"wordOneSpecialChar": "Bitte mindestens ein Sonderzeichen verwenden",
|
"wordOneSpecialChar": "Bitte mindestens ein Sonderzeichen verwenden",
|
||||||
"errorList": "Fehler:",
|
"errorList": "Fehler:",
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
"wordRepetitions": "Too many repetitions",
|
"wordRepetitions": "Too many repetitions",
|
||||||
"wordSequences": "Your password contains sequences",
|
"wordSequences": "Your password contains sequences",
|
||||||
"wordLowercase": "Use at least one lowercase character",
|
"wordLowercase": "Use at least one lowercase character",
|
||||||
|
"word": "Use at least one character",
|
||||||
"wordUppercase": "Use at least one uppercase character",
|
"wordUppercase": "Use at least one uppercase character",
|
||||||
"wordOneNumber": "Use at least one number",
|
"wordOneNumber": "Use at least one number",
|
||||||
"wordOneSpecialChar": "Use at least one special character",
|
"wordOneSpecialChar": "Use at least one special character",
|
||||||
|
@ -144,13 +144,13 @@ try {
|
|||||||
|
|
||||||
validation.wordTwoCharacterClasses = function(options, word, score) {
|
validation.wordTwoCharacterClasses = function(options, word, score) {
|
||||||
var specialCharRE = new RegExp(
|
var specialCharRE = new RegExp(
|
||||||
'(.' + options.rules.specialCharClass + ')'
|
'(.' + options.rules.specialCharClass + ')', 'u'
|
||||||
);
|
);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
word.match(/([a-z].*[A-Z])|([A-Z].*[a-z])/) ||
|
word.match(/(\p{Ll}.*\p{Lu})|(\p{Lu}.*\p{Ll})/u) ||
|
||||||
(word.match(/([a-zA-Z])/) && word.match(/([0-9])/)) ||
|
(word.match(/(\p{Letter})/u) && word.match(/([0-9])/)) ||
|
||||||
(word.match(specialCharRE) && word.match(/[a-zA-Z0-9_]/))
|
(word.match(specialCharRE) && word.match(/[\p{Letter}0-9_]/u))
|
||||||
) {
|
) {
|
||||||
return score;
|
return score;
|
||||||
}
|
}
|
||||||
@ -202,11 +202,15 @@ try {
|
|||||||
};
|
};
|
||||||
|
|
||||||
validation.wordLowercase = function(options, word, score) {
|
validation.wordLowercase = function(options, word, score) {
|
||||||
return word.match(/[a-z]/) && score;
|
return word.match(/\p{Ll}/u) && score;
|
||||||
};
|
};
|
||||||
|
|
||||||
validation.wordUppercase = function(options, word, score) {
|
validation.wordUppercase = function(options, word, score) {
|
||||||
return word.match(/[A-Z]/) && score;
|
return word.match(/\p{Lu}/u) && score;
|
||||||
|
};
|
||||||
|
|
||||||
|
validation.word = function(options, word, score) {
|
||||||
|
return word.match(/\p{Letter}/u) && score;
|
||||||
};
|
};
|
||||||
|
|
||||||
validation.wordOneNumber = function(options, word, score) {
|
validation.wordOneNumber = function(options, word, score) {
|
||||||
@ -218,7 +222,7 @@ try {
|
|||||||
};
|
};
|
||||||
|
|
||||||
validation.wordOneSpecialChar = function(options, word, score) {
|
validation.wordOneSpecialChar = function(options, word, score) {
|
||||||
var specialCharRE = new RegExp(options.rules.specialCharClass);
|
var specialCharRE = new RegExp(options.rules.specialCharClass, 'u');
|
||||||
return word.match(specialCharRE) && score;
|
return word.match(specialCharRE) && score;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -228,27 +232,27 @@ try {
|
|||||||
options.rules.specialCharClass +
|
options.rules.specialCharClass +
|
||||||
'.*' +
|
'.*' +
|
||||||
options.rules.specialCharClass +
|
options.rules.specialCharClass +
|
||||||
')'
|
')', 'u'
|
||||||
);
|
);
|
||||||
|
|
||||||
return word.match(twoSpecialCharRE) && score;
|
return word.match(twoSpecialCharRE) && score;
|
||||||
};
|
};
|
||||||
|
|
||||||
validation.wordUpperLowerCombo = function(options, word, score) {
|
validation.wordUpperLowerCombo = function(options, word, score) {
|
||||||
return word.match(/([a-z].*[A-Z])|([A-Z].*[a-z])/) && score;
|
return word.match(/(\p{Ll}.*\p{Lu})|(\p{Lu}.*\p{Ll})/u) && score;
|
||||||
};
|
};
|
||||||
|
|
||||||
validation.wordLetterNumberCombo = function(options, word, score) {
|
validation.wordLetterNumberCombo = function(options, word, score) {
|
||||||
return word.match(/([a-zA-Z])/) && word.match(/([0-9])/) && score;
|
return word.match(/([\p{Letter}])/u) && word.match(/([0-9])/) && score;
|
||||||
};
|
};
|
||||||
|
|
||||||
validation.wordLetterNumberCharCombo = function(options, word, score) {
|
validation.wordLetterNumberCharCombo = function(options, word, score) {
|
||||||
var letterNumberCharComboRE = new RegExp(
|
var letterNumberCharComboRE = new RegExp(
|
||||||
'([a-zA-Z0-9].*' +
|
'([\p{Letter}0-9].*' +
|
||||||
options.rules.specialCharClass +
|
options.rules.specialCharClass +
|
||||||
')|(' +
|
')|(' +
|
||||||
options.rules.specialCharClass +
|
options.rules.specialCharClass +
|
||||||
'.*[a-zA-Z0-9])'
|
'.*[\p{Letter}0-9])', 'u'
|
||||||
);
|
);
|
||||||
|
|
||||||
return word.match(letterNumberCharComboRE) && score;
|
return word.match(letterNumberCharComboRE) && score;
|
||||||
@ -341,6 +345,7 @@ defaultOptions.rules.scores = {
|
|||||||
wordTwoCharacterClasses: 2,
|
wordTwoCharacterClasses: 2,
|
||||||
wordRepetitions: -25,
|
wordRepetitions: -25,
|
||||||
wordLowercase: 1,
|
wordLowercase: 1,
|
||||||
|
word: 1,
|
||||||
wordUppercase: 3,
|
wordUppercase: 3,
|
||||||
wordOneNumber: 3,
|
wordOneNumber: 3,
|
||||||
wordThreeNumbers: 5,
|
wordThreeNumbers: 5,
|
||||||
@ -361,6 +366,7 @@ defaultOptions.rules.activated = {
|
|||||||
wordTwoCharacterClasses: true,
|
wordTwoCharacterClasses: true,
|
||||||
wordRepetitions: true,
|
wordRepetitions: true,
|
||||||
wordLowercase: true,
|
wordLowercase: true,
|
||||||
|
word: true,
|
||||||
wordUppercase: true,
|
wordUppercase: true,
|
||||||
wordOneNumber: true,
|
wordOneNumber: true,
|
||||||
wordThreeNumbers: true,
|
wordThreeNumbers: true,
|
||||||
@ -372,7 +378,7 @@ defaultOptions.rules.activated = {
|
|||||||
wordIsACommonPassword: true
|
wordIsACommonPassword: true
|
||||||
};
|
};
|
||||||
defaultOptions.rules.raisePower = 1.4;
|
defaultOptions.rules.raisePower = 1.4;
|
||||||
defaultOptions.rules.specialCharClass = "(?=.*?[^A-Za-z\s0-9])"; //'[!,@,#,$,%,^,&,*,?,_,~]';
|
defaultOptions.rules.specialCharClass = "(?=.*?[^\\p{Letter}\\s0-9])"; //'[!,@,#,$,%,^,&,*,?,_,~]';
|
||||||
// List taken from https://github.com/danielmiessler/SecLists (MIT License)
|
// List taken from https://github.com/danielmiessler/SecLists (MIT License)
|
||||||
defaultOptions.rules.commonPasswords = [
|
defaultOptions.rules.commonPasswords = [
|
||||||
'123456',
|
'123456',
|
||||||
|
File diff suppressed because one or more lines are too long
@ -38,22 +38,20 @@ $(document).ready(function() {
|
|||||||
showVerdicts: false,
|
showVerdicts: false,
|
||||||
}
|
}
|
||||||
options.rules= {
|
options.rules= {
|
||||||
specialCharClass: "(?=.*?[^A-Za-z\\s0-9])",
|
specialCharClass: "(?=.*?[^\\p{Letter}\\s0-9])",
|
||||||
activated: {
|
activated: {
|
||||||
wordNotEmail: false,
|
wordNotEmail: false,
|
||||||
wordMinLength: $('#password').data("min"),
|
wordMinLength: $('#password').data("min"),
|
||||||
// wordMaxLength: false,
|
|
||||||
// wordInvalidChar: true,
|
|
||||||
wordSimilarToUsername: false,
|
wordSimilarToUsername: false,
|
||||||
wordSequences: false,
|
wordSequences: false,
|
||||||
wordTwoCharacterClasses: false,
|
wordTwoCharacterClasses: false,
|
||||||
wordRepetitions: false,
|
wordRepetitions: false,
|
||||||
wordLowercase: $('#password').data("lower") === "True" ? true : false,
|
wordLowercase: $('#password').data("lower") === "True" ? true : false,
|
||||||
wordUppercase: $('#password').data("upper") === "True" ? true : false,
|
wordUppercase: $('#password').data("upper") === "True" ? true : false,
|
||||||
|
word: $('#password').data("word") === "True" ? true : false,
|
||||||
wordOneNumber: $('#password').data("number") === "True" ? true : false,
|
wordOneNumber: $('#password').data("number") === "True" ? true : false,
|
||||||
wordThreeNumbers: false,
|
wordThreeNumbers: false,
|
||||||
wordOneSpecialChar: $('#password').data("special") === "True" ? true : false,
|
wordOneSpecialChar: $('#password').data("special") === "True" ? true : false,
|
||||||
// wordTwoSpecialChar: true,
|
|
||||||
wordUpperLowerCombo: false,
|
wordUpperLowerCombo: false,
|
||||||
wordLetterNumberCombo: false,
|
wordLetterNumberCombo: false,
|
||||||
wordLetterNumberCharCombo: false
|
wordLetterNumberCharCombo: false
|
||||||
|
@ -410,6 +410,10 @@
|
|||||||
<input type="checkbox" id="config_password_upper" name="config_password_upper" {% if config.config_password_upper %}checked{% endif %}>
|
<input type="checkbox" id="config_password_upper" name="config_password_upper" {% if config.config_password_upper %}checked{% endif %}>
|
||||||
<label for="config_password_upper">{{_('Enforce uppercase characters')}}</label>
|
<label for="config_password_upper">{{_('Enforce uppercase characters')}}</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group" style="margin-left:10px;">
|
||||||
|
<input type="checkbox" id="config_password_character" name="config_password_character" {% if config.config_password_character %}checked{% endif %}>
|
||||||
|
<label for="config_password_lower">{{_('Enforce characters (needed For Chinese/Japanese/Korean Characters)')}}</label>
|
||||||
|
</div>
|
||||||
<div class="form-group" style="margin-left:10px;">
|
<div class="form-group" style="margin-left:10px;">
|
||||||
<input type="checkbox" id="config_password_special" name="config_password_special" {% if config.config_password_special %}checked{% endif %}>
|
<input type="checkbox" id="config_password_special" name="config_password_special" {% if config.config_password_special %}checked{% endif %}>
|
||||||
<label for="config_password_special">{{_('Enforce special characters')}}</label>
|
<label for="config_password_special">{{_('Enforce special characters')}}</label>
|
||||||
|
@ -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" data-lang="{{ current_user.locale }}" data-verify="{{ config.config_password_policy }}" {% if config.config_password_policy %} data-min={{ config.config_password_min_length }} data-special={{ config.config_password_special }} data-upper={{ config.config_password_upper }} data-lower={{ config.config_password_lower }} data-number={{ config.config_password_number }}{% endif %} value="" autocomplete="off">
|
<input type="password" class="form-control" name="password" id="password" data-lang="{{ current_user.locale }}" data-verify="{{ config.config_password_policy }}" {% if config.config_password_policy %} data-min={{ config.config_password_min_length }} data-word={{ config.config_password_character }} data-special={{ config.config_password_special }} data-upper={{ config.config_password_upper }} data-lower={{ config.config_password_lower }} data-number={{ config.config_password_number }}{% endif %} value="" autocomplete="off">
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@ -177,7 +177,7 @@
|
|||||||
<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/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/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/libs/pwstrength/pwstrength-bootstrap.js') }}"></script>
|
||||||
<script src="{{ url_for('static', filename='js/password.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 %}
|
||||||
|
@ -18,3 +18,4 @@ flask-wtf>=0.14.2,<1.3.0
|
|||||||
chardet>=3.0.0,<4.1.0
|
chardet>=3.0.0,<4.1.0
|
||||||
advocate>=1.0.0,<1.1.0
|
advocate>=1.0.0,<1.1.0
|
||||||
Flask-Limiter>=2.3.0,<3.6.0
|
Flask-Limiter>=2.3.0,<3.6.0
|
||||||
|
regex>=2022.3.2,<2024.2.25
|
||||||
|
Loading…
Reference in New Issue
Block a user