2025-11-09 23:29:07 +01:00
from datetime import timedelta
feat: add 2fa support, starred items, batch operations, and logging infrastructure
- Implement two-factor authentication with TOTP verification, recovery codes, and QR code setup in auth flow
- Add is_starred and last_accessed_at fields to File and Folder models for bookmarking and recency tracking
- Introduce batch operation endpoints for files and folders (delete, star, unstar, move, copy)
- Configure structured logging with timestamps and module names, replacing print statements
- Register admin and starred routers, add global HTTPException handler with JSON error responses
- Update authenticate_user and create_access_token to handle 2FA verification and token claims
2025-11-10 01:58:41 +01:00
from typing import Optional , List
2025-11-09 23:29:07 +01:00
from fastapi import APIRouter , Depends , HTTPException , status
feat: add 2fa support, starred items, batch operations, and logging infrastructure
- Implement two-factor authentication with TOTP verification, recovery codes, and QR code setup in auth flow
- Add is_starred and last_accessed_at fields to File and Folder models for bookmarking and recency tracking
- Introduce batch operation endpoints for files and folders (delete, star, unstar, move, copy)
- Configure structured logging with timestamps and module names, replacing print statements
- Register admin and starred routers, add global HTTPException handler with JSON error responses
- Update authenticate_user and create_access_token to handle 2FA verification and token claims
2025-11-10 01:58:41 +01:00
from pydantic import BaseModel
2025-11-09 23:29:07 +01:00
2025-11-11 01:05:13 +01:00
from . . auth import authenticate_user , create_access_token , get_password_hash , get_current_user , get_current_verified_user , verify_password
2025-11-09 23:29:07 +01:00
from . . models import User
feat: add 2fa support, starred items, batch operations, and logging infrastructure
- Implement two-factor authentication with TOTP verification, recovery codes, and QR code setup in auth flow
- Add is_starred and last_accessed_at fields to File and Folder models for bookmarking and recency tracking
- Introduce batch operation endpoints for files and folders (delete, star, unstar, move, copy)
- Configure structured logging with timestamps and module names, replacing print statements
- Register admin and starred routers, add global HTTPException handler with JSON error responses
- Update authenticate_user and create_access_token to handle 2FA verification and token claims
2025-11-10 01:58:41 +01:00
from . . schemas import Token , UserCreate , TokenData , UserLoginWith2FA
from . . two_factor import (
generate_totp_secret , generate_totp_uri , generate_qr_code_base64 ,
verify_totp_code , generate_recovery_codes , hash_recovery_codes ,
verify_recovery_codes
)
2025-11-09 23:29:07 +01:00
router = APIRouter (
prefix = " /auth " ,
tags = [ " auth " ] ,
)
2025-11-11 01:05:13 +01:00
class LoginRequest ( BaseModel ) :
username : str
password : str
feat: add 2fa support, starred items, batch operations, and logging infrastructure
- Implement two-factor authentication with TOTP verification, recovery codes, and QR code setup in auth flow
- Add is_starred and last_accessed_at fields to File and Folder models for bookmarking and recency tracking
- Introduce batch operation endpoints for files and folders (delete, star, unstar, move, copy)
- Configure structured logging with timestamps and module names, replacing print statements
- Register admin and starred routers, add global HTTPException handler with JSON error responses
- Update authenticate_user and create_access_token to handle 2FA verification and token claims
2025-11-10 01:58:41 +01:00
class TwoFactorLogin ( BaseModel ) :
username : str
password : str
two_factor_code : Optional [ str ] = None
class TwoFactorSetupResponse ( BaseModel ) :
secret : str
qr_code_base64 : str
recovery_codes : List [ str ]
class TwoFactorCode ( BaseModel ) :
two_factor_code : str
class TwoFactorDisable ( BaseModel ) :
password : str
two_factor_code : str
2025-11-09 23:29:07 +01:00
@router.post ( " /register " , response_model = Token )
async def register_user ( user_in : UserCreate ) :
user = await User . get_or_none ( username = user_in . username )
if user :
raise HTTPException (
status_code = status . HTTP_400_BAD_REQUEST ,
detail = " Username already registered " ,
)
user = await User . get_or_none ( email = user_in . email )
if user :
raise HTTPException (
status_code = status . HTTP_400_BAD_REQUEST ,
detail = " Email already registered " ,
)
hashed_password = get_password_hash ( user_in . password )
user = await User . create (
username = user_in . username ,
email = user_in . email ,
hashed_password = hashed_password ,
)
2025-11-11 12:47:26 +01:00
# Send welcome email
from . . mail import queue_email
queue_email (
to_email = user . email ,
chore: rebrand all user-facing strings from RBox to MyWebdav across docs, emails, and config
Replace every occurrence of "RBox" with "MyWebdav" in README.md, invoice templates, welcome emails, share notifications, FastAPI metadata, default database filename, domain name, S3 bucket name, TOTP issuer, and WebDAV realm header to reflect the commercial rebranding of the application.
2025-11-13 12:05:05 +01:00
subject = " Welcome to MyWebdav! " ,
body = f " Hi { user . username } , \n \n Welcome to MyWebdav! Your account has been created successfully. \n \n Best regards, \n The MyWebdav Team " ,
html = f " <h1>Welcome to MyWebdav!</h1><p>Hi { user . username } ,</p><p>Welcome to MyWebdav! Your account has been created successfully.</p><p>Best regards,<br>The MyWebdav Team</p> "
2025-11-11 12:47:26 +01:00
)
2025-11-09 23:29:07 +01:00
access_token_expires = timedelta ( minutes = 30 ) # Use settings
access_token = create_access_token (
data = { " sub " : user . username } , expires_delta = access_token_expires
)
return { " access_token " : access_token , " token_type " : " bearer " }
@router.post ( " /token " , response_model = Token )
2025-11-11 01:05:13 +01:00
async def login_for_access_token ( login_data : LoginRequest ) :
auth_result = await authenticate_user ( login_data . username , login_data . password , None )
2025-11-10 15:46:40 +01:00
feat: add 2fa support, starred items, batch operations, and logging infrastructure
- Implement two-factor authentication with TOTP verification, recovery codes, and QR code setup in auth flow
- Add is_starred and last_accessed_at fields to File and Folder models for bookmarking and recency tracking
- Introduce batch operation endpoints for files and folders (delete, star, unstar, move, copy)
- Configure structured logging with timestamps and module names, replacing print statements
- Register admin and starred routers, add global HTTPException handler with JSON error responses
- Update authenticate_user and create_access_token to handle 2FA verification and token claims
2025-11-10 01:58:41 +01:00
if not auth_result :
2025-11-09 23:29:07 +01:00
raise HTTPException (
status_code = status . HTTP_401_UNAUTHORIZED ,
2025-11-10 15:46:40 +01:00
detail = " Incorrect username or password " ,
2025-11-09 23:29:07 +01:00
headers = { " WWW-Authenticate " : " Bearer " } ,
)
2025-11-10 15:46:40 +01:00
feat: add 2fa support, starred items, batch operations, and logging infrastructure
- Implement two-factor authentication with TOTP verification, recovery codes, and QR code setup in auth flow
- Add is_starred and last_accessed_at fields to File and Folder models for bookmarking and recency tracking
- Introduce batch operation endpoints for files and folders (delete, star, unstar, move, copy)
- Configure structured logging with timestamps and module names, replacing print statements
- Register admin and starred routers, add global HTTPException handler with JSON error responses
- Update authenticate_user and create_access_token to handle 2FA verification and token claims
2025-11-10 01:58:41 +01:00
user = auth_result [ " user " ]
if auth_result [ " 2fa_required " ] :
raise HTTPException (
status_code = status . HTTP_403_FORBIDDEN ,
detail = " Two-factor authentication required " ,
headers = { " X-2FA-Required " : " true " } ,
)
2025-11-11 01:05:13 +01:00
access_token_expires = timedelta ( minutes = 30 )
2025-11-09 23:29:07 +01:00
access_token = create_access_token (
feat: add 2fa support, starred items, batch operations, and logging infrastructure
- Implement two-factor authentication with TOTP verification, recovery codes, and QR code setup in auth flow
- Add is_starred and last_accessed_at fields to File and Folder models for bookmarking and recency tracking
- Introduce batch operation endpoints for files and folders (delete, star, unstar, move, copy)
- Configure structured logging with timestamps and module names, replacing print statements
- Register admin and starred routers, add global HTTPException handler with JSON error responses
- Update authenticate_user and create_access_token to handle 2FA verification and token claims
2025-11-10 01:58:41 +01:00
data = { " sub " : user . username } , expires_delta = access_token_expires , two_factor_verified = True
)
return { " access_token " : access_token , " token_type " : " bearer " }
@router.post ( " /2fa/setup " , response_model = TwoFactorSetupResponse )
async def setup_two_factor_authentication ( current_user : User = Depends ( get_current_user ) ) :
if current_user . is_2fa_enabled :
raise HTTPException ( status_code = status . HTTP_400_BAD_REQUEST , detail = " 2FA is already enabled. " )
if current_user . two_factor_secret :
raise HTTPException ( status_code = status . HTTP_400_BAD_REQUEST , detail = " 2FA setup already initiated. Verify or disable first. " )
secret = generate_totp_secret ( )
current_user . two_factor_secret = secret
await current_user . save ( )
2025-11-13 20:50:03 +01:00
totp_uri = generate_totp_uri ( secret , current_user . email , " MyWebdav " )
feat: add 2fa support, starred items, batch operations, and logging infrastructure
- Implement two-factor authentication with TOTP verification, recovery codes, and QR code setup in auth flow
- Add is_starred and last_accessed_at fields to File and Folder models for bookmarking and recency tracking
- Introduce batch operation endpoints for files and folders (delete, star, unstar, move, copy)
- Configure structured logging with timestamps and module names, replacing print statements
- Register admin and starred routers, add global HTTPException handler with JSON error responses
- Update authenticate_user and create_access_token to handle 2FA verification and token claims
2025-11-10 01:58:41 +01:00
qr_code_base64 = generate_qr_code_base64 ( totp_uri )
recovery_codes = generate_recovery_codes ( )
hashed_recovery_codes = hash_recovery_codes ( recovery_codes )
current_user . recovery_codes = " , " . join ( hashed_recovery_codes )
await current_user . save ( )
return TwoFactorSetupResponse ( secret = secret , qr_code_base64 = qr_code_base64 , recovery_codes = recovery_codes )
@router.post ( " /2fa/verify " , response_model = Token )
async def verify_two_factor_authentication ( two_factor_code_data : TwoFactorCode , current_user : User = Depends ( get_current_user ) ) :
if current_user . is_2fa_enabled :
raise HTTPException ( status_code = status . HTTP_400_BAD_REQUEST , detail = " 2FA is already enabled. " )
if not current_user . two_factor_secret :
raise HTTPException ( status_code = status . HTTP_400_BAD_REQUEST , detail = " 2FA setup not initiated. " )
if not verify_totp_code ( current_user . two_factor_secret , two_factor_code_data . two_factor_code ) :
raise HTTPException ( status_code = status . HTTP_401_UNAUTHORIZED , detail = " Invalid 2FA code. " )
current_user . is_2fa_enabled = True
await current_user . save ( )
access_token_expires = timedelta ( minutes = 30 ) # Use settings
access_token = create_access_token (
data = { " sub " : current_user . username } , expires_delta = access_token_expires , two_factor_verified = True
2025-11-09 23:29:07 +01:00
)
return { " access_token " : access_token , " token_type " : " bearer " }
feat: add 2fa support, starred items, batch operations, and logging infrastructure
- Implement two-factor authentication with TOTP verification, recovery codes, and QR code setup in auth flow
- Add is_starred and last_accessed_at fields to File and Folder models for bookmarking and recency tracking
- Introduce batch operation endpoints for files and folders (delete, star, unstar, move, copy)
- Configure structured logging with timestamps and module names, replacing print statements
- Register admin and starred routers, add global HTTPException handler with JSON error responses
- Update authenticate_user and create_access_token to handle 2FA verification and token claims
2025-11-10 01:58:41 +01:00
@router.post ( " /2fa/disable " , response_model = dict )
async def disable_two_factor_authentication ( disable_data : TwoFactorDisable , current_user : User = Depends ( get_current_verified_user ) ) :
if not current_user . is_2fa_enabled :
raise HTTPException ( status_code = status . HTTP_400_BAD_REQUEST , detail = " 2FA is not enabled. " )
# Verify password
if not verify_password ( disable_data . password , current_user . hashed_password ) :
raise HTTPException ( status_code = status . HTTP_401_UNAUTHORIZED , detail = " Invalid password. " )
# Verify 2FA code
if not verify_totp_code ( current_user . two_factor_secret , disable_data . two_factor_code ) :
raise HTTPException ( status_code = status . HTTP_401_UNAUTHORIZED , detail = " Invalid 2FA code. " )
current_user . two_factor_secret = None
current_user . is_2fa_enabled = False
current_user . recovery_codes = None
await current_user . save ( )
return { " message " : " 2FA disabled successfully. " }
@router.get ( " /2fa/recovery-codes " , response_model = List [ str ] )
async def get_new_recovery_codes ( current_user : User = Depends ( get_current_verified_user ) ) :
if not current_user . is_2fa_enabled :
raise HTTPException ( status_code = status . HTTP_400_BAD_REQUEST , detail = " 2FA is not enabled. " )
recovery_codes = generate_recovery_codes ( )
hashed_recovery_codes = hash_recovery_codes ( recovery_codes )
current_user . recovery_codes = " , " . join ( hashed_recovery_codes )
await current_user . save ( )
return recovery_codes