Skip to content

Commit

Permalink
Enforce meta key present during preprocess in FileData payloads (#9898
Browse files Browse the repository at this point in the history
)

* add code

* add code

* add changeset

* revert

* use is_file_obj_with_meta

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>
  • Loading branch information
freddyaboulton and gradio-pr-bot authored Nov 4, 2024
1 parent 7d77024 commit dcfa7ad
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 11 deletions.
5 changes: 5 additions & 0 deletions .changeset/four-swans-throw.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"gradio": minor
---

feat:Enforce `meta` key present during preprocess in FileData payloads
17 changes: 7 additions & 10 deletions gradio/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,7 @@
from collections.abc import AsyncIterator, Callable, Coroutine, Sequence, Set
from pathlib import Path
from types import ModuleType
from typing import (
TYPE_CHECKING,
Any,
Literal,
cast,
)
from typing import TYPE_CHECKING, Any, Literal, Union, cast
from urllib.parse import urlparse, urlunparse

import anyio
Expand Down Expand Up @@ -1702,10 +1697,12 @@ async def preprocess_data(
check_in_upload_folder=not explicit_call,
)
if getattr(block, "data_model", None) and inputs_cached is not None:
if issubclass(block.data_model, GradioModel): # type: ignore
inputs_cached = block.data_model(**inputs_cached) # type: ignore
elif issubclass(block.data_model, GradioRootModel): # type: ignore
inputs_cached = block.data_model(root=inputs_cached) # type: ignore
data_model = cast(
Union[GradioModel, GradioRootModel], block.data_model
)
inputs_cached = data_model.model_validate(
inputs_cached, context={"validate_meta": True}
)
processed_input.append(block.preprocess(inputs_cached))
else:
processed_input = inputs
Expand Down
17 changes: 16 additions & 1 deletion gradio/data_classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,15 @@

from fastapi import Request
from gradio_client.documentation import document
from gradio_client.utils import traverse
from gradio_client.utils import is_file_obj_with_meta, traverse
from pydantic import (
BaseModel,
GetCoreSchemaHandler,
GetJsonSchemaHandler,
RootModel,
ValidationError,
ValidationInfo,
model_validator,
)
from pydantic.json_schema import JsonSchemaValue
from pydantic_core import core_schema
Expand Down Expand Up @@ -227,6 +229,19 @@ class FileData(GradioModel):
is_stream: bool = False
meta: dict = {"_type": "gradio.FileData"}

@model_validator(mode="before")
@classmethod
def validate_model(cls, v, info: ValidationInfo):
if (
info.context
and info.context.get("validate_meta")
and not is_file_obj_with_meta(v)
):
raise ValueError(
"The 'meta' field must be explicitly provided in the input data and be equal to {'_type': 'gradio.FileData'}."
)
return v

@property
def is_none(self) -> bool:
"""
Expand Down
28 changes: 28 additions & 0 deletions test/test_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,7 @@ def test_get_file_created_by_app(self, test_client):
{
"path": file_response.json()[0],
"size": os.path.getsize("test/test_files/alphabet.txt"),
"meta": {"_type": "gradio.FileData"},
}
],
"fn_index": 0,
Expand Down Expand Up @@ -1613,3 +1614,30 @@ def victim(url, results):
t.join()

assert not any(results), "attacker was able to modify a victim's config root url"


def test_file_without_meta_key_not_moved():
demo = gr.Interface(
fn=lambda s: str(s), inputs=gr.File(type="binary"), outputs="textbox"
)

app, _, _ = demo.launch(prevent_thread_lock=True)
test_client = TestClient(app)
try:
with test_client:
req = test_client.post(
"gradio_api/run/predict",
json={
"data": [
{
"path": "test/test_files/alphabet.txt",
"orig_name": "test.txt",
"size": 4,
"mime_type": "text/plain",
}
]
},
)
assert req.status_code == 500
finally:
demo.close()

0 comments on commit dcfa7ad

Please sign in to comment.