From 8d5a72f0b5e329eac640f20792c59cbdf8a56296 Mon Sep 17 00:00:00 2001
From: HelloZeroNet <hello@noloop.me>
Date: Mon, 20 Apr 2015 02:56:33 +0200
Subject: [PATCH] rev110, Support for 127.0.0.1:43110-less Chrome plugin,
 Namecoin updater ignores invalid characters in address, Every site's
 favicon.ico leads to main favicon to prevent 404 request when using chrome
 extension, Detect chrome extension proxy requests, Use wrapper=False instead
 of /media, 404errormessage fix

---
 README.md                                    |  4 +--
 plugins/Stats/StatsPlugin.py                 |  1 +
 plugins/Zeroname/UiRequestPlugin.py          | 10 ++++--
 plugins/Zeroname/updater/zeroname_updater.py |  4 ++-
 src/Config.py                                |  2 +-
 src/Ui/UiRequest.py                          | 37 +++++++++++++++-----
 src/Ui/media/Wrapper.coffee                  |  5 ++-
 src/Ui/media/all.js                          |  9 +++--
 src/Ui/template/wrapper.html                 |  9 ++---
 9 files changed, 59 insertions(+), 22 deletions(-)

diff --git a/README.md b/README.md
index cbb412dc..d9ce9db8 100644
--- a/README.md
+++ b/README.md
@@ -35,8 +35,8 @@ Decentralized websites using Bitcoin crypto and the BitTorrent network
  * Namecoin .bit domains support
  * Easy to setup: unpack & run
  * Password-less [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) 
-   based authorization: Your account is protected by same cryptography as your bitcoin wallet
- * SQL Database support: Allows easier site development and faster page load times
+   based authorization: Your account is protected by same cryptography as your Bitcoin wallet
+ * Built-in SQL server with P2P data synchronization: Allows easier site development and faster page load times
  * Tor network support
  * Automatic, uPnP port opening
  * Plugin for multiuser (openproxy) support
diff --git a/plugins/Stats/StatsPlugin.py b/plugins/Stats/StatsPlugin.py
index 195bcc53..7aa44ab5 100644
--- a/plugins/Stats/StatsPlugin.py
+++ b/plugins/Stats/StatsPlugin.py
@@ -53,6 +53,7 @@ class UiRequestPlugin(object):
 
 		# Memory
 		try:
+			yield "rev%s | " % config.rev
 			yield "IP external: %s | " % config.ip_external
 			yield "Opened: %s | " % main.file_server.port_opened
 			yield "Recv: %.2fMB, Sent: %.2fMB  | " % (float(main.file_server.bytes_recv)/1024/1024, float(main.file_server.bytes_sent)/1024/1024)
diff --git a/plugins/Zeroname/UiRequestPlugin.py b/plugins/Zeroname/UiRequestPlugin.py
index 9be5f62d..371ab2d0 100644
--- a/plugins/Zeroname/UiRequestPlugin.py
+++ b/plugins/Zeroname/UiRequestPlugin.py
@@ -23,8 +23,14 @@ class UiRequestPlugin(object):
 	# 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("\?.*", "", referer_path) # Remove html params
