| @@ -21,6 +21,7 @@ $def with (nav, apply_form, get_apply_permission_form, project, applicants, perm | |||||
| </div> | </div> | ||||
| <form method="POST"> | <form method="POST"> | ||||
| $:csrf_field() | |||||
| <h4>Add Users</h4> | <h4>Add Users</h4> | ||||
| $:apply_form.render() | $:apply_form.render() | ||||
| <h4>Users to apply:</h4> | <h4>Users to apply:</h4> | ||||
| @@ -15,6 +15,7 @@ $def with (nav, login_form, message) | |||||
| $if not session.username: | $if not session.username: | ||||
| <h3>Log In</h3> | <h3>Log In</h3> | ||||
| <form method="POST"> | <form method="POST"> | ||||
| $:csrf_field() | |||||
| $:login_form.render() | $:login_form.render() | ||||
| </form> | </form> | ||||
| @@ -14,6 +14,7 @@ $def with (nav, project_form, project_buttons, messasge) | |||||
| <h2>Add project!</h2> | <h2>Add project!</h2> | ||||
| <form method="POST"> | <form method="POST"> | ||||
| $:csrf_field() | |||||
| <div> | <div> | ||||
| $:project_form.render() | $:project_form.render() | ||||
| </div> | </div> | ||||
| @@ -37,6 +37,7 @@ $def with (nav, project_form, project, tasks, permissions, categories) | |||||
| <a href="$filename[0]" download>$filename[0].split("/")[-1]</a> | <a href="$filename[0]" download>$filename[0].split("/")[-1]</a> | ||||
| <br> | <br> | ||||
| <form method="POST" enctype="multipart/form-data" action=""> | <form method="POST" enctype="multipart/form-data" action=""> | ||||
| $:csrf_field() | |||||
| $project_form.taskid.set_value(task[0]) | $project_form.taskid.set_value(task[0]) | ||||
| $:project_form.taskid.render() | $:project_form.taskid.render() | ||||
| $if (task[5] == "waiting for delivery" or task[5] == "declined"): | $if (task[5] == "waiting for delivery" or task[5] == "declined"): | ||||
| @@ -15,6 +15,7 @@ $def with (nav, register_form, message) | |||||
| <h2>Register user!</h2> | <h2>Register user!</h2> | ||||
| <form method="POST"> | <form method="POST"> | ||||
| $:csrf_field() | |||||
| $:register_form.render() | $:register_form.render() | ||||
| </form> | </form> | ||||
| @@ -1,6 +1,6 @@ | |||||
| import os | import os | ||||
| import web | import web | ||||
| from views.utils import get_nav_bar | |||||
| from views.utils import get_nav_bar, csrf_field | |||||
| from views.login import Login | from views.login import Login | ||||
| from views.logout import Logout | from views.logout import Logout | ||||
| from views.register import Register | from views.register import Register | ||||
| @@ -42,6 +42,9 @@ else: | |||||
| # Add session to global variables | # Add session to global variables | ||||
| render._add_global(session, 'session') | render._add_global(session, 'session') | ||||
| # Add CSRF field to global variables | |||||
| web.template.Template.globals['csrf_field'] = csrf_field | |||||
| # Make the session available cross modules through webctx | # Make the session available cross modules through webctx | ||||
| def session_hook(): | def session_hook(): | ||||
| web.ctx.session = session | web.ctx.session = session | ||||
| @@ -50,5 +53,3 @@ def session_hook(): | |||||
| app.add_processor(web.loadhook(session_hook)) | app.add_processor(web.loadhook(session_hook)) | ||||
| app = app.wsgifunc() | app = app.wsgifunc() | ||||
| @@ -1,7 +1,7 @@ | |||||
| import web | import web | ||||
| import models.project | import models.project | ||||
| from models.user import get_user_name_by_id | from models.user import get_user_name_by_id | ||||
| from views.utils import get_nav_bar, get_element_count | |||||
| from views.utils import get_nav_bar, get_element_count, csrf_protected | |||||
| from views.forms import get_apply_form, get_apply_permissions_form | from views.forms import get_apply_form, get_apply_permissions_form | ||||
| # Get html templates | # Get html templates | ||||
| @@ -34,6 +34,7 @@ class Apply: | |||||
| return render.apply(nav, apply_form, get_apply_permissions_form, project, applicants, permissions) | return render.apply(nav, apply_form, get_apply_permissions_form, project, applicants, permissions) | ||||
| @csrf_protected | |||||
| def POST(self): | def POST(self): | ||||
| """ | """ | ||||
| Post an application to the view, adding selected users to a project | Post an application to the view, adding selected users to a project | ||||
| @@ -123,5 +124,3 @@ class Apply: | |||||
| permissions.append(["TRUE", "FALSE", "FALSE"]) | permissions.append(["TRUE", "FALSE", "FALSE"]) | ||||
| return applicants, permissions | return applicants, permissions | ||||
| @@ -1,8 +1,8 @@ | |||||
| import web | import web | ||||
| from views.forms import login_form | from views.forms import login_form | ||||
| from views.utils import get_nav_bar, csrf_protected | |||||
| import models.session | import models.session | ||||
| import models.user | import models.user | ||||
| from views.utils import get_nav_bar | |||||
| import random | import random | ||||
| import string | import string | ||||
| import hashlib | import hashlib | ||||
| @@ -34,6 +34,7 @@ class Login(): | |||||
| return render.login(nav, login_form, "") | return render.login(nav, login_form, "") | ||||
| @csrf_protected | |||||
| def POST(self): | def POST(self): | ||||
| """ | """ | ||||
| Log in to the web application and register the session | Log in to the web application and register the session | ||||
| @@ -1,9 +1,9 @@ | |||||
| import web | import web | ||||
| from web import form | from web import form | ||||
| from views.forms import get_task_form_elements, get_project_form_elements, get_user_form_elements, project_buttons | from views.forms import get_task_form_elements, get_project_form_elements, get_user_form_elements, project_buttons | ||||
| from views.utils import get_nav_bar, get_element_count, csrf_protected | |||||
| import models.project | import models.project | ||||
| import models.user | import models.user | ||||
| from views.utils import get_nav_bar, get_element_count | |||||
| # Get html templates | # Get html templates | ||||
| render = web.template.render('templates/') | render = web.template.render('templates/') | ||||
| @@ -26,6 +26,7 @@ class New_project: | |||||
| project_form = form.Form(*(project_form_elements + task_form_elements + user_form_elements)) | project_form = form.Form(*(project_form_elements + task_form_elements + user_form_elements)) | ||||
| return render.new_project(nav, project_form, project_buttons, "") | return render.new_project(nav, project_form, project_buttons, "") | ||||
| @csrf_protected | |||||
| def POST(self): | def POST(self): | ||||
| """ | """ | ||||
| Create a new project | Create a new project | ||||
| @@ -176,4 +177,3 @@ class New_project: | |||||
| project_form = form.Form(*(project_form_elements + task_form_elements + user_form_elements)) | project_form = form.Form(*(project_form_elements + task_form_elements + user_form_elements)) | ||||
| return project_form | return project_form | ||||
| @@ -1,6 +1,6 @@ | |||||
| import web | import web | ||||
| import models.project | import models.project | ||||
| from views.utils import get_nav_bar | |||||
| from views.utils import get_nav_bar, csrf_protected | |||||
| from views.forms import project_form | from views.forms import project_form | ||||
| import os | import os | ||||
| from time import sleep | from time import sleep | ||||
| @@ -41,6 +41,7 @@ class Project: | |||||
| render = web.template.render('templates/', globals={'get_task_files':models.project.get_task_files, 'session':session}) | render = web.template.render('templates/', globals={'get_task_files':models.project.get_task_files, 'session':session}) | ||||
| return render.project(nav, project_form, project, tasks,permissions, categories) | return render.project(nav, project_form, project, tasks,permissions, categories) | ||||
| @csrf_protected | |||||
| def POST(self): | def POST(self): | ||||
| # Get session | # Get session | ||||
| session = web.ctx.session | session = web.ctx.session | ||||
| @@ -109,4 +110,3 @@ class Project: | |||||
| models.project.update_task_status(data.taskid, "declined") | models.project.update_task_status(data.taskid, "declined") | ||||
| raise web.seeother(('/project?projectid=' + data.projectid)) | raise web.seeother(('/project?projectid=' + data.projectid)) | ||||
| @@ -1,8 +1,8 @@ | |||||
| import web | import web | ||||
| from views.forms import register_form | from views.forms import register_form | ||||
| from views.utils import get_nav_bar, csrf_protected | |||||
| import models.register | import models.register | ||||
| import models.user | import models.user | ||||
| from views.utils import get_nav_bar | |||||
| import hashlib | import hashlib | ||||
| import re | import re | ||||
| @@ -22,6 +22,7 @@ class Register: | |||||
| nav = get_nav_bar(session) | nav = get_nav_bar(session) | ||||
| return render.register(nav, register_form, "") | return render.register(nav, register_form, "") | ||||
| @csrf_protected | |||||
| def POST(self): | def POST(self): | ||||
| """ | """ | ||||
| Handle input data and register new user in database | Handle input data and register new user in database | ||||
| @@ -46,4 +47,3 @@ class Register: | |||||
| data.city, data.state, data.postal_code, data.country) | data.city, data.state, data.postal_code, data.country) | ||||
| return render.register(nav, register_form, "User registered!") | return render.register(nav, register_form, "User registered!") | ||||
| @@ -1,3 +1,6 @@ | |||||
| import web | |||||
| from uuid import uuid4 | |||||
| def get_nav_bar(session): | def get_nav_bar(session): | ||||
| """ | """ | ||||
| @@ -38,3 +41,40 @@ def get_element_count(data, element): | |||||
| except: | except: | ||||
| break | break | ||||
| return task_count | return task_count | ||||
| def csrf_token(): | |||||
| """ | |||||
| Get the CSRF token for the session | |||||
| """ | |||||
| session = web.ctx.session | |||||
| if 'csrf_token' not in session: | |||||
| session.csrf_token = uuid4().hex | |||||
| return session.csrf_token | |||||
| def csrf_field(): | |||||
| """ | |||||
| Return a HTML form field for the CSRF token | |||||
| """ | |||||
| return f'<input type="hidden" name="csrf_token" value="{csrf_token()}" />' | |||||
| def csrf_protected(f): | |||||
| """ | |||||
| Decorate a function to do a CSRF check. | |||||
| """ | |||||
| def decorated(*args, **kwargs): | |||||
| session = web.ctx.session | |||||
| inp = web.input() | |||||
| if not ('csrf_token' in inp and inp.csrf_token == session.pop('csrf_token', None)): | |||||
| raise web.HTTPError( | |||||
| '400 Bad request', | |||||
| {'content-type': 'text/html'}, | |||||
| 'Cross-site request forgery attempt', | |||||
| ) | |||||
| return f(*args, **kwargs) | |||||
| return decorated | |||||