fix: create apis for magicleaps password things avoiding calling code depot

This commit is contained in:
haolou 2025-10-20 14:51:38 +08:00
parent e12fb4568e
commit 497e6080a3
6 changed files with 112 additions and 0 deletions

View File

@ -95,6 +95,12 @@ class SignInHub:
user_id=user_id, password=password
)
@log_entry_exit_async
async def update_magicleaps_user_password(self, user_id: str, password: str) -> dict[str, any]:
return await self.signin_manager.update_magicleaps_user_password(
user_id=user_id, password=password
)
@log_entry_exit_async
async def send_email_code(self, sender_id: str, email: str) -> dict[str, any]:
result = await self.signin_manager.send_email_code(sender_id, email)

View File

@ -368,6 +368,23 @@ class SignInManager:
)
return {"succeeded": True}
async def update_magicleaps_user_password(self, user_id: str, password: str) -> dict[str, any]:
error_message = """
Password does not pass complexity requirements:
- At least one lowercase character
- At least one uppercase character
- At least one digit
- At least one special character (punctuation, brackets, quotes, etc.)
"""
if not check_password_complexity(password):
raise InvalidDataError(error_message)
user_flid = await self.user_auth_service.get_user_flid(user_id)
await self.user_auth_service.save_magicleaps_password_auth_method(
user_id, user_flid, password
)
return {"succeeded": True}
async def send_email_code(self, sender_id: str, email: str) -> bool:
mail_code = await self.user_auth_service.generate_auth_code_for_object(
email, AuthType.EMAIL

View File

@ -235,6 +235,31 @@ class UserAuthHandler:
if not result:
raise Exception("Failed to update user password in code depot")
async def save_magicleaps_password_auth_method(self, user_id: str, user_flid, password: str):
"""save password auth method to user_password doc for MagicLeaps users (skips depot service)
Args:
user_id (str): user id
password (str): user password
"""
password_hashed = bcrypt.hashpw(password.encode("utf-8"), bcrypt.gensalt())
user_password = await UserPasswordDoc.find(
UserPasswordDoc.user_id == user_id
).first_or_none()
if user_password is None:
new_user_password = UserPasswordDoc(
user_id=user_id, password=password_hashed
)
await new_user_password.create()
else:
user_password.password = password_hashed
await user_password.save()
# Skip depot service call for MagicLeaps users
# MagicLeaps users don't exist in Gitea, so we don't update depot password
async def reset_password(self, user_id: str):
"""clean password auth method from user_password doc

View File

@ -51,3 +51,10 @@ class UserAuthService:
return await self.user_auth_handler.save_password_auth_method(
user_id, user_flid, password
)
async def save_magicleaps_password_auth_method(
self, user_id: str, user_flid: str, password: str
):
return await self.user_auth_handler.save_magicleaps_password_auth_method(
user_id, user_flid, password
)

View File

@ -5,6 +5,7 @@ from .signin_with_email_and_password import router as se_router
from .signin_with_email_and_code import router as sw_router
from .signin_with_magicleaps_email_and_code import router as swm_router
from .update_user_password import router as up_router
from .update_magicleaps_user_password import router as ump_router
from .update_new_user_flid import router as uu_router
from .reset_password_through_email import router as rp_router
from .sign_out import router as so_router
@ -17,6 +18,7 @@ router.include_router(tms_router, prefix="/signin", tags=["signin"])
router.include_router(sw_router, prefix="/signin", tags=["signin"])
router.include_router(swm_router, prefix="/signin", tags=["signin"])
router.include_router(up_router, prefix="/signin", tags=["signin"])
router.include_router(ump_router, prefix="/signin", tags=["signin"])
router.include_router(se_router, prefix="/signin", tags=["signin"])
router.include_router(so_router, prefix="/signin", tags=["signin"])
router.include_router(rp_router, prefix="/signin", tags=["signin"])

View File

@ -0,0 +1,55 @@
from backend.application.signin_hub import SignInHub
from pydantic import BaseModel
from fastapi import APIRouter, Security, HTTPException
from common.token.token_manager import TokenManager
from fastapi.encoders import jsonable_encoder
from fastapi.responses import JSONResponse
from starlette.status import HTTP_401_UNAUTHORIZED
from jose import jwt
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from common.config.app_settings import app_settings
router = APIRouter()
token_manager = TokenManager()
# Web API
# update_magicleaps_user_password
#
class RequestIn(BaseModel):
password: str
password2: str
@router.post(
"/update-magicleaps-user-password",
operation_id="magicleaps_update_user_password",
summary="update MagicLeaps user's sign-in password",
description="Update the MagicLeaps user's sign-in password without updating code depot. If the password was not set yet, this will enable the user to log in using the password",
response_description="signin_type:0 meaning simplified(using email) signin, \
1 meaning standard(using FLID and passward) signin",
)
async def update_magicleaps_user_password(
item: RequestIn,
credentials: HTTPAuthorizationCredentials = Security(HTTPBearer()),
):
payload = jwt.decode(
credentials.credentials,
app_settings.JWT_SECRET_KEY,
algorithms=[app_settings.JWT_ALGORITHM],
)
user_id = payload.get("subject").get("id")
if not user_id:
raise HTTPException(
status_code=HTTP_401_UNAUTHORIZED, detail="Could not validate credentials"
)
if item.password != item.password2:
return JSONResponse(
content=jsonable_encoder(
{"error": "password and password2 are not the same"}
)
)
else:
result = await SignInHub().update_magicleaps_user_password(user_id, item.password)
return JSONResponse(content=jsonable_encoder(result))