Forking what is left of ZeroNet and hopefully adding an AT Proto Frontend/Proxy
at main 176 lines 6.9 kB view raw
1import logging 2import json 3import time 4import binascii 5 6import gevent 7 8import util 9from Crypt import CryptBitcoin 10from Plugin import PluginManager 11from Config import config 12from util import helper 13from Debug import Debug 14 15 16@PluginManager.acceptPlugins 17class User(object): 18 def __init__(self, master_address=None, master_seed=None, data={}): 19 if master_seed: 20 self.master_seed = master_seed 21 self.master_address = CryptBitcoin.privatekeyToAddress(self.master_seed) 22 elif master_address: 23 self.master_address = master_address 24 self.master_seed = data.get("master_seed") 25 else: 26 self.master_seed = CryptBitcoin.newSeed() 27 self.master_address = CryptBitcoin.privatekeyToAddress(self.master_seed) 28 self.sites = data.get("sites", {}) 29 self.certs = data.get("certs", {}) 30 self.settings = data.get("settings", {}) 31 self.delayed_save_thread = None 32 33 self.log = logging.getLogger("User:%s" % self.master_address) 34 35 # Save to data/users.json 36 @util.Noparallel(queue=True, ignore_class=True) 37 def save(self): 38 s = time.time() 39 users = json.load(open("%s/users.json" % config.data_dir)) 40 if self.master_address not in users: 41 users[self.master_address] = {} # Create if not exist 42 user_data = users[self.master_address] 43 if self.master_seed: 44 user_data["master_seed"] = self.master_seed 45 user_data["sites"] = self.sites 46 user_data["certs"] = self.certs 47 user_data["settings"] = self.settings 48 helper.atomicWrite("%s/users.json" % config.data_dir, helper.jsonDumps(users).encode("utf8")) 49 self.log.debug("Saved in %.3fs" % (time.time() - s)) 50 self.delayed_save_thread = None 51 52 def saveDelayed(self): 53 if not self.delayed_save_thread: 54 self.delayed_save_thread = gevent.spawn_later(5, self.save) 55 56 def getAddressAuthIndex(self, address): 57 return int(binascii.hexlify(address.encode()), 16) 58 59 @util.Noparallel() 60 def generateAuthAddress(self, address): 61 s = time.time() 62 address_id = self.getAddressAuthIndex(address) # Convert site address to int 63 auth_privatekey = CryptBitcoin.hdPrivatekey(self.master_seed, address_id) 64 self.sites[address] = { 65 "auth_address": CryptBitcoin.privatekeyToAddress(auth_privatekey), 66 "auth_privatekey": auth_privatekey 67 } 68 self.saveDelayed() 69 self.log.debug("Added new site: %s in %.3fs" % (address, time.time() - s)) 70 return self.sites[address] 71 72 # Get user site data 73 # Return: {"auth_address": "xxx", "auth_privatekey": "xxx"} 74 def getSiteData(self, address, create=True): 75 if address not in self.sites: # Generate new BIP32 child key based on site address 76 if not create: 77 return {"auth_address": None, "auth_privatekey": None} # Dont create user yet 78 self.generateAuthAddress(address) 79 return self.sites[address] 80 81 def deleteSiteData(self, address): 82 if address in self.sites: 83 del(self.sites[address]) 84 self.saveDelayed() 85 self.log.debug("Deleted site: %s" % address) 86 87 def setSiteSettings(self, address, settings): 88 site_data = self.getSiteData(address) 89 site_data["settings"] = settings 90 self.saveDelayed() 91 return site_data 92 93 # Get data for a new, unique site 94 # Return: [site_address, bip32_index, {"auth_address": "xxx", "auth_privatekey": "xxx", "privatekey": "xxx"}] 95 def getNewSiteData(self): 96 import random 97 bip32_index = random.randrange(2 ** 256) % 100000000 98 site_privatekey = CryptBitcoin.hdPrivatekey(self.master_seed, bip32_index) 99 site_address = CryptBitcoin.privatekeyToAddress(site_privatekey) 100 if site_address in self.sites: 101 raise Exception("Random error: site exist!") 102 # Save to sites 103 self.getSiteData(site_address) 104 self.sites[site_address]["privatekey"] = site_privatekey 105 self.save() 106 return site_address, bip32_index, self.sites[site_address] 107 108 # Get BIP32 address from site address 109 # Return: BIP32 auth address 110 def getAuthAddress(self, address, create=True): 111 cert = self.getCert(address) 112 if cert: 113 return cert["auth_address"] 114 else: 115 return self.getSiteData(address, create)["auth_address"] 116 117 def getAuthPrivatekey(self, address, create=True): 118 cert = self.getCert(address) 119 if cert: 120 return cert["auth_privatekey"] 121 else: 122 return self.getSiteData(address, create)["auth_privatekey"] 123 124 # Add cert for the user 125 def addCert(self, auth_address, domain, auth_type, auth_user_name, cert_sign): 126 # Find privatekey by auth address 127 auth_privatekey = [site["auth_privatekey"] for site in list(self.sites.values()) if site["auth_address"] == auth_address][0] 128 cert_node = { 129 "auth_address": auth_address, 130 "auth_privatekey": auth_privatekey, 131 "auth_type": auth_type, 132 "auth_user_name": auth_user_name, 133 "cert_sign": cert_sign 134 } 135 # Check if we have already cert for that domain and its not the same 136 if self.certs.get(domain) and self.certs[domain] != cert_node: 137 return False 138 elif self.certs.get(domain) == cert_node: # Same, not updated 139 return None 140 else: # Not exist yet, add 141 self.certs[domain] = cert_node 142 self.save() 143 return True 144 145 # Remove cert from user 146 def deleteCert(self, domain): 147 del self.certs[domain] 148 149 # Set active cert for a site 150 def setCert(self, address, domain): 151 site_data = self.getSiteData(address) 152 if domain: 153 site_data["cert"] = domain 154 else: 155 if "cert" in site_data: 156 del site_data["cert"] 157 self.saveDelayed() 158 return site_data 159 160 # Get cert for the site address 161 # Return: { "auth_address":.., "auth_privatekey":.., "auth_type": "web", "auth_user_name": "nofish", "cert_sign":.. } or None 162 def getCert(self, address): 163 site_data = self.getSiteData(address, create=False) 164 if not site_data or "cert" not in site_data: 165 return None # Site dont have cert 166 return self.certs.get(site_data["cert"]) 167 168 # Get cert user name for the site address 169 # Return: user@certprovider.bit or None 170 def getCertUserId(self, address): 171 site_data = self.getSiteData(address, create=False) 172 if not site_data or "cert" not in site_data: 173 return None # Site dont have cert 174 cert = self.certs.get(site_data["cert"]) 175 if cert: 176 return cert["auth_user_name"] + "@" + site_data["cert"]