import shutil from pathlib import Path import flask import markdown from flask_caching import Cache from flask_htpasswd import HtPasswdAuth from flask_restful import reqparse, Api, Resource from config import Config app = flask.Flask(__name__) api = Api(app) # app config if app.config["ENV"] == "development": app.config.from_object("config.DevelopConfig") else: app.config.from_object(Config) cache = Cache(app) htpasswd = HtPasswdAuth(app) htpasswd.users.autosave = True parser = reqparse.RequestParser() messages = { 'Created': { 'message': "User creation succeeded" }, 'Conflict': { 'message': 'Username conflict' }, 'InternalServerError': { 'message': 'Something went wrong, please contact the administrator.' } } @app.route('/joplin/') @cache.cached(timeout=21600) def index(): # codehilite css with open(Path(app.root_path).joinpath('./static/hilite.css'), 'r') as hilite_file: css = ''.format(css=hilite_file.read()) # Open the README file with open(Path(app.root_path).joinpath('./static/Readme.md'), 'r') as markdown_file: # Read the content of the file content = markdown_file.read() html = ''.join([css, content]) # render finished HTML return markdown.markdown(html, extensions=["fenced_code", "codehilite"]), 200 @app.route('/joplin/auth-test') @htpasswd.required def auth_test(user): return 'Hello {user}'.format(user=user) class NewUser(Resource): """ class to create new htpasswd user entry """ def post(self, username): parser.add_argument('password') parser.add_argument('invite') args = parser.parse_args() password = args['password'] invitecode = args['invite'] path = app.config['JOPLIN_DIR'] # break early if invitecode != app.config['INVITE_CODE']: return {'message': 'Unauthorized Request'}, 401 if None in [password, invitecode]: return {'message': 'Missing parameter'}, 422 if username not in htpasswd.users.users(): # firstly try to create the folder to break if permissions aren't correct try: Path.mkdir(Path(path).joinpath('./%s' % username), mode=0o750, exist_ok=True) except OSError: return messages['InternalServerError'], 500 # create user entry htpasswd.users.set_password(username, password) return messages['Created'], 201 else: return messages['Conflict'], 409 class ChangePW(Resource): """ class to update a users password """ def post(self, username): parser.add_argument('password') parser.add_argument('new_password') args = parser.parse_args() password = args['password'] new_password = args['new_password'] if None in [password, new_password]: return {'message': 'Missing parameter'}, 422 # check_password return False if password mismatch and None if no user is found if htpasswd.users.check_password(username, password): htpasswd.users.set_password(username, new_password) return {'message': 'OK'}, 200 else: return {'message': 'Unauthorized Request'}, 401 class DelUser(Resource): """ class to delete a user """ def delete(self, username): parser.add_argument('password') args = parser.parse_args() password = args['password'] if password is None: return {'message': 'Missing parameter'}, 422 # check_password return False if password mismatch and None if no user is found if htpasswd.users.check_password(username, password): htpasswd.users.delete(username) try: # remove users files recursively shutil.rmtree(Path(app.config['JOPLIN_DIR']).joinpath('./%s' % username)) except FileNotFoundError: pass return [], 204 else: return {'message': 'Unauthorized Request'}, 401 api.add_resource(NewUser, '/joplin//create') api.add_resource(ChangePW, '/joplin//changepw') api.add_resource(DelUser, '/joplin/') if __name__ == '__main__': app.run()