From 018edaded79b2dbb200e576ba2a2fa7373ee7fe6 Mon Sep 17 00:00:00 2001 From: cryptorugmunch Date: Tue, 7 Jul 2026 14:53:21 +0700 Subject: [PATCH] refactor(auth): archive app/auth.py + app/auth_wallet.py, migrate all imports to app.domains.auth.* (P4.3 cont) --- app/{ => _archive/legacy_2026_07}/auth.py | 0 .../legacy_2026_07}/auth_wallet.py | 0 app/admin_backend.py | 4 +-- app/domains/billing/x402/tools/token_tools.py | 4 +-- app/routers/admin_backend.py | 2 +- app/routers/admin_users_api.py | 22 ++++++------- app/routers/agents.py | 2 +- app/routers/alerts.py | 3 +- app/routers/auth_extensions.py | 31 ++++++++++++------- app/routers/bulletin.py | 2 +- app/routers/cases_investigators_api.py | 12 +++---- app/routers/chat.py | 2 +- app/routers/news.py | 2 +- app/routers/scam_school.py | 2 +- app/routers/subscription_pricing_api.py | 18 +++++------ app/routers/x402_dashboard.py | 2 +- app/routers/x402_middleware.py | 12 +++---- app/routers/x402_settle_api.py | 4 +-- app/scan_rate_limiter.py | 2 +- 19 files changed, 68 insertions(+), 58 deletions(-) rename app/{ => _archive/legacy_2026_07}/auth.py (100%) rename app/{ => _archive/legacy_2026_07}/auth_wallet.py (100%) diff --git a/app/auth.py b/app/_archive/legacy_2026_07/auth.py similarity index 100% rename from app/auth.py rename to app/_archive/legacy_2026_07/auth.py diff --git a/app/auth_wallet.py b/app/_archive/legacy_2026_07/auth_wallet.py similarity index 100% rename from app/auth_wallet.py rename to app/_archive/legacy_2026_07/auth_wallet.py diff --git a/app/admin_backend.py b/app/admin_backend.py index 7faa91f..dfb357e 100644 --- a/app/admin_backend.py +++ b/app/admin_backend.py @@ -819,7 +819,7 @@ class AdminUserStore: created_by: str = "", ) -> dict | None: """Create a new admin user.""" - from app.auth import hash_password + from app.domains.auth.passwords import hash_password # Check if email already exists existing = await AdminUserStore.get_admin_by_email(email) @@ -853,7 +853,7 @@ class AdminUserStore: @staticmethod async def verify_admin_login(email: str, password: str) -> dict | None: """Verify admin login credentials.""" - from app.auth import verify_password + from app.domains.auth.passwords import verify_password admin = await AdminUserStore.get_admin_by_email(email) if not admin: diff --git a/app/domains/billing/x402/tools/token_tools.py b/app/domains/billing/x402/tools/token_tools.py index 7b149e5..7555b07 100644 --- a/app/domains/billing/x402/tools/token_tools.py +++ b/app/domains/billing/x402/tools/token_tools.py @@ -51,7 +51,7 @@ async def deep_contract_audit(req: TokenRequest): # If primary returned no data, use full fallback chain if not result.get("sources_used"): - from app.auth import get_redis as _get_redis + from app.core.redis import get_redis as _get_redis from app.fallback_engine import try_all_fallbacks r = await _get_redis() @@ -72,7 +72,7 @@ async def deep_contract_audit(req: TokenRequest): except Exception as e: # Last resort: try fallback before raising error try: - from app.auth import get_redis as _get_redis + from app.core.redis import get_redis as _get_redis from app.fallback_engine import try_all_fallbacks r = await _get_redis() diff --git a/app/routers/admin_backend.py b/app/routers/admin_backend.py index b55620d..e5b662d 100644 --- a/app/routers/admin_backend.py +++ b/app/routers/admin_backend.py @@ -1128,7 +1128,7 @@ async def reset_admin_password(request: Request, admin_id: str, body: dict = Bod updater = auth["admin"] ip, ua = _get_client_info(request) - from app.auth import hash_password + from app.domains.auth.passwords import hash_password admin = await AdminUserStore.get_admin(admin_id) if not admin: diff --git a/app/routers/admin_users_api.py b/app/routers/admin_users_api.py index 215b305..dfb278d 100644 --- a/app/routers/admin_users_api.py +++ b/app/routers/admin_users_api.py @@ -33,7 +33,7 @@ router = APIRouter(tags=["admin-users"]) # ── Redis helper ── async def require_admin(request: Request, min_role: str = "ADMIN"): """Require admin authentication.""" - from app.auth import get_current_user + from app.domains.auth import get_current_user user = await get_current_user(request) if not user: @@ -131,7 +131,7 @@ def _get_all_users() -> list[dict]: def _get_user_full(user_id: str) -> dict | None: """Get user with enriched data.""" - from app.auth import _get_user + from app.domains.auth.store import _get_user user = _get_user(user_id) if not user: @@ -285,7 +285,7 @@ async def warn_user(user_id: str, req: WarnUserRequest, request: Request): """Add a warning to a user.""" admin = await require_admin(request, min_role="MODERATOR") - from app.auth import _get_user + from app.domains.auth.store import _get_user user = _get_user(user_id) if not user: @@ -320,7 +320,7 @@ async def flag_suspect(user_id: str, request: Request, reason: str | None = Quer """Flag a user as suspicious.""" admin = await require_admin(request, min_role="MODERATOR") - from app.auth import _get_user + from app.domains.auth.store import _get_user user = _get_user(user_id) if not user: @@ -360,7 +360,7 @@ async def ban_user(user_id: str, request: Request, reason: str | None = Query(No """Ban a user.""" admin = await require_admin(request, min_role="ADMIN") - from app.auth import _get_user + from app.domains.auth.store import _get_user user = _get_user(user_id) if not user: @@ -402,7 +402,7 @@ async def delete_user(user_id: str, request: Request, reason: str | None = Query """Soft delete a user.""" admin = await require_admin(request, min_role="ADMIN") - from app.auth import _get_user, _save_user + from app.domains.auth.store import _get_user, _save_user user = _get_user(user_id) if not user: @@ -430,7 +430,7 @@ async def restore_user(user_id: str, request: Request): """Restore a soft-deleted user.""" admin = await require_admin(request, min_role="ADMIN") - from app.auth import _get_user, _save_user + from app.domains.auth.store import _get_user, _save_user user = _get_user(user_id) if not user: @@ -454,7 +454,7 @@ async def update_user(user_id: str, req: UpdateUserRequest, request: Request): """Update user properties (tier, role, status, etc.).""" admin = await require_admin(request, min_role="ADMIN") - from app.auth import _get_user, _save_user + from app.domains.auth.store import _get_user, _save_user user = _get_user(user_id) if not user: @@ -530,7 +530,7 @@ async def bulk_action(req: BulkActionRequest, request: Request): r.hset("rmi:user_status", user_id, "active") results["success"].append({"id": user_id, "action": "cleared_suspect"}) elif req.action == "delete": - from app.auth import _get_user, _save_user + from app.domains.auth.store import _get_user, _save_user user = _get_user(user_id) if user: @@ -541,7 +541,7 @@ async def bulk_action(req: BulkActionRequest, request: Request): r.hset("rmi:user_status", user_id, "deleted") results["success"].append({"id": user_id, "action": "deleted"}) elif req.action == "restore": - from app.auth import _get_user, _save_user + from app.domains.auth.store import _get_user, _save_user user = _get_user(user_id) if user: @@ -553,7 +553,7 @@ async def bulk_action(req: BulkActionRequest, request: Request): results["success"].append({"id": user_id, "action": "restored"}) elif req.action == "update_tier": tier = req.params.get("tier", "FREE") if req.params else "FREE" - from app.auth import _get_user, _save_user + from app.domains.auth.store import _get_user, _save_user user = _get_user(user_id) if user: diff --git a/app/routers/agents.py b/app/routers/agents.py index 3b0433e..19b068a 100644 --- a/app/routers/agents.py +++ b/app/routers/agents.py @@ -84,7 +84,7 @@ class AgentCommandRequest(BaseModel): priority: str = Field(default="normal") -from app.auth import get_redis # noqa: E402 +from app.domains.auth import get_redis # noqa: E402 # ── Static routes must comes before parameterized routes to avoid FastAPI matching issues ── diff --git a/app/routers/alerts.py b/app/routers/alerts.py index 4270293..0d0551c 100644 --- a/app/routers/alerts.py +++ b/app/routers/alerts.py @@ -21,7 +21,8 @@ class AlertRequest(BaseModel): webhook_url: str | None = None -from app.auth import get_redis, require_auth # noqa: E402 +from app.core.redis import get_redis +from app.domains.auth import require_auth # noqa: E402 def _get_redis_sync(): diff --git a/app/routers/auth_extensions.py b/app/routers/auth_extensions.py index d738922..efac72a 100644 --- a/app/routers/auth_extensions.py +++ b/app/routers/auth_extensions.py @@ -91,7 +91,7 @@ class ProfileResponse(BaseModel): @router.post("/forgot-password") async def forgot_password(req: ForgotPasswordRequest): """Request password reset - sends email with reset token.""" - from app.auth import _get_user_by_email + from app.domains.auth.store import _get_user_by_email user = _get_user_by_email(req.email) if not user: @@ -140,7 +140,8 @@ async def forgot_password(req: ForgotPasswordRequest): @router.post("/reset-password") async def reset_password(req: ResetPasswordRequest): """Reset password using token from email.""" - from app.auth import _get_user, _save_user, hash_password + from app.domains.auth.passwords import hash_password + from app.domains.auth.store import _get_user, _save_user token_hash = hashlib.sha256(req.token.encode()).hexdigest() r = get_redis() # noqa: F821 -- pre-existing bug, see fix(f821) tracking issue @@ -173,7 +174,9 @@ async def reset_password(req: ResetPasswordRequest): @router.post("/change-password") async def change_password(req: ChangePasswordRequest, request: Request): """Change password while logged in.""" - from app.auth import _save_user, get_current_user, hash_password, verify_password + from app.domains.auth import get_current_user + from app.domains.auth.passwords import hash_password, verify_password + from app.domains.auth.store import _save_user user = await get_current_user(request) if not user: @@ -200,7 +203,7 @@ async def change_password(req: ChangePasswordRequest, request: Request): @router.get("/profile", response_model=ProfileResponse) async def get_profile(request: Request): """Get full user profile including linked wallets.""" - from app.auth import get_current_user + from app.domains.auth import get_current_user user = await get_current_user(request) if not user: @@ -229,7 +232,8 @@ async def get_profile(request: Request): @router.patch("/profile") async def update_profile(req: UpdateProfileRequest, request: Request): """Update user profile (display name, avatar).""" - from app.auth import _save_user, get_current_user + from app.domains.auth import get_current_user + from app.domains.auth.store import _save_user user = await get_current_user(request) if not user: @@ -388,7 +392,8 @@ async def list_supported_chains(): @router.post("/wallet/link") async def link_wallet(req: LinkWalletRequest, request: Request): """Link a new wallet to the user's account.""" - from app.auth import _save_user, get_current_user + from app.domains.auth import get_current_user + from app.domains.auth.store import _save_user user = await get_current_user(request) if not user: @@ -437,7 +442,8 @@ async def link_wallet(req: LinkWalletRequest, request: Request): @router.post("/wallet/unlink") async def unlink_wallet(req: UnlinkWalletRequest, request: Request): """Unlink a wallet from the user's account.""" - from app.auth import _save_user, get_current_user + from app.domains.auth import get_current_user + from app.domains.auth.store import _save_user user = await get_current_user(request) if not user: @@ -476,7 +482,7 @@ async def unlink_wallet(req: UnlinkWalletRequest, request: Request): @router.get("/wallet/list") async def list_wallets(request: Request): """List all wallets linked to the current user.""" - from app.auth import get_current_user + from app.domains.auth import get_current_user user = await get_current_user(request) if not user: @@ -504,7 +510,7 @@ class PrivacySettings(BaseModel): @router.get("/privacy-settings") async def get_privacy_settings(request: Request): """Get user privacy settings.""" - from app.auth import get_current_user + from app.domains.auth import get_current_user user = await get_current_user(request) if not user: @@ -528,7 +534,8 @@ async def get_privacy_settings(request: Request): @router.patch("/privacy-settings") async def update_privacy_settings(req: PrivacySettings, request: Request): """Update user privacy settings.""" - from app.auth import _save_user, get_current_user + from app.domains.auth import get_current_user + from app.domains.auth.store import _save_user user = await get_current_user(request) if not user: @@ -559,8 +566,10 @@ async def delete_account(req: DeleteAccountRequest, request: Request): Permanently delete user account and all associated data (GDPR compliant). Requires password confirmation. """ - from app.auth import _delete_user, get_current_user, verify_password from app.core.redis import get_redis + from app.domains.auth import get_current_user + from app.domains.auth.passwords import verify_password + from app.domains.auth.store import _delete_user user = await get_current_user(request) if not user: diff --git a/app/routers/bulletin.py b/app/routers/bulletin.py index eed4b6d..24690f8 100644 --- a/app/routers/bulletin.py +++ b/app/routers/bulletin.py @@ -33,7 +33,7 @@ from app.services.supabase_service import ( # noqa: E402 # Lazy auth dependency - avoids importing jose+bcrypt at module load async def _require_public_profile(request: Request): - from app.auth import require_public_profile + from app.domains.auth import require_public_profile return await require_public_profile(request) diff --git a/app/routers/cases_investigators_api.py b/app/routers/cases_investigators_api.py index a524278..b08fd20 100644 --- a/app/routers/cases_investigators_api.py +++ b/app/routers/cases_investigators_api.py @@ -133,7 +133,7 @@ async def create_case(req: CaseCreateRequest, request: Request): # Resolve creator if authed creator = "anonymous" try: - from app.auth import get_current_user + from app.domains.auth import get_current_user user = await get_current_user(request) if user: @@ -199,7 +199,7 @@ async def get_case(case_id: str): async def list_my_cases(request: Request, limit: int = 50): """List cases created by the current user. Auth required.""" try: - from app.auth import get_current_user + from app.domains.auth import get_current_user user = await get_current_user(request) except Exception: @@ -219,7 +219,7 @@ async def delete_case(case_id: str, request: Request): if not data: raise HTTPException(status_code=404, detail="Case not found") try: - from app.auth import get_current_user + from app.domains.auth import get_current_user user = await get_current_user(request) except Exception: @@ -261,7 +261,7 @@ async def get_investigator(username: str): async def upsert_investigator(username: str, request: Request): """Update or create investigator profile. Auth required.""" try: - from app.auth import get_current_user + from app.domains.auth import get_current_user user = await get_current_user(request) except Exception: @@ -312,7 +312,7 @@ async def portfolio_features(request: Request): base_tier = "FREE" try: - from app.auth import get_current_user + from app.domains.auth import get_current_user user = await get_current_user(request) except Exception: @@ -360,7 +360,7 @@ async def add_addon(req: AddonRequest, request: Request): Returns an x402 challenge for micropayment, or a stripe checkout URL for fiat, or a crypto payment address. """ - from app.auth import get_current_user + from app.domains.auth import get_current_user try: user = await get_current_user(request) diff --git a/app/routers/chat.py b/app/routers/chat.py index 881c6de..91c0f8e 100755 --- a/app/routers/chat.py +++ b/app/routers/chat.py @@ -41,7 +41,7 @@ ai_guard = AIGuard() # ── Auth ── # ── AI Router ── from app.ai_router import router as ai_router # noqa: E402 -from app.auth import get_current_user, require_auth # noqa: E402 +from app.domains.auth import get_current_user, require_auth # noqa: E402 # ── DB path ── DB_PATH = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), "data", "rmi.db") diff --git a/app/routers/news.py b/app/routers/news.py index 3b7a8df..4a20c74 100644 --- a/app/routers/news.py +++ b/app/routers/news.py @@ -21,7 +21,7 @@ from datetime import UTC, datetime, timedelta from fastapi import APIRouter, Depends, HTTPException, Query from pydantic import BaseModel -from app.auth import require_public_profile +from app.domains.auth import require_public_profile logger = logging.getLogger(__name__) diff --git a/app/routers/scam_school.py b/app/routers/scam_school.py index 9e37b6c..e37cdaa 100644 --- a/app/routers/scam_school.py +++ b/app/routers/scam_school.py @@ -29,7 +29,7 @@ API_BASE = os.getenv("API_BASE", "https://rugmunch.io") # ── Redis helper ── async def get_current_user(request: Request) -> dict | None: """Extract user from JWT.""" - from app.auth import get_current_user as _get_user + from app.domains.auth import get_current_user as _get_user return await _get_user(request) diff --git a/app/routers/subscription_pricing_api.py b/app/routers/subscription_pricing_api.py index e1a3cad..f797bc7 100644 --- a/app/routers/subscription_pricing_api.py +++ b/app/routers/subscription_pricing_api.py @@ -354,7 +354,7 @@ async def calculate_pricing(tier: str, period: str): @router.get("/subscription") async def get_my_subscription(request: Request): """Get current user's active subscription.""" - from app.auth import get_current_user + from app.domains.auth import get_current_user user = await get_current_user(request) if not user: @@ -391,7 +391,7 @@ async def get_my_subscription(request: Request): @router.post("/subscription/create") async def create_subscription(req: SubscriptionCreateRequest, request: Request): """Create a new subscription (Stripe, crypto, or x402).""" - from app.auth import get_current_user + from app.domains.auth import get_current_user user = await get_current_user(request) if not user: @@ -526,7 +526,8 @@ async def create_subscription(req: SubscriptionCreateRequest, request: Request): @router.post("/subscription/crypto/confirm") async def confirm_crypto_payment(req: CryptoPaymentRequest, request: Request): """Confirm a crypto payment (called by user after sending tx, or webhook).""" - from app.auth import _save_user, get_current_user + from app.domains.auth import get_current_user + from app.domains.auth.store import _save_user user = await get_current_user(request) if not user: @@ -570,7 +571,7 @@ async def confirm_crypto_payment(req: CryptoPaymentRequest, request: Request): @router.post("/subscription/cancel") async def cancel_subscription(request: Request): """Cancel subscription at period end.""" - from app.auth import get_current_user + from app.domains.auth import get_current_user user = await get_current_user(request) if not user: @@ -596,7 +597,7 @@ async def cancel_subscription(request: Request): @router.post("/subscription/upgrade") async def upgrade_subscription(tier: str, request: Request): """Upgrade to a higher tier.""" - from app.auth import get_current_user + from app.domains.auth import get_current_user user = await get_current_user(request) if not user: @@ -636,7 +637,7 @@ async def upgrade_subscription(tier: str, request: Request): @router.post("/webhooks/stripe") async def stripe_webhook(request: Request): """Handle Stripe webhooks for subscription events.""" - from app.auth import _get_user, _save_user + from app.domains.auth.store import _get_user, _save_user payload = await request.body() sig_header = request.headers.get("stripe-signature") @@ -681,7 +682,6 @@ async def stripe_webhook(request: Request): event["data"]["object"] # Mark subscription as past_due # TODO: Implement - pass return {"status": "ok"} @@ -698,7 +698,7 @@ async def list_all_subscriptions( offset: int = 0, ): """List all subscriptions (admin only).""" - from app.auth import get_current_user + from app.domains.auth import get_current_user user = await get_current_user(request) if not user or user.get("role") not in ("ADMIN", "SUPERADMIN"): @@ -732,8 +732,8 @@ async def list_all_subscriptions( @router.get("/admin/revenue") async def get_revenue_stats(request: Request): """Get revenue statistics (admin only).""" - from app.auth import get_current_user from app.core.redis import get_redis + from app.domains.auth import get_current_user user = await get_current_user(request) if not user or user.get("role") not in ("ADMIN", "SUPERADMIN"): diff --git a/app/routers/x402_dashboard.py b/app/routers/x402_dashboard.py index 42fa60f..07e3101 100644 --- a/app/routers/x402_dashboard.py +++ b/app/routers/x402_dashboard.py @@ -53,7 +53,7 @@ def _get_redis(): async def _get_redis_async(): """Async Redis client for dashboard queries.""" try: - from app.auth import get_redis + from app.core.redis import get_redis r = await get_redis() return r diff --git a/app/routers/x402_middleware.py b/app/routers/x402_middleware.py index fc650ec..a2c9d96 100644 --- a/app/routers/x402_middleware.py +++ b/app/routers/x402_middleware.py @@ -338,7 +338,7 @@ async def verify_receipt_public(receipt_id: str): Returns: receipt data + on-chain proof + verification status. """ try: - from app.auth import get_redis + from app.core.redis import get_redis r = await get_redis() @@ -404,7 +404,7 @@ async def payment_ledger( No wallet addresses, no PII. """ try: - from app.auth import get_redis + from app.core.redis import get_redis r = await get_redis() @@ -471,7 +471,7 @@ async def transparency_dashboard(hours: int = 24): No sensitive data - all aggregated and anonymized. """ try: - from app.auth import get_redis + from app.core.redis import get_redis r = await get_redis() @@ -619,7 +619,7 @@ async def verify_payment_endpoint( # Store verification result for audit trail if result["verified"]: try: - from app.auth import get_redis + from app.core.redis import get_redis r = await get_redis() verify_key = f"x402:verify:{result.get('settlement_id') or str(time.time())}" @@ -709,7 +709,7 @@ async def store_receipt(request: Request): amount_float = 0.0 # Store in Redis (sync - app.auth.get_redis returns a sync client) - from app.auth import get_redis as _get_redis + from app.core.redis import get_redis as _get_redis r = _get_redis() @@ -804,7 +804,7 @@ async def fallback_status(): Shows which fallback layers are working and which are failing. """ try: - from app.auth import get_redis + from app.core.redis import get_redis r = await get_redis() diff --git a/app/routers/x402_settle_api.py b/app/routers/x402_settle_api.py index 2bb8d5d..a857ab9 100644 --- a/app/routers/x402_settle_api.py +++ b/app/routers/x402_settle_api.py @@ -119,7 +119,7 @@ async def settle_x402(req: SettleRequest, request: Request): Then activates the subscription / add-on for the user. """ - from app.auth import get_current_user + from app.domains.auth import get_current_user try: user = await get_current_user(request) @@ -187,7 +187,7 @@ async def settle_x402(req: SettleRequest, request: Request): # Also write the user_metadata flag so /api/v1/portfolio/features picks it up try: - from app.auth import _save_user + from app.domains.auth.store import _save_user md = (user.get("user_metadata") or {}).copy() if addon == "PORTFOLIO_PRO": diff --git a/app/scan_rate_limiter.py b/app/scan_rate_limiter.py index 1f87a4b..b80bef7 100644 --- a/app/scan_rate_limiter.py +++ b/app/scan_rate_limiter.py @@ -350,7 +350,7 @@ def get_identity(request) -> tuple[str, str]: auth = request.headers.get("Authorization", "") if hasattr(request, "headers") else "" if auth.startswith("Bearer "): try: - from app.auth import _verify_jwt + from app.domains.auth.jwt import _verify_jwt payload = _verify_jwt(auth[7:]) if payload: