|
1 | | -"""Shared GitHub-authenticated HTTP helpers. |
2 | | -
|
3 | | -Used by both ExtensionCatalog and PresetCatalog to attach |
4 | | -GITHUB_TOKEN / GH_TOKEN credentials to requests targeting |
5 | | -GitHub-hosted domains, while preventing token leakage to |
6 | | -third-party hosts on redirects. |
| 1 | +"""Shared GitHub HTTP request helpers. |
| 2 | +
|
| 3 | +Provides ``build_github_request()`` for attaching GITHUB_TOKEN / GH_TOKEN |
| 4 | +credentials to requests targeting GitHub-hosted domains, and |
| 5 | +``resolve_github_release_asset_api_url()`` — used by extensions, presets, |
| 6 | +and workflow URL resolution — to translate browser release-download URLs |
| 7 | +into GitHub REST API asset URLs. Authenticated downloads themselves go |
| 8 | +through the config-driven helpers in :mod:`specify_cli.authentication.http`. |
7 | 9 | """ |
8 | 10 |
|
9 | 11 | import os |
@@ -54,28 +56,6 @@ def build_github_request(url: str) -> urllib.request.Request: |
54 | 56 | return urllib.request.Request(url, headers=headers) |
55 | 57 |
|
56 | 58 |
|
57 | | -class _StripAuthOnRedirect(urllib.request.HTTPRedirectHandler): |
58 | | - """Redirect handler that drops the Authorization header when leaving GitHub. |
59 | | -
|
60 | | - Prevents token leakage to CDNs or other third-party hosts that GitHub |
61 | | - may redirect to (e.g. S3 for release asset downloads, objects.githubusercontent.com). |
62 | | - Auth is preserved as long as the redirect target remains within GITHUB_HOSTS. |
63 | | - """ |
64 | | - |
65 | | - def redirect_request(self, req, fp, code, msg, headers, newurl): |
66 | | - original_auth = req.get_header("Authorization") |
67 | | - new_req = super().redirect_request(req, fp, code, msg, headers, newurl) |
68 | | - if new_req is not None: |
69 | | - hostname = (urlparse(newurl).hostname or "").lower() |
70 | | - if hostname in GITHUB_HOSTS: |
71 | | - if original_auth: |
72 | | - new_req.add_unredirected_header("Authorization", original_auth) |
73 | | - else: |
74 | | - new_req.headers.pop("Authorization", None) |
75 | | - new_req.unredirected_hdrs.pop("Authorization", None) |
76 | | - return new_req |
77 | | - |
78 | | - |
79 | 59 | def resolve_github_release_asset_api_url( |
80 | 60 | download_url: str, |
81 | 61 | open_url_fn: Callable, |
@@ -147,20 +127,3 @@ def resolve_github_release_asset_api_url( |
147 | 127 | return str(asset["url"]) |
148 | 128 |
|
149 | 129 | return None |
150 | | - |
151 | | - |
152 | | -def open_github_url(url: str, timeout: int = 10): |
153 | | - """Open a URL with GitHub auth, stripping the header on cross-host redirects. |
154 | | -
|
155 | | - When the request carries an Authorization header, a custom redirect |
156 | | - handler drops that header if the redirect target is not a GitHub-owned |
157 | | - domain, preventing token leakage to CDNs or other third-party hosts |
158 | | - that GitHub may redirect to (e.g. S3 for release asset downloads). |
159 | | - """ |
160 | | - req = build_github_request(url) |
161 | | - |
162 | | - if not req.get_header("Authorization"): |
163 | | - return urllib.request.urlopen(req, timeout=timeout) |
164 | | - |
165 | | - opener = urllib.request.build_opener(_StripAuthOnRedirect) |
166 | | - return opener.open(req, timeout=timeout) |
0 commit comments