You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
112 lines
3.7 KiB
Python
112 lines
3.7 KiB
Python
from mailu import models
|
|
from mailu.ui import forms
|
|
|
|
import flask
|
|
import flask_login
|
|
import functools
|
|
|
|
|
|
def permissions_wrapper(handler):
|
|
""" Decorator that produces a decorator for checking permissions.
|
|
"""
|
|
def callback(function, args, kwargs, dargs, dkwargs):
|
|
authorized = handler(args, kwargs, *dargs, **dkwargs)
|
|
if not authorized:
|
|
flask.abort(403)
|
|
elif type(authorized) is int:
|
|
flask.abort(authorized)
|
|
else:
|
|
return function(*args, **kwargs)
|
|
# If the handler has no argument, declare a
|
|
# simple decorator, otherwise declare a nested decorator
|
|
# There are at least two mandatory arguments
|
|
if handler.__code__.co_argcount > 2:
|
|
def decorator(*dargs, **dkwargs):
|
|
def inner(function):
|
|
@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:
|
|
def decorator(function):
|
|
@functools.wraps(function)
|
|
def wrapper(*args, **kwargs):
|
|
return callback(function, args, kwargs, (), {})
|
|
wrapper._audit_permissions = handler, []
|
|
return flask_login.login_required(wrapper)
|
|
return decorator
|
|
|
|
|
|
@permissions_wrapper
|
|
def global_admin(args, kwargs):
|
|
""" The view is only available to global administrators.
|
|
"""
|
|
return flask_login.current_user.global_admin
|
|
|
|
|
|
@permissions_wrapper
|
|
def domain_admin(args, kwargs, model, key):
|
|
""" The view is only available to specific domain admins.
|
|
Global admins will still be able to access the resource.
|
|
|
|
A model and key must be provided. The model will be queries
|
|
based on the query parameter named after the key. The model may
|
|
either be Domain or an Email subclass (or any class with a
|
|
``domain`` attribute which stores a related Domain instance).
|
|
"""
|
|
obj = model.query.get(kwargs[key])
|
|
if obj:
|
|
domain = obj if type(obj) is models.Domain else obj.domain
|
|
return domain in flask_login.current_user.get_managed_domains()
|
|
|
|
|
|
@permissions_wrapper
|
|
def owner(args, kwargs, model, key):
|
|
""" The view is only available to the resource owner or manager.
|
|
|
|
A model and key must be provided. The model will be queries
|
|
based on the query parameter named after the key. The model may
|
|
either be User or any model with a ``user`` attribute storing
|
|
a user instance (like Fetch).
|
|
|
|
If the query parameter is empty and the model is User, then
|
|
the resource being accessed is supposed to be the current
|
|
logged in user and access is obviously authorized.
|
|
"""
|
|
if kwargs[key] is None and model == models.User:
|
|
return True
|
|
obj = model.query.get(kwargs[key])
|
|
if obj:
|
|
user = obj if type(obj) is models.User else obj.user
|
|
return (
|
|
user.email == flask_login.current_user.email
|
|
or user.domain in flask_login.current_user.get_managed_domains()
|
|
)
|
|
|
|
|
|
@permissions_wrapper
|
|
def authenticated(args, kwargs):
|
|
""" The view is only available to logged in users.
|
|
"""
|
|
return True
|
|
|
|
|
|
|
|
def confirmation_required(action):
|
|
""" View decorator that asks for a confirmation first.
|
|
"""
|
|
def inner(function):
|
|
@functools.wraps(function)
|
|
def wrapper(*args, **kwargs):
|
|
form = forms.ConfirmationForm()
|
|
if form.validate_on_submit():
|
|
return function(*args, **kwargs)
|
|
return flask.render_template(
|
|
"confirm.html", action=action.format(*args, **kwargs),
|
|
form=form
|
|
)
|
|
return wrapper
|
|
return inner
|