aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-node/src/meshbay_node/transport/quic_client.py
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-node/src/meshbay_node/transport/quic_client.py')
-rw-r--r--packages/meshbay-node/src/meshbay_node/transport/quic_client.py52
1 files changed, 23 insertions, 29 deletions
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 9102085..4debd27 100644
--- a/packages/meshbay-node/src/meshbay_node/transport/quic_client.py
+++ b/packages/meshbay-node/src/meshbay_node/transport/quic_client.py
@@ -15,7 +15,6 @@ import os
import struct
from pathlib import Path
-import blake3
import jwt
import msgpack
from aioquic.asyncio import connect, QuicConnectionProtocol
@@ -24,9 +23,7 @@ from aioquic.quic.events import QuicEvent, StreamDataReceived
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
from meshbay_common import MNP_VERSION
-from meshbay_common.crypto import verify_chunk_signature
-from meshbay_common.webcrypto import chunk_key_aes as derive_chunk_key, decrypt_chunk_aes as decrypt_chunk
-from meshbay_common.protocol import MNP
+from meshbay_common.protocol import MNP, file_chunk_plaintext
from meshbay_common.handshake import (
NONCE_LEN,
ROLE_CLIENT,
@@ -252,15 +249,28 @@ class QuicChunkClient:
stream_id = self._proto._quic.get_next_available_stream_id(is_unidirectional=False)
return stream_id
- async def fetch_index(self) -> bytes:
- """Request the Mesh Group Index."""
+ async def fetch_index(self) -> dict:
+ """
+ Request the Mesh Group Index.
+
+ Returns the message itself — `{group_id, version, entries, dirs, roots}` —
+ which is what the WebRTC client has always received. It used to return the
+ bytes of a `GroupIndex.serialize()` envelope for the caller to deserialize:
+ the same message type carrying a different encoding on this transport alone.
+ """
sid = self._new_stream()
self._proto._send(sid, {"type": MNP.INDEX_SYNC, "v": MNP_VERSION})
- msg = await self._proto._recv(sid)
- return base64.b64decode(msg["index_b64"])
+ return await self._proto._recv(sid)
async def fetch_chunk(self, file_id: str, chunk_index: int) -> bytes:
- """Fetch, verify, and decrypt one chunk over QUIC."""
+ """
+ Fetch and decrypt one chunk over QUIC.
+
+ The per-chunk Ed25519 signature this used to verify is gone (see
+ `meshbay_common.protocol`): the AEAD tag authenticates the ciphertext under a
+ GEK-derived key, and the node proved its identity in the handshake — which
+ `connect()` verified and pinned — rather than once per megabyte.
+ """
sid = self._new_stream()
self._proto._send(sid, {
"type": MNP.FILE_REQUEST,
@@ -273,26 +283,10 @@ class QuicChunkClient:
if msg.get("type") == "error":
raise LookupError(msg.get("detail", "Unknown error"))
- ct = base64.b64decode(msg["ct_b64"])
- nonce = base64.b64decode(msg["nonce_b64"])
- ct_hash = base64.b64decode(msg["ct_hash_b64"])
- pt_hash = base64.b64decode(msg["pt_hash_b64"])
- sig = base64.b64decode(msg["sig_b64"])
- file_hash = base64.b64decode(msg["file_hash_b64"])
- ci = msg["chunk_index"]
-
- verify_chunk_signature(self._pk_node, ci, nonce, ct_hash, sig)
-
- if blake3.blake3(ct).digest() != ct_hash:
- raise ValueError("Ciphertext hash mismatch")
-
- ckey = derive_chunk_key(self._gek, file_hash, ci)
- plaintext = decrypt_chunk(ckey, nonce, ct)
-
- if blake3.blake3(plaintext).digest() != pt_hash:
- raise ValueError("Plaintext hash mismatch after decryption")
-
- return plaintext
+ # From the id we asked for, not the one the answer claims: a peer that
+ # substitutes it would otherwise choose which key we decrypt with.
+ return file_chunk_plaintext(
+ self._gek, msg, file_hash=bytes.fromhex(file_id))
async def fetch_stream_segment(
self, file_id: str, segment_index: int, segment_duration: int = 4,