Skip to content

Commit

Permalink
Do not send HF token to other domains via /proxy (#4368)
Browse files Browse the repository at this point in the history
* test

* fix

* changelog

* fix, add warnings
  • Loading branch information
abidlabs authored May 31, 2023
1 parent 114f4b4 commit e503ae0
Show file tree
Hide file tree
Showing 7 changed files with 25 additions and 9 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
- Make `Blocks.load` behave like other event listeners (allows chaining `then` off of it) [@anentropic](https://github.com/anentropic/) in [PR 4304](https://github.com/gradio-app/gradio/pull/4304)
- Respect `interactive=True` in output components of a `gr.Interface` by [@abidlabs](https://github.com/abidlabs) in [PR 4356](https://github.com/gradio-app/gradio/pull/4356).
- Remove unused frontend code by [@akx](https://github.com/akx) in [PR 4275](https://github.com/gradio-app/gradio/pull/4275)
- Do not send HF token to other domains via `/proxy` route by [@abidlabs](https://github.com/abidlabs) in [PR 4368](https://github.com/gradio-app/gradio/pull/4368).

## Other Changes:

Expand Down
2 changes: 1 addition & 1 deletion gradio/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -1448,7 +1448,7 @@ def load(
Parameters:
name: Class Method - the name of the model (e.g. "gpt2" or "facebook/bart-base") or space (e.g. "flax-community/spanish-gpt2"), can include the `src` as prefix (e.g. "models/facebook/bart-base")
src: Class Method - the source of the model: `models` or `spaces` (or leave empty if source is provided as a prefix in `name`)
api_key: Class Method - optional access token for loading private Hugging Face Hub models or spaces. Find your token here: https://huggingface.co/settings/tokens
api_key: Class Method - optional access token for loading private Hugging Face Hub models or spaces. Find your token here: https://huggingface.co/settings/tokens. Warning: only provide this if you are loading a trusted private Space as it can be read by the Space you are loading.
alias: Class Method - optional string used as the name of the loaded model instead of the default name (only applies if loading a Space running Gradio 2.x)
fn: Instance Method - the function to wrap an interface around. Often a machine learning model's prediction function. Each parameter of the function corresponds to one input component, and the function should return a single value or a tuple of values, with each element in the tuple corresponding to one output component.
inputs: Instance Method - List of gradio.components to use as inputs. If the function takes no inputs, this should be an empty list.
Expand Down
2 changes: 1 addition & 1 deletion gradio/external.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def load(
name: the name of the model (e.g. "gpt2" or "facebook/bart-base") or space (e.g. "flax-community/spanish-gpt2"), can include the `src` as prefix (e.g. "models/facebook/bart-base")
src: the source of the model: `models` or `spaces` (or leave empty if source is provided as a prefix in `name`)
api_key: Deprecated. Please use the `hf_token` parameter instead.
hf_token: optional access token for loading private Hugging Face Hub models or spaces. Find your token here: https://huggingface.co/settings/tokens
hf_token: optional access token for loading private Hugging Face Hub models or spaces. Find your token here: https://huggingface.co/settings/tokens. Warning: only provide this if you are loading a trusted private Space as it can be read by the Space you are loading.
alias: optional string used as the name of the loaded model instead of the default name (only applies if loading a Space running Gradio 2.x)
Returns:
a Gradio Blocks object for the given model
Expand Down
2 changes: 1 addition & 1 deletion gradio/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ def load(
Parameters:
name: the name of the model (e.g. "gpt2" or "facebook/bart-base") or space (e.g. "flax-community/spanish-gpt2"), can include the `src` as prefix (e.g. "models/facebook/bart-base")
src: the source of the model: `models` or `spaces` (or leave empty if source is provided as a prefix in `name`)
api_key: optional access token for loading private Hugging Face Hub models or spaces. Find your token here: https://huggingface.co/settings/tokens
api_key: optional access token for loading private Hugging Face Hub models or spaces. Find your token here: https://huggingface.co/settings/tokens. Warning: only provide this if you are loading a trusted private Space as it can be read by the Space you are loading.
alias: optional string used as the name of the loaded model instead of the default name (only applies if loading a Space running Gradio 2.x)
Returns:
a Gradio Interface object for the given model
Expand Down
16 changes: 11 additions & 5 deletions gradio/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,16 @@ def get_blocks(self) -> gradio.Blocks:
raise ValueError("No Blocks has been configured for this app.")
return self.blocks

@staticmethod
def build_proxy_request(url_path):
url = httpx.URL(url_path)
is_hf_url = url.host.endswith(".hf.space")
headers = {}
if Context.hf_token is not None and is_hf_url:
headers["Authorization"] = f"Bearer {Context.hf_token}"
rp_req = client.build_request("GET", url, headers=headers)
return rp_req

@staticmethod
def create_app(
blocks: gradio.Blocks, app_kwargs: Dict[str, Any] | None = None
Expand Down Expand Up @@ -300,11 +310,7 @@ async def favicon():
@app.get("/proxy={url_path:path}", dependencies=[Depends(login_check)])
async def reverse_proxy(url_path: str):
# Adapted from: https://github.com/tiangolo/fastapi/issues/1788
url = httpx.URL(url_path)
headers = {}
if Context.hf_token is not None:
headers["Authorization"] = f"Bearer {Context.hf_token}"
rp_req = client.build_request("GET", url, headers=headers)
rp_req = app.build_proxy_request(url_path)
rp_resp = await client.send(rp_req, stream=True)
return StreamingResponse(
rp_resp.aiter_raw(),
Expand Down
2 changes: 1 addition & 1 deletion test/test_external.py
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ def test_multiple_spaces_one_private(self):
def test_loading_files_via_proxy_works(self):
api_key = "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" # Intentionally revealing this key for testing purposes
io = gr.load(
"spaces/gradio-tests/test-loading-examples-private", api_key=api_key
"spaces/gradio-tests/test-loading-examples-private", hf_token=api_key
)
assert io.theme.name == "default"
app, _, _ = io.launch(prevent_thread_lock=True)
Expand Down
9 changes: 9 additions & 0 deletions test/test_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,15 @@ def test_mount_gradio_app_raises_error_if_event_queued_but_queue_disabled(self):

demo.close()

def test_proxy_does_not_leak_hf_token_externally(self):
gr.context.Context.hf_token = "abcdef"
r = routes.App.build_proxy_request(
"https://gradio-tests-test-loading-examples-private.hf.space/file=Bunny.obj"
)
assert "authorization" in dict(r.headers)
r = routes.App.build_proxy_request("https://google.com")
assert "authorization" not in dict(r.headers)


class TestApp:
def test_create_app(self):
Expand Down

0 comments on commit e503ae0

Please sign in to comment.