feat: 增加认证更新配置与自动检查 (#94)
This commit is contained in:
@@ -1,18 +1,23 @@
|
||||
"""在线更新清单、下载校验和安全解压测试。"""
|
||||
|
||||
import base64
|
||||
import hashlib
|
||||
import io
|
||||
import json
|
||||
import tempfile
|
||||
import unittest
|
||||
import urllib.request
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
|
||||
from src.update_service import (
|
||||
DEFAULT_UPDATE_MANIFEST_URL,
|
||||
UnsafeUpdateArchiveError,
|
||||
UpdateConfigurationError,
|
||||
UpdateIntegrityError,
|
||||
UpdateCredentials,
|
||||
UpdateService,
|
||||
_SameOriginRedirectHandler,
|
||||
mark_current_version_healthy,
|
||||
parse_version,
|
||||
validate_manifest_url,
|
||||
@@ -41,9 +46,11 @@ class FakeUrlOpen:
|
||||
def __init__(self, responses):
|
||||
self.responses = responses
|
||||
self.requested_urls = []
|
||||
self.requested_headers = []
|
||||
|
||||
def __call__(self, request, timeout):
|
||||
self.requested_urls.append((request.full_url, timeout))
|
||||
self.requested_headers.append(dict(request.header_items()))
|
||||
content, final_url = self.responses[request.full_url]
|
||||
return FakeResponse(content, final_url, len(content))
|
||||
|
||||
@@ -107,6 +114,10 @@ class UpdateServiceTest(unittest.TestCase):
|
||||
validate_manifest_url(self.manifest_url),
|
||||
self.manifest_url,
|
||||
)
|
||||
self.assertEqual(
|
||||
validate_manifest_url(DEFAULT_UPDATE_MANIFEST_URL),
|
||||
DEFAULT_UPDATE_MANIFEST_URL,
|
||||
)
|
||||
for invalid in (
|
||||
"http://updates.example.test/manifest.json",
|
||||
"https://user:pass@updates.example.test/manifest.json",
|
||||
@@ -118,6 +129,56 @@ class UpdateServiceTest(unittest.TestCase):
|
||||
):
|
||||
validate_manifest_url(invalid)
|
||||
|
||||
def test_basic_auth_is_used_for_manifest_and_update_without_repr_leak(self):
|
||||
update_content = make_update_zip()
|
||||
service, opener = self.service_with(update_content)
|
||||
credentials = UpdateCredentials("release-reader", "unit-test-password")
|
||||
|
||||
result = service.check(
|
||||
self.manifest_url,
|
||||
"0.1.0",
|
||||
credentials=credentials,
|
||||
)
|
||||
service.download_and_stage(result.update, credentials=credentials)
|
||||
|
||||
expected = "Basic " + base64.b64encode(
|
||||
b"release-reader:unit-test-password"
|
||||
).decode("ascii")
|
||||
self.assertEqual(len(opener.requested_headers), 2)
|
||||
self.assertTrue(
|
||||
all(
|
||||
headers.get("Authorization") == expected
|
||||
for headers in opener.requested_headers
|
||||
)
|
||||
)
|
||||
self.assertNotIn("unit-test-password", repr(credentials))
|
||||
|
||||
def test_default_unicode_manifest_path_is_encoded_for_http_request(self):
|
||||
request = UpdateService._make_request(
|
||||
DEFAULT_UPDATE_MANIFEST_URL,
|
||||
UpdateCredentials("release-reader", "unit-test-password"),
|
||||
)
|
||||
|
||||
self.assertNotIn("——", request.full_url)
|
||||
self.assertIn("%E2%80%94%E2%80%94", request.full_url)
|
||||
|
||||
def test_authenticated_redirect_cannot_change_origin(self):
|
||||
handler = _SameOriginRedirectHandler()
|
||||
request = urllib.request.Request(
|
||||
"https://updates.example.test/manifest.json",
|
||||
headers={"Authorization": "Basic test"},
|
||||
)
|
||||
|
||||
with self.assertRaises(UpdateConfigurationError):
|
||||
handler.redirect_request(
|
||||
request,
|
||||
None,
|
||||
302,
|
||||
"Found",
|
||||
{},
|
||||
"https://other.example.test/manifest.json",
|
||||
)
|
||||
|
||||
def test_check_reports_newer_and_current_versions(self):
|
||||
update_content = make_update_zip()
|
||||
service, _opener = self.service_with(update_content)
|
||||
@@ -196,7 +257,7 @@ class UpdateServiceTest(unittest.TestCase):
|
||||
health = json.loads(
|
||||
(self.update_directory / "healthy.json").read_text(encoding="utf-8")
|
||||
)
|
||||
self.assertEqual(health["version"], "0.2.0")
|
||||
self.assertEqual(health["version"], "0.2.1")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user