diff --git a/src/api/api_document.py b/src/api/api_document.py index 54dac1c..cd33db7 100644 --- a/src/api/api_document.py +++ b/src/api/api_document.py @@ -1,5 +1,6 @@ from flask import Blueprint, request from web_utils.get_arg import get_arg +from web_utils.business_exception import BusinessException import os from data.document import Document @@ -14,7 +15,7 @@ def build(): doc = Document(doc_name, branch) if doc.get_api_key() != apikey: - raise Exception("Invalid API key") + raise BusinessException("Invalid API key") build_task = doc.build() build_task.join() diff --git a/src/app.py b/src/app.py index be23dc9..262980c 100644 --- a/src/app.py +++ b/src/app.py @@ -1,10 +1,14 @@ import os import random import string -from flask import Flask +from web_utils.business_exception import BusinessException +from flask import Flask, render_template import data.document +def handle_exceptions(e): + return render_template("error.html", message = str(e)) + def create_app(): app = Flask(__name__) @@ -29,6 +33,8 @@ def create_app(): raise Exception("Internal error: insecure secret key") app.secret_key = secret_key + app.register_error_handler(BusinessException, handle_exceptions) + if app.config['BEHIND_REVERSE_PROXY']: from werkzeug.middleware.proxy_fix import ProxyFix app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_prefix=1) diff --git a/src/data/document.py b/src/data/document.py index 87aa456..61db5fa 100644 --- a/src/data/document.py +++ b/src/data/document.py @@ -2,6 +2,7 @@ import os import uuid from flask import current_app from web_utils.task import ProcessTask +from web_utils.business_exception import BusinessException import shutil from unicodedata import normalize import string @@ -24,7 +25,7 @@ def sanitize_name(initial_name): valid_chars = "-_.(){0}{1}".format(string.ascii_letters, string.digits) name = "".join(ch for ch in name if ch in valid_chars) if len(name) == 0 or '..' in name: - raise Exception("Invalid name: " + initial_name) + raise BusinessException("Invalid name: " + initial_name) return name class Document: @@ -38,7 +39,7 @@ class Document: self.valid = False return else: - raise Exception("This document does not exist: "+doc_name+"@"+branch) + raise BusinessException("This document does not exist: "+doc_name+"@"+branch) self.doc_path = doc_path self.valid = True @@ -73,7 +74,7 @@ class Document: def make_doc_path(doc_name, branch): doc_path = os.path.realpath(get_document_root()+'/'+sanitize_name(doc_name)+'/'+sanitize_name(branch)) if not doc_path.startswith(get_document_root()): - raise Exception("Invalid document path for "+doc_name+"@"+branch) + raise BusinessException("Invalid document path for "+doc_name+"@"+branch) return doc_path @staticmethod @@ -81,14 +82,14 @@ class Document: # check the document does not already exist doc_path = Document.make_doc_path(doc_name, branch) if os.path.isdir(doc_path): - raise Exception("This document already exists: "+doc_name+"@"+branch) + raise BusinessException("This document already exists: "+doc_name+"@"+branch) if source_dir != sanitize_name(source_dir): - raise Exception("Invalid source directory name: " + source_dir) + raise BusinessException("Invalid source directory name: " + source_dir) # we have potentially serious security issues related to cloning anything. For example cloning from SSH may use a pre-configured server identity, etc. if not repo.startswith("https://"): - raise Exception("Only HTTPS repositories are allowed in current implementation") + raise BusinessException("Only HTTPS repositories are allowed in current implementation") # Generate an API key apikey = str(uuid.uuid4()) diff --git a/src/templates/error.html b/src/templates/error.html new file mode 100644 index 0000000..c81aceb --- /dev/null +++ b/src/templates/error.html @@ -0,0 +1,8 @@ +{% extends 'base.html' %} + +{% block title %}Erreur{% endblock %} + +{% block content %} +

Une erreur s'est produite

+

{{message}}

+{% endblock %} diff --git a/src/web/admin/admin.py b/src/web/admin/admin.py index 13c706c..7898c39 100644 --- a/src/web/admin/admin.py +++ b/src/web/admin/admin.py @@ -1,6 +1,7 @@ import os import random import string +from web_utils.business_exception import BusinessException from flask import current_app, Blueprint, render_template, session, redirect, url_for, request from data.document import Document @@ -31,6 +32,6 @@ def login(): session['authenticated'] = True return redirect(url_for('admin.index'), code=302) else: - raise Exception("Incorrect password") + raise BusinessException("Incorrect password") else: return render_template("admin/login.html") diff --git a/src/web_utils/business_exception.py b/src/web_utils/business_exception.py new file mode 100644 index 0000000..88ac67a --- /dev/null +++ b/src/web_utils/business_exception.py @@ -0,0 +1,10 @@ +class BusinessException(Exception): + def __init__(self, *args): + super().__init__(args) + self.message = args[0] + + def __str__(self): + if hasattr(self, 'message'): + return self.message + else: + return super().__str__() diff --git a/src/web_utils/get_arg.py b/src/web_utils/get_arg.py index 063d1cd..0d47670 100644 --- a/src/web_utils/get_arg.py +++ b/src/web_utils/get_arg.py @@ -1,10 +1,11 @@ +from web_utils.business_exception import BusinessException from flask import request def get_arg(arg_name, default_value = None): result = request.args.get(arg_name) if result == None: if default_value == None: - raise Exception("Missing query string parameter '"+arg_name+"'") + raise BusinessException("Missing query string parameter '"+arg_name+"'") else: return default_value return result diff --git a/src/web_utils/run.py b/src/web_utils/run.py index b941b38..fb2d64c 100644 --- a/src/web_utils/run.py +++ b/src/web_utils/run.py @@ -1,4 +1,5 @@ from subprocess import Popen, PIPE, STDOUT +from web_utils.business_exception import BusinessException def run(cmd): p = Popen(cmd, stdout = PIPE, stderr = STDOUT, shell = True) @@ -9,6 +10,6 @@ def run(cmd): p.wait() if p.returncode != 0: - raise Exception("Command failed ("+str(p.returncode)+")\n"+cmd+"\n"+outputStr) + raise BusinessException("Command failed ("+str(p.returncode)+")\n"+cmd+"\n"+outputStr) return outputStr diff --git a/src/web_utils/task.py b/src/web_utils/task.py index ce2073e..a8f7622 100644 --- a/src/web_utils/task.py +++ b/src/web_utils/task.py @@ -2,6 +2,7 @@ from threading import Thread, Lock from io import StringIO from subprocess import Popen, PIPE, STDOUT, DEVNULL import uuid +from web_utils.business_exception import BusinessException tasks = {} @@ -61,4 +62,4 @@ class ProcessTask(Task): if self.__process.returncode != 0: if self.__fail_callback: self.__fail_callback() - raise Exception("Command failed ("+str(self.__process.returncode)+")\n"+self.get_output_str()) \ No newline at end of file + raise BusinessException("Command failed ("+str(self.__process.returncode)+")\n"+self.get_output_str()) \ No newline at end of file