back to format

This commit is contained in:
MiXaiLL76 2026-03-31 00:29:16 +03:00
parent 11cebdf904
commit f1199eb6ca
2 changed files with 104 additions and 89 deletions

View file

@ -1,13 +1,14 @@
import logging
import uuid
from typing import Optional
from open_webui.internal.db import Base, get_db_context
from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import Session
from open_webui.internal.db import Base, JSONField, get_db, get_db_context
from open_webui.models.users import User, UserModel, UserProfileImageResponse, Users
from open_webui.utils.validate import validate_profile_image_url
from pydantic import BaseModel, field_validator
from sqlalchemy import Boolean, Column, String, Text
from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import Session
log = logging.getLogger(__name__)
@ -43,7 +44,7 @@ class Token(BaseModel):
class ApiKey(BaseModel):
api_key: str | None = None
api_key: Optional[str] = None
class SigninResponse(Token, UserProfileImageResponse):
@ -73,18 +74,18 @@ class SignupForm(BaseModel):
name: str
email: str
password: str
profile_image_url: str | None = '/user.png'
profile_image_url: Optional[str] = '/user.png'
@field_validator('profile_image_url')
@classmethod
def check_profile_image_url(cls, v: str | None) -> str | None:
def check_profile_image_url(cls, v: Optional[str]) -> Optional[str]:
if v is not None:
return validate_profile_image_url(v)
return v
class AddUserForm(SignupForm):
role: str | None = 'pending'
role: Optional[str] = 'pending'
class AuthsTable:
@ -95,10 +96,10 @@ class AuthsTable:
name: str,
profile_image_url: str = '/user.png',
role: str = 'pending',
oauth: dict | None = None,
db: Session | None = None,
id: str | None = None,
) -> UserModel | None:
oauth: Optional[dict] = None,
db: Optional[Session] = None,
id: Optional[str] = None,
) -> Optional[UserModel]:
with get_db_context(db) as db:
log.info('insert_new_auth')
@ -156,7 +157,9 @@ class AuthsTable:
log.error(f'Failed to insert auth: {str(e)}')
return None
def authenticate_user(self, email: str, verify_password: callable, db: Session | None = None) -> UserModel | None:
def authenticate_user(
self, email: str, verify_password: callable, db: Optional[Session] = None
) -> Optional[UserModel]:
log.info(f'authenticate_user: {email}')
user = Users.get_user_by_email(email, db=db)
@ -176,8 +179,8 @@ class AuthsTable:
except Exception:
return None
def authenticate_user_by_api_key(self, api_key: str, db: Session | None = None) -> UserModel | None:
log.info('authenticate_user_by_api_key')
def authenticate_user_by_api_key(self, api_key: str, db: Optional[Session] = None) -> Optional[UserModel]:
log.info(f'authenticate_user_by_api_key')
# if no api_key, return None
if not api_key:
return None
@ -188,7 +191,7 @@ class AuthsTable:
except Exception:
return False
def authenticate_user_by_email(self, email: str, db: Session | None = None) -> UserModel | None:
def authenticate_user_by_email(self, email: str, db: Optional[Session] = None) -> Optional[UserModel]:
log.info(f'authenticate_user_by_email: {email}')
try:
with get_db_context(db) as db:
@ -206,7 +209,7 @@ class AuthsTable:
except Exception:
return None
def update_user_password_by_id(self, id: str, new_password: str, db: Session | None = None) -> bool:
def update_user_password_by_id(self, id: str, new_password: str, db: Optional[Session] = None) -> bool:
try:
with get_db_context(db) as db:
result = db.query(Auth).filter_by(id=id).update({'password': new_password})
@ -215,7 +218,7 @@ class AuthsTable:
except Exception:
return False
def update_email_by_id(self, id: str, email: str, db: Session | None = None) -> bool:
def update_email_by_id(self, id: str, email: str, db: Optional[Session] = None) -> bool:
try:
with get_db_context(db) as db:
result = db.query(Auth).filter_by(id=id).update({'email': email})
@ -227,7 +230,7 @@ class AuthsTable:
except Exception:
return False
def delete_auth_by_id(self, id: str, db: Session | None = None) -> bool:
def delete_auth_by_id(self, id: str, db: Optional[Session] = None) -> bool:
try:
with get_db_context(db) as db:
# Delete User
@ -244,4 +247,4 @@ class AuthsTable:
return False
Auths = AuthsTable()
Auths = AuthsTable()

View file

