diff --git a/plugins/Sidebar/SidebarPlugin.py b/plugins/Sidebar/SidebarPlugin.py index bde16359..d3490cd4 100644 --- a/plugins/Sidebar/SidebarPlugin.py +++ b/plugins/Sidebar/SidebarPlugin.py @@ -143,7 +143,7 @@ class UiWebsocketPlugin(object): size = size_filetypes.get(extension, 0) size_other -= size percent = 100 * (float(size) / size_total) - body.append("<li style='width: %.0f%%' class='html back-%s' title='%s'></li>" % (percent, color, extension)) + body.append("<li style='width: %.2f%%' class='%s back-%s' title='%s'></li>" % (percent, extension, color, extension)) # Legend body.append("</ul><ul class='graph-legend'>") diff --git a/plugins/Trayicon/TrayiconPlugin.py b/plugins/Trayicon/TrayiconPlugin.py index 6aec34a1..6579612c 100644 --- a/plugins/Trayicon/TrayiconPlugin.py +++ b/plugins/Trayicon/TrayiconPlugin.py @@ -19,8 +19,10 @@ class ActionsPlugin(object): self.main = sys.modules["main"] + fs_encoding = sys.getfilesystemencoding() + icon = notificationicon.NotificationIcon( - os.path.join(os.path.dirname(os.path.abspath(__file__)), 'trayicon.ico'), + os.path.join(os.path.dirname(os.path.abspath(__file__).decode(fs_encoding)), 'trayicon.ico'), "ZeroNet %s" % config.version ) self.icon = icon diff --git a/plugins/disabled-Multiuser/MultiuserPlugin.py b/plugins/disabled-Multiuser/MultiuserPlugin.py index 850a0995..9d65fac8 100644 --- a/plugins/disabled-Multiuser/MultiuserPlugin.py +++ b/plugins/disabled-Multiuser/MultiuserPlugin.py @@ -1,169 +1,171 @@ -import re, time, sys +import re +import sys from Plugin import PluginManager -from Crypt import CryptBitcoin + @PluginManager.registerTo("UiRequest") class UiRequestPlugin(object): - def __init__(self, *args, **kwargs): - self.user_manager = sys.modules["User.UserManager"].user_manager - super(UiRequestPlugin, self).__init__(*args, **kwargs) + def __init__(self, *args, **kwargs): + self.user_manager = sys.modules["User.UserManager"].user_manager + super(UiRequestPlugin, self).__init__(*args, **kwargs) + # Create new user and inject user welcome message if necessary + # Return: Html body also containing the injection + def actionWrapper(self, path, extra_headers=None): - # Create new user and inject user welcome message if necessary - # Return: Html body also containing the injection - def actionWrapper(self, path): - user_created = False - user = self.getCurrentUser() # Get user from cookie + match = re.match("/(?P<address>[A-Za-z0-9\._-]+)(?P<inner_path>/.*|$)", path) + if not match: + return False + inner_path = match.group("inner_path").lstrip("/") + html_request = "." not in inner_path or inner_path.endswith(".html") # Only inject html to html requests - if not user: # No user found by cookie - user = self.user_manager.create() - user_created = True + user_created = False + if html_request: + user = self.getCurrentUser() # Get user from cookie + if not user: # No user found by cookie + user = self.user_manager.create() + user_created = True - master_address = user.master_address - master_seed = user.master_seed + if user_created: + if not extra_headers: + extra_headers = [] + extra_headers.append(('Set-Cookie', "master_address=%s;path=/;max-age=2592000;" % user.master_address)) # = 30 days - if user_created: - extra_headers = [('Set-Cookie', "master_address=%s;path=/;max-age=2592000;" % user.master_address)] # Max age = 30 days - else: - extra_headers = [] + loggedin = self.get.get("login") == "done" - loggedin = self.get.get("login") == "done" + back_generator = super(UiRequestPlugin, self).actionWrapper(path, extra_headers) # Get the wrapper frame output - back = super(UiRequestPlugin, self).actionWrapper(path, extra_headers) # Get the wrapper frame output + if not back_generator: # Wrapper error or not string returned, injection not possible + return False - if not user_created and not loggedin: return back # No injection necessary + if user_created: + back = back_generator.next() + master_seed = user.master_seed + # Inject the welcome message + inject_html = """ + <!-- Multiser plugin --> + <style> + .masterseed { font-size: 95%; background-color: #FFF0AD; padding: 5px 8px; margin: 9px 0px } + </style> + <script> + hello_message = "<b>Hello, welcome to ZeroProxy!</b><div style='margin-top: 8px'>A new, unique account created for you:</div>" + hello_message+= "<div class='masterseed'>{master_seed}</div> <div>This is your private key, <b>save it</b>, so you can login next time.</div><br>" + hello_message+= "<a href='#' class='button' style='margin-left: 0px'>Ok, Saved it!</a> or <a href='#Login' onclick='wrapper.ws.cmd(\\"userLoginForm\\", []); return false'>Login</a><br><br>" + hello_message+= "<small>This site is allows you to browse ZeroNet content, but if you want to secure your account <br>" + hello_message+= "and help to make a better network, then please run your own <a href='https://github.com/HelloZeroNet/ZeroNet' target='_blank'>ZeroNet client</a>.</small>" + setTimeout(function() { + wrapper.notifications.add("hello", "info", hello_message) + delete(hello_message) + }, 1000) + </script> + </body> + </html> + """.replace("\t", "") + inject_html = inject_html.replace("{master_seed}", master_seed) # Set the master seed in the message - if not back or not hasattr(back, "endswith"): return back # Wrapper error or not string returned, injection not possible + return iter([re.sub("</body>\s*</html>\s*$", inject_html, back)]) # Replace the </body></html> tags with the injection - if user_created: - # Inject the welcome message - inject_html = """ - <!-- Multiser plugin --> - <style> - .masterseed { font-size: 95%; background-color: #FFF0AD; padding: 5px 8px; margin: 9px 0px } - </style> - <script> - hello_message = "<b>Hello, welcome to ZeroProxy!</b><div style='margin-top: 8px'>A new, unique account created for you:</div>" - hello_message+= "<div class='masterseed'>{master_seed}</div> <div>This is your private key, <b>save it</b>, so you can login next time.</div><br>" - hello_message+= "<a href='#' class='button' style='margin-left: 0px'>Ok, Saved it!</a> or <a href='#Login' onclick='wrapper.ws.cmd(\\"userLoginForm\\", []); return false'>Login</a><br><br>" - hello_message+= "<small>This site is allows you to browse ZeroNet content, but if you want to secure your account <br>" - hello_message+= "and help to make a better network, then please run your own <a href='https://github.com/HelloZeroNet/ZeroNet' target='_blank'>ZeroNet client</a>.</small>" - setTimeout(function() { - wrapper.notifications.add("hello", "info", hello_message) - delete(hello_message) - }, 1000) - </script> - </body> - </html> - """.replace("\t", "") - inject_html = inject_html.replace("{master_seed}", master_seed) # Set the master seed in the message + elif loggedin: + back = back_generator.next() + inject_html = """ + <!-- Multiser plugin --> + <script> + setTimeout(function() { + wrapper.notifications.add("login", "done", "Hello again!<br><small>You have been logged in successfully</small>", 5000) + }, 1000) + </script> + </body> + </html> + """.replace("\t", "") + return iter([re.sub("</body>\s*</html>\s*$", inject_html, back)]) # Replace the </body></html> tags with the injection - back = re.sub("</body>\s*</html>\s*$", inject_html, back) # Replace the </body></html> tags with the injection + else: # No injection necessary + return back_generator - elif loggedin: - inject_html = """ - <!-- Multiser plugin --> - <script> - setTimeout(function() { - wrapper.notifications.add("login", "done", "Hello again!<br><small>You have been logged in successfully</small>", 5000) - }, 1000) - </script> - </body> - </html> - """.replace("\t", "") - back = re.sub("</body>\s*</html>\s*$", inject_html, back) # Replace the </body></html> tags with the injection - - return back - - - # Get the current user based on request's cookies - # Return: User object or None if no match - def getCurrentUser(self): - cookies = self.getCookies() - user_manager = self.user_manager - user = None - if "master_address" in cookies: - users = self.user_manager.list() - user = users.get(cookies["master_address"]) - return user + # Get the current user based on request's cookies + # Return: User object or None if no match + def getCurrentUser(self): + cookies = self.getCookies() + user = None + if "master_address" in cookies: + users = self.user_manager.list() + user = users.get(cookies["master_address"]) + return user @PluginManager.registerTo("UserManager") class UserManagerPlugin(object): - # In multiuser mode do not load the users - def load(self): - if not self.users: self.users = {} - return self.users + # In multiuser mode do not load the users + def load(self): + if not self.users: + self.users = {} + return self.users - - # Find user by master address - # Return: User or None - def get(self, master_address=None): - users = self.list() - if master_address in users: - user = users[master_address] - else: - user = None - return user + # Find user by master address + # Return: User or None + def get(self, master_address=None): + users = self.list() + if master_address in users: + user = users[master_address] + else: + user = None + return user @PluginManager.registerTo("User") class UserPlugin(object): - # In multiuser mode users data only exits in memory, dont write to data/user.json - def save(self): - return False - + # In multiuser mode users data only exits in memory, dont write to data/user.json + def save(self): + return False + @PluginManager.registerTo("UiWebsocket") class UiWebsocketPlugin(object): - # Let the page know we running in multiuser mode - def formatServerInfo(self): - server_info = super(UiWebsocketPlugin, self).formatServerInfo() - server_info["multiuser"] = True - if "ADMIN" in self.site.settings["permissions"]: - server_info["master_address"] = self.user.master_address - return server_info + # Let the page know we running in multiuser mode + def formatServerInfo(self): + server_info = super(UiWebsocketPlugin, self).formatServerInfo() + server_info["multiuser"] = True + if "ADMIN" in self.site.settings["permissions"]: + server_info["master_address"] = self.user.master_address + return server_info + # Show current user's master seed + def actionUserShowMasterSeed(self, to): + if "ADMIN" not in self.site.settings["permissions"]: + return self.response(to, "Show master seed not allowed") + message = "<b style='padding-top: 5px; display: inline-block'>Your unique private key:</b>" + message += "<div style='font-size: 84%%; background-color: #FFF0AD; padding: 5px 8px; margin: 9px 0px'>%s</div>" % self.user.master_seed + message += "<small>(Save it, you can access your account using this information)</small>" + self.cmd("notification", ["info", message]) - # Show current user's master seed - def actionUserShowMasterSeed(self, to): - if not "ADMIN" in self.site.settings["permissions"]: return self.response(to, "Show master seed not allowed") - message = "<b style='padding-top: 5px; display: inline-block'>Your unique private key:</b>" - message+= "<div style='font-size: 84%%; background-color: #FFF0AD; padding: 5px 8px; margin: 9px 0px'>%s</div>" % self.user.master_seed - message+= "<small>(Save it, you can access your account using this information)</small>" - self.cmd("notification", ["info", message]) + # Logout user + def actionUserLogout(self, to): + if "ADMIN" not in self.site.settings["permissions"]: + return self.response(to, "Logout not allowed") + message = "<b>You have been logged out.</b> <a href='#Login' class='button' onclick='wrapper.ws.cmd(\"userLoginForm\", []); return false'>Login to another account</a>" + message += "<script>document.cookie = 'master_address=; expires=Thu, 01 Jan 1970 00:00:00 UTC'</script>" + self.cmd("notification", ["done", message, 1000000]) # 1000000 = Show ~forever :) + # Delete from user_manager + user_manager = sys.modules["User.UserManager"].user_manager + if self.user.master_address in user_manager.users: + del user_manager.users[self.user.master_address] + self.response(to, "Successful logout") + else: + self.response(to, "User not found") + # Show login form + def actionUserLoginForm(self, to): + self.cmd("prompt", ["<b>Login</b><br>Your private key:", "password", "Login"], self.responseUserLogin) - # Logout user - def actionUserLogout(self, to): - if not "ADMIN" in self.site.settings["permissions"]: return self.response(to, "Logout not allowed") - message = "<b>You have been logged out.</b> <a href='#Login' class='button' onclick='wrapper.ws.cmd(\"userLoginForm\", []); return false'>Login to another account</a>" - message+= "<script>document.cookie = 'master_address=; expires=Thu, 01 Jan 1970 00:00:00 UTC'</script>" - self.cmd("notification", ["done", message, 1000000]) # 1000000 = Show ~forever :) - # Delete from user_manager - user_manager = sys.modules["User.UserManager"].user_manager - if self.user.master_address in user_manager.users: - del user_manager.users[self.user.master_address] - self.response(to, "Successful logout") - else: - self.response(to, "User not found") - - - # Show login form - def actionUserLoginForm(self, to): - self.cmd("prompt", ["<b>Login</b><br>Your private key:", "password", "Login"], self.responseUserLogin) - - - # Login form submit - def responseUserLogin(self, master_seed): - user_manager = sys.modules["User.UserManager"].user_manager - user = user_manager.create(master_seed=master_seed) - if user.master_address: - message = "Successfull login, reloading page..." - message+= "<script>document.cookie = 'master_address=%s;path=/;max-age=2592000;'</script>" % user.master_address - message+= "<script>wrapper.reload('login=done')</script>" - self.cmd("notification", ["done", message]) - else: - self.cmd("notification", ["error", "Error: Invalid master seed"]) - self.actionUserLoginForm(0) - + # Login form submit + def responseUserLogin(self, master_seed): + user_manager = sys.modules["User.UserManager"].user_manager + user = user_manager.create(master_seed=master_seed) + if user.master_address: + message = "Successfull login, reloading page..." + message += "<script>document.cookie = 'master_address=%s;path=/;max-age=2592000;'</script>" % user.master_address + message += "<script>wrapper.reload('login=done')</script>" + self.cmd("notification", ["done", message]) + else: + self.cmd("notification", ["error", "Error: Invalid master seed"]) + self.actionUserLoginForm(0) diff --git a/src/Config.py b/src/Config.py index 43b756cb..45419a26 100644 --- a/src/Config.py +++ b/src/Config.py @@ -8,7 +8,7 @@ class Config(object): def __init__(self, argv): self.version = "0.3.2" - self.rev = 360 + self.rev = 377 self.argv = argv self.action = None self.createParser() diff --git a/src/Crypt/CryptConnection.py b/src/Crypt/CryptConnection.py index cf990ff3..7a6e7401 100644 --- a/src/Crypt/CryptConnection.py +++ b/src/Crypt/CryptConnection.py @@ -110,4 +110,4 @@ class CryptConnectionManager: return False -manager = CryptConnectionManager() +manager = CryptConnectionManager() \ No newline at end of file diff --git a/src/Debug/DebugMedia.py b/src/Debug/DebugMedia.py index 24dc3222..8f3b23bb 100644 --- a/src/Debug/DebugMedia.py +++ b/src/Debug/DebugMedia.py @@ -108,4 +108,4 @@ if __name__ == "__main__": logging.getLogger().setLevel(logging.DEBUG) os.chdir("..") config.coffeescript_compiler = r'type "%s" | tools\coffee-node\bin\node.exe tools\coffee-node\bin\coffee --no-header -s -p' - merge("data/12Hw8rTgzrNo4DSh2AkqwPRqDyTticwJyH/js/all.js") + merge("data/12Hw8rTgzrNo4DSh2AkqwPRqDyTticwJyH/js/all.js") \ No newline at end of file diff --git a/src/Site/Site.py b/src/Site/Site.py index c7830f06..cdee33a0 100644 --- a/src/Site/Site.py +++ b/src/Site/Site.py @@ -312,10 +312,19 @@ class Site: # Update content.json on peers @util.Noparallel() def publish(self, limit=5, inner_path="content.json"): - self.log.info("Publishing to %s/%s peers..." % (min(len(self.peers), limit), len(self.peers))) published = [] # Successfully published (Peer) publishers = [] # Publisher threads - peers = self.peers.values() + + connected_peers = self.getConnectedPeers() + if len(connected_peers) > limit * 2: # Publish to already connected peers if possible + peers = connected_peers + else: + peers = self.peers.values() + + self.log.info("Publishing to %s/%s peers (connected: %s)..." % ( + min(len(self.peers), limit), len(self.peers), len(connected_peers) + )) + if not peers: return 0 # No peers found @@ -336,13 +345,15 @@ class Site: peer for peer in peers if peer.connection and not peer.connection.closed and peer.key.endswith(":0") and peer not in published ] # Every connected passive peer that we not published to - for peer in passive_peers: - gevent.spawn(self.publisher, inner_path, passive_peers, published, limit=10) self.log.info( "Successfuly published to %s peers, publishing to %s more passive peers" % (len(published), len(passive_peers)) ) + + for peer in passive_peers: + gevent.spawn(self.publisher, inner_path, passive_peers, published, limit=10) + return len(published) # Copy this site @@ -664,6 +675,9 @@ class Site: return found + def getConnectedPeers(self): + return [peer for peer in self.peers.values() if peer.connection and peer.connection.connected] + # Cleanup probably dead peers def cleanupPeers(self): peers = self.peers.values() diff --git a/src/Site/SiteStorage.py b/src/Site/SiteStorage.py index 4e73839c..4292267a 100644 --- a/src/Site/SiteStorage.py +++ b/src/Site/SiteStorage.py @@ -3,6 +3,7 @@ import re import shutil import json import time +import sys import sqlite3 import gevent.event @@ -16,7 +17,9 @@ class SiteStorage: def __init__(self, site, allow_create=True): self.site = site + self.fs_encoding = sys.getfilesystemencoding() self.directory = "%s/%s" % (config.data_dir, self.site.address) # Site data diretory + self.allowed_dir = os.path.abspath(self.directory) # Only serve/modify file within this dir self.log = site.log self.db = None # Db class self.db_checked = False # Checked db tables since startup @@ -204,10 +207,10 @@ class SiteStorage: def getPath(self, inner_path): inner_path = inner_path.replace("\\", "/") # Windows separator fix inner_path = re.sub("^%s/" % re.escape(self.directory), "", inner_path) # Remove site directory if begins with it - file_path = self.directory + "/" + inner_path - allowed_dir = os.path.abspath(self.directory) # Only files within this directory allowed - if ".." in file_path or not os.path.dirname(os.path.abspath(file_path)).startswith(allowed_dir): - raise Exception("File not allowed: %s" % file_path) + file_path = u"%s/%s" % (self.directory, inner_path) + file_abspath = os.path.dirname(os.path.abspath(file_path)) + if ".." in file_path or not file_abspath.startswith(self.allowed_dir): + raise Exception(u"File not allowed: %s" % file_path) return file_path # Get site dir relative path diff --git a/src/Ui/UiRequest.py b/src/Ui/UiRequest.py index bf29472b..52f6a42a 100644 --- a/src/Ui/UiRequest.py +++ b/src/Ui/UiRequest.py @@ -131,6 +131,7 @@ class UiRequest(object): content_type = "text/html; charset=utf-8" headers = [] headers.append(("Version", "HTTP/1.1")) + headers.append(("Connection", "Keep-Alive")) headers.append(("Access-Control-Allow-Origin", "*")) # Allow json access if self.env["REQUEST_METHOD"] == "OPTIONS": # Allow json access @@ -414,8 +415,8 @@ class UiRequest(object): yield "He" time.sleep(1) yield "llo!" - yield "Running websockets: %s" % len(self.server.websockets) - self.server.sendMessage("Hello!") + # yield "Running websockets: %s" % len(self.server.websockets) + # self.server.sendMessage("Hello!") # - Errors - diff --git a/src/lib/cssvendor/cssvendor.py b/src/lib/cssvendor/cssvendor.py index 49da87fb..3545f59c 100644 --- a/src/lib/cssvendor/cssvendor.py +++ b/src/lib/cssvendor/cssvendor.py @@ -8,7 +8,7 @@ def prefix(content): ) content = re.sub( '([^-\*])(border-radius|box-shadow|appearance|transition|animation|box-sizing|' + - 'transform|filter|perspective|animation-[a-z-]+): (.*?)([;}])', + 'backface-visibility|transform|filter|perspective|animation-[a-z-]+): (.*?)([;}])', '\\1-webkit-\\2: \\3; -moz-\\2: \\3; -o-\\2: \\3; -ms-\\2: \\3; \\2: \\3 \\4', content ) content = re.sub(