wag-managment-api-service-v.../databases/extensions/auth.py

316 lines
12 KiB
Python

import hashlib
import uuid
import requests
from datetime import timedelta
from fastapi.exceptions import HTTPException
from databases.no_sql_models.validations import (
PasswordHistoryViaUser,
AccessHistoryViaUser,
)
from api_library.date_time_actions.date_functions import system_arrow, client_arrow
from api_configs import ApiStatic, Auth
class PasswordModule:
@staticmethod
def generate_token(length=32):
return uuid.uuid4().__str__()[:length]
@staticmethod
def create_hashed_password(domain: str, id_: str, password: str):
return hashlib.sha256(f"{domain}:{id_}:{password}".encode("utf-8")).hexdigest()
@classmethod
def check_password(cls, domain, id_, password, password_hashed):
return cls.create_hashed_password(domain, id_, password) == password_hashed
class AuthModule(PasswordModule):
@classmethod
def check_user_exits(cls, access_key, domain):
from databases import Users
from sqlalchemy import or_
from fastapi import status
found_user: Users = Users.query.filter(
or_(
Users.email == str(access_key).lower(),
Users.phone_number == str(access_key).replace(" ", ""),
),
).first()
if not found_user:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Given access key or domain is not matching with the any user record.",
)
other_domains_list = found_user.get_main_domain_and_other_domains(
get_main_domain=False
)
if domain not in other_domains_list:
raise HTTPException(
status_code=401,
detail=dict(message="Unauthorized User attempts to connect api"),
)
return found_user
def generate_access_token(self):
return self.generate_token(Auth.ACCESS_TOKEN_LENGTH)
def remove_refresher_token(self, domain, disconnect: bool = False):
from databases import UsersTokens
if disconnect:
registered_tokens = UsersTokens.filter_all(
UsersTokens.user_id == self.id, system=True
)
else:
registered_tokens = UsersTokens.filter_all(
UsersTokens.domain == domain,
UsersTokens.user_id == self.id,
system=True,
)
registered_tokens.query.delete()
UsersTokens.save()
def check_password_is_different(self, password):
main_domain = self.get_main_domain_and_other_domains(get_main_domain=True)
if self.hash_password == self.create_hashed_password(
domain=main_domain, id_=self.uu_id, password=password
):
raise HTTPException(
status_code=401,
detail="New password is same with old password.",
)
@staticmethod
def create_password(found_user, password, password_token=None):
from databases import MongoQueryIdentity, Users
found_user: Users = found_user
if found_user.password_token:
replace_day = 0
try:
replace_day = int(
str(found_user.password_expires_day or 0)
.split(",")[0]
.replace(" days", "")
)
except Exception as e:
err = e
token_is_expired = system_arrow.now() >= system_arrow.get(
str(found_user.password_expiry_begins)
).shift(days=replace_day)
if not password_token == found_user.password_token and token_is_expired:
raise HTTPException(
status_code=401,
detail="Password token is not valid. Please request a new password token.",
)
query_engine = MongoQueryIdentity(company_uuid=found_user.related_company)
domain_via_user = query_engine.get_domain_via_user(
user_uu_id=str(found_user.uu_id)
)[0]["main_domain"]
new_password_dict = {
"password": found_user.create_hashed_password(
domain=domain_via_user, id_=str(found_user.uu_id), password=password
),
"date": str(system_arrow.now().date()),
}
history_dict = PasswordHistoryViaUser(
user_uu_id=str(found_user.uu_id),
password_add=new_password_dict,
access_history_detail={
"request": "",
"ip": "",
},
)
found_user.password_expiry_begins = str(system_arrow.now())
found_user.hash_password = new_password_dict.get("password")
found_user.password_token = "" if found_user.password_token else ""
query_engine.refresh_password_history_via_user(payload=history_dict)
found_user.save()
return found_user
@staticmethod
def reset_password_token(found_user):
found_user.password_expiry_begins = str(system_arrow.now())
found_user.password_token = found_user.generate_token(
Auth.REFRESHER_TOKEN_LENGTH
)
found_user.save()
return found_user.password_token
def generate_refresher_token(self, domain: str, remember_me=False):
from databases import (
UsersTokens,
)
if remember_me:
refresh_token = self.generate_token(Auth.REFRESHER_TOKEN_LENGTH)
if already_token := UsersTokens.filter_by_one(
system=True, user_id=self.id, token_type="RememberMe", domain=domain
).data:
already_token.update(token=refresh_token)
already_token.expires_at = system_arrow.shift(days=3)
already_token.save()
return refresh_token
users_tokens = UsersTokens.filter_by_all(
user_id=self.id, token_type="RememberMe", domain=domain, system=True
).data
if users_tokens:
users_tokens.query.delete()
UsersTokens.save()
users_token = UsersTokens.find_or_create(
user_id=self.id,
token_type="RememberMe",
token=refresh_token,
domain=domain,
)
users_token.save_and_confirm()
return refresh_token
return None
def remainder_day(self):
join_list = [
_ for _ in str(self.password_expires_day).split(",")[0] if _.isdigit()
]
return float(timedelta(days=int("".join(join_list))).seconds)
class UserLoginModule(AuthModule):
@classmethod
def set_login_details_to_mongo_database(
cls, found_user, headers_request, access_token, record_id
):
from databases.no_sql_models.identity import MongoQueryIdentity
agent = headers_request.get("evyos-user-agent", "")
platform = headers_request.get("evyos-platform", "")
ext_ip = headers_request.get("evyos-ip-ext")
address = requests.get(f"http://ip-api.com/json/{ext_ip}").json()
address_package = {
"city": address["city"],
"zip": address["zip"],
"country": address["country"],
"countryCode": address["countryCode"],
"region": address["region"],
"regionName": address["regionName"],
}
mongo_db = MongoQueryIdentity(
company_uuid=found_user.related_company,
storage_reasoning="AccessHistory",
)
query_engine = MongoQueryIdentity(company_uuid=found_user.related_company)
filter_query = {
"agent": agent,
"platform": platform,
"address": address_package,
"user_id": found_user.id,
}
already_exits = mongo_db.mongo_engine.filter_by(filter_query) or None
no_address_validates = mongo_db.mongo_engine.get_all()[0] == 0
access_via_user = query_engine.update_access_history_via_user(
AccessHistoryViaUser(
**{
"user_uu_id": found_user.uu_id.__str__(),
"access_history": {
"record_id": record_id,
"agent": agent,
"platform": platform,
"address": address_package,
"ip": ext_ip,
"access_token": access_token,
"created_at": system_arrow.now().timestamp(),
},
}
)
)
if already_exits:
update_mongo = mongo_db.mongo_engine.table.update_one(
filter=filter_query,
update={
"$set": {
"ip": ext_ip,
"access_token": access_token,
"created_at": system_arrow.now().timestamp(),
}
},
)
print("update_mongo", update_mongo)
else:
insert_mongo = mongo_db.mongo_engine.insert(
payload={
"user_id": found_user.id,
"record_id": record_id,
"agent": agent,
"platform": platform,
"address": address_package,
"ip": ext_ip,
"access_token": access_token,
"created_at": system_arrow.now().timestamp(),
"is_confirmed": True if no_address_validates else False,
"is_first": True if no_address_validates else False,
}
)
print("insert_mongo", insert_mongo)
@classmethod
def login_user_with_credentials(cls, data, request):
from databases.sql_models.identity.identity import Users
from ApiServices.api_handlers.auth_actions.auth import AuthActions
found_user = Users.check_user_exits(
access_key=data.access_key, domain=data.domain
)
if not found_user:
raise HTTPException(
status_code=401,
detail="Login is not successful. Please check your credentials.",
)
if len(found_user.hash_password) < 5:
raise HTTPException(
status_code=401,
detail="This user has not set up password. Please contact support.",
)
if found_user.check_password(
domain=data.domain,
id_=found_user.uu_id,
password_hashed=found_user.hash_password,
password=data.password,
):
access_object_to_redis = AuthActions.save_access_token_to_redis(
request=request,
found_user=found_user,
domain=data.domain,
# remember_me=data.remember_me,
)
print("access_object_to_redis", access_object_to_redis)
access_token = access_object_to_redis.get("access_token")
headers_request = dict(request.headers)
headers_request["evyos-user-agent"] = headers_request.get("user-agent")
headers_request["evyos-platform"] = headers_request.get("user-agent")
headers_request["evyos-ip-ext"] = "94.54.68.158"
if headers_request.get("evyos-ip-ext"):
record_id = uuid.uuid4().__str__()
cls.set_login_details_to_mongo_database(
found_user=found_user,
headers_request=headers_request,
access_token=access_token,
record_id=record_id,
)
notice_link = ApiStatic.blacklist_login(record_id=record_id)
found_user.remember_me = bool(data.remember_me)
found_user.save()
return access_object_to_redis
raise HTTPException(
status_code=401,
detail="Login is not successful. Please check your credentials.",
)