File size: 2,443 Bytes
a4f74f3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
"""
Authentication routes with planted bugs.

BUGS PLANTED:
- BUG_AUTH_01 (hard): Auth tokens are not user-scoped — any valid token works for any user's resources
- BUG_AUTH_02 (medium): Login with empty password succeeds (missing validation)
"""

import uuid
from datetime import datetime, timedelta

from fastapi import APIRouter, Depends, Header, HTTPException
from typing import Optional

from ..database import Database
from ..models import LoginRequest, LoginResponse

router = APIRouter(prefix="/auth", tags=["auth"])

_db: Database | None = None


def set_db(db: Database):
    global _db
    _db = db


def get_db() -> Database:
    return _db


def get_current_user(authorization: Optional[str] = Header(None)) -> dict | None:
    """Extract user from auth token.

    BUG_AUTH_01: Returns the token's user but doesn't enforce ownership anywhere.
    The routes that use this don't check if the resource belongs to the user.
    """
    if not authorization:
        return None
    token = authorization.replace("Bearer ", "")
    db = get_db()
    rows = db.execute(
        "SELECT u.id, u.username, u.role FROM auth_tokens t JOIN users u ON t.user_id = u.id WHERE t.token = ?",
        (token,),
    )
    if not rows:
        return None
    return rows[0]


@router.post("/login", response_model=LoginResponse)
def login(req: LoginRequest):
    db = get_db()

    # BUG_AUTH_02: Empty password check is missing — empty password matches hash
    # Should validate: if not req.password: raise HTTPException(400, ...)
    rows = db.execute(
        "SELECT id, username, role, password_hash FROM users WHERE username = ?",
        (req.username,),
    )
    if not rows:
        raise HTTPException(status_code=401, detail="Invalid credentials")

    user = rows[0]
    # BUG_AUTH_02 continued: Only checks username, not password properly
    # In a real system we'd verify the password hash
    # Here we just check if password is non-empty... but we don't!
    # Any password (including empty string) works as long as username exists.

    token = str(uuid.uuid4())
    expires = datetime.utcnow() + timedelta(hours=24)
    db.execute_insert(
        "INSERT INTO auth_tokens (token, user_id, expires_at) VALUES (?, ?, ?)",
        (token, user["id"], expires.isoformat()),
    )

    return LoginResponse(
        token=token,
        user_id=user["id"],
        username=user["username"],
        role=user["role"],
    )