mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-11-08 13:33:42 +08:00
a82935f326
Integrate onroad views, configurable widgets, local settings, steering-profile contracts, Bluetooth and Android Auto with their device and runtime services. Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com> Co-authored-by: Daniel Koepping <elkoled@gmail.com> Co-authored-by: Danny <dannyirwin31@yahoo.com> Co-authored-by: DimitriChrysafis <Dimitri.chrysafis@gmail.com> Co-authored-by: Dom <168790843+firestar5683@users.noreply.github.com> Co-authored-by: Harald Schäfer <harald.the.engineer@gmail.com> Co-authored-by: Prabhaav Pillai <prabhaav@msu.edu> Co-authored-by: Shane Smiskol <shane@smiskol.com> Co-authored-by: dirwin31 <83434411+dirwin31@users.noreply.github.com> Co-authored-by: firestarsdog <229254897+firestarsdog@users.noreply.github.com> Co-authored-by: stef <19478336+stefpi@users.noreply.github.com> Co-authored-by: whoisdomi <dcantu83@gmail.com> Co-authored-by: Intelli <contact@intelli.software> Co-authored-by: pharmacomaniac <blittle65@gmail.com> Co-authored-by: prabhaavp <prabhaav@msu.edu>
151 lines
6.8 KiB
Python
151 lines
6.8 KiB
Python
import hashlib
|
|
import os
|
|
from pathlib import Path
|
|
import tempfile
|
|
import threading
|
|
import unittest
|
|
from unittest.mock import patch
|
|
|
|
from openpilot.starpilot.galaxy.remote import RemotePairing, default_remote_pairing, gateway_cookie_valid
|
|
|
|
|
|
class TestPairingMigration(unittest.TestCase):
|
|
def setUp(self):
|
|
temporary = tempfile.TemporaryDirectory()
|
|
self.addCleanup(temporary.cleanup)
|
|
self.root = Path(temporary.name)
|
|
self.legacy = self.root / 'legacy'
|
|
self.legacy.mkdir()
|
|
self.values = {'glxyslug': 'ExistingGalaxy01', 'glxyauth': hashlib.sha256(b'old-password').hexdigest(),
|
|
'glxysession': 'a' * 64}
|
|
for key, value in self.values.items():
|
|
(self.legacy / key).write_text(value + '\n')
|
|
self.pairing = RemotePairing(self.root / 'new')
|
|
|
|
def test_default_startup_keeps_link_password_and_session_without_password_entry(self):
|
|
original = {path.name: path.read_bytes() for path in self.legacy.iterdir()}
|
|
with patch('openpilot.starpilot.storage.galaxy_storage_root', return_value=self.pairing.root), \
|
|
patch('openpilot.starpilot.galaxy.access.legacy_galaxy_root', return_value=self.legacy):
|
|
pairing = default_remote_pairing()
|
|
record = pairing.read()
|
|
assert record is not None
|
|
self.assertEqual(record, {'version': 1, 'slug': self.values['glxyslug'], 'authHash': self.values['glxyauth'],
|
|
'session': self.values['glxysession']})
|
|
self.assertEqual(pairing.url(record['slug']), 'https://galaxy.firestar.link/ExistingGalaxy01')
|
|
self.assertTrue(gateway_cookie_valid(record['slug'] + ':' + record['session'], record))
|
|
saved = (pairing.root / pairing.FILE).read_bytes()
|
|
self.assertEqual(default_remote_pairing().read(), record)
|
|
self.assertEqual((pairing.root / pairing.FILE).read_bytes(), saved)
|
|
self.assertEqual((pairing.root / pairing.FILE).stat().st_mode & 0o777, 0o600)
|
|
self.assertEqual({path.name: path.read_bytes() for path in self.legacy.iterdir()}, original)
|
|
self.assertFalse((self.pairing.root / 'access-v1.json').exists())
|
|
|
|
def test_unpair_survives_restart_and_manual_repair_rotates_identity(self):
|
|
self.assertTrue(self.pairing.migrate_legacy(self.legacy))
|
|
old = self.pairing.read()
|
|
assert old is not None
|
|
self.assertTrue(self.pairing.unpair())
|
|
restarted = RemotePairing(self.pairing.root)
|
|
self.assertFalse(restarted.migrate_legacy(self.legacy))
|
|
self.assertIsNone(restarted.read())
|
|
assert restarted.pair(old['authHash'], legacy_root=self.legacy) is not None
|
|
new = restarted.read()
|
|
assert new is not None
|
|
self.assertNotEqual(new['slug'], old['slug'])
|
|
self.assertNotEqual(new['session'], old['session'])
|
|
self.assertFalse(gateway_cookie_valid(old['slug'] + ':' + old['session'], new))
|
|
|
|
def test_existing_and_malformed_destination_are_never_replaced(self):
|
|
assert self.pairing.pair('b' * 64) is not None
|
|
path = self.pairing.root / self.pairing.FILE
|
|
before = path.read_bytes()
|
|
self.assertFalse(self.pairing.migrate_legacy(self.legacy))
|
|
self.assertEqual(path.read_bytes(), before)
|
|
path.write_text('incomplete')
|
|
self.assertFalse(self.pairing.migrate_legacy(self.legacy))
|
|
self.assertIsNone(self.pairing.pair('c' * 64))
|
|
self.assertEqual(path.read_text(), 'incomplete')
|
|
|
|
def test_partial_or_invalid_legacy_does_not_create_pairing(self):
|
|
for name in self.values:
|
|
path = self.legacy / name
|
|
original = path.read_bytes()
|
|
for raw in (None, b'bad', b'x' * 129, b'\xff'):
|
|
with self.subTest(name=name, raw=raw):
|
|
path.unlink(missing_ok=True)
|
|
if raw is not None:
|
|
path.write_bytes(raw)
|
|
self.assertFalse(self.pairing.migrate_legacy(self.legacy))
|
|
self.assertIsNone(self.pairing.read())
|
|
path.write_bytes(original)
|
|
|
|
def test_previous_local_setup_requires_explicit_pairing(self):
|
|
from openpilot.starpilot.galaxy.access import GalaxyAccessOwner
|
|
owner = GalaxyAccessOwner(self.pairing.root)
|
|
self.assertTrue(owner.configure('new-password', lambda: True))
|
|
self.assertFalse(self.pairing.migrate_legacy(self.legacy))
|
|
self.assertIsNone(self.pairing.read())
|
|
self.assertTrue(owner.verify('new-password'))
|
|
assert self.pairing.pair(self.values['glxyauth'], legacy_root=self.legacy) is not None
|
|
|
|
def test_unsafe_legacy_and_destination_paths_are_not_followed(self):
|
|
path = self.legacy / 'glxyslug'
|
|
original = path.read_bytes()
|
|
outside = self.root / 'outside'
|
|
outside.write_bytes(original)
|
|
path.unlink()
|
|
path.symlink_to(outside)
|
|
self.assertFalse(self.pairing.migrate_legacy(self.legacy))
|
|
path.unlink()
|
|
os.mkfifo(path)
|
|
self.assertFalse(self.pairing.migrate_legacy(self.legacy))
|
|
path.unlink()
|
|
path.write_bytes(original)
|
|
outside_dir = self.root / 'outside-dir'
|
|
outside_dir.mkdir(mode=0o700)
|
|
symlink = self.root / 'linked'
|
|
symlink.symlink_to(outside_dir, target_is_directory=True)
|
|
self.assertFalse(RemotePairing(symlink).migrate_legacy(self.legacy))
|
|
self.assertEqual(list(outside_dir.iterdir()), [])
|
|
|
|
def test_storage_failure_leaves_original_pairing_for_retry(self):
|
|
with patch('openpilot.starpilot.galaxy.remote.os.link', side_effect=OSError('disk full')):
|
|
self.assertFalse(self.pairing.migrate_legacy(self.legacy))
|
|
self.assertIsNone(self.pairing.read())
|
|
self.assertTrue(self.pairing.migrate_legacy(self.legacy))
|
|
|
|
def test_concurrent_startups_do_not_resurrect_an_explicit_unpair(self):
|
|
self.assertTrue(self.pairing.migrate_legacy(self.legacy))
|
|
start = threading.Barrier(3)
|
|
results = []
|
|
def import_again():
|
|
start.wait()
|
|
results.append(RemotePairing(self.pairing.root).migrate_legacy(self.legacy))
|
|
def unpair():
|
|
start.wait()
|
|
results.append(RemotePairing(self.pairing.root).unpair())
|
|
workers = [threading.Thread(target=import_again), threading.Thread(target=unpair)]
|
|
for worker in workers:
|
|
worker.start()
|
|
start.wait()
|
|
for worker in workers:
|
|
worker.join(2)
|
|
self.assertFalse(worker.is_alive())
|
|
self.assertCountEqual(results, [False, True])
|
|
self.assertIsNone(self.pairing.read())
|
|
self.assertFalse(self.pairing.migrate_legacy(self.legacy))
|
|
|
|
def test_named_namespace_cannot_import_normal_pairing(self):
|
|
from openpilot.starpilot.galaxy.access import legacy_galaxy_root
|
|
for desktop in (False, True):
|
|
with self.subTest(desktop=desktop), patch.dict(os.environ, {'OPENPILOT_PREFIX': 'isolated-desk'}), \
|
|
patch('openpilot.common.hardware.PC', desktop), \
|
|
patch('openpilot.starpilot.storage.galaxy_storage_root', return_value=self.pairing.root), \
|
|
patch.object(RemotePairing, '_legacy_record', side_effect=AssertionError('legacy access')):
|
|
self.assertIsNone(legacy_galaxy_root())
|
|
self.assertIsNone(default_remote_pairing().read())
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|