login.py
1 import os 2 import json 3 import argparse 4 import getpass 5 from typing import Dict, Any, Optional 6 7 import sys 8 sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) 9 10 from src.identity_manager import SeedDeriver, EnvoyIdentityTree 11 from cryptography.hazmat.primitives import serialization 12 13 class UserRegistry: 14 def __init__(self, repo_path: str): 15 self.repo_path = repo_path 16 self.registry_path = os.path.join(repo_path, "envoy", "registry", "users.json") 17 os.makedirs(os.path.dirname(self.registry_path), exist_ok=True) 18 self._ensure_registry() 19 20 def _ensure_registry(self): 21 if not os.path.exists(self.registry_path): 22 with open(self.registry_path, "w") as f: 23 json.dump({"users": []}, f, indent=2) 24 25 def register_or_update_user(self, user_id: str, public_key_hex: str, roles: list = ["member"]) -> None: 26 with open(self.registry_path, "r") as f: 27 data = json.load(f) 28 29 found = False 30 for user in data["users"]: 31 if user["user_id"] == user_id: 32 user.update({ 33 "public_key": public_key_hex, 34 "roles": roles, 35 "status": "active" 36 }) 37 found = True 38 break 39 40 if not found: 41 data["users"].append({ 42 "user_id": user_id, 43 "public_key": public_key_hex, 44 "roles": roles, 45 "status": "active" 46 }) 47 48 with open(self.registry_path, "w") as f: 49 json.dump(data, f, indent=2) 50 51 def login(): 52 print("=== ENVOY V4 Identity Recovery ===") 53 print("Enter your 10-12 word ENVOY recovery phrase.") 54 # In a real CLI, we'd hide the input. For testing, we'll use input() or getpass() 55 phrase = input("Phrase: ").strip() 56 57 words = phrase.split() 58 if len(words) not in [10, 11, 12]: 59 print(f"Warning: Phrase has {len(words)} words. Proceeding anyway...") 60 61 print("\n[1] Deriving Root Seed (This takes a moment for security...)") 62 root_seed = SeedDeriver.derive_root_seed(phrase) 63 64 print("[2] Regenerating Key Tree...") 65 tree = EnvoyIdentityTree(root_seed) 66 67 # Core Identity 68 envoy_priv = tree.get_envoy_identity() 69 pub_bytes = envoy_priv.public_key().public_bytes( 70 encoding=serialization.Encoding.Raw, 71 format=serialization.PublicFormat.Raw 72 ) 73 user_id = tree.get_user_id() 74 75 # Radicle 76 rad_priv = tree.get_radicle_key() 77 # IRC 78 irc_priv, irc_nick = tree.get_irc_identity() 79 # Age Encryption 80 age_raw = tree.export_age_identity() 81 82 print("\n=== Recovery Successful ===") 83 print(f"User ID: {user_id}") 84 print(f"IRC Nick: {irc_nick}") 85 print(f"Age Key: {age_raw[:16]}... (hidden)") 86 87 # Phase 8: Register User 88 print("\n[3] Synchronizing with Registry...") 89 # Point to the operational repository 90 repo_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) 91 network_repo_path = os.path.join(repo_root, "envoy-network-alpha") 92 registry = UserRegistry(network_repo_path) 93 94 registry.register_or_update_user(user_id, pub_bytes.hex()) 95 print("User securely registered in envoy/registry/users.json") 96 print("You are now fully authenticated as this identity.") 97 98 if __name__ == "__main__": 99 login()