Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions ogc/edr/edr_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import pygeoapi.plugin
import pygeoapi.api
from typing import Tuple, Any, Dict, Generator
from werkzeug.security import safe_join
from http import HTTPStatus
from copy import deepcopy
from pygeoapi.openapi import get_oas
Expand Down Expand Up @@ -107,11 +108,13 @@ def static_files(self, request: pygeoapi.api.APIRequest, file_path: str) -> Tupl
static_path = os.path.join(os.path.dirname(pygeoapi.__file__), "static")
if "templates" in self.api.config["server"]:
static_path = self.api.config["server"]["templates"].get("static", static_path)
file_path = os.path.join(static_path, file_path)
if os.path.isfile(file_path):
mime_type, _ = mimetypes.guess_type(file_path)

# Use a safe join to ensure the untrusted path is a subpath of the trusted static directory
safe_path = safe_join(static_path, file_path)
if safe_path is not None and os.path.isfile(safe_path):
mime_type, _ = mimetypes.guess_type(safe_path)
mime_type = mime_type or "application/octet-stream"
with open(file_path, "rb") as f:
with open(safe_path, "rb") as f:
content = f.read()
return {"Content-Type": mime_type}, HTTPStatus.OK, content
else:
Expand Down
14 changes: 14 additions & 0 deletions ogc/edr/test/test_edr_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,20 @@ def test_edr_routes_static_files_valid_path():
assert headers["Content-Type"] == "image/png"


def test_edr_routes_static_files_prevents_path_traversal():
"""Test the EDR static routes prevents path traversal."""
request = mock_request()
edr_routes = EdrRoutes(layers=[])

static_path = os.path.join(os.path.dirname(__file__), "..", "static")
file_path = os.path.join(os.path.dirname(__file__), "..")
with tempfile.NamedTemporaryFile(dir=file_path) as temp_file:
relative_path = os.path.relpath(temp_file.name, static_path)
_, status, _ = edr_routes.static_files(request, relative_path)
assert os.path.exists(temp_file.name)
assert status == HTTPStatus.NOT_FOUND


def test_edr_routes_static_files_invalid_path():
"""Test the EDR static routes with an invalid static file path."""
request = mock_request()
Expand Down
22 changes: 22 additions & 0 deletions ogc/test/test_servers.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import os
import tempfile
from ogc import servers
from ogc import core
from ogc import podpac as pogc
Expand Down Expand Up @@ -179,6 +181,26 @@ def test_edr_render_post_returns_405(enable_edr_in_env, client):
assert response.status_code == 405


def test_edr_render_static_file_returns_200(enable_edr_in_env, client):
static_path = os.path.join(os.path.dirname(__file__), "..", "edr", "static")
file_path = static_path
with tempfile.NamedTemporaryFile(dir=file_path) as temp_file:
relative_path = os.path.relpath(temp_file.name, static_path)
response = client.get(f"/ogc/edr/static/{relative_path}")
assert os.path.exists(temp_file.name)
assert response.status_code == 200


def test_edr_render_static_file_path_traversal_returns_404(enable_edr_in_env, client):
static_path = os.path.join(os.path.dirname(__file__), "..", "edr", "static")
file_path = os.path.join(os.path.dirname(__file__), "..", "edr")
with tempfile.NamedTemporaryFile(dir=file_path) as temp_file:
relative_path = os.path.relpath(temp_file.name, static_path)
response = client.get(f"/ogc/edr/static/{relative_path}")
assert os.path.exists(temp_file.name)
assert response.status_code == 404


def test_edr_render_query_string_too_long_returns_400(enable_edr_in_env, client):
oversized = "f=json&" + "A=" + "B" * settings.MAX_QUERY_STRING_BYTES
response = client.get("/ogc/edr", environ_overrides={"QUERY_STRING": oversized})
Expand Down
Loading