1
0
Fork 0
mirror of https://github.com/mealie-recipes/mealie.git synced 2025-08-02 03:55:22 +02:00

fix: Remove API Tokens from User APIs (#4985)

This commit is contained in:
Michael Genson 2025-01-29 13:52:12 -06:00 committed by GitHub
parent f2eadd2908
commit cb05adeb48
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 41 additions and 4 deletions

View file

@ -93,6 +93,12 @@ export interface GroupSummary {
slug: string; slug: string;
preferences?: ReadGroupPreferences | null; preferences?: ReadGroupPreferences | null;
} }
export interface LongLiveTokenCreateResponse {
name: string;
id: number;
createdAt?: string | null;
token: string;
}
export interface LongLiveTokenIn { export interface LongLiveTokenIn {
name: string; name: string;
integrationId?: string; integrationId?: string;
@ -130,7 +136,6 @@ export interface PrivateUser {
lockedAt?: string | null; lockedAt?: string | null;
} }
export interface LongLiveTokenOut { export interface LongLiveTokenOut {
token: string;
name: string; name: string;
id: number; id: number;
createdAt?: string | null; createdAt?: string | null;

View file

@ -5,14 +5,20 @@ from fastapi import HTTPException, status
from mealie.core.security import create_access_token from mealie.core.security import create_access_token
from mealie.routes._base import BaseUserController, controller from mealie.routes._base import BaseUserController, controller
from mealie.routes._base.routers import UserAPIRouter from mealie.routes._base.routers import UserAPIRouter
from mealie.schema.user import CreateToken, DeleteTokenResponse, LongLiveTokenIn, LongLiveTokenInDB, LongLiveTokenOut from mealie.schema.user import (
CreateToken,
DeleteTokenResponse,
LongLiveTokenCreateResponse,
LongLiveTokenIn,
LongLiveTokenInDB,
)
router = UserAPIRouter(prefix="/users", tags=["Users: Tokens"]) router = UserAPIRouter(prefix="/users", tags=["Users: Tokens"])
@controller(router) @controller(router)
class UserApiTokensController(BaseUserController): class UserApiTokensController(BaseUserController):
@router.post("/api-tokens", status_code=status.HTTP_201_CREATED, response_model=LongLiveTokenOut) @router.post("/api-tokens", status_code=status.HTTP_201_CREATED, response_model=LongLiveTokenCreateResponse)
def create_api_token( def create_api_token(
self, self,
token_params: LongLiveTokenIn, token_params: LongLiveTokenIn,

View file

@ -10,6 +10,7 @@ from .user import (
GroupInDB, GroupInDB,
GroupPagination, GroupPagination,
GroupSummary, GroupSummary,
LongLiveTokenCreateResponse,
LongLiveTokenIn, LongLiveTokenIn,
LongLiveTokenInDB, LongLiveTokenInDB,
LongLiveTokenOut, LongLiveTokenOut,
@ -57,6 +58,7 @@ __all__ = [
"GroupInDB", "GroupInDB",
"GroupPagination", "GroupPagination",
"GroupSummary", "GroupSummary",
"LongLiveTokenCreateResponse",
"LongLiveTokenIn", "LongLiveTokenIn",
"LongLiveTokenInDB", "LongLiveTokenInDB",
"LongLiveTokenOut", "LongLiveTokenOut",

View file

@ -31,7 +31,6 @@ class LongLiveTokenIn(MealieModel):
class LongLiveTokenOut(MealieModel): class LongLiveTokenOut(MealieModel):
token: str
name: str name: str
id: int id: int
created_at: datetime | None = None created_at: datetime | None = None
@ -42,6 +41,12 @@ class LongLiveTokenOut(MealieModel):
return [joinedload(LongLiveToken.user)] return [joinedload(LongLiveToken.user)]
class LongLiveTokenCreateResponse(LongLiveTokenOut):
"""Should ONLY be used when creating a new token, as the token field is sensitive"""
token: str
class CreateToken(LongLiveTokenIn): class CreateToken(LongLiveTokenIn):
user_id: UUID4 user_id: UUID4
token: str token: str

View file

@ -17,6 +17,25 @@ def long_live_token(api_client: TestClient, admin_token):
def test_api_token_creation(api_client: TestClient, admin_token): def test_api_token_creation(api_client: TestClient, admin_token):
response = api_client.post(api_routes.users_api_tokens, json={"name": "Test API Token"}, headers=admin_token) response = api_client.post(api_routes.users_api_tokens, json={"name": "Test API Token"}, headers=admin_token)
assert response.status_code == 201 assert response.status_code == 201
assert response.json()["token"]
def test_api_token_private(api_client: TestClient, admin_token):
response = api_client.post(api_routes.users_api_tokens, json={"name": "Test API Token"}, headers=admin_token)
assert response.status_code == 201
response = api_client.get(api_routes.users, headers=admin_token, params={"perPage": -1})
assert response.status_code == 200
for user in response.json()["items"]:
for user_token in user["tokens"] or []:
assert "token" not in user_token
response = api_client.get(api_routes.users_self, headers=admin_token)
assert response.status_code == 200
response_json = response.json()
assert response_json["tokens"]
for user_token in response_json["tokens"]:
assert "token" not in user_token
def test_use_token(api_client: TestClient, long_live_token): def test_use_token(api_client: TestClient, long_live_token):