SiteManagerPlugin.py 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. import logging, json, os, re, sys, time, socket
  2. from Plugin import PluginManager
  3. from Config import config
  4. from Debug import Debug
  5. from http.client import HTTPSConnection, HTTPConnection, HTTPException
  6. from base64 import b64encode
  7. allow_reload = False # No reload supported
  8. @PluginManager.registerTo("SiteManager")
  9. class SiteManagerPlugin(object):
  10. def load(self, *args, **kwargs):
  11. super(SiteManagerPlugin, self).load(*args, **kwargs)
  12. self.log = logging.getLogger("ZeronetLocal Plugin")
  13. self.error_message = None
  14. if not config.namecoin_host or not config.namecoin_rpcport or not config.namecoin_rpcuser or not config.namecoin_rpcpassword:
  15. self.error_message = "Missing parameters"
  16. self.log.error("Missing parameters to connect to namecoin node. Please check all the arguments needed with '--help'. Zeronet will continue working without it.")
  17. return
  18. url = "%(host)s:%(port)s" % {"host": config.namecoin_host, "port": config.namecoin_rpcport}
  19. self.c = HTTPConnection(url, timeout=3)
  20. user_pass = "%(user)s:%(password)s" % {"user": config.namecoin_rpcuser, "password": config.namecoin_rpcpassword}
  21. userAndPass = b64encode(bytes(user_pass, "utf-8")).decode("ascii")
  22. self.headers = {"Authorization" : "Basic %s" % userAndPass, "Content-Type": " application/json " }
  23. payload = json.dumps({
  24. "jsonrpc": "2.0",
  25. "id": "zeronet",
  26. "method": "ping",
  27. "params": []
  28. })
  29. try:
  30. self.c.request("POST", "/", payload, headers=self.headers)
  31. response = self.c.getresponse()
  32. data = response.read()
  33. self.c.close()
  34. if response.status == 200:
  35. result = json.loads(data.decode())["result"]
  36. else:
  37. raise Exception(response.reason)
  38. except Exception as err:
  39. self.log.error("The Namecoin node is unreachable. Please check the configuration value are correct. Zeronet will continue working without it.")
  40. self.error_message = err
  41. self.cache = dict()
  42. # Checks if it's a valid address
  43. def isAddress(self, address):
  44. return self.isBitDomain(address) or super(SiteManagerPlugin, self).isAddress(address)
  45. # Return: True if the address is domain
  46. def isDomain(self, address):
  47. return self.isBitDomain(address) or super(SiteManagerPlugin, self).isDomain(address)
  48. # Return: True if the address is .bit domain
  49. def isBitDomain(self, address):
  50. return re.match(r"(.*?)([A-Za-z0-9_-]+\.bit)$", address)
  51. # Return: Site object or None if not found
  52. def get(self, address):
  53. if self.isBitDomain(address): # Its looks like a domain
  54. address_resolved = self.resolveDomain(address)
  55. if address_resolved: # Domain found
  56. site = self.sites.get(address_resolved)
  57. if site:
  58. site_domain = site.settings.get("domain")
  59. if site_domain != address:
  60. site.settings["domain"] = address
  61. else: # Domain not found
  62. site = self.sites.get(address)
  63. else: # Access by site address
  64. site = super(SiteManagerPlugin, self).get(address)
  65. return site
  66. # Return or create site and start download site files
  67. # Return: Site or None if dns resolve failed
  68. def need(self, address, *args, **kwargs):
  69. if self.isBitDomain(address): # Its looks like a domain
  70. address_resolved = self.resolveDomain(address)
  71. if address_resolved:
  72. address = address_resolved
  73. else:
  74. return None
  75. return super(SiteManagerPlugin, self).need(address, *args, **kwargs)
  76. # Resolve domain
  77. # Return: The address or None
  78. def resolveDomain(self, domain):
  79. domain = domain.lower()
  80. #remove .bit on end
  81. if domain[-4:] == ".bit":
  82. domain = domain[0:-4]
  83. domain_array = domain.split(".")
  84. if self.error_message:
  85. self.log.error("Not able to connect to Namecoin node : {!s}".format(self.error_message))
  86. return None
  87. if len(domain_array) > 2:
  88. self.log.error("Too many subdomains! Can only handle one level (eg. staging.mixtape.bit)")
  89. return None
  90. subdomain = ""
  91. if len(domain_array) == 1:
  92. domain = domain_array[0]
  93. else:
  94. subdomain = domain_array[0]
  95. domain = domain_array[1]
  96. if domain in self.cache:
  97. delta = time.time() - self.cache[domain]["time"]
  98. if delta < 3600:
  99. # Must have been less than 1hour
  100. return self.cache[domain]["addresses_resolved"][subdomain]
  101. payload = json.dumps({
  102. "jsonrpc": "2.0",
  103. "id": "zeronet",
  104. "method": "name_show",
  105. "params": ["d/"+domain]
  106. })
  107. try:
  108. self.c.request("POST", "/", payload, headers=self.headers)
  109. response = self.c.getresponse()
  110. data = response.read()
  111. self.c.close()
  112. domain_object = json.loads(data.decode())["result"]
  113. except Exception as err:
  114. #domain doesn't exist
  115. return None
  116. if "zeronet" in domain_object["value"]:
  117. zeronet_domains = json.loads(domain_object["value"])["zeronet"]
  118. if isinstance(zeronet_domains, str):
  119. # {
  120. # "zeronet":"19rXKeKptSdQ9qt7omwN82smehzTuuq6S9"
  121. # } is valid
  122. zeronet_domains = {"": zeronet_domains}
  123. self.cache[domain] = {"addresses_resolved": zeronet_domains, "time": time.time()}
  124. elif "map" in domain_object["value"]:
  125. # Namecoin standard use {"map": { "blog": {"zeronet": "1D..."} }}
  126. data_map = json.loads(domain_object["value"])["map"]
  127. zeronet_domains = dict()
  128. for subdomain in data_map:
  129. if "zeronet" in data_map[subdomain]:
  130. zeronet_domains[subdomain] = data_map[subdomain]["zeronet"]
  131. if "zeronet" in data_map and isinstance(data_map["zeronet"], str):
  132. # {"map":{
  133. # "zeronet":"19rXKeKptSdQ9qt7omwN82smehzTuuq6S9",
  134. # }}
  135. zeronet_domains[""] = data_map["zeronet"]
  136. self.cache[domain] = {"addresses_resolved": zeronet_domains, "time": time.time()}
  137. else:
  138. # No Zeronet address registered
  139. return None
  140. return self.cache[domain]["addresses_resolved"][subdomain]
  141. @PluginManager.registerTo("ConfigPlugin")
  142. class ConfigPlugin(object):
  143. def createArguments(self):
  144. group = self.parser.add_argument_group("Zeroname Local plugin")
  145. group.add_argument('--namecoin_host', help="Host to namecoin node (eg. 127.0.0.1)")
  146. group.add_argument('--namecoin_rpcport', help="Port to connect (eg. 8336)")
  147. group.add_argument('--namecoin_rpcuser', help="RPC user to connect to the namecoin node (eg. nofish)")
  148. group.add_argument('--namecoin_rpcpassword', help="RPC password to connect to namecoin node")
  149. return super(ConfigPlugin, self).createArguments()