/ src / login.py
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()