Merge pull request #215 from caryoscelus/no-local-zeroname
No local zeroname refs #23
This commit is contained in:
commit
62f14371bd
6 changed files with 0 additions and 411 deletions
|
@ -1,153 +0,0 @@
|
||||||
import logging, json, os, re, sys, time
|
|
||||||
import gevent
|
|
||||||
from Plugin import PluginManager
|
|
||||||
from Config import config
|
|
||||||
from util import Http
|
|
||||||
from Debug import Debug
|
|
||||||
|
|
||||||
allow_reload = False # No reload supported
|
|
||||||
|
|
||||||
log = logging.getLogger("DnschainPlugin")
|
|
||||||
|
|
||||||
@PluginManager.registerTo("SiteManager")
|
|
||||||
class SiteManagerPlugin(object):
|
|
||||||
dns_cache_path = "%s/dns_cache.json" % config.data_dir
|
|
||||||
dns_cache = None
|
|
||||||
|
|
||||||
# Checks if its a valid address
|
|
||||||
def isAddress(self, address):
|
|
||||||
if self.isDomain(address):
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return super(SiteManagerPlugin, self).isAddress(address)
|
|
||||||
|
|
||||||
|
|
||||||
# Return: True if the address is domain
|
|
||||||
def isDomain(self, address):
|
|
||||||
return re.match(r"(.*?)([A-Za-z0-9_-]+\.[A-Za-z0-9]+)$", address)
|
|
||||||
|
|
||||||
|
|
||||||
# Load dns entries from data/dns_cache.json
|
|
||||||
def loadDnsCache(self):
|
|
||||||
if os.path.isfile(self.dns_cache_path):
|
|
||||||
self.dns_cache = json.load(open(self.dns_cache_path))
|
|
||||||
else:
|
|
||||||
self.dns_cache = {}
|
|
||||||
log.debug("Loaded dns cache, entries: %s" % len(self.dns_cache))
|
|
||||||
|
|
||||||
|
|
||||||
# Save dns entries to data/dns_cache.json
|
|
||||||
def saveDnsCache(self):
|
|
||||||
json.dump(self.dns_cache, open(self.dns_cache_path, "wb"), indent=2)
|
|
||||||
|
|
||||||
|
|
||||||
# Resolve domain using dnschain.net
|
|
||||||
# Return: The address or None
|
|
||||||
def resolveDomainDnschainNet(self, domain):
|
|
||||||
try:
|
|
||||||
match = self.isDomain(domain)
|
|
||||||
sub_domain = match.group(1).strip(".")
|
|
||||||
top_domain = match.group(2)
|
|
||||||
if not sub_domain: sub_domain = "@"
|
|
||||||
address = None
|
|
||||||
with gevent.Timeout(5, Exception("Timeout: 5s")):
|
|
||||||
res = Http.get("https://api.dnschain.net/v1/namecoin/key/%s" % top_domain).read()
|
|
||||||
data = json.loads(res)["data"]["value"]
|
|
||||||
if "zeronet" in data:
|
|
||||||
for key, val in data["zeronet"].items():
|
|
||||||
self.dns_cache[key+"."+top_domain] = [val, time.time()+60*60*5] # Cache for 5 hours
|
|
||||||
self.saveDnsCache()
|
|
||||||
return data["zeronet"].get(sub_domain)
|
|
||||||
# Not found
|
|
||||||
return address
|
|
||||||
except Exception as err:
|
|
||||||
log.debug("Dnschain.net %s resolve error: %s" % (domain, Debug.formatException(err)))
|
|
||||||
|
|
||||||
|
|
||||||
# Resolve domain using dnschain.info
|
|
||||||
# Return: The address or None
|
|
||||||
def resolveDomainDnschainInfo(self, domain):
|
|
||||||
try:
|
|
||||||
match = self.isDomain(domain)
|
|
||||||
sub_domain = match.group(1).strip(".")
|
|
||||||
top_domain = match.group(2)
|
|
||||||
if not sub_domain: sub_domain = "@"
|
|
||||||
address = None
|
|
||||||
with gevent.Timeout(5, Exception("Timeout: 5s")):
|
|
||||||
res = Http.get("https://dnschain.info/bit/d/%s" % re.sub(r"\.bit$", "", top_domain)).read()
|
|
||||||
data = json.loads(res)["value"]
|
|
||||||
for key, val in data["zeronet"].items():
|
|
||||||
self.dns_cache[key+"."+top_domain] = [val, time.time()+60*60*5] # Cache for 5 hours
|
|
||||||
self.saveDnsCache()
|
|
||||||
return data["zeronet"].get(sub_domain)
|
|
||||||
# Not found
|
|
||||||
return address
|
|
||||||
except Exception as err:
|
|
||||||
log.debug("Dnschain.info %s resolve error: %s" % (domain, Debug.formatException(err)))
|
|
||||||
|
|
||||||
|
|
||||||
# Resolve domain
|
|
||||||
# Return: The address or None
|
|
||||||
def resolveDomain(self, domain):
|
|
||||||
domain = domain.lower()
|
|
||||||
if self.dns_cache == None:
|
|
||||||
self.loadDnsCache()
|
|
||||||
if domain.count(".") < 2: # Its a topleved request, prepend @. to it
|
|
||||||
domain = "@."+domain
|
|
||||||
|
|
||||||
domain_details = self.dns_cache.get(domain)
|
|
||||||
if domain_details and time.time() < domain_details[1]: # Found in cache and its not expired
|
|
||||||
return domain_details[0]
|
|
||||||
else:
|
|
||||||
# Resovle dns using dnschain
|
|
||||||
thread_dnschain_info = gevent.spawn(self.resolveDomainDnschainInfo, domain)
|
|
||||||
thread_dnschain_net = gevent.spawn(self.resolveDomainDnschainNet, domain)
|
|
||||||
gevent.joinall([thread_dnschain_net, thread_dnschain_info]) # Wait for finish
|
|
||||||
|
|
||||||
if thread_dnschain_info.value and thread_dnschain_net.value: # Booth successfull
|
|
||||||
if thread_dnschain_info.value == thread_dnschain_net.value: # Same returned value
|
|
||||||
return thread_dnschain_info.value
|
|
||||||
else:
|
|
||||||
log.error("Dns %s missmatch: %s != %s" % (domain, thread_dnschain_info.value, thread_dnschain_net.value))
|
|
||||||
|
|
||||||
# Problem during resolve
|
|
||||||
if domain_details: # Resolve failed, but we have it in the cache
|
|
||||||
domain_details[1] = time.time()+60*60 # Dont try again for 1 hour
|
|
||||||
return domain_details[0]
|
|
||||||
else: # Not found in cache
|
|
||||||
self.dns_cache[domain] = [None, time.time()+60] # Don't check again for 1 min
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
# Return or create site and start download site files
|
|
||||||
# Return: Site or None if dns resolve failed
|
|
||||||
def need(self, address, all_file=True):
|
|
||||||
if self.isDomain(address): # Its looks like a domain
|
|
||||||
address_resolved = self.resolveDomain(address)
|
|
||||||
if address_resolved:
|
|
||||||
address = address_resolved
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
return super(SiteManagerPlugin, self).need(address, all_file)
|
|
||||||
|
|
||||||
|
|
||||||
# Return: Site object or None if not found
|
|
||||||
def get(self, address):
|
|
||||||
if self.sites == None: # Not loaded yet
|
|
||||||
self.load()
|
|
||||||
if self.isDomain(address): # Its looks like a domain
|
|
||||||
address_resolved = self.resolveDomain(address)
|
|
||||||
if address_resolved: # Domain found
|
|
||||||
site = self.sites.get(address_resolved)
|
|
||||||
if site:
|
|
||||||
site_domain = site.settings.get("domain")
|
|
||||||
if site_domain != address:
|
|
||||||
site.settings["domain"] = address
|
|
||||||
else: # Domain not found
|
|
||||||
site = self.sites.get(address)
|
|
||||||
|
|
||||||
else: # Access by site address
|
|
||||||
site = self.sites.get(address)
|
|
||||||
return site
|
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
import re
|
|
||||||
from Plugin import PluginManager
|
|
||||||
|
|
||||||
@PluginManager.registerTo("UiRequest")
|
|
||||||
class UiRequestPlugin(object):
|
|
||||||
def __init__(self, server = None):
|
|
||||||
from Site import SiteManager
|
|
||||||
self.site_manager = SiteManager.site_manager
|
|
||||||
super(UiRequestPlugin, self).__init__(server)
|
|
||||||
|
|
||||||
|
|
||||||
# Media request
|
|
||||||
def actionSiteMedia(self, path):
|
|
||||||
match = re.match(r"/media/(?P<address>[A-Za-z0-9-]+\.[A-Za-z0-9\.-]+)(?P<inner_path>/.*|$)", path)
|
|
||||||
if match: # Its a valid domain, resolve first
|
|
||||||
domain = match.group("address")
|
|
||||||
address = self.site_manager.resolveDomain(domain)
|
|
||||||
if address:
|
|
||||||
path = "/media/"+address+match.group("inner_path")
|
|
||||||
return super(UiRequestPlugin, self).actionSiteMedia(path) # Get the wrapper frame output
|
|
||||||
|
|
||||||
|
|
||||||
# Is mediarequest allowed from that referer
|
|
||||||
def isMediaRequestAllowed(self, site_address, referer):
|
|
||||||
referer_path = re.sub("http[s]{0,1}://.*?/", "/", referer).replace("/media", "") # Remove site address
|
|
||||||
referer_site_address = re.match(r"/(?P<address>[A-Za-z0-9\.-]+)(?P<inner_path>/.*|$)", referer_path).group("address")
|
|
||||||
|
|
||||||
if referer_site_address == site_address: # Referer site address as simple address
|
|
||||||
return True
|
|
||||||
elif self.site_manager.resolveDomain(referer_site_address) == site_address: # Referer site address as dns
|
|
||||||
return True
|
|
||||||
else: # Invalid referer
|
|
||||||
return False
|
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
# This plugin is experimental, if you really want to enable uncomment the following lines:
|
|
||||||
# import DnschainPlugin
|
|
||||||
# import SiteManagerPlugin
|
|
|
@ -1,180 +0,0 @@
|
||||||
import logging, json, os, re, sys, time, socket
|
|
||||||
from Plugin import PluginManager
|
|
||||||
from Config import config
|
|
||||||
from Debug import Debug
|
|
||||||
from http.client import HTTPSConnection, HTTPConnection, HTTPException
|
|
||||||
from base64 import b64encode
|
|
||||||
|
|
||||||
allow_reload = False # No reload supported
|
|
||||||
|
|
||||||
@PluginManager.registerTo("SiteManager")
|
|
||||||
class SiteManagerPlugin(object):
|
|
||||||
def load(self, *args, **kwargs):
|
|
||||||
super(SiteManagerPlugin, self).load(*args, **kwargs)
|
|
||||||
self.log = logging.getLogger("ZeronetLocal Plugin")
|
|
||||||
self.error_message = None
|
|
||||||
if not config.namecoin_host or not config.namecoin_rpcport or not config.namecoin_rpcuser or not config.namecoin_rpcpassword:
|
|
||||||
self.error_message = "Missing parameters"
|
|
||||||
self.log.error("Missing parameters to connect to namecoin node. Please check all the arguments needed with '--help'. Zeronet will continue working without it.")
|
|
||||||
return
|
|
||||||
|
|
||||||
url = "%(host)s:%(port)s" % {"host": config.namecoin_host, "port": config.namecoin_rpcport}
|
|
||||||
self.c = HTTPConnection(url, timeout=3)
|
|
||||||
user_pass = "%(user)s:%(password)s" % {"user": config.namecoin_rpcuser, "password": config.namecoin_rpcpassword}
|
|
||||||
userAndPass = b64encode(bytes(user_pass, "utf-8")).decode("ascii")
|
|
||||||
self.headers = {"Authorization" : "Basic %s" % userAndPass, "Content-Type": " application/json " }
|
|
||||||
|
|
||||||
payload = json.dumps({
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"id": "zeronet",
|
|
||||||
"method": "ping",
|
|
||||||
"params": []
|
|
||||||
})
|
|
||||||
|
|
||||||
try:
|
|
||||||
self.c.request("POST", "/", payload, headers=self.headers)
|
|
||||||
response = self.c.getresponse()
|
|
||||||
data = response.read()
|
|
||||||
self.c.close()
|
|
||||||
if response.status == 200:
|
|
||||||
result = json.loads(data.decode())["result"]
|
|
||||||
else:
|
|
||||||
raise Exception(response.reason)
|
|
||||||
except Exception as err:
|
|
||||||
self.log.error("The Namecoin node is unreachable. Please check the configuration value are correct. Zeronet will continue working without it.")
|
|
||||||
self.error_message = err
|
|
||||||
self.cache = dict()
|
|
||||||
|
|
||||||
# Checks if it's a valid address
|
|
||||||
def isAddress(self, address):
|
|
||||||
return self.isBitDomain(address) or super(SiteManagerPlugin, self).isAddress(address)
|
|
||||||
|
|
||||||
# Return: True if the address is domain
|
|
||||||
def isDomain(self, address):
|
|
||||||
return self.isBitDomain(address) or super(SiteManagerPlugin, self).isDomain(address)
|
|
||||||
|
|
||||||
# Return: True if the address is .bit domain
|
|
||||||
def isBitDomain(self, address):
|
|
||||||
return re.match(r"(.*?)([A-Za-z0-9_-]+\.bit)$", address)
|
|
||||||
|
|
||||||
# Return: Site object or None if not found
|
|
||||||
def get(self, address):
|
|
||||||
if self.isBitDomain(address): # Its looks like a domain
|
|
||||||
address_resolved = self.resolveDomain(address)
|
|
||||||
if address_resolved: # Domain found
|
|
||||||
site = self.sites.get(address_resolved)
|
|
||||||
if site:
|
|
||||||
site_domain = site.settings.get("domain")
|
|
||||||
if site_domain != address:
|
|
||||||
site.settings["domain"] = address
|
|
||||||
else: # Domain not found
|
|
||||||
site = self.sites.get(address)
|
|
||||||
|
|
||||||
else: # Access by site address
|
|
||||||
site = super(SiteManagerPlugin, self).get(address)
|
|
||||||
return site
|
|
||||||
|
|
||||||
# Return or create site and start download site files
|
|
||||||
# Return: Site or None if dns resolve failed
|
|
||||||
def need(self, address, *args, **kwargs):
|
|
||||||
if self.isBitDomain(address): # Its looks like a domain
|
|
||||||
address_resolved = self.resolveDomain(address)
|
|
||||||
if address_resolved:
|
|
||||||
address = address_resolved
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
return super(SiteManagerPlugin, self).need(address, *args, **kwargs)
|
|
||||||
|
|
||||||
# Resolve domain
|
|
||||||
# Return: The address or None
|
|
||||||
def resolveDomain(self, domain):
|
|
||||||
domain = domain.lower()
|
|
||||||
|
|
||||||
#remove .bit on end
|
|
||||||
if domain[-4:] == ".bit":
|
|
||||||
domain = domain[0:-4]
|
|
||||||
|
|
||||||
domain_array = domain.split(".")
|
|
||||||
|
|
||||||
if self.error_message:
|
|
||||||
self.log.error("Not able to connect to Namecoin node : {!s}".format(self.error_message))
|
|
||||||
return None
|
|
||||||
|
|
||||||
if len(domain_array) > 2:
|
|
||||||
self.log.error("Too many subdomains! Can only handle one level (eg. staging.mixtape.bit)")
|
|
||||||
return None
|
|
||||||
|
|
||||||
subdomain = ""
|
|
||||||
if len(domain_array) == 1:
|
|
||||||
domain = domain_array[0]
|
|
||||||
else:
|
|
||||||
subdomain = domain_array[0]
|
|
||||||
domain = domain_array[1]
|
|
||||||
|
|
||||||
if domain in self.cache:
|
|
||||||
delta = time.time() - self.cache[domain]["time"]
|
|
||||||
if delta < 3600:
|
|
||||||
# Must have been less than 1hour
|
|
||||||
return self.cache[domain]["addresses_resolved"][subdomain]
|
|
||||||
|
|
||||||
payload = json.dumps({
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"id": "zeronet",
|
|
||||||
"method": "name_show",
|
|
||||||
"params": ["d/"+domain]
|
|
||||||
})
|
|
||||||
|
|
||||||
try:
|
|
||||||
self.c.request("POST", "/", payload, headers=self.headers)
|
|
||||||
response = self.c.getresponse()
|
|
||||||
data = response.read()
|
|
||||||
self.c.close()
|
|
||||||
domain_object = json.loads(data.decode())["result"]
|
|
||||||
except Exception as err:
|
|
||||||
#domain doesn't exist
|
|
||||||
return None
|
|
||||||
|
|
||||||
if "zeronet" in domain_object["value"]:
|
|
||||||
zeronet_domains = json.loads(domain_object["value"])["zeronet"]
|
|
||||||
|
|
||||||
if isinstance(zeronet_domains, str):
|
|
||||||
# {
|
|
||||||
# "zeronet":"19rXKeKptSdQ9qt7omwN82smehzTuuq6S9"
|
|
||||||
# } is valid
|
|
||||||
zeronet_domains = {"": zeronet_domains}
|
|
||||||
|
|
||||||
self.cache[domain] = {"addresses_resolved": zeronet_domains, "time": time.time()}
|
|
||||||
|
|
||||||
elif "map" in domain_object["value"]:
|
|
||||||
# Namecoin standard use {"map": { "blog": {"zeronet": "1D..."} }}
|
|
||||||
data_map = json.loads(domain_object["value"])["map"]
|
|
||||||
|
|
||||||
zeronet_domains = dict()
|
|
||||||
for subdomain in data_map:
|
|
||||||
if "zeronet" in data_map[subdomain]:
|
|
||||||
zeronet_domains[subdomain] = data_map[subdomain]["zeronet"]
|
|
||||||
if "zeronet" in data_map and isinstance(data_map["zeronet"], str):
|
|
||||||
# {"map":{
|
|
||||||
# "zeronet":"19rXKeKptSdQ9qt7omwN82smehzTuuq6S9",
|
|
||||||
# }}
|
|
||||||
zeronet_domains[""] = data_map["zeronet"]
|
|
||||||
|
|
||||||
self.cache[domain] = {"addresses_resolved": zeronet_domains, "time": time.time()}
|
|
||||||
|
|
||||||
else:
|
|
||||||
# No Zeronet address registered
|
|
||||||
return None
|
|
||||||
|
|
||||||
return self.cache[domain]["addresses_resolved"][subdomain]
|
|
||||||
|
|
||||||
@PluginManager.registerTo("ConfigPlugin")
|
|
||||||
class ConfigPlugin(object):
|
|
||||||
def createArguments(self):
|
|
||||||
group = self.parser.add_argument_group("Zeroname Local plugin")
|
|
||||||
group.add_argument('--namecoin_host', help="Host to namecoin node (eg. 127.0.0.1)")
|
|
||||||
group.add_argument('--namecoin_rpcport', help="Port to connect (eg. 8336)")
|
|
||||||
group.add_argument('--namecoin_rpcuser', help="RPC user to connect to the namecoin node (eg. nofish)")
|
|
||||||
group.add_argument('--namecoin_rpcpassword', help="RPC password to connect to namecoin node")
|
|
||||||
|
|
||||||
return super(ConfigPlugin, self).createArguments()
|
|
|
@ -1,39 +0,0 @@
|
||||||
import re
|
|
||||||
from Plugin import PluginManager
|
|
||||||
|
|
||||||
@PluginManager.registerTo("UiRequest")
|
|
||||||
class UiRequestPlugin(object):
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
from Site import SiteManager
|
|
||||||
self.site_manager = SiteManager.site_manager
|
|
||||||
super(UiRequestPlugin, self).__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
# Media request
|
|
||||||
def actionSiteMedia(self, path):
|
|
||||||
match = re.match(r"/media/(?P<address>[A-Za-z0-9-]+\.[A-Za-z0-9\.-]+)(?P<inner_path>/.*|$)", path)
|
|
||||||
if match: # Its a valid domain, resolve first
|
|
||||||
domain = match.group("address")
|
|
||||||
address = self.site_manager.resolveDomain(domain)
|
|
||||||
if address:
|
|
||||||
path = "/media/"+address+match.group("inner_path")
|
|
||||||
return super(UiRequestPlugin, self).actionSiteMedia(path) # Get the wrapper frame output
|
|
||||||
|
|
||||||
|
|
||||||
# Is mediarequest allowed from that referer
|
|
||||||
def isMediaRequestAllowed(self, site_address, referer):
|
|
||||||
referer_path = re.sub("http[s]{0,1}://.*?/", "/", referer).replace("/media", "") # Remove site address
|
|
||||||
referer_path = re.sub(r"\?.*", "", referer_path) # Remove http params
|
|
||||||
|
|
||||||
if self.isProxyRequest(): # Match to site domain
|
|
||||||
referer = re.sub("^http://zero[/]+", "http://", referer) # Allow /zero access
|
|
||||||
referer_site_address = re.match("http[s]{0,1}://(.*?)(/|$)", referer).group(1)
|
|
||||||
else: # Match to request path
|
|
||||||
referer_site_address = re.match(r"/(?P<address>[A-Za-z0-9\.-]+)(?P<inner_path>/.*|$)", referer_path).group("address")
|
|
||||||
|
|
||||||
if referer_site_address == site_address: # Referer site address as simple address
|
|
||||||
return True
|
|
||||||
elif self.site_manager.resolveDomain(referer_site_address) == site_address: # Referer site address as dns
|
|
||||||
return True
|
|
||||||
else: # Invalid referer
|
|
||||||
return False
|
|
|
@ -1,2 +0,0 @@
|
||||||
from . import UiRequestPlugin
|
|
||||||
from . import SiteManagerPlugin
|
|
Loading…
Reference in a new issue