From 398bb272c19da68375107059e50465490741d322 Mon Sep 17 00:00:00 2001 From: mendacus Date: Tue, 18 Nov 2025 11:05:10 -0500 Subject: [PATCH] Add automated TLS enrollment workflow --- README.md | 23 +++ dispatch-server.py | 9 +- dispatch/app.py | 63 +++++++- dispatch/auth.py | 0 dispatch/certs.py | 141 ++++++++++++++++++ dispatch/config.py | 48 +++++- dispatch/db.py | 69 ++++++++- dispatch/static/css/style.css | 0 dispatch/static/js/main.js | 0 .../bootstrap-icons/bootstrap-icons.css | 0 .../bootstrap-icons/bootstrap-icons.json | 0 .../bootstrap-icons/bootstrap-icons.min.css | 0 .../bootstrap-icons/bootstrap-icons.scss | 0 .../fonts/bootstrap-icons.woff | Bin .../fonts/bootstrap-icons.woff2 | Bin .../vendor/bootstrap/css/bootstrap-grid.css | 0 .../bootstrap/css/bootstrap-grid.css.map | 0 .../bootstrap/css/bootstrap-grid.min.css | 0 .../bootstrap/css/bootstrap-grid.min.css.map | 0 .../bootstrap/css/bootstrap-grid.rtl.css | 0 .../bootstrap/css/bootstrap-grid.rtl.css.map | 0 .../bootstrap/css/bootstrap-grid.rtl.min.css | 0 .../css/bootstrap-grid.rtl.min.css.map | 0 .../vendor/bootstrap/css/bootstrap-reboot.css | 0 .../bootstrap/css/bootstrap-reboot.css.map | 0 .../bootstrap/css/bootstrap-reboot.min.css | 0 .../css/bootstrap-reboot.min.css.map | 0 .../bootstrap/css/bootstrap-reboot.rtl.css | 0 .../css/bootstrap-reboot.rtl.css.map | 0 .../css/bootstrap-reboot.rtl.min.css | 0 .../css/bootstrap-reboot.rtl.min.css.map | 0 .../bootstrap/css/bootstrap-utilities.css | 0 .../bootstrap/css/bootstrap-utilities.css.map | 0 .../bootstrap/css/bootstrap-utilities.min.css | 0 .../css/bootstrap-utilities.min.css.map | 0 .../bootstrap/css/bootstrap-utilities.rtl.css | 0 .../css/bootstrap-utilities.rtl.css.map | 0 .../css/bootstrap-utilities.rtl.min.css | 0 .../css/bootstrap-utilities.rtl.min.css.map | 0 .../static/vendor/bootstrap/css/bootstrap.css | 0 .../vendor/bootstrap/css/bootstrap.css.map | 0 .../vendor/bootstrap/css/bootstrap.min.css | 0 .../bootstrap/css/bootstrap.min.css.map | 0 .../vendor/bootstrap/css/bootstrap.rtl.css | 0 .../bootstrap/css/bootstrap.rtl.css.map | 0 .../bootstrap/css/bootstrap.rtl.min.css | 0 .../bootstrap/css/bootstrap.rtl.min.css.map | 0 .../vendor/bootstrap/js/bootstrap.bundle.js | 0 .../bootstrap/js/bootstrap.bundle.js.map | 0 .../bootstrap/js/bootstrap.bundle.min.js | 0 .../bootstrap/js/bootstrap.bundle.min.js.map | 0 .../vendor/bootstrap/js/bootstrap.esm.js | 0 .../vendor/bootstrap/js/bootstrap.esm.js.map | 0 .../vendor/bootstrap/js/bootstrap.esm.min.js | 0 .../bootstrap/js/bootstrap.esm.min.js.map | 0 .../static/vendor/bootstrap/js/bootstrap.js | 0 .../vendor/bootstrap/js/bootstrap.js.map | 0 .../vendor/bootstrap/js/bootstrap.min.js | 0 .../vendor/bootstrap/js/bootstrap.min.js.map | 0 .../static/vendor/highlightjs/darcula.css | 0 dispatch/static/vendor/highlightjs/decaf.css | 0 .../static/vendor/highlightjs/default.min.css | 0 .../vendor/highlightjs/highlight.min.js | 0 dispatch/static/vendor/highlightjs/hybrid.css | 0 dispatch/static/vendor/highlightjs/vs2015.css | 0 dispatch/static/vendor/tinymce/CHANGELOG.md | 0 dispatch/static/vendor/tinymce/README.md | 0 dispatch/static/vendor/tinymce/bower.json | 0 dispatch/static/vendor/tinymce/composer.json | 0 .../vendor/tinymce/icons/default/icons.js | 0 .../vendor/tinymce/icons/default/icons.min.js | 0 .../vendor/tinymce/icons/default/index.js | 0 dispatch/static/vendor/tinymce/license.txt | 0 .../static/vendor/tinymce/models/dom/index.js | 0 .../static/vendor/tinymce/models/dom/model.js | 0 .../vendor/tinymce/models/dom/model.min.js | 0 dispatch/static/vendor/tinymce/package.json | 0 .../vendor/tinymce/plugins/advlist/index.js | 0 .../vendor/tinymce/plugins/advlist/plugin.js | 0 .../tinymce/plugins/advlist/plugin.min.js | 0 .../vendor/tinymce/plugins/anchor/index.js | 0 .../vendor/tinymce/plugins/anchor/plugin.js | 0 .../tinymce/plugins/anchor/plugin.min.js | 0 .../vendor/tinymce/plugins/autolink/index.js | 0 .../vendor/tinymce/plugins/autolink/plugin.js | 0 .../tinymce/plugins/autolink/plugin.min.js | 0 .../tinymce/plugins/autoresize/index.js | 0 .../tinymce/plugins/autoresize/plugin.js | 0 .../tinymce/plugins/autoresize/plugin.min.js | 0 .../vendor/tinymce/plugins/autosave/index.js | 0 .../vendor/tinymce/plugins/autosave/plugin.js | 0 .../tinymce/plugins/autosave/plugin.min.js | 0 .../vendor/tinymce/plugins/charmap/index.js | 0 .../vendor/tinymce/plugins/charmap/plugin.js | 0 .../tinymce/plugins/charmap/plugin.min.js | 0 .../vendor/tinymce/plugins/code/index.js | 0 .../vendor/tinymce/plugins/code/plugin.js | 0 .../vendor/tinymce/plugins/code/plugin.min.js | 0 .../tinymce/plugins/codesample/index.js | 0 .../tinymce/plugins/codesample/plugin.js | 0 .../tinymce/plugins/codesample/plugin.min.js | 0 .../tinymce/plugins/directionality/index.js | 0 .../tinymce/plugins/directionality/plugin.js | 0 .../plugins/directionality/plugin.min.js | 0 .../vendor/tinymce/plugins/emoticons/index.js | 0 .../plugins/emoticons/js/emojiimages.js | 0 .../plugins/emoticons/js/emojiimages.min.js | 0 .../tinymce/plugins/emoticons/js/emojis.js | 0 .../plugins/emoticons/js/emojis.min.js | 0 .../tinymce/plugins/emoticons/plugin.js | 0 .../tinymce/plugins/emoticons/plugin.min.js | 0 .../tinymce/plugins/fullscreen/index.js | 0 .../tinymce/plugins/fullscreen/plugin.js | 0 .../tinymce/plugins/fullscreen/plugin.min.js | 0 .../vendor/tinymce/plugins/help/index.js | 0 .../vendor/tinymce/plugins/help/plugin.js | 0 .../vendor/tinymce/plugins/help/plugin.min.js | 0 .../vendor/tinymce/plugins/image/index.js | 0 .../vendor/tinymce/plugins/image/plugin.js | 0 .../tinymce/plugins/image/plugin.min.js | 0 .../vendor/tinymce/plugins/importcss/index.js | 0 .../tinymce/plugins/importcss/plugin.js | 0 .../tinymce/plugins/importcss/plugin.min.js | 0 .../tinymce/plugins/insertdatetime/index.js | 0 .../tinymce/plugins/insertdatetime/plugin.js | 0 .../plugins/insertdatetime/plugin.min.js | 0 .../vendor/tinymce/plugins/link/index.js | 0 .../vendor/tinymce/plugins/link/plugin.js | 0 .../vendor/tinymce/plugins/link/plugin.min.js | 0 .../vendor/tinymce/plugins/lists/index.js | 0 .../vendor/tinymce/plugins/lists/plugin.js | 0 .../tinymce/plugins/lists/plugin.min.js | 0 .../vendor/tinymce/plugins/media/index.js | 0 .../vendor/tinymce/plugins/media/plugin.js | 0 .../tinymce/plugins/media/plugin.min.js | 0 .../tinymce/plugins/nonbreaking/index.js | 0 .../tinymce/plugins/nonbreaking/plugin.js | 0 .../tinymce/plugins/nonbreaking/plugin.min.js | 0 .../vendor/tinymce/plugins/pagebreak/index.js | 0 .../tinymce/plugins/pagebreak/plugin.js | 0 .../tinymce/plugins/pagebreak/plugin.min.js | 0 .../vendor/tinymce/plugins/preview/index.js | 0 .../vendor/tinymce/plugins/preview/plugin.js | 0 .../tinymce/plugins/preview/plugin.min.js | 0 .../vendor/tinymce/plugins/quickbars/index.js | 0 .../tinymce/plugins/quickbars/plugin.js | 0 .../tinymce/plugins/quickbars/plugin.min.js | 0 .../vendor/tinymce/plugins/save/index.js | 0 .../vendor/tinymce/plugins/save/plugin.js | 0 .../vendor/tinymce/plugins/save/plugin.min.js | 0 .../tinymce/plugins/searchreplace/index.js | 0 .../tinymce/plugins/searchreplace/plugin.js | 0 .../plugins/searchreplace/plugin.min.js | 0 .../vendor/tinymce/plugins/table/index.js | 0 .../vendor/tinymce/plugins/table/plugin.js | 0 .../tinymce/plugins/table/plugin.min.js | 0 .../vendor/tinymce/plugins/template/index.js | 0 .../vendor/tinymce/plugins/template/plugin.js | 0 .../tinymce/plugins/template/plugin.min.js | 0 .../tinymce/plugins/visualblocks/index.js | 0 .../tinymce/plugins/visualblocks/plugin.js | 0 .../plugins/visualblocks/plugin.min.js | 0 .../tinymce/plugins/visualchars/index.js | 0 .../tinymce/plugins/visualchars/plugin.js | 0 .../tinymce/plugins/visualchars/plugin.min.js | 0 .../vendor/tinymce/plugins/wordcount/index.js | 0 .../tinymce/plugins/wordcount/plugin.js | 0 .../tinymce/plugins/wordcount/plugin.min.js | 0 .../tinymce/skins/content/dark/content.css | 0 .../skins/content/dark/content.min.css | 0 .../tinymce/skins/content/default/content.css | 0 .../skins/content/default/content.min.css | 0 .../skins/content/document/content.css | 0 .../skins/content/document/content.min.css | 0 .../skins/content/tinymce-5-dark/content.css | 0 .../content/tinymce-5-dark/content.min.css | 0 .../skins/content/tinymce-5/content.css | 0 .../skins/content/tinymce-5/content.min.css | 0 .../tinymce/skins/content/writer/content.css | 0 .../skins/content/writer/content.min.css | 0 .../tinymce/skins/ui/oxide-dark/content.css | 0 .../skins/ui/oxide-dark/content.inline.css | 0 .../ui/oxide-dark/content.inline.min.css | 0 .../skins/ui/oxide-dark/content.min.css | 0 .../tinymce/skins/ui/oxide-dark/skin.css | 0 .../tinymce/skins/ui/oxide-dark/skin.min.css | 0 .../skins/ui/oxide-dark/skin.shadowdom.css | 0 .../ui/oxide-dark/skin.shadowdom.min.css | 0 .../vendor/tinymce/skins/ui/oxide/content.css | 0 .../tinymce/skins/ui/oxide/content.inline.css | 0 .../skins/ui/oxide/content.inline.min.css | 0 .../tinymce/skins/ui/oxide/content.min.css | 0 .../vendor/tinymce/skins/ui/oxide/skin.css | 0 .../tinymce/skins/ui/oxide/skin.min.css | 0 .../tinymce/skins/ui/oxide/skin.shadowdom.css | 0 .../skins/ui/oxide/skin.shadowdom.min.css | 0 .../skins/ui/tinymce-5-dark/content.css | 0 .../ui/tinymce-5-dark/content.inline.css | 0 .../ui/tinymce-5-dark/content.inline.min.css | 0 .../skins/ui/tinymce-5-dark/content.min.css | 0 .../tinymce/skins/ui/tinymce-5-dark/skin.css | 0 .../skins/ui/tinymce-5-dark/skin.min.css | 0 .../ui/tinymce-5-dark/skin.shadowdom.css | 0 .../ui/tinymce-5-dark/skin.shadowdom.min.css | 0 .../tinymce/skins/ui/tinymce-5/content.css | 0 .../skins/ui/tinymce-5/content.inline.css | 0 .../skins/ui/tinymce-5/content.inline.min.css | 0 .../skins/ui/tinymce-5/content.min.css | 0 .../tinymce/skins/ui/tinymce-5/skin.css | 0 .../tinymce/skins/ui/tinymce-5/skin.min.css | 0 .../skins/ui/tinymce-5/skin.shadowdom.css | 0 .../skins/ui/tinymce-5/skin.shadowdom.min.css | 0 .../vendor/tinymce/themes/silver/index.js | 0 .../vendor/tinymce/themes/silver/theme.js | 0 .../vendor/tinymce/themes/silver/theme.min.js | 0 dispatch/static/vendor/tinymce/tinymce.d.ts | 0 dispatch/static/vendor/tinymce/tinymce.js | 0 dispatch/static/vendor/tinymce/tinymce.min.js | 0 dispatch/templates/docs/access.html | 0 dispatch/templates/docs/files.html | 0 dispatch/templates/docs/upload.html | 0 dispatch/templates/docs/users.html | 0 dispatch/templates/files/cradles.html | 0 dispatch/templates/files/create.html | 0 dispatch/templates/files/download.html | 0 dispatch/templates/files/edit.html | 0 dispatch/templates/files/upload.html | 0 dispatch/templates/img/file_permissions.png | Bin dispatch/templates/img/param_key.png | Bin dispatch/templates/img/post_build_1.png | Bin dispatch/templates/img/post_build_2.png | Bin dispatch/templates/img/user_roles.png | Bin dispatch/templates/index.html | 0 dispatch/templates/js/dispatch.js | 0 dispatch/templates/login.html | 0 dispatch/templates/master.html | 0 dispatch/templates/settings/access.html | 0 dispatch/templates/settings/log.html | 0 dispatch/templates/settings/proxy.html | 0 dispatch/templates/settings/settings.html | 57 ++++++- dispatch/templates/users/add.html | 0 dispatch/templates/users/list.html | 0 requirements.txt | 0 243 files changed, 394 insertions(+), 16 deletions(-) mode change 100755 => 100644 README.md mode change 100755 => 100644 dispatch-server.py mode change 100755 => 100644 dispatch/app.py mode change 100755 => 100644 dispatch/auth.py create mode 100644 dispatch/certs.py mode change 100755 => 100644 dispatch/config.py mode change 100755 => 100644 dispatch/db.py mode change 100755 => 100644 dispatch/static/css/style.css mode change 100755 => 100644 dispatch/static/js/main.js mode change 100755 => 100644 dispatch/static/vendor/bootstrap-icons/bootstrap-icons.css mode change 100755 => 100644 dispatch/static/vendor/bootstrap-icons/bootstrap-icons.json mode change 100755 => 100644 dispatch/static/vendor/bootstrap-icons/bootstrap-icons.min.css mode change 100755 => 100644 dispatch/static/vendor/bootstrap-icons/bootstrap-icons.scss mode change 100755 => 100644 dispatch/static/vendor/bootstrap-icons/fonts/bootstrap-icons.woff mode change 100755 => 100644 dispatch/static/vendor/bootstrap-icons/fonts/bootstrap-icons.woff2 mode change 100755 => 100644 dispatch/static/vendor/bootstrap/css/bootstrap-grid.css mode change 100755 => 100644 dispatch/static/vendor/bootstrap/css/bootstrap-grid.css.map mode change 100755 => 100644 dispatch/static/vendor/bootstrap/css/bootstrap-grid.min.css mode change 100755 => 100644 dispatch/static/vendor/bootstrap/css/bootstrap-grid.min.css.map mode change 100755 => 100644 dispatch/static/vendor/bootstrap/css/bootstrap-grid.rtl.css mode change 100755 => 100644 dispatch/static/vendor/bootstrap/css/bootstrap-grid.rtl.css.map mode change 100755 => 100644 dispatch/static/vendor/bootstrap/css/bootstrap-grid.rtl.min.css mode change 100755 => 100644 dispatch/static/vendor/bootstrap/css/bootstrap-grid.rtl.min.css.map mode change 100755 => 100644 dispatch/static/vendor/bootstrap/css/bootstrap-reboot.css mode change 100755 => 100644 dispatch/static/vendor/bootstrap/css/bootstrap-reboot.css.map mode change 100755 => 100644 dispatch/static/vendor/bootstrap/css/bootstrap-reboot.min.css mode change 100755 => 100644 dispatch/static/vendor/bootstrap/css/bootstrap-reboot.min.css.map mode change 100755 => 100644 dispatch/static/vendor/bootstrap/css/bootstrap-reboot.rtl.css mode change 100755 => 100644 dispatch/static/vendor/bootstrap/css/bootstrap-reboot.rtl.css.map mode change 100755 => 100644 dispatch/static/vendor/bootstrap/css/bootstrap-reboot.rtl.min.css mode change 100755 => 100644 dispatch/static/vendor/bootstrap/css/bootstrap-reboot.rtl.min.css.map mode change 100755 => 100644 dispatch/static/vendor/bootstrap/css/bootstrap-utilities.css mode change 100755 => 100644 dispatch/static/vendor/bootstrap/css/bootstrap-utilities.css.map mode change 100755 => 100644 dispatch/static/vendor/bootstrap/css/bootstrap-utilities.min.css mode change 100755 => 100644 dispatch/static/vendor/bootstrap/css/bootstrap-utilities.min.css.map mode change 100755 => 100644 dispatch/static/vendor/bootstrap/css/bootstrap-utilities.rtl.css mode change 100755 => 100644 dispatch/static/vendor/bootstrap/css/bootstrap-utilities.rtl.css.map mode change 100755 => 100644 dispatch/static/vendor/bootstrap/css/bootstrap-utilities.rtl.min.css mode change 100755 => 100644 dispatch/static/vendor/bootstrap/css/bootstrap-utilities.rtl.min.css.map mode change 100755 => 100644 dispatch/static/vendor/bootstrap/css/bootstrap.css mode change 100755 => 100644 dispatch/static/vendor/bootstrap/css/bootstrap.css.map mode change 100755 => 100644 dispatch/static/vendor/bootstrap/css/bootstrap.min.css mode change 100755 => 100644 dispatch/static/vendor/bootstrap/css/bootstrap.min.css.map mode change 100755 => 100644 dispatch/static/vendor/bootstrap/css/bootstrap.rtl.css mode change 100755 => 100644 dispatch/static/vendor/bootstrap/css/bootstrap.rtl.css.map mode change 100755 => 100644 dispatch/static/vendor/bootstrap/css/bootstrap.rtl.min.css mode change 100755 => 100644 dispatch/static/vendor/bootstrap/css/bootstrap.rtl.min.css.map mode change 100755 => 100644 dispatch/static/vendor/bootstrap/js/bootstrap.bundle.js mode change 100755 => 100644 dispatch/static/vendor/bootstrap/js/bootstrap.bundle.js.map mode change 100755 => 100644 dispatch/static/vendor/bootstrap/js/bootstrap.bundle.min.js mode change 100755 => 100644 dispatch/static/vendor/bootstrap/js/bootstrap.bundle.min.js.map mode change 100755 => 100644 dispatch/static/vendor/bootstrap/js/bootstrap.esm.js mode change 100755 => 100644 dispatch/static/vendor/bootstrap/js/bootstrap.esm.js.map mode change 100755 => 100644 dispatch/static/vendor/bootstrap/js/bootstrap.esm.min.js mode change 100755 => 100644 dispatch/static/vendor/bootstrap/js/bootstrap.esm.min.js.map mode change 100755 => 100644 dispatch/static/vendor/bootstrap/js/bootstrap.js mode change 100755 => 100644 dispatch/static/vendor/bootstrap/js/bootstrap.js.map mode change 100755 => 100644 dispatch/static/vendor/bootstrap/js/bootstrap.min.js mode change 100755 => 100644 dispatch/static/vendor/bootstrap/js/bootstrap.min.js.map mode change 100755 => 100644 dispatch/static/vendor/highlightjs/darcula.css mode change 100755 => 100644 dispatch/static/vendor/highlightjs/decaf.css mode change 100755 => 100644 dispatch/static/vendor/highlightjs/default.min.css mode change 100755 => 100644 dispatch/static/vendor/highlightjs/highlight.min.js mode change 100755 => 100644 dispatch/static/vendor/highlightjs/hybrid.css mode change 100755 => 100644 dispatch/static/vendor/highlightjs/vs2015.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/CHANGELOG.md mode change 100755 => 100644 dispatch/static/vendor/tinymce/README.md mode change 100755 => 100644 dispatch/static/vendor/tinymce/bower.json mode change 100755 => 100644 dispatch/static/vendor/tinymce/composer.json mode change 100755 => 100644 dispatch/static/vendor/tinymce/icons/default/icons.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/icons/default/icons.min.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/icons/default/index.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/license.txt mode change 100755 => 100644 dispatch/static/vendor/tinymce/models/dom/index.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/models/dom/model.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/models/dom/model.min.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/package.json mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/advlist/index.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/advlist/plugin.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/advlist/plugin.min.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/anchor/index.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/anchor/plugin.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/anchor/plugin.min.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/autolink/index.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/autolink/plugin.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/autolink/plugin.min.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/autoresize/index.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/autoresize/plugin.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/autoresize/plugin.min.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/autosave/index.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/autosave/plugin.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/autosave/plugin.min.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/charmap/index.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/charmap/plugin.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/charmap/plugin.min.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/code/index.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/code/plugin.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/code/plugin.min.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/codesample/index.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/codesample/plugin.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/codesample/plugin.min.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/directionality/index.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/directionality/plugin.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/directionality/plugin.min.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/emoticons/index.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/emoticons/js/emojiimages.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/emoticons/js/emojiimages.min.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/emoticons/js/emojis.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/emoticons/js/emojis.min.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/emoticons/plugin.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/emoticons/plugin.min.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/fullscreen/index.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/fullscreen/plugin.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/fullscreen/plugin.min.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/help/index.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/help/plugin.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/help/plugin.min.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/image/index.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/image/plugin.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/image/plugin.min.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/importcss/index.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/importcss/plugin.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/importcss/plugin.min.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/insertdatetime/index.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/insertdatetime/plugin.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/insertdatetime/plugin.min.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/link/index.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/link/plugin.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/link/plugin.min.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/lists/index.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/lists/plugin.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/lists/plugin.min.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/media/index.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/media/plugin.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/media/plugin.min.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/nonbreaking/index.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/nonbreaking/plugin.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/nonbreaking/plugin.min.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/pagebreak/index.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/pagebreak/plugin.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/pagebreak/plugin.min.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/preview/index.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/preview/plugin.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/preview/plugin.min.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/quickbars/index.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/quickbars/plugin.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/quickbars/plugin.min.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/save/index.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/save/plugin.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/save/plugin.min.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/searchreplace/index.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/searchreplace/plugin.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/searchreplace/plugin.min.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/table/index.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/table/plugin.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/table/plugin.min.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/template/index.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/template/plugin.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/template/plugin.min.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/visualblocks/index.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/visualblocks/plugin.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/visualblocks/plugin.min.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/visualchars/index.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/visualchars/plugin.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/visualchars/plugin.min.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/wordcount/index.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/wordcount/plugin.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/plugins/wordcount/plugin.min.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/content/dark/content.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/content/dark/content.min.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/content/default/content.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/content/default/content.min.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/content/document/content.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/content/document/content.min.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/content/tinymce-5-dark/content.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/content/tinymce-5-dark/content.min.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/content/tinymce-5/content.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/content/tinymce-5/content.min.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/content/writer/content.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/content/writer/content.min.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/ui/oxide-dark/content.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/ui/oxide-dark/content.inline.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/ui/oxide-dark/content.inline.min.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/ui/oxide-dark/content.min.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/ui/oxide-dark/skin.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/ui/oxide-dark/skin.min.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/ui/oxide-dark/skin.shadowdom.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/ui/oxide-dark/skin.shadowdom.min.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/ui/oxide/content.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/ui/oxide/content.inline.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/ui/oxide/content.inline.min.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/ui/oxide/content.min.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/ui/oxide/skin.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/ui/oxide/skin.min.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/ui/oxide/skin.shadowdom.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/ui/oxide/skin.shadowdom.min.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/ui/tinymce-5-dark/content.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/ui/tinymce-5-dark/content.inline.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/ui/tinymce-5-dark/content.inline.min.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/ui/tinymce-5-dark/content.min.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/ui/tinymce-5-dark/skin.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/ui/tinymce-5-dark/skin.min.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/ui/tinymce-5-dark/skin.shadowdom.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/ui/tinymce-5-dark/skin.shadowdom.min.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/ui/tinymce-5/content.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/ui/tinymce-5/content.inline.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/ui/tinymce-5/content.inline.min.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/ui/tinymce-5/content.min.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/ui/tinymce-5/skin.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/ui/tinymce-5/skin.min.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/ui/tinymce-5/skin.shadowdom.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/skins/ui/tinymce-5/skin.shadowdom.min.css mode change 100755 => 100644 dispatch/static/vendor/tinymce/themes/silver/index.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/themes/silver/theme.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/themes/silver/theme.min.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/tinymce.d.ts mode change 100755 => 100644 dispatch/static/vendor/tinymce/tinymce.js mode change 100755 => 100644 dispatch/static/vendor/tinymce/tinymce.min.js mode change 100755 => 100644 dispatch/templates/docs/access.html mode change 100755 => 100644 dispatch/templates/docs/files.html mode change 100755 => 100644 dispatch/templates/docs/upload.html mode change 100755 => 100644 dispatch/templates/docs/users.html mode change 100755 => 100644 dispatch/templates/files/cradles.html mode change 100755 => 100644 dispatch/templates/files/create.html mode change 100755 => 100644 dispatch/templates/files/download.html mode change 100755 => 100644 dispatch/templates/files/edit.html mode change 100755 => 100644 dispatch/templates/files/upload.html mode change 100755 => 100644 dispatch/templates/img/file_permissions.png mode change 100755 => 100644 dispatch/templates/img/param_key.png mode change 100755 => 100644 dispatch/templates/img/post_build_1.png mode change 100755 => 100644 dispatch/templates/img/post_build_2.png mode change 100755 => 100644 dispatch/templates/img/user_roles.png mode change 100755 => 100644 dispatch/templates/index.html mode change 100755 => 100644 dispatch/templates/js/dispatch.js mode change 100755 => 100644 dispatch/templates/login.html mode change 100755 => 100644 dispatch/templates/master.html mode change 100755 => 100644 dispatch/templates/settings/access.html mode change 100755 => 100644 dispatch/templates/settings/log.html mode change 100755 => 100644 dispatch/templates/settings/proxy.html mode change 100755 => 100644 dispatch/templates/settings/settings.html mode change 100755 => 100644 dispatch/templates/users/add.html mode change 100755 => 100644 dispatch/templates/users/list.html mode change 100755 => 100644 requirements.txt diff --git a/README.md b/README.md old mode 100755 new mode 100644 index 89c25b1..e75ba71 --- a/README.md +++ b/README.md @@ -56,5 +56,28 @@ Set network interfaces using command-line arguments to easily configure automati +## 🔐 Automatic TLS Certificates +Dispatch can enroll Let’s Encrypt certificates directly from the Settings UI. + +1. **Verify inbound access to ports 80/443.** HTTP-01 challenges require plaintext HTTP. From another host connect to a temporary `nc -lvnp 80` / `nc -lvnp 443` listener on the Dispatch server to confirm routing through firewalls and load balancers. +2. **Run Dispatch in HTTP mode while requesting a cert:** + ```bash + sudo python3 dispatch-server.py --http --bind-host 0.0.0.0 --bind-port 80 \ + --external-host --external-port 443 + ``` + Use a fresh browser session because cookies issued over HTTPS are marked `secure` and won’t be sent to HTTP. +3. **Open Settings → TLS Certificate Enrollment.** + - Click **Install Certbot** if it is missing. + - Provide the domain and contact email. + - Leave **Use Let’s Encrypt staging** enabled for test runs; uncheck it for production. + - Press **Request Certificate** and monitor the toast/log output (`dispatch/data/logs/dispatch.log`). +4. **Switch to production:** When staging is unchecked Dispatch automatically removes the staging lineage so Certbot reissues via the production ACME server. +5. **Restart Dispatch on HTTPS/443** after a successful enrollment: + ```bash + sudo python3 dispatch-server.py --bind-host 0.0.0.0 --bind-port 443 \ + --external-host --external-port 443 + ``` + Confirm with `openssl s_client -connect :443 -servername ` or a browser visit. + ## ⚠️ Disclaimer Dispatch is intended for authorized security testing. Never test against systems you don’t own or have explicit permission. diff --git a/dispatch-server.py b/dispatch-server.py old mode 100755 new mode 100644 index 494f22b..daf587f --- a/dispatch-server.py +++ b/dispatch-server.py @@ -9,6 +9,7 @@ import logging import argparse from dispatch import config +from dispatch import certs from dispatch.db import DispatchDB from gevent.pywsgi import WSGIServer from dispatch.app import DispatchServer @@ -31,6 +32,7 @@ def filter(self, record): return "SSLEOFError" not in record.getMessage() logging.getLogger("gevent").addFilter(IgnoreSSLEOFError()) +log = logging.getLogger('dispatch-logger') def main(): parser = argparse.ArgumentParser(description="Dispatch Server Options") @@ -84,6 +86,11 @@ def main(): else: context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) context.load_cert_chain(config.CERT_PATH, config.KEY_PATH) + try: + meta = certs.read_cert_metadata(config.CERT_PATH) + log.info(f"Loaded TLS certificate subject={meta.get('subject')} issuer={meta.get('issuer')} notAfter={meta.get('notAfter')}") + except Exception as e: + log.warning(f"Unable to log certificate metadata: {e}") # Start server print(f'[+] Starting Dispatch locally on: {"http" if args.http else "https"}://{config.INTERFACE}:{config.PORT}/\n') @@ -109,4 +116,4 @@ def main(): if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/dispatch/app.py b/dispatch/app.py old mode 100755 new mode 100644 index 428e7f2..5fec9b4 --- a/dispatch/app.py +++ b/dispatch/app.py @@ -12,6 +12,7 @@ from dispatch import auth from dispatch import config +from dispatch import certs from dispatch.db import DispatchDB log = logging.getLogger('dispatch-logger') @@ -24,6 +25,11 @@ class DispatchServer(object): app.config['allow__ua'] = [] app.config['allow_login'] = [] app.config['redirect_url'] = '' + app.config['cert_domain'] = '' + app.config['cert_email'] = '' + app.config['cert_staging'] = False + app.config['cert_status'] = 'Not Configured' + app.config['cert_last_error'] = '' @app.route('/', methods=['GET']) @auth.login_required @@ -81,6 +87,8 @@ def logout(): @app.route('/settings', methods=['GET', 'POST']) @auth.operator_required def settings(token): + cert_status_msg = '' + certbot_installed = certs.certbot_available() if request.method == 'POST': db = DispatchDB(current_app.config['db_name']) if request.form['name'] == 'ui_settings': @@ -96,9 +104,50 @@ def settings(token): db.update_allow_login(request.form['allow_login']) config.log(f"Login restrictions updated", token, request.remote_addr) + elif request.form['name'] == 'certbot_settings': + cert_domain = request.form.get('cert_domain', '').strip() + cert_email = request.form.get('cert_email', '').strip() + cert_staging = 1 if request.form.get('cert_staging', False) else 0 + action = request.form.get('action', 'save') + db.update_certbot_settings(cert_domain, cert_email, cert_staging) + cert_status_msg = Markup('') + + if action == 'install': + if certs.certbot_available(): + cert_status_msg = Markup('') + else: + try: + certs.install_certbot() + cert_status_msg = Markup('') + certbot_installed = True + except Exception as e: + err_msg = str(e) + cert_status_msg = Markup(f'') + logging.error(f"Certbot installation failed: {err_msg}") + + elif action == 'enroll': + try: + certs.request_certificate(cert_domain, cert_email, bool(cert_staging)) + cert_status_msg = Markup('') + db.update_certbot_status('Certificate issued', '') + config.log(f"Certificate enrollment completed for {cert_domain}", token, request.remote_addr) + except Exception as e: + err_msg = str(e) + cert_status_msg = Markup(f'') + db.update_certbot_status('Error', err_msg[:250]) + logging.error(f"Certificate enrollment failed: {err_msg}") + config.refresh_app_configs(db, current_app) db.close() - return render_template('settings/settings.html', token=token, config=current_app.config) + else: + certbot_installed = certs.certbot_available() + return render_template( + 'settings/settings.html', + token=token, + config=current_app.config, + cert_status_msg=cert_status_msg, + certbot_installed=certbot_installed + ) @app.route('/settings/access', methods=['GET', 'POST']) @auth.operator_required @@ -150,6 +199,16 @@ def dispatch_log(token): with open(config.DISPATCH_LOG, 'r') as f: return render_template('settings/log.html', token=token, content=escape(f.read()), config=current_app.config) + @app.route('/.well-known/acme-challenge/', methods=['GET']) + def acme_challenge(token): + if '/' in token or '..' in token: + return abort(404) + challenge_dir = os.path.join(config.CHALLENGE_PATH, '.well-known', 'acme-challenge') + challenge_file = os.path.join(challenge_dir, token) + if os.path.exists(challenge_file): + return send_file(challenge_file) + return abort(404) + # # File Interactions # @@ -864,5 +923,3 @@ def reverse_proxy(redirect_url): return Response(response.content, response.status_code, response_headers) except requests.exceptions.RequestException as e: return f"Proxy Error: {str(e)}", 502 - - diff --git a/dispatch/auth.py b/dispatch/auth.py old mode 100755 new mode 100644 diff --git a/dispatch/certs.py b/dispatch/certs.py new file mode 100644 index 0000000..2d9c192 --- /dev/null +++ b/dispatch/certs.py @@ -0,0 +1,141 @@ +import os +import sys +import ssl +import shutil +import subprocess +import logging +from os import path + +from dispatch import config + + +log = logging.getLogger('dispatch-logger') + + +def certbot_available(): + return shutil.which(config.CERTBOT_BIN) is not None + + +def install_certbot(): + """ + Attempt to install certbot using pip. Returns stdout on success. + """ + cmd = [sys.executable, '-m', 'pip', 'install', 'certbot'] + log.info("Attempting to install certbot via pip") + result = subprocess.run(cmd, capture_output=True, text=True) + if result.returncode != 0: + error_output = result.stderr if result.stderr else result.stdout + log.error(f"Certbot install failed: {error_output}") + raise RuntimeError(error_output) + log.info("Certbot installation completed.") + return result.stdout + + +def _get_acme_server(staging): + return config.LE_STAGING_ACME_URL if staging else config.LE_PROD_ACME_URL + + +def _build_certbot_command(domain, email, staging): + server = _get_acme_server(staging) + cmd = [ + config.CERTBOT_BIN, + 'certonly', + '--non-interactive', + '--agree-tos', + '--email', email, + '--webroot', + '-w', config.CHALLENGE_PATH, + '-d', domain, + '--config-dir', config.CERTBOT_CONFIG_PATH, + '--work-dir', config.CERTBOT_WORK_PATH, + '--logs-dir', config.CERTBOT_LOG_PATH, + '--preferred-challenges', 'http', + '--server', server + ] + if staging: + cmd.append('--test-cert') + return cmd + + +def _remove_lineage(domain): + live_dir = path.join(config.CERTBOT_CONFIG_PATH, 'live', domain) + archive_dir = path.join(config.CERTBOT_CONFIG_PATH, 'archive', domain) + renewal_conf = path.join(config.CERTBOT_CONFIG_PATH, 'renewal', f'{domain}.conf') + + for target in [live_dir, archive_dir]: + if path.exists(target): + shutil.rmtree(target, ignore_errors=True) + if path.exists(renewal_conf): + os.remove(renewal_conf) + + +def _renewal_server_matches(domain, staging): + renewal_conf = path.join(config.CERTBOT_CONFIG_PATH, 'renewal', f'{domain}.conf') + desired = _get_acme_server(staging) + if not path.exists(renewal_conf): + return True + try: + with open(renewal_conf, 'r') as f: + for line in f: + if line.strip().startswith('server ='): + current = line.split('=', 1)[1].strip() + return current == desired + except Exception as e: + log.debug(f"Unable to read renewal config {renewal_conf}: {e}") + return False + + +def read_cert_metadata(cert_path): + """Return subject/issuer/dates for logging.""" + try: + info = ssl._ssl._test_decode_cert(cert_path) + return { + 'subject': info.get('subject'), + 'issuer': info.get('issuer'), + 'notBefore': info.get('notBefore'), + 'notAfter': info.get('notAfter') + } + except Exception as e: + log.debug(f"Unable to decode certificate metadata for {cert_path}: {e}") + return {} + + +def request_certificate(domain, email, staging=False): + """ + Execute certbot to request/renew a certificate for the provided domain. + Certificates are placed under dispatch/data/certs/. + """ + if not domain or not email: + raise ValueError("Domain and email must be provided for certificate enrollment.") + + if not certbot_available(): + raise FileNotFoundError(f"Certbot binary '{config.CERTBOT_BIN}' was not found in PATH.") + + os.makedirs(config.CHALLENGE_PATH, exist_ok=True) + + if not _renewal_server_matches(domain, staging): + log.info(f"Detected ACME server change for {domain}. Removing existing Certbot lineage before requesting new certificate.") + _remove_lineage(domain) + + cmd = _build_certbot_command(domain, email, staging) + log.info(f"Running certbot for domain {domain} with staging={staging}") + result = subprocess.run(cmd, capture_output=True, text=True) + + if result.returncode != 0: + error_output = result.stderr if result.stderr else result.stdout + log.error(f"Certbot enrollment failed: {error_output}") + raise RuntimeError(error_output) + + live_dir = path.join(config.CERTBOT_CONFIG_PATH, 'live', domain) + fullchain_src = path.join(live_dir, 'fullchain.pem') + privkey_src = path.join(live_dir, 'privkey.pem') + + if not path.exists(fullchain_src) or not path.exists(privkey_src): + raise FileNotFoundError("Certbot did not produce the expected certificate files.") + + shutil.copy2(fullchain_src, config.CERT_PATH) + shutil.copy2(privkey_src, config.KEY_PATH) + + meta = read_cert_metadata(config.CERT_PATH) + log.info(f"Successfully updated certificate for {domain} (issuer={meta.get('issuer')}, notAfter={meta.get('notAfter')})") + return result.stdout diff --git a/dispatch/config.py b/dispatch/config.py old mode 100755 new mode 100644 index 077fb95..dd61951 --- a/dispatch/config.py +++ b/dispatch/config.py @@ -205,6 +205,11 @@ def refresh_app_configs(db, app): app.config['server_header'] = s['server_header'] app.config['MAX_CONTENT_LENGTH'] = s['max_file_size'] app.config['param_rotation'] = int(s['param_rotation']) + app.config['cert_domain'] = s.get('cert_domain', '') + app.config['cert_email'] = s.get('cert_email', '') + app.config['cert_staging'] = bool(s.get('cert_staging', 0)) + app.config['cert_status'] = s.get('cert_status', 'Not Configured') + app.config['cert_last_error'] = s.get('cert_last_error', '') def setup_debug_logger(): @@ -274,17 +279,48 @@ def dispatch_native_decrypt(b64_data, password) -> str: # # File Storage # -DB_NAME = path.join(path.dirname(path.realpath(__file__)), 'data', 'dispatch.db') -CERT_PATH = path.join(path.dirname(path.realpath(__file__)), 'data', 'certs', 'cert.crt') -KEY_PATH = path.join(path.dirname(path.realpath(__file__)), 'data', 'certs', 'key.pem') -FILE_PATH = path.join(path.dirname(path.realpath(__file__)), 'data', 'uploads') +BASE_PATH = path.dirname(path.realpath(__file__)) +DATA_PATH = path.join(BASE_PATH, 'data') +DB_NAME = path.join(DATA_PATH, 'dispatch.db') +CERT_DIR = path.join(DATA_PATH, 'certs') +CERT_PATH = path.join(CERT_DIR, 'cert.crt') +KEY_PATH = path.join(CERT_DIR, 'key.pem') +FILE_PATH = path.join(DATA_PATH, 'uploads') +CHALLENGE_PATH = path.join(DATA_PATH, 'challenges') +CERTBOT_DATA_PATH = path.join(DATA_PATH, 'certbot') +CERTBOT_CONFIG_PATH = path.join(CERTBOT_DATA_PATH, 'config') +CERTBOT_WORK_PATH = path.join(CERTBOT_DATA_PATH, 'work') +CERTBOT_LOG_PATH = path.join(CERTBOT_DATA_PATH, 'logs') # # Password protect site resources # -TMPL_PATH = path.join(path.dirname(path.realpath(__file__)), 'templates') +TMPL_PATH = path.join(BASE_PATH, 'templates') # # Log Path # -DISPATCH_LOG = path.join(path.dirname(path.realpath(__file__)), 'data', 'logs', 'dispatch.log') +DISPATCH_LOG = path.join(DATA_PATH, 'logs', 'dispatch.log') + +# +# Certificate enrollment +# +CERTBOT_BIN = os.environ.get('CERTBOT_BIN', 'certbot') +LE_PROD_ACME_URL = os.environ.get('DISPATCH_ACME_URL', 'https://acme-v02.api.letsencrypt.org/directory') +LE_STAGING_ACME_URL = 'https://acme-staging-v02.api.letsencrypt.org/directory' + +# Ensure required directories exist +CHALLENGE_WELL_KNOWN = path.join(CHALLENGE_PATH, '.well-known', 'acme-challenge') + +for required_path in [ + DATA_PATH, + CERT_DIR, + FILE_PATH, + path.dirname(DISPATCH_LOG), + CHALLENGE_PATH, + CHALLENGE_WELL_KNOWN, + CERTBOT_CONFIG_PATH, + CERTBOT_WORK_PATH, + CERTBOT_LOG_PATH +]: + os.makedirs(required_path, exist_ok=True) diff --git a/dispatch/db.py b/dispatch/db.py old mode 100755 new mode 100644 index cabbfcb..1dd1a7b --- a/dispatch/db.py +++ b/dispatch/db.py @@ -17,6 +17,7 @@ class SqliteDB: def __init__(self, db_file, timeout=3): self.db_file = db_file self.conn = connect(self.db_file, timeout=timeout, check_same_thread=False) + self.apply_migrations() def close(self): try: @@ -37,6 +38,39 @@ def exec(self, query, args=()): finally: cur.close() + def column_exists(self, table, column): + try: + result = self.exec(f"PRAGMA table_info({table});") + if result: + for row in result: + if row[1] == column: + return True + except Exception as e: + logging.debug(f"Column check error:: {e}") + return False + + def ensure_column(self, table, column, definition): + if not self.column_exists(table, column): + try: + self.exec(f"ALTER TABLE {table} ADD COLUMN {column} {definition};") + except Exception as e: + logging.debug(f"Column migration error:: {e}") + + def apply_migrations(self): + # Ensure new columns exist for legacy databases + try: + tables = self.exec("SELECT name FROM sqlite_master WHERE type='table' AND name='settings';") + if not tables: + return + self.ensure_column('settings', 'cert_domain', "TEXT DEFAULT ''") + self.ensure_column('settings', 'cert_email', "TEXT DEFAULT ''") + self.ensure_column('settings', 'cert_staging', "BOOLEAN DEFAULT 1") + self.ensure_column('settings', 'cert_status', "TEXT DEFAULT 'Not Configured'") + self.ensure_column('settings', 'cert_last_error', "TEXT DEFAULT ''") + self.ensure_column('settings', 'cert_last_attempt', "DATETIME DEFAULT (datetime('now','localtime'))") + except Exception as e: + logging.debug(f"Migration error:: {e}") + def executemany(self, query, args_list): try: cur = self.conn.cursor() @@ -97,7 +131,13 @@ class DispatchDB(SqliteDB): "server_header" TEXT, "param_rotation" BOOLEAN DEFAULT 0, "param_key" TEXT DEFAULT 's=1234', - "max_file_size" INTEGER DEFAULT {});'''.format(config.MAX_FILE_SIZE), + "max_file_size" INTEGER DEFAULT {}, + "cert_domain" TEXT DEFAULT '', + "cert_email" TEXT DEFAULT '', + "cert_staging" BOOLEAN DEFAULT 1, + "cert_status" TEXT DEFAULT 'Not Configured', + "cert_last_error" TEXT DEFAULT '', + "cert_last_attempt" DATETIME DEFAULT (datetime('now','localtime')));'''.format(config.MAX_FILE_SIZE), '''INSERT OR IGNORE INTO settings (redirect_url, source_ip, source_port, server_header) @@ -315,7 +355,8 @@ def del_file_by_id(self, file_id): def get_settings(self): data = {} sql = '''SELECT redirect_url, source_ip, source_port, param_rotation, - param_key, max_file_size, server_header FROM settings WHERE id=1;''' + param_key, max_file_size, server_header, cert_domain, cert_email, + cert_staging, cert_status, cert_last_error FROM settings WHERE id=1;''' for x in self.exec(sql): data['redirect_url'] = x[0] @@ -325,6 +366,11 @@ def get_settings(self): data['param_key'] = x[4] data['max_file_size'] = x[5] data['server_header'] = x[6] + data['cert_domain'] = x[7] + data['cert_email'] = x[8] + data['cert_staging'] = x[9] + data['cert_status'] = x[10] + data['cert_last_error'] = x[11] return data def update_settings(self, r_url, source_ip, source_port, max_size, server_header): @@ -338,6 +384,22 @@ def update_settings(self, r_url, source_ip, source_port, max_size, server_header ''' self.exec(sql, (r_url, source_ip, source_port, max_size, server_header)) + def update_certbot_settings(self, domain, email, staging): + sql = '''UPDATE settings SET + cert_domain=?, + cert_email=?, + cert_staging=? + WHERE id=1;''' + self.exec(sql, (domain, email, staging)) + + def update_certbot_status(self, status, error=''): + sql = '''UPDATE settings SET + cert_status=?, + cert_last_error=?, + cert_last_attempt=datetime('now','localtime') + WHERE id=1;''' + self.exec(sql, (status, error)) + def update_external_host(self, ip): # Update external IP/hostname for server self.exec('UPDATE settings SET source_ip=? WHERE id=1;', (ip,)) @@ -423,6 +485,3 @@ def update_allow_login(self, form_input): for x in form_input.split('\n'): if x.strip(): self.exec('INSERT OR IGNORE INTO ip_allow_login (ip) VALUES (?);',(x.strip(),)) - - - diff --git a/dispatch/static/css/style.css b/dispatch/static/css/style.css old mode 100755 new mode 100644 diff --git a/dispatch/static/js/main.js b/dispatch/static/js/main.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap-icons/bootstrap-icons.css b/dispatch/static/vendor/bootstrap-icons/bootstrap-icons.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap-icons/bootstrap-icons.json b/dispatch/static/vendor/bootstrap-icons/bootstrap-icons.json old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap-icons/bootstrap-icons.min.css b/dispatch/static/vendor/bootstrap-icons/bootstrap-icons.min.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap-icons/bootstrap-icons.scss b/dispatch/static/vendor/bootstrap-icons/bootstrap-icons.scss old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap-icons/fonts/bootstrap-icons.woff b/dispatch/static/vendor/bootstrap-icons/fonts/bootstrap-icons.woff old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap-icons/fonts/bootstrap-icons.woff2 b/dispatch/static/vendor/bootstrap-icons/fonts/bootstrap-icons.woff2 old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/css/bootstrap-grid.css b/dispatch/static/vendor/bootstrap/css/bootstrap-grid.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/css/bootstrap-grid.css.map b/dispatch/static/vendor/bootstrap/css/bootstrap-grid.css.map old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/css/bootstrap-grid.min.css b/dispatch/static/vendor/bootstrap/css/bootstrap-grid.min.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/css/bootstrap-grid.min.css.map b/dispatch/static/vendor/bootstrap/css/bootstrap-grid.min.css.map old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/css/bootstrap-grid.rtl.css b/dispatch/static/vendor/bootstrap/css/bootstrap-grid.rtl.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/css/bootstrap-grid.rtl.css.map b/dispatch/static/vendor/bootstrap/css/bootstrap-grid.rtl.css.map old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/css/bootstrap-grid.rtl.min.css b/dispatch/static/vendor/bootstrap/css/bootstrap-grid.rtl.min.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/css/bootstrap-grid.rtl.min.css.map b/dispatch/static/vendor/bootstrap/css/bootstrap-grid.rtl.min.css.map old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/css/bootstrap-reboot.css b/dispatch/static/vendor/bootstrap/css/bootstrap-reboot.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/css/bootstrap-reboot.css.map b/dispatch/static/vendor/bootstrap/css/bootstrap-reboot.css.map old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/css/bootstrap-reboot.min.css b/dispatch/static/vendor/bootstrap/css/bootstrap-reboot.min.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/css/bootstrap-reboot.min.css.map b/dispatch/static/vendor/bootstrap/css/bootstrap-reboot.min.css.map old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/css/bootstrap-reboot.rtl.css b/dispatch/static/vendor/bootstrap/css/bootstrap-reboot.rtl.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/css/bootstrap-reboot.rtl.css.map b/dispatch/static/vendor/bootstrap/css/bootstrap-reboot.rtl.css.map old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/css/bootstrap-reboot.rtl.min.css b/dispatch/static/vendor/bootstrap/css/bootstrap-reboot.rtl.min.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/css/bootstrap-reboot.rtl.min.css.map b/dispatch/static/vendor/bootstrap/css/bootstrap-reboot.rtl.min.css.map old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/css/bootstrap-utilities.css b/dispatch/static/vendor/bootstrap/css/bootstrap-utilities.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/css/bootstrap-utilities.css.map b/dispatch/static/vendor/bootstrap/css/bootstrap-utilities.css.map old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/css/bootstrap-utilities.min.css b/dispatch/static/vendor/bootstrap/css/bootstrap-utilities.min.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/css/bootstrap-utilities.min.css.map b/dispatch/static/vendor/bootstrap/css/bootstrap-utilities.min.css.map old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/css/bootstrap-utilities.rtl.css b/dispatch/static/vendor/bootstrap/css/bootstrap-utilities.rtl.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/css/bootstrap-utilities.rtl.css.map b/dispatch/static/vendor/bootstrap/css/bootstrap-utilities.rtl.css.map old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/css/bootstrap-utilities.rtl.min.css b/dispatch/static/vendor/bootstrap/css/bootstrap-utilities.rtl.min.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/css/bootstrap-utilities.rtl.min.css.map b/dispatch/static/vendor/bootstrap/css/bootstrap-utilities.rtl.min.css.map old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/css/bootstrap.css b/dispatch/static/vendor/bootstrap/css/bootstrap.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/css/bootstrap.css.map b/dispatch/static/vendor/bootstrap/css/bootstrap.css.map old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/css/bootstrap.min.css b/dispatch/static/vendor/bootstrap/css/bootstrap.min.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/css/bootstrap.min.css.map b/dispatch/static/vendor/bootstrap/css/bootstrap.min.css.map old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/css/bootstrap.rtl.css b/dispatch/static/vendor/bootstrap/css/bootstrap.rtl.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/css/bootstrap.rtl.css.map b/dispatch/static/vendor/bootstrap/css/bootstrap.rtl.css.map old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/css/bootstrap.rtl.min.css b/dispatch/static/vendor/bootstrap/css/bootstrap.rtl.min.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/css/bootstrap.rtl.min.css.map b/dispatch/static/vendor/bootstrap/css/bootstrap.rtl.min.css.map old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/js/bootstrap.bundle.js b/dispatch/static/vendor/bootstrap/js/bootstrap.bundle.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/js/bootstrap.bundle.js.map b/dispatch/static/vendor/bootstrap/js/bootstrap.bundle.js.map old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/js/bootstrap.bundle.min.js b/dispatch/static/vendor/bootstrap/js/bootstrap.bundle.min.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/js/bootstrap.bundle.min.js.map b/dispatch/static/vendor/bootstrap/js/bootstrap.bundle.min.js.map old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/js/bootstrap.esm.js b/dispatch/static/vendor/bootstrap/js/bootstrap.esm.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/js/bootstrap.esm.js.map b/dispatch/static/vendor/bootstrap/js/bootstrap.esm.js.map old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/js/bootstrap.esm.min.js b/dispatch/static/vendor/bootstrap/js/bootstrap.esm.min.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/js/bootstrap.esm.min.js.map b/dispatch/static/vendor/bootstrap/js/bootstrap.esm.min.js.map old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/js/bootstrap.js b/dispatch/static/vendor/bootstrap/js/bootstrap.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/js/bootstrap.js.map b/dispatch/static/vendor/bootstrap/js/bootstrap.js.map old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/js/bootstrap.min.js b/dispatch/static/vendor/bootstrap/js/bootstrap.min.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/bootstrap/js/bootstrap.min.js.map b/dispatch/static/vendor/bootstrap/js/bootstrap.min.js.map old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/highlightjs/darcula.css b/dispatch/static/vendor/highlightjs/darcula.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/highlightjs/decaf.css b/dispatch/static/vendor/highlightjs/decaf.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/highlightjs/default.min.css b/dispatch/static/vendor/highlightjs/default.min.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/highlightjs/highlight.min.js b/dispatch/static/vendor/highlightjs/highlight.min.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/highlightjs/hybrid.css b/dispatch/static/vendor/highlightjs/hybrid.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/highlightjs/vs2015.css b/dispatch/static/vendor/highlightjs/vs2015.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/CHANGELOG.md b/dispatch/static/vendor/tinymce/CHANGELOG.md old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/README.md b/dispatch/static/vendor/tinymce/README.md old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/bower.json b/dispatch/static/vendor/tinymce/bower.json old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/composer.json b/dispatch/static/vendor/tinymce/composer.json old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/icons/default/icons.js b/dispatch/static/vendor/tinymce/icons/default/icons.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/icons/default/icons.min.js b/dispatch/static/vendor/tinymce/icons/default/icons.min.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/icons/default/index.js b/dispatch/static/vendor/tinymce/icons/default/index.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/license.txt b/dispatch/static/vendor/tinymce/license.txt old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/models/dom/index.js b/dispatch/static/vendor/tinymce/models/dom/index.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/models/dom/model.js b/dispatch/static/vendor/tinymce/models/dom/model.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/models/dom/model.min.js b/dispatch/static/vendor/tinymce/models/dom/model.min.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/package.json b/dispatch/static/vendor/tinymce/package.json old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/advlist/index.js b/dispatch/static/vendor/tinymce/plugins/advlist/index.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/advlist/plugin.js b/dispatch/static/vendor/tinymce/plugins/advlist/plugin.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/advlist/plugin.min.js b/dispatch/static/vendor/tinymce/plugins/advlist/plugin.min.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/anchor/index.js b/dispatch/static/vendor/tinymce/plugins/anchor/index.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/anchor/plugin.js b/dispatch/static/vendor/tinymce/plugins/anchor/plugin.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/anchor/plugin.min.js b/dispatch/static/vendor/tinymce/plugins/anchor/plugin.min.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/autolink/index.js b/dispatch/static/vendor/tinymce/plugins/autolink/index.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/autolink/plugin.js b/dispatch/static/vendor/tinymce/plugins/autolink/plugin.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/autolink/plugin.min.js b/dispatch/static/vendor/tinymce/plugins/autolink/plugin.min.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/autoresize/index.js b/dispatch/static/vendor/tinymce/plugins/autoresize/index.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/autoresize/plugin.js b/dispatch/static/vendor/tinymce/plugins/autoresize/plugin.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/autoresize/plugin.min.js b/dispatch/static/vendor/tinymce/plugins/autoresize/plugin.min.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/autosave/index.js b/dispatch/static/vendor/tinymce/plugins/autosave/index.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/autosave/plugin.js b/dispatch/static/vendor/tinymce/plugins/autosave/plugin.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/autosave/plugin.min.js b/dispatch/static/vendor/tinymce/plugins/autosave/plugin.min.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/charmap/index.js b/dispatch/static/vendor/tinymce/plugins/charmap/index.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/charmap/plugin.js b/dispatch/static/vendor/tinymce/plugins/charmap/plugin.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/charmap/plugin.min.js b/dispatch/static/vendor/tinymce/plugins/charmap/plugin.min.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/code/index.js b/dispatch/static/vendor/tinymce/plugins/code/index.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/code/plugin.js b/dispatch/static/vendor/tinymce/plugins/code/plugin.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/code/plugin.min.js b/dispatch/static/vendor/tinymce/plugins/code/plugin.min.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/codesample/index.js b/dispatch/static/vendor/tinymce/plugins/codesample/index.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/codesample/plugin.js b/dispatch/static/vendor/tinymce/plugins/codesample/plugin.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/codesample/plugin.min.js b/dispatch/static/vendor/tinymce/plugins/codesample/plugin.min.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/directionality/index.js b/dispatch/static/vendor/tinymce/plugins/directionality/index.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/directionality/plugin.js b/dispatch/static/vendor/tinymce/plugins/directionality/plugin.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/directionality/plugin.min.js b/dispatch/static/vendor/tinymce/plugins/directionality/plugin.min.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/emoticons/index.js b/dispatch/static/vendor/tinymce/plugins/emoticons/index.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/emoticons/js/emojiimages.js b/dispatch/static/vendor/tinymce/plugins/emoticons/js/emojiimages.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/emoticons/js/emojiimages.min.js b/dispatch/static/vendor/tinymce/plugins/emoticons/js/emojiimages.min.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/emoticons/js/emojis.js b/dispatch/static/vendor/tinymce/plugins/emoticons/js/emojis.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/emoticons/js/emojis.min.js b/dispatch/static/vendor/tinymce/plugins/emoticons/js/emojis.min.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/emoticons/plugin.js b/dispatch/static/vendor/tinymce/plugins/emoticons/plugin.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/emoticons/plugin.min.js b/dispatch/static/vendor/tinymce/plugins/emoticons/plugin.min.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/fullscreen/index.js b/dispatch/static/vendor/tinymce/plugins/fullscreen/index.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/fullscreen/plugin.js b/dispatch/static/vendor/tinymce/plugins/fullscreen/plugin.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/fullscreen/plugin.min.js b/dispatch/static/vendor/tinymce/plugins/fullscreen/plugin.min.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/help/index.js b/dispatch/static/vendor/tinymce/plugins/help/index.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/help/plugin.js b/dispatch/static/vendor/tinymce/plugins/help/plugin.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/help/plugin.min.js b/dispatch/static/vendor/tinymce/plugins/help/plugin.min.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/image/index.js b/dispatch/static/vendor/tinymce/plugins/image/index.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/image/plugin.js b/dispatch/static/vendor/tinymce/plugins/image/plugin.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/image/plugin.min.js b/dispatch/static/vendor/tinymce/plugins/image/plugin.min.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/importcss/index.js b/dispatch/static/vendor/tinymce/plugins/importcss/index.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/importcss/plugin.js b/dispatch/static/vendor/tinymce/plugins/importcss/plugin.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/importcss/plugin.min.js b/dispatch/static/vendor/tinymce/plugins/importcss/plugin.min.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/insertdatetime/index.js b/dispatch/static/vendor/tinymce/plugins/insertdatetime/index.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/insertdatetime/plugin.js b/dispatch/static/vendor/tinymce/plugins/insertdatetime/plugin.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/insertdatetime/plugin.min.js b/dispatch/static/vendor/tinymce/plugins/insertdatetime/plugin.min.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/link/index.js b/dispatch/static/vendor/tinymce/plugins/link/index.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/link/plugin.js b/dispatch/static/vendor/tinymce/plugins/link/plugin.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/link/plugin.min.js b/dispatch/static/vendor/tinymce/plugins/link/plugin.min.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/lists/index.js b/dispatch/static/vendor/tinymce/plugins/lists/index.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/lists/plugin.js b/dispatch/static/vendor/tinymce/plugins/lists/plugin.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/lists/plugin.min.js b/dispatch/static/vendor/tinymce/plugins/lists/plugin.min.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/media/index.js b/dispatch/static/vendor/tinymce/plugins/media/index.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/media/plugin.js b/dispatch/static/vendor/tinymce/plugins/media/plugin.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/media/plugin.min.js b/dispatch/static/vendor/tinymce/plugins/media/plugin.min.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/nonbreaking/index.js b/dispatch/static/vendor/tinymce/plugins/nonbreaking/index.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/nonbreaking/plugin.js b/dispatch/static/vendor/tinymce/plugins/nonbreaking/plugin.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/nonbreaking/plugin.min.js b/dispatch/static/vendor/tinymce/plugins/nonbreaking/plugin.min.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/pagebreak/index.js b/dispatch/static/vendor/tinymce/plugins/pagebreak/index.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/pagebreak/plugin.js b/dispatch/static/vendor/tinymce/plugins/pagebreak/plugin.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/pagebreak/plugin.min.js b/dispatch/static/vendor/tinymce/plugins/pagebreak/plugin.min.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/preview/index.js b/dispatch/static/vendor/tinymce/plugins/preview/index.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/preview/plugin.js b/dispatch/static/vendor/tinymce/plugins/preview/plugin.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/preview/plugin.min.js b/dispatch/static/vendor/tinymce/plugins/preview/plugin.min.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/quickbars/index.js b/dispatch/static/vendor/tinymce/plugins/quickbars/index.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/quickbars/plugin.js b/dispatch/static/vendor/tinymce/plugins/quickbars/plugin.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/quickbars/plugin.min.js b/dispatch/static/vendor/tinymce/plugins/quickbars/plugin.min.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/save/index.js b/dispatch/static/vendor/tinymce/plugins/save/index.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/save/plugin.js b/dispatch/static/vendor/tinymce/plugins/save/plugin.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/save/plugin.min.js b/dispatch/static/vendor/tinymce/plugins/save/plugin.min.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/searchreplace/index.js b/dispatch/static/vendor/tinymce/plugins/searchreplace/index.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/searchreplace/plugin.js b/dispatch/static/vendor/tinymce/plugins/searchreplace/plugin.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/searchreplace/plugin.min.js b/dispatch/static/vendor/tinymce/plugins/searchreplace/plugin.min.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/table/index.js b/dispatch/static/vendor/tinymce/plugins/table/index.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/table/plugin.js b/dispatch/static/vendor/tinymce/plugins/table/plugin.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/table/plugin.min.js b/dispatch/static/vendor/tinymce/plugins/table/plugin.min.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/template/index.js b/dispatch/static/vendor/tinymce/plugins/template/index.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/template/plugin.js b/dispatch/static/vendor/tinymce/plugins/template/plugin.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/template/plugin.min.js b/dispatch/static/vendor/tinymce/plugins/template/plugin.min.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/visualblocks/index.js b/dispatch/static/vendor/tinymce/plugins/visualblocks/index.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/visualblocks/plugin.js b/dispatch/static/vendor/tinymce/plugins/visualblocks/plugin.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/visualblocks/plugin.min.js b/dispatch/static/vendor/tinymce/plugins/visualblocks/plugin.min.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/visualchars/index.js b/dispatch/static/vendor/tinymce/plugins/visualchars/index.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/visualchars/plugin.js b/dispatch/static/vendor/tinymce/plugins/visualchars/plugin.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/visualchars/plugin.min.js b/dispatch/static/vendor/tinymce/plugins/visualchars/plugin.min.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/wordcount/index.js b/dispatch/static/vendor/tinymce/plugins/wordcount/index.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/wordcount/plugin.js b/dispatch/static/vendor/tinymce/plugins/wordcount/plugin.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/plugins/wordcount/plugin.min.js b/dispatch/static/vendor/tinymce/plugins/wordcount/plugin.min.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/content/dark/content.css b/dispatch/static/vendor/tinymce/skins/content/dark/content.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/content/dark/content.min.css b/dispatch/static/vendor/tinymce/skins/content/dark/content.min.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/content/default/content.css b/dispatch/static/vendor/tinymce/skins/content/default/content.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/content/default/content.min.css b/dispatch/static/vendor/tinymce/skins/content/default/content.min.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/content/document/content.css b/dispatch/static/vendor/tinymce/skins/content/document/content.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/content/document/content.min.css b/dispatch/static/vendor/tinymce/skins/content/document/content.min.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/content/tinymce-5-dark/content.css b/dispatch/static/vendor/tinymce/skins/content/tinymce-5-dark/content.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/content/tinymce-5-dark/content.min.css b/dispatch/static/vendor/tinymce/skins/content/tinymce-5-dark/content.min.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/content/tinymce-5/content.css b/dispatch/static/vendor/tinymce/skins/content/tinymce-5/content.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/content/tinymce-5/content.min.css b/dispatch/static/vendor/tinymce/skins/content/tinymce-5/content.min.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/content/writer/content.css b/dispatch/static/vendor/tinymce/skins/content/writer/content.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/content/writer/content.min.css b/dispatch/static/vendor/tinymce/skins/content/writer/content.min.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/ui/oxide-dark/content.css b/dispatch/static/vendor/tinymce/skins/ui/oxide-dark/content.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/ui/oxide-dark/content.inline.css b/dispatch/static/vendor/tinymce/skins/ui/oxide-dark/content.inline.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/ui/oxide-dark/content.inline.min.css b/dispatch/static/vendor/tinymce/skins/ui/oxide-dark/content.inline.min.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/ui/oxide-dark/content.min.css b/dispatch/static/vendor/tinymce/skins/ui/oxide-dark/content.min.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/ui/oxide-dark/skin.css b/dispatch/static/vendor/tinymce/skins/ui/oxide-dark/skin.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/ui/oxide-dark/skin.min.css b/dispatch/static/vendor/tinymce/skins/ui/oxide-dark/skin.min.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/ui/oxide-dark/skin.shadowdom.css b/dispatch/static/vendor/tinymce/skins/ui/oxide-dark/skin.shadowdom.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/ui/oxide-dark/skin.shadowdom.min.css b/dispatch/static/vendor/tinymce/skins/ui/oxide-dark/skin.shadowdom.min.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/ui/oxide/content.css b/dispatch/static/vendor/tinymce/skins/ui/oxide/content.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/ui/oxide/content.inline.css b/dispatch/static/vendor/tinymce/skins/ui/oxide/content.inline.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/ui/oxide/content.inline.min.css b/dispatch/static/vendor/tinymce/skins/ui/oxide/content.inline.min.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/ui/oxide/content.min.css b/dispatch/static/vendor/tinymce/skins/ui/oxide/content.min.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/ui/oxide/skin.css b/dispatch/static/vendor/tinymce/skins/ui/oxide/skin.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/ui/oxide/skin.min.css b/dispatch/static/vendor/tinymce/skins/ui/oxide/skin.min.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/ui/oxide/skin.shadowdom.css b/dispatch/static/vendor/tinymce/skins/ui/oxide/skin.shadowdom.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/ui/oxide/skin.shadowdom.min.css b/dispatch/static/vendor/tinymce/skins/ui/oxide/skin.shadowdom.min.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/ui/tinymce-5-dark/content.css b/dispatch/static/vendor/tinymce/skins/ui/tinymce-5-dark/content.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/ui/tinymce-5-dark/content.inline.css b/dispatch/static/vendor/tinymce/skins/ui/tinymce-5-dark/content.inline.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/ui/tinymce-5-dark/content.inline.min.css b/dispatch/static/vendor/tinymce/skins/ui/tinymce-5-dark/content.inline.min.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/ui/tinymce-5-dark/content.min.css b/dispatch/static/vendor/tinymce/skins/ui/tinymce-5-dark/content.min.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/ui/tinymce-5-dark/skin.css b/dispatch/static/vendor/tinymce/skins/ui/tinymce-5-dark/skin.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/ui/tinymce-5-dark/skin.min.css b/dispatch/static/vendor/tinymce/skins/ui/tinymce-5-dark/skin.min.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/ui/tinymce-5-dark/skin.shadowdom.css b/dispatch/static/vendor/tinymce/skins/ui/tinymce-5-dark/skin.shadowdom.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/ui/tinymce-5-dark/skin.shadowdom.min.css b/dispatch/static/vendor/tinymce/skins/ui/tinymce-5-dark/skin.shadowdom.min.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/ui/tinymce-5/content.css b/dispatch/static/vendor/tinymce/skins/ui/tinymce-5/content.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/ui/tinymce-5/content.inline.css b/dispatch/static/vendor/tinymce/skins/ui/tinymce-5/content.inline.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/ui/tinymce-5/content.inline.min.css b/dispatch/static/vendor/tinymce/skins/ui/tinymce-5/content.inline.min.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/ui/tinymce-5/content.min.css b/dispatch/static/vendor/tinymce/skins/ui/tinymce-5/content.min.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/ui/tinymce-5/skin.css b/dispatch/static/vendor/tinymce/skins/ui/tinymce-5/skin.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/ui/tinymce-5/skin.min.css b/dispatch/static/vendor/tinymce/skins/ui/tinymce-5/skin.min.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/ui/tinymce-5/skin.shadowdom.css b/dispatch/static/vendor/tinymce/skins/ui/tinymce-5/skin.shadowdom.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/skins/ui/tinymce-5/skin.shadowdom.min.css b/dispatch/static/vendor/tinymce/skins/ui/tinymce-5/skin.shadowdom.min.css old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/themes/silver/index.js b/dispatch/static/vendor/tinymce/themes/silver/index.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/themes/silver/theme.js b/dispatch/static/vendor/tinymce/themes/silver/theme.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/themes/silver/theme.min.js b/dispatch/static/vendor/tinymce/themes/silver/theme.min.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/tinymce.d.ts b/dispatch/static/vendor/tinymce/tinymce.d.ts old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/tinymce.js b/dispatch/static/vendor/tinymce/tinymce.js old mode 100755 new mode 100644 diff --git a/dispatch/static/vendor/tinymce/tinymce.min.js b/dispatch/static/vendor/tinymce/tinymce.min.js old mode 100755 new mode 100644 diff --git a/dispatch/templates/docs/access.html b/dispatch/templates/docs/access.html old mode 100755 new mode 100644 diff --git a/dispatch/templates/docs/files.html b/dispatch/templates/docs/files.html old mode 100755 new mode 100644 diff --git a/dispatch/templates/docs/upload.html b/dispatch/templates/docs/upload.html old mode 100755 new mode 100644 diff --git a/dispatch/templates/docs/users.html b/dispatch/templates/docs/users.html old mode 100755 new mode 100644 diff --git a/dispatch/templates/files/cradles.html b/dispatch/templates/files/cradles.html old mode 100755 new mode 100644 diff --git a/dispatch/templates/files/create.html b/dispatch/templates/files/create.html old mode 100755 new mode 100644 diff --git a/dispatch/templates/files/download.html b/dispatch/templates/files/download.html old mode 100755 new mode 100644 diff --git a/dispatch/templates/files/edit.html b/dispatch/templates/files/edit.html old mode 100755 new mode 100644 diff --git a/dispatch/templates/files/upload.html b/dispatch/templates/files/upload.html old mode 100755 new mode 100644 diff --git a/dispatch/templates/img/file_permissions.png b/dispatch/templates/img/file_permissions.png old mode 100755 new mode 100644 diff --git a/dispatch/templates/img/param_key.png b/dispatch/templates/img/param_key.png old mode 100755 new mode 100644 diff --git a/dispatch/templates/img/post_build_1.png b/dispatch/templates/img/post_build_1.png old mode 100755 new mode 100644 diff --git a/dispatch/templates/img/post_build_2.png b/dispatch/templates/img/post_build_2.png old mode 100755 new mode 100644 diff --git a/dispatch/templates/img/user_roles.png b/dispatch/templates/img/user_roles.png old mode 100755 new mode 100644 diff --git a/dispatch/templates/index.html b/dispatch/templates/index.html old mode 100755 new mode 100644 diff --git a/dispatch/templates/js/dispatch.js b/dispatch/templates/js/dispatch.js old mode 100755 new mode 100644 diff --git a/dispatch/templates/login.html b/dispatch/templates/login.html old mode 100755 new mode 100644 diff --git a/dispatch/templates/master.html b/dispatch/templates/master.html old mode 100755 new mode 100644 diff --git a/dispatch/templates/settings/access.html b/dispatch/templates/settings/access.html old mode 100755 new mode 100644 diff --git a/dispatch/templates/settings/log.html b/dispatch/templates/settings/log.html old mode 100755 new mode 100644 diff --git a/dispatch/templates/settings/proxy.html b/dispatch/templates/settings/proxy.html old mode 100755 new mode 100644 diff --git a/dispatch/templates/settings/settings.html b/dispatch/templates/settings/settings.html old mode 100755 new mode 100644 index ce16eb8..e4ef5e2 --- a/dispatch/templates/settings/settings.html +++ b/dispatch/templates/settings/settings.html @@ -108,7 +108,62 @@
Login Allow List
+ + +
+
+
TLS Certificate Enrollment
+

+ Automate certificate issuance with Certbot. Dispatch will call the Certbot CLI using the HTTP-01 challenge, + so ensure TCP/80 routes to this server and that certbot is installed. +

+ {% if cert_status_msg %} + {{ cert_status_msg|safe }} + {% endif %} +
+ +
+ + +
+
+ + +
+
+
+ + +
+
+
+
Certbot Installed: {{ 'Yes' if certbot_installed else 'No' }}
+
Current Certificate Status: {{ config['cert_status'] }}
+ {% if config['cert_last_error'] %} +
Last error: {{ config['cert_last_error'] }}
+ {% endif %} +
+
+ +
+
+ +
+
+ +
+
+
+
{% endblock %} {% block html_footer %} -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/dispatch/templates/users/add.html b/dispatch/templates/users/add.html old mode 100755 new mode 100644 diff --git a/dispatch/templates/users/list.html b/dispatch/templates/users/list.html old mode 100755 new mode 100644 diff --git a/requirements.txt b/requirements.txt old mode 100755 new mode 100644