feat: Block new plugins from running until they have been verified
All checks were successful
Build Docker / Build Image (push) Successful in 42s

This commit is contained in:
Nathan Woodburn 2024-02-08 14:33:27 +11:00
parent bfbac3a679
commit 0c0125b40c
Signed by: nathanwoodburn
GPG Key ID: 203B000478AD0EF1
4 changed files with 117 additions and 4 deletions

4
.gitignore vendored
View File

@ -4,3 +4,7 @@
__pycache__/ __pycache__/
templates/assets/css/styles.min.css templates/assets/css/styles.min.css
ignore/
plugins/signatures.json

24
main.py
View File

@ -1152,6 +1152,10 @@ def plugin(plugin):
functions = plugins_module.getPluginFunctions(plugin) functions = plugins_module.getPluginFunctions(plugin)
functions = render.plugin_functions(functions,plugin) functions = render.plugin_functions(functions,plugin)
if data['verified'] == False:
functions = "<div class='container-fluid'><div class='alert alert-warning' role='alert'>This plugin is not verified and is disabled for your protection. Please check the code before marking the plugin as verified <a href='/plugin/" + plugin + "/verify' class='btn btn-danger'>Verify</a></div></div>" + functions
error = request.args.get("error") error = request.args.get("error")
if error == None: if error == None:
error = "" error = ""
@ -1161,6 +1165,26 @@ def plugin(plugin):
author=data['author'],version=data['version'], author=data['author'],version=data['version'],
functions=functions,error=error) functions=functions,error=error)
@app.route('/plugin/<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/<plugin>/<function>', methods=["POST"]) @app.route('/plugin/<plugin>/<function>', methods=["POST"])
def plugin_function(plugin,function): def plugin_function(plugin,function):
# Check if the user is logged in # Check if the user is logged in

View File

@ -13,6 +13,27 @@ def listPlugins():
details = plugin.info details = plugin.info
details["link"] = file[:-3] details["link"] = file[:-3]
plugins.append(details) 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 return plugins
@ -22,9 +43,49 @@ def pluginExists(plugin: str):
return True return True
return False return False
def getPluginData(plugin: str): def verifyPlugin(plugin: str):
plugin = importlib.import_module("plugins."+plugin) signatures = []
return plugin.info 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): def getPluginFunctions(plugin: str):
plugin = importlib.import_module("plugins."+plugin) 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 # Get the function object from the plugin module
plugin_function = getattr(plugin_module, function) 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 # Call the function with provided parameters
try: try:
result = plugin_function(params, authentication) result = plugin_function(params, authentication)

View File

@ -189,7 +189,10 @@ def plugins(plugins):
name = plugin['name'] name = plugin['name']
link = plugin['link'] link = plugin['link']
if plugin['verified']:
html += f'<li class="list-group-item"><a class="btn btn-secondary" style="width:100%;height:100%;margin:0px;font-size: x-large;" role="button" href="/plugin/{link}">{name}</a></li>' html += f'<li class="list-group-item"><a class="btn btn-secondary" style="width:100%;height:100%;margin:0px;font-size: x-large;" role="button" href="/plugin/{link}">{name}</a></li>'
else:
html += f'<li class="list-group-item"><a class="btn btn-danger" style="width:100%;height:100%;margin:0px;font-size: x-large;" role="button" href="/plugin/{link}">{name} (Not verified)</a></li>'
return html return html
def plugin_functions(functions, pluginName): def plugin_functions(functions, pluginName):
@ -301,5 +304,8 @@ def plugin_output_dash(outputs, returns):
html = '' html = ''
for returnOutput in returns: 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]) html += render_template('components/dashboard-plugin.html', name=returns[returnOutput]["name"], output=outputs[returnOutput])
return html return html