Development
This commit is contained in:
parent
8a8e947fcf
commit
450c0081f7
9 changed files with 59 additions and 28 deletions
|
|
@ -1,6 +1,7 @@
|
|||
from pathlib import Path
|
||||
from flask import Blueprint, request, session, redirect, flash
|
||||
import bcrypt, secrets, smtplib
|
||||
import secrets, smtplib
|
||||
import settings
|
||||
import time
|
||||
from email.message import EmailMessage
|
||||
import auth
|
||||
|
|
@ -78,8 +79,7 @@ def form_create():
|
|||
flash('This account is already set up. Please log in instead.', 'error')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
salt = bcrypt.gensalt()
|
||||
hashed = bcrypt.hashpw(password.encode('utf-8'), salt).decode('utf-8')
|
||||
hashed = settings.hash_password(password)
|
||||
code = f'{secrets.randbelow(1000000):06d}'
|
||||
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
from pathlib import Path
|
||||
from flask import Blueprint, request, session, redirect, flash
|
||||
import bcrypt
|
||||
import auth
|
||||
import config_utils
|
||||
import sanitize
|
||||
|
|
@ -29,7 +28,7 @@ def form_login():
|
|||
if email != settings.get_initial_manager_email() or not stored_hash:
|
||||
flash('Invalid email address or password.', 'error')
|
||||
return redirect(f'/{_PAGE}')
|
||||
if not bcrypt.checkpw(password.encode('utf-8'), stored_hash.encode('utf-8')):
|
||||
if not settings.verify_password(password, stored_hash):
|
||||
flash('Invalid email address or password.', 'error')
|
||||
return redirect(f'/{_PAGE}')
|
||||
session.clear()
|
||||
|
|
@ -76,7 +75,7 @@ def form_login():
|
|||
flash('Account setup is not complete. Please use Create Account to set your password first.', 'error')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
if not bcrypt.checkpw(password.encode('utf-8'), account['hashed_password'].encode('utf-8')):
|
||||
if not settings.verify_password(password, account['hashed_password']):
|
||||
flash('Invalid email address or password.', 'error')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import sqlite3
|
||||
import time
|
||||
|
||||
import bcrypt
|
||||
from cryptography.fernet import Fernet
|
||||
from flask import Blueprint, request, redirect, flash
|
||||
import auth
|
||||
|
|
@ -19,12 +18,12 @@ USER_TYPE_CAPTIVE = 0
|
|||
USER_TYPE_SUPPLICANT = 1
|
||||
|
||||
DIGEST_CYPHERTEXT_FERNET = 0
|
||||
DIGEST_HASH_BCRYPT = 2
|
||||
DIGEST_HASH_SCRYPT = 2
|
||||
|
||||
VALID_USER_TYPES = {USER_TYPE_CAPTIVE, USER_TYPE_SUPPLICANT}
|
||||
|
||||
HASH_FOR_USER_TYPE = {
|
||||
USER_TYPE_CAPTIVE: DIGEST_HASH_BCRYPT,
|
||||
USER_TYPE_CAPTIVE: DIGEST_HASH_SCRYPT,
|
||||
USER_TYPE_SUPPLICANT: DIGEST_CYPHERTEXT_FERNET,
|
||||
}
|
||||
|
||||
|
|
@ -99,8 +98,8 @@ def _get_by_index(conn, row_index):
|
|||
def _hash_password(plaintext, digest_type):
|
||||
if digest_type == DIGEST_CYPHERTEXT_FERNET:
|
||||
return encrypt_password(plaintext)
|
||||
if digest_type == DIGEST_HASH_BCRYPT:
|
||||
return bcrypt.hashpw(plaintext.encode(), bcrypt.gensalt()).decode()
|
||||
if digest_type == DIGEST_HASH_SCRYPT:
|
||||
return settings.hash_password(plaintext)
|
||||
raise ValueError(f"Unknown digest_type: {digest_type}")
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
from pathlib import Path
|
||||
from flask import Blueprint, request, session, redirect, flash
|
||||
import bcrypt
|
||||
import auth
|
||||
import config_utils
|
||||
import sanitize
|
||||
|
|
@ -131,11 +130,11 @@ def changepassword_save():
|
|||
flash('New password must be at least 8 characters.', 'error')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
hashed = bcrypt.hashpw(new_password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')
|
||||
hashed = settings.hash_password(new_password)
|
||||
|
||||
if settings.is_single_user():
|
||||
stored_hash = settings.get_initial_manager_password_hash()
|
||||
if not stored_hash or not bcrypt.checkpw(current_password.encode('utf-8'), stored_hash.encode('utf-8')):
|
||||
if not stored_hash or not settings.verify_password(current_password, stored_hash):
|
||||
flash('Current password is incorrect.', 'error')
|
||||
return redirect(f'/{_PAGE}')
|
||||
try:
|
||||
|
|
@ -156,7 +155,7 @@ def changepassword_save():
|
|||
flash('Account not found. Please log in again.', 'error')
|
||||
return redirect('/accountlogin')
|
||||
|
||||
if not bcrypt.checkpw(current_password.encode('utf-8'), account['hashed_password'].encode('utf-8')):
|
||||
if not settings.verify_password(current_password, account['hashed_password']):
|
||||
flash('Current password is incorrect.', 'error')
|
||||
return redirect(f'/{_PAGE}')
|
||||
|
||||
|
|
|
|||
|
|
@ -100,6 +100,28 @@ def get_credentials_key():
|
|||
return base64.urlsafe_b64encode(raw)
|
||||
|
||||
|
||||
def hash_password(plaintext):
|
||||
import hashlib, os as _os
|
||||
salt = _os.urandom(16)
|
||||
h = hashlib.scrypt(plaintext.encode('utf-8'), salt=salt, n=16384, r=8, p=1, dklen=32)
|
||||
return f'scrypt:16384:8:1:{salt.hex()}:{h.hex()}'
|
||||
|
||||
|
||||
def verify_password(plaintext, stored):
|
||||
import hashlib, hmac
|
||||
try:
|
||||
tag, n, r, p, salt_hex, hash_hex = stored.split(':')
|
||||
if tag != 'scrypt':
|
||||
return False
|
||||
salt = bytes.fromhex(salt_hex)
|
||||
expected = bytes.fromhex(hash_hex)
|
||||
h = hashlib.scrypt(plaintext.encode('utf-8'), salt=salt,
|
||||
n=int(n), r=int(r), p=int(p), dklen=len(expected))
|
||||
return hmac.compare_digest(h, expected)
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
def get_smtp_config():
|
||||
"""Return SMTP settings from app_config.json, falling back to env vars."""
|
||||
cfg = _load_app_config()
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
flask
|
||||
bcrypt
|
||||
cryptography
|
||||
manuf
|
||||
mac-vendor-lookup
|
||||
|
|
|
|||
|
|
@ -1,14 +1,29 @@
|
|||
import hashlib
|
||||
import hmac
|
||||
import ipaddress
|
||||
import sqlite3
|
||||
import time
|
||||
|
||||
import bcrypt
|
||||
from flask import Blueprint, request, redirect
|
||||
import config_utils
|
||||
|
||||
CREDENTIALS_DB = f'{config_utils.CONFIGS_DIR}/.client-credentials'
|
||||
USER_TYPE_CAPTIVE = 0
|
||||
DIGEST_HASH_BCRYPT = 2
|
||||
DIGEST_HASH_SCRYPT = 2
|
||||
|
||||
|
||||
def _verify_scrypt(plaintext, stored):
|
||||
try:
|
||||
tag, n, r, p, salt_hex, hash_hex = stored.split(':')
|
||||
if tag != 'scrypt':
|
||||
return False
|
||||
salt = bytes.fromhex(salt_hex)
|
||||
expected = bytes.fromhex(hash_hex)
|
||||
h = hashlib.scrypt(plaintext.encode('utf-8'), salt=salt,
|
||||
n=int(n), r=int(r), p=int(p), dklen=len(expected))
|
||||
return hmac.compare_digest(h, expected)
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
bp = Blueprint('portal', __name__)
|
||||
|
||||
|
|
@ -85,11 +100,8 @@ def _verify_credential(username, password, vlan_name):
|
|||
return False
|
||||
if row['expires_seconds'] > 0 and (row['date_set'] + row['expires_seconds']) < now:
|
||||
return False
|
||||
if row['digest_type'] == DIGEST_HASH_BCRYPT:
|
||||
try:
|
||||
return bcrypt.checkpw(password.encode(), row['password'].encode())
|
||||
except Exception:
|
||||
return False
|
||||
if row['digest_type'] == DIGEST_HASH_SCRYPT:
|
||||
return _verify_scrypt(password, row['password'])
|
||||
return False
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,2 +1 @@
|
|||
flask
|
||||
bcrypt
|
||||
|
|
|
|||
|
|
@ -373,7 +373,7 @@ def setup_docker_compose(reuse_config=False):
|
|||
print()
|
||||
while True:
|
||||
import getpass as _gp
|
||||
pw = _gp.getpass(f" Password for {manager_email}: ")
|
||||
pw = _gp.getpass(f" Create password for {manager_email}: ")
|
||||
pw2 = _gp.getpass(f" Confirm password: ")
|
||||
if pw != pw2:
|
||||
print(" Passwords do not match. Try again.")
|
||||
|
|
@ -382,8 +382,10 @@ def setup_docker_compose(reuse_config=False):
|
|||
print(" Password must be at least 8 characters.")
|
||||
continue
|
||||
break
|
||||
import bcrypt as _bcrypt
|
||||
pw_hash = _bcrypt.hashpw(pw.encode('utf-8'), _bcrypt.gensalt()).decode('utf-8')
|
||||
import hashlib as _hashlib, os as _os
|
||||
_salt = _os.urandom(16)
|
||||
_h = _hashlib.scrypt(pw.encode('utf-8'), salt=_salt, n=16384, r=8, p=1, dklen=32)
|
||||
pw_hash = f'scrypt:16384:8:1:{_salt.hex()}:{_h.hex()}'
|
||||
app_config = {
|
||||
"initial_manager_email": manager_email,
|
||||
"credentials_key": credentials_key,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue