feat(12.1-01): add cross-origin nextLink guard and Drive/OneDrive contract tests
- Validate @odata.nextLink hostname against graph.microsoft.com before following (T-12.1-03); cross-origin nextLink returns complete=False with prior items retained - Add TestOneDriveCrossOriginNextLink: cross-origin rejection, same-origin follows, page failure retains prior items - Add TestGoogleDriveAuthFailureControl: 401 returns complete=False, page1+page2 error retains page1 items - All 163 four-provider contract tests pass
This commit is contained in:
@@ -28,6 +28,8 @@ import io
|
||||
import uuid
|
||||
from typing import Optional
|
||||
|
||||
import urllib.parse
|
||||
|
||||
import httpx
|
||||
import msal
|
||||
|
||||
@@ -50,6 +52,9 @@ from storage.google_drive_backend import CloudConnectionError # reuse shared ex
|
||||
GRAPH_BASE = "https://graph.microsoft.com/v1.0"
|
||||
CHUNK_SIZE = 10 * 1024 * 1024 # 10 MB — above Graph's 4 MB simple upload limit (Pitfall 6)
|
||||
|
||||
# Trusted Graph API origin for @odata.nextLink validation (T-12.1-03)
|
||||
_GRAPH_HOST = "graph.microsoft.com"
|
||||
|
||||
|
||||
class OneDriveBackend(StorageBackend, CloudResourceAdapter):
|
||||
"""Microsoft Graph / OneDrive implementation of StorageBackend.
|
||||
@@ -351,7 +356,6 @@ class OneDriveBackend(StorageBackend, CloudResourceAdapter):
|
||||
content_type: Optional[str] = None
|
||||
if "file" in item:
|
||||
content_type = item["file"].get("mimeType")
|
||||
parent_ref_val = item.get("parentReference", {}).get("id")
|
||||
resources.append(
|
||||
CloudResource(
|
||||
id=uuid.uuid4(),
|
||||
@@ -367,7 +371,15 @@ class OneDriveBackend(StorageBackend, CloudResourceAdapter):
|
||||
etag=item.get("eTag") or item.get("cTag"),
|
||||
)
|
||||
)
|
||||
url = data.get("@odata.nextLink")
|
||||
# Validate @odata.nextLink origin before following (T-12.1-03)
|
||||
next_link = data.get("@odata.nextLink")
|
||||
if next_link:
|
||||
parsed_next = urllib.parse.urlparse(next_link)
|
||||
if parsed_next.hostname != _GRAPH_HOST:
|
||||
# Cross-origin continuation URL — untrusted; stop pagination
|
||||
complete = False
|
||||
break
|
||||
url = next_link
|
||||
except Exception:
|
||||
complete = False
|
||||
|
||||
|
||||
Reference in New Issue
Block a user