moved cleaning to create where possible. Changed nh_safe to safe as we assume everything was cleaned in the first place

This commit is contained in:
Liam Brydon
2025-11-06 09:46:30 +13:00
parent c663eaf7bd
commit 4524b8fdf3
49 changed files with 232 additions and 263 deletions

View File

@ -58,16 +58,6 @@ def log_post_params(request):
logger.debug(f"{k}\t{v}")
def clean_dict(bad_dict):
"""Check each value in a dictionary for XSS attempts"""
clean = {} # TODO: I'm not sure if this is the best way to do this.
for key, value in bad_dict.items():
if key != 'csrfmiddlewaretoken' and isinstance(value, str):
value = nh3.clean(value, tags=s.ALLOWED_HTML_TAGS)
clean[key] = value
return clean
def error(request, message: str, detail: str, code: int = 400):
context = get_base_context(request)
error_context = {
@ -94,8 +84,7 @@ def login(request):
from django.contrib.auth import authenticate
from django.contrib.auth import login
# Check if the cleaned username is equal to the unclean username, if not, invalid username
username = nh3.clean(request.POST.get("username")).strip()
username = request.POST.get("username").strip()
if username != request.POST.get("username").strip():
context["message"] = "Login failed!"
return render(request, "static/login.html", context)
@ -158,15 +147,12 @@ def register(request):
if next := request.POST.get("next"):
context["next"] = next
# We are not allowing usernames or emails to contain any html (unlike using tags=s.ALLOWED_HTML_TAGS elsewhere)
username = nh3.clean(request.POST.get("username", "")).strip()
email = nh3.clean(request.POST.get("email", "")).strip()
username = request.POST.get("username", "").strip()
email = request.POST.get("email", "").strip()
password = request.POST.get("password", "").strip()
rpassword = request.POST.get("rpassword", "").strip()
# Check if cleaned username and email are equal to the unclean, if not, invalid username or email
if (not (username and email and password) or username != request.POST.get("username", "").strip() or
email != request.POST.get("email", "").strip()):
if not (username and email and password):
context["message"] = "Invalid username/email/password"
return render(request, "static/register.html", context)
@ -407,11 +393,8 @@ def packages(request):
else:
return HttpResponseBadRequest()
else:
# Clean for potential XSS
package_name = nh3.clean(request.POST.get("package-name"), tags=s.ALLOWED_HTML_TAGS).strip()
package_description = nh3.clean(request.POST.get(
"package-description", s.DEFAULT_VALUES["description"]
), tags=s.ALLOWED_HTML_TAGS).strip()
package_name = request.POST.get("package-name")
package_description = request.POST.get("package-description", s.DEFAULT_VALUES["description"])
created_package = PackageManager.create_package(
current_user, package_name, package_description
@ -686,8 +669,7 @@ def search(request):
if request.method == "GET":
package_urls = request.GET.getlist("packages")
# Clean for potential XSS
searchterm = nh3.clean(request.GET.get("search"), tags=s.ALLOWED_HTML_TAGS).strip()
searchterm = request.GET.get("search").strip()
mode = request.GET.get("mode")
@ -789,9 +771,8 @@ def package_models(request, package_uuid):
elif request.method == "POST":
log_post_params(request)
# Clean for potential XSS
name = nh3.clean(request.POST.get("model-name"), tags=s.ALLOWED_HTML_TAGS).strip()
description = nh3.clean(request.POST.get("model-description"), tags=s.ALLOWED_HTML_TAGS).strip()
name = request.POST.get("model-name")
description = request.POST.get("model-description")
model_type = request.POST.get("model-type")
@ -936,7 +917,7 @@ def package_model(request, package_uuid, model_uuid):
else:
return HttpResponseBadRequest()
else:
# Clean for potential XSS
# TODO: Move cleaning to property updater
name = nh3.clean(request.POST.get("model-name", "").strip(), tags=s.ALLOWED_HTML_TAGS).strip()
description = nh3.clean(request.POST.get("model-description", "").strip(), tags=s.ALLOWED_HTML_TAGS).strip()
@ -1040,7 +1021,7 @@ def package(request, package_uuid):
else:
return HttpResponseBadRequest()
# Clean for potential XSS
# TODO: Move cleaning to property updater
new_package_name = nh3.clean(request.POST.get("package-name"), tags=s.ALLOWED_HTML_TAGS).strip()
new_package_description = nh3.clean(request.POST.get("package-description"), tags=s.ALLOWED_HTML_TAGS).strip()
@ -1150,10 +1131,9 @@ def package_compounds(request, package_uuid):
return render(request, "collections/objects_list.html", context)
elif request.method == "POST":
# Clean for potential XSS
compound_name = nh3.clean(request.POST.get("compound-name"), tags=s.ALLOWED_HTML_TAGS).strip()
compound_name = request.POST.get("compound-name")
compound_smiles = request.POST.get("compound-smiles").strip()
compound_description = nh3.clean(request.POST.get("compound-description"), tags=s.ALLOWED_HTML_TAGS).strip()
compound_description = request.POST.get("compound-description")
c = Compound.create(current_package, compound_smiles, compound_name, compound_description)
@ -1204,7 +1184,7 @@ def package_compound(request, package_uuid, compound_uuid):
return JsonResponse({"error": str(e)}, status=400)
return JsonResponse({"success": current_compound.url})
# Clean for potential XSS
# TODO: Move cleaning to property updater
new_compound_name = nh3.clean(request.POST.get("compound-name", ""), tags=s.ALLOWED_HTML_TAGS).strip()
new_compound_description = nh3.clean(request.POST.get("compound-description", ""),
tags=s.ALLOWED_HTML_TAGS).strip()
@ -1271,10 +1251,9 @@ def package_compound_structures(request, package_uuid, compound_uuid):
return render(request, "collections/objects_list.html", context)
elif request.method == "POST":
# Clean for potential XSS
structure_name = nh3.clean(request.POST.get("structure-name"), tags=s.ALLOWED_HTML_TAGS).strip()
structure_name = request.POST.get("structure-name")
structure_smiles = request.POST.get("structure-smiles").strip()
structure_description = nh3.clean(request.POST.get("structure-description"), tags=s.ALLOWED_HTML_TAGS).strip()
structure_description = request.POST.get("structure-description")
cs = current_compound.add_structure(structure_smiles, structure_name, structure_description)
@ -1334,7 +1313,7 @@ def package_compound_structure(request, package_uuid, compound_uuid, structure_u
return redirect(current_compound.url + "/structure")
else:
return HttpResponseBadRequest()
# Clean for potential XSS
# TODO: Move cleaning to property updater
new_structure_name = nh3.clean(request.POST.get("compound-structure-name", ""),
tags=s.ALLOWED_HTML_TAGS).strip()
new_structure_description = nh3.clean(request.POST.get("compound-structure-description", ""),
@ -1431,9 +1410,8 @@ def package_rules(request, package_uuid):
log_post_params(request)
# Generic params
# Clean for potential XSS
rule_name = nh3.clean(request.POST.get("rule-name"), tags=s.ALLOWED_HTML_TAGS).strip()
rule_description = nh3.clean(request.POST.get("rule-description"), tags=s.ALLOWED_HTML_TAGS).strip()
rule_name = request.POST.get("rule-name")
rule_description = request.POST.get("rule-description")
rule_type = request.POST.get("rule-type")
@ -1441,14 +1419,10 @@ def package_rules(request, package_uuid):
# Obtain parameters as required by rule type
if rule_type == "SimpleAmbitRule":
# Clean for potential XSS
params["smirks"] = request.POST.get("rule-smirks").strip()
params["reactant_filter_smarts"] = nh3.clean(request.POST.get("rule-reactant-smarts"),
tags=s.ALLOWED_HTML_TAGS).strip()
params["product_filter_smarts"] = nh3.clean(request.POST.get("rule-product-smarts"),
tags=s.ALLOWED_HTML_TAGS).strip()
params["reactant_filter_smarts"] = request.POST.get("rule-reactant-smarts")
params["product_filter_smarts"] = request.POST.get("rule-product-smarts")
elif rule_type == "SimpleRDKitRule":
# Clean for potential XSS
params["reaction_smarts"] = request.POST.get("rule-reaction-smarts").strip()
elif rule_type == "ParallelRule":
pass
@ -1542,7 +1516,7 @@ def package_rule(request, package_uuid, rule_uuid):
return JsonResponse({"success": current_rule.url})
# Clean for potential XSS
# TODO: Move cleaning to property updater
rule_name = nh3.clean(request.POST.get("rule-name", ""), tags=s.ALLOWED_HTML_TAGS).strip()
rule_description = nh3.clean(request.POST.get("rule-description", "").strip(), tags=s.ALLOWED_HTML_TAGS).strip()
@ -1605,9 +1579,8 @@ def package_reactions(request, package_uuid):
return render(request, "collections/objects_list.html", context)
elif request.method == "POST":
# Clean for potential XSS
reaction_name = nh3.clean(request.POST.get("reaction-name"), tags=s.ALLOWED_HTML_TAGS).strip()
reaction_description = nh3.clean(request.POST.get("reaction-description"), tags=s.ALLOWED_HTML_TAGS).strip()
reaction_name = request.POST.get("reaction-name")
reaction_description = request.POST.get("reaction-description")
reactions_smirks = request.POST.get("reaction-smirks").strip()
educts = reactions_smirks.split(">>")[0].split(".")
@ -1670,7 +1643,7 @@ def package_reaction(request, package_uuid, reaction_uuid):
return JsonResponse({"success": current_reaction.url})
# Clean for potential XSS
# TODO: Move cleaning to property updater
new_reaction_name = nh3.clean(request.POST.get("reaction-name", ""), tags=s.ALLOWED_HTML_TAGS).strip()
new_reaction_description = nh3.clean(request.POST.get("reaction-description", ""),
tags=s.ALLOWED_HTML_TAGS).strip()
@ -1748,9 +1721,8 @@ def package_pathways(request, package_uuid):
elif request.method == "POST":
log_post_params(request)
# Clean for potential XSS
name = nh3.clean(request.POST.get("name"), tags=s.ALLOWED_HTML_TAGS).strip()
description = nh3.clean(request.POST.get("description"), tags=s.ALLOWED_HTML_TAGS).strip()
name = request.POST.get("name")
description = request.POST.get("description")
smiles = request.POST.get("smiles", "").strip()
pw_mode = request.POST.get("predict", "predict").strip()
@ -1901,7 +1873,7 @@ def package_pathway(request, package_uuid, pathway_uuid):
return JsonResponse({"success": current_pathway.url})
# Clean for potential XSS
# TODO: Move cleaning to property updater
pathway_name = nh3.clean(request.POST.get("pathway-name"), tags=s.ALLOWED_HTML_TAGS).strip()
pathway_description = nh3.clean(request.POST.get("pathway-description"), tags=s.ALLOWED_HTML_TAGS).strip()
@ -1983,9 +1955,8 @@ def package_pathway_nodes(request, package_uuid, pathway_uuid):
return render(request, "collections/objects_list.html", context)
elif request.method == "POST":
# Clean for potential XSS
node_name = nh3.clean(request.POST.get("node-name"), tags=s.ALLOWED_HTML_TAGS).strip()
node_description = nh3.clean(request.POST.get("node-description"), tags=s.ALLOWED_HTML_TAGS).strip()
node_name = request.POST.get("node-name")
node_description = request.POST.get("node-description")
node_smiles = request.POST.get("node-smiles").strip()
current_pathway.add_node(node_smiles, name=node_name, description=node_description)
@ -2116,9 +2087,8 @@ def package_pathway_edges(request, package_uuid, pathway_uuid):
elif request.method == "POST":
log_post_params(request)
# Clean for potential XSS
edge_name = nh3.clean(request.POST.get("edge-name"), tags=s.ALLOWED_HTML_TAGS).strip()
edge_description = nh3.clean(request.POST.get("edge-description"), tags=s.ALLOWED_HTML_TAGS).strip()
edge_name = request.POST.get("edge-name")
edge_description = request.POST.get("edge-description")
edge_substrates = request.POST.getlist("edge-substrates")
edge_products = request.POST.getlist("edge-products")
@ -2281,9 +2251,8 @@ def package_scenarios(request, package_uuid):
elif request.method == "POST":
log_post_params(request)
# Clean for potential XSS
scenario_name = nh3.clean(request.POST.get("scenario-name"), tags=s.ALLOWED_HTML_TAGS).strip()
scenario_description = nh3.clean(request.POST.get("scenario-description"), tags=s.ALLOWED_HTML_TAGS).strip()
scenario_name = request.POST.get("scenario-name")
scenario_description = request.POST.get("scenario-description")
scenario_date_year = request.POST.get("scenario-date-year")
scenario_date_month = request.POST.get("scenario-date-month")
@ -2297,7 +2266,7 @@ def package_scenarios(request, package_uuid):
scenario_type = request.POST.get("scenario-type")
additional_information = HTMLGenerator.build_models(clean_dict(request.POST.dict()))
additional_information = HTMLGenerator.build_models(request.POST.dict())
additional_information = [x for sv in additional_information.values() for x in sv]
new_scen = Scenario.create(
@ -2368,8 +2337,7 @@ def package_scenario(request, package_uuid, scenario_uuid):
current_scenario.save()
return redirect(current_scenario.url)
elif hidden == "set-additional-information":
post_dict = clean_dict(request.POST.dict()) # Clean post dict inputs for potential XSS
ais = HTMLGenerator.build_models(post_dict)
ais = HTMLGenerator.build_models(request.POST.dict())
if s.DEBUG:
logger.info(ais)
@ -2377,8 +2345,7 @@ def package_scenario(request, package_uuid, scenario_uuid):
current_scenario.set_additional_information(ais)
return redirect(current_scenario.url)
elif hidden == "add-additional-information":
post_dict = clean_dict(request.POST.dict()) # Clean post dict inputs for potential XSS
ais = HTMLGenerator.build_models(post_dict)
ais = HTMLGenerator.build_models(request.POST.dict())
if len(ais.keys()) != 1:
raise ValueError(
@ -2518,10 +2485,8 @@ def groups(request):
return render(request, "collections/objects_list.html", context)
elif request.method == "POST":
# Clean for potential XSS
group_name = nh3.clean(request.POST.get("group-name"), tags=s.ALLOWED_HTML_TAGS).strip()
group_description = nh3.clean(request.POST.get("group-description", s.DEFAULT_VALUES["description"]),
tags=s.ALLOWED_HTML_TAGS).strip()
group_name = request.POST.get("group-name")
group_description = request.POST.get("group-description", s.DEFAULT_VALUES["description"])
g = GroupManager.create_group(current_user, group_name, group_description)
@ -2611,9 +2576,8 @@ def settings(request):
logger.info("Parameters received:")
logger.info(f"{k}\t{v}")
# Clean for potential XSS
name = nh3.clean(request.POST.get("prediction-setting-name"), tags=s.ALLOWED_HTML_TAGS).strip()
description = nh3.clean(request.POST.get("prediction-setting-description"), tags=s.ALLOWED_HTML_TAGS).strip()
name = request.POST.get("prediction-setting-name")
description = request.POST.get("prediction-setting-description")
new_default = request.POST.get("prediction-setting-new-default", "off") == "on"