diff options
Diffstat (limited to 'packages/meshbay-node/tests')
| -rw-r--r-- | packages/meshbay-node/tests/test_admin_ops_mnp.py | 8 | ||||
| -rw-r--r-- | packages/meshbay-node/tests/test_bundle_store_recovery.py | 76 | ||||
| -rw-r--r-- | packages/meshbay-node/tests/test_webrtc_transport.py | 3 |
3 files changed, 86 insertions, 1 deletions
diff --git a/packages/meshbay-node/tests/test_admin_ops_mnp.py b/packages/meshbay-node/tests/test_admin_ops_mnp.py index 1bf8365..92e50b5 100644 --- a/packages/meshbay-node/tests/test_admin_ops_mnp.py +++ b/packages/meshbay-node/tests/test_admin_ops_mnp.py @@ -100,10 +100,15 @@ async def _session(tmp_path: Path, roster, *, operator: bool) -> WebRTCPeerSessi class _FakeBundleStore: def __init__(self): self.stored = [] + self.deleted_keypairs = [] async def store(self, *args): self.stored.append(args) + async def delete_keypair(self, user_id): + self.deleted_keypairs.append(user_id) + return True + class _FakeHub: class _S: @@ -279,6 +284,9 @@ async def test_the_operator_unpins(tmp_path, roster): assert _last(session)["type"] == MNP.MEMBER_UNPIN_ACK assert await roster.get_identity("bob") is None + # The stored keypair bundle goes too โ left behind it blocks the re-join + # the unpin exists to enable. + assert "bob" in session.state["bundle_store"].deleted_keypairs async def test_unpinning_someone_unknown_says_so(tmp_path, roster): diff --git a/packages/meshbay-node/tests/test_bundle_store_recovery.py b/packages/meshbay-node/tests/test_bundle_store_recovery.py new file mode 100644 index 0000000..10a3400 --- /dev/null +++ b/packages/meshbay-node/tests/test_bundle_store_recovery.py @@ -0,0 +1,76 @@ +""" +The recovery-wrapped keypair copy (docs/auth-confirm.md ยง4.3, MNP 0.14). + +`bundle_enc_recovery` is a second copy of the identity bundle wrapped under the +account's recovery key. The store has to add the column to a database that +predates it, and a plain re-backup that omits the recovery copy must not erase +one already there. +""" + +import aiosqlite +import pytest +from meshbay_node.bundle_store import BundleStore + + +@pytest.mark.asyncio +async def test_round_trip_with_and_without_recovery(tmp_path): + store = BundleStore(db_path=tmp_path / "bundles.db") + await store.open() + + await store.store_keypair("u1", "pass-wrapped-1") + row = await store.fetch_keypair("u1") + assert row == {"bundle_enc": "pass-wrapped-1", "bundle_enc_recovery": None} + + await store.store_keypair("u2", "pass-wrapped-2", "recovery-wrapped-2") + row = await store.fetch_keypair("u2") + assert row["bundle_enc"] == "pass-wrapped-2" + assert row["bundle_enc_recovery"] == "recovery-wrapped-2" + + assert await store.fetch_keypair("nobody") is None + await store.close() + + +@pytest.mark.asyncio +async def test_re_backup_without_recovery_keeps_the_existing_copy(tmp_path): + """A passphrase-change re-wrap sends only bundle_enc; the recovery copy stays.""" + store = BundleStore(db_path=tmp_path / "bundles.db") + await store.open() + + await store.store_keypair("u1", "v1", "recovery-v1") + await store.store_keypair("u1", "v2") # no recovery arg + row = await store.fetch_keypair("u1") + assert row["bundle_enc"] == "v2" + assert row["bundle_enc_recovery"] == "recovery-v1" + + # An explicit new recovery copy does replace it. + await store.store_keypair("u1", "v3", "recovery-v3") + row = await store.fetch_keypair("u1") + assert row == {"bundle_enc": "v3", "bundle_enc_recovery": "recovery-v3"} + await store.close() + + +@pytest.mark.asyncio +async def test_migration_adds_the_column_to_an_old_database(tmp_path): + db_path = tmp_path / "bundles.db" + + # A keypair_bundles table as it looked before MNP 0.14. + async with aiosqlite.connect(str(db_path)) as db: + await db.execute( + "CREATE TABLE keypair_bundles (" + " user_id TEXT PRIMARY KEY," + " bundle_enc TEXT NOT NULL," + " stored_at TEXT NOT NULL DEFAULT (datetime('now')))") + await db.execute( + "INSERT INTO keypair_bundles (user_id, bundle_enc) VALUES ('old', 'legacy')") + await db.commit() + + store = BundleStore(db_path=db_path) + await store.open() # runs the migration + + row = await store.fetch_keypair("old") + assert row == {"bundle_enc": "legacy", "bundle_enc_recovery": None} + + await store.store_keypair("old", "legacy", "recovery-now") + row = await store.fetch_keypair("old") + assert row["bundle_enc_recovery"] == "recovery-now" + await store.close() diff --git a/packages/meshbay-node/tests/test_webrtc_transport.py b/packages/meshbay-node/tests/test_webrtc_transport.py index ec6e987..159ba63 100644 --- a/packages/meshbay-node/tests/test_webrtc_transport.py +++ b/packages/meshbay-node/tests/test_webrtc_transport.py @@ -1359,7 +1359,8 @@ async def test_keypair_bundle_store_and_fetch(sk_node, sk_hub, gek, shared_dir, # Verify in DB stored = await bundle_store.fetch_keypair("user-001") - assert stored == "encrypted-keypair-data-base64" + assert stored["bundle_enc"] == "encrypted-keypair-data-base64" + assert stored["bundle_enc_recovery"] is None await pc1.close() |