feat(map): add protected operations access
This commit is contained in:
@@ -1,5 +1,9 @@
|
||||
import importlib.util
|
||||
import hashlib
|
||||
import hmac
|
||||
import json
|
||||
from pathlib import Path
|
||||
import time
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
@@ -41,6 +45,49 @@ class DashboardTest(unittest.TestCase):
|
||||
self.assertEqual(result["vehicles"][0]["dailyMileageKm"], 12.345)
|
||||
self.assertEqual(result["vehicles"][2]["dailyMileageKm"], 0)
|
||||
|
||||
def test_public_station_directory_uses_an_allowlist(self):
|
||||
stations = [{
|
||||
"id": "GD-1", "name": "广州合作站", "shortName": "合作站", "province": "广东省",
|
||||
"city": "广州市", "district": "黄埔区", "address": "开源大道1号", "longitude": 113.2,
|
||||
"latitude": 23.1, "cooperative": True, "monthlyHydrogenKg": 88.8,
|
||||
"totalHydrogenKg": 999.9, "internalOwner": "must-not-leak",
|
||||
}]
|
||||
with patch.object(server, "_post_open_platform", return_value=stations):
|
||||
with patch.object(server, "_cache", {}):
|
||||
result = server._load_public_stations()
|
||||
|
||||
station = result["stations"][0]
|
||||
self.assertEqual(result["access"]["level"], "public")
|
||||
self.assertEqual(station["name"], "广州合作站")
|
||||
self.assertTrue(station["cooperative"])
|
||||
self.assertNotIn("monthlyHydrogenKg", station)
|
||||
self.assertNotIn("totalHydrogenKg", station)
|
||||
self.assertNotIn("internalOwner", station)
|
||||
|
||||
def test_signed_operations_session_requires_the_operations_scope(self):
|
||||
with patch.object(server, "LOCAL_ACCESS_CODE", "LN-map-test-code"), patch.object(server, "SESSION_SECRET", b"test-session-secret"), patch.object(server, "SESSION_TTL_SECONDS", 600):
|
||||
principal = server._authorizer().authorize_access_code("LN-map-test-code")
|
||||
token = server._create_session(principal)
|
||||
session = server._read_session(f"{server.SESSION_COOKIE_NAME}={token}")
|
||||
|
||||
self.assertEqual(session["subject"], "local-access-code")
|
||||
self.assertIn(server.OPERATIONS_READ_SCOPE, session["scopes"])
|
||||
self.assertIsNone(server._read_session(f"{server.SESSION_COOKIE_NAME}={token}tampered"))
|
||||
|
||||
legacy_payload = {"v": 1, "sub": "legacy", "scopes": [server.OPERATIONS_READ_SCOPE], "exp": 4_102_444_800}
|
||||
legacy_encoded = server._b64encode(server._json_bytes(legacy_payload))
|
||||
legacy_signature = server._b64encode(hmac.new(server.SESSION_SECRET, legacy_encoded.encode("ascii"), hashlib.sha256).digest())
|
||||
self.assertIsNone(server._read_session(f"{server.SESSION_COOKIE_NAME}={legacy_encoded}.{legacy_signature}"))
|
||||
|
||||
def test_default_operations_session_expires_after_thirty_minutes(self):
|
||||
self.assertEqual(server.SESSION_TTL_SECONDS, 1800)
|
||||
with patch.object(server, "SESSION_SECRET", b"test-session-secret"), patch.object(server, "SESSION_TTL_SECONDS", 1800):
|
||||
token = server._create_session({"subject": "test", "scopes": [server.OPERATIONS_READ_SCOPE]})
|
||||
encoded, _ = token.split(".", 1)
|
||||
payload = json.loads(server._b64decode(encoded))
|
||||
self.assertGreaterEqual(payload["exp"], int(time.time()) + 1798)
|
||||
self.assertLessEqual(payload["exp"], int(time.time()) + 1801)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user