Files
neuron-tai/packages/p2p/meshnet_p2p/identity.py
Dobromir Popov a2258d3df4 feat(us-017): P2P gossip, NAT-traversal relay node, and TLS
- packages/p2p: identity (peer_id from sha256 of RSA pubkey), TLS cert
  generation with SHA-256 fingerprint, GossipClient (WSS PubSub with
  per-topic handlers, dedup by msg_id, auto-reconnect), MdnsDiscovery
  (zeroconf optional dependency, graceful no-op fallback)
- packages/relay: new meshnet-relay package — RelayServer (asyncio +
  websockets) with gossip fanout hub, circuit relay proxy for NAT traversal,
  peer registry; meshnet-relay CLI
- packages/p2p/relay_bootstrap.json: team relay bootstrap list
- Tracker: _NodeEntry gains relay_addr, cert_fingerprint, peer_id; both
  register and heartbeat handlers read and store these optional fields
- docs/adr/0010 already written (previous commit)
- conftest.py: packages/relay added to sys.path
- 18 new tests; 115 passed total, 1 skipped (no regressions)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 17:58:16 +03:00

65 lines
1.9 KiB
Python

"""Peer identity — stable peer_id and RSA keypair, persisted to disk."""
from __future__ import annotations
import hashlib
import json
import os
import stat
from pathlib import Path
_DEFAULT_IDENTITY_PATH = Path.home() / ".config" / "meshnet" / "identity.json"
def _generate_keypair() -> tuple[bytes, bytes]:
"""Return (private_key_pem, public_key_pem) for a new RSA-2048 keypair."""
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import serialization
key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
priv_pem = key.private_bytes(
serialization.Encoding.PEM,
serialization.PrivateFormat.PKCS8,
serialization.NoEncryption(),
)
pub_pem = key.public_key().public_bytes(
serialization.Encoding.PEM,
serialization.PublicFormat.SubjectPublicKeyInfo,
)
return priv_pem, pub_pem
def _peer_id_from_pubkey(pub_pem: bytes) -> str:
return hashlib.sha256(pub_pem).hexdigest()[:16]
def load_or_create_identity(path: Path | None = None) -> dict:
"""Return identity dict with peer_id, private_key_pem, public_key_pem.
Creates and persists a new identity if none exists at path.
"""
p = path or _DEFAULT_IDENTITY_PATH
if p.exists():
try:
data = json.loads(p.read_text())
if "peer_id" in data and "public_key_pem" in data:
return data
except (json.JSONDecodeError, OSError):
pass
priv_pem, pub_pem = _generate_keypair()
identity = {
"peer_id": _peer_id_from_pubkey(pub_pem),
"private_key_pem": priv_pem.decode(),
"public_key_pem": pub_pem.decode(),
}
p.parent.mkdir(parents=True, exist_ok=True)
p.write_text(json.dumps(identity, indent=2))
try:
os.chmod(p, stat.S_IRUSR | stat.S_IWUSR)
except OSError:
pass
return identity