|
| 1 | +from flask_sqlalchemy import SQLAlchemy |
| 2 | +from flask_login import UserMixin |
| 3 | +from werkzeug.security import generate_password_hash, check_password_hash |
| 4 | +import pyotp |
| 5 | +import base64 |
| 6 | +import os |
| 7 | + |
| 8 | +db = SQLAlchemy() |
| 9 | + |
| 10 | +class User(UserMixin, db.Model): |
| 11 | + id = db.Column(db.Integer, primary_key=True) |
| 12 | + username = db.Column(db.String(80), unique=True, nullable=False) |
| 13 | + password_hash = db.Column(db.String(120), nullable=False) |
| 14 | + totp_secret = db.Column(db.String(32), nullable=True) |
| 15 | + totp_enabled = db.Column(db.Boolean, default=False) |
| 16 | + |
| 17 | + def set_password(self, password): |
| 18 | + self.password_hash = generate_password_hash(password) |
| 19 | + |
| 20 | + def check_password(self, password): |
| 21 | + return check_password_hash(self.password_hash, password) |
| 22 | + |
| 23 | + def generate_totp_secret(self): |
| 24 | + secret = base64.b32encode(os.urandom(10)).decode('utf-8') |
| 25 | + self.totp_secret = secret |
| 26 | + return secret |
| 27 | + |
| 28 | + def verify_totp(self, token): |
| 29 | + if not self.totp_enabled or not self.totp_secret: |
| 30 | + return True |
| 31 | + totp = pyotp.TOTP(self.totp_secret) |
| 32 | + return totp.verify(token, valid_window=1) |
| 33 | + |
| 34 | + def get_totp_uri(self): |
| 35 | + return pyotp.totp.TOTP(self.totp_secret).provisioning_uri( |
| 36 | + name=self.username, |
| 37 | + issuer_name='DirectAdmin Email Forwarder' |
| 38 | + ) |
0 commit comments