From cbac57dc8824a9dff4a79dcfab008bebe5cddf6f Mon Sep 17 00:00:00 2001 From: shortcutme Date: Wed, 19 Jul 2017 16:48:24 +0200 Subject: [PATCH] Plugin to request cross-site resource access --- plugins/Cors/CorsPlugin.py | 84 ++++++++++++++++++++++++++++++++++++++ plugins/Cors/__init__.py | 1 + 2 files changed, 85 insertions(+) create mode 100644 plugins/Cors/CorsPlugin.py create mode 100644 plugins/Cors/__init__.py diff --git a/plugins/Cors/CorsPlugin.py b/plugins/Cors/CorsPlugin.py new file mode 100644 index 00000000..5aa73ee1 --- /dev/null +++ b/plugins/Cors/CorsPlugin.py @@ -0,0 +1,84 @@ +import re +import cgi + +from Plugin import PluginManager +from Translate import Translate +from util import helper +from Debug import Debug +if "_" not in locals(): + _ = Translate("plugins/Cors/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): + # Add cors support for file commands + def corsFuncWrapper(self, func_name, to, inner_path, *args, **kwargs): + func = getattr(super(UiWebsocketPlugin, self), func_name) + if inner_path.startswith("cors-"): + cors_address, cors_inner_path = getCorsPath(self.site, inner_path) + + site_before = self.site # Save to be able to change it back after we ran the command + self.site = self.server.sites.get(cors_address) # Change the site to the merged one + try: + back = func(to, cors_inner_path, *args, **kwargs) + finally: + self.site = site_before # Change back to original site + return back + else: + 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 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): + site = self.server.sites.get(address) + if site: + site_name = site.content_manager.contents.get("content.json", {}).get("title") + button_title = _["Grant"] + else: + site_name = address + button_title = _["Grant & Add"] + + self.cmd( + "confirm", + [_["This site requests read permission to: %s"] % cgi.escape(site_name), button_title], + lambda (res): self.cbCorsPermission(to, address) + ) + + def cbCorsPermission(self, to, address): + self.actionPermissionAdd(to, "Cors:"+address) + site = self.server.sites.get(address) + if not site: + 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: + return None + return path_parts diff --git a/plugins/Cors/__init__.py b/plugins/Cors/__init__.py new file mode 100644 index 00000000..bca1ab3e --- /dev/null +++ b/plugins/Cors/__init__.py @@ -0,0 +1 @@ +import CorsPlugin \ No newline at end of file