ZeroNet/src/User/User.py

177 lines
6.7 KiB
Python
Raw Normal View History

import logging
import json
import time
import binascii
import gevent
2017-04-01 22:31:38 +02:00
import util
from Crypt import CryptBitcoin
from Plugin import PluginManager
from Config import config
from util import helper
2019-03-15 21:06:59 +01:00
from Debug import Debug
@PluginManager.acceptPlugins
class User(object):
2015-06-17 23:34:54 +02:00
def __init__(self, master_address=None, master_seed=None, data={}):
if master_seed:
self.master_seed = master_seed
self.master_address = CryptBitcoin.privatekeyToAddress(self.master_seed)
elif master_address:
self.master_address = master_address
self.master_seed = data.get("master_seed")
else:
self.master_seed = CryptBitcoin.newSeed()
self.master_address = CryptBitcoin.privatekeyToAddress(self.master_seed)
self.sites = data.get("sites", {})
self.certs = data.get("certs", {})
2018-10-20 02:28:58 +02:00
self.settings = data.get("settings", {})
2018-04-12 19:25:13 +02:00
self.delayed_save_thread = None
2015-06-17 23:34:54 +02:00
self.log = logging.getLogger("User:%s" % self.master_address)
# Save to data/users.json
2017-04-01 22:31:38 +02:00
@util.Noparallel(queue=True, ignore_class=True)
2015-06-17 23:34:54 +02:00
def save(self):
s = time.time()
2015-06-17 23:34:54 +02:00
users = json.load(open("%s/users.json" % config.data_dir))
if self.master_address not in users:
users[self.master_address] = {} # Create if not exist
user_data = users[self.master_address]
if self.master_seed:
user_data["master_seed"] = self.master_seed
2015-06-17 23:34:54 +02:00
user_data["sites"] = self.sites
user_data["certs"] = self.certs
2018-10-20 02:28:58 +02:00
user_data["settings"] = self.settings
2019-03-15 23:56:16 +01:00
helper.atomicWrite("%s/users.json" % config.data_dir, json.dumps(users, indent=2, sort_keys=True).encode("utf8"))
2018-04-12 19:25:13 +02:00
self.log.debug("Saved in %.3fs" % (time.time() - s))
self.delayed_save_thread = None
def saveDelayed(self):
if not self.delayed_save_thread:
self.delayed_save_thread = gevent.spawn_later(5, self.save)
2015-06-17 23:34:54 +02:00
def getAddressAuthIndex(self, address):
return int(binascii.hexlify(address.encode()), 16)
2015-06-17 23:34:54 +02:00
@util.Noparallel()
def generateAuthAddress(self, address):
s = time.time()
address_id = self.getAddressAuthIndex(address) # Convert site address to int
auth_privatekey = CryptBitcoin.hdPrivatekey(self.master_seed, address_id)
self.sites[address] = {
"auth_address": CryptBitcoin.privatekeyToAddress(auth_privatekey),
"auth_privatekey": auth_privatekey
}
self.saveDelayed()
self.log.debug("Added new site: %s in %.3fs" % (address, time.time() - s))
return self.sites[address]
2015-06-17 23:34:54 +02:00
# Get user site data
# Return: {"auth_address": "xxx", "auth_privatekey": "xxx"}
def getSiteData(self, address, create=True):
if address not in self.sites: # Generate new BIP32 child key based on site address
if not create:
return {"auth_address": None, "auth_privatekey": None} # Dont create user yet
self.generateAuthAddress(address)
2015-06-17 23:34:54 +02:00
return self.sites[address]
def deleteSiteData(self, address):
if address in self.sites:
del(self.sites[address])
2018-04-12 19:25:13 +02:00
self.saveDelayed()
self.log.debug("Deleted site: %s" % address)
2018-10-20 02:28:58 +02:00
def setSiteSettings(self, address, settings):
site_data = self.getSiteData(address)
site_data["settings"] = settings
2018-04-12 19:25:13 +02:00
self.saveDelayed()
return site_data
2015-06-17 23:34:54 +02:00
# Get data for a new, unique site
# Return: [site_address, bip32_index, {"auth_address": "xxx", "auth_privatekey": "xxx", "privatekey": "xxx"}]
def getNewSiteData(self):
import random
bip32_index = random.randrange(2 ** 256) % 100000000
2015-06-17 23:34:54 +02:00
site_privatekey = CryptBitcoin.hdPrivatekey(self.master_seed, bip32_index)
site_address = CryptBitcoin.privatekeyToAddress(site_privatekey)
if site_address in self.sites:
raise Exception("Random error: site exist!")
2015-06-17 23:34:54 +02:00
# Save to sites
self.getSiteData(site_address)
self.sites[site_address]["privatekey"] = site_privatekey
self.save()
2015-06-17 23:34:54 +02:00
return site_address, bip32_index, self.sites[site_address]
# Get BIP32 address from site address
# Return: BIP32 auth address
def getAuthAddress(self, address, create=True):
cert = self.getCert(address)
if cert:
return cert["auth_address"]
else:
return self.getSiteData(address, create)["auth_address"]
def getAuthPrivatekey(self, address, create=True):
cert = self.getCert(address)
if cert:
return cert["auth_privatekey"]
else:
return self.getSiteData(address, create)["auth_privatekey"]
# Add cert for the user
def addCert(self, auth_address, domain, auth_type, auth_user_name, cert_sign):
# Find privatekey by auth address
2019-03-15 21:06:59 +01:00
auth_privatekey = [site["auth_privatekey"] for site in list(self.sites.values()) if site["auth_address"] == auth_address][0]
2015-06-17 23:34:54 +02:00
cert_node = {
"auth_address": auth_address,
"auth_privatekey": auth_privatekey,
"auth_type": auth_type,
"auth_user_name": auth_user_name,
"cert_sign": cert_sign
}
# Check if we have already cert for that domain and its not the same
if self.certs.get(domain) and self.certs[domain] != cert_node:
return False
elif self.certs.get(domain) == cert_node: # Same, not updated
2015-06-17 23:34:54 +02:00
return None
else: # Not exist yet, add
2015-06-17 23:34:54 +02:00
self.certs[domain] = cert_node
self.save()
return True
# Remove cert from user
def deleteCert(self, domain):
del self.certs[domain]
# Set active cert for a site
2015-06-17 23:34:54 +02:00
def setCert(self, address, domain):
site_data = self.getSiteData(address)
if domain:
site_data["cert"] = domain
else:
if "cert" in site_data:
del site_data["cert"]
2018-04-12 19:25:13 +02:00
self.saveDelayed()
2015-06-17 23:34:54 +02:00
return site_data
# Get cert for the site address
# Return: { "auth_address":.., "auth_privatekey":.., "auth_type": "web", "auth_user_name": "nofish", "cert_sign":.. } or None
2015-06-17 23:34:54 +02:00
def getCert(self, address):
site_data = self.getSiteData(address, create=False)
if not site_data or "cert" not in site_data:
return None # Site dont have cert
2015-06-17 23:34:54 +02:00
return self.certs.get(site_data["cert"])
# Get cert user name for the site address
# Return: user@certprovider.bit or None
def getCertUserId(self, address):
site_data = self.getSiteData(address, create=False)
if not site_data or "cert" not in site_data:
return None # Site dont have cert
2015-06-17 23:34:54 +02:00
cert = self.certs.get(site_data["cert"])
if cert:
return cert["auth_user_name"] + "@" + site_data["cert"]