-		referer_site_address = re.match("/(?P<address>[A-Za-z0-9\.]+)(?P<inner_path>/.*|$)", referer_path).group("address")
+		referer_path = re.sub("\?.*", "", referer_path) # Remove http params
+
+		if self.isProxyRequest(): # Match to site domain
+			referer = re.sub("^http://zero[/]+", "http://", referer) # Allow /zero access
+			print referer
+			referer_site_address = re.match("http[s]{0,1}://(.*?)(/|$)", referer).group(1)
+		else: # Match to request path
+			referer_site_address = re.match("/(?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
diff --git a/plugins/Zeroname/updater/zeroname_updater.py b/plugins/Zeroname/updater/zeroname_updater.py
index d3ed7f6c..30521afe 100644
--- a/plugins/Zeroname/updater/zeroname_updater.py
+++ b/plugins/Zeroname/updater/zeroname_updater.py
@@ -31,6 +31,7 @@ def processNameOp(domain, value):
 	names_raw = open(names_path, "rb").read()
 	names = json.loads(names_raw)
 	for subdomain, address in data["zeronet"].items():
+		address = re.sub("[^A-Za-z0-9]", "", address)
 		print subdomain, domain, "->", address
 		if subdomain:
 			names["%s.%s.bit" % (subdomain, domain)] = address
@@ -99,7 +100,8 @@ print "Processing block from #%s to #%s..." % (config["lastprocessed"], last_blo
 for block_id in range(config["lastprocessed"], last_block+1):
 	processBlock(block_id)
 
-# processBlock(223911) # Testing
+# processBlock(223911) # Testing zeronetwork.bit
+# processBlock(227052) # Testing brainwallets.bit
 
 while 1:
 	print "Waiting for new block",
diff --git a/src/Config.py b/src/Config.py
index fb7a3583..d4eb20df 100644
--- a/src/Config.py
+++ b/src/Config.py
@@ -4,7 +4,7 @@ import ConfigParser
 class Config(object):
 	def __init__(self):
 		self.version = "0.2.9"
-		self.rev = 107
+		self.rev = 110
 		self.parser = self.createArguments()
 		argv = sys.argv[:] # Copy command line arguments
 		argv = self.parseConfig(argv) # Add arguments from config file
diff --git a/src/Ui/UiRequest.py b/src/Ui/UiRequest.py
index dc837168..ed45096f 100644
--- a/src/Ui/UiRequest.py
+++ b/src/Ui/UiRequest.py
@@ -31,9 +31,12 @@ class UiRequest(object):
 		if config.ui_restrict and self.env['REMOTE_ADDR'] not in config.ui_restrict: # Restict Ui access by ip
 			return self.error403()
 
+		path = re.sub("^http://zero[/]+", "/", path) # Remove begining http://zero/ for chrome extension
+		path = re.sub("^http://", "/", path) # Remove begining http for chrome extension .bit access
+
 		if path == "/":
 			return self.actionIndex()
-		elif path == "/favicon.ico":
+		elif path.endswith("favicon.ico"):
 			return self.actionFile("src/Ui/media/img/favicon.ico")
 		# Media
 		elif path.startswith("/uimedia/"):
@@ -61,6 +64,11 @@ class UiRequest(object):
 					return self.error404(path)
 
 
+	# The request is proxied by chrome extension
+	def isProxyRequest(self):
+		return self.env["PATH_INFO"].startswith("http://")
+
+
 	# Get mime by filename
 	def getContentType(self, file_name):
 		content_type = mimetypes.guess_type(file_name)[0]
@@ -137,7 +145,11 @@ class UiRequest(object):
 			if "." in inner_path and not inner_path.endswith(".html"): return self.actionSiteMedia("/media"+path) # Only serve html files with frame
 			if self.env.get("HTTP_X_REQUESTED_WITH"): return self.error403("Ajax request not allowed to load wrapper") # No ajax allowed on wrapper
 
-			if not inner_path: inner_path = "index.html" # If inner path defaults to index.html
+			file_inner_path = inner_path
+			if not file_inner_path: file_inner_path = "index.html" # If inner path defaults to index.html
+
+			if not inner_path and not path.endswith("/"): inner_path = address+"/" # Fix relative resources loading if missing / end of site address
+			inner_path = re.sub(".*/(.+)", "\\1", inner_path) # Load innerframe relative to current url
 
 			site = SiteManager.site_manager.get(address)
 
@@ -158,7 +170,16 @@ class UiRequest(object):
 			body_style = ""
 			meta_tags = ""
 
-			if self.env.get("QUERY_STRING"): query_string = "?"+self.env["QUERY_STRING"]
+			if self.env.get("QUERY_STRING"): query_string = "?"+self.env["QUERY_STRING"]+"&wrapper=False"
+			else: query_string = "?wrapper=False"
+
+			if self.isProxyRequest(): # Its a remote proxy request
+				server_url = "http://%s:%s" % (self.env["SERVER_NAME"], self.env["SERVER_PORT"])
+				homepage = "http://zero/"+config.homepage
+			else: # Use relative path
+				server_url = ""
+				homepage = "/"+config.homepage
+
 			if site.content_manager.contents.get("content.json") : # Got content.json
 				content = site.content_manager.contents["content.json"]
 				if content.get("background-color"): 
@@ -167,6 +188,7 @@ class UiRequest(object):
 					meta_tags += '<meta name="viewport" id="viewport" content="%s">' % cgi.escape(content["viewport"], True)
 
 			return self.render("src/Ui/template/wrapper.html", 
+				server_url=server_url,
 				inner_path=inner_path, 
 				address=address, 
 				title=title, 
@@ -175,8 +197,8 @@ class UiRequest(object):
 				query_string=query_string,
 				wrapper_key=site.settings["wrapper_key"],
 				permissions=json.dumps(site.settings["permissions"]),
-				show_loadingscreen=json.dumps(not site.storage.isFile(inner_path)),
-				homepage=config.homepage
+				show_loadingscreen=json.dumps(not site.storage.isFile(file_inner_path)),
+				homepage=homepage
 			)
 
 		else: # Bad url
@@ -192,6 +214,7 @@ class UiRequest(object):
 	# Serve a media for site
 	def actionSiteMedia(self, path):
 		path = path.replace("/index.html/", "/") # Base Backward compatibility fix
+		if path.endswith("/"): path = path+"index.html"
 		
 		match = re.match("/media/(?P<address>[A-Za-z0-9\._-]+)/(?P<inner_path>.*)", path)
 
@@ -225,8 +248,6 @@ class UiRequest(object):
 					else:
 						self.log.debug("File not found: %s" % match.group("inner_path"))
 						return self.error404(match.group("inner_path"))
-						#self.sendHeader(404)
-						#return "Not found"
 
 		else: # Bad url
 			return self.error404(path)
@@ -351,7 +372,7 @@ class UiRequest(object):
 	# Send file not found error
 	def error404(self, path = None):
 		self.sendHeader(404)
-		return "Not Found: %s" % path
+		return "Not Found: %s" % path.encode("utf8")
 
 
 	# Internal server error
diff --git a/src/Ui/media/Wrapper.coffee b/src/Ui/media/Wrapper.coffee
index a611c745..da6db5bc 100644
--- a/src/Ui/media/Wrapper.coffee
+++ b/src/Ui/media/Wrapper.coffee
@@ -313,5 +313,8 @@ class Wrapper
 		console.log "[Wrapper]", args...
 
 
-ws_url = "ws://#{window.location.hostname}:#{window.location.port}/Websocket?wrapper_key=#{window.wrapper_key}"
+if window.server_url
+	ws_url = "ws://#{window.server_url.replace('http://', '')}/Websocket?wrapper_key=#{window.wrapper_key}"
+else
+	ws_url = "ws://#{window.location.hostname}:#{window.location.port}/Websocket?wrapper_key=#{window.wrapper_key}"
 window.wrapper = new Wrapper(ws_url)
diff --git a/src/Ui/media/all.js b/src/Ui/media/all.js
index 4389934a..53374939 100644
--- a/src/Ui/media/all.js
+++ b/src/Ui/media/all.js
@@ -737,7 +737,6 @@ jQuery.extend( jQuery.easing,
 }).call(this);
 
 
-
 /* ---- src/Ui/media/Wrapper.coffee ---- */
 
 
@@ -1165,8 +1164,12 @@ jQuery.extend( jQuery.easing,
 
   })();
 
