From 0c0125b40c925e1451ed32fe4f4f8a04f98dd405 Mon Sep 17 00:00:00 2001 From: Nathan Woodburn Date: Thu, 8 Feb 2024 14:33:27 +1100 Subject: [PATCH] feat: Block new plugins from running until they have been verified --- .gitignore | 4 +++ main.py | 24 +++++++++++++++ plugin.py | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- render.py | 8 ++++- 4 files changed, 117 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index c841779..9a72b84 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,7 @@ __pycache__/ templates/assets/css/styles.min.css + +ignore/ + +plugins/signatures.json diff --git a/main.py b/main.py index b851fe4..4e6a6d4 100644 --- a/main.py +++ b/main.py @@ -1151,6 +1151,10 @@ def plugin(plugin): functions = plugins_module.getPluginFunctions(plugin) functions = render.plugin_functions(functions,plugin) + + if data['verified'] == False: + functions = "
" + functions + error = request.args.get("error") if error == None: @@ -1161,6 +1165,26 @@ def plugin(plugin): author=data['author'],version=data['version'], functions=functions,error=error) +@app.route('/plugin//verify') +def plugin_verify(plugin): + # Check if the user is logged in + if request.cookies.get("account") is None: + return redirect("/login") + + account = account_module.check_account(request.cookies.get("account")) + if not account: + return redirect("/logout") + + if not plugins_module.pluginExists(plugin): + return redirect("/plugins") + + data = plugins_module.getPluginData(plugin) + + if data['verified'] == False: + plugins_module.verifyPlugin(plugin) + + return redirect("/plugin/" + plugin) + @app.route('/plugin//', methods=["POST"]) def plugin_function(plugin,function): # Check if the user is logged in diff --git a/plugin.py b/plugin.py index 10d784d..b032e7a 100644 --- a/plugin.py +++ b/plugin.py @@ -13,6 +13,27 @@ def listPlugins(): details = plugin.info details["link"] = file[:-3] plugins.append(details) + + # Verify plugin signature + signatures = [] + try: + with open("plugins/signatures.json", "r") as f: + signatures = json.load(f) + except: + # Write a new signatures file + with open("plugins/signatures.json", "w") as f: + json.dump(signatures, f) + + for plugin in plugins: + # Hash the plugin file + with open(f"plugins/{plugin['link']}.py", "r") as f: + file = f.read() + plugin_hash = hash(file) + if plugin_hash not in signatures: + plugin["verified"] = False + else: + plugin["verified"] = True + return plugins @@ -22,9 +43,49 @@ def pluginExists(plugin: str): return True return False -def getPluginData(plugin: str): - plugin = importlib.import_module("plugins."+plugin) - return plugin.info +def verifyPlugin(plugin: str): + signatures = [] + try: + with open("plugins/signatures.json", "r") as f: + signatures = json.load(f) + except: + # Write a new signatures file + with open("plugins/signatures.json", "w") as f: + json.dump(signatures, f) + + # Hash the plugin file + with open(f"plugins/{plugin}.py", "r") as f: + file = f.read() + plugin_hash = hash(file) + if plugin_hash not in signatures: + signatures.append(plugin_hash) + with open("plugins/signatures.json", "w") as f: + json.dump(signatures, f) + +def getPluginData(pluginStr: str): + plugin = importlib.import_module("plugins."+pluginStr) + + # Check if the plugin is verified + signatures = [] + try: + with open("plugins/signatures.json", "r") as f: + signatures = json.load(f) + except: + # Write a new signatures file + with open("plugins/signatures.json", "w") as f: + json.dump(signatures, f) + + info = plugin.info + # Hash the plugin file + with open(f"plugins/{pluginStr}.py", "r") as f: + file = f.read() + plugin_hash = hash(file) + if plugin_hash not in signatures: + info["verified"] = False + else: + info["verified"] = True + + return info def getPluginFunctions(plugin: str): plugin = importlib.import_module("plugins."+plugin) @@ -41,6 +102,24 @@ def runPluginFunction(plugin: str, function: str, params: dict, authentication: # Get the function object from the plugin module plugin_function = getattr(plugin_module, function) + # Check if the function is in the signature list + signatures = [] + try: + with open("plugins/signatures.json", "r") as f: + signatures = json.load(f) + except: + # Write a new signatures file + with open("plugins/signatures.json", "w") as f: + json.dump(signatures, f) + + # Hash the plugin file + with open(f"plugins/{plugin}.py", "r") as f: + file = f.read() + plugin_hash = hash(file) + if plugin_hash not in signatures: + return {"error": "Plugin not verified"} + + # Call the function with provided parameters try: result = plugin_function(params, authentication) diff --git a/render.py b/render.py index 7db13e8..6cf5e91 100644 --- a/render.py +++ b/render.py @@ -189,7 +189,10 @@ def plugins(plugins): name = plugin['name'] link = plugin['link'] - html += f'
  • {name}
  • ' + if plugin['verified']: + html += f'
  • {name}
  • ' + else: + html += f'
  • {name} (Not verified)
  • ' return html def plugin_functions(functions, pluginName): @@ -301,5 +304,8 @@ def plugin_output_dash(outputs, returns): html = '' for returnOutput in returns: + if returnOutput not in outputs: + html += render_template('components/dashboard-plugin.html', name=returns[returnOutput]["name"], output="No output") + continue html += render_template('components/dashboard-plugin.html', name=returns[returnOutput]["name"], output=outputs[returnOutput]) return html \ No newline at end of file