123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222 |
- import io
- import os
- import json
- import shutil
- import time
- from Plugin import PluginManager
- from Config import config
- from Debug import Debug
- from Translate import Translate
- from util.Flag import flag
- plugin_dir = os.path.dirname(__file__)
- if "_" not in locals():
- _ = Translate(plugin_dir + "/languages/")
- # Convert non-str,int,float values to str in a dict
- def restrictDictValues(input_dict):
- allowed_types = (int, str, float)
- return {
- key: val if type(val) in allowed_types else str(val)
- for key, val in input_dict.items()
- }
- @PluginManager.registerTo("UiRequest")
- class UiRequestPlugin(object):
- def actionWrapper(self, path, extra_headers=None):
- if path.strip("/") != "Plugins":
- return super(UiRequestPlugin, self).actionWrapper(path, extra_headers)
- if not extra_headers:
- extra_headers = {}
- script_nonce = self.getScriptNonce()
- self.sendHeader(extra_headers=extra_headers, script_nonce=script_nonce)
- site = self.server.site_manager.get(config.homepage)
- return iter([super(UiRequestPlugin, self).renderWrapper(
- site, path, "uimedia/plugins/plugin_manager/plugin_manager.html",
- "Plugin Manager", extra_headers, show_loadingscreen=False, script_nonce=script_nonce
- )])
- def actionUiMedia(self, path, *args, **kwargs):
- if path.startswith("/uimedia/plugins/plugin_manager/"):
- file_path = path.replace("/uimedia/plugins/plugin_manager/", plugin_dir + "/media/")
- if config.debug and (file_path.endswith("all.js") or file_path.endswith("all.css")):
- # If debugging merge *.css to all.css and *.js to all.js
- from Debug import DebugMedia
- DebugMedia.merge(file_path)
- if file_path.endswith("js"):
- data = _.translateData(open(file_path).read(), mode="js").encode("utf8")
- elif file_path.endswith("html"):
- data = _.translateData(open(file_path).read(), mode="html").encode("utf8")
- else:
- data = open(file_path, "rb").read()
- return self.actionFile(file_path, file_obj=io.BytesIO(data), file_size=len(data))
- else:
- return super(UiRequestPlugin, self).actionUiMedia(path)
- @PluginManager.registerTo("UiWebsocket")
- class UiWebsocketPlugin(object):
- @flag.admin
- def actionPluginList(self, to):
- plugins = []
- for plugin in PluginManager.plugin_manager.listPlugins(list_disabled=True):
- plugin_info_path = plugin["dir_path"] + "/plugin_info.json"
- plugin_info = {}
- if os.path.isfile(plugin_info_path):
- try:
- plugin_info = json.load(open(plugin_info_path))
- except Exception as err:
- self.log.error(
- "Error loading plugin info for %s: %s" %
- (plugin["name"], Debug.formatException(err))
- )
- if plugin_info:
- plugin_info = restrictDictValues(plugin_info) # For security reasons don't allow complex values
- plugin["info"] = plugin_info
- if plugin["source"] != "builtin":
- plugin_site = self.server.sites.get(plugin["source"])
- if plugin_site:
- try:
- plugin_site_info = plugin_site.storage.loadJson(plugin["inner_path"] + "/plugin_info.json")
- plugin_site_info = restrictDictValues(plugin_site_info)
- plugin["site_info"] = plugin_site_info
- plugin["site_title"] = plugin_site.content_manager.contents["content.json"].get("title")
- plugin_key = "%s/%s" % (plugin["source"], plugin["inner_path"])
- plugin["updated"] = plugin_key in PluginManager.plugin_manager.plugins_updated
- except Exception:
- pass
- plugins.append(plugin)
- return {"plugins": plugins}
- @flag.admin
- @flag.no_multiuser
- def actionPluginConfigSet(self, to, source, inner_path, key, value):
- plugin_manager = PluginManager.plugin_manager
- plugins = plugin_manager.listPlugins(list_disabled=True)
- plugin = None
- for item in plugins:
- if item["source"] == source and item["inner_path"] in (inner_path, "disabled-" + inner_path):
- plugin = item
- break
- if not plugin:
- return {"error": "Plugin not found"}
- config_source = plugin_manager.config.setdefault(source, {})
- config_plugin = config_source.setdefault(inner_path, {})
- if key in config_plugin and value is None:
- del config_plugin[key]
- else:
- config_plugin[key] = value
- plugin_manager.saveConfig()
- return "ok"
- def pluginAction(self, action, address, inner_path):
- site = self.server.sites.get(address)
- plugin_manager = PluginManager.plugin_manager
- # Install/update path should exists
- if action in ("add", "update", "add_request"):
- if not site:
- raise Exception("Site not found")
- if not site.storage.isDir(inner_path):
- raise Exception("Directory not found on the site")
- try:
- plugin_info = site.storage.loadJson(inner_path + "/plugin_info.json")
- plugin_data = (plugin_info["rev"], plugin_info["description"], plugin_info["name"])
- except Exception as err:
- raise Exception("Invalid plugin_info.json: %s" % Debug.formatExceptionMessage(err))
- source_path = site.storage.getPath(inner_path)
- target_path = plugin_manager.path_installed_plugins + "/" + address + "/" + inner_path
- plugin_config = plugin_manager.config.setdefault(site.address, {}).setdefault(inner_path, {})
- # Make sure plugin (not)installed
- if action in ("add", "add_request") and os.path.isdir(target_path):
- raise Exception("Plugin already installed")
- if action in ("update", "remove") and not os.path.isdir(target_path):
- raise Exception("Plugin not installed")
- # Do actions
- if action == "add":
- shutil.copytree(source_path, target_path)
- plugin_config["date_added"] = int(time.time())
- plugin_config["rev"] = plugin_info["rev"]
- plugin_config["enabled"] = True
- if action == "update":
- shutil.rmtree(target_path)
- shutil.copytree(source_path, target_path)
- plugin_config["rev"] = plugin_info["rev"]
- plugin_config["date_updated"] = time.time()
- if action == "remove":
- del plugin_manager.config[address][inner_path]
- shutil.rmtree(target_path)
- def doPluginAdd(self, to, inner_path, res):
- if not res:
- return None
- self.pluginAction("add", self.site.address, inner_path)
- PluginManager.plugin_manager.saveConfig()
- self.cmd(
- "confirm",
- ["Plugin installed!<br>You have to restart the client to load the plugin", "Restart"],
- lambda res: self.actionServerShutdown(to, restart=True)
- )
- self.response(to, "ok")
- @flag.no_multiuser
- def actionPluginAddRequest(self, to, inner_path):
- self.pluginAction("add_request", self.site.address, inner_path)
- plugin_info = self.site.storage.loadJson(inner_path + "/plugin_info.json")
- warning = "<b>Warning!<br/>Plugins has the same permissions as the ZeroNet client.<br/>"
- warning += "Do not install it if you don't trust the developer.</b>"
- self.cmd(
- "confirm",
- ["Install new plugin: %s?<br>%s" % (plugin_info["name"], warning), "Trust & Install"],
- lambda res: self.doPluginAdd(to, inner_path, res)
- )
- @flag.admin
- @flag.no_multiuser
- def actionPluginRemove(self, to, address, inner_path):
- self.pluginAction("remove", address, inner_path)
- PluginManager.plugin_manager.saveConfig()
- return "ok"
- @flag.admin
- @flag.no_multiuser
- def actionPluginUpdate(self, to, address, inner_path):
- self.pluginAction("update", address, inner_path)
- PluginManager.plugin_manager.saveConfig()
- PluginManager.plugin_manager.plugins_updated["%s/%s" % (address, inner_path)] = True
- return "ok"
|