diff --git a/admin/audit.py b/admin/audit.py new file mode 100644 index 00000000..fdd997f6 --- /dev/null +++ b/admin/audit.py @@ -0,0 +1,43 @@ +from freeposte import app + +import sys +import tabulate + + +# Known endpoints without permissions +known_missing_permissions = [ + "index", + "static", "bootstrap.static", + "admin.static", "admin.login" +] + + +# Compute the permission table +missing_permissions = [] +permissions = {} +for endpoint, function in app.view_functions.items(): + audit = function.__dict__.get("_audit_permissions") + if audit: + handler, args = audit + if args: + model = args[0].__name__ + key = args[1] + else: + model = key = None + permissions[endpoint] = [endpoint, handler.__name__, model, key] + elif endpoint not in known_missing_permissions: + missing_permissions.append(endpoint) + + +# Fail if any endpoint is missing a permission check +if missing_permissions: + print("The following endpoints are missing permission checks:") + print(missing_permissions.join(",")) + sys.exit(1) + + +# Display the permissions table +print(tabulate.tabulate([ + [route, *permissions[route.endpoint]] + for route in app.url_map.iter_rules() if route.endpoint in permissions +])) diff --git a/admin/freeposte/admin/access.py b/admin/freeposte/admin/access.py index 8a8f2447..58ea4b6e 100644 --- a/admin/freeposte/admin/access.py +++ b/admin/freeposte/admin/access.py @@ -25,6 +25,7 @@ def permissions_wrapper(handler): @functools.wraps(function) def wrapper(*args, **kwargs): return callback(function, args, kwargs, dargs, dkwargs) + wrapper._audit_permissions = handler, dargs return flask_login.login_required(wrapper) return inner else: @@ -32,6 +33,7 @@ def permissions_wrapper(handler): @functools.wraps(function) def wrapper(*args, **kwargs): return callback(function, args, kwargs, (), {}) + wrapper._audit_permissions = handler, [] return flask_login.login_required(wrapper) return decorator diff --git a/admin/requirements.txt b/admin/requirements.txt index acd52c92..a7076531 100644 --- a/admin/requirements.txt +++ b/admin/requirements.txt @@ -10,3 +10,4 @@ PyOpenSSL passlib gunicorn docker-py +tabulate