File size: 3,322 Bytes
8450c71 b856986 8450c71 b856986 8450c71 b856986 8450c71 b856986 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
import asyncio
import uuid
from tortoise import fields, Tortoise
from tortoise.models import Model
from passlib.context import CryptContext
import datetime
import random
import string
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
def generate_short_uuid() -> str:
"""Generate a random 5-character alphanumeric string."""
return ''.join(random.choices(string.ascii_letters + string.digits, k=5))
class User(Model):
id = fields.CharField(primary_key=True, max_length=5, default=generate_short_uuid)
name = fields.CharField(max_length=100, db_index=True)
email = fields.CharField(max_length=100, db_index=True, unique=True)
password = fields.CharField(max_length=100)
phoneNumber = fields.CharField(max_length=100, null=True)
account_type = fields.IntField(default=1)
balance = fields.DecimalField(max_digits=10, decimal_places=2, default=0.00)
ip_address = fields.CharField(max_length=45, null=True)
mac_address = fields.CharField(max_length=17, null=True)
createdAt = fields.DatetimeField(default=datetime.datetime.now)
updatedAt = fields.DatetimeField(default=datetime.datetime.now)
lastLogin = fields.DatetimeField(default=datetime.datetime.now)
failed_attempts = fields.IntField(default=0)
account_locked = fields.BooleanField(default=False)
reset_token = fields.CharField(max_length=100, null=True, unique=True)
reset_token_expiration = fields.DatetimeField(null=True)
class Meta:
table = "users"
def verify_password(self, plain_password: str) -> bool:
if self.account_locked:
print("Account is locked due to too many failed attempts.")
return False
if pwd_context.verify(plain_password, self.password):
self.failed_attempts = 0 # Reset failed attempts on success
self.account_locked = False
self.save() # Save changes to reset the failed attempts count
return True
else:
self.failed_attempts += 1
if self.failed_attempts >= 5:
self.account_locked = True
print("Account locked due to too many failed attempts.")
self.save() # Save changes to update the failed attempts count
return False
async def initiate_password_reset(self):
# Generate a unique reset token
self.reset_token = str(uuid.uuid4())
self.reset_token_expiration = datetime.datetime.now() + datetime.timedelta(hours=1) # Token expires in 1 hour
await self.save()
# In a real application, send this token to the user's email or phone
print(f"Password reset token for {self.email}: {self.reset_token}")
async def reset_password(self, reset_token, new_password):
# Check if the reset token is valid and not expired
if self.reset_token != reset_token or datetime.datetime.now() > self.reset_token_expiration:
print("Invalid or expired reset token.")
return False
# Set the new password
self.password = pwd_context.hash(new_password)
self.reset_token = None # Clear the token after successful reset
self.reset_token_expiration = None
await self.save()
print("Password has been reset successfully.")
return True |