forked from Github-Mirrors/canaille
consumes haveibeenpwned API directly
This commit is contained in:
parent
8af6263b2f
commit
0acbb40ecd
3 changed files with 29 additions and 0 deletions
|
@ -84,6 +84,31 @@ def password_strength_calculator(password):
|
||||||
return strength_score
|
return strength_score
|
||||||
|
|
||||||
|
|
||||||
|
def pwned_password_validator(form, field):
|
||||||
|
try:
|
||||||
|
from hashlib import sha1
|
||||||
|
|
||||||
|
import requests
|
||||||
|
except ImportError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
hashed_password = sha1(field.data.encode("utf-8")).hexdigest()
|
||||||
|
hashed_password_splited = (hashed_password[:5].upper(), hashed_password[5:].upper())
|
||||||
|
try:
|
||||||
|
response = requests.api.get(
|
||||||
|
f"https://api2.pwnedpasswords.com/range/{hashed_password_splited[0]}",
|
||||||
|
timeout=10,
|
||||||
|
)
|
||||||
|
except requests.exceptions.HTTPError as e:
|
||||||
|
print("Error: " + str(e))
|
||||||
|
|
||||||
|
decoded_response = response.content.decode("utf8").split("\r\n")
|
||||||
|
|
||||||
|
for each in decoded_response:
|
||||||
|
if hashed_password_splited[1] == each.split(":")[0]:
|
||||||
|
raise wtforms.ValidationError(_("This password is compromised."))
|
||||||
|
|
||||||
|
|
||||||
def email_validator(form, field):
|
def email_validator(form, field):
|
||||||
try:
|
try:
|
||||||
import email_validator # noqa: F401
|
import email_validator # noqa: F401
|
||||||
|
|
|
@ -37,6 +37,7 @@ from canaille.app.forms import TableForm
|
||||||
from canaille.app.forms import is_readonly
|
from canaille.app.forms import is_readonly
|
||||||
from canaille.app.forms import password_length_validator
|
from canaille.app.forms import password_length_validator
|
||||||
from canaille.app.forms import password_too_long_validator
|
from canaille.app.forms import password_too_long_validator
|
||||||
|
from canaille.app.forms import pwned_password_validator
|
||||||
from canaille.app.forms import set_readonly
|
from canaille.app.forms import set_readonly
|
||||||
from canaille.app.forms import set_writable
|
from canaille.app.forms import set_writable
|
||||||
from canaille.app.i18n import gettext as _
|
from canaille.app.i18n import gettext as _
|
||||||
|
@ -316,6 +317,7 @@ def registration(data=None, hash=None):
|
||||||
wtforms.validators.DataRequired(),
|
wtforms.validators.DataRequired(),
|
||||||
password_length_validator,
|
password_length_validator,
|
||||||
password_too_long_validator,
|
password_too_long_validator,
|
||||||
|
pwned_password_validator,
|
||||||
]
|
]
|
||||||
form["password2"].validators = [
|
form["password2"].validators = [
|
||||||
wtforms.validators.DataRequired(),
|
wtforms.validators.DataRequired(),
|
||||||
|
|
|
@ -15,6 +15,7 @@ from canaille.app.forms import is_uri
|
||||||
from canaille.app.forms import password_length_validator
|
from canaille.app.forms import password_length_validator
|
||||||
from canaille.app.forms import password_too_long_validator
|
from canaille.app.forms import password_too_long_validator
|
||||||
from canaille.app.forms import phone_number
|
from canaille.app.forms import phone_number
|
||||||
|
from canaille.app.forms import pwned_password_validator
|
||||||
from canaille.app.forms import set_readonly
|
from canaille.app.forms import set_readonly
|
||||||
from canaille.app.forms import unique_values
|
from canaille.app.forms import unique_values
|
||||||
from canaille.app.i18n import gettext
|
from canaille.app.i18n import gettext
|
||||||
|
@ -265,6 +266,7 @@ PROFILE_FORM_FIELDS = dict(
|
||||||
wtforms.validators.Optional(),
|
wtforms.validators.Optional(),
|
||||||
password_length_validator,
|
password_length_validator,
|
||||||
password_too_long_validator,
|
password_too_long_validator,
|
||||||
|
pwned_password_validator,
|
||||||
],
|
],
|
||||||
render_kw={
|
render_kw={
|
||||||
"autocomplete": "new-password",
|
"autocomplete": "new-password",
|
||||||
|
|
Loading…
Reference in a new issue