import re import html import copy import os import gevent from Plugin import PluginManager from Translate import Translate plugin_dir = os.path.dirname(__file__) if "_" not in locals(): _ = Translate(plugin_dir + "/languages/") def getCorsPath(site, inner_path): match = re.match("^cors-([A-Za-z0-9]{26,35})/(.*)", inner_path) if not match: raise Exception("Invalid cors path: %s" % inner_path) cors_address = match.group(1) cors_inner_path = match.group(2) if not "Cors:%s" % cors_address in site.settings["permissions"]: raise Exception("This site has no permission to access site %s" % cors_address) return cors_address, cors_inner_path @PluginManager.registerTo("UiWebsocket") class UiWebsocketPlugin(object): def hasSitePermission(self, address, cmd=None): if super(UiWebsocketPlugin, self).hasSitePermission(address, cmd=cmd): return True allowed_commands = [ "fileGet", "fileList", "dirList", "fileRules", "optionalFileInfo", "fileQuery", "dbQuery", "userGetSettings", "siteInfo" ] if not "Cors:%s" % address in self.site.settings["permissions"] or cmd not in allowed_commands: return False else: return True # Add cors support for file commands def corsFuncWrapper(self, func_name, to, inner_path, *args, **kwargs): if inner_path.startswith("cors-"): cors_address, cors_inner_path = getCorsPath(self.site, inner_path) req_self = copy.copy(self) req_self.site = self.server.sites.get(cors_address) # Change the site to the merged one if not req_self.site: return {"error": "No site found"} func = getattr(super(UiWebsocketPlugin, req_self), func_name) back = func(to, cors_inner_path, *args, **kwargs) return back else: func = getattr(super(UiWebsocketPlugin, self), func_name) return func(to, inner_path, *args, **kwargs) def actionFileGet(self, to, inner_path, *args, **kwargs): return self.corsFuncWrapper("actionFileGet", to, inner_path, *args, **kwargs) def actionFileList(self, to, inner_path, *args, **kwargs): return self.corsFuncWrapper("actionFileList", to, inner_path, *args, **kwargs) def actionDirList(self, to, inner_path, *args, **kwargs): return self.corsFuncWrapper("actionDirList", to, inner_path, *args, **kwargs) def actionFileRules(self, to, inner_path, *args, **kwargs): return self.corsFuncWrapper("actionFileRules", to, inner_path, *args, **kwargs) def actionOptionalFileInfo(self, to, inner_path, *args, **kwargs): return self.corsFuncWrapper("actionOptionalFileInfo", to, inner_path, *args, **kwargs) def actionCorsPermission(self, to, address): if isinstance(address, list): addresses = address else: addresses = [address] button_title = _["Grant"] site_names = [] site_addresses = [] for address in addresses: site = self.server.sites.get(address) if site: site_name = site.content_manager.contents.get("content.json", {}).get("title", address) else: site_name = address # If at least one site is not downloaded yet, show "Grant & Add" instead button_title = _["Grant & Add"] if not (site and "Cors:" + address in self.permissions): # No site or no permission site_names.append(site_name) site_addresses.append(address) if len(site_names) == 0: return "ignored" self.cmd( "confirm", [_["This site requests read permission to: %s"] % ", ".join(map(html.escape, site_names)), button_title], lambda res: self.cbCorsPermission(to, site_addresses) ) def cbCorsPermission(self, to, addresses): # Add permissions for address in addresses: permission = "Cors:" + address if permission not in self.site.settings["permissions"]: self.site.settings["permissions"].append(permission) self.site.saveSettings() self.site.updateWebsocket(permission_added=permission) self.response(to, "ok") for address in addresses: site = self.server.sites.get(address) if not site: gevent.spawn(self.server.site_manager.need, address) @PluginManager.registerTo("UiRequest") class UiRequestPlugin(object): # Allow to load cross origin files using /cors-address/file.jpg def parsePath(self, path): path_parts = super(UiRequestPlugin, self).parsePath(path) if "cors-" not in path: # Optimization return path_parts site = self.server.sites[path_parts["address"]] try: path_parts["address"], path_parts["inner_path"] = getCorsPath(site, path_parts["inner_path"]) except Exception: return None return path_parts