2020-09-28 18:19:59 +02:00
|
|
|
from datetime import datetime
|
2020-10-05 17:04:40 +02:00
|
|
|
|
2020-09-28 18:19:59 +02:00
|
|
|
from fastapi import HTTPException
|
2020-09-30 11:27:48 +02:00
|
|
|
from passlib.context import CryptContext
|
2020-06-05 01:09:55 +02:00
|
|
|
|
|
|
|
from app.schemas import *
|
2020-10-05 15:35:13 +02:00
|
|
|
from constants import SHA1_SALT
|
2020-08-01 19:04:35 +02:00
|
|
|
from database import SessionLocal
|
|
|
|
from database.models import *
|
2020-06-05 01:09:55 +02:00
|
|
|
|
2020-10-05 17:04:40 +02:00
|
|
|
pwd_context = CryptContext(schemes=["bcrypt", "hex_sha1"], deprecated=["hex_sha1"])
|
2020-09-30 11:27:48 +02:00
|
|
|
|
|
|
|
|
2020-08-01 19:04:35 +02:00
|
|
|
def get_db():
|
|
|
|
db = SessionLocal()
|
|
|
|
try:
|
|
|
|
yield db
|
|
|
|
finally:
|
|
|
|
db.close()
|
2020-04-15 00:29:59 +02:00
|
|
|
|
2020-05-28 00:53:23 +02:00
|
|
|
|
2020-09-11 00:00:48 +02:00
|
|
|
def instantiate_model(model, data):
|
|
|
|
table = eval(model)
|
|
|
|
instance = table(**data.dict())
|
2020-05-28 00:53:23 +02:00
|
|
|
return instance
|
|
|
|
|
|
|
|
|
2020-09-11 00:00:48 +02:00
|
|
|
def insert_data(model, data, db):
|
|
|
|
item = instantiate_model(model=model, data=data)
|
2020-08-01 19:04:35 +02:00
|
|
|
db.add(item)
|
|
|
|
db.commit()
|
2020-09-11 00:00:48 +02:00
|
|
|
db.refresh(item)
|
2020-09-22 13:59:29 +02:00
|
|
|
return item
|
2020-06-05 01:09:55 +02:00
|
|
|
|
|
|
|
|
2020-08-01 19:04:35 +02:00
|
|
|
# FIXME db.id has to be replaced with the table's UID
|
2020-09-22 13:59:29 +02:00
|
|
|
def delete_data(model, data, db):
|
|
|
|
item = instantiate_model(model=model, data=data)
|
|
|
|
result = db.query(item).filter(item.email == data.email).delete()
|
2020-08-01 19:04:35 +02:00
|
|
|
return result
|
2020-04-15 00:29:59 +02:00
|
|
|
|
|
|
|
|
2020-09-28 18:19:59 +02:00
|
|
|
def fetch_user_by_key(data, db):
|
|
|
|
return db.query(Users).filter(Users.access_key == data.access_key).first()
|
2020-04-15 00:29:59 +02:00
|
|
|
|
|
|
|
|
2020-09-28 18:19:59 +02:00
|
|
|
def fetch_user_by_email(data, db):
|
|
|
|
return db.query(Users).filter(Users.email == data.email).first()
|
2020-04-19 21:30:41 +02:00
|
|
|
|
|
|
|
|
2020-10-03 14:50:19 +02:00
|
|
|
def create_user(data, db):
|
2020-10-05 17:04:40 +02:00
|
|
|
data.password = pwd_context.hash(secret=data.password)
|
2020-09-30 11:27:48 +02:00
|
|
|
user = insert_data(model="Users", data=data, db=db)
|
|
|
|
return user
|
|
|
|
|
|
|
|
|
2020-10-08 21:23:19 +02:00
|
|
|
def update_otp(data, db):
|
2020-10-03 14:50:19 +02:00
|
|
|
db.query(Users).filter(Users.email == data.email).update(
|
|
|
|
{Users.otp: data.otp, Users.otp_valid_time: data.otp_valid_time}
|
|
|
|
)
|
|
|
|
db.commit()
|
|
|
|
|
|
|
|
|
2020-10-05 15:35:13 +02:00
|
|
|
def update_password_hash(user, password, db):
|
2020-10-05 17:04:40 +02:00
|
|
|
new_hash = pwd_context.hash(secret=password)
|
2020-10-05 15:35:13 +02:00
|
|
|
db.query(Users).filter(Users.email == user.email).update({Users.password: new_hash})
|
|
|
|
db.commit()
|
|
|
|
db.refresh(user)
|
|
|
|
|
|
|
|
|
2020-10-05 17:04:40 +02:00
|
|
|
def check_legacy_hash(db_hash):
|
2020-10-05 15:35:13 +02:00
|
|
|
sha1_length = 40
|
2020-10-05 17:04:40 +02:00
|
|
|
if len(db_hash) == sha1_length:
|
2020-10-05 15:35:13 +02:00
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
2020-10-05 17:04:40 +02:00
|
|
|
def construct_secret(db_hash, password):
|
|
|
|
legacy_hash = check_legacy_hash(db_hash=db_hash)
|
|
|
|
if legacy_hash:
|
|
|
|
return SHA1_SALT + password, legacy_hash
|
|
|
|
return password, legacy_hash
|
2020-10-05 15:35:13 +02:00
|
|
|
|
|
|
|
|
|
|
|
def verify_password(user, password, db):
|
2020-10-05 17:04:40 +02:00
|
|
|
secret, legacy_hash = construct_secret(db_hash=user.password, password=password)
|
|
|
|
correct_password = pwd_context.verify(secret=secret, hash=user.password)
|
|
|
|
if correct_password:
|
|
|
|
if legacy_hash:
|
|
|
|
update_password_hash(user=user, password=password, db=db)
|
|
|
|
return True
|
|
|
|
return False
|
2020-10-05 15:35:13 +02:00
|
|
|
|
|
|
|
|
|
|
|
def authenticate_user(data: UserLogin, db):
|
|
|
|
user = fetch_user_by_email(data=data, db=db)
|
|
|
|
if not user:
|
|
|
|
raise HTTPException(status_code=400, detail="Incorrect username or password")
|
|
|
|
correct_password = verify_password(user=user, password=data.password, db=db)
|
|
|
|
if not correct_password:
|
|
|
|
raise HTTPException(status_code=400, detail="Incorrect username or password")
|
|
|
|
valid_account = user.status
|
|
|
|
if not valid_account:
|
|
|
|
raise HTTPException(status_code=400, detail="Your account is not active")
|
2020-09-28 18:19:59 +02:00
|
|
|
return user
|
2020-04-19 21:30:41 +02:00
|
|
|
|
|
|
|
|
2020-10-04 16:42:18 +02:00
|
|
|
def activate_account(user, db):
|
|
|
|
db.query(Users).filter(Users.access_key == user.access_key).update(
|
|
|
|
{Users.status: 1}
|
|
|
|
)
|
|
|
|
db.commit()
|
|
|
|
db.refresh(user)
|
|
|
|
|
|
|
|
|
2020-10-08 20:47:10 +02:00
|
|
|
def deactivate_account(user, db):
|
|
|
|
db.query(Users).filter(Users.email == user.email).update(
|
|
|
|
{Users.status: 0, Users.forgot_password: 1}
|
|
|
|
)
|
|
|
|
db.commit()
|
|
|
|
db.refresh(user)
|
|
|
|
|
|
|
|
|
2020-10-08 21:23:19 +02:00
|
|
|
def unset_forgot_password(user, db):
|
|
|
|
db.query(Users).filter(Users.email == user.email).update({Users.forgot_password: 0})
|
|
|
|
db.commit()
|
|
|
|
db.refresh(user)
|
|
|
|
|
|
|
|
|
2020-09-11 00:00:48 +02:00
|
|
|
def verify_otp(data: OTPVerify, db):
|
2020-09-28 18:19:59 +02:00
|
|
|
user = fetch_user_by_key(data=data, db=db)
|
|
|
|
matching_otp = user.otp == data.otp
|
|
|
|
valid_time = datetime.now() < user.otp_valid_time
|
|
|
|
valid_otp = matching_otp and valid_time
|
2020-09-11 00:00:48 +02:00
|
|
|
if valid_otp:
|
2020-10-04 16:42:18 +02:00
|
|
|
activate_account(user=user, db=db)
|
|
|
|
return user
|
2020-09-28 18:19:59 +02:00
|
|
|
else:
|
|
|
|
raise HTTPException(status_code=400, detail="The OTP is not correct")
|
2020-10-08 20:47:10 +02:00
|
|
|
|
|
|
|
|
|
|
|
def mark_password_reset(data, db):
|
|
|
|
user = fetch_user_by_email(data=data, db=db)
|
|
|
|
if user.social_id:
|
|
|
|
raise HTTPException(
|
|
|
|
status_code=400,
|
|
|
|
detail="You logged in with Facebook/Google. You can't reset the password",
|
|
|
|
)
|
|
|
|
deactivate_account(user=user, db=db)
|
|
|
|
|
|
|
|
|
2020-10-08 21:23:19 +02:00
|
|
|
def verify_password_reset(data, db):
|
|
|
|
user = fetch_user_by_email(data=data, db=db)
|
|
|
|
valid_account = user.status
|
|
|
|
password_reset_request = user.forgot_password
|
|
|
|
valid_request = valid_account and password_reset_request
|
|
|
|
if valid_request:
|
|
|
|
update_password_hash(user=user, password=data.password, db=db)
|
|
|
|
unset_forgot_password(user=user, db=db)
|
|
|
|
return user
|
|
|
|
else:
|
|
|
|
raise HTTPException(status_code=400, detail="The OTP is not correct")
|