diff --git a/.gitignore b/.gitignore index f8b73e7..4b48b57 100644 --- a/.gitignore +++ b/.gitignore @@ -138,3 +138,5 @@ dmypy.json # Cython debug symbols cython_debug/ +# SQLite databases +*.sqlite diff --git a/libertywiki/app.py b/libertywiki/app.py index f9e40c4..6694f54 100644 --- a/libertywiki/app.py +++ b/libertywiki/app.py @@ -23,7 +23,8 @@ DEFAULT_CONFIG = { 'SECURITY_SEND_REGISTER_EMAIL': False, 'SQLALCHEMY_DATABASE_URI': 'sqlite://', 'SQLALCHEMY_ENGINE_OPTIONS': {'pool_pre_ping': True}, - 'SQLALCHEMY_TRACK_MODIFICATIONS': False + 'SQLALCHEMY_TRACK_MODIFICATIONS': False, + 'WIKI_MODE': 'PUBLIC' } CONFIG_VARS = [ 'LIBERTYWIKI_CONFIG', diff --git a/libertywiki/decorators.py b/libertywiki/decorators.py new file mode 100644 index 0000000..9311098 --- /dev/null +++ b/libertywiki/decorators.py @@ -0,0 +1,35 @@ +from functools import wraps + +from flask import current_app, request +from flask_login import current_user +from flask_login.config import EXEMPT_METHODS + +from libertywiki.utils import AccessType, WikiMode + + +def check_access(access_type): + """Check if a user can access the view method""" + + def wrapper(func): + """Decorator wrapper""" + + @wraps(func) + def decorated_view(*args, **kwargs): + """Determine if the decorated view should be run""" + wiki_mode = WikiMode[current_app.config.get('WIKI_MODE', 'OPEN').upper()] + print(wiki_mode) + if request.method in EXEMPT_METHODS or \ + current_app.config.get('LOGIN_DISABLED'): + pass + elif (wiki_mode == WikiMode.PRIVATE + or (wiki_mode == WikiMode.PUBLIC and access_type == AccessType.READ)) \ + and not current_user.is_authenticated: + return current_app.login_manager.unauthorized() + try: + # current_app.ensure_sync available in Flask >= 2.0 + return current_app.ensure_sync(func)(*args, **kwargs) + except AttributeError: + return func(*args, **kwargs) + + return decorated_view + return wrapper diff --git a/libertywiki/utils.py b/libertywiki/utils.py index 938efa2..8303465 100644 --- a/libertywiki/utils.py +++ b/libertywiki/utils.py @@ -1,6 +1,20 @@ +from enum import Enum + from flask_bcrypt import Bcrypt + +class AccessType(Enum): + READ = 1 + WRITE = 2 + + +class WikiMode(Enum): + OPEN = 1 + PUBLIC = 2 + PRIVATE = 3 + + bcrypt = Bcrypt() -__all__ = ['bcrypt'] +__all__ = ['AccessType', 'WikiMode', 'bcrypt'] diff --git a/libertywiki/views.py b/libertywiki/views.py index 40907e1..325e062 100644 --- a/libertywiki/views.py +++ b/libertywiki/views.py @@ -3,13 +3,16 @@ from datetime import datetime from flask import Blueprint, request, render_template, redirect from libertywiki.db import session +from libertywiki.decorators import check_access from libertywiki.models import Page +from libertywiki.utils import AccessType wiki = Blueprint('wiki', __name__, url_prefix='') @wiki.route('/', defaults={'path': 'Main_Page'}, methods=['GET']) @wiki.route('/', methods=['GET']) +@check_access(AccessType.READ) def index(path=None): page = Page.query.filter_by(slug=path).first() if not page: @@ -18,6 +21,7 @@ def index(path=None): @wiki.route('//edit', methods=['GET']) +@check_access(AccessType.WRITE) def edit(path): page = Page.query.filter_by(slug=path).first() if not page: @@ -26,6 +30,7 @@ def edit(path): @wiki.route("//edit", methods=['POST']) +@check_access(AccessType.WRITE) def save(path): page = Page.query.filter_by(slug=path).first() if not page: