mongo updated

This commit is contained in:
2025-01-10 20:52:45 +03:00
parent d8685dd496
commit cecf1e69a2
66 changed files with 3597 additions and 857 deletions

View File

@@ -1,40 +1,28 @@
import uuid
import secrets
import hashlib
import uuid
import requests
from sqlalchemy import or_
from datetime import timedelta
from fastapi.exceptions import HTTPException
from fastapi import status
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 generate_token(cls, length):
return secrets.token_urlsafe(length)
@classmethod
def create_hashed_password(cls, domain, id_, password):
salted_password = f"{domain}-{id_}-{password}"
return hashlib.sha256(salted_password.encode()).hexdigest()
@classmethod
def check_hashed_password(cls, domain, id_, password, password_hashed):
if not password_hashed:
raise HTTPException(
status_code=401,
detail="Password is not changed yet user has no password.",
)
def check_password(cls, domain, id_, password, password_hashed):
return cls.create_hashed_password(domain, id_, password) == password_hashed
@@ -43,8 +31,10 @@ 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.query.filter(
found_user: Users = Users.query.filter(
or_(
Users.email == str(access_key).lower(),
Users.phone_number == str(access_key).replace(" ", ""),
@@ -70,9 +60,7 @@ class AuthModule(PasswordModule):
return self.generate_token(Auth.ACCESS_TOKEN_LENGTH)
def remove_refresher_token(self, domain, disconnect: bool = False):
from databases import (
UsersTokens,
)
from databases import UsersTokens
if disconnect:
registered_tokens = UsersTokens.filter_all(
@@ -87,20 +75,6 @@ class AuthModule(PasswordModule):
registered_tokens.query.delete()
UsersTokens.save()
def check_password(self, password):
main_domain = self.get_main_domain_and_other_domains(get_main_domain=True)
if check_password := self.check_hashed_password(
domain=main_domain,
id_=str(self.uu_id),
password_hashed=self.hash_password,
password=password,
):
return check_password
raise HTTPException(
status_code=401,
detail="Password is not correct.",
)
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(
@@ -113,7 +87,9 @@ class AuthModule(PasswordModule):
@staticmethod
def create_password(found_user, password, password_token=None):
from databases import MongoQueryIdentity
from databases import MongoQueryIdentity, Users
found_user: Users = found_user
if found_user.password_token:
replace_day = 0
@@ -135,10 +111,9 @@ class AuthModule(PasswordModule):
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)
)["main_domain"]
)[0]["main_domain"]
new_password_dict = {
"password": found_user.create_hashed_password(
domain=domain_via_user, id_=str(found_user.uu_id), password=password
@@ -208,155 +183,133 @@ class AuthModule(PasswordModule):
class UserLoginModule(AuthModule):
@classmethod
def login_user_with_credentials(cls, data, request):
from api_services.redis.functions import RedisActions
from databases import (
Users,
People,
MongoQueryIdentity,
)
def set_login_details_to_mongo_database(
cls, found_user, headers_request, access_token, record_id
):
from databases.no_sql_models.identity import MongoQueryIdentity
found_user: Users = Users.check_user_exits(
access_key=data.access_key, domain=data.domain
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",
)
access_token = found_user.generate_access_token()
query_engine = MongoQueryIdentity(company_uuid=found_user.related_company)
if found_user.check_password(password=data.password):
access_object_to_redis = RedisActions.save_access_token_to_redis(
request=request,
found_user=found_user,
domain=data.domain,
access_token=access_token,
)
refresher_token = found_user.generate_refresher_token(
domain=data.domain, remember_me=data.remember_me
)
headers_request = request.headers
headers_request = dict(headers_request)
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"
# found_user.last_agent = headers_request.get("evyos-user-agent", None)
# found_user.last_platform = headers_request.get("evyos-platform", None)
# found_user.last_remote_addr = headers_request.get("evyos-ip-ext", None)
# found_user.last_seen = str(system_arrow.now())
if ext_ip := headers_request.get("evyos-ip-ext"):
agent = headers_request.get("evyos-user-agent", "")
platform = headers_request.get("evyos-platform", "")
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"],
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(),
},
}
mongo_db = MongoQueryIdentity(
company_uuid=str(found_user.related_company).replace(" ", ""),
storage_reasoning="AccessHistory",
)
filter_query = {
)
)
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,
"user_id": found_user.id,
"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,
}
already_exits = mongo_db.mongo_engine.filter_by(filter_query) or None
no_address_validates = mongo_db.mongo_engine.get_all()[0] == 0
)
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__()
notice_link = ApiStatic.blacklist_login(record_id=record_id)
found_people = People.filter_one(People.id == found_user.person_id).data
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(),
# "is_confirmed": True if no_address_validates else False,
# "is_first": True if no_address_validates else False,
},
}
)
cls.set_login_details_to_mongo_database(
found_user=found_user,
headers_request=headers_request,
access_token=access_token,
record_id=record_id,
)
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(),
}
},
)
else:
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,
}
)
notice_link = ApiStatic.blacklist_login(record_id=record_id)
found_user.remember_me = bool(data.remember_me)
found_user.save()
return {
"access_token": access_token,
"refresher_token": refresher_token,
"user": found_user,
"access_object": access_object_to_redis,
}
return access_object_to_redis
raise HTTPException(
status_code=401,
detail="Login is not successful. Please check your credentials.",
)
# UserLogger.log_error(
# dict(
# user_id=found_user.id,
# domain=data.domain,
# access_key=data.access_key,
# agent=found_user.last_agent,
# ip=getattr(request, "remote_addr", None)
# or request.headers.get("X-Forwarded-For", None),
# platform=found_user.last_platform,
# login_date=str(DateTimeLocal.now()),
# is_login=True,
# )
# )
# if (
# not str(found_people.country_code).lower()
# == str(address_package.get("countryCode")).lower()
# ):
# send_email_completed = send_email(
# subject=f"Dear {found_user.nick_name}, your password has been changed.",
# receivers=[str(found_user.email)],
# html=invalid_ip_or_address_found(
# user_name=found_user.nick_name,
# address=address_package,
# notice_link=notice_link,
# ),
# )
# if not send_email_completed:
# raise HTTPException(
# status_code=400,
# detail="An error occured at sending email. Please contact with support team.",
# )

View File

@@ -56,14 +56,41 @@ class MongoQueryIdentity:
return [self.validate_timestamp(doc) for doc in result.data] if result else None
def refresh_password_history_via_user(self, payload: PasswordHistoryViaUser):
self.use_collection("PasswordHistory")
password_history_item = self.mongo_engine.get_one(
match=payload.user_uu_id, field="user_uu_id"
)
if not password_history_item:
self.mongo_engine.insert(
payload={
"user_uu_id": str(payload.user_uu_id),
"password_history": [],
}
)
password_history_item = self.mongo_engine.get_one(
match=payload.user_uu_id, field="user_uu_id"
).data
password_history_list = password_history_item.get("password_history", [])
hashed_password = payload.password_add.get("password")
for password_in_history in password_history_list:
if str(password_in_history.get("password")) == str(hashed_password):
raise HTTPException(
status_code=400,
detail="Password already used. Please enter a new password that you have not used last 3 times.",
)
if len(password_history_list) > 3:
password_history_list.pop(0)
password_history_list.append(payload.password_add)
return self.mongo_engine.update(
field="user_uu_id",
match=payload.user_uu_id,
payload={
"password_history": payload.password_history,
"password_history": password_history_list,
"access_history_detail": payload.access_history_detail,
"modified_at": system_arrow.to_timestamp(system_arrow.now()),
"modified_at": system_arrow.now().timestamp(),
},
field="user_uu_id",
)
def get_password_history_via_user(self, user_uu_id):
@@ -99,6 +126,7 @@ class MongoQueryIdentity:
result = self.mongo_engine.filter_by(payload={"user_uu_id": user_uu_id})
return [self.validate_timestamp(doc) for doc in result.data] if result else None
@staticmethod
def validate_timestamp(doc):
"""Validate and fix timestamp fields in MongoDB documents"""
if not doc:

View File

@@ -1,5 +1,4 @@
from datetime import timedelta
from typing import Optional, List
from fastapi import HTTPException
from sqlalchemy import (
@@ -106,13 +105,11 @@ class Users(CrudCollection, UserLoginModule, SelectAction):
)
password_expires_day: Mapped[int] = mapped_column(
"expires_day",
Integer,
server_default=str(Auth.PASSWORD_EXPIRE_DAY.days),
comment="Password expires in days",
)
password_expiry_begins: Mapped[TIMESTAMP] = mapped_column(
"expiry_begins",
TIMESTAMP(timezone=True),
server_default=func.now(),
comment="Timestamp when password expiry begins",
@@ -243,9 +240,15 @@ class Users(CrudCollection, UserLoginModule, SelectAction):
query_engine = MongoQueryIdentity(company_uuid=self.related_company)
domain_via_user = query_engine.get_domain_via_user(user_uu_id=str(self.uu_id))
if not domain_via_user:
raise HTTPException(
status_code=401,
detail="Domain not found. Please contact the admin.",
)
domain_via_user = domain_via_user[0]
if get_main_domain:
return domain_via_user.get("main_domain")
return domain_via_user.get("other_domains_list")
return domain_via_user.get("main_domain", None)
return domain_via_user.get("other_domains_list", None)
class RelationshipDutyPeople(CrudCollection):