import re import sys import json from Config import config from Plugin import PluginManager from Crypt import CryptBitcoin import UserPlugin try: local_master_addresses = set(json.load(open("%s/users.json" % config.data_dir)).keys()) # Users in users.json except Exception, err: local_master_addresses = set() @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) # Create new user and inject user welcome message if necessary # Return: Html body also containing the injection def actionWrapper(self, path, extra_headers=None): match = re.match("/(?P
[A-Za-z0-9\._-]+)(?P/.*|$)", 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 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 else: user = None # Disable new site creation if --multiuser_no_new_sites enabled if config.multiuser_no_new_sites: path_parts = self.parsePath(path) if not self.server.site_manager.get(match.group("address")) and (not user or user.master_address not in local_master_addresses): self.sendHeader(404) return self.formatError("Not Found", "Adding new sites disabled on this proxy", details=False) if user_created: if not extra_headers: extra_headers = {} extra_headers['Set-Cookie'] = "master_address=%s;path=/;max-age=2592000;" % user.master_address # = 30 days loggedin = self.get.get("login") == "done" back_generator = 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 elif loggedin: back = back_generator.next() inject_html = """ """.replace("\t", "") if user.master_address in local_master_addresses: message = "Hello master!" else: message = "Hello again!" inject_html = inject_html.replace("{message}", message) inject_html = inject_html.replace("{script_nonce}", self.getScriptNonce()) return iter([re.sub("\s*\s*$", inject_html, back)]) # Replace the tags with the injection else: # No injection necessary return back_generator # 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("UiWebsocket") class UiWebsocketPlugin(object): def __init__(self, *args, **kwargs): self.multiuser_denied_cmds = ( "sitePause", "siteResume", "siteDelete", "configSet", "serverShutdown", "serverUpdate", "siteClone", "siteSetOwned", "siteSetAutodownloadoptional", "dbReload", "dbRebuild", "mergerSiteDelete", "siteSetLimit", "siteSetAutodownloadBigfileLimit", "optionalLimitSet", "optionalHelp", "optionalHelpRemove", "optionalHelpAll", "optionalFilePin", "optionalFileUnpin", "optionalFileDelete", "muteAdd", "muteRemove", "siteblockAdd", "siteblockRemove", "filterIncludeAdd", "filterIncludeRemove" ) if config.multiuser_no_new_sites: self.multiuser_denied_cmds += ("mergerSiteAdd", ) super(UiWebsocketPlugin, self).__init__(*args, **kwargs) # 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 = "Your unique private key:" message += "
%s
" % self.user.master_seed message += "(Save it, you can access your account using this information)" 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 = "You have been logged out. Login to another account" self.cmd("notification", ["done", message, 1000000]) # 1000000 = Show ~forever :) script = "document.cookie = 'master_address=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/';" script += "$('#button_notification').on('click', function() { zeroframe.cmd(\"userLoginForm\", []); });" self.cmd("injectScript", script) # Delete from user_manager user_manager = sys.modules["User.UserManager"].user_manager if self.user.master_address in user_manager.users: if not config.multiuser_local: 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", ["Login
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.get(CryptBitcoin.privatekeyToAddress(master_seed)) if not user: user = user_manager.create(master_seed=master_seed) if user.master_address: script = "document.cookie = 'master_address=%s;path=/;max-age=2592000;';" % user.master_address script += "zeroframe.cmd('wrapperReload', ['login=done']);" self.cmd("notification", ["done", "Successful login, reloading page..."]) self.cmd("injectScript", script) else: self.cmd("notification", ["error", "Error: Invalid master seed"]) self.actionUserLoginForm(0) def hasCmdPermission(self, cmd): cmd = cmd[0].lower() + cmd[1:] if not config.multiuser_local and self.user.master_address not in local_master_addresses and cmd in self.multiuser_denied_cmds: self.cmd("notification", ["info", "This function is disabled on this proxy!"]) return False else: return super(UiWebsocketPlugin, self).hasCmdPermission(cmd) def actionCertAdd(self, *args, **kwargs): super(UiWebsocketPlugin, self).actionCertAdd(*args, **kwargs) master_seed = self.user.master_seed message = """ Hello, welcome to ZeroProxy!
A new, unique account created for you:
or Download backup as text file
This is your private key, save it, so you can login next time.
Warning: Without this key, your account will be lost forever!

Ok, Saved it!

This site allows you to browse ZeroNet content, but if you want to secure your account
and help to keep the network alive, then please run your own ZeroNet client.
""" self.cmd("notification", ["info", message]) script = """ $("#button_notification_masterseed").on("click", function() { this.value = "{master_seed}"; this.setSelectionRange(0,100); }) $("#button_notification_download").on("mousedown", function() { this.href = window.URL.createObjectURL(new Blob(["ZeroNet user master seed:\\r\\n{master_seed}"])) }) """.replace("{master_seed}", master_seed) self.cmd("injectScript", script) def actionPermissionAdd(self, to, permission): if permission == "NOSANDBOX": self.cmd("notification", ["info", "You can't disable sandbox on this proxy!"]) self.response(to, {"error": "Denied by proxy"}) return False else: return super(UiWebsocketPlugin, self).actionPermissionAdd(to, permission) @PluginManager.registerTo("ConfigPlugin") class ConfigPlugin(object): def createArguments(self): group = self.parser.add_argument_group("Multiuser plugin") group.add_argument('--multiuser_local', help="Enable unsafe Ui functions and write users to disk", action='store_true') group.add_argument('--multiuser_no_new_sites', help="Denies adding new sites by normal users", action='store_true') return super(ConfigPlugin, self).createArguments()