-  ws_url = "ws://" + window.location.hostname + ":" + window.location.port + "/Websocket?wrapper_key=" + window.wrapper_key;
+  if (window.server_url) {
+    ws_url = "ws://" + (window.server_url.replace('http://', '')) + "/Websocket?wrapper_key=" + window.wrapper_key;
+  } else {
+    ws_url = "ws://" + window.location.hostname + ":" + window.location.port + "/Websocket?wrapper_key=" + window.wrapper_key;
+  }
 
   window.wrapper = new Wrapper(ws_url);
 
-}).call(this);
\ No newline at end of file
+}).call(this);
diff --git a/src/Ui/template/wrapper.html b/src/Ui/template/wrapper.html
index bc83607b..cc20d1fd 100644
--- a/src/Ui/template/wrapper.html
+++ b/src/Ui/template/wrapper.html
@@ -6,7 +6,7 @@
  <title>{title} - ZeroNet</title>
  <meta charset="utf-8">
  <meta http-equiv="content-type" content="text/html; charset=utf-8" />
- <link rel="stylesheet" href="/uimedia/all.css" />
+ <link rel="stylesheet" href="{server_url}/uimedia/all.css" />
  {meta_tags}
 </head>
 <body style="{body_style}">
@@ -19,7 +19,7 @@
 <div class='fixbutton'>
  <div class='fixbutton-text'>0</div>
  <div class='fixbutton-burger'>&#x2261;</div>
- <a class='fixbutton-bg' href="/{homepage}"></a>
+ <a class='fixbutton-bg' href="{homepage}"></a>
 </div>
 
 
@@ -40,7 +40,7 @@
 
 
 <!-- Site Iframe -->
-<iframe src='/media/{address}/{inner_path}{query_string}' id='inner-iframe' sandbox="allow-forms allow-scripts allow-top-navigation"></iframe>
+<iframe src='{inner_path}{query_string}' id='inner-iframe' sandbox="allow-forms allow-scripts allow-top-navigation"></iframe>
 
 <!-- Site info -->
 <script>address = "{address}"</script>
@@ -48,7 +48,8 @@
 <script>inner_path = "{inner_path}"</script>
 <script>permissions = {permissions}</script>
 <script>show_loadingscreen = {show_loadingscreen}</script>
-<script type="text/javascript" src="/uimedia/all.js" asyc></script>
+<script>server_url = '{server_url}'</script>
+<script type="text/javascript" src="{server_url}/uimedia/all.js" asyc></script>
 
 </body>
 </html>
\ No newline at end of file