utils.py 3.76 KB
Newer Older
1
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
Timothy J. Baek's avatar
Timothy J. Baek committed
2
from fastapi import HTTPException, status, Depends, Request
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
3

4
from apps.webui.models.users import Users
liu.vaayne's avatar
liu.vaayne committed
5

6
7
from pydantic import BaseModel
from typing import Union, Optional
8
from constants import ERROR_MESSAGES
9
10
11
12
from passlib.context import CryptContext
from datetime import datetime, timedelta
import requests
import jwt
liu.vaayne's avatar
liu.vaayne committed
13
import uuid
Timothy J. Baek's avatar
Timothy J. Baek committed
14
import logging
15
16
import config

Timothy J. Baek's avatar
Timothy J. Baek committed
17
18
19
logging.getLogger("passlib").setLevel(logging.ERROR)


20
SESSION_SECRET = config.WEBUI_SECRET_KEY
21
22
23
24
25
26
ALGORITHM = "HS256"

##############
# Auth Utils
##############

Timothy J. Baek's avatar
Timothy J. Baek committed
27
bearer_security = HTTPBearer(auto_error=False)
28
29
30
31
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")


def verify_password(plain_password, hashed_password):
Timothy J. Baek's avatar
Timothy J. Baek committed
32
33
34
    return (
        pwd_context.verify(plain_password, hashed_password) if hashed_password else None
    )
35
36
37
38
39
40


def get_password_hash(password):
    return pwd_context.hash(password)


Timothy J. Baek's avatar
Timothy J. Baek committed
41
def create_token(data: dict, expires_delta: Union[timedelta, None] = None) -> str:
42
43
44
45
46
47
    payload = data.copy()

    if expires_delta:
        expire = datetime.utcnow() + expires_delta
        payload.update({"exp": expire})

48
    encoded_jwt = jwt.encode(payload, SESSION_SECRET, algorithm=ALGORITHM)
49
50
51
52
53
    return encoded_jwt


def decode_token(token: str) -> Optional[dict]:
    try:
54
        decoded = jwt.decode(token, SESSION_SECRET, algorithms=[ALGORITHM])
55
56
57
58
59
60
        return decoded
    except Exception as e:
        return None


def extract_token_from_auth_header(auth_header: str):
Timothy J. Baek's avatar
Timothy J. Baek committed
61
    return auth_header[len("Bearer ") :]
62
63


liu.vaayne's avatar
liu.vaayne committed
64
65
66
67
68
def create_api_key():
    key = str(uuid.uuid4()).replace("-", "")
    return f"sk-{key}"


Timothy J. Baek's avatar
Timothy J. Baek committed
69
70
71
def get_http_authorization_cred(auth_header: str):
    try:
        scheme, credentials = auth_header.split(" ")
Timothy J. Baek's avatar
Timothy J. Baek committed
72
        return HTTPAuthorizationCredentials(scheme=scheme, credentials=credentials)
Timothy J. Baek's avatar
Timothy J. Baek committed
73
74
75
76
    except:
        raise ValueError(ERROR_MESSAGES.INVALID_TOKEN)


Timothy J. Baek's avatar
Timothy J. Baek committed
77
def get_current_user(
Timothy J. Baek's avatar
Timothy J. Baek committed
78
    request: Request,
Timothy J. Baek's avatar
Timothy J. Baek committed
79
80
    auth_token: HTTPAuthorizationCredentials = Depends(bearer_security),
):
Timothy J. Baek's avatar
fix  
Timothy J. Baek committed
81
    token = None
Timothy J. Baek's avatar
Timothy J. Baek committed
82
83
84
85

    if auth_token is not None:
        token = auth_token.credentials

Timothy J. Baek's avatar
fix  
Timothy J. Baek committed
86
87
88
89
90
91
    if token is None and "token" in request.cookies:
        token = request.cookies.get("token")

    if token is None:
        raise HTTPException(status_code=403, detail="Not authenticated")

liu.vaayne's avatar
liu.vaayne committed
92
    # auth by api key
Timothy J. Baek's avatar
Timothy J. Baek committed
93
94
95
    if token.startswith("sk-"):
        return get_current_user_by_api_key(token)

liu.vaayne's avatar
liu.vaayne committed
96
    # auth by jwt token
Timothy J. Baek's avatar
Timothy J. Baek committed
97
    data = decode_token(token)
98
99
    if data != None and "id" in data:
        user = Users.get_user_by_id(data["id"])
100
101
102
103
        if user is None:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail=ERROR_MESSAGES.INVALID_TOKEN,
104
            )
Timothy J. Baek's avatar
Timothy J. Baek committed
105
106
        else:
            Users.update_user_last_active_by_id(user.id)
107
        return user
108
109
110
111
112
    else:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail=ERROR_MESSAGES.UNAUTHORIZED,
        )
113

Timothy J. Baek's avatar
Timothy J. Baek committed
114

liu.vaayne's avatar
liu.vaayne committed
115
def get_current_user_by_api_key(api_key: str):
Timothy J. Baek's avatar
fix  
Timothy J. Baek committed
116
    user = Users.get_user_by_api_key(api_key)
Timothy J. Baek's avatar
Timothy J. Baek committed
117

liu.vaayne's avatar
liu.vaayne committed
118
119
120
121
122
    if user is None:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail=ERROR_MESSAGES.INVALID_TOKEN,
        )
Timothy J. Baek's avatar
Timothy J. Baek committed
123
124
125
    else:
        Users.update_user_last_active_by_id(user.id)

liu.vaayne's avatar
liu.vaayne committed
126
    return user
127

Timothy J. Baek's avatar
Timothy J. Baek committed
128

Timothy J. Baek's avatar
Timothy J. Baek committed
129
def get_verified_user(user=Depends(get_current_user)):
130
131
132
133
134
    if user.role not in {"user", "admin"}:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail=ERROR_MESSAGES.ACCESS_PROHIBITED,
        )
Timothy J. Baek's avatar
Timothy J. Baek committed
135
    return user
136
137


Timothy J. Baek's avatar
Timothy J. Baek committed
138
def get_admin_user(user=Depends(get_current_user)):
139
140
141
142
143
    if user.role != "admin":
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail=ERROR_MESSAGES.ACCESS_PROHIBITED,
        )
Timothy J. Baek's avatar
Timothy J. Baek committed
144
    return user