@ -1,79 +1,91 @@
import asyncio
import re
import uuid
import time
import datetime
import logging
import re
import time
import urllib
import uuid
from ssl import CERT_NONE, CERT_REQUIRED, PROTOCOL_TLS
from aiohttp import ClientSession
from fastapi import APIRouter, Depends, HTTPException, Request, status
from fastapi.responses import JSONResponse, Response
from ldap3 import NONE, Connection, Server, Tls
from ldap3.utils.conv import escape_filter_chars
from open_webui.config import (
ENABLE_PASSWORD_AUTH,
OAUTH_MERGE_ACCOUNTS_BY_EMAIL,
OAUTH_PROVIDERS,
OPENID_END_SESSION_ENDPOINT,
OPENID_PROVIDER_URL,
)
from open_webui.constants import ERROR_MESSAGES, WEBHOOK_MESSAGES
from open_webui.env import (
ENABLE_INITIAL_ADMIN_SIGNUP,
ENABLE_OAUTH_TOKEN_EXCHANGE,
WEBUI_AUTH,
WEBUI_AUTH_COOKIE_SAME_SITE,
WEBUI_AUTH_COOKIE_SECURE,
WEBUI_AUTH_SIGNOUT_REDIRECT_URL,
WEBUI_AUTH_TRUSTED_EMAIL_HEADER,
WEBUI_AUTH_TRUSTED_GROUPS_HEADER,
WEBUI_AUTH_TRUSTED_NAME_HEADER,
WEBUI_AUTH_TRUSTED_ROLE_HEADER,
)
from open_webui.internal.db import get_session
import urllib
from open_webui.models.auths import (
AddUserForm,
ApiKey,
Auths,
Token,
LdapForm,
SigninForm,
SigninResponse,
SignupForm,
Token,
UpdatePasswordForm,
)
from open_webui.models.groups import Groups
from open_webui.models.oauth_sessions import OAuthSessions
from open_webui.models.users import (
UpdateProfileForm,
UserModel,
UserProfileImageResponse,
Users,
UpdateProfileForm,
UserStatus,
)
from open_webui.utils.access_control import get_permissions, has_permission
from open_webui.models.groups import Groups
from open_webui.models.oauth_sessions import OAuthSessions
from open_webui.constants import ERROR_MESSAGES, WEBHOOK_MESSAGES
from open_webui.env import (
WEBUI_AUTH,
WEBUI_AUTH_TRUSTED_EMAIL_HEADER,
WEBUI_AUTH_TRUSTED_NAME_HEADER,
WEBUI_AUTH_TRUSTED_GROUPS_HEADER,
WEBUI_AUTH_TRUSTED_ROLE_HEADER,
WEBUI_AUTH_COOKIE_SAME_SITE,
WEBUI_AUTH_COOKIE_SECURE,
WEBUI_AUTH_SIGNOUT_REDIRECT_URL,
ENABLE_INITIAL_ADMIN_SIGNUP,
ENABLE_OAUTH_TOKEN_EXCHANGE,
AIOHTTP_CLIENT_SESSION_SSL,
)
from fastapi import APIRouter, Depends, HTTPException, Request, status
from fastapi.responses import RedirectResponse, Response, JSONResponse
from open_webui.config import (
OPENID_PROVIDER_URL,
OPENID_END_SESSION_ENDPOINT,
ENABLE_OAUTH_SIGNUP,
ENABLE_LDAP,
ENABLE_PASSWORD_AUTH,
OAUTH_PROVIDERS,
OAUTH_MERGE_ACCOUNTS_BY_EMAIL,
)
from pydantic import BaseModel
from open_webui.utils.misc import parse_duration, validate_email_format
from open_webui.utils.auth import (
create_api_key,
create_token,
decode_token,
get_admin_user,
get_current_user,
get_http_authorization_cred,
get_password_hash,
get_verified_user,
invalidate_token,
validate_password,
verify_password,
decode_token,
invalidate_token,
create_api_key,
create_token,
get_admin_user,
get_verified_user,
get_current_user,
get_password_hash,
get_http_authorization_cred,
)
from open_webui.utils.groups import apply_default_group_assignment
from open_webui.utils.misc import parse_duration, validate_email_format
from open_webui.utils.rate_limit import RateLimiter
from open_webui.utils.redis import get_redis_client
from open_webui.utils.webhook import post_webhook
from pydantic import BaseModel
from open_webui.internal.db import get_session
from sqlalchemy.orm import Session
from open_webui.utils.webhook import post_webhook
from open_webui.utils.access_control import get_permissions, has_permission
from open_webui.utils.groups import apply_default_group_assignment
from open_webui.utils.redis import get_redis_client
from open_webui.utils.rate_limit import RateLimiter
from typing import Optional, List
from ssl import CERT_NONE, CERT_REQUIRED, PROTOCOL_TLS
from ldap3 import Server, Connection, NONE, Tls
from ldap3.utils.conv import escape_filter_chars
router = APIRouter()
@ -107,7 +119,7 @@ def create_session_response(request: Request, user, db, response: Response = Non
)
if set_cookie and response:
datetime_expires_at = datetime.datetime.fromtimestamp(expires_at, datetime.UTC) if expires_at else None
datetime_expires_at = datetime.datetime.fromtimestamp(expires_at, datetime.timezone.utc) if expires_at else None
max_age = int(expires_delta.total_seconds()) if expires_delta else None
response.set_cookie(
key='token',
@ -140,14 +152,14 @@ def create_session_response(request: Request, user, db, response: Response = Non
class SessionUserResponse(Token, UserProfileImageResponse):
expires_at: int | None = None
permissions: dict | None = None
expires_at: Optional[int] = None
permissions: Optional[dict] = None
class SessionUserInfoResponse(SessionUserResponse, UserStatus):
bio: str | None = None
gender: str | None = None
date_of_birth: datetime.date | None = None
bio: Optional[str] = None
gender: Optional[str] = None
date_of_birth: Optional[datetime.date] = None
@router.get('/', response_model=SessionUserInfoResponse)
@ -178,7 +190,7 @@ async def get_session_user(
response.set_cookie(
key='token',
value=token,
expires=(datetime.datetime.fromtimestamp(expires_at, datetime.UTC) if expires_at else None),
expires=(datetime.datetime.fromtimestamp(expires_at, datetime.timezone.utc) if expires_at else None),
httponly=True, # Ensures the cookie is not accessible via JavaScript
samesite=WEBUI_AUTH_COOKIE_SAME_SITE,
secure=WEBUI_AUTH_COOKIE_SECURE,
@ -617,7 +629,7 @@ async def signin(
name = request.headers.get(WEBUI_AUTH_TRUSTED_NAME_HEADER, email)
try:
name = urllib.parse.unquote(name, encoding='utf-8')
except Exception:
except Exception as e:
pass
if not Users.get_user_by_email(email.lower(), db=db):
@ -1024,7 +1036,7 @@ async def get_admin_config(request: Request, user=Depends(get_admin_user)):
class AdminConfig(BaseModel):
SHOW_ADMIN_DETAILS: bool
ADMIN_EMAIL: str | None = None
ADMIN_EMAIL: Optional[str] = None
WEBUI_URL: str
ENABLE_SIGNUP: bool
ENABLE_API_KEYS: bool
@ -1036,15 +1048,15 @@ class AdminConfig(BaseModel):
ENABLE_COMMUNITY_SHARING: bool
ENABLE_MESSAGE_RATING: bool
ENABLE_FOLDERS: bool
FOLDER_MAX_FILE_COUNT: int | str | None = None
FOLDER_MAX_FILE_COUNT: Optional[int | str] = None
ENABLE_CHANNELS: bool
ENABLE_MEMORIES: bool
ENABLE_NOTES: bool
ENABLE_USER_WEBHOOKS: bool
ENABLE_USER_STATUS: bool
PENDING_USER_OVERLAY_TITLE: str | None = None
PENDING_USER_OVERLAY_CONTENT: str | None = None
RESPONSE_WATERMARK: str | None = None
PENDING_USER_OVERLAY_TITLE: Optional[str] = None
PENDING_USER_OVERLAY_CONTENT: Optional[str] = None
RESPONSE_WATERMARK: Optional[str] = None
@router.post('/admin/config')
@ -1117,7 +1129,7 @@ async def update_admin_config(request: Request, form_data: AdminConfig, user=Dep
class LdapServerConfig(BaseModel):
label: str
host: str
port: int | None = None
port: Optional[int] = None
attribute_for_mail: str = 'mail'
attribute_for_username: str = 'uid'
app_dn: str
@ -1125,9 +1137,9 @@ class LdapServerConfig(BaseModel):
search_base: str
search_filters: str = ''
use_tls: bool = True
certificate_path: str | None = None
certificate_path: Optional[str] = None
validate_cert: bool = True
ciphers: str | None = 'ALL'
ciphers: Optional[str] = 'ALL'
@router.get('/admin/config/ldap/server', response_model=LdapServerConfig)
@ -1200,7 +1212,7 @@ async def get_ldap_config(request: Request, user=Depends(get_admin_user)):
class LdapConfigForm(BaseModel):
enable_ldap: bool | None = None
enable_ldap: Optional[bool] = None
@router.post('/admin/config/ldap')
@ -1323,7 +1335,7 @@ async def token_exchange(
# Get sub claim
sub = user_data.get(request.app.state.config.OAUTH_SUB_CLAIM or OAUTH_PROVIDERS[provider].get('sub_claim', 'sub'))
if not sub:
log.warning('Token exchange failed: sub claim missing from user data')
log.warning(f'Token exchange failed: sub claim missing from user data')
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Token missing required 'sub' claim",
@ -1331,7 +1343,7 @@ async def token_exchange(
email = user_data.get(email_claim, '')
if not email:
log.warning('Token exchange failed: email claim missing from user data')
log.warning(f'Token exchange failed: email claim missing from user data')
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail='Token missing required email claim',