aboutsummaryrefslogtreecommitdiffstats
path: root/packages
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-09-19 14:24:13 +0200
committerChristophe Besson <cbesson@gmail.com>2026-09-19 14:24:13 +0200
commit86188385cbdae1ee90c1dca7a7b9db2edef1ecd4 (patch)
treecc01153f05e84ad6cd34556caecd3f4bc335d0bd /packages
parentd2495a2c4b89fbbfc18cefec83ae96cabdd745e2 (diff)
downloadmeshbay-86188385cbdae1ee90c1dca7a7b9db2edef1ecd4.tar.gz
style: ruff's own fixes, mechanically applied
`ruff check .` had gone unrun long enough to report 568 errors, which is the same as having no linter: the next real finding would have been invisible in the noise. This is the 521 it fixes by itself, in 173 files, and nothing else — the 98 it cannot fix are the next commit. What actually changed: import sorting (225), imports nobody used (87, none of them a re-export — no `__init__.py` is touched, which was the one way this could have broken an import elsewhere), `datetime.timezone.utc` to `datetime.UTC` (69) and `asyncio.TimeoutError` to `TimeoutError` (18), both plain aliases on the 3.12 this project requires, `Optional[X]` to `X | None` (24), and f-strings with nothing to interpolate (19). Checked rather than assumed: every module in the three packages still imports, and the suite is 2893 passed — the same count, test for test, as the merge before it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Diffstat (limited to 'packages')
-rw-r--r--packages/meshbay-common/src/meshbay_common/background.py3
-rw-r--r--packages/meshbay-common/src/meshbay_common/crypto.py10
-rw-r--r--packages/meshbay-common/src/meshbay_common/keyderive.py6
-rw-r--r--packages/meshbay-common/src/meshbay_common/protocol.py4
-rw-r--r--packages/meshbay-common/src/meshbay_common/webcrypto.py3
-rw-r--r--packages/meshbay-common/tests/test_background_tasks.py1
-rw-r--r--packages/meshbay-common/tests/test_handshake.py5
-rw-r--r--packages/meshbay-common/tests/test_js_python_parity.py6
-rw-r--r--packages/meshbay-common/tests/test_keyderive.py4
-rw-r--r--packages/meshbay-common/tests/test_paths.py2
-rw-r--r--packages/meshbay-common/tests/test_webcrypto.py16
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/api/admin.py5
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/api/deps.py2
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/api/federation.py12
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/api/groups.py21
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/api/hub.py2
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/api/moderation.py1
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/api/nodes.py10
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/api/notifications.py6
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/api/revocation.py20
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/api/signaling.py4
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/api/users.py49
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/app.py42
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/auth.py4
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/csam.py5
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/db/__init__.py4
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/db/migrations/env.py6
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/db/migrations/versions/a7b8c9d0e1f2_add_group_last_activity.py11
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/db/migrations/versions/a9b8c7d6e5f4_add_login_throttle.py8
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/db/migrations/versions/b1c2d3e4f5a6_add_hub_settings.py11
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/db/migrations/versions/c3d4e5f6a7b8_group_name_unique_per_owner.py11
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/db/migrations/versions/d28b9caf9f07_initial_schema.py11
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/db/migrations/versions/d4e5f6a7b8c9_add_email_verification.py11
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/db/migrations/versions/e5f6a7b8c9d0_add_mail_quota.py8
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/db/migrations/versions/f1a2b3c4d5e6_add_user_preferences.py11
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/db/models.py14
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/login_throttle.py10
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/mail.py24
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/tasks/cleanup.py10
-rw-r--r--packages/meshbay-hub/tests/conftest.py14
-rw-r--r--packages/meshbay-hub/tests/harness/chat_send_probe.py1
-rw-r--r--packages/meshbay-hub/tests/test_account_deletion.py3
-rw-r--r--packages/meshbay-hub/tests/test_account_pinning.py1
-rw-r--r--packages/meshbay-hub/tests/test_admin_views.py6
-rw-r--r--packages/meshbay-hub/tests/test_asset_versioning.py1
-rw-r--r--packages/meshbay-hub/tests/test_availability_between_members.py8
-rw-r--r--packages/meshbay-hub/tests/test_captcha_host_check.py2
-rw-r--r--packages/meshbay-hub/tests/test_device_auth.py2
-rw-r--r--packages/meshbay-hub/tests/test_group_hosting.py21
-rw-r--r--packages/meshbay-hub/tests/test_group_leave_and_quota.py7
-rw-r--r--packages/meshbay-hub/tests/test_group_membership.py3
-rw-r--r--packages/meshbay-hub/tests/test_group_purge.py13
-rw-r--r--packages/meshbay-hub/tests/test_groups_self_service.py8
-rw-r--r--packages/meshbay-hub/tests/test_hub_api.py29
-rw-r--r--packages/meshbay-hub/tests/test_login_lockout.py9
-rw-r--r--packages/meshbay-hub/tests/test_mail_is_not_a_relay.py13
-rw-r--r--packages/meshbay-hub/tests/test_migrations_reach_head.py3
-rw-r--r--packages/meshbay-hub/tests/test_node_auth.py2
-rw-r--r--packages/meshbay-hub/tests/test_node_ws_auth.py6
-rw-r--r--packages/meshbay-hub/tests/test_notification_dismissal.py1
-rw-r--r--packages/meshbay-hub/tests/test_notifications.py1
-rw-r--r--packages/meshbay-hub/tests/test_notifications_behaviour.py5
-rw-r--r--packages/meshbay-hub/tests/test_packaging_hub_unit.py1
-rw-r--r--packages/meshbay-hub/tests/test_password_change.py3
-rw-r--r--packages/meshbay-hub/tests/test_password_reset.py4
-rw-r--r--packages/meshbay-hub/tests/test_public_groups_toggle.py4
-rw-r--r--packages/meshbay-hub/tests/test_revocation.py4
-rw-r--r--packages/meshbay-hub/tests/test_session_lifetime.py13
-rw-r--r--packages/meshbay-hub/tests/test_session_renewal.py2
-rw-r--r--packages/meshbay-hub/tests/test_table_rows_measured.py3
-rw-r--r--packages/meshbay-node/src/meshbay_node/config.py4
-rw-r--r--packages/meshbay-node/src/meshbay_node/daemon.py39
-rw-r--r--packages/meshbay-node/src/meshbay_node/hub_client.py2
-rw-r--r--packages/meshbay-node/src/meshbay_node/indexer/__init__.py4
-rw-r--r--packages/meshbay-node/src/meshbay_node/indexer/enrich.py6
-rw-r--r--packages/meshbay-node/src/meshbay_node/indexer/enrich_photo.py4
-rw-r--r--packages/meshbay-node/src/meshbay_node/indexer/group_index.py19
-rw-r--r--packages/meshbay-node/src/meshbay_node/indexer/indexer.py11
-rw-r--r--packages/meshbay-node/src/meshbay_node/indexer/title_parse.py2
-rw-r--r--packages/meshbay-node/src/meshbay_node/keystore.py6
-rw-r--r--packages/meshbay-node/src/meshbay_node/ops.py10
-rw-r--r--packages/meshbay-node/src/meshbay_node/replication.py2
-rw-r--r--packages/meshbay-node/src/meshbay_node/revocation.py3
-rw-r--r--packages/meshbay-node/src/meshbay_node/roots.py4
-rw-r--r--packages/meshbay-node/src/meshbay_node/roster.py12
-rw-r--r--packages/meshbay-node/src/meshbay_node/transport/__init__.py4
-rw-r--r--packages/meshbay-node/src/meshbay_node/transport/quic_client.py7
-rw-r--r--packages/meshbay-node/src/meshbay_node/transport/quic_server.py11
-rw-r--r--packages/meshbay-node/src/meshbay_node/transport/tls_cert.py9
-rw-r--r--packages/meshbay-node/src/meshbay_node/transport/webrtc_server.py110
-rw-r--r--packages/meshbay-node/src/meshbay_node/ui/app.py2
-rw-r--r--packages/meshbay-node/src/meshbay_node/uploads.py2
-rw-r--r--packages/meshbay-node/tests/test_admin_ops_mnp.py5
-rw-r--r--packages/meshbay-node/tests/test_app_directories.py1
-rw-r--r--packages/meshbay-node/tests/test_app_directories_signed.py1
-rw-r--r--packages/meshbay-node/tests/test_apps_enabled_policy.py3
-rw-r--r--packages/meshbay-node/tests/test_audio_root_gates_enrichment.py3
-rw-r--r--packages/meshbay-node/tests/test_chat_is_bounded.py1
-rw-r--r--packages/meshbay-node/tests/test_chat_multidevice.py3
-rw-r--r--packages/meshbay-node/tests/test_chat_pagination.py2
-rw-r--r--packages/meshbay-node/tests/test_chat_store.py3
-rw-r--r--packages/meshbay-node/tests/test_cli_dispatch.py3
-rw-r--r--packages/meshbay-node/tests/test_daemon.py13
-rw-r--r--packages/meshbay-node/tests/test_device_linking.py4
-rw-r--r--packages/meshbay-node/tests/test_enrich.py8
-rw-r--r--packages/meshbay-node/tests/test_enrich_photo.py3
-rw-r--r--packages/meshbay-node/tests/test_group_roster.py4
-rw-r--r--packages/meshbay-node/tests/test_hot_reload_survives_client_close.py10
-rw-r--r--packages/meshbay-node/tests/test_hub_client.py13
-rw-r--r--packages/meshbay-node/tests/test_hub_ws_group_claim.py1
-rw-r--r--packages/meshbay-node/tests/test_ice_filter.py2
-rw-r--r--packages/meshbay-node/tests/test_index_cache.py1
-rw-r--r--packages/meshbay-node/tests/test_index_delta_carries_roots.py2
-rw-r--r--packages/meshbay-node/tests/test_index_no_cleartext.py3
-rw-r--r--packages/meshbay-node/tests/test_index_progress.py7
-rw-r--r--packages/meshbay-node/tests/test_indexer.py17
-rw-r--r--packages/meshbay-node/tests/test_keystore.py6
-rw-r--r--packages/meshbay-node/tests/test_leaseless_reads.py5
-rw-r--r--packages/meshbay-node/tests/test_media_cache.py3
-rw-r--r--packages/meshbay-node/tests/test_media_cache_eviction.py1
-rw-r--r--packages/meshbay-node/tests/test_multi_group.py11
-rw-r--r--packages/meshbay-node/tests/test_musicbrainz_enabled_policy.py3
-rw-r--r--packages/meshbay-node/tests/test_node_status.py22
-rw-r--r--packages/meshbay-node/tests/test_partial_uploads.py20
-rw-r--r--packages/meshbay-node/tests/test_peer_session_limits.py6
-rw-r--r--packages/meshbay-node/tests/test_platform.py2
-rw-r--r--packages/meshbay-node/tests/test_poster_cache.py1
-rw-r--r--packages/meshbay-node/tests/test_quic_transport.py10
-rw-r--r--packages/meshbay-node/tests/test_rename_reenrichment.py3
-rw-r--r--packages/meshbay-node/tests/test_replug_restores_enrichment.py4
-rw-r--r--packages/meshbay-node/tests/test_root_availability.py2
-rw-r--r--packages/meshbay-node/tests/test_root_eject.py1
-rw-r--r--packages/meshbay-node/tests/test_root_ops_reach_the_live_set.py1
-rw-r--r--packages/meshbay-node/tests/test_root_paths_are_operator_only.py1
-rw-r--r--packages/meshbay-node/tests/test_root_writable_policy.py6
-rw-r--r--packages/meshbay-node/tests/test_roots.py12
-rw-r--r--packages/meshbay-node/tests/test_roster_pairing.py4
-rw-r--r--packages/meshbay-node/tests/test_scan_settings_policy.py1
-rw-r--r--packages/meshbay-node/tests/test_season_and_search_requests.py1
-rw-r--r--packages/meshbay-node/tests/test_security_regressions.py30
-rw-r--r--packages/meshbay-node/tests/test_startup_scan_enrichment.py5
-rw-r--r--packages/meshbay-node/tests/test_stream_audio_track_selection.py1
-rw-r--r--packages/meshbay-node/tests/test_stream_audio_transcode.py3
-rw-r--r--packages/meshbay-node/tests/test_stream_capacity.py9
-rw-r--r--packages/meshbay-node/tests/test_stream_capacity_config.py1
-rw-r--r--packages/meshbay-node/tests/test_stream_seek_audio_alignment.py1
-rw-r--r--packages/meshbay-node/tests/test_stream_seek_reports_the_keyframe.py1
-rw-r--r--packages/meshbay-node/tests/test_stream_subtitle_tracks.py1
-rw-r--r--packages/meshbay-node/tests/test_stream_video_transcode.py1
-rw-r--r--packages/meshbay-node/tests/test_title_parse.py1
-rw-r--r--packages/meshbay-node/tests/test_tmdb.py1
-rw-r--r--packages/meshbay-node/tests/test_tmdb_config_policy.py3
-rw-r--r--packages/meshbay-node/tests/test_tmdb_enabled_policy.py3
-rw-r--r--packages/meshbay-node/tests/test_tmdb_language_fallback.py1
-rw-r--r--packages/meshbay-node/tests/test_tmdb_override_policy.py3
-rw-r--r--packages/meshbay-node/tests/test_tmdb_rematch_policy.py3
-rw-r--r--packages/meshbay-node/tests/test_tmdb_show_director.py1
-rw-r--r--packages/meshbay-node/tests/test_transfer_settings.py6
-rw-r--r--packages/meshbay-node/tests/test_transfer_slots.py14
-rw-r--r--packages/meshbay-node/tests/test_transport_wire_parity.py3
-rw-r--r--packages/meshbay-node/tests/test_upload_size_cap.py1
-rw-r--r--packages/meshbay-node/tests/test_video_root_gates_enrichment.py3
-rw-r--r--packages/meshbay-node/tests/test_webrtc_transport.py33
-rw-r--r--packages/meshbay-node/tests/test_windows_root_shapes.py1
-rw-r--r--packages/meshbay-node/tests/test_wizard_apps_endpoint.py4
-rwxr-xr-xpackages/meshbay-node/tests/transfer_probe.py12
166 files changed, 601 insertions, 643 deletions
diff --git a/packages/meshbay-common/src/meshbay_common/background.py b/packages/meshbay-common/src/meshbay_common/background.py
index 1f25dfd..0afc3e8 100644
--- a/packages/meshbay-common/src/meshbay_common/background.py
+++ b/packages/meshbay-common/src/meshbay_common/background.py
@@ -30,7 +30,8 @@ from __future__ import annotations
import asyncio
import logging
-from typing import Any, Coroutine
+from collections.abc import Coroutine
+from typing import Any
log = logging.getLogger(__name__)
diff --git a/packages/meshbay-common/src/meshbay_common/crypto.py b/packages/meshbay-common/src/meshbay_common/crypto.py
index eadb42b..e537500 100644
--- a/packages/meshbay-common/src/meshbay_common/crypto.py
+++ b/packages/meshbay-common/src/meshbay_common/crypto.py
@@ -5,17 +5,17 @@ Validated in Spike 1 and Spike 6 of the POC.
All operations use PyCA cryptography (OpenSSL-backed, hardware-accelerated).
"""
-import os
import base64
+import os
+import blake3
+from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey, Ed25519PublicKey
from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey, X25519PublicKey
+from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305
-from cryptography.hazmat.primitives.kdf.hkdf import HKDF
from cryptography.hazmat.primitives.kdf.argon2 import Argon2id
-from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
-from cryptography.hazmat.primitives import hashes, serialization
-import blake3
+from cryptography.hazmat.primitives.kdf.hkdf import HKDF
# ── Key serialisation helpers ─────────────────────────────────────────────────
diff --git a/packages/meshbay-common/src/meshbay_common/keyderive.py b/packages/meshbay-common/src/meshbay_common/keyderive.py
index 497f877..4b90af3 100644
--- a/packages/meshbay-common/src/meshbay_common/keyderive.py
+++ b/packages/meshbay-common/src/meshbay_common/keyderive.py
@@ -24,11 +24,11 @@ See keyderive.js for the browser-side implementation.
"""
import hashlib
+
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey
from cryptography.hazmat.primitives.kdf.argon2 import Argon2id
-
# Argon2id parameters — same as keystore (see crypto.py)
_ITERATIONS = 3
_MEMORY_COST = 65536 # 64 MB — increase to 262144 for production
@@ -85,9 +85,11 @@ def encrypt_keypair_bundle(
Returns: AES-256-GCM ciphertext (nonce prepended).
"""
import os
+
+ import msgpack
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
+
from meshbay_common.crypto import sk_to_raw
- import msgpack
# Derive an AES key from the password (different info string from key derivation)
salt = hashlib.sha256(f"meshbay:bundle:v1:{username}".encode()).digest()
diff --git a/packages/meshbay-common/src/meshbay_common/protocol.py b/packages/meshbay-common/src/meshbay_common/protocol.py
index c444711..d6e30e7 100644
--- a/packages/meshbay-common/src/meshbay_common/protocol.py
+++ b/packages/meshbay-common/src/meshbay_common/protocol.py
@@ -32,12 +32,11 @@ which local promise a reply belongs to.
import os
from dataclasses import dataclass, field
-from typing import Any
# The wire versions live in meshbay_common/__init__.py — one source, because a
# second copy here said "0.1" while every message on the wire carried "0.2".
# Nothing imported it, which is the only reason it was harmless.
-from meshbay_common import MNP_VERSION, MHP_VERSION # noqa: F401 (re-export)
+from meshbay_common import MHP_VERSION, MNP_VERSION # noqa: F401 (re-export)
from meshbay_common.groupbox import PURPOSE_UPLOAD, seal, unseal
from meshbay_common.webcrypto import (
chunk_key_aes,
@@ -45,7 +44,6 @@ from meshbay_common.webcrypto import (
encrypt_chunk_aes,
)
-
# ── MNP message types ─────────────────────────────────────────────────────────
class MNP:
diff --git a/packages/meshbay-common/src/meshbay_common/webcrypto.py b/packages/meshbay-common/src/meshbay_common/webcrypto.py
index 58958f8..3bd5ae6 100644
--- a/packages/meshbay-common/src/meshbay_common/webcrypto.py
+++ b/packages/meshbay-common/src/meshbay_common/webcrypto.py
@@ -26,9 +26,10 @@ This ensures AES and ChaCha20 keys are always distinct even from the same GEK.
"""
import os
+
+from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
-from cryptography.hazmat.primitives import hashes
def chunk_key_aes(gek: bytes, file_hash: bytes, chunk_index: int) -> bytes:
diff --git a/packages/meshbay-common/tests/test_background_tasks.py b/packages/meshbay-common/tests/test_background_tasks.py
index 4f0ac59..d01235b 100644
--- a/packages/meshbay-common/tests/test_background_tasks.py
+++ b/packages/meshbay-common/tests/test_background_tasks.py
@@ -28,7 +28,6 @@ import logging
from pathlib import Path
import pytest
-
from meshbay_common import background
REPO = Path(__file__).resolve().parents[3]
diff --git a/packages/meshbay-common/tests/test_handshake.py b/packages/meshbay-common/tests/test_handshake.py
index d4f6d2b..11313aa 100644
--- a/packages/meshbay-common/tests/test_handshake.py
+++ b/packages/meshbay-common/tests/test_handshake.py
@@ -12,7 +12,6 @@ import jwt
import pytest
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
-
from meshbay_common.handshake import (
HANDSHAKE_PREFIX,
NONCE_LEN,
@@ -207,8 +206,8 @@ def test_membership_refusal_carries_a_code_a_client_can_act_on():
is exactly the kind of coupling that breaks when someone improves a message.
"""
import jwt as _jwt
- from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives import serialization
+ from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
sk = Ed25519PrivateKey.generate()
pem_priv = sk.private_bytes(
@@ -234,8 +233,8 @@ def test_a_group_this_node_does_not_host_is_refused_with_a_code():
dark on 2026-09-11 with its real host online — or had to match on wording.
"""
import jwt as _jwt
- from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives import serialization
+ from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
sk = Ed25519PrivateKey.generate()
pem_priv = sk.private_bytes(
diff --git a/packages/meshbay-common/tests/test_js_python_parity.py b/packages/meshbay-common/tests/test_js_python_parity.py
index 9893a9f..3887414 100644
--- a/packages/meshbay-common/tests/test_js_python_parity.py
+++ b/packages/meshbay-common/tests/test_js_python_parity.py
@@ -21,7 +21,6 @@ import tempfile
from pathlib import Path
import pytest
-
from meshbay_common.adminop import admin_transcript
from meshbay_common.handshake import handshake_transcript, webrtc_binding
from meshbay_common.join import join_transcript
@@ -312,7 +311,6 @@ def _groupbox_payload(idx: int) -> dict:
@pytest.fixture(scope="module")
def groupbox_js(tmp_path_factory):
import msgpack
-
from meshbay_common.groupbox import seal
d = tmp_path_factory.mktemp("groupbox-parity")
@@ -486,7 +484,6 @@ def chatbox_js(tmp_path_factory):
from cryptography.hazmat.primitives.asymmetric.ed25519 import (
Ed25519PrivateKey,
)
-
from meshbay_common.chatbox import seal
d = tmp_path_factory.mktemp("chatbox-parity")
@@ -537,7 +534,6 @@ def test_browser_opens_a_chat_message_python_sealed(idx, vector, chatbox_js):
@pytest.mark.parametrize("idx,vector", list(enumerate(CHAT_VECTORS)))
def test_python_opens_a_chat_message_the_browser_sealed(idx, vector, chatbox_js):
import msgpack
-
from meshbay_common.chatbox import open_message
js, vectors = chatbox_js
@@ -580,7 +576,6 @@ def test_a_message_does_not_open_under_another_epoch(chatbox_js):
would round-trip against itself and pass every other test here.
"""
import pytest as _pytest
-
from meshbay_common.chatbox import open_message
_js, vectors = chatbox_js
@@ -598,7 +593,6 @@ def test_a_message_does_not_open_under_another_devices_key(chatbox_js):
any coordination — the property per-device ratchet chains were wanted for.
"""
import pytest as _pytest
-
from meshbay_common.chatbox import open_message
_js, vectors = chatbox_js
diff --git a/packages/meshbay-common/tests/test_keyderive.py b/packages/meshbay-common/tests/test_keyderive.py
index 0aa6201..40b3c71 100644
--- a/packages/meshbay-common/tests/test_keyderive.py
+++ b/packages/meshbay-common/tests/test_keyderive.py
@@ -1,12 +1,12 @@
"""Tests for password-based key derivation."""
import pytest
+from meshbay_common.crypto import pk_to_b64
from meshbay_common.keyderive import (
+ decrypt_keypair_bundle,
derive_keys_from_password,
encrypt_keypair_bundle,
- decrypt_keypair_bundle,
)
-from meshbay_common.crypto import pk_to_b64
def test_deterministic():
diff --git a/packages/meshbay-common/tests/test_paths.py b/packages/meshbay-common/tests/test_paths.py
index b9052e3..223a2a6 100644
--- a/packages/meshbay-common/tests/test_paths.py
+++ b/packages/meshbay-common/tests/test_paths.py
@@ -7,7 +7,6 @@ one file, and whether a member can save what they downloaded.
"""
import pytest
-
from meshbay_common.paths import (
find_fold_collisions,
fold,
@@ -18,7 +17,6 @@ from meshbay_common.paths import (
sanitize_for_download,
)
-
# ── Same file or not ─────────────────────────────────────────────────────────
def test_case_differences_fold_together():
diff --git a/packages/meshbay-common/tests/test_webcrypto.py b/packages/meshbay-common/tests/test_webcrypto.py
index 2ed6405..fbffdc1 100644
--- a/packages/meshbay-common/tests/test_webcrypto.py
+++ b/packages/meshbay-common/tests/test_webcrypto.py
@@ -1,10 +1,11 @@
"""Tests for AES-256-GCM webcrypto variant."""
import os
-import pytest
+
import blake3
+import pytest
from meshbay_common.crypto import generate_gek
-from meshbay_common.webcrypto import chunk_key_aes, encrypt_chunk_aes, decrypt_chunk_aes
+from meshbay_common.webcrypto import chunk_key_aes, decrypt_chunk_aes, encrypt_chunk_aes
def test_aes_roundtrip():
@@ -49,7 +50,10 @@ def test_aes_chunk_keys_unique_per_chunk():
def test_aes_gek_wrap_unwrap_roundtrip():
from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey
from meshbay_common.crypto import (
- wrap_gek_aes, unwrap_gek_aes, sk_to_raw, pk_to_raw,
+ pk_to_raw,
+ sk_to_raw,
+ unwrap_gek_aes,
+ wrap_gek_aes,
)
gek = generate_gek()
sk = X25519PrivateKey.generate()
@@ -63,7 +67,7 @@ def test_aes_gek_wrap_unwrap_roundtrip():
def test_aes_gek_wrap_wrong_key_rejected():
from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey
- from meshbay_common.crypto import wrap_gek_aes, unwrap_gek_aes, sk_to_raw, pk_to_raw
+ from meshbay_common.crypto import pk_to_raw, sk_to_raw, unwrap_gek_aes, wrap_gek_aes
gek = generate_gek()
sk_a = X25519PrivateKey.generate()
@@ -77,7 +81,9 @@ def test_aes_gek_wrap_wrong_key_rejected():
def test_aes_gek_wrap_differs_from_chacha_wrap():
from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey
from meshbay_common.crypto import (
- wrap_gek, wrap_gek_aes, pk_to_raw,
+ pk_to_raw,
+ wrap_gek,
+ wrap_gek_aes,
)
gek = generate_gek()
sk = X25519PrivateKey.generate()
diff --git a/packages/meshbay-hub/src/meshbay_hub/api/admin.py b/packages/meshbay-hub/src/meshbay_hub/api/admin.py
index 7ca1e68..d8e13e9 100644
--- a/packages/meshbay-hub/src/meshbay_hub/api/admin.py
+++ b/packages/meshbay-hub/src/meshbay_hub/api/admin.py
@@ -6,19 +6,18 @@ Separate from moderation.py (which handles public reporting and content blocklis
"""
import logging
-from datetime import datetime, timezone
from fastapi import APIRouter, Depends, HTTPException, Query
from pydantic import BaseModel
from sqlalchemy import func, select
from sqlalchemy.ext.asyncio import AsyncSession
-from meshbay_hub.auth import decrypt_email
+from meshbay_hub import hub_settings
from meshbay_hub.api.deps import require_admin, require_moderator, user_is_admin
from meshbay_hub.api.revocation import get_connected_node_count, is_node_connected
+from meshbay_hub.auth import decrypt_email
from meshbay_hub.db.engine import get_db
from meshbay_hub.db.models import Group, GroupMember, IPLog, Node, User
-from meshbay_hub import hub_settings
log = logging.getLogger(__name__)
diff --git a/packages/meshbay-hub/src/meshbay_hub/api/deps.py b/packages/meshbay-hub/src/meshbay_hub/api/deps.py
index 907a481..501be9d 100644
--- a/packages/meshbay-hub/src/meshbay_hub/api/deps.py
+++ b/packages/meshbay-hub/src/meshbay_hub/api/deps.py
@@ -8,8 +8,8 @@ JWT scope enforcement:
"""
from fastapi import Depends, Header, HTTPException, status
-from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
+from sqlalchemy.ext.asyncio import AsyncSession
from meshbay_hub.auth import decode_access_token
from meshbay_hub.db.engine import get_db
diff --git a/packages/meshbay-hub/src/meshbay_hub/api/federation.py b/packages/meshbay-hub/src/meshbay_hub/api/federation.py
index 9e252c6..755639e 100644
--- a/packages/meshbay-hub/src/meshbay_hub/api/federation.py
+++ b/packages/meshbay-hub/src/meshbay_hub/api/federation.py
@@ -23,18 +23,18 @@ Protocol version: MHP 0.1
import logging
import time
import uuid
+from datetime import UTC
import jwt
-from fastapi import APIRouter, Depends, HTTPException, Header
+from fastapi import APIRouter, Depends, Header, HTTPException
+from meshbay_common import MHP_VERSION
from pydantic import BaseModel
from sqlalchemy import func, select
from sqlalchemy.ext.asyncio import AsyncSession
-from meshbay_common import MHP_VERSION
from meshbay_hub import __version__, hub_settings
from meshbay_hub.api.deps import require_admin
-from meshbay_hub.auth import (
- hub_id, hub_private_key_pem, hub_public_key_pem)
+from meshbay_hub.auth import hub_id, hub_private_key_pem, hub_public_key_pem
from meshbay_hub.db.engine import get_db
from meshbay_hub.db.models import FederatedGroup, Group, HubPeer, User
@@ -244,8 +244,8 @@ async def receive_directory(
if len(body.groups) > MAX_FEDERATED_GROUPS_PER_PUSH:
raise HTTPException(status_code=413, detail="Too many groups in one push")
- from datetime import datetime, timezone
- now = datetime.now(timezone.utc)
+ from datetime import datetime
+ now = datetime.now(UTC)
have = await db.scalar(
select(func.count()).select_from(FederatedGroup)
.where(FederatedGroup.source_hub == sender)) or 0
diff --git a/packages/meshbay-hub/src/meshbay_hub/api/groups.py b/packages/meshbay-hub/src/meshbay_hub/api/groups.py
index 72ba194..3a11345 100644
--- a/packages/meshbay-hub/src/meshbay_hub/api/groups.py
+++ b/packages/meshbay-hub/src/meshbay_hub/api/groups.py
@@ -1,22 +1,27 @@
"""Group endpoints — /v1/groups/*"""
import re
+from datetime import UTC, datetime
from fastapi import APIRouter, Depends, HTTPException, Query, Request
from pydantic import BaseModel
-from datetime import datetime, timezone
from sqlalchemy import func, or_, select, update
from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.asyncio import AsyncSession
from meshbay_hub import hub_settings, mail
-from meshbay_hub.auth import decrypt_email
from meshbay_hub.api.deps import get_current_user, require_user_scope
from meshbay_hub.api.middleware import limiter
from meshbay_hub.api.netutil import client_ip
+from meshbay_hub.auth import decrypt_email
from meshbay_hub.db.engine import get_db
from meshbay_hub.db.models import (
- FederatedGroup, Group, GroupMember, IPLog, SwarmSource, User,
+ FederatedGroup,
+ Group,
+ GroupMember,
+ IPLog,
+ SwarmSource,
+ User,
)
router = APIRouter(prefix="/v1/groups", tags=["groups"])
@@ -97,7 +102,7 @@ async def touch_group_activity(
await db.execute(
update(Group)
.where(Group.id == group_id)
- .values(last_activity_at=datetime.now(timezone.utc)))
+ .values(last_activity_at=datetime.now(UTC)))
await db.commit()
return {"ok": True}
@@ -261,9 +266,9 @@ async def swarm_register(
detail="endpoint must be '<webrtc|quic>:<port>' — a port on the "
"registering node, not an address")
- from datetime import datetime, timezone
+ from datetime import datetime
existing = await db.get(SwarmSource, (body.content_hash, current_user.id))
- now = datetime.now(timezone.utc)
+ now = datetime.now(UTC)
if existing:
existing.endpoint = body.endpoint
existing.last_seen = now
@@ -297,8 +302,8 @@ async def swarm_sources(
Authenticated (H7): an open endpoint lets anyone probe whether a given file
exists anywhere in the network and which node holds it.
"""
- from datetime import datetime, timezone, timedelta
- cutoff = datetime.now(timezone.utc) - timedelta(minutes=30)
+ from datetime import datetime, timedelta
+ cutoff = datetime.now(UTC) - timedelta(minutes=30)
result = await db.execute(
select(SwarmSource)
.where(
diff --git a/packages/meshbay-hub/src/meshbay_hub/api/hub.py b/packages/meshbay-hub/src/meshbay_hub/api/hub.py
index 94e9b3c..cab60c8 100644
--- a/packages/meshbay-hub/src/meshbay_hub/api/hub.py
+++ b/packages/meshbay-hub/src/meshbay_hub/api/hub.py
@@ -1,9 +1,9 @@
"""Hub info endpoints — /v1/hub/*"""
from fastapi import APIRouter, Depends
+from meshbay_common import MHP_VERSION, MNP_VERSION
from sqlalchemy.ext.asyncio import AsyncSession
-from meshbay_common import MNP_VERSION, MHP_VERSION
from meshbay_hub import __version__, hub_settings
from meshbay_hub.api import federation
from meshbay_hub.auth import hub_public_key_pem
diff --git a/packages/meshbay-hub/src/meshbay_hub/api/moderation.py b/packages/meshbay-hub/src/meshbay_hub/api/moderation.py
index ee10cbc..35c688c 100644
--- a/packages/meshbay-hub/src/meshbay_hub/api/moderation.py
+++ b/packages/meshbay-hub/src/meshbay_hub/api/moderation.py
@@ -23,7 +23,6 @@ Node integration:
"""
import logging
-from datetime import datetime, timezone
from fastapi import APIRouter, Depends, HTTPException, Query, Request
from pydantic import BaseModel
diff --git a/packages/meshbay-hub/src/meshbay_hub/api/nodes.py b/packages/meshbay-hub/src/meshbay_hub/api/nodes.py
index 83b60f2..7478173 100644
--- a/packages/meshbay-hub/src/meshbay_hub/api/nodes.py
+++ b/packages/meshbay-hub/src/meshbay_hub/api/nodes.py
@@ -1,20 +1,20 @@
"""Node endpoints — /v1/nodes/*"""
-from datetime import datetime, timezone
import base64
import time
+from datetime import UTC, datetime
-from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
from cryptography.exceptions import InvalidSignature
+from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
from fastapi import APIRouter, Depends, HTTPException, Request
from pydantic import BaseModel
from sqlalchemy import func, select
from sqlalchemy.ext.asyncio import AsyncSession
-from meshbay_hub.auth import issue_access_token
from meshbay_hub.api.deps import get_current_user
from meshbay_hub.api.middleware import limiter
from meshbay_hub.api.netutil import client_ip
+from meshbay_hub.auth import issue_access_token
from meshbay_hub.db.engine import get_db
from meshbay_hub.db.models import GroupMember, IPLog, Node, User
@@ -156,7 +156,7 @@ async def announce_node(
if node is not None:
node.endpoint_hint = body.endpoint_hint
node.observed_ip = seen_from
- node.last_seen = datetime.now(timezone.utc)
+ node.last_seen = datetime.now(UTC)
db.add(IPLog(user_id=current_user.id, event="node_announce",
ip_address=seen_from, detail=body.endpoint_hint))
await db.commit()
@@ -182,7 +182,7 @@ async def announce_node(
pk_node=body.pk_node,
endpoint_hint=body.endpoint_hint,
observed_ip=seen_from,
- last_seen=datetime.now(timezone.utc),
+ last_seen=datetime.now(UTC),
)
db.add(node)
db.add(IPLog(
diff --git a/packages/meshbay-hub/src/meshbay_hub/api/notifications.py b/packages/meshbay-hub/src/meshbay_hub/api/notifications.py
index b5783ab..d96ec18 100644
--- a/packages/meshbay-hub/src/meshbay_hub/api/notifications.py
+++ b/packages/meshbay-hub/src/meshbay_hub/api/notifications.py
@@ -19,9 +19,9 @@ migration for no gain, and `unread_only` stays because it is what an older
interface asks for and it still answers correctly — every row is unread.
"""
-from fastapi import APIRouter, Depends, HTTPException, Query
-from datetime import datetime, timezone
+from datetime import UTC, datetime
+from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy import delete, func, select
from sqlalchemy.ext.asyncio import AsyncSession
@@ -182,7 +182,7 @@ async def create_notification(
existing.detail = detail
existing.link = link
existing.read = False
- existing.created_at = datetime.now(timezone.utc)
+ existing.created_at = datetime.now(UTC)
await db.flush()
return existing
diff --git a/packages/meshbay-hub/src/meshbay_hub/api/revocation.py b/packages/meshbay-hub/src/meshbay_hub/api/revocation.py
index 1f1f5c5..f8cae8a 100644
--- a/packages/meshbay-hub/src/meshbay_hub/api/revocation.py
+++ b/packages/meshbay-hub/src/meshbay_hub/api/revocation.py
@@ -26,23 +26,21 @@ and close active connections for that user.
"""
import asyncio
-import base64
import json
import logging
import time
import uuid
-from datetime import datetime, timezone
-from typing import Any
+from datetime import UTC, datetime
+import jwt
from fastapi import APIRouter, Depends, HTTPException, Request, WebSocket, WebSocketDisconnect
+from meshbay_common.background import spawn
from pydantic import BaseModel
from sqlalchemy import select, update
from sqlalchemy.ext.asyncio import AsyncSession
-import jwt
-from meshbay_common.background import spawn
-from meshbay_hub.auth import hub_public_key_pem, decode_access_token
from meshbay_hub.api.deps import get_current_user, require_admin
+from meshbay_hub.auth import decode_access_token
from meshbay_hub.db.engine import get_db
from meshbay_hub.db.models import Group, GroupMember, IPLog, Node, User
@@ -143,7 +141,7 @@ async def _mark_hosted(group_ids: list[str]) -> None:
await db.execute(
update(Group)
.where(Group.id.in_(group_ids), Group.hosted_at.is_(None))
- .values(hosted_at=datetime.now(timezone.utc)))
+ .values(hosted_at=datetime.now(UTC)))
await db.commit()
except Exception as e:
# A group that stays unhosted in the table is visible to its owner and
@@ -169,7 +167,7 @@ async def broadcast_revocation(token: str) -> int:
def _sign_revocation(target: str, target_id: str, reason: str) -> str:
"""Issue a signed revocation token (JWT EdDSA)."""
- from meshbay_hub.auth import _hub_sk_pem, _hub_id
+ from meshbay_hub.auth import _hub_id, _hub_sk_pem
now = int(time.time())
payload = {
"type": "revocation",
@@ -208,9 +206,9 @@ async def _handle_chat_notify(group_id: str, sender_name: str, sender_user_id: s
(node_id or "?")[:8])
return
try:
- from meshbay_hub.db.engine import get_session_factory
- from meshbay_hub.db.models import GroupMember, Group
from meshbay_hub.api.notifications import create_notification
+ from meshbay_hub.db.engine import get_session_factory
+ from meshbay_hub.db.models import Group, GroupMember
async with get_session_factory()() as db:
group = await db.get(Group, group_id)
@@ -478,7 +476,7 @@ async def notify_incoming(
try:
await asyncio.wait_for(event.wait(), timeout=5.0)
- except asyncio.TimeoutError:
+ except TimeoutError:
raise HTTPException(status_code=504, detail="Node did not respond in time")
finally:
_punch_events.pop(node_id, None)
diff --git a/packages/meshbay-hub/src/meshbay_hub/api/signaling.py b/packages/meshbay-hub/src/meshbay_hub/api/signaling.py
index bc03b45..8a10822 100644
--- a/packages/meshbay-hub/src/meshbay_hub/api/signaling.py
+++ b/packages/meshbay-hub/src/meshbay_hub/api/signaling.py
@@ -25,8 +25,8 @@ from sqlalchemy.ext.asyncio import AsyncSession
from meshbay_hub import hub_settings
from meshbay_hub.api.deps import get_current_user
from meshbay_hub.api.middleware import limiter
-from meshbay_hub.db.engine import get_db
from meshbay_hub.api.netutil import client_ip
+from meshbay_hub.db.engine import get_db
from meshbay_hub.db.models import Group, GroupMember, IPLog, User
log = logging.getLogger(__name__)
@@ -167,7 +167,7 @@ async def webrtc_offer(
try:
answer = await asyncio.wait_for(answer_future, timeout=15.0)
- except asyncio.TimeoutError:
+ except TimeoutError:
raise HTTPException(
status_code=504, detail="Node did not respond with WebRTC answer")
diff --git a/packages/meshbay-hub/src/meshbay_hub/api/users.py b/packages/meshbay-hub/src/meshbay_hub/api/users.py
index 0394f53..ee8aabc 100644
--- a/packages/meshbay-hub/src/meshbay_hub/api/users.py
+++ b/packages/meshbay-hub/src/meshbay_hub/api/users.py
@@ -6,7 +6,7 @@ import re
import secrets
import time
import uuid
-from datetime import datetime, timedelta, timezone
+from datetime import UTC, datetime, timedelta
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
from fastapi import APIRouter, Depends, HTTPException, Request
@@ -33,8 +33,17 @@ from meshbay_hub.auth import (
from meshbay_hub.config import HubConfig
from meshbay_hub.db.engine import get_db
from meshbay_hub.db.models import (
- EmailVerification, Group, GroupMember, IPLog, Node, Notification,
- RefreshToken, SwarmSource, User, UserDevice, UserPreference,
+ EmailVerification,
+ Group,
+ GroupMember,
+ IPLog,
+ Node,
+ Notification,
+ RefreshToken,
+ SwarmSource,
+ User,
+ UserDevice,
+ UserPreference,
)
log = logging.getLogger(__name__)
@@ -61,7 +70,7 @@ async def _refresh_expiry(db: AsyncSession, family_id: str | None = None) -> dat
renewals of a tab that is being used.
"""
limits = await hub_settings.session_limits(db)
- now = datetime.now(timezone.utc)
+ now = datetime.now(UTC)
idle = max(limits["refresh_idle_hours"] * 3600, _ttl() + 3600)
started = now
if family_id is not None:
@@ -69,7 +78,7 @@ async def _refresh_expiry(db: AsyncSession, family_id: str | None = None) -> dat
select(func.min(RefreshToken.created_at))
.where(RefreshToken.family_id == family_id))
if first is not None:
- started = first if first.tzinfo else first.replace(tzinfo=timezone.utc)
+ started = first if first.tzinfo else first.replace(tzinfo=UTC)
return min(now + timedelta(seconds=idle),
started + timedelta(hours=limits["max_hours"]))
@@ -193,7 +202,7 @@ async def register(
EmailVerification.user_id == found.id,
EmailVerification.purpose == "registration",
EmailVerification.created_at
- > datetime.now(timezone.utc)
+ > datetime.now(UTC)
- timedelta(seconds=resend_cooldown),
))
if not recent.first():
@@ -270,7 +279,7 @@ async def _create_and_send_verification(
code=code,
purpose="registration",
user_id=user.id,
- expires_at=datetime.now(timezone.utc) + timedelta(seconds=VERIFICATION_TTL),
+ expires_at=datetime.now(UTC) + timedelta(seconds=VERIFICATION_TTL),
))
await db.flush()
await mail.send_off_loop(
@@ -292,7 +301,7 @@ async def verify_email(
):
"""Verify a registration email with the code received by mail."""
eh = hash_email_blind(body.email)
- now = datetime.now(timezone.utc)
+ now = datetime.now(UTC)
result = await db.execute(
select(EmailVerification).where(
@@ -306,7 +315,7 @@ async def verify_email(
raise HTTPException(status_code=404,
detail="No pending verification for this email")
- if verif.expires_at.replace(tzinfo=timezone.utc) < now:
+ if verif.expires_at.replace(tzinfo=UTC) < now:
raise HTTPException(status_code=410, detail="Verification code expired")
if verif.attempts >= VERIFICATION_MAX_ATTEMPTS:
@@ -603,7 +612,7 @@ async def device_auth(
await db.commit()
raise HTTPException(status_code=401, detail="Invalid signature")
- matched.last_seen = datetime.now(timezone.utc)
+ matched.last_seen = datetime.now(UTC)
memberships = await db.execute(
select(GroupMember.group_id).where(GroupMember.user_id == user.id))
@@ -650,7 +659,7 @@ async def token_refresh(
await db.commit()
raise HTTPException(status_code=401, detail="Token reuse detected — family revoked")
- if rt.expires_at.replace(tzinfo=timezone.utc) < datetime.now(timezone.utc):
+ if rt.expires_at.replace(tzinfo=UTC) < datetime.now(UTC):
raise HTTPException(status_code=401, detail="Expired refresh token")
user = await db.get(User, rt.user_id)
@@ -659,7 +668,7 @@ async def token_refresh(
# The family's first sign-in was longer ago than any session may last.
expires_at = await _refresh_expiry(db, rt.family_id)
- if expires_at <= datetime.now(timezone.utc):
+ if expires_at <= datetime.now(UTC):
await db.execute(
update(RefreshToken)
.where(RefreshToken.family_id == rt.family_id)
@@ -779,7 +788,7 @@ async def update_profile(
cooldown = await hub_settings.get_int(
db, "mail.email_change_cooldown",
hub_settings.mail_default("email_change_cooldown"))
- since = datetime.now(timezone.utc) - timedelta(seconds=cooldown)
+ since = datetime.now(UTC) - timedelta(seconds=cooldown)
recent = await db.execute(
select(IPLog).where(
IPLog.user_id == current_user.id,
@@ -820,7 +829,7 @@ async def update_profile(
code=code,
purpose="email_change",
user_id=current_user.id,
- expires_at=datetime.now(timezone.utc) + timedelta(seconds=VERIFICATION_TTL),
+ expires_at=datetime.now(UTC) + timedelta(seconds=VERIFICATION_TTL),
))
db.add(IPLog(user_id=current_user.id, event="email_change_request",
ip_address=client_ip(request)))
@@ -860,7 +869,7 @@ async def verify_email_change(
db: AsyncSession = Depends(get_db),
):
"""Confirm an email change with the code sent to the new address."""
- now = datetime.now(timezone.utc)
+ now = datetime.now(UTC)
result = await db.execute(
select(EmailVerification).where(
@@ -874,7 +883,7 @@ async def verify_email_change(
raise HTTPException(status_code=404,
detail="No pending email change")
- if verif.expires_at.replace(tzinfo=timezone.utc) < now:
+ if verif.expires_at.replace(tzinfo=UTC) < now:
raise HTTPException(status_code=410, detail="Verification code expired")
if verif.attempts >= VERIFICATION_MAX_ATTEMPTS:
@@ -1090,7 +1099,7 @@ async def password_reset_request(
EmailVerification.user_id == user.id,
EmailVerification.purpose == "password_reset",
EmailVerification.created_at
- > datetime.now(timezone.utc) - timedelta(seconds=reset_cooldown),
+ > datetime.now(UTC) - timedelta(seconds=reset_cooldown),
))
if recent.first():
return {"status": "sent_if_exists"}
@@ -1110,7 +1119,7 @@ async def password_reset_request(
code=code,
purpose="password_reset",
user_id=user.id,
- expires_at=datetime.now(timezone.utc)
+ expires_at=datetime.now(UTC)
+ timedelta(seconds=PASSWORD_RESET_TTL),
))
db.add(IPLog(user_id=user.id, event="password_reset_request",
@@ -1141,7 +1150,7 @@ async def password_reset(
request: Request,
db: AsyncSession = Depends(get_db),
):
- now = datetime.now(timezone.utc)
+ now = datetime.now(UTC)
result = await db.execute(select(User).where(User.username == body.username))
user = result.scalar_one_or_none()
if not user:
@@ -1157,7 +1166,7 @@ async def password_reset(
if not verif:
raise HTTPException(status_code=404,
detail="No pending reset for this account")
- if verif.expires_at.replace(tzinfo=timezone.utc) < now:
+ if verif.expires_at.replace(tzinfo=UTC) < now:
raise HTTPException(status_code=410, detail="Reset code expired")
if verif.attempts >= VERIFICATION_MAX_ATTEMPTS:
raise HTTPException(status_code=429, detail="Too many attempts")
diff --git a/packages/meshbay-hub/src/meshbay_hub/app.py b/packages/meshbay-hub/src/meshbay_hub/app.py
index afc1cde..209dc32 100644
--- a/packages/meshbay-hub/src/meshbay_hub/app.py
+++ b/packages/meshbay-hub/src/meshbay_hub/app.py
@@ -11,37 +11,41 @@ Usage:
import asyncio
from contextlib import asynccontextmanager
-from pathlib import Path
from fastapi import FastAPI
from slowapi import _rate_limit_exceeded_handler
from slowapi.errors import RateLimitExceeded
from meshbay_hub import __version__
+from meshbay_hub.api.admin import router as admin_router
+from meshbay_hub.api.deps import set_admin_usernames
+from meshbay_hub.api.federation import router as federation_router
+from meshbay_hub.api.groups import router as groups_router
+from meshbay_hub.api.groups import swarm_router
+from meshbay_hub.api.health import router as health_router
+from meshbay_hub.api.hub import router as hub_router
+from meshbay_hub.api.hub import set_config as hub_set_config
+from meshbay_hub.api.middleware import limiter
+from meshbay_hub.api.moderation import router as moderation_router
+from meshbay_hub.api.nodes import router as nodes_router
+from meshbay_hub.api.notifications import router as notifications_router
+from meshbay_hub.api.relay import router as relay_router
+from meshbay_hub.api.revocation import router as revocation_router
+from meshbay_hub.api.signaling import router as signaling_router
+from meshbay_hub.api.users import router as users_router
+from meshbay_hub.api.users import set_config as users_set_config
+from meshbay_hub.api.webapp import ASSET_V, CSP, STATIC_DIR
+from meshbay_hub.api.webapp import router as webapp_router
from meshbay_hub.auth import generate_hub_keypair, load_hub_keypair
from meshbay_hub.config import HubConfig
+from meshbay_hub.csam import csam_router
from meshbay_hub.db.engine import close_db, init_db
-from meshbay_hub.api.hub import router as hub_router, set_config as hub_set_config
-from meshbay_hub.api.users import router as users_router, set_config as users_set_config
-from meshbay_hub.api.deps import set_admin_usernames
-from meshbay_hub.api.nodes import router as nodes_router
-from meshbay_hub.api.groups import router as groups_router, swarm_router
-from meshbay_hub.api.revocation import router as revocation_router
-from meshbay_hub.api.moderation import router as moderation_router
-from meshbay_hub.api.federation import router as federation_router
-from meshbay_hub.csam import csam_router
-from meshbay_hub.api.health import router as health_router
-from meshbay_hub.api.relay import router as relay_router
-from meshbay_hub.api.signaling import router as signaling_router
-from meshbay_hub.api.admin import router as admin_router
-from meshbay_hub.api.notifications import router as notifications_router
-from meshbay_hub.api.webapp import router as webapp_router, STATIC_DIR, ASSET_V, CSP
-from meshbay_hub.api.middleware import limiter
async def _sync_admin_roles(admin_usernames: list[str]) -> None:
"""Ensure config-listed admin usernames have role='admin' in the DB."""
- from sqlalchemy import select, update
+ from sqlalchemy import select
+
from meshbay_hub.db.engine import get_session_factory
from meshbay_hub.db.models import User
@@ -122,8 +126,8 @@ def create_app(cfg: HubConfig | None = None) -> FastAPI:
from meshbay_hub.csam import get_csam_checker
get_csam_checker().load()
- from meshbay_hub.tasks.cleanup import cleanup_loop
from meshbay_hub.db.engine import get_session_factory
+ from meshbay_hub.tasks.cleanup import cleanup_loop
cleanup_task = asyncio.create_task(cleanup_loop(get_session_factory()))
yield
diff --git a/packages/meshbay-hub/src/meshbay_hub/auth.py b/packages/meshbay-hub/src/meshbay_hub/auth.py
index 7045197..d038027 100644
--- a/packages/meshbay-hub/src/meshbay_hub/auth.py
+++ b/packages/meshbay-hub/src/meshbay_hub/auth.py
@@ -18,12 +18,12 @@ from pathlib import Path
import blake3
import jwt
-from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives import serialization
+from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
+from cryptography.hazmat.primitives.hashes import SHA256
from cryptography.hazmat.primitives.kdf.argon2 import Argon2id
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
-from cryptography.hazmat.primitives.hashes import SHA256
# Argon2id parameters — versioned for gradual migration
_ARGON2_LANES = 4
diff --git a/packages/meshbay-hub/src/meshbay_hub/csam.py b/packages/meshbay-hub/src/meshbay_hub/csam.py
index 2a0ce25..e540068 100644
--- a/packages/meshbay-hub/src/meshbay_hub/csam.py
+++ b/packages/meshbay-hub/src/meshbay_hub/csam.py
@@ -19,9 +19,7 @@ IMPORTANT: Never log matched hashes or file contents. CSAM detection
must be reported to NCMEC (US law) or relevant authority immediately.
"""
-import hashlib
import logging
-import os
from pathlib import Path
log = logging.getLogger(__name__)
@@ -123,7 +121,8 @@ def check_content_hash(blake3_hex: str) -> bool:
# ── Hub API integration ───────────────────────────────────────────────────────
-from fastapi import APIRouter, Depends, HTTPException, UploadFile, File
+from fastapi import APIRouter, Depends, HTTPException
+
from meshbay_hub.api.deps import require_admin
from meshbay_hub.db.models import User
diff --git a/packages/meshbay-hub/src/meshbay_hub/db/__init__.py b/packages/meshbay-hub/src/meshbay_hub/db/__init__.py
index 62e5388..9d7483a 100644
--- a/packages/meshbay-hub/src/meshbay_hub/db/__init__.py
+++ b/packages/meshbay-hub/src/meshbay_hub/db/__init__.py
@@ -1,6 +1,6 @@
"""Hub database layer."""
-from .engine import init_db, close_db, get_db
-from .models import Base, User, Node, Group, GroupMember, RefreshToken, IPLog
+from .engine import close_db, get_db, init_db
+from .models import Base, Group, GroupMember, IPLog, Node, RefreshToken, User
__all__ = [
"init_db", "close_db", "get_db",
diff --git a/packages/meshbay-hub/src/meshbay_hub/db/migrations/env.py b/packages/meshbay-hub/src/meshbay_hub/db/migrations/env.py
index 8908deb..61f80be 100644
--- a/packages/meshbay-hub/src/meshbay_hub/db/migrations/env.py
+++ b/packages/meshbay-hub/src/meshbay_hub/db/migrations/env.py
@@ -4,14 +4,12 @@ import asyncio
import os
from logging.config import fileConfig
+from alembic import context
+from meshbay_hub.db.models import Base
from sqlalchemy import pool
from sqlalchemy.engine import Connection
from sqlalchemy.ext.asyncio import async_engine_from_config
-from alembic import context
-
-from meshbay_hub.db.models import Base
-
config = context.config
if config.config_file_name is not None:
diff --git a/packages/meshbay-hub/src/meshbay_hub/db/migrations/versions/a7b8c9d0e1f2_add_group_last_activity.py b/packages/meshbay-hub/src/meshbay_hub/db/migrations/versions/a7b8c9d0e1f2_add_group_last_activity.py
index 8a4e2ee..034d12f 100644
--- a/packages/meshbay-hub/src/meshbay_hub/db/migrations/versions/a7b8c9d0e1f2_add_group_last_activity.py
+++ b/packages/meshbay-hub/src/meshbay_hub/db/migrations/versions/a7b8c9d0e1f2_add_group_last_activity.py
@@ -5,16 +5,15 @@ Revises: f1a2b3c4d5e6
Create Date: 2026-08-20 20:50:00.000000
"""
-from typing import Sequence, Union
+from collections.abc import Sequence
-from alembic import op
import sqlalchemy as sa
-
+from alembic import op
revision: str = 'a7b8c9d0e1f2'
-down_revision: Union[str, Sequence[str], None] = 'f1a2b3c4d5e6'
-branch_labels: Union[str, Sequence[str], None] = None
-depends_on: Union[str, Sequence[str], None] = None
+down_revision: str | Sequence[str] | None = 'f1a2b3c4d5e6'
+branch_labels: str | Sequence[str] | None = None
+depends_on: str | Sequence[str] | None = None
def upgrade() -> None:
diff --git a/packages/meshbay-hub/src/meshbay_hub/db/migrations/versions/a9b8c7d6e5f4_add_login_throttle.py b/packages/meshbay-hub/src/meshbay_hub/db/migrations/versions/a9b8c7d6e5f4_add_login_throttle.py
index 2fead6c..45985e2 100644
--- a/packages/meshbay-hub/src/meshbay_hub/db/migrations/versions/a9b8c7d6e5f4_add_login_throttle.py
+++ b/packages/meshbay-hub/src/meshbay_hub/db/migrations/versions/a9b8c7d6e5f4_add_login_throttle.py
@@ -7,15 +7,15 @@ Revision ID: a9b8c7d6e5f4
Revises: e5f6a7b8c9d0
"""
-from typing import Sequence, Union
+from collections.abc import Sequence
import sqlalchemy as sa
from alembic import op
revision: str = "a9b8c7d6e5f4"
-down_revision: Union[str, Sequence[str], None] = "e5f6a7b8c9d0"
-branch_labels: Union[str, Sequence[str], None] = None
-depends_on: Union[str, Sequence[str], None] = None
+down_revision: str | Sequence[str] | None = "e5f6a7b8c9d0"
+branch_labels: str | Sequence[str] | None = None
+depends_on: str | Sequence[str] | None = None
def upgrade() -> None:
diff --git a/packages/meshbay-hub/src/meshbay_hub/db/migrations/versions/b1c2d3e4f5a6_add_hub_settings.py b/packages/meshbay-hub/src/meshbay_hub/db/migrations/versions/b1c2d3e4f5a6_add_hub_settings.py
index 13f2b5c..9a90f7a 100644
--- a/packages/meshbay-hub/src/meshbay_hub/db/migrations/versions/b1c2d3e4f5a6_add_hub_settings.py
+++ b/packages/meshbay-hub/src/meshbay_hub/db/migrations/versions/b1c2d3e4f5a6_add_hub_settings.py
@@ -5,16 +5,15 @@ Revises: a7b8c9d0e1f2
Create Date: 2026-08-28 12:00:00.000000
"""
-from typing import Sequence, Union
+from collections.abc import Sequence
-from alembic import op
import sqlalchemy as sa
-
+from alembic import op
revision: str = 'b1c2d3e4f5a6'
-down_revision: Union[str, Sequence[str], None] = 'a7b8c9d0e1f2'
-branch_labels: Union[str, Sequence[str], None] = None
-depends_on: Union[str, Sequence[str], None] = None
+down_revision: str | Sequence[str] | None = 'a7b8c9d0e1f2'
+branch_labels: str | Sequence[str] | None = None
+depends_on: str | Sequence[str] | None = None
def upgrade() -> None:
diff --git a/packages/meshbay-hub/src/meshbay_hub/db/migrations/versions/c3d4e5f6a7b8_group_name_unique_per_owner.py b/packages/meshbay-hub/src/meshbay_hub/db/migrations/versions/c3d4e5f6a7b8_group_name_unique_per_owner.py
index 6fc5b73..fea0583 100644
--- a/packages/meshbay-hub/src/meshbay_hub/db/migrations/versions/c3d4e5f6a7b8_group_name_unique_per_owner.py
+++ b/packages/meshbay-hub/src/meshbay_hub/db/migrations/versions/c3d4e5f6a7b8_group_name_unique_per_owner.py
@@ -10,16 +10,15 @@ its UUID — this only makes `name@owner` a dependable handle.
Pre-flight: abort if the data already violates it, with the offending
(admin_id, name) pairs listed, rather than silently renaming anyone's group.
"""
-from typing import Sequence, Union
+from collections.abc import Sequence
-from alembic import op
import sqlalchemy as sa
-
+from alembic import op
revision: str = 'c3d4e5f6a7b8'
-down_revision: Union[str, Sequence[str], None] = 'b1c2d3e4f5a6'
-branch_labels: Union[str, Sequence[str], None] = None
-depends_on: Union[str, Sequence[str], None] = None
+down_revision: str | Sequence[str] | None = 'b1c2d3e4f5a6'
+branch_labels: str | Sequence[str] | None = None
+depends_on: str | Sequence[str] | None = None
def upgrade() -> None:
diff --git a/packages/meshbay-hub/src/meshbay_hub/db/migrations/versions/d28b9caf9f07_initial_schema.py b/packages/meshbay-hub/src/meshbay_hub/db/migrations/versions/d28b9caf9f07_initial_schema.py
index 6301426..a814f37 100644
--- a/packages/meshbay-hub/src/meshbay_hub/db/migrations/versions/d28b9caf9f07_initial_schema.py
+++ b/packages/meshbay-hub/src/meshbay_hub/db/migrations/versions/d28b9caf9f07_initial_schema.py
@@ -12,16 +12,15 @@ Revises:
Create Date: 2026-08-09 04:35:07.120021
"""
-from typing import Sequence, Union
+from collections.abc import Sequence
-from alembic import op
import sqlalchemy as sa
-
+from alembic import op
revision: str = 'd28b9caf9f07'
-down_revision: Union[str, Sequence[str], None] = None
-branch_labels: Union[str, Sequence[str], None] = None
-depends_on: Union[str, Sequence[str], None] = None
+down_revision: str | Sequence[str] | None = None
+branch_labels: str | Sequence[str] | None = None
+depends_on: str | Sequence[str] | None = None
def upgrade() -> None:
diff --git a/packages/meshbay-hub/src/meshbay_hub/db/migrations/versions/d4e5f6a7b8c9_add_email_verification.py b/packages/meshbay-hub/src/meshbay_hub/db/migrations/versions/d4e5f6a7b8c9_add_email_verification.py
index 6741eb8..aa15b6d 100644
--- a/packages/meshbay-hub/src/meshbay_hub/db/migrations/versions/d4e5f6a7b8c9_add_email_verification.py
+++ b/packages/meshbay-hub/src/meshbay_hub/db/migrations/versions/d4e5f6a7b8c9_add_email_verification.py
@@ -9,16 +9,15 @@ Revises: c3d4e5f6a7b8
Create Date: 2026-08-31 14:00:00.000000
"""
-from typing import Sequence, Union
+from collections.abc import Sequence
-from alembic import op
import sqlalchemy as sa
-
+from alembic import op
revision: str = 'd4e5f6a7b8c9'
-down_revision: Union[str, Sequence[str], None] = 'c3d4e5f6a7b8'
-branch_labels: Union[str, Sequence[str], None] = None
-depends_on: Union[str, Sequence[str], None] = None
+down_revision: str | Sequence[str] | None = 'c3d4e5f6a7b8'
+branch_labels: str | Sequence[str] | None = None
+depends_on: str | Sequence[str] | None = None
def upgrade() -> None:
diff --git a/packages/meshbay-hub/src/meshbay_hub/db/migrations/versions/e5f6a7b8c9d0_add_mail_quota.py b/packages/meshbay-hub/src/meshbay_hub/db/migrations/versions/e5f6a7b8c9d0_add_mail_quota.py
index 8f2e4d2..c729de4 100644
--- a/packages/meshbay-hub/src/meshbay_hub/db/migrations/versions/e5f6a7b8c9d0_add_mail_quota.py
+++ b/packages/meshbay-hub/src/meshbay_hub/db/migrations/versions/e5f6a7b8c9d0_add_mail_quota.py
@@ -8,15 +8,15 @@ Revision ID: e5f6a7b8c9d0
Revises: d4e5f6a7b8c9
"""
-from typing import Sequence, Union
+from collections.abc import Sequence
import sqlalchemy as sa
from alembic import op
revision: str = "e5f6a7b8c9d0"
-down_revision: Union[str, Sequence[str], None] = "d4e5f6a7b8c9"
-branch_labels: Union[str, Sequence[str], None] = None
-depends_on: Union[str, Sequence[str], None] = None
+down_revision: str | Sequence[str] | None = "d4e5f6a7b8c9"
+branch_labels: str | Sequence[str] | None = None
+depends_on: str | Sequence[str] | None = None
def upgrade() -> None:
diff --git a/packages/meshbay-hub/src/meshbay_hub/db/migrations/versions/f1a2b3c4d5e6_add_user_preferences.py b/packages/meshbay-hub/src/meshbay_hub/db/migrations/versions/f1a2b3c4d5e6_add_user_preferences.py
index e30a4da..9f8e729 100644
--- a/packages/meshbay-hub/src/meshbay_hub/db/migrations/versions/f1a2b3c4d5e6_add_user_preferences.py
+++ b/packages/meshbay-hub/src/meshbay_hub/db/migrations/versions/f1a2b3c4d5e6_add_user_preferences.py
@@ -5,16 +5,15 @@ Revises: d28b9caf9f07
Create Date: 2026-08-19 12:00:00.000000
"""
-from typing import Sequence, Union
+from collections.abc import Sequence
-from alembic import op
import sqlalchemy as sa
-
+from alembic import op
revision: str = 'f1a2b3c4d5e6'
-down_revision: Union[str, Sequence[str], None] = 'd28b9caf9f07'
-branch_labels: Union[str, Sequence[str], None] = None
-depends_on: Union[str, Sequence[str], None] = None
+down_revision: str | Sequence[str] | None = 'd28b9caf9f07'
+branch_labels: str | Sequence[str] | None = None
+depends_on: str | Sequence[str] | None = None
def upgrade() -> None:
diff --git a/packages/meshbay-hub/src/meshbay_hub/db/models.py b/packages/meshbay-hub/src/meshbay_hub/db/models.py
index 62e4a11..38c4723 100644
--- a/packages/meshbay-hub/src/meshbay_hub/db/models.py
+++ b/packages/meshbay-hub/src/meshbay_hub/db/models.py
@@ -11,17 +11,23 @@ Tables:
"""
import uuid
-from datetime import datetime, timezone
+from datetime import UTC, datetime
from sqlalchemy import (
- Boolean, DateTime, ForeignKey, Index, Integer,
- String, Text, UniqueConstraint, text,
+ Boolean,
+ DateTime,
+ ForeignKey,
+ Index,
+ Integer,
+ String,
+ Text,
+ text,
)
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship
def _now() -> datetime:
- return datetime.now(timezone.utc)
+ return datetime.now(UTC)
def _uuid() -> str:
return str(uuid.uuid4())
diff --git a/packages/meshbay-hub/src/meshbay_hub/login_throttle.py b/packages/meshbay-hub/src/meshbay_hub/login_throttle.py
index 3281088..bfd142e 100644
--- a/packages/meshbay-hub/src/meshbay_hub/login_throttle.py
+++ b/packages/meshbay-hub/src/meshbay_hub/login_throttle.py
@@ -24,7 +24,7 @@ locks somebody else's name from signing them out (§13.5b, AV26).
"""
import hashlib
-from datetime import datetime, timedelta, timezone
+from datetime import UTC, datetime, timedelta
from sqlalchemy import case, delete, select, update
from sqlalchemy.ext.asyncio import AsyncSession
@@ -39,7 +39,7 @@ def _key(username: str) -> str:
def _aware(dt: datetime) -> datetime:
# SQLite hands back naive datetimes for a timezone-aware column.
- return dt if dt.tzinfo is not None else dt.replace(tzinfo=timezone.utc)
+ return dt if dt.tzinfo is not None else dt.replace(tzinfo=UTC)
def _insert_for(db: AsyncSession):
@@ -64,7 +64,7 @@ async def reserve(db: AsyncSession, username: str) -> tuple[bool, int]:
if max_failures == 0:
return True, 0
- now = datetime.now(timezone.utc)
+ now = datetime.now(UTC)
window = timedelta(minutes=limits["lockout_minutes"])
window_start = now - window
key = _key(username)
@@ -102,7 +102,7 @@ async def locked_for(db: AsyncSession, username: str) -> int:
return 0
remaining = (_aware(row.last_failure_at)
+ timedelta(minutes=limits["lockout_minutes"])
- - datetime.now(timezone.utc)).total_seconds()
+ - datetime.now(UTC)).total_seconds()
return max(0, int(remaining + 0.999))
@@ -136,7 +136,7 @@ async def clear(db: AsyncSession, username: str) -> None:
async def purge_expired(db: AsyncSession) -> int:
"""Rows whose failures have aged out. Every unknown name typed creates one."""
limits = await hub_settings.login_limits(db)
- cutoff = datetime.now(timezone.utc) - timedelta(minutes=limits["lockout_minutes"])
+ cutoff = datetime.now(UTC) - timedelta(minutes=limits["lockout_minutes"])
result = await db.execute(
delete(LoginThrottle).where(LoginThrottle.last_failure_at < cutoff))
await db.commit()
diff --git a/packages/meshbay-hub/src/meshbay_hub/mail.py b/packages/meshbay-hub/src/meshbay_hub/mail.py
index 126ed45..1eb7c51 100644
--- a/packages/meshbay-hub/src/meshbay_hub/mail.py
+++ b/packages/meshbay-hub/src/meshbay_hub/mail.py
@@ -16,7 +16,7 @@ import asyncio
import hashlib
import logging
import smtplib
-from datetime import datetime, timedelta, timezone
+from datetime import UTC, datetime, timedelta
from email.message import EmailMessage
log = logging.getLogger(__name__)
@@ -79,7 +79,7 @@ async def _take(db, key: str, window: timedelta, ceiling: int,
"""
from meshbay_hub.db.models import MailQuota
- now = datetime.now(timezone.utc)
+ now = datetime.now(UTC)
row = await db.get(MailQuota, key)
if row is None:
row = MailQuota(key=key, window_start=now, count=0, last_sent=None)
@@ -87,14 +87,14 @@ async def _take(db, key: str, window: timedelta, ceiling: int,
started = row.window_start
if started.tzinfo is None:
- started = started.replace(tzinfo=timezone.utc)
+ started = started.replace(tzinfo=UTC)
if now - started >= window:
row.window_start, row.count = now, 0
if cooldown is not None and row.last_sent is not None:
last = row.last_sent
if last.tzinfo is None:
- last = last.replace(tzinfo=timezone.utc)
+ last = last.replace(tzinfo=UTC)
if now - last < cooldown:
raise MailRefused("too soon since the last message to this recipient")
@@ -131,12 +131,12 @@ async def _announce_exhaustion(scope: str) -> None:
try:
async with get_session_factory()() as db:
key = f"alert:{scope}"
- now = datetime.now(timezone.utc)
+ now = datetime.now(UTC)
row = await db.get(MailQuota, key)
if row is not None and row.last_sent is not None:
last = row.last_sent
if last.tzinfo is None:
- last = last.replace(tzinfo=timezone.utc)
+ last = last.replace(tzinfo=UTC)
if now - last < timedelta(hours=1):
return
if row is None:
@@ -202,9 +202,10 @@ async def reserve(db, purpose: str, address: str) -> None:
async def status(db) -> dict:
"""What the operator sees in the panel: is the hub still sending?"""
+ from sqlalchemy import func, select
+
from meshbay_hub import hub_settings
from meshbay_hub.db.models import MailQuota
- from sqlalchemy import func, select
limits = await hub_settings.mail_limits(db)
row = await db.get(MailQuota, "hour")
@@ -213,8 +214,8 @@ async def status(db) -> dict:
if row is not None:
started = row.window_start
if started.tzinfo is None:
- started = started.replace(tzinfo=timezone.utc)
- if datetime.now(timezone.utc) - started < timedelta(hours=1):
+ started = started.replace(tzinfo=UTC)
+ if datetime.now(UTC) - started < timedelta(hours=1):
used, window_start = row.count, started.isoformat()
recipients = await db.scalar(
@@ -244,10 +245,11 @@ async def status(db) -> dict:
async def purge_expired_quota(db) -> int:
"""Drop counters whose window has passed. Returns how many went."""
- from meshbay_hub.db.models import MailQuota
from sqlalchemy import delete
- cutoff = datetime.now(timezone.utc) - timedelta(days=1)
+ from meshbay_hub.db.models import MailQuota
+
+ cutoff = datetime.now(UTC) - timedelta(days=1)
result = await db.execute(
delete(MailQuota).where(MailQuota.window_start < cutoff))
await db.commit()
diff --git a/packages/meshbay-hub/src/meshbay_hub/tasks/cleanup.py b/packages/meshbay-hub/src/meshbay_hub/tasks/cleanup.py
index 5c52387..429575f 100644
--- a/packages/meshbay-hub/src/meshbay_hub/tasks/cleanup.py
+++ b/packages/meshbay-hub/src/meshbay_hub/tasks/cleanup.py
@@ -2,7 +2,7 @@
import asyncio
import logging
-from datetime import datetime, timedelta, timezone
+from datetime import UTC, datetime, timedelta
from sqlalchemy import delete, select
from sqlalchemy.ext.asyncio import AsyncSession
@@ -16,7 +16,7 @@ CLEANUP_INTERVAL_HOURS = 24
async def purge_old_ip_logs(db: AsyncSession, retention_days: int = RETENTION_DAYS) -> int:
- cutoff = datetime.now(timezone.utc) - timedelta(days=retention_days)
+ cutoff = datetime.now(UTC) - timedelta(days=retention_days)
result = await db.execute(delete(IPLog).where(IPLog.timestamp < cutoff))
await db.commit()
return result.rowcount
@@ -26,7 +26,7 @@ PENDING_USER_EXPIRY_DAYS = 7
async def purge_expired_verifications(db: AsyncSession) -> int:
- now = datetime.now(timezone.utc)
+ now = datetime.now(UTC)
result = await db.execute(
delete(EmailVerification).where(EmailVerification.expires_at < now))
await db.commit()
@@ -35,7 +35,7 @@ async def purge_expired_verifications(db: AsyncSession) -> int:
async def purge_stale_pending_users(db: AsyncSession,
expiry_days: int = PENDING_USER_EXPIRY_DAYS) -> int:
- cutoff = datetime.now(timezone.utc) - timedelta(days=expiry_days)
+ cutoff = datetime.now(UTC) - timedelta(days=expiry_days)
result = await db.execute(
delete(User).where(User.status == "pending", User.created_at < cutoff))
await db.commit()
@@ -93,7 +93,7 @@ async def find_unhosted_groups(db: AsyncSession, grace_days: int = UNHOSTED_GRAC
whole reason the column exists rather than a check against the live socket
registry, which would delete every group during a hub restart.
"""
- cutoff = datetime.now(timezone.utc) - timedelta(days=grace_days)
+ cutoff = datetime.now(UTC) - timedelta(days=grace_days)
result = await db.execute(
select(Group).where(Group.hosted_at.is_(None), Group.created_at < cutoff))
return list(result.scalars().all())
diff --git a/packages/meshbay-hub/tests/conftest.py b/packages/meshbay-hub/tests/conftest.py
index bf94464..bb0ed28 100644
--- a/packages/meshbay-hub/tests/conftest.py
+++ b/packages/meshbay-hub/tests/conftest.py
@@ -1,12 +1,12 @@
"""Shared pytest fixtures for hub tests."""
import os
+from pathlib import Path
+
import pytest
import pytest_asyncio
-from pathlib import Path
-from unittest.mock import AsyncMock
-from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives import serialization
+from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
# Force SQLite in-memory for all hub tests
os.environ.setdefault("MESHBAY_DATABASE_URL", "sqlite+aiosqlite:///:memory:")
@@ -28,7 +28,13 @@ def hub_key_path(tmp_path_factory) -> Path:
@pytest.fixture
def hub_config(hub_key_path, tmp_path):
- from meshbay_hub.config import HubConfig, DatabaseConfig, ServerConfig, HubIdentityConfig, JWTConfig
+ from meshbay_hub.config import (
+ DatabaseConfig,
+ HubConfig,
+ HubIdentityConfig,
+ JWTConfig,
+ ServerConfig,
+ )
cfg = HubConfig(
db=DatabaseConfig(url="sqlite+aiosqlite:///:memory:"),
server=ServerConfig(host="127.0.0.1", port=8000),
diff --git a/packages/meshbay-hub/tests/harness/chat_send_probe.py b/packages/meshbay-hub/tests/harness/chat_send_probe.py
index b6dd957..d343c50 100644
--- a/packages/meshbay-hub/tests/harness/chat_send_probe.py
+++ b/packages/meshbay-hub/tests/harness/chat_send_probe.py
@@ -96,7 +96,6 @@ def _page() -> str:
the page built itself would prove only that the page agrees with the page.
"""
import msgpack # noqa: F401 (imported for the failure it gives if absent)
-
from meshbay_common.groupbox import PURPOSE_CHAT_KEYS, seal
sealed = seal(GEK, PURPOSE_CHAT_KEYS, "chat_keys_resp", GROUP_ID,
diff --git a/packages/meshbay-hub/tests/test_account_deletion.py b/packages/meshbay-hub/tests/test_account_deletion.py
index 3d3fee4..2653f0d 100644
--- a/packages/meshbay-hub/tests/test_account_deletion.py
+++ b/packages/meshbay-hub/tests/test_account_deletion.py
@@ -12,9 +12,8 @@ command.
import hashlib
import pytest
-from sqlalchemy import select
-
from meshbay_hub.db.models import GroupMember, Notification, RefreshToken, User
+from sqlalchemy import select
def _auth_key(password: str, username: str) -> str:
diff --git a/packages/meshbay-hub/tests/test_account_pinning.py b/packages/meshbay-hub/tests/test_account_pinning.py
index 192bd25..a1419c3 100644
--- a/packages/meshbay-hub/tests/test_account_pinning.py
+++ b/packages/meshbay-hub/tests/test_account_pinning.py
@@ -23,7 +23,6 @@ from pathlib import Path
import pytest
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
-
from meshbay_common.device import device_add_transcript
STATIC = (Path(__file__).resolve().parents[1]
diff --git a/packages/meshbay-hub/tests/test_admin_views.py b/packages/meshbay-hub/tests/test_admin_views.py
index 5017b76..da2d3c9 100644
--- a/packages/meshbay-hub/tests/test_admin_views.py
+++ b/packages/meshbay-hub/tests/test_admin_views.py
@@ -11,9 +11,8 @@ import base64
import hashlib
import pytest
-from sqlalchemy import select
-
from meshbay_hub.db.models import User
+from sqlalchemy import select
def _auth_key(password: str, username: str) -> str:
@@ -109,9 +108,8 @@ async def test_a_node_is_recorded_at_the_address_it_announced_from(
import base64
import time
- from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives import serialization
-
+ from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from meshbay_hub.db.models import Node
admin = await _admin(client, db_session, "root4_test")
diff --git a/packages/meshbay-hub/tests/test_asset_versioning.py b/packages/meshbay-hub/tests/test_asset_versioning.py
index 0c93f5a..aa2dc6d 100644
--- a/packages/meshbay-hub/tests/test_asset_versioning.py
+++ b/packages/meshbay-hub/tests/test_asset_versioning.py
@@ -22,7 +22,6 @@ import re
import pytest
from fastapi.testclient import TestClient
-
from meshbay_hub.api.webapp import ASSET_V, STATIC_DIR, _asset_version
from meshbay_hub.app import create_app
diff --git a/packages/meshbay-hub/tests/test_availability_between_members.py b/packages/meshbay-hub/tests/test_availability_between_members.py
index 2be7c03..4f5cbfb 100644
--- a/packages/meshbay-hub/tests/test_availability_between_members.py
+++ b/packages/meshbay-hub/tests/test_availability_between_members.py
@@ -24,7 +24,6 @@ import time
import pytest
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey
-
from meshbay_common.crypto import pk_to_b64
@@ -158,8 +157,7 @@ async def test_one_node_cannot_spend_the_hubs_database_on_notifications():
without backpressure. The budget is what stops one group's node from
costing every other group on the instance.
"""
- from meshbay_hub.api.revocation import (
- NOTIFY_BURST, _notify_budget, _notify_window)
+ from meshbay_hub.api.revocation import NOTIFY_BURST, _notify_budget, _notify_window
node = "budget-node"
_notify_window.pop(node, None)
@@ -265,8 +263,7 @@ def test_a_node_cannot_answer_an_offer_it_was_never_sent():
"""
import asyncio
- from meshbay_hub.api.signaling import (
- _answer_owner, _webrtc_answers, handle_webrtc_answer)
+ from meshbay_hub.api.signaling import _answer_owner, _webrtc_answers, handle_webrtc_answer
loop = asyncio.new_event_loop()
try:
@@ -657,6 +654,7 @@ async def test_a_member_still_reaches_the_node_they_share_a_group_with(client):
class _AnsweringWS:
async def send_text(self, text):
import json as _json
+
from meshbay_hub.api.signaling import handle_webrtc_answer
msg = _json.loads(text)
answered.append(msg)
diff --git a/packages/meshbay-hub/tests/test_captcha_host_check.py b/packages/meshbay-hub/tests/test_captcha_host_check.py
index 68cad34..778009f 100644
--- a/packages/meshbay-hub/tests/test_captcha_host_check.py
+++ b/packages/meshbay-hub/tests/test_captcha_host_check.py
@@ -31,12 +31,10 @@ TOML list is a typo far more often than an intention.
import json
import pytest
-
from meshbay_hub.captcha import verify_captcha
from meshbay_hub.config import CaptchaConfig, load_config
-
class _Resp:
def __init__(self, payload):
self._payload = payload
diff --git a/packages/meshbay-hub/tests/test_device_auth.py b/packages/meshbay-hub/tests/test_device_auth.py
index e899f12..f9b172e 100644
--- a/packages/meshbay-hub/tests/test_device_auth.py
+++ b/packages/meshbay-hub/tests/test_device_auth.py
@@ -21,9 +21,7 @@ stopped being true.
import base64
import time
-import pytest
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
-
from meshbay_common.crypto import pk_to_b64
diff --git a/packages/meshbay-hub/tests/test_group_hosting.py b/packages/meshbay-hub/tests/test_group_hosting.py
index c571771..c6111f2 100644
--- a/packages/meshbay-hub/tests/test_group_hosting.py
+++ b/packages/meshbay-hub/tests/test_group_hosting.py
@@ -14,13 +14,12 @@ deleted every group during a hub restart.
import base64
import hashlib
-from datetime import datetime, timedelta, timezone
+from datetime import UTC, datetime, timedelta
import pytest
-from sqlalchemy import select
-
from meshbay_hub.db.models import Group, GroupMember
from meshbay_hub.tasks.cleanup import find_unhosted_groups, prune_unhosted_groups
+from sqlalchemy import select
def _auth_key(password: str, username: str) -> str:
@@ -49,7 +48,7 @@ async def _group(client, owner, name, visibility="private", join_policy=None):
async def _mark_hosted(db_session, group_id, when=None):
g = await db_session.get(Group, group_id)
- g.hosted_at = when or datetime.now(timezone.utc)
+ g.hosted_at = when or datetime.now(UTC)
await db_session.commit()
@@ -134,7 +133,7 @@ async def test_an_unhosted_group_past_the_grace_period_is_collected(client, db_s
gid = (await _group(client, owner, "abandoned")).json()["group_id"]
g = await db_session.get(Group, gid)
- g.created_at = datetime.now(timezone.utc) - timedelta(days=8)
+ g.created_at = datetime.now(UTC) - timedelta(days=8)
await db_session.commit()
gone = await prune_unhosted_groups(db_session)
@@ -149,8 +148,8 @@ async def test_an_old_group_that_was_hosted_is_never_collected(client, db_sessio
gid = (await _group(client, owner, "long-lived")).json()["group_id"]
g = await db_session.get(Group, gid)
- g.created_at = datetime.now(timezone.utc) - timedelta(days=400)
- g.hosted_at = datetime.now(timezone.utc) - timedelta(days=399)
+ g.created_at = datetime.now(UTC) - timedelta(days=400)
+ g.hosted_at = datetime.now(UTC) - timedelta(days=399)
await db_session.commit()
assert await find_unhosted_groups(db_session) == []
@@ -161,7 +160,7 @@ async def test_dry_run_reports_without_deleting(client, db_session):
owner = await _user(client, "reaper4_test")
gid = (await _group(client, owner, "still-here")).json()["group_id"]
g = await db_session.get(Group, gid)
- g.created_at = datetime.now(timezone.utc) - timedelta(days=30)
+ g.created_at = datetime.now(UTC) - timedelta(days=30)
await db_session.commit()
gone = await prune_unhosted_groups(db_session, dry_run=True)
@@ -178,7 +177,7 @@ async def test_collecting_a_group_takes_its_memberships_with_it(client, db_sessi
await client.post(f"/v1/groups/{gid}/members/tagalong", json={}, headers=owner)
g = await db_session.get(Group, gid)
- g.created_at = datetime.now(timezone.utc) - timedelta(days=9)
+ g.created_at = datetime.now(UTC) - timedelta(days=9)
await db_session.commit()
await prune_unhosted_groups(db_session)
@@ -247,7 +246,7 @@ async def test_the_stamp_is_not_moved_by_a_later_reconnection(client, db_session
owner = await _user(client, "stamped2")
gid = (await _group(client, owner, "steady")).json()["group_id"]
- first = datetime.now(timezone.utc) - timedelta(days=30)
+ first = datetime.now(UTC) - timedelta(days=30)
await _mark_hosted([gid])
g = await db_session.get(Group, gid)
g.hosted_at = first
@@ -259,7 +258,7 @@ async def test_the_stamp_is_not_moved_by_a_later_reconnection(client, db_session
await db_session.refresh(g)
# SQLite hands back a naive datetime where PostgreSQL keeps the offset, so
# the comparison is made on common ground rather than on the driver.
- stored = g.hosted_at.replace(tzinfo=timezone.utc) if g.hosted_at.tzinfo is None \
+ stored = g.hosted_at.replace(tzinfo=UTC) if g.hosted_at.tzinfo is None \
else g.hosted_at
assert abs((stored - first).total_seconds()) < 1, "the stamp moved"
diff --git a/packages/meshbay-hub/tests/test_group_leave_and_quota.py b/packages/meshbay-hub/tests/test_group_leave_and_quota.py
index 4431f53..8af830d 100644
--- a/packages/meshbay-hub/tests/test_group_leave_and_quota.py
+++ b/packages/meshbay-hub/tests/test_group_leave_and_quota.py
@@ -14,13 +14,12 @@ removes them, and whoever left still holds the group key they were served.
import base64
import hashlib
-from datetime import datetime, timezone
+from datetime import UTC, datetime
import pytest
-from sqlalchemy import select
-
from meshbay_hub.api.groups import MAX_PUBLIC_GROUPS
from meshbay_hub.db.models import Group, GroupMember, User
+from sqlalchemy import select
def _auth_key(password: str, username: str) -> str:
@@ -61,7 +60,7 @@ async def test_a_member_can_leave(client, db_session):
# Marked hosted, or the member would not see the group in the first place
# and the assertion below would hold whether or not leaving worked.
g = await db_session.get(Group, gid)
- g.hosted_at = datetime.now(timezone.utc)
+ g.hosted_at = datetime.now(UTC)
await db_session.commit()
before = await client.get("/v1/groups/mine", headers=member)
diff --git a/packages/meshbay-hub/tests/test_group_membership.py b/packages/meshbay-hub/tests/test_group_membership.py
index 2761595..ad1b3ab 100644
--- a/packages/meshbay-hub/tests/test_group_membership.py
+++ b/packages/meshbay-hub/tests/test_group_membership.py
@@ -11,10 +11,9 @@ import base64
import hashlib
import pytest
+from meshbay_hub.db.models import GroupMember, User
from sqlalchemy import select
-from meshbay_hub.db.models import Group, GroupMember, User
-
def _auth_key(password: str, username: str) -> str:
salt = hashlib.sha256(f"meshbay:auth:v1:{username}".encode()).digest()
diff --git a/packages/meshbay-hub/tests/test_group_purge.py b/packages/meshbay-hub/tests/test_group_purge.py
index 0611dba..e729297 100644
--- a/packages/meshbay-hub/tests/test_group_purge.py
+++ b/packages/meshbay-hub/tests/test_group_purge.py
@@ -21,13 +21,18 @@ from datetime import UTC, datetime, timedelta
import jwt
import pytest
-from sqlalchemy import delete, func, select, text
-from sqlalchemy.exc import IntegrityError
-
from meshbay_hub.db.models import (
- ContentReport, EmailVerification, Group, GroupMember, IPLog, Notification, User,
+ ContentReport,
+ EmailVerification,
+ Group,
+ GroupMember,
+ IPLog,
+ Notification,
+ User,
)
from meshbay_hub.db.purge import _referencing
+from sqlalchemy import delete, func, select, text
+from sqlalchemy.exc import IntegrityError
SEEDED = {"group_members", "notifications", "email_verifications", "content_reports"}
diff --git a/packages/meshbay-hub/tests/test_groups_self_service.py b/packages/meshbay-hub/tests/test_groups_self_service.py
index f9346c1..a3a8f2d 100644
--- a/packages/meshbay-hub/tests/test_groups_self_service.py
+++ b/packages/meshbay-hub/tests/test_groups_self_service.py
@@ -1,9 +1,10 @@
"""Integration tests for group self-service: create, join, members."""
+from datetime import UTC
+
import pytest
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey
-
from meshbay_common.crypto import pk_to_b64
@@ -43,10 +44,11 @@ async def _create_group(client, token, name="test-group", visibility="public",
async def _mark_hosted(db_session, *group_ids):
"""Pretend a node announced these groups, as /v1/nodes/ws would."""
- from datetime import datetime, timezone
+ from datetime import datetime
+
from meshbay_hub.db.models import Group
for gid in group_ids:
- (await db_session.get(Group, gid)).hosted_at = datetime.now(timezone.utc)
+ (await db_session.get(Group, gid)).hosted_at = datetime.now(UTC)
await db_session.commit()
diff --git a/packages/meshbay-hub/tests/test_hub_api.py b/packages/meshbay-hub/tests/test_hub_api.py
index 37e8e4f..9b73701 100644
--- a/packages/meshbay-hub/tests/test_hub_api.py
+++ b/packages/meshbay-hub/tests/test_hub_api.py
@@ -3,13 +3,11 @@ Integration tests for the Hub API.
Uses SQLite in-memory + httpx.AsyncClient — no PostgreSQL, no network.
"""
-import base64
+from datetime import UTC
+
import pytest
-import pytest_asyncio
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey
-from cryptography.hazmat.primitives import serialization
-
from meshbay_common.crypto import pk_to_b64
from meshbay_hub.api.deps import set_admin_usernames
@@ -32,7 +30,8 @@ async def _announce_signed(client, token: str) -> tuple[str, str]:
The node key is independent of the user's identity key, so this mints a fresh
one and signs the domain-separated announce message with it.
"""
- import base64 as _b64, time as _t
+ import base64 as _b64
+ import time as _t
me = await client.get("/v1/users/me",
headers={"Authorization": f"Bearer {token}"})
@@ -399,9 +398,10 @@ async def test_my_groups(client, db_session):
# A group no node has announced is shown to its owner only — a member would
# otherwise see a name they cannot open. Stamped here so the rest of this
# test is about membership, which is what it was written for.
- from datetime import datetime, timezone
+ from datetime import datetime
+
from meshbay_hub.db.models import Group
- (await db_session.get(Group, group_id)).hosted_at = datetime.now(timezone.utc)
+ (await db_session.get(Group, group_id)).hosted_at = datetime.now(UTC)
await db_session.commit()
# Re-login to get fresh token with group claims
@@ -434,7 +434,6 @@ async def test_my_groups(client, db_session):
@pytest.mark.asyncio
async def test_group_online_nodes(client):
"""GET /v1/groups/{id}/nodes returns online nodes serving the group."""
- import json
from meshbay_hub.api.revocation import _connected_nodes, _node_groups
pk_ed, pk_x, _ = _gen_user_keys()
@@ -541,7 +540,7 @@ async def test_admin_can_revoke(client):
@pytest.mark.asyncio
async def test_email_encrypted_at_rest(client):
"""Email stored in DB must not contain plaintext address."""
- from meshbay_hub.auth import encrypt_email, decrypt_email
+ from meshbay_hub.auth import decrypt_email, encrypt_email
encrypted = encrypt_email("test@example.com")
assert "@" not in encrypted
assert decrypt_email(encrypted) == "test@example.com"
@@ -589,9 +588,10 @@ async def test_password_rehash_on_login(client, app):
user = result.scalar_one()
user.pw_version = 1
# Re-hash with v1 params so verify_password(version=1) succeeds
- from meshbay_hub.auth import _ARGON2_VERSIONS, _ARGON2_KEY_LEN, _ARGON2_LANES
- from cryptography.hazmat.primitives.kdf.argon2 import Argon2id
import os
+
+ from cryptography.hazmat.primitives.kdf.argon2 import Argon2id
+ from meshbay_hub.auth import _ARGON2_KEY_LEN, _ARGON2_LANES, _ARGON2_VERSIONS
salt = os.urandom(16)
params = _ARGON2_VERSIONS[1]
pw_hash = Argon2id(
@@ -760,13 +760,14 @@ async def test_webrtc_signaling_roundtrip(client, app):
@pytest.mark.asyncio
async def test_ip_log_cleanup(app):
"""Old IP log entries are purged by cleanup task."""
- from datetime import datetime, timezone, timedelta
+ from datetime import datetime, timedelta
+
from meshbay_hub.db.engine import get_db
from meshbay_hub.db.models import IPLog
from meshbay_hub.tasks.cleanup import purge_old_ip_logs
async for db in get_db():
- old_ts = datetime.now(timezone.utc) - timedelta(days=400)
+ old_ts = datetime.now(UTC) - timedelta(days=400)
db.add(IPLog(event="test_old", ip_address="1.2.3.4", timestamp=old_ts))
db.add(IPLog(event="test_recent", ip_address="5.6.7.8"))
await db.commit()
@@ -774,7 +775,7 @@ async def test_ip_log_cleanup(app):
deleted = await purge_old_ip_logs(db, retention_days=365)
assert deleted == 1
- from sqlalchemy import select, func
+ from sqlalchemy import func, select
count = (await db.execute(
select(func.count()).where(IPLog.event.in_(["test_old", "test_recent"]))
)).scalar_one()
diff --git a/packages/meshbay-hub/tests/test_login_lockout.py b/packages/meshbay-hub/tests/test_login_lockout.py
index 6f17d98..601edbd 100644
--- a/packages/meshbay-hub/tests/test_login_lockout.py
+++ b/packages/meshbay-hub/tests/test_login_lockout.py
@@ -18,14 +18,13 @@ is `test_availability_between_members.py`, because it takes two accounts.
"""
import asyncio
-from datetime import datetime, timedelta, timezone
+from datetime import UTC, datetime, timedelta
import pytest
-from sqlalchemy import select, update
-
from meshbay_hub.api.deps import set_admin_usernames
from meshbay_hub.db.models import LoginThrottle
from meshbay_hub.login_throttle import _key
+from sqlalchemy import select, update
RIGHT = "r" * 44
WRONG = "w" * 44
@@ -94,7 +93,7 @@ async def test_a_lockout_ends_when_its_window_does(client, db_session):
await db_session.execute(
update(LoginThrottle).where(LoginThrottle.key == _key("dave_test"))
- .values(last_failure_at=datetime.now(timezone.utc) - timedelta(minutes=61)))
+ .values(last_failure_at=datetime.now(UTC) - timedelta(minutes=61)))
await db_session.commit()
assert (await _login(client, "dave_test", RIGHT)).status_code == 200
@@ -106,7 +105,7 @@ async def test_old_failures_do_not_carry_into_a_new_window(client, db_session):
await _fail(client, "erin_test", 3)
await db_session.execute(
update(LoginThrottle).where(LoginThrottle.key == _key("erin_test"))
- .values(last_failure_at=datetime.now(timezone.utc) - timedelta(minutes=61)))
+ .values(last_failure_at=datetime.now(UTC) - timedelta(minutes=61)))
await db_session.commit()
# One stale window of three, then one fresh failure: a count of one, not four.
diff --git a/packages/meshbay-hub/tests/test_mail_is_not_a_relay.py b/packages/meshbay-hub/tests/test_mail_is_not_a_relay.py
index fe6a5ee..a3f9a21 100644
--- a/packages/meshbay-hub/tests/test_mail_is_not_a_relay.py
+++ b/packages/meshbay-hub/tests/test_mail_is_not_a_relay.py
@@ -28,7 +28,6 @@ import base64
import pytest
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey
-
from meshbay_common.crypto import pk_to_b64
from meshbay_hub import mail as mail_mod
from meshbay_hub.api import users as users_mod
@@ -316,9 +315,8 @@ async def _signed_in(client, db_session, username: str, email: str) -> dict:
genuinely `pending` here, exactly as it would be in production, and a
pending account cannot log in.
"""
- from sqlalchemy import select, update
-
from meshbay_hub.db.models import User
+ from sqlalchemy import select, update
r = await _register(client, username, email)
assert r.status_code == 201, r.text
@@ -406,9 +404,8 @@ async def test_the_delay_survives_the_verification_row_being_deleted(
json={"email": "c-first@example.test"})
assert r.status_code == 200, r.text
- from sqlalchemy import delete
-
from meshbay_hub.db.models import EmailVerification
+ from sqlalchemy import delete
await db_session.execute(delete(EmailVerification))
await db_session.commit()
@@ -421,9 +418,8 @@ async def test_the_delay_survives_the_verification_row_being_deleted(
# ── The operator's controls ──────────────────────────────────────────────────
async def _admin(client, db_session, username: str) -> dict:
- from sqlalchemy import update
-
from meshbay_hub.db.models import User
+ from sqlalchemy import update
headers = await _signed_in(client, db_session, username,
f"{username}@example.test")
@@ -491,9 +487,8 @@ async def test_an_unknown_mail_setting_is_refused(client, db_session):
@pytest.mark.asyncio
async def test_a_moderator_may_read_the_bounds_but_not_change_them(
client, db_session):
- from sqlalchemy import update
-
from meshbay_hub.db.models import User
+ from sqlalchemy import update
headers = await _signed_in(client, db_session, "mailmod_test",
"mailmod@example.test")
diff --git a/packages/meshbay-hub/tests/test_migrations_reach_head.py b/packages/meshbay-hub/tests/test_migrations_reach_head.py
index 13c5590..7f0d5df 100644
--- a/packages/meshbay-hub/tests/test_migrations_reach_head.py
+++ b/packages/meshbay-hub/tests/test_migrations_reach_head.py
@@ -30,9 +30,8 @@ from pathlib import Path
import pytest
from alembic import command
from alembic.config import Config
-from sqlalchemy import create_engine, inspect
-
from meshbay_hub.db.models import Base
+from sqlalchemy import create_engine, inspect
HUB = Path(__file__).resolve().parents[1]
diff --git a/packages/meshbay-hub/tests/test_node_auth.py b/packages/meshbay-hub/tests/test_node_auth.py
index 4137932..09816de 100644
--- a/packages/meshbay-hub/tests/test_node_auth.py
+++ b/packages/meshbay-hub/tests/test_node_auth.py
@@ -8,9 +8,9 @@ import base64
import time
import pytest
+from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey
-from cryptography.hazmat.primitives import serialization
def _gen_ed25519():
diff --git a/packages/meshbay-hub/tests/test_node_ws_auth.py b/packages/meshbay-hub/tests/test_node_ws_auth.py
index f3ac3a2..7d96851 100644
--- a/packages/meshbay-hub/tests/test_node_ws_auth.py
+++ b/packages/meshbay-hub/tests/test_node_ws_auth.py
@@ -16,7 +16,6 @@ import base64
import pytest
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey
-
from meshbay_common.crypto import pk_to_b64
@@ -405,7 +404,10 @@ async def test_empty_node_cannot_shadow_another_members_group(client):
source for that group, because it is the one clients would reach first.
"""
from meshbay_hub.api.revocation import (
- _authorize_node_ws, _node_groups, get_online_nodes_for_group)
+ _authorize_node_ws,
+ _node_groups,
+ get_online_nodes_for_group,
+ )
host = await _make_user(client, "hoster_test")
guest = await _make_user(client, "guest_test")
diff --git a/packages/meshbay-hub/tests/test_notification_dismissal.py b/packages/meshbay-hub/tests/test_notification_dismissal.py
index 1c9c7b3..d498b4d 100644
--- a/packages/meshbay-hub/tests/test_notification_dismissal.py
+++ b/packages/meshbay-hub/tests/test_notification_dismissal.py
@@ -32,7 +32,6 @@ from pathlib import Path
import pytest
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey
-
from meshbay_common.crypto import pk_to_b64
from meshbay_hub.api.deps import set_admin_usernames
diff --git a/packages/meshbay-hub/tests/test_notifications.py b/packages/meshbay-hub/tests/test_notifications.py
index 02aca1c..b87e1d5 100644
--- a/packages/meshbay-hub/tests/test_notifications.py
+++ b/packages/meshbay-hub/tests/test_notifications.py
@@ -3,7 +3,6 @@
import pytest
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey
-
from meshbay_common.crypto import pk_to_b64
from meshbay_hub.api.deps import set_admin_usernames
diff --git a/packages/meshbay-hub/tests/test_notifications_behaviour.py b/packages/meshbay-hub/tests/test_notifications_behaviour.py
index a247508..67fd99e 100644
--- a/packages/meshbay-hub/tests/test_notifications_behaviour.py
+++ b/packages/meshbay-hub/tests/test_notifications_behaviour.py
@@ -7,13 +7,12 @@ browser's localStorage and nothing read it), and there was no way to clear the
list.
"""
-import hashlib
import base64
+import hashlib
import pytest
-from sqlalchemy import select
-
from meshbay_hub.db.models import GroupMember, Notification, User
+from sqlalchemy import select
def _auth_key(password: str, username: str) -> str:
diff --git a/packages/meshbay-hub/tests/test_packaging_hub_unit.py b/packages/meshbay-hub/tests/test_packaging_hub_unit.py
index 7d8f5d2..e29164e 100644
--- a/packages/meshbay-hub/tests/test_packaging_hub_unit.py
+++ b/packages/meshbay-hub/tests/test_packaging_hub_unit.py
@@ -85,7 +85,6 @@ def test_the_command_resolves_from_the_installed_package_not_the_checkout():
"""Derived from `meshbay_hub.__file__`, so it is correct in a venv, an RPM
and a checkout alike — which is the whole point of not writing it down."""
import meshbay_hub
-
from meshbay_hub.daemon import migrations_dir
assert migrations_dir() == (
diff --git a/packages/meshbay-hub/tests/test_password_change.py b/packages/meshbay-hub/tests/test_password_change.py
index b2fe586..bfe0c97 100644
--- a/packages/meshbay-hub/tests/test_password_change.py
+++ b/packages/meshbay-hub/tests/test_password_change.py
@@ -11,9 +11,8 @@ import base64
import hashlib
import pytest
-from sqlalchemy import select
-
from meshbay_hub.db.models import IPLog, RefreshToken, User
+from sqlalchemy import select
def _auth_key(password: str, username: str) -> str:
diff --git a/packages/meshbay-hub/tests/test_password_reset.py b/packages/meshbay-hub/tests/test_password_reset.py
index 823807c..b07f77c 100644
--- a/packages/meshbay-hub/tests/test_password_reset.py
+++ b/packages/meshbay-hub/tests/test_password_reset.py
@@ -9,7 +9,7 @@ the recovery key and is not exercised here.
import base64
import time
-from datetime import datetime, timedelta, timezone
+from datetime import UTC, datetime, timedelta
import pytest
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
@@ -126,7 +126,7 @@ async def test_an_expired_code_is_refused(client, db_session):
select(User.id).where(User.username == "carol_test"))).scalar_one()
row = (await db_session.execute(select(EmailVerification).where(
EmailVerification.user_id == uid))).scalars().one()
- row.expires_at = datetime.now(timezone.utc) - timedelta(minutes=1)
+ row.expires_at = datetime.now(UTC) - timedelta(minutes=1)
await db_session.commit()
r = await client.post("/v1/users/password/reset", json={
diff --git a/packages/meshbay-hub/tests/test_public_groups_toggle.py b/packages/meshbay-hub/tests/test_public_groups_toggle.py
index 96e3383..dbc6a38 100644
--- a/packages/meshbay-hub/tests/test_public_groups_toggle.py
+++ b/packages/meshbay-hub/tests/test_public_groups_toggle.py
@@ -17,7 +17,7 @@ and their access — plan A, not a purge.
import base64
import hashlib
-from datetime import datetime, timezone
+from datetime import UTC, datetime
import pytest
from meshbay_hub.api.deps import set_admin_usernames
@@ -61,7 +61,7 @@ async def _create_public(client, owner, name):
async def _mark_hosted(db_session, *group_ids):
"""Pretend a node announced these groups, as /v1/nodes/ws would."""
for gid in group_ids:
- (await db_session.get(Group, gid)).hosted_at = datetime.now(timezone.utc)
+ (await db_session.get(Group, gid)).hosted_at = datetime.now(UTC)
await db_session.commit()
diff --git a/packages/meshbay-hub/tests/test_revocation.py b/packages/meshbay-hub/tests/test_revocation.py
index ad9caf4..e2ca5e7 100644
--- a/packages/meshbay-hub/tests/test_revocation.py
+++ b/packages/meshbay-hub/tests/test_revocation.py
@@ -1,11 +1,9 @@
"""Tests for revocation — admin endpoint + token signing."""
-import time
-import pytest
import jwt
+import pytest
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey
-
from meshbay_common.crypto import pk_to_b64
from meshbay_hub.api.deps import set_admin_usernames
diff --git a/packages/meshbay-hub/tests/test_session_lifetime.py b/packages/meshbay-hub/tests/test_session_lifetime.py
index af73767..3a1f47a 100644
--- a/packages/meshbay-hub/tests/test_session_lifetime.py
+++ b/packages/meshbay-hub/tests/test_session_lifetime.py
@@ -6,13 +6,12 @@ maximum — plus a sign-out the hub honours and "sign out everywhere". The
browser half is `test_browser_idle_signout.py`; this is the hub's.
"""
-from datetime import datetime, timedelta, timezone
+from datetime import UTC, datetime, timedelta
import pytest
-from sqlalchemy import select, update
-
from meshbay_hub.api.deps import set_admin_usernames
from meshbay_hub.db.models import RefreshToken, User
+from sqlalchemy import select, update
AUTH_KEY = "s" * 44
@@ -40,7 +39,7 @@ async def _refresh(client, token):
def _aware(dt):
- return dt if dt.tzinfo else dt.replace(tzinfo=timezone.utc)
+ return dt if dt.tzinfo else dt.replace(tzinfo=UTC)
async def _expiry(db_session, username):
@@ -66,7 +65,7 @@ async def test_the_defaults_are_in_the_panel_and_the_browser_delay_is_public(cli
async def test_a_refresh_token_lasts_the_idle_window(client, db_session):
await _register(client, "idle_window")
await _login(client, "idle_window")
- left = await _expiry(db_session, "idle_window") - datetime.now(timezone.utc)
+ left = await _expiry(db_session, "idle_window") - datetime.now(UTC)
assert timedelta(hours=23, minutes=58) < left <= timedelta(hours=24)
@@ -78,7 +77,7 @@ async def test_the_idle_window_never_undercuts_the_access_token(client, db_sessi
json={"session": {"refresh_idle_hours": 1}})
await _register(client, "short_idle")
await _login(client, "short_idle")
- left = await _expiry(db_session, "short_idle") - datetime.now(timezone.utc)
+ left = await _expiry(db_session, "short_idle") - datetime.now(UTC)
# The test hub's access token lives 3600 s; the floor is that plus an hour.
assert left > timedelta(hours=1, minutes=58)
@@ -98,7 +97,7 @@ async def test_no_session_renews_past_its_maximum(client, db_session):
select(User.id).where(User.username == "long_session"))).scalar_one()
await db_session.execute(
update(RefreshToken).where(RefreshToken.user_id == uid)
- .values(created_at=datetime.now(timezone.utc) - timedelta(hours=721)))
+ .values(created_at=datetime.now(UTC) - timedelta(hours=721)))
await db_session.commit()
r = await _refresh(client, current)
diff --git a/packages/meshbay-hub/tests/test_session_renewal.py b/packages/meshbay-hub/tests/test_session_renewal.py
index 5d4bcfd..7b8c108 100644
--- a/packages/meshbay-hub/tests/test_session_renewal.py
+++ b/packages/meshbay-hub/tests/test_session_renewal.py
@@ -26,9 +26,9 @@ broken client.
"""
import json
+import re
import shutil
import subprocess
-import re
from pathlib import Path
import pytest
diff --git a/packages/meshbay-hub/tests/test_table_rows_measured.py b/packages/meshbay-hub/tests/test_table_rows_measured.py
index 60ec878..f203624 100644
--- a/packages/meshbay-hub/tests/test_table_rows_measured.py
+++ b/packages/meshbay-hub/tests/test_table_rows_measured.py
@@ -16,11 +16,10 @@ rectangles show it does not — which is what this file is for.
"""
import json
+import shutil
import subprocess
from pathlib import Path
-import shutil
-
import pytest
HARNESS = Path(__file__).parent / "harness" / "layout_probe.py"
diff --git a/packages/meshbay-node/src/meshbay_node/config.py b/packages/meshbay-node/src/meshbay_node/config.py
index 2ae3c7c..437f629 100644
--- a/packages/meshbay-node/src/meshbay_node/config.py
+++ b/packages/meshbay-node/src/meshbay_node/config.py
@@ -14,9 +14,9 @@ from pathlib import Path
from meshbay_node.platform import config_dir, data_dir
try:
- import tomllib # Python 3.11+
+ import tomllib # Python 3.11+
except ImportError:
- import tomli as tomllib # type: ignore[no-redef]
+ import tomli as tomllib # type: ignore[no-redef]
log = logging.getLogger(__name__)
diff --git a/packages/meshbay-node/src/meshbay_node/daemon.py b/packages/meshbay-node/src/meshbay_node/daemon.py
index 3492d03..a0ce211 100644
--- a/packages/meshbay-node/src/meshbay_node/daemon.py
+++ b/packages/meshbay-node/src/meshbay_node/daemon.py
@@ -25,43 +25,43 @@ Usage:
"""
import asyncio
-from dataclasses import asdict, replace
import base64
-import json
import logging
import os
import signal
import sys
import time
+from dataclasses import asdict, replace
from pathlib import Path
import uvicorn
-
+from meshbay_common import MNP_VERSION
from meshbay_common.background import spawn
from meshbay_common.paths import fold
-from meshbay_common import MNP_VERSION
from meshbay_common.protocol import MNP
-from meshbay_node.audit import RETENTION_DAYS as AUDIT_RETENTION_DAYS, AuditStore
+
+from meshbay_node import uploads as uploads_mod
+from meshbay_node.audit import RETENTION_DAYS as AUDIT_RETENTION_DAYS
+from meshbay_node.audit import AuditStore
from meshbay_node.bundle_store import BundleStore
from meshbay_node.chat.store import ChatStore
-from meshbay_node.config import Config, DEFAULT_CONFIG_PATH, load_config, write_example_config
-from meshbay_node.roots import RootSet, RootError, entry_abs_path, off_disk
+from meshbay_node.config import DEFAULT_CONFIG_PATH, Config, load_config
from meshbay_node.hub_client import HubClient, HubConfig
-from meshbay_node.indexer import DirectoryIndexer, IndexCache, GroupIndex
+from meshbay_node.indexer import DirectoryIndexer, GroupIndex, IndexCache
from meshbay_node.indexer.enrich import Enricher
from meshbay_node.indexer.enrich_audio import AudioEnricher
from meshbay_node.indexer.enrich_photo import PhotoEnricher
+from meshbay_node.keystore import create_keystore, load_keystore, load_or_create_keystore
from meshbay_node.media_cache import MediaCache
-from meshbay_node.tmdb import TmdbClient
-from meshbay_node import uploads as uploads_mod
from meshbay_node.musicbrainz import MusicBrainzClient
-from meshbay_node.keystore import create_keystore, load_keystore, load_or_create_keystore
from meshbay_node.platform import chmod_private, config_dir, data_dir, state_dir
+from meshbay_node.roots import RootError, RootSet, entry_abs_path, off_disk
from meshbay_node.roster import Roster
+from meshbay_node.tmdb import TmdbClient
from meshbay_node.transport import (
- Denylist,
QUIC_AVAILABLE,
WEBRTC_AVAILABLE,
+ Denylist,
)
from meshbay_node.transport.wire import index_delta_message, index_sync_message
@@ -109,8 +109,8 @@ def _owning_directory(path: str, directories: list[str]) -> str | None:
def calibrate_argon2(target_ms: int = 500) -> None:
"""Benchmark Argon2id and suggest parameters targeting ~target_ms."""
- import time
import os
+ import time
print(f"Calibrating Argon2id (target: {target_ms}ms) ...")
salt = os.urandom(16)
@@ -1938,8 +1938,7 @@ def _systemctl_user(verb: str, unit: str, *, not_running_hint: str,
def main() -> None:
import argparse
- from meshbay_node.platform import (configure_event_loop, force_utf8_stdio,
- load_node_env)
+ from meshbay_node.platform import configure_event_loop, force_utf8_stdio, load_node_env
force_utf8_stdio()
configure_event_loop()
# Before anything reads the environment. On Linux systemd has usually loaded
@@ -2164,10 +2163,10 @@ def main() -> None:
print("Aborted.")
return
- import subprocess as _sp
import json as _json
- import urllib.request
+ import subprocess as _sp
import urllib.error
+ import urllib.request
token_file = data_dir_ / "ui-token"
if token_file.exists():
@@ -2475,7 +2474,11 @@ def main() -> None:
if args.command == "restart-daemon":
if sys.platform == "win32":
from meshbay_node.platform import (
- autostart_end, autostart_run, service_end, service_run, service_status,
+ autostart_end,
+ autostart_run,
+ service_end,
+ service_run,
+ service_status,
)
if service_status()["installed"]:
service_end()
diff --git a/packages/meshbay-node/src/meshbay_node/hub_client.py b/packages/meshbay-node/src/meshbay_node/hub_client.py
index ef12bb4..58bf657 100644
--- a/packages/meshbay-node/src/meshbay_node/hub_client.py
+++ b/packages/meshbay-node/src/meshbay_node/hub_client.py
@@ -20,7 +20,7 @@ import logging
import time
from dataclasses import dataclass, field
from pathlib import Path
-from typing import Any, Callable
+from typing import Any
import httpx
import jwt
diff --git a/packages/meshbay-node/src/meshbay_node/indexer/__init__.py b/packages/meshbay-node/src/meshbay_node/indexer/__init__.py
index c92c730..a40e9f2 100644
--- a/packages/meshbay-node/src/meshbay_node/indexer/__init__.py
+++ b/packages/meshbay-node/src/meshbay_node/indexer/__init__.py
@@ -1,6 +1,6 @@
"""Directory indexer and Mesh Group Index."""
-from .indexer import DirectoryIndexer
-from .group_index import GroupIndex
from .cache import IndexCache
+from .group_index import GroupIndex
+from .indexer import DirectoryIndexer
__all__ = ["DirectoryIndexer", "GroupIndex", "IndexCache"]
diff --git a/packages/meshbay-node/src/meshbay_node/indexer/enrich.py b/packages/meshbay-node/src/meshbay_node/indexer/enrich.py
index b44a246..9881298 100644
--- a/packages/meshbay-node/src/meshbay_node/indexer/enrich.py
+++ b/packages/meshbay-node/src/meshbay_node/indexer/enrich.py
@@ -13,12 +13,12 @@ the rest asynchronously and hands the result back via a callback.
import asyncio
import logging
+from collections.abc import Awaitable, Callable
from pathlib import Path
-from typing import Awaitable, Callable
import blake3
-
from meshbay_common.protocol import IndexEntry
+
from meshbay_node.indexer import title_parse
from meshbay_node.indexer.indexer import MEDIA_EXTENSIONS
from meshbay_node.media_cache import MediaCache
@@ -173,7 +173,7 @@ async def _make_thumbnail(file_path: Path, duration: float | None) -> bytes | No
)
try:
stdout, _ = await asyncio.wait_for(proc.communicate(), THUMB_TIMEOUT_SECS)
- except asyncio.TimeoutError:
+ except TimeoutError:
proc.kill()
await proc.wait()
return None
diff --git a/packages/meshbay-node/src/meshbay_node/indexer/enrich_photo.py b/packages/meshbay-node/src/meshbay_node/indexer/enrich_photo.py
index 6613f85..5cacef9 100644
--- a/packages/meshbay-node/src/meshbay_node/indexer/enrich_photo.py
+++ b/packages/meshbay-node/src/meshbay_node/indexer/enrich_photo.py
@@ -22,13 +22,13 @@ import asyncio
import datetime
import io
import logging
+from collections.abc import Awaitable, Callable
from pathlib import Path
-from typing import Awaitable, Callable
import blake3
+from meshbay_common.protocol import IndexEntry
from PIL import ExifTags, Image, ImageOps
-from meshbay_common.protocol import IndexEntry
from meshbay_node.media_cache import MediaCache
log = logging.getLogger(__name__)
diff --git a/packages/meshbay-node/src/meshbay_node/indexer/group_index.py b/packages/meshbay-node/src/meshbay_node/indexer/group_index.py
index 2340c78..9e4e780 100644
--- a/packages/meshbay-node/src/meshbay_node/indexer/group_index.py
+++ b/packages/meshbay-node/src/meshbay_node/indexer/group_index.py
@@ -13,29 +13,27 @@ Delta format:
import base64
import logging
-import os
-import time
-from dataclasses import dataclass, field, asdict
-from pathlib import Path
-from typing import Iterator
+from dataclasses import asdict, dataclass, field
import blake3
import msgpack
import zstandard as zstd
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
-
from meshbay_common.crypto import (
+ pk_to_b64,
sign_chunk,
verify_chunk_signature,
- pk_to_b64,
- generate_gek,
)
+from meshbay_common.protocol import IndexDelta, IndexEntry
from meshbay_common.webcrypto import (
chunk_key_aes as derive_chunk_key,
- encrypt_chunk_aes as encrypt_chunk,
+)
+from meshbay_common.webcrypto import (
decrypt_chunk_aes as decrypt_chunk,
)
-from meshbay_common.protocol import IndexEntry, IndexDelta
+from meshbay_common.webcrypto import (
+ encrypt_chunk_aes as encrypt_chunk,
+)
log = logging.getLogger(__name__)
@@ -171,7 +169,6 @@ class GroupIndex:
) -> "GroupIndex":
"""Deserialize, verify signature, and decrypt (if private)."""
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
- from meshbay_common.crypto import verify_chunk_signature
envelope = msgpack.unpackb(data, raw=False)
diff --git a/packages/meshbay-node/src/meshbay_node/indexer/indexer.py b/packages/meshbay-node/src/meshbay_node/indexer/indexer.py
index 3fe4f3e..4b619d7 100644
--- a/packages/meshbay-node/src/meshbay_node/indexer/indexer.py
+++ b/packages/meshbay-node/src/meshbay_node/indexer/indexer.py
@@ -25,19 +25,20 @@ it is the only thing that recovers a missed event.
import asyncio
import logging
import time
+from collections.abc import Awaitable, Callable
from concurrent.futures import ThreadPoolExecutor
-from dataclasses import dataclass, field as dataclass_field
+from dataclasses import dataclass
+from dataclasses import field as dataclass_field
from pathlib import Path
-from typing import Callable, Awaitable
import blake3
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
+from meshbay_common.background import spawn
+from meshbay_common.paths import find_fold_collisions, fold, long_path
+from meshbay_common.protocol import IndexEntry
from watchdog.events import FileSystemEvent, FileSystemEventHandler
from watchdog.observers import Observer
-from meshbay_common.background import spawn
-from meshbay_common.paths import fold, find_fold_collisions, long_path
-from meshbay_common.protocol import IndexEntry
from meshbay_node.indexer.cache import IndexCache
from meshbay_node.indexer.group_index import GroupIndex
from meshbay_node.roots import Root, RootSet, off_disk
diff --git a/packages/meshbay-node/src/meshbay_node/indexer/title_parse.py b/packages/meshbay-node/src/meshbay_node/indexer/title_parse.py
index 14728ff..5df70c4 100644
--- a/packages/meshbay-node/src/meshbay_node/indexer/title_parse.py
+++ b/packages/meshbay-node/src/meshbay_node/indexer/title_parse.py
@@ -19,7 +19,7 @@ directory listing; this module only parses strings it's handed.
from __future__ import annotations
import re
-from dataclasses import dataclass, field
+from dataclasses import dataclass
from guessit import guessit
diff --git a/packages/meshbay-node/src/meshbay_node/keystore.py b/packages/meshbay-node/src/meshbay_node/keystore.py
index 00e504e..78fe122 100644
--- a/packages/meshbay-node/src/meshbay_node/keystore.py
+++ b/packages/meshbay-node/src/meshbay_node/keystore.py
@@ -38,8 +38,6 @@ from pathlib import Path
import msgpack
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey
-
-from meshbay_node.platform import chmod_private, config_dir
from meshbay_common.crypto import (
ARGON2_ITERATIONS,
ARGON2_LANES,
@@ -50,12 +48,12 @@ from meshbay_common.crypto import (
decrypt_keystore,
derive_keystore_key,
encrypt_keystore,
- generate_gek,
pk_to_b64,
sk_to_b64,
- sk_to_raw,
)
+from meshbay_node.platform import chmod_private, config_dir
+
log = logging.getLogger(__name__)
KEYSTORE_VERSION = 1
diff --git a/packages/meshbay-node/src/meshbay_node/ops.py b/packages/meshbay-node/src/meshbay_node/ops.py
index ca1b87d..baea365 100644
--- a/packages/meshbay-node/src/meshbay_node/ops.py
+++ b/packages/meshbay-node/src/meshbay_node/ops.py
@@ -24,8 +24,8 @@ from __future__ import annotations
import asyncio
import logging
-import time as _time
import re
+import time as _time
from dataclasses import asdict
from pathlib import Path
from typing import Any
@@ -37,8 +37,9 @@ from meshbay_common.crypto import (
unwrap_gek_aes,
wrap_gek_aes,
)
-from meshbay_node.config import DEFAULT_CONFIG_PATH
from meshbay_common.join import ROLE_MEMBER, ROLE_OPERATOR
+
+from meshbay_node.config import DEFAULT_CONFIG_PATH
from meshbay_node.roots import RootError, RootSet, off_disk
from meshbay_node.roster import Roster
@@ -951,6 +952,7 @@ async def remove_root(state: dict, group_id: str, root_name: str) -> dict:
raise OpError("Group not configured on this node", status=404)
from meshbay_common.paths import fold
+
from meshbay_node.roots import derive_name
target = fold(root_name)
match_idx = None
@@ -1001,6 +1003,7 @@ async def update_root(state: dict, group_id: str, root_name: str, *,
raise OpError("Group not configured on this node", status=404)
from meshbay_common.paths import fold
+
from meshbay_node.roots import RootSet
target = fold(root_name)
match = None
@@ -1462,8 +1465,7 @@ async def list_transfers(state: dict) -> dict:
ctx = getattr(webrtc, "_ctx", {}) if webrtc else {}
slots = ctx.get("_transfer_slots")
if slots is None:
- from meshbay_node.transfers import (
- DEFAULT_MAX_CONCURRENT, DEFAULT_MAX_PER_MEMBER, KINDS)
+ from meshbay_node.transfers import DEFAULT_MAX_CONCURRENT, DEFAULT_MAX_PER_MEMBER, KINDS
# No pool built means nothing has transferred since the daemon started,
# which is a real answer and not an error.
#
diff --git a/packages/meshbay-node/src/meshbay_node/replication.py b/packages/meshbay-node/src/meshbay_node/replication.py
index c2f5cd3..297ed0b 100644
--- a/packages/meshbay-node/src/meshbay_node/replication.py
+++ b/packages/meshbay-node/src/meshbay_node/replication.py
@@ -16,8 +16,6 @@ Usage:
await replicator.replicate_file(file_id, file_name, file_size)
"""
-import asyncio
-import hashlib
import logging
from pathlib import Path
diff --git a/packages/meshbay-node/src/meshbay_node/revocation.py b/packages/meshbay-node/src/meshbay_node/revocation.py
index d3ee18f..1e8caee 100644
--- a/packages/meshbay-node/src/meshbay_node/revocation.py
+++ b/packages/meshbay-node/src/meshbay_node/revocation.py
@@ -17,7 +17,6 @@ Usage in daemon:
import asyncio
import json
import logging
-import time
from typing import Literal
import httpx
@@ -151,5 +150,5 @@ class RevocationSubscriber:
else:
log.debug("WS message: %s", msg.get("type"))
- except asyncio.TimeoutError:
+ except TimeoutError:
continue
diff --git a/packages/meshbay-node/src/meshbay_node/roots.py b/packages/meshbay-node/src/meshbay_node/roots.py
index 67778ca..89b0441 100644
--- a/packages/meshbay-node/src/meshbay_node/roots.py
+++ b/packages/meshbay-node/src/meshbay_node/roots.py
@@ -71,7 +71,7 @@ def _free_name(directory: Path, filename: str) -> str:
raise FileExistsError(filename)
-def safe_subdir(roots: "RootSet", rel: str) -> Path | None:
+def safe_subdir(roots: RootSet, rel: str) -> Path | None:
"""
Resolve a client-supplied directory inside one of the group's roots, or refuse.
@@ -219,7 +219,7 @@ class RootSet:
# ── Construction ─────────────────────────────────────────────────────────
@classmethod
- def build(cls, specs: list[dict]) -> "RootSet":
+ def build(cls, specs: list[dict]) -> RootSet:
"""
Build from configuration, refusing anything ambiguous.
diff --git a/packages/meshbay-node/src/meshbay_node/roster.py b/packages/meshbay-node/src/meshbay_node/roster.py
index 8c9b3ef..9478a32 100644
--- a/packages/meshbay-node/src/meshbay_node/roster.py
+++ b/packages/meshbay-node/src/meshbay_node/roster.py
@@ -24,13 +24,11 @@ from __future__ import annotations
import hashlib
import json
import logging
-import os
import secrets
-from datetime import datetime, timedelta, timezone
+from datetime import UTC, datetime, timedelta
from pathlib import Path
import aiosqlite
-
from meshbay_common.paths import fold
log = logging.getLogger(__name__)
@@ -194,11 +192,11 @@ def hash_code(code: str) -> str:
def _now() -> str:
- return datetime.now(timezone.utc).isoformat(timespec="seconds")
+ return datetime.now(UTC).isoformat(timespec="seconds")
def _iso_in(seconds: int) -> str:
- return (datetime.now(timezone.utc)
+ return (datetime.now(UTC)
+ timedelta(seconds=seconds)).isoformat(timespec="seconds")
@@ -1073,7 +1071,7 @@ class Roster:
(group_id, user_id),
)
code = generate_code()
- expires = datetime.now(timezone.utc) + timedelta(seconds=ttl)
+ expires = datetime.now(UTC) + timedelta(seconds=ttl)
await self._db.execute(
"INSERT INTO invites (code_hash, group_id, user_id, username, role, "
"created_by, created_at, expires_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
@@ -1106,7 +1104,7 @@ class Roster:
# redeemed by whoever finds it first.
if invite["user_id"] != user_id:
return None
- if datetime.fromisoformat(invite["expires_at"]) < datetime.now(timezone.utc):
+ if datetime.fromisoformat(invite["expires_at"]) < datetime.now(UTC):
return None
cur = await self._db.execute(
diff --git a/packages/meshbay-node/src/meshbay_node/transport/__init__.py b/packages/meshbay-node/src/meshbay_node/transport/__init__.py
index e423e35..86dbf23 100644
--- a/packages/meshbay-node/src/meshbay_node/transport/__init__.py
+++ b/packages/meshbay-node/src/meshbay_node/transport/__init__.py
@@ -15,8 +15,8 @@ Transport decision (2026-08-13, second security review):
# QUIC transport (MNP v2) — requires aioquic>=1.0
try:
- from .quic_server import QuicChunkServer, Denylist
from .quic_client import QuicChunkClient
+ from .quic_server import Denylist, QuicChunkServer
QUIC_AVAILABLE = True
except ImportError:
QuicChunkServer = None # type: ignore[assignment,misc]
@@ -26,7 +26,7 @@ except ImportError:
# WebRTC transport (browsers + native clients) — requires aiortc>=1.9
try:
- from .webrtc_server import WebRTCTransport, WebRTCPeerSession
+ from .webrtc_server import WebRTCPeerSession, WebRTCTransport
WEBRTC_AVAILABLE = True
except ImportError:
WebRTCTransport = None # type: ignore[assignment,misc]
diff --git a/packages/meshbay-node/src/meshbay_node/transport/quic_client.py b/packages/meshbay-node/src/meshbay_node/transport/quic_client.py
index af87b70..273f225 100644
--- a/packages/meshbay-node/src/meshbay_node/transport/quic_client.py
+++ b/packages/meshbay-node/src/meshbay_node/transport/quic_client.py
@@ -13,18 +13,14 @@ import base64
import logging
import os
import struct
-from pathlib import Path
-import jwt
import msgpack
-from aioquic.asyncio import connect, QuicConnectionProtocol
+from aioquic.asyncio import QuicConnectionProtocol, connect
from aioquic.quic.configuration import QuicConfiguration
from aioquic.quic.events import QuicEvent, StreamDataReceived
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
-
from meshbay_common import MNP_VERSION
from meshbay_common.groupbox import PURPOSE_ACK, PURPOSE_INDEX, unseal
-from meshbay_common.protocol import MNP, file_chunk_plaintext
from meshbay_common.handshake import (
MNP_MIN_SUPPORTED,
NONCE_LEN,
@@ -36,6 +32,7 @@ from meshbay_common.handshake import (
quic_binding,
verify_proof,
)
+from meshbay_common.protocol import MNP, file_chunk_plaintext
def _peer_cert_der(proto) -> bytes | None:
diff --git a/packages/meshbay-node/src/meshbay_node/transport/quic_server.py b/packages/meshbay-node/src/meshbay_node/transport/quic_server.py
index 2a2b07a..036574b 100644
--- a/packages/meshbay-node/src/meshbay_node/transport/quic_server.py
+++ b/packages/meshbay-node/src/meshbay_node/transport/quic_server.py
@@ -24,17 +24,16 @@ import os
import struct
import uuid
from pathlib import Path
-from typing import Any, Callable
+from typing import Any
-import jwt
import msgpack
from aioquic.asyncio import QuicConnectionProtocol, serve
from aioquic.quic.configuration import QuicConfiguration
from aioquic.quic.events import QuicEvent, StreamDataReceived, StreamReset
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
-
from meshbay_common import MNP_VERSION
-from meshbay_node.roots import ROOT_NOT_SERVED, RootSet, entry_abs_path
+from meshbay_common.crypto import pk_to_b64
+from meshbay_common.groupbox import PURPOSE_ACK, seal
from meshbay_common.handshake import (
MNP_MIN_SUPPORTED,
NONCE_LEN,
@@ -48,10 +47,10 @@ from meshbay_common.handshake import (
quic_binding,
verify_proof,
)
-from meshbay_common.crypto import pk_to_b64
-from meshbay_common.groupbox import PURPOSE_ACK, seal
from meshbay_common.protocol import MNP, file_chunk_wire
+
from meshbay_node.indexer import GroupIndex
+from meshbay_node.roots import ROOT_NOT_SERVED, RootSet, entry_abs_path
from meshbay_node.transport.wire import index_sync_message
log = logging.getLogger(__name__)
diff --git a/packages/meshbay-node/src/meshbay_node/transport/tls_cert.py b/packages/meshbay-node/src/meshbay_node/transport/tls_cert.py
index 8d680ea..cfc93c7 100644
--- a/packages/meshbay-node/src/meshbay_node/transport/tls_cert.py
+++ b/packages/meshbay-node/src/meshbay_node/transport/tls_cert.py
@@ -10,11 +10,10 @@ the QUIC handshake proof (11.5.6), since QUIC has no DTLS fingerprint to bind to
Certificate is generated once and cached at ~/.config/meshbay/node_tls.crt/.key.
"""
-import logging
-import os
-from pathlib import Path
import datetime
import ipaddress
+import logging
+from pathlib import Path
from cryptography import x509
from cryptography.hazmat.primitives import hashes, serialization
@@ -47,8 +46,8 @@ def generate_self_signed_cert(
.issuer_name(issuer)
.public_key(rsa_key.public_key())
.serial_number(x509.random_serial_number())
- .not_valid_before(datetime.datetime.now(datetime.timezone.utc))
- .not_valid_after(datetime.datetime.now(datetime.timezone.utc)
+ .not_valid_before(datetime.datetime.now(datetime.UTC))
+ .not_valid_after(datetime.datetime.now(datetime.UTC)
+ datetime.timedelta(days=3650))
.add_extension(
x509.SubjectAlternativeName([
diff --git a/packages/meshbay-node/src/meshbay_node/transport/webrtc_server.py b/packages/meshbay-node/src/meshbay_node/transport/webrtc_server.py
index 8a5bbff..2bd1419 100644
--- a/packages/meshbay-node/src/meshbay_node/transport/webrtc_server.py
+++ b/packages/meshbay-node/src/meshbay_node/transport/webrtc_server.py
@@ -25,8 +25,6 @@ Signaling flow (handled externally by the hub):
import asyncio
import base64
import contextvars
-import hashlib
-import hmac
import logging
import os
import re
@@ -38,63 +36,53 @@ from pathlib import Path
from typing import Any
import blake3
-import jwt
import msgpack
-from aiortc import RTCPeerConnection, RTCSessionDescription, RTCDataChannel
+from aiortc import RTCDataChannel, RTCPeerConnection, RTCSessionDescription
from cryptography.hazmat.primitives.asymmetric.ed25519 import (
Ed25519PrivateKey,
Ed25519PublicKey,
)
-
from meshbay_common import MNP_VERSION
-from meshbay_common.handshake import (
- MNP_MIN_SUPPORTED,
- NONCE_LEN,
- ROLE_CLIENT,
- ROLE_NODE,
- HandshakeError,
- authorize_token,
- check_version,
- handshake_transcript,
- make_proof,
- verify_proof,
- webrtc_binding,
-)
from meshbay_common.adminop import (
ADMIN_CHALLENGE_TTL,
+ OP_APP_DIRECTORIES,
+ OP_APPS_ENABLED,
+ OP_CHAT_DIRECTORY,
+ OP_CHAT_EPOCH,
+ OP_CHAT_LINK_PREVIEW,
OP_DIR_DELETE,
OP_FILE_DELETE,
+ OP_GEK_ROTATE,
+ OP_GROUP_ATTACH,
+ OP_GROUP_DETACH,
OP_INVITE_CREATE,
OP_MEMBER_REVOKE,
- OP_GEK_ROTATE,
OP_MEMBER_UNPIN,
- OP_APPS_ENABLED,
+ OP_MUSICBRAINZ_ENABLED,
+ OP_ROOT_ADD,
+ OP_ROOT_EJECT,
+ OP_ROOT_PLUG,
+ OP_ROOT_REMOVE,
+ OP_ROOT_UPDATE,
+ OP_SEARCH_LISTED,
OP_SET_SCAN_SETTINGS,
- OP_TRANSFER_LIMITS,
OP_TMDB_CONFIG,
OP_TMDB_ENABLED,
OP_TMDB_OVERRIDE,
OP_TMDB_REMATCH,
- OP_MUSICBRAINZ_ENABLED,
- OP_APP_DIRECTORIES,
- OP_CHAT_DIRECTORY,
- OP_CHAT_EPOCH,
- OP_CHAT_LINK_PREVIEW,
- OP_SEARCH_LISTED,
- OP_ROOT_ADD,
- OP_ROOT_REMOVE,
- OP_ROOT_UPDATE,
- OP_ROOT_EJECT,
- OP_ROOT_PLUG,
- OP_GROUP_ATTACH,
- OP_GROUP_DETACH,
+ OP_TRANSFER_LIMITS,
admin_transcript,
)
+from meshbay_common.chatbox import (
+ NONCE_LEN as CHAT_NONCE_LEN,
+)
+from meshbay_common.chatbox import (
+ SIG_LEN as CHAT_SIG_LEN,
+)
from meshbay_common.crypto import pk_to_b64, wrap_gek_aes
from meshbay_common.device import (
DEVICE_TTL,
device_add_transcript,
- device_code_hash,
device_hello_transcript,
device_request_transcript,
)
@@ -104,44 +92,62 @@ from meshbay_common.groupbox import (
PURPOSE_ROSTER,
seal,
)
+from meshbay_common.handshake import (
+ MNP_MIN_SUPPORTED,
+ NONCE_LEN,
+ ROLE_CLIENT,
+ ROLE_NODE,
+ HandshakeError,
+ authorize_token,
+ check_version,
+ handshake_transcript,
+ make_proof,
+ verify_proof,
+ webrtc_binding,
+)
from meshbay_common.join import (
JOIN_TTL,
ROLE_MEMBER,
ROLE_OPERATOR,
join_transcript,
)
-from meshbay_common.chatbox import (
- NONCE_LEN as CHAT_NONCE_LEN,
- SIG_LEN as CHAT_SIG_LEN,
-)
from meshbay_common.protocol import (
MNP,
+ UPLOAD_PROBE_INDEX,
chunk_ciphertext,
file_chunk_wire,
- UPLOAD_PROBE_INDEX,
file_upload_ack_wire,
file_upload_payload,
)
-from meshbay_node.chat import FORMAT_SEALED_V1, ReplayedMessage
-from meshbay_node.transport.wire import index_sync_message
-from meshbay_node.indexer import GroupIndex
-from meshbay_node.indexer.indexer import DirectoryIndexer
+
from meshbay_node import hwaccel, linkpreview, ops, platform
from meshbay_node import transfers as transfers_mod
from meshbay_node import uploads as uploads_mod
-from meshbay_node.transfers import TransferSlots
+from meshbay_node.chat import FORMAT_SEALED_V1, ReplayedMessage
+from meshbay_node.indexer import GroupIndex
+from meshbay_node.indexer.indexer import DirectoryIndexer
+
# Re-imported under its original name: every call site and existing test in
# this module still refers to it as `_probe_video`. The implementation lives
# in media_probe.py so the indexer package (imported just above) can call it
# too, for index-time enrichment, without a circular import.
from meshbay_node.media_probe import (
BROWSER_INCOMPATIBLE_VIDEO_CODECS,
+)
+from meshbay_node.media_probe import (
probe_video as _probe_video,
)
from meshbay_node.roots import (
- ROOT_NOT_SERVED, RootSet, entry_abs_path, off_disk, SAFE_UPLOAD_NAME, safe_subdir,
+ ROOT_NOT_SERVED,
+ SAFE_UPLOAD_NAME,
+ RootSet,
_free_name,
+ entry_abs_path,
+ off_disk,
+ safe_subdir,
)
+from meshbay_node.transfers import TransferSlots
+from meshbay_node.transport.wire import index_sync_message
log = logging.getLogger(__name__)
@@ -6160,7 +6166,7 @@ class WebRTCPeerSession:
# total budget is unchanged.
await asyncio.wait_for(self._stream_credit_evt.wait(),
timeout=STREAM_CREDIT_POLL)
- except asyncio.TimeoutError:
+ except TimeoutError:
silent = time.monotonic() - self._stream_heard_at
if silent >= STREAM_CREDIT_TIMEOUT:
log.info("Stream stalled: nothing from peer=%s for %.0fs",
@@ -6208,7 +6214,7 @@ class WebRTCPeerSession:
await asyncio.wait_for(asyncio.shield(prev), timeout=15)
log.info("stream: previous stream ended in %.1fs",
time.monotonic() - t0)
- except asyncio.TimeoutError:
+ except TimeoutError:
log.warning("stream: previous stream STILL RUNNING after 15s")
except Exception:
pass # it failed on its own; the slot is free either way
@@ -6851,7 +6857,7 @@ async def _transcode_audio_to_aac(file_path: Path) -> bytes:
try:
_, stderr = await asyncio.wait_for(
proc.communicate(), timeout=AUDIO_TRANSCODE_TIMEOUT_SECS)
- except asyncio.TimeoutError:
+ except TimeoutError:
proc.kill()
await proc.wait()
raise RuntimeError(f"ffmpeg timed out after {AUDIO_TRANSCODE_TIMEOUT_SECS}s")
@@ -6912,7 +6918,7 @@ async def _seek_lands_at(file_path: Path, t: float, map_args: list[str]) -> floa
)
stdout, _ = await asyncio.wait_for(
probe.communicate(), timeout=SEEK_PROBE_TIMEOUT_SECS)
- except (asyncio.TimeoutError, OSError) as e:
+ except (TimeoutError, OSError) as e:
log.warning("stream: seek probe failed at %.1fs: %r", t, e)
return None
finally:
@@ -6967,7 +6973,7 @@ async def _extract_subtitle_to_webvtt(file_path: Path, ordinal: int,
try:
_, stderr = await asyncio.wait_for(
proc.communicate(), timeout=timeout)
- except asyncio.TimeoutError:
+ except TimeoutError:
proc.kill()
await proc.wait()
raise RuntimeError(f"ffmpeg timed out after {timeout:.0f}s")
@@ -7152,7 +7158,7 @@ class WebRTCTransport:
Returns (answer_sdp, ice_candidates) to relay back via hub signaling.
ICE candidates are embedded in the SDP (aiortc gathers before returning).
"""
- from aiortc import RTCIceServer, RTCConfiguration
+ from aiortc import RTCConfiguration, RTCIceServer
# aiortc keeps only the first STUN entry it sees here; the actual
# multi-server fan-out is done by transport/stun_multi, which patches
diff --git a/packages/meshbay-node/src/meshbay_node/ui/app.py b/packages/meshbay-node/src/meshbay_node/ui/app.py
index 77491a0..888487c 100644
--- a/packages/meshbay-node/src/meshbay_node/ui/app.py
+++ b/packages/meshbay-node/src/meshbay_node/ui/app.py
@@ -16,8 +16,8 @@ import logging
from fastapi import FastAPI, HTTPException, Query
from fastapi.responses import JSONResponse
-
from meshbay_common.background import spawn
+
from meshbay_node import __version__, ops
from meshbay_node.indexer.indexer import DirectoryIndexer
diff --git a/packages/meshbay-node/src/meshbay_node/uploads.py b/packages/meshbay-node/src/meshbay_node/uploads.py
index f8ae7f9..dd31e1e 100644
--- a/packages/meshbay-node/src/meshbay_node/uploads.py
+++ b/packages/meshbay-node/src/meshbay_node/uploads.py
@@ -25,9 +25,9 @@ build first.
from __future__ import annotations
import time
+from collections.abc import Iterable
from dataclasses import dataclass, field
from pathlib import Path
-from typing import Iterable
# What an unfinished upload is called on disk while it is being written. The
# node has always used this; it is named here because the reaper below has to
diff --git a/packages/meshbay-node/tests/test_admin_ops_mnp.py b/packages/meshbay-node/tests/test_admin_ops_mnp.py
index 92e50b5..7fd1c2b 100644
--- a/packages/meshbay-node/tests/test_admin_ops_mnp.py
+++ b/packages/meshbay-node/tests/test_admin_ops_mnp.py
@@ -15,13 +15,10 @@ thing that finishes a revocation: the ex-member still holds the current key.
"""
import base64
-import time
from pathlib import Path
import pytest
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
-
-from conftest import one_root
from meshbay_common.adminop import (
OP_GEK_ROTATE,
OP_MEMBER_UNPIN,
@@ -34,6 +31,8 @@ from meshbay_node.indexer.group_index import GroupIndex
from meshbay_node.roster import open_roster
from meshbay_node.transport.webrtc_server import WebRTCPeerSession
+from conftest import one_root
+
GROUP = "g" * 32
diff --git a/packages/meshbay-node/tests/test_app_directories.py b/packages/meshbay-node/tests/test_app_directories.py
index 726f5bd..955a769 100644
--- a/packages/meshbay-node/tests/test_app_directories.py
+++ b/packages/meshbay-node/tests/test_app_directories.py
@@ -26,7 +26,6 @@ from types import SimpleNamespace
import pytest
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
-
from meshbay_common.adminop import OP_APP_DIRECTORIES
from meshbay_node import ops
from meshbay_node.indexer.group_index import GroupIndex
diff --git a/packages/meshbay-node/tests/test_app_directories_signed.py b/packages/meshbay-node/tests/test_app_directories_signed.py
index eda09d8..af362a1 100644
--- a/packages/meshbay-node/tests/test_app_directories_signed.py
+++ b/packages/meshbay-node/tests/test_app_directories_signed.py
@@ -24,7 +24,6 @@ from pathlib import Path
import pytest
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
-
from meshbay_common.adminop import OP_APP_DIRECTORIES, admin_transcript
from meshbay_common.crypto import pk_to_b64
from meshbay_common.join import ROLE_OPERATOR
diff --git a/packages/meshbay-node/tests/test_apps_enabled_policy.py b/packages/meshbay-node/tests/test_apps_enabled_policy.py
index 40c7cc8..1fa3d5c 100644
--- a/packages/meshbay-node/tests/test_apps_enabled_policy.py
+++ b/packages/meshbay-node/tests/test_apps_enabled_policy.py
@@ -13,12 +13,11 @@ way an unsigned upload is refused, so the check has to happen up front.
from pathlib import Path
import pytest
-
+from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from meshbay_common.adminop import OP_APPS_ENABLED
from meshbay_node.indexer.group_index import GroupIndex
from meshbay_node.roster import Roster
from meshbay_node.transport.webrtc_server import WebRTCPeerSession
-from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from conftest import one_root
diff --git a/packages/meshbay-node/tests/test_audio_root_gates_enrichment.py b/packages/meshbay-node/tests/test_audio_root_gates_enrichment.py
index 251617c..b8c4dd6 100644
--- a/packages/meshbay-node/tests/test_audio_root_gates_enrichment.py
+++ b/packages/meshbay-node/tests/test_audio_root_gates_enrichment.py
@@ -17,10 +17,9 @@ import os
import pytest
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
-
from meshbay_common.crypto import generate_gek
from meshbay_node import ops
-from meshbay_node.config import Config, HubConfig, NodeConfig, GroupConfig, KeystoreConfig
+from meshbay_node.config import Config, GroupConfig, HubConfig, KeystoreConfig, NodeConfig
from meshbay_node.daemon import NodeDaemon
from meshbay_node.indexer import DirectoryIndexer
from meshbay_node.indexer.enrich_audio import AudioEnricher
diff --git a/packages/meshbay-node/tests/test_chat_is_bounded.py b/packages/meshbay-node/tests/test_chat_is_bounded.py
index 4e767bc..5dc1128 100644
--- a/packages/meshbay-node/tests/test_chat_is_bounded.py
+++ b/packages/meshbay-node/tests/test_chat_is_bounded.py
@@ -33,7 +33,6 @@ import os
import pytest
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
-
from meshbay_common.chatbox import NONCE_LEN, SIG_LEN
from meshbay_common.crypto import pk_to_b64
from meshbay_node.chat import FORMAT_SEALED_V1, ChatStore
diff --git a/packages/meshbay-node/tests/test_chat_multidevice.py b/packages/meshbay-node/tests/test_chat_multidevice.py
index bb61285..058544a 100644
--- a/packages/meshbay-node/tests/test_chat_multidevice.py
+++ b/packages/meshbay-node/tests/test_chat_multidevice.py
@@ -16,10 +16,9 @@ account where it should be keyed by connection" mistake as `pin_identity`'s
old INSERT OR REPLACE.
"""
-from pathlib import Path
-
import base64
import hashlib
+from pathlib import Path
from aiortc import RTCPeerConnection
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
diff --git a/packages/meshbay-node/tests/test_chat_pagination.py b/packages/meshbay-node/tests/test_chat_pagination.py
index caf1f73..f3949a9 100644
--- a/packages/meshbay-node/tests/test_chat_pagination.py
+++ b/packages/meshbay-node/tests/test_chat_pagination.py
@@ -13,12 +13,10 @@ The cursor is the row id rather than the timestamp. `timestamp` is a float from
timestamp cursor would then skip a message or return it twice.
"""
-import asyncio
from pathlib import Path
import pytest
import pytest_asyncio
-
from meshbay_node.chat.store import ChatStore
diff --git a/packages/meshbay-node/tests/test_chat_store.py b/packages/meshbay-node/tests/test_chat_store.py
index d74310d..2533921 100644
--- a/packages/meshbay-node/tests/test_chat_store.py
+++ b/packages/meshbay-node/tests/test_chat_store.py
@@ -2,10 +2,9 @@
Tests for the SQLite-backed chat message store.
"""
+
import pytest
import pytest_asyncio
-from pathlib import Path
-
from meshbay_node.chat.store import ChatStore
diff --git a/packages/meshbay-node/tests/test_cli_dispatch.py b/packages/meshbay-node/tests/test_cli_dispatch.py
index ad60b91..cf2fd6e 100644
--- a/packages/meshbay-node/tests/test_cli_dispatch.py
+++ b/packages/meshbay-node/tests/test_cli_dispatch.py
@@ -14,10 +14,8 @@ branch nobody ever ran.
"""
import sys
-from pathlib import Path
import pytest
-
from meshbay_node import daemon as daemon_mod
# Each verb, with the arguments that reach its branch. `--yes` where the command
@@ -155,7 +153,6 @@ def test_the_verb_list_here_matches_the_parser():
A verb added to the parser and not to this file would go untested, which is
exactly how `reload` shipped broken.
"""
- import argparse
import inspect
source = inspect.getsource(daemon_mod.main)
diff --git a/packages/meshbay-node/tests/test_daemon.py b/packages/meshbay-node/tests/test_daemon.py
index 8bd169d..8c4da2d 100644
--- a/packages/meshbay-node/tests/test_daemon.py
+++ b/packages/meshbay-node/tests/test_daemon.py
@@ -9,20 +9,21 @@ Hub interaction is mocked.
import asyncio
import base64
import os
+from unittest.mock import AsyncMock, MagicMock, patch
import pytest
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey
-from unittest.mock import AsyncMock, MagicMock, patch
-
from meshbay_common.crypto import generate_gek
from meshbay_common.groupbox import PURPOSE_INDEX, unseal
-from meshbay_node.config import Config, HubConfig, NodeConfig, GroupConfig, KeystoreConfig
-from conftest import one_root
+from meshbay_node.config import Config, GroupConfig, HubConfig, KeystoreConfig, NodeConfig
from meshbay_node.daemon import NodeDaemon
from meshbay_node.indexer import DirectoryIndexer
+from conftest import one_root
+
+
def _mock_keystore_keys(sk_ed):
"""Create a mock keystore with real Ed25519 + X25519 key material."""
sk_x = X25519PrivateKey.generate()
@@ -125,7 +126,7 @@ async def test_daemon_creates_chat_store(tmp_path, node_config, gek, hub_pk_pem)
patch("signal.SIGTERM", 15):
try:
await asyncio.wait_for(daemon.run(), timeout=5)
- except (asyncio.TimeoutError, Exception):
+ except (TimeoutError, Exception):
pass
task = asyncio.create_task(run_daemon())
@@ -204,7 +205,7 @@ async def test_daemon_no_groups_stays_up(tmp_path, hub_pk_pem):
patch("signal.SIGTERM", 15):
try:
await asyncio.wait_for(daemon.run(), timeout=5)
- except (asyncio.TimeoutError, Exception):
+ except (TimeoutError, Exception):
pass
task = asyncio.create_task(run_daemon())
diff --git a/packages/meshbay-node/tests/test_device_linking.py b/packages/meshbay-node/tests/test_device_linking.py
index 6d50580..53387ca 100644
--- a/packages/meshbay-node/tests/test_device_linking.py
+++ b/packages/meshbay-node/tests/test_device_linking.py
@@ -25,8 +25,6 @@ from pathlib import Path
import pytest
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
-
-from conftest import one_root
from meshbay_common.crypto import pk_to_b64
from meshbay_common.device import (
device_add_transcript,
@@ -39,6 +37,8 @@ from meshbay_node.indexer.group_index import GroupIndex
from meshbay_node.roster import generate_code, normalize_code, open_roster
from meshbay_node.transport.webrtc_server import WebRTCPeerSession
+from conftest import one_root
+
GROUP = "g" * 32
NONCE = b"\x11" * 32
diff --git a/packages/meshbay-node/tests/test_enrich.py b/packages/meshbay-node/tests/test_enrich.py
index e059bbe..ca03392 100644
--- a/packages/meshbay-node/tests/test_enrich.py
+++ b/packages/meshbay-node/tests/test_enrich.py
@@ -3,15 +3,15 @@
import asyncio
import shutil
import subprocess
-from pathlib import Path
-
import sys
+from pathlib import Path
import pytest
-
from meshbay_common.protocol import IndexEntry
from meshbay_node.indexer.enrich import (
- Enricher, _season_and_show_from_ancestors, _synthetic_episode_number,
+ Enricher,
+ _season_and_show_from_ancestors,
+ _synthetic_episode_number,
_title_from_siblings,
)
from meshbay_node.media_cache import MediaCache
diff --git a/packages/meshbay-node/tests/test_enrich_photo.py b/packages/meshbay-node/tests/test_enrich_photo.py
index 81367eb..fb0530c 100644
--- a/packages/meshbay-node/tests/test_enrich_photo.py
+++ b/packages/meshbay-node/tests/test_enrich_photo.py
@@ -6,11 +6,10 @@ from pathlib import Path
import piexif
import pytest
-from PIL import Image
-
from meshbay_common.protocol import IndexEntry
from meshbay_node.indexer.enrich_photo import PhotoEnricher
from meshbay_node.media_cache import MediaCache
+from PIL import Image
@pytest.fixture
diff --git a/packages/meshbay-node/tests/test_group_roster.py b/packages/meshbay-node/tests/test_group_roster.py
index a41cce2..74908e7 100644
--- a/packages/meshbay-node/tests/test_group_roster.py
+++ b/packages/meshbay-node/tests/test_group_roster.py
@@ -23,8 +23,6 @@ import time
import pytest
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
-
-from conftest import one_root
from meshbay_common.crypto import generate_gek, pk_to_b64
from meshbay_common.device import device_add_transcript
from meshbay_common.groupbox import PURPOSE_ROSTER, unseal
@@ -34,6 +32,8 @@ from meshbay_node.indexer.group_index import GroupIndex
from meshbay_node.roster import open_roster
from meshbay_node.transport.webrtc_server import WebRTCPeerSession
+from conftest import one_root
+
GROUP = "g" * 32
NONCE = b"\x11" * 32
diff --git a/packages/meshbay-node/tests/test_hot_reload_survives_client_close.py b/packages/meshbay-node/tests/test_hot_reload_survives_client_close.py
index fc6af70..fb9eade 100644
--- a/packages/meshbay-node/tests/test_hot_reload_survives_client_close.py
+++ b/packages/meshbay-node/tests/test_hot_reload_survives_client_close.py
@@ -18,17 +18,15 @@ import asyncio
import base64
import os
from pathlib import Path
+from unittest.mock import AsyncMock, MagicMock, patch
+import meshbay_node.indexer.indexer as indexer_mod
import pytest
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey
-from unittest.mock import AsyncMock, MagicMock, patch
-
from meshbay_node import ops
-from meshbay_node.config import Config, HubConfig, NodeConfig, GroupConfig, KeystoreConfig
from meshbay_node.daemon import NodeDaemon
-import meshbay_node.indexer.indexer as indexer_mod
def _free_port() -> int:
@@ -149,7 +147,7 @@ async def test_hot_loaded_group_finishes_scanning_without_anyone_awaiting_the_re
with patch("signal.SIGINT", 2), patch("signal.SIGTERM", 15):
try:
await asyncio.wait_for(daemon.run(), timeout=15)
- except (asyncio.TimeoutError, Exception):
+ except (TimeoutError, Exception):
pass
run_task = asyncio.create_task(run_daemon())
@@ -270,7 +268,7 @@ async def test_group_scoped_ops_404_until_listed_then_succeed(tmp_path):
with patch("signal.SIGINT", 2), patch("signal.SIGTERM", 15):
try:
await asyncio.wait_for(daemon.run(), timeout=15)
- except (asyncio.TimeoutError, Exception):
+ except (TimeoutError, Exception):
pass
run_task = asyncio.create_task(run_daemon())
diff --git a/packages/meshbay-node/tests/test_hub_client.py b/packages/meshbay-node/tests/test_hub_client.py
index 2975ee8..e733610 100644
--- a/packages/meshbay-node/tests/test_hub_client.py
+++ b/packages/meshbay-node/tests/test_hub_client.py
@@ -2,24 +2,17 @@
Tests for meshbay_node.hub_client — uses httpx.MockTransport to avoid network.
"""
-import json
-import os
import time
-import pytest
-from pathlib import Path
-from unittest.mock import AsyncMock, MagicMock, patch
import httpx
import jwt
+import pytest
+from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey
-from cryptography.hazmat.primitives import serialization
-
-
-from meshbay_node.hub_client import HubClient, HubConfig, HubSession
+from meshbay_node.hub_client import HubClient, HubConfig
from meshbay_node.keystore import NodeKeys
-
# ── Test fixtures ──────────────────────────────────────────────────────────────
@pytest.fixture
diff --git a/packages/meshbay-node/tests/test_hub_ws_group_claim.py b/packages/meshbay-node/tests/test_hub_ws_group_claim.py
index 49ac776..98b944b 100644
--- a/packages/meshbay-node/tests/test_hub_ws_group_claim.py
+++ b/packages/meshbay-node/tests/test_hub_ws_group_claim.py
@@ -15,7 +15,6 @@ import asyncio
import json
import pytest
-
from meshbay_node.hub_client import HubClient, HubConfig, HubSession
diff --git a/packages/meshbay-node/tests/test_ice_filter.py b/packages/meshbay-node/tests/test_ice_filter.py
index a995c2b..0fec2d2 100644
--- a/packages/meshbay-node/tests/test_ice_filter.py
+++ b/packages/meshbay-node/tests/test_ice_filter.py
@@ -3,8 +3,8 @@ transport/ice_filter — the interface filter must name the same adapter on
every platform, and must never leave the gather with no address at all.
"""
-import ifaddr
import aioice.ice
+import ifaddr
import pytest
from meshbay_node.transport import ice_filter
diff --git a/packages/meshbay-node/tests/test_index_cache.py b/packages/meshbay-node/tests/test_index_cache.py
index 036b4d7..8f0ff25 100644
--- a/packages/meshbay-node/tests/test_index_cache.py
+++ b/packages/meshbay-node/tests/test_index_cache.py
@@ -1,7 +1,6 @@
"""Tests for the (path, size, mtime) -> hash cache (indexer/cache.py)."""
import pytest
-
from meshbay_node.indexer.cache import IndexCache
diff --git a/packages/meshbay-node/tests/test_index_delta_carries_roots.py b/packages/meshbay-node/tests/test_index_delta_carries_roots.py
index 227f2d0..c939b4a 100644
--- a/packages/meshbay-node/tests/test_index_delta_carries_roots.py
+++ b/packages/meshbay-node/tests/test_index_delta_carries_roots.py
@@ -19,14 +19,12 @@ Additive on the wire (MNP 1.1): a 1.0 client sees a field it does not read.
from pathlib import Path
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
-
from meshbay_common.crypto import generate_gek
from meshbay_common.groupbox import PURPOSE_INDEX, unseal
from meshbay_node.indexer.group_index import GroupIndex
from meshbay_node.roots import RootSet
from meshbay_node.transport.wire import index_delta_message, index_sync_message
-
GROUP = "g" * 32
diff --git a/packages/meshbay-node/tests/test_index_no_cleartext.py b/packages/meshbay-node/tests/test_index_no_cleartext.py
index e5e4555..30d1226 100644
--- a/packages/meshbay-node/tests/test_index_no_cleartext.py
+++ b/packages/meshbay-node/tests/test_index_no_cleartext.py
@@ -14,7 +14,6 @@ framing or in a field name.
import msgpack
import pytest
-from conftest import one_root
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from meshbay_common.crypto import generate_gek
from meshbay_common.groupbox import PURPOSE_ACK, PURPOSE_INDEX, seal, unseal
@@ -22,6 +21,8 @@ from meshbay_common.protocol import MNP
from meshbay_node.indexer import DirectoryIndexer, GroupIndex
from meshbay_node.transport.wire import index_delta_message, index_sync_message
+from conftest import one_root
+
# A filename and a folder name that appear nowhere else in the tree.
SECRET_FILE = "quixotry-ledger-2019.pdf"
SECRET_DIR = "zarfwidget-archive"
diff --git a/packages/meshbay-node/tests/test_index_progress.py b/packages/meshbay-node/tests/test_index_progress.py
index df51e85..ecdc223 100644
--- a/packages/meshbay-node/tests/test_index_progress.py
+++ b/packages/meshbay-node/tests/test_index_progress.py
@@ -6,16 +6,15 @@ itself (see test_daemon.py for that) and never anything sent to the hub.
"""
import asyncio
+from unittest.mock import MagicMock
import pytest
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
-from unittest.mock import MagicMock
from fastapi.testclient import TestClient
-
-from meshbay_node.config import Config, HubConfig, NodeConfig, GroupConfig, KeystoreConfig
+from meshbay_node.config import Config, HubConfig, KeystoreConfig, NodeConfig
from meshbay_node.daemon import NodeDaemon
-from meshbay_node.indexer.indexer import IndexProgress
from meshbay_node.indexer.group_index import GroupIndex
+from meshbay_node.indexer.indexer import IndexProgress
from meshbay_node.transport.webrtc_server import WebRTCPeerSession
from meshbay_node.ui.app import create_ui_app
diff --git a/packages/meshbay-node/tests/test_indexer.py b/packages/meshbay-node/tests/test_indexer.py
index 6aee1b5..48bf399 100644
--- a/packages/meshbay-node/tests/test_indexer.py
+++ b/packages/meshbay-node/tests/test_indexer.py
@@ -4,16 +4,15 @@ import asyncio
import os
import threading
import time
-import pytest
from pathlib import Path
-from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
-from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey
+import meshbay_node.indexer.indexer as indexer_mod
+import pytest
+from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from meshbay_common.crypto import generate_gek
from meshbay_node.indexer import DirectoryIndexer, GroupIndex, IndexCache
-import meshbay_node.indexer.indexer as indexer_mod
+
from conftest import one_root
-from meshbay_node.keystore import NodeKeys
@pytest.fixture
@@ -741,7 +740,7 @@ def test_small_file_gets_hash_version_1(tmp_path):
def test_large_file_gets_hash_version_2(tmp_path):
- from meshbay_node.indexer.indexer import _scan_file, _PARTIAL_THRESHOLD
+ from meshbay_node.indexer.indexer import _PARTIAL_THRESHOLD, _scan_file
d = tmp_path / "root"
d.mkdir()
f = d / "big.mkv"
@@ -755,7 +754,7 @@ def test_large_file_gets_hash_version_2(tmp_path):
def test_file_at_threshold_gets_hash_version_1(tmp_path):
- from meshbay_node.indexer.indexer import _scan_file, _PARTIAL_THRESHOLD
+ from meshbay_node.indexer.indexer import _PARTIAL_THRESHOLD, _scan_file
d = tmp_path / "root"
d.mkdir()
f = d / "exact.mkv"
@@ -770,7 +769,7 @@ def test_partial_hash_differs_from_full_hash(tmp_path):
"""For a file above the threshold, the partial hash must differ from what
a full-file blake3 would produce (they read different bytes)."""
import blake3 as b3
- from meshbay_node.indexer.indexer import _scan_file, _PARTIAL_THRESHOLD
+ from meshbay_node.indexer.indexer import _PARTIAL_THRESHOLD, _scan_file
d = tmp_path / "root"
d.mkdir()
f = d / "big.mkv"
@@ -785,7 +784,7 @@ def test_partial_hash_differs_from_full_hash(tmp_path):
def test_partial_hash_is_deterministic(tmp_path):
- from meshbay_node.indexer.indexer import _scan_file, _PARTIAL_THRESHOLD
+ from meshbay_node.indexer.indexer import _PARTIAL_THRESHOLD, _scan_file
d = tmp_path / "root"
d.mkdir()
f = d / "big.mkv"
diff --git a/packages/meshbay-node/tests/test_keystore.py b/packages/meshbay-node/tests/test_keystore.py
index 7dfefce..b9dd3a4 100644
--- a/packages/meshbay-node/tests/test_keystore.py
+++ b/packages/meshbay-node/tests/test_keystore.py
@@ -3,15 +3,13 @@
import sys
import pytest
-from pathlib import Path
+from meshbay_common.crypto import generate_gek
from meshbay_node.keystore import (
- NodeKeys,
create_keystore,
load_keystore,
- save_keystore,
load_or_create_keystore,
+ save_keystore,
)
-from meshbay_common.crypto import generate_gek
def test_create_and_load(tmp_path):
diff --git a/packages/meshbay-node/tests/test_leaseless_reads.py b/packages/meshbay-node/tests/test_leaseless_reads.py
index 6bd7f1f..2c4c6cd 100644
--- a/packages/meshbay-node/tests/test_leaseless_reads.py
+++ b/packages/meshbay-node/tests/test_leaseless_reads.py
@@ -23,9 +23,10 @@ import re
from pathlib import Path
import pytest
-
from meshbay_node.transfers import (
- LEASELESS_IDLE_SECS, MAX_LEASELESS_IN_FLIGHT, LeaselessReads,
+ LEASELESS_IDLE_SECS,
+ MAX_LEASELESS_IN_FLIGHT,
+ LeaselessReads,
)
SPA = (Path(__file__).resolve().parents[2] / "meshbay-hub" / "src"
diff --git a/packages/meshbay-node/tests/test_media_cache.py b/packages/meshbay-node/tests/test_media_cache.py
index dc78d8d..ec4e56e 100644
--- a/packages/meshbay-node/tests/test_media_cache.py
+++ b/packages/meshbay-node/tests/test_media_cache.py
@@ -3,8 +3,7 @@
import time
import pytest
-
-from meshbay_node.media_cache import MediaCache, TMDB_META_TTL_SECS, MUSICBRAINZ_META_TTL_SECS
+from meshbay_node.media_cache import MUSICBRAINZ_META_TTL_SECS, TMDB_META_TTL_SECS, MediaCache
@pytest.fixture
diff --git a/packages/meshbay-node/tests/test_media_cache_eviction.py b/packages/meshbay-node/tests/test_media_cache_eviction.py
index 587063a..f0292b5 100644
--- a/packages/meshbay-node/tests/test_media_cache_eviction.py
+++ b/packages/meshbay-node/tests/test_media_cache_eviction.py
@@ -18,7 +18,6 @@ about `create_all()`. Every existing node has a `thumbs` table without it.
import sqlite3
import pytest
-
from meshbay_node.media_cache import MediaCache
diff --git a/packages/meshbay-node/tests/test_multi_group.py b/packages/meshbay-node/tests/test_multi_group.py
index 3dc4778..e095426 100644
--- a/packages/meshbay-node/tests/test_multi_group.py
+++ b/packages/meshbay-node/tests/test_multi_group.py
@@ -7,19 +7,18 @@ Verifies that:
- A user in both groups can access both
"""
-import os
import time
+
import jwt
import pytest
-from pathlib import Path
-from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives import serialization
-
+from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from meshbay_common.crypto import generate_gek, pk_to_b64
from meshbay_node.indexer import DirectoryIndexer
-from conftest import one_root
-from meshbay_node.transport.quic_server import QuicChunkServer
from meshbay_node.transport.quic_client import QuicChunkClient
+from meshbay_node.transport.quic_server import QuicChunkServer
+
+from conftest import one_root
@pytest.fixture
diff --git a/packages/meshbay-node/tests/test_musicbrainz_enabled_policy.py b/packages/meshbay-node/tests/test_musicbrainz_enabled_policy.py
index 76b687e..00c1b69 100644
--- a/packages/meshbay-node/tests/test_musicbrainz_enabled_policy.py
+++ b/packages/meshbay-node/tests/test_musicbrainz_enabled_policy.py
@@ -13,12 +13,11 @@ The contact string stays node-wide — see test_musicbrainz_config_policy.py.
from pathlib import Path
import pytest
-
+from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from meshbay_common.adminop import OP_MUSICBRAINZ_ENABLED
from meshbay_node.indexer.group_index import GroupIndex
from meshbay_node.roster import Roster
from meshbay_node.transport.webrtc_server import WebRTCPeerSession
-from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from conftest import one_root
diff --git a/packages/meshbay-node/tests/test_node_status.py b/packages/meshbay-node/tests/test_node_status.py
index 897be33..7a27623 100644
--- a/packages/meshbay-node/tests/test_node_status.py
+++ b/packages/meshbay-node/tests/test_node_status.py
@@ -12,22 +12,22 @@ from pathlib import Path
import pytest
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
-
-from conftest import one_root
from meshbay_common.adminop import (
- OP_ROOT_ADD, OP_ROOT_REMOVE, OP_GROUP_ATTACH, OP_MEMBER_UNPIN,
+ OP_MEMBER_UNPIN,
admin_transcript,
)
-from meshbay_node.transport.quic_server import Denylist
from meshbay_common.crypto import pk_to_b64
from meshbay_common.join import ROLE_OPERATOR
from meshbay_common.protocol import MNP
from meshbay_node import ops
from meshbay_node.indexer.group_index import GroupIndex
-from meshbay_node.roster import open_roster
from meshbay_node.roots import RootSet
+from meshbay_node.roster import open_roster
+from meshbay_node.transport.quic_server import Denylist
from meshbay_node.transport.webrtc_server import WebRTCPeerSession
+from conftest import one_root
+
GROUP = "g" * 32
@@ -260,7 +260,7 @@ async def test_add_root_creates_directory_and_returns_info(tmp_path):
shared.mkdir()
new_dir = tmp_path / "new_root"
- from meshbay_node.config import NodeConfig, GroupConfig, RootSpec
+ from meshbay_node.config import GroupConfig, NodeConfig, RootSpec
cfg = GroupConfig(id=GROUP, name="test", roots=[
RootSpec(path=str(shared), name="shared", kind="generic", writable=True),
])
@@ -300,7 +300,7 @@ async def test_remove_root_requires_at_least_one_remaining(tmp_path):
shared = tmp_path / "shared"
shared.mkdir()
- from meshbay_node.config import GroupConfig, RootSpec, NodeConfig
+ from meshbay_node.config import GroupConfig, NodeConfig, RootSpec
cfg = GroupConfig(id=GROUP, name="test", roots=[
RootSpec(path=str(shared), name="shared", kind="generic", writable=True),
])
@@ -333,7 +333,7 @@ async def test_removing_a_writable_root_is_allowed(tmp_path):
d1.mkdir()
d2.mkdir()
- from meshbay_node.config import GroupConfig, RootSpec, NodeConfig
+ from meshbay_node.config import GroupConfig, NodeConfig, RootSpec
cfg = GroupConfig(id=GROUP, name="test", roots=[
RootSpec(path=str(d1), name="incoming", kind="generic", writable=True),
RootSpec(path=str(d2), name="shared", kind="generic", writable=False),
@@ -369,7 +369,7 @@ async def test_update_root_rewrites_the_flags_in_node_toml(tmp_path):
d1 = tmp_path / "media"
d1.mkdir()
- from meshbay_node.config import GroupConfig, RootSpec, NodeConfig
+ from meshbay_node.config import GroupConfig, NodeConfig, RootSpec
cfg = GroupConfig(id=GROUP, name="test", roots=[
RootSpec(path=str(d1), name="media", kind="generic", writable=False),
])
@@ -420,7 +420,7 @@ async def test_update_root_replaces_a_legacy_upload_line(tmp_path):
d1 = tmp_path / "media"
d1.mkdir()
- from meshbay_node.config import GroupConfig, RootSpec, NodeConfig
+ from meshbay_node.config import GroupConfig, NodeConfig, RootSpec
cfg = GroupConfig(id=GROUP, name="test", roots=[
RootSpec(path=str(d1), name="media", kind="generic", writable=True),
])
@@ -452,7 +452,7 @@ async def test_remove_root_succeeds_with_two_roots(tmp_path):
d1.mkdir()
d2.mkdir()
- from meshbay_node.config import GroupConfig, RootSpec, NodeConfig
+ from meshbay_node.config import GroupConfig, NodeConfig, RootSpec
cfg = GroupConfig(id=GROUP, name="test", roots=[
RootSpec(path=str(d1), name="dir1", kind="generic", writable=True),
RootSpec(path=str(d2), name="dir2", kind="generic", writable=False),
diff --git a/packages/meshbay-node/tests/test_partial_uploads.py b/packages/meshbay-node/tests/test_partial_uploads.py
index 0270a69..80ab454 100644
--- a/packages/meshbay-node/tests/test_partial_uploads.py
+++ b/packages/meshbay-node/tests/test_partial_uploads.py
@@ -23,21 +23,23 @@ from pathlib import Path
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from meshbay_common.crypto import generate_gek
+from meshbay_common.protocol import (
+ UPLOAD_PROBE_INDEX,
+ file_upload_ack_payload,
+)
from meshbay_node.daemon import NodeDaemon
from meshbay_node.indexer.group_index import GroupIndex
from meshbay_node.roots import Root, RootSet
from meshbay_node.transport.webrtc_server import WebRTCPeerSession
-
-from meshbay_common.protocol import (
- UPLOAD_PROBE_INDEX, file_upload_ack_payload,
-)
-
-from conftest import one_root, sealed_upload
-
from meshbay_node.uploads import (
- ORPHAN_AFTER_SECS, PART_SUFFIX, PartialUploads, find_parts, orphaned_parts,
+ ORPHAN_AFTER_SECS,
+ PART_SUFFIX,
+ PartialUploads,
+ find_parts,
+ orphaned_parts,
)
+from conftest import one_root, sealed_upload
# ── the state ───────────────────────────────────────────────────────────────
@@ -466,7 +468,7 @@ async def test_an_upload_chunk_says_its_slot_is_in_use(tmp_path):
The download twin of this was fixed a day earlier; the same omission was
still here, invisible until uploads took a real lease.
"""
- from meshbay_node.transfers import TransferSlots, UPLOAD
+ from meshbay_node.transfers import UPLOAD, TransferSlots
ctx = _group_ctx(tmp_path)
peer = _peer(ctx)
diff --git a/packages/meshbay-node/tests/test_peer_session_limits.py b/packages/meshbay-node/tests/test_peer_session_limits.py
index 64961ad..d5c909b 100644
--- a/packages/meshbay-node/tests/test_peer_session_limits.py
+++ b/packages/meshbay-node/tests/test_peer_session_limits.py
@@ -15,10 +15,12 @@ import asyncio
from unittest.mock import MagicMock
import pytest
-
from meshbay_node.transport import webrtc_server as ws_mod
from meshbay_node.transport.webrtc_server import (
- MAX_PEER_SESSIONS, UNAUTHENTICATED_SESSION_TIMEOUT, WebRTCTransport)
+ MAX_PEER_SESSIONS,
+ UNAUTHENTICATED_SESSION_TIMEOUT,
+ WebRTCTransport,
+)
def _transport() -> WebRTCTransport:
diff --git a/packages/meshbay-node/tests/test_platform.py b/packages/meshbay-node/tests/test_platform.py
index 3fb27f3..5c80c5b 100644
--- a/packages/meshbay-node/tests/test_platform.py
+++ b/packages/meshbay-node/tests/test_platform.py
@@ -5,8 +5,8 @@ here by monkeypatching that (and `os.environ`) rather than only on the OS the
suite happens to run on.
"""
-import os
import asyncio
+import os
import sys
from pathlib import Path
from unittest.mock import Mock
diff --git a/packages/meshbay-node/tests/test_poster_cache.py b/packages/meshbay-node/tests/test_poster_cache.py
index bbd824d..908fb69 100644
--- a/packages/meshbay-node/tests/test_poster_cache.py
+++ b/packages/meshbay-node/tests/test_poster_cache.py
@@ -15,7 +15,6 @@ already uses to resolve a thumbnail by id.
"""
import pytest
-
from meshbay_node.media_cache import MediaCache
from meshbay_node.transport.webrtc_server import WebRTCPeerSession
diff --git a/packages/meshbay-node/tests/test_quic_transport.py b/packages/meshbay-node/tests/test_quic_transport.py
index fb28295..8eb0622 100644
--- a/packages/meshbay-node/tests/test_quic_transport.py
+++ b/packages/meshbay-node/tests/test_quic_transport.py
@@ -6,17 +6,17 @@ Same structure as test_transport.py but uses QUIC instead of TCP+TLS.
import asyncio
import os
import time
+
import jwt
import pytest
-from pathlib import Path
-from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives import serialization
-
+from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from meshbay_common.crypto import generate_gek, pk_to_b64
from meshbay_node.indexer import DirectoryIndexer
-from conftest import one_root
-from meshbay_node.transport.quic_server import QuicChunkServer, Denylist
from meshbay_node.transport.quic_client import QuicChunkClient
+from meshbay_node.transport.quic_server import Denylist, QuicChunkServer
+
+from conftest import one_root
@pytest.fixture
diff --git a/packages/meshbay-node/tests/test_rename_reenrichment.py b/packages/meshbay-node/tests/test_rename_reenrichment.py
index f6761d9..7ddca6f 100644
--- a/packages/meshbay-node/tests/test_rename_reenrichment.py
+++ b/packages/meshbay-node/tests/test_rename_reenrichment.py
@@ -17,9 +17,8 @@ import asyncio
import pytest
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
-
from meshbay_common.crypto import generate_gek
-from meshbay_node.config import Config, HubConfig, NodeConfig, GroupConfig, KeystoreConfig
+from meshbay_node.config import Config, GroupConfig, HubConfig, KeystoreConfig, NodeConfig
from meshbay_node.daemon import NodeDaemon
from meshbay_node.indexer import DirectoryIndexer
from meshbay_node.media_cache import MediaCache
diff --git a/packages/meshbay-node/tests/test_replug_restores_enrichment.py b/packages/meshbay-node/tests/test_replug_restores_enrichment.py
index 04a06ae..a2d2db4 100644
--- a/packages/meshbay-node/tests/test_replug_restores_enrichment.py
+++ b/packages/meshbay-node/tests/test_replug_restores_enrichment.py
@@ -46,10 +46,8 @@ import os
import pytest
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
-
from meshbay_common.crypto import generate_gek
-from meshbay_node.config import (Config, GroupConfig, HubConfig, KeystoreConfig,
- NodeConfig)
+from meshbay_node.config import Config, GroupConfig, HubConfig, KeystoreConfig, NodeConfig
from meshbay_node.daemon import NodeDaemon
from meshbay_node.indexer import DirectoryIndexer
from meshbay_node.indexer.enrich_audio import AudioEnricher
diff --git a/packages/meshbay-node/tests/test_root_availability.py b/packages/meshbay-node/tests/test_root_availability.py
index 2d848c7..82bf6bd 100644
--- a/packages/meshbay-node/tests/test_root_availability.py
+++ b/packages/meshbay-node/tests/test_root_availability.py
@@ -13,13 +13,11 @@ an indexer that treats a vanished root as a set of deletions, which is what the
straightforward implementation does.
"""
-import asyncio
import os
from pathlib import Path
import pytest
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
-
from meshbay_node.indexer.indexer import DirectoryIndexer
from meshbay_node.roots import RootSet
diff --git a/packages/meshbay-node/tests/test_root_eject.py b/packages/meshbay-node/tests/test_root_eject.py
index f57fb92..d73e71c 100644
--- a/packages/meshbay-node/tests/test_root_eject.py
+++ b/packages/meshbay-node/tests/test_root_eject.py
@@ -21,7 +21,6 @@ from pathlib import Path
import pytest
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
-
from meshbay_node.indexer.indexer import DirectoryIndexer
from meshbay_node.roots import RootSet
from meshbay_node.roster import Roster
diff --git a/packages/meshbay-node/tests/test_root_ops_reach_the_live_set.py b/packages/meshbay-node/tests/test_root_ops_reach_the_live_set.py
index 976af82..6a52c06 100644
--- a/packages/meshbay-node/tests/test_root_ops_reach_the_live_set.py
+++ b/packages/meshbay-node/tests/test_root_ops_reach_the_live_set.py
@@ -28,7 +28,6 @@ from types import SimpleNamespace
import pytest
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
-
from meshbay_node import ops
from meshbay_node.config import GroupConfig, NodeConfig, RootSpec
from meshbay_node.indexer.group_index import GroupIndex
diff --git a/packages/meshbay-node/tests/test_root_paths_are_operator_only.py b/packages/meshbay-node/tests/test_root_paths_are_operator_only.py
index 080d4be..0e89afa 100644
--- a/packages/meshbay-node/tests/test_root_paths_are_operator_only.py
+++ b/packages/meshbay-node/tests/test_root_paths_are_operator_only.py
@@ -21,7 +21,6 @@ import inspect
import re
from pathlib import Path
-
from meshbay_node import daemon as daemon_mod
from meshbay_node import ops
from meshbay_node.roots import RootSet
diff --git a/packages/meshbay-node/tests/test_root_writable_policy.py b/packages/meshbay-node/tests/test_root_writable_policy.py
index 3c8a837..0cd9af8 100644
--- a/packages/meshbay-node/tests/test_root_writable_policy.py
+++ b/packages/meshbay-node/tests/test_root_writable_policy.py
@@ -26,15 +26,15 @@ from pathlib import Path
import pytest
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
-
-from conftest import sealed_upload
-from meshbay_common.adminop import OP_ROOT_UPDATE, OP_ROOT_EJECT, OP_ROOT_PLUG
+from meshbay_common.adminop import OP_ROOT_EJECT, OP_ROOT_PLUG, OP_ROOT_UPDATE
from meshbay_common.crypto import generate_gek
from meshbay_common.protocol import MNP
from meshbay_node.indexer.group_index import GroupIndex
from meshbay_node.roots import RootSet
from meshbay_node.transport.webrtc_server import WebRTCPeerSession
+from conftest import sealed_upload
+
pytestmark = pytest.mark.asyncio
diff --git a/packages/meshbay-node/tests/test_roots.py b/packages/meshbay-node/tests/test_roots.py
index 9233180..004f004 100644
--- a/packages/meshbay-node/tests/test_roots.py
+++ b/packages/meshbay-node/tests/test_roots.py
@@ -7,15 +7,17 @@ file went to the wrong disk" or "the same film is listed twice and deleting one
copy breaks the other".
"""
-from pathlib import Path
import pytest
-
+from meshbay_common.protocol import IndexEntry
from meshbay_node.roots import (
- Root, RootError, RootSet, entry_abs_path,
- SAFE_UPLOAD_NAME, safe_subdir, _free_name,
+ SAFE_UPLOAD_NAME,
+ RootError,
+ RootSet,
+ _free_name,
+ entry_abs_path,
+ safe_subdir,
)
-from meshbay_common.protocol import IndexEntry
def _spec(path, **kw):
diff --git a/packages/meshbay-node/tests/test_roster_pairing.py b/packages/meshbay-node/tests/test_roster_pairing.py
index 2e8c183..67c3b08 100644
--- a/packages/meshbay-node/tests/test_roster_pairing.py
+++ b/packages/meshbay-node/tests/test_roster_pairing.py
@@ -18,14 +18,13 @@ import pytest
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey
-
from meshbay_common.crypto import generate_gek, pk_to_b64, unwrap_gek_aes
from meshbay_common.join import ROLE_MEMBER, ROLE_OPERATOR, join_transcript
from meshbay_node.indexer.group_index import GroupIndex
-from conftest import one_root
from meshbay_node.roster import Roster, hash_code, normalize_code
from meshbay_node.transport.webrtc_server import WebRTCPeerSession
+from conftest import one_root
# ── Fixtures ──────────────────────────────────────────────────────────────────
@@ -694,7 +693,6 @@ async def test_unpinned_operator_loses_authority_immediately(tmp_path, roster):
def _ui_client(tmp_path, roster, **extra):
from fastapi.testclient import TestClient
-
from meshbay_node.config import Config
from meshbay_node.ui.app import create_ui_app
diff --git a/packages/meshbay-node/tests/test_scan_settings_policy.py b/packages/meshbay-node/tests/test_scan_settings_policy.py
index 94f4421..926c94f 100644
--- a/packages/meshbay-node/tests/test_scan_settings_policy.py
+++ b/packages/meshbay-node/tests/test_scan_settings_policy.py
@@ -13,7 +13,6 @@ from pathlib import Path
import pytest
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
-
from meshbay_common.adminop import OP_SET_SCAN_SETTINGS
from meshbay_common.crypto import generate_gek
from meshbay_node import ops
diff --git a/packages/meshbay-node/tests/test_season_and_search_requests.py b/packages/meshbay-node/tests/test_season_and_search_requests.py
index 4141d13..7e81e63 100644
--- a/packages/meshbay-node/tests/test_season_and_search_requests.py
+++ b/packages/meshbay-node/tests/test_season_and_search_requests.py
@@ -10,7 +10,6 @@ test_tmdb_override_policy.py.
"""
import pytest
-
from meshbay_common.protocol import MNP
from meshbay_node.media_cache import MediaCache
from meshbay_node.transport.webrtc_server import WebRTCPeerSession
diff --git a/packages/meshbay-node/tests/test_security_regressions.py b/packages/meshbay-node/tests/test_security_regressions.py
index d6ecb71..bfe25b9 100644
--- a/packages/meshbay-node/tests/test_security_regressions.py
+++ b/packages/meshbay-node/tests/test_security_regressions.py
@@ -9,20 +9,18 @@ only ever exercised happy paths, never an authorization boundary.
If one of these starts failing, a fix has been reverted. Do not "fix" the test.
"""
-import base64
import struct
from pathlib import Path
import pytest
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
-
from meshbay_common.crypto import generate_gek
-from meshbay_common.protocol import IndexEntry
from meshbay_node.indexer.group_index import GroupIndex
from meshbay_node.roots import RootSet
-from conftest import one_root, opened_ack, sealed_upload
from meshbay_node.transport.webrtc_server import WebRTCPeerSession
+from conftest import one_root, opened_ack, sealed_upload
+
def _safe_name_re():
"""
@@ -64,7 +62,7 @@ def test_daemon_exposes_no_plaintext_listener():
C1: the daemon must not bind anything that serves content without a handshake.
NodeConfig no longer carries an HTTP port at all.
"""
- from meshbay_node.config import NodeConfig, GroupConfig
+ from meshbay_node.config import GroupConfig, NodeConfig
assert "http_port" not in NodeConfig.__dataclass_fields__
assert "http_port" not in GroupConfig.__dataclass_fields__
@@ -568,6 +566,7 @@ def test_admin_signature_does_not_transfer_between_operations(tmp_path):
def test_admin_challenge_expires(tmp_path):
"""H5: a stale challenge must not be usable."""
import time as _time
+
from meshbay_common.adminop import ADMIN_CHALLENGE_TTL, OP_FILE_DELETE
session = _session(tmp_path, "operator")
@@ -633,6 +632,7 @@ def test_keystore_records_argon2_params_for_migration(tmp_path):
envelope records the parameters it was written with.
"""
import json
+
from meshbay_node.keystore import create_keystore, load_keystore
path = tmp_path / "keystore.enc"
@@ -648,11 +648,17 @@ def test_legacy_keystore_still_opens(tmp_path):
"""M2: a keystore written under the 64 MB profile must still unlock."""
import base64 as _b64
import json
+
import msgpack
from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey
from meshbay_common.crypto import (
- LEGACY_ARGON2_ITERATIONS, LEGACY_ARGON2_LANES, LEGACY_ARGON2_MEMORY_COST,
- derive_keystore_key, encrypt_keystore, pk_to_b64, sk_to_b64,
+ LEGACY_ARGON2_ITERATIONS,
+ LEGACY_ARGON2_LANES,
+ LEGACY_ARGON2_MEMORY_COST,
+ derive_keystore_key,
+ encrypt_keystore,
+ pk_to_b64,
+ sk_to_b64,
)
from meshbay_node.keystore import load_keystore
@@ -717,7 +723,9 @@ def test_pre_handshake_message_budget_is_small():
unauthenticated peer could announce a huge frame and dribble bytes into it.
"""
from meshbay_node.transport.webrtc_server import (
- MAX_MSG, PRE_HANDSHAKE_MAX_MSG, _DataChannelBuffer,
+ MAX_MSG,
+ PRE_HANDSHAKE_MAX_MSG,
+ _DataChannelBuffer,
)
assert PRE_HANDSHAKE_MAX_MSG <= 1024 * 1024
assert PRE_HANDSHAKE_MAX_MSG < MAX_MSG
@@ -918,8 +926,8 @@ async def test_an_identified_device_that_is_not_an_operator_is_refused(tmp_path)
and `operator_pks()` is rebuilt from the roster on every call so a revoked
one stops working at once.
"""
- from meshbay_node.roster import Roster
from meshbay_common.crypto import pk_to_b64
+ from meshbay_node.roster import Roster
roster = Roster(db_path=tmp_path / "roster.db")
await roster.open()
@@ -940,9 +948,9 @@ async def test_an_identified_device_that_is_not_an_operator_is_refused(tmp_path)
async def test_a_paired_operator_device_is_what_opens_it(tmp_path):
"""The positive case, so the test above is about authority and not about
everything being refused."""
- from meshbay_node.roster import Roster
- from meshbay_common.join import ROLE_OPERATOR
from meshbay_common.crypto import pk_to_b64
+ from meshbay_common.join import ROLE_OPERATOR
+ from meshbay_node.roster import Roster
roster = Roster(db_path=tmp_path / "roster.db")
await roster.open()
diff --git a/packages/meshbay-node/tests/test_startup_scan_enrichment.py b/packages/meshbay-node/tests/test_startup_scan_enrichment.py
index f43c6e9..f3ad2ca 100644
--- a/packages/meshbay-node/tests/test_startup_scan_enrichment.py
+++ b/packages/meshbay-node/tests/test_startup_scan_enrichment.py
@@ -21,12 +21,9 @@ is exercised the same way a real operator's group would be.
import asyncio
import pytest
-from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
-from unittest.mock import MagicMock
-
from meshbay_common.crypto import generate_gek
-from meshbay_node.config import Config, HubConfig, NodeConfig, GroupConfig, KeystoreConfig
+from meshbay_node.config import Config, GroupConfig, HubConfig, KeystoreConfig, NodeConfig
from meshbay_node.daemon import NodeDaemon
from meshbay_node.indexer import DirectoryIndexer
from meshbay_node.indexer.enrich import Enricher
diff --git a/packages/meshbay-node/tests/test_stream_audio_track_selection.py b/packages/meshbay-node/tests/test_stream_audio_track_selection.py
index 53781f9..b9e2105 100644
--- a/packages/meshbay-node/tests/test_stream_audio_track_selection.py
+++ b/packages/meshbay-node/tests/test_stream_audio_track_selection.py
@@ -23,7 +23,6 @@ from pathlib import Path
import pytest
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
-
from meshbay_common.crypto import generate_gek
from meshbay_common.webcrypto import chunk_key_aes, decrypt_chunk_aes
from meshbay_node.indexer.group_index import GroupIndex
diff --git a/packages/meshbay-node/tests/test_stream_audio_transcode.py b/packages/meshbay-node/tests/test_stream_audio_transcode.py
index 92518ba..6c9bde7 100644
--- a/packages/meshbay-node/tests/test_stream_audio_transcode.py
+++ b/packages/meshbay-node/tests/test_stream_audio_transcode.py
@@ -22,7 +22,6 @@ from pathlib import Path
import pytest
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
-
from meshbay_common.crypto import generate_gek
from meshbay_common.webcrypto import chunk_key_aes, decrypt_chunk_aes
from meshbay_node.indexer.group_index import GroupIndex
@@ -44,7 +43,7 @@ def _make_clip(path: Path, *, acodec: str, channels: int = 2) -> None:
subprocess.run(
["ffmpeg", "-hide_banner", "-loglevel", "error", "-y",
"-f", "lavfi", "-i", "testsrc=size=320x240:rate=25:duration=1",
- "-f", "lavfi", "-i", f"sine=frequency=440:duration=1:sample_rate=48000",
+ "-f", "lavfi", "-i", "sine=frequency=440:duration=1:sample_rate=48000",
"-ac", str(channels),
"-c:v", "libx264", "-preset", "ultrafast", "-c:a", acodec,
str(path)],
diff --git a/packages/meshbay-node/tests/test_stream_capacity.py b/packages/meshbay-node/tests/test_stream_capacity.py
index a35ece8..7ce6bf6 100644
--- a/packages/meshbay-node/tests/test_stream_capacity.py
+++ b/packages/meshbay-node/tests/test_stream_capacity.py
@@ -17,9 +17,10 @@ find.
import asyncio
import pytest
-
from meshbay_node.transport.webrtc_server import (
- MAX_CONCURRENT_TRANSCODES, WebRTCPeerSession, WebRTCTransport,
+ MAX_CONCURRENT_TRANSCODES,
+ WebRTCPeerSession,
+ WebRTCTransport,
)
@@ -35,11 +36,11 @@ def transport(tmp_path):
"""A real WebRTCTransport. Its keys and index are genuine but incidental —
nothing below the capacity code reads them."""
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
-
- from conftest import one_root
from meshbay_common.crypto import generate_gek
from meshbay_node.indexer.group_index import GroupIndex
+ from conftest import one_root
+
sk_node = Ed25519PrivateKey.generate()
gek = generate_gek()
shared = tmp_path / "shared"
diff --git a/packages/meshbay-node/tests/test_stream_capacity_config.py b/packages/meshbay-node/tests/test_stream_capacity_config.py
index 442d3ef..c788ba6 100644
--- a/packages/meshbay-node/tests/test_stream_capacity_config.py
+++ b/packages/meshbay-node/tests/test_stream_capacity_config.py
@@ -23,7 +23,6 @@ import textwrap
from pathlib import Path
import pytest
-
from meshbay_node.config import load_config
from meshbay_node.roots import RootSet
from meshbay_node.transport.webrtc_server import (
diff --git a/packages/meshbay-node/tests/test_stream_seek_audio_alignment.py b/packages/meshbay-node/tests/test_stream_seek_audio_alignment.py
index c1d0c66..5d78c00 100644
--- a/packages/meshbay-node/tests/test_stream_seek_audio_alignment.py
+++ b/packages/meshbay-node/tests/test_stream_seek_audio_alignment.py
@@ -29,7 +29,6 @@ from pathlib import Path
import pytest
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
-
from meshbay_common.crypto import generate_gek
from meshbay_common.webcrypto import chunk_key_aes, decrypt_chunk_aes
from meshbay_node.indexer.group_index import GroupIndex
diff --git a/packages/meshbay-node/tests/test_stream_seek_reports_the_keyframe.py b/packages/meshbay-node/tests/test_stream_seek_reports_the_keyframe.py
index 9aea2b4..c575572 100644
--- a/packages/meshbay-node/tests/test_stream_seek_reports_the_keyframe.py
+++ b/packages/meshbay-node/tests/test_stream_seek_reports_the_keyframe.py
@@ -35,7 +35,6 @@ from pathlib import Path
import pytest
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
-
from meshbay_common.crypto import generate_gek
from meshbay_common.webcrypto import chunk_key_aes, decrypt_chunk_aes
from meshbay_node.indexer.group_index import GroupIndex
diff --git a/packages/meshbay-node/tests/test_stream_subtitle_tracks.py b/packages/meshbay-node/tests/test_stream_subtitle_tracks.py
index d3bcc8b..7a27a37 100644
--- a/packages/meshbay-node/tests/test_stream_subtitle_tracks.py
+++ b/packages/meshbay-node/tests/test_stream_subtitle_tracks.py
@@ -33,7 +33,6 @@ from pathlib import Path
import pytest
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
-
from meshbay_common.crypto import generate_gek
from meshbay_common.webcrypto import chunk_key_aes, decrypt_chunk_aes
from meshbay_node.indexer.group_index import GroupIndex
diff --git a/packages/meshbay-node/tests/test_stream_video_transcode.py b/packages/meshbay-node/tests/test_stream_video_transcode.py
index 316fdce..b60d546 100644
--- a/packages/meshbay-node/tests/test_stream_video_transcode.py
+++ b/packages/meshbay-node/tests/test_stream_video_transcode.py
@@ -32,7 +32,6 @@ from pathlib import Path
import pytest
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
-
from meshbay_common.crypto import generate_gek
from meshbay_common.webcrypto import chunk_key_aes, decrypt_chunk_aes
from meshbay_node import hwaccel
diff --git a/packages/meshbay-node/tests/test_title_parse.py b/packages/meshbay-node/tests/test_title_parse.py
index 2c4573a..95c798b 100644
--- a/packages/meshbay-node/tests/test_title_parse.py
+++ b/packages/meshbay-node/tests/test_title_parse.py
@@ -17,7 +17,6 @@ from meshbay_node.indexer.title_parse import (
year_in,
)
-
# ── §3.3 row: plain, well-formed movie filename ──────────────────────────────
def test_plain_movie_filename_parses_confidently():
diff --git a/packages/meshbay-node/tests/test_tmdb.py b/packages/meshbay-node/tests/test_tmdb.py
index 299ff2a..981357a 100644
--- a/packages/meshbay-node/tests/test_tmdb.py
+++ b/packages/meshbay-node/tests/test_tmdb.py
@@ -2,7 +2,6 @@
import httpx
import pytest
-
from meshbay_node.tmdb import TmdbClient
diff --git a/packages/meshbay-node/tests/test_tmdb_config_policy.py b/packages/meshbay-node/tests/test_tmdb_config_policy.py
index cef4fda..6a51eb0 100644
--- a/packages/meshbay-node/tests/test_tmdb_config_policy.py
+++ b/packages/meshbay-node/tests/test_tmdb_config_policy.py
@@ -21,12 +21,11 @@ wire (see _issue_admin_challenge's docstring).
from pathlib import Path
import pytest
-
+from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from meshbay_common.adminop import OP_TMDB_CONFIG
from meshbay_node.indexer.group_index import GroupIndex
from meshbay_node.roster import Roster
from meshbay_node.transport.webrtc_server import WebRTCPeerSession
-from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from conftest import one_root
diff --git a/packages/meshbay-node/tests/test_tmdb_enabled_policy.py b/packages/meshbay-node/tests/test_tmdb_enabled_policy.py
index 0a748cd..10d1e2b 100644
--- a/packages/meshbay-node/tests/test_tmdb_enabled_policy.py
+++ b/packages/meshbay-node/tests/test_tmdb_enabled_policy.py
@@ -14,12 +14,11 @@ test_tmdb_config_policy.py for those.
from pathlib import Path
import pytest
-
+from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from meshbay_common.adminop import OP_TMDB_ENABLED
from meshbay_node.indexer.group_index import GroupIndex
from meshbay_node.roster import Roster
from meshbay_node.transport.webrtc_server import WebRTCPeerSession
-from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from conftest import one_root
diff --git a/packages/meshbay-node/tests/test_tmdb_language_fallback.py b/packages/meshbay-node/tests/test_tmdb_language_fallback.py
index 52fe4c4..62171c3 100644
--- a/packages/meshbay-node/tests/test_tmdb_language_fallback.py
+++ b/packages/meshbay-node/tests/test_tmdb_language_fallback.py
@@ -9,7 +9,6 @@ field, or silently showing a blank overview/poster.
"""
import pytest
-
from meshbay_node.transport.webrtc_server import WebRTCPeerSession
pytestmark = pytest.mark.asyncio
diff --git a/packages/meshbay-node/tests/test_tmdb_override_policy.py b/packages/meshbay-node/tests/test_tmdb_override_policy.py
index d434e1a..aed3ea2 100644
--- a/packages/meshbay-node/tests/test_tmdb_override_policy.py
+++ b/packages/meshbay-node/tests/test_tmdb_override_policy.py
@@ -14,9 +14,8 @@ from pathlib import Path
import pytest
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
-
from meshbay_common.adminop import OP_TMDB_OVERRIDE
-from meshbay_common.protocol import IndexEntry, MNP
+from meshbay_common.protocol import MNP, IndexEntry
from meshbay_node.indexer.group_index import GroupIndex
from meshbay_node.media_cache import MediaCache
from meshbay_node.transport.webrtc_server import WebRTCPeerSession
diff --git a/packages/meshbay-node/tests/test_tmdb_rematch_policy.py b/packages/meshbay-node/tests/test_tmdb_rematch_policy.py
index 198d75b..4d43552 100644
--- a/packages/meshbay-node/tests/test_tmdb_rematch_policy.py
+++ b/packages/meshbay-node/tests/test_tmdb_rematch_policy.py
@@ -9,7 +9,6 @@ asking for a fresh resolution.
import hashlib
import pytest
-from conftest import one_root
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from meshbay_common.adminop import OP_TMDB_REMATCH
from meshbay_common.protocol import MNP, IndexEntry
@@ -17,6 +16,8 @@ from meshbay_node.indexer.group_index import GroupIndex
from meshbay_node.media_cache import MediaCache
from meshbay_node.transport.webrtc_server import WebRTCPeerSession
+from conftest import one_root
+
pytestmark = pytest.mark.asyncio
diff --git a/packages/meshbay-node/tests/test_tmdb_show_director.py b/packages/meshbay-node/tests/test_tmdb_show_director.py
index cb31c2c..fd324b1 100644
--- a/packages/meshbay-node/tests/test_tmdb_show_director.py
+++ b/packages/meshbay-node/tests/test_tmdb_show_director.py
@@ -12,7 +12,6 @@ the show details. Several creators is ordinary, so they join into one line.
"""
import pytest
-
from meshbay_node.transport.webrtc_server import WebRTCPeerSession
pytestmark = pytest.mark.asyncio
diff --git a/packages/meshbay-node/tests/test_transfer_settings.py b/packages/meshbay-node/tests/test_transfer_settings.py
index bcfa6a8..a2c7fd9 100644
--- a/packages/meshbay-node/tests/test_transfer_settings.py
+++ b/packages/meshbay-node/tests/test_transfer_settings.py
@@ -19,10 +19,12 @@ shape of the bug this whole branch started from (`webrtc._stream_sem`).
"""
import pytest
-
from meshbay_node.roster import Roster
from meshbay_node.transfers import (
- DEFAULT_MAX_PER_MEMBER, DOWNLOAD, UPLOAD, TransferSlots,
+ DEFAULT_MAX_PER_MEMBER,
+ DOWNLOAD,
+ UPLOAD,
+ TransferSlots,
)
diff --git a/packages/meshbay-node/tests/test_transfer_slots.py b/packages/meshbay-node/tests/test_transfer_slots.py
index 7056e93..08e7e70 100644
--- a/packages/meshbay-node/tests/test_transfer_slots.py
+++ b/packages/meshbay-node/tests/test_transfer_slots.py
@@ -21,12 +21,18 @@ by reasoning about it.
import random
import pytest
-
from meshbay_node.transfers import (
- DOWNLOAD, GRANT_DEADLINE_SECS, IDLE_TIMEOUT_SECS, KINDS,
- MAX_MISSED_GRANTS, MAX_QUEUED_PER_MEMBER, REASON_ABANDONED, REASON_IDLE,
- REASON_NOT_TAKEN_UP, TransferSlots,
+ DOWNLOAD,
+ GRANT_DEADLINE_SECS,
+ IDLE_TIMEOUT_SECS,
+ KINDS,
+ MAX_MISSED_GRANTS,
+ MAX_QUEUED_PER_MEMBER,
+ REASON_ABANDONED,
+ REASON_IDLE,
+ REASON_NOT_TAKEN_UP,
UPLOAD,
+ TransferSlots,
)
diff --git a/packages/meshbay-node/tests/test_transport_wire_parity.py b/packages/meshbay-node/tests/test_transport_wire_parity.py
index bc6b134..6e74b28 100644
--- a/packages/meshbay-node/tests/test_transport_wire_parity.py
+++ b/packages/meshbay-node/tests/test_transport_wire_parity.py
@@ -16,7 +16,6 @@ again.
import inspect
import pytest
-from conftest import one_root
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from meshbay_common.crypto import generate_gek
from meshbay_common.groupbox import PURPOSE_INDEX, unseal
@@ -25,6 +24,8 @@ from meshbay_node.indexer import DirectoryIndexer
from meshbay_node.transport import quic_server, webrtc_server
from meshbay_node.transport.wire import index_sync_message
+from conftest import one_root
+
@pytest.fixture
def gek():
diff --git a/packages/meshbay-node/tests/test_upload_size_cap.py b/packages/meshbay-node/tests/test_upload_size_cap.py
index dca6e15..cc04eba 100644
--- a/packages/meshbay-node/tests/test_upload_size_cap.py
+++ b/packages/meshbay-node/tests/test_upload_size_cap.py
@@ -17,7 +17,6 @@ import textwrap
from pathlib import Path
import pytest
-
from meshbay_node.config import load_config
from meshbay_node.roots import RootSet
from meshbay_node.transport.webrtc_server import (
diff --git a/packages/meshbay-node/tests/test_video_root_gates_enrichment.py b/packages/meshbay-node/tests/test_video_root_gates_enrichment.py
index d06b3f4..c39876a 100644
--- a/packages/meshbay-node/tests/test_video_root_gates_enrichment.py
+++ b/packages/meshbay-node/tests/test_video_root_gates_enrichment.py
@@ -17,10 +17,9 @@ import asyncio
import pytest
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
-
from meshbay_common.crypto import generate_gek
from meshbay_node import ops
-from meshbay_node.config import Config, HubConfig, NodeConfig, GroupConfig, KeystoreConfig
+from meshbay_node.config import Config, GroupConfig, HubConfig, KeystoreConfig, NodeConfig
from meshbay_node.daemon import NodeDaemon
from meshbay_node.indexer import DirectoryIndexer
from meshbay_node.indexer.enrich import Enricher
diff --git a/packages/meshbay-node/tests/test_webrtc_transport.py b/packages/meshbay-node/tests/test_webrtc_transport.py
index 0839d42..4aba99f 100644
--- a/packages/meshbay-node/tests/test_webrtc_transport.py
+++ b/packages/meshbay-node/tests/test_webrtc_transport.py
@@ -9,52 +9,59 @@ Uses local loopback (no STUN/ICE needed for localhost).
import asyncio
import base64
-from contextlib import asynccontextmanager
import hashlib
import hmac
import os
import struct
import time
+from contextlib import asynccontextmanager
import jwt
import msgpack
import pytest
+from aiortc import RTCPeerConnection, RTCSessionDescription
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric.ed25519 import (
- Ed25519PrivateKey, Ed25519PublicKey,
+ Ed25519PrivateKey,
+ Ed25519PublicKey,
)
-from aiortc import RTCPeerConnection, RTCSessionDescription
-
from meshbay_common import MNP_VERSION
from meshbay_common.crypto import (
generate_gek,
pk_to_b64,
- wrap_gek,
- wrap_gek_aes,
unwrap_gek,
unwrap_gek_aes,
+ wrap_gek,
+ wrap_gek_aes,
)
from meshbay_common.groupbox import PURPOSE_ACK, PURPOSE_INDEX, unseal
-from meshbay_common.webcrypto import chunk_key_aes, decrypt_chunk_aes
from meshbay_common.protocol import MNP
+from meshbay_common.webcrypto import chunk_key_aes, decrypt_chunk_aes
+
TEST_GROUP = "g"
-from meshbay_common.handshake import (
- NONCE_LEN, ROLE_CLIENT, ROLE_NODE, handshake_transcript,
- make_proof, verify_proof, webrtc_binding,
-)
from meshbay_common.adminop import (
OP_FILE_DELETE,
OP_INVITE_CREATE,
admin_transcript,
)
+from meshbay_common.handshake import (
+ NONCE_LEN,
+ ROLE_CLIENT,
+ ROLE_NODE,
+ handshake_transcript,
+ make_proof,
+ verify_proof,
+ webrtc_binding,
+)
from meshbay_common.join import ROLE_MEMBER, ROLE_OPERATOR, join_transcript
from meshbay_node.bundle_store import BundleStore
-from conftest import one_root
-from meshbay_node.roster import Roster
from meshbay_node.indexer import DirectoryIndexer
+from meshbay_node.roster import Roster
from meshbay_node.transport.webrtc_server import WebRTCTransport
+from conftest import one_root
+
@pytest.fixture
def sk_node():
diff --git a/packages/meshbay-node/tests/test_windows_root_shapes.py b/packages/meshbay-node/tests/test_windows_root_shapes.py
index 5c5da25..56279b1 100644
--- a/packages/meshbay-node/tests/test_windows_root_shapes.py
+++ b/packages/meshbay-node/tests/test_windows_root_shapes.py
@@ -27,7 +27,6 @@ import tomllib
from pathlib import Path, PureWindowsPath
import pytest
-
from meshbay_node.roots import RootError, RootSet, derive_name
BS = chr(92)
diff --git a/packages/meshbay-node/tests/test_wizard_apps_endpoint.py b/packages/meshbay-node/tests/test_wizard_apps_endpoint.py
index 10ab489..77fa9a6 100644
--- a/packages/meshbay-node/tests/test_wizard_apps_endpoint.py
+++ b/packages/meshbay-node/tests/test_wizard_apps_endpoint.py
@@ -13,12 +13,12 @@ from pathlib import Path
import pytest
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from fastapi.testclient import TestClient
-
-from conftest import one_root
from meshbay_node.indexer.group_index import GroupIndex
from meshbay_node.roster import Roster
from meshbay_node.ui.app import create_ui_app
+from conftest import one_root
+
pytestmark = pytest.mark.asyncio
diff --git a/packages/meshbay-node/tests/transfer_probe.py b/packages/meshbay-node/tests/transfer_probe.py
index 38e6cb6..7aa4902 100755
--- a/packages/meshbay-node/tests/transfer_probe.py
+++ b/packages/meshbay-node/tests/transfer_probe.py
@@ -69,9 +69,8 @@ if not (_QE / "e2e.py").exists():
f"run this from a machine that has one.")
sys.path.insert(0, str(_QE))
-import httpx # noqa: E402
-
-from e2e import Client, env # noqa: E402
+import httpx # noqa: E402
+from e2e import Client, env # noqa: E402
def _line(ok: bool, text: str) -> None:
@@ -272,7 +271,6 @@ async def operator_checks(client, ack, group, node_id) -> int:
and the operator's view because it reported the module defaults.
"""
import asyncio as _a
- import json as _json
import re as _re
failures = 0
@@ -322,7 +320,7 @@ async def operator_checks(client, ack, group, node_id) -> int:
try:
started = await _a.wait_for(
_wait_for_grant(client, tr_waiting), timeout=20)
- except _a.TimeoutError:
+ except TimeoutError:
started = False
_line(started, "raising the cap started the waiting transfer, with no "
"restart and no reconnection")
@@ -371,7 +369,7 @@ async def operator_checks(client, ack, group, node_id) -> int:
_cli("transfers", "per-member", "4", "4", "--group", group["id"])
try:
moved = await _a.wait_for(_wait_for_grant(client, tr_c), timeout=20)
- except _a.TimeoutError:
+ except TimeoutError:
moved = False
_line(moved, "raising the per-member cap started what was waiting on it")
failures += not moved
@@ -526,7 +524,7 @@ async def probe(args) -> int:
try:
seen.append(await alice.recv_type("transfer_state",
timeout=15))
- except asyncio.TimeoutError:
+ except TimeoutError:
break
promoted = [m for m in seen if m.get("state") == "granted"]
ok = bool(promoted)