UI - load config template from json

This commit is contained in:
bunkerity 2020-12-22 22:35:15 +01:00
parent 459bb8ea1c
commit bd7b6af668
No known key found for this signature in database
GPG Key ID: 654FFF51CEF7CC47
6 changed files with 605 additions and 35 deletions

512
ui/config.json Normal file
View File

@ -0,0 +1,512 @@
{
"max-client-size":{
"category":"Misc",
"type":"text",
"label":"Max client size",
"env":"MAX_CLIENT_SIZE"
},
"allowed-methods":{
"category":"Misc",
"type":"text",
"label":"Allowed methods",
"env":"ALLOWED_METHODS"
},
"serve-files":{
"category":"Misc",
"type":"checkbox",
"label":"Serve files",
"env":"SERVE_FILES"
},
"remove-headers":{
"category":"Info leak",
"type":"text",
"label":"Remove headers",
"env":"REMOVE_HEADERS"
},
"use-auth-basic":{
"category":"Basic auth",
"type":"checkbox",
"label":"Use auth basic",
"env":"USE_AUTH_BASIC"
},
"auth-basic-location":{
"category":"Basic auth",
"type":"text",
"label":"Auth basic location",
"env":"AUTH_BASIC_LOCATION"
},
"auth-basic-user":{
"category":"Basic auth",
"type":"text",
"label":"Auth basic user",
"env":"AUTH_BASIC_USER"
},
"auth-basic-password":{
"category":"Basic auth",
"type":"text",
"label":"Auth basic password",
"env":"AUTH_BASIC_PASSWORD"
},
"auth-basic-text":{
"category":"Basic auth",
"type":"text",
"label":"Auth basic text",
"env":"AUTH_BASIC_TEXT"
},
"use-reverse-proxy":{
"category":"Reverse proxy",
"type":"checkbox",
"label":"Use reverse proxy",
"env":"USE_REVERSE_PROXY"
},
"reverse-proxy-url":{
"category":"Reverse proxy",
"type":"text",
"label":"Reverse proxy url",
"env":"REVERSE_PROXY_URL"
},
"reverse-proxy-host":{
"category":"Reverse proxy",
"type":"text",
"label":"Reverse proxy host",
"env":"REVERSE_PROXY_HOST"
},
"reverse-proxy-ws":{
"category":"Reverse proxy",
"type":"checkbox",
"label":"Reverse proxy ws",
"env":"REVERSE_PROXY_WS"
},
"proxy-real-ip":{
"category":"Reverse proxy",
"type":"checkbox",
"label":"Proxy real ip",
"env":"PROXY_REAL_IP"
},
"proxy-real-ip-from":{
"category":"Reverse proxy",
"type":"text",
"label":"Proxy real ip from",
"env":"PROXY_REAL_IP_FROM"
},
"proxy-real-ip-header":{
"category":"Reverse proxy",
"type":"text",
"label":"Proxy real ip header",
"env":"PROXY_REAL_IP_HEADER"
},
"proxy-real-ip-recursive":{
"category":"Reverse proxy",
"type":"text",
"label":"Proxy real ip recursive",
"env":"PROXY_REAL_IP_RECURSIVE"
},
"use-gzip":{
"category":"Compression",
"type":"checkbox",
"label":"Use gzip",
"env":"USE_GZIP"
},
"gzip-comp-level":{
"category":"Compression",
"type":"text",
"label":"Gzip comp level",
"env":"GZIP_COMP_LEVEL"
},
"gzip-min-length":{
"category":"Compression",
"type":"text",
"label":"Gzip min length",
"env":"GZIP_MIN_LENGTH"
},
"gzip-types":{
"category":"Compression",
"type":"text",
"label":"Gzip types",
"env":"GZIP_TYPES"
},
"use-brotli":{
"category":"Compression",
"type":"checkbox",
"label":"Use brotli",
"env":"USE_BROTLI"
},
"brotli-comp-level":{
"category":"Compression",
"type":"text",
"label":"Brotli comp level",
"env":"BROTLI_COMP_LEVEL"
},
"brotli-min-length":{
"category":"Compression",
"type":"text",
"label":"Brotli min length",
"env":"BROTLI_MIN_LENGTH"
},
"brotli-types":{
"category":"Compression",
"type":"text",
"label":"Brotli types",
"env":"BROTLI_TYPES"
},
"use-client-cache":{
"category":"Cache",
"type":"checkbox",
"label":"Use client cache",
"env":"USE_CLIENT_CACHE"
},
"client-cache-extensions":{
"category":"Cache",
"type":"text",
"label":"Client cache extensions",
"env":"CLIENT_CACHE_EXTENSIONS"
},
"client-cache-control":{
"category":"Cache",
"type":"text",
"label":"Client cache control",
"env":"CLIENT_CACHE_CONTROL"
},
"client-cache-etag":{
"category":"Cache",
"type":"text",
"label":"Client cache etag",
"env":"CLIENT_CACHE_ETAG"
},
"use-open-file-cache":{
"category":"Cache",
"type":"checkbox",
"label":"Use open file cache",
"env":"USE_OPEN_FILE_CACHE"
},
"open-file-cache":{
"category":"Cache",
"type":"text",
"label":"Open file cache",
"env":"OPEN_FILE_CACHE"
},
"open-file-cache-errors":{
"category":"Cache",
"type":"text",
"label":"Open file cache errors",
"env":"OPEN_FILE_CACHE_ERRORS"
},
"open-file-cache-min-uses":{
"category":"Cache",
"type":"text",
"label":"Open file cache min uses",
"env":"OPEN_FILE_CACHE_MIN_USES"
},
"open-file-cache-valid":{
"category":"Cache",
"type":"text",
"label":"Open file cache valid",
"env":"OPEN_FILE_CACHE_VALID"
},
"use-proxy-cache":{
"category":"Cache",
"type":"checkbox",
"label":"Use proxy cache",
"env":"USE_PROXY_CACHE"
},
"proxy-cache-path-zone-size":{
"category":"Cache",
"type":"text",
"label":"Proxy cache path zone size",
"env":"PROXY_CACHE_PATH_ZONE_SIZE"
},
"proxy-cache-path-params":{
"category":"Cache",
"type":"text",
"label":"Proxy cache path params",
"env":"PROXY_CACHE_PATH_PARAMS"
},
"proxy-cache-methods":{
"category":"Cache",
"type":"text",
"label":"Proxy cache methods",
"env":"PROXY_CACHE_METHODS"
},
"proxy-cache-min-uses":{
"category":"Cache",
"type":"text",
"label":"Proxy cache min uses",
"env":"PROXY_CACHE_MIN_USES"
},
"proxy-cache-key":{
"category":"Cache",
"type":"text",
"label":"Proxy cache key",
"env":"PROXY_CACHE_KEY"
},
"proxy-cache-valid":{
"category":"Cache",
"type":"text",
"label":"Proxy cache valid",
"env":"PROXY_CACHE_VALID"
},
"proxy-no-cache":{
"category":"Cache",
"type":"text",
"label":"Proxy no cache",
"env":"PROXY_NO_CACHE"
},
"proxy-cache-bypass":{
"category":"Cache",
"type":"text",
"label":"Proxy cache bypass",
"env":"PROXY_CACHE_BYPASS"
},
"auto-lets-encrypt":{
"category":"HTTPS",
"type":"checkbox",
"label":"Auto lets encrypt",
"env":"AUTO_LETS_ENCRYPT"
},
"email-lets-encrypt":{
"category":"HTTPS",
"type":"text",
"label":"Email lets encrypt",
"env":"EMAIL_LETS_ENCRYPT"
},
"listen-http":{
"category":"",
"type":"checkbox",
"label":"Listen http",
"env":"LISTEN_HTTP"
},
"redirect-http-to-https":{
"category":"HTTPS",
"type":"checkbox",
"label":"Redirect http to https",
"env":"REDIRECT_HTTP_TO_HTTPS"
},
"http2":{
"category":"HTTPS",
"type":"checkbox",
"label":"HTTP2",
"env":"HTTP2"
},
"https-protocols":{
"category":"HTTPS",
"type":"text",
"label":"HTTPS protocols",
"env":"HTTPS_PROTOCOLS"
},
"use-modsecurity":{
"category":"ModSecurity",
"type":"checkbox",
"label":"Use modsecurity",
"env":"USE_MODSECURITY"
},
"use-modsecurity-crs":{
"category":"ModSecurity",
"type":"checkbox",
"label":"Use modsecurity crs",
"env":"USE_MODSECURITY_CRS"
},
"x-frame-options":{
"category":"Headers",
"type":"text",
"label":"X frame options",
"env":"X_FRAME_OPTIONS"
},
"x-xss-protection":{
"category":"Headers",
"type":"text",
"label":"X xss protection",
"env":"X_XSS_PROTECTION"
},
"x-content-type-options":{
"category":"Headers",
"type":"text",
"label":"X content type options",
"env":"X_CONTENT_TYPE_OPTIONS"
},
"referrer-policy":{
"category":"Headers",
"type":"text",
"label":"Referrer policy",
"env":"REFERRER_POLICY"
},
"feature-policy":{
"category":"Headers",
"type":"text",
"label":"Feature policy",
"env":"FEATURE_POLICY"
},
"permissions-policy":{
"category":"Headers",
"type":"text",
"label":"Permissions policy",
"env":"PERMISSIONS_POLICY"
},
"cookie-flags":{
"category":"Headers",
"type":"text",
"label":"Cookie flags",
"env":"COOKIE_FLAGS"
},
"cookie-auto-secure-flag":{
"category":"Headers",
"type":"checkbox",
"label":"Cookie auto secure flag",
"env":"COOKIE_AUTO_SECURE_FLAG"
},
"strict-transport-security":{
"category":"Headers",
"type":"text",
"label":"Strict transport security",
"env":"STRICT_TRANSPORT_SECURITY"
},
"content-security-policy":{
"category":"Headers",
"type":"text",
"label":"Content security policy",
"env":"CONTENT_SECURITY_POLICY"
},
"use-antibot":{
"category":"Antibot",
"type":"text",
"label":"Use antibot",
"env":"USE_ANTIBOT"
},
"antibot-uri":{
"category":"Antibot",
"type":"text",
"label":"Antibot uri",
"env":"ANTIBOT_URI"
},
"antibot-session-secret":{
"category":"Antibot",
"type":"text",
"label":"Antibot session secret",
"env":"ANTIBOT_SESSION_SECRET"
},
"antibot-recaptcha-score":{
"category":"Antibot",
"type":"text",
"label":"Antibot recaptcha score",
"env":"ANTIBOT_RECAPTCHA_SCORE"
},
"block-user-agent":{
"category":"Block",
"type":"checkbox",
"label":"Block user agent",
"env":"BLOCK_USER_AGENT"
},
"block-tor-exit-node":{
"category":"Block",
"type":"checkbox",
"label":"Block tor exit node",
"env":"BLOCK_TOR_EXIT_NODE"
},
"block-proxies":{
"category":"Block",
"type":"checkbox",
"label":"Block proxies",
"env":"BLOCK_PROXIES"
},
"block-abusers":{
"category":"Block",
"type":"checkbox",
"label":"Block abusers",
"env":"BLOCK_ABUSERS"
},
"block-referrer":{
"category":"Block",
"type":"checkbox",
"label":"Block referrer",
"env":"BLOCK_REFERRER"
},
"use-dnsbl":{
"category":"DNSBL",
"type":"checkbox",
"label":"Use dnsbl",
"env":"USE_DNSBL"
},
"use-crowdsec":{
"category":"CrowdSec",
"type":"checkbox",
"label":"Use crowdsec",
"env":"USE_CROWDSEC"
},
"use-whitelist-ip":{
"category":"Whitelist",
"type":"checkbox",
"label":"Use whitelist ip",
"env":"USE_WHITELIST_IP"
},
"use-whitelist-reverse":{
"category":"Whitelist",
"type":"checkbox",
"label":"Use whitelist reverse",
"env":"USE_WHITELIST_REVERSE"
},
"use-blacklist-ip":{
"category":"Blacklist",
"type":"checkbox",
"label":"Use blacklist ip",
"env":"USE_BLACKLIST_IP"
},
"use-blacklist-reverse":{
"category":"Blacklist",
"type":"checkbox",
"label":"Use blacklist reverse",
"env":"USE_BLACKLIST_REVERSE"
},
"use-limit-req":{
"category":"Limit req",
"type":"checkbox",
"label":"Use limit req",
"env":"USE_LIMIT_REQ"
},
"limit-req-rate":{
"category":"Limit req",
"type":"text",
"label":"Limit req rate",
"env":"LIMIT_REQ_RATE"
},
"limit-req-burst":{
"category":"Limit req",
"type":"text",
"label":"Limit req burst",
"env":"LIMIT_REQ_BURST"
},
"blacklist-country":{
"category":"Blacklist",
"type":"text",
"label":"Blacklist country",
"env":"BLACKLIST_COUNTRY"
},
"whitelist-country":{
"category":"Whitelist",
"type":"text",
"label":"Whitelist country",
"env":"WHITELIST_COUNTRY"
},
"remote-php":{
"category":"PHP",
"type":"text",
"label":"Remote php",
"env":"REMOTE_PHP"
},
"remote-php-path":{
"category":"PHP",
"type":"text",
"label":"Remote php path",
"env":"REMOTE_PHP_PATH"
},
"use-fail2ban":{
"category":"PHP",
"type":"checkbox",
"label":"Use fail2ban",
"env":"USE_FAIL2BAN"
},
"use-clamav-upload":{
"category":"ClamAV",
"type":"checkbox",
"label":"Use clamav upload",
"env":"USE_CLAMAV_UPLOAD"
}
}

View File

@ -3,14 +3,25 @@
from flask import Flask, render_template, current_app
import wrappers, utils
import os
import os, json
app = Flask(__name__, static_url_path="/", static_folder="static", template_folder="templates")
ABSOLUTE_URI = ""
if "ABSOLUTE_URI" in os.environ :
ABSOLUTE_URI = os.environ["ABSOLUTE_URI"]
app.config["ABSOLUTE_URI"] = ABSOLUTE_URI
with open("/opt/entrypoint/config.json", "r") as f :
config = json.loads(f.read())
app.config["CONFIG"] = {}
for k in config :
if not config[k]["category"] in app.config["CONFIG"] :
app.config["CONFIG"][config[k]["category"]] = []
tmp = config[k].copy()
tmp["id"] = k
app.config["CONFIG"][config[k]["category"]].append(tmp)
app.jinja_env.globals.update(env_to_summary_class=utils.env_to_summary_class)
app.jinja_env.globals.update(form_service_gen=utils.form_service_gen)
@app.route('/')
@app.route('/home')

View File

@ -0,0 +1,17 @@
<div class="modal fade" id="modal-delete-id-{{ service["SERVER_NAME"].replace(".", "-") }}" tabindex="-1" aria-labelledby="modal-delete-label-{{ service["SERVER_NAME"].replace(".", "-") }}" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modal-delete-label-{{ service["SERVER_NAME"].replace(".", "-") }}">Delete {{ service["SERVER_NAME"] }} configuration</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
Are you sure you want to delete the configuration of {{ service["SERVER_NAME"] }} ?
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" class="btn btn-danger">Delete</button>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,42 @@
{% set id_server_name = service["SERVER_NAME"].replace(".", "-") %}
<div class="modal fade" id="modal-edit-id-{{ id_server_name }}" tabindex="-1" aria-labelledby="modal-edit-label-{{ id_server_name }}" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modal-edit-label-{{ id_server_name }}">View/edit {{ service["SERVER_NAME"] }} configuration</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<ul class="nav nav-pills mb-3" id="pills-tab" role="tablist">
{% set check = {"active": "active", "selected": "true"} %}
{% for category in config["CONFIG"] %}
{% set id_category = category.replace(" ", "") %}
<li class="nav-item" role="presentation">
<a class="nav-link {{ check.active }}" id="edit-{{ id_category }}-{{ id_server_name }}-tab" data-bs-toggle="pill" href="#edit-{{ id_category }}-{{ id_server_name }}" role="tab" aria-controls="edit-{{ id_category }}-{{ id_server_name }}" aria-selected="{{ check.selected }}">{{ category }}</a>
</li>
{% if check.update({"active": "", "selected": "false"}) %}
{% endif %}
{% endfor %}
</ul>
<div class="tab-content" id="edit-content-{{ id_server_name }}">
{% set check = {"class": "show active"} %}
{% for category in config["CONFIG"] %}
{% set id_category = category.replace(" ", "") %}
<div class="tab-pane fade {{ check.class }}" id="edit-{{ id_category }}-{{ id_server_name }}" role="tabpanel" aria-labelledby="edit-{{ id_category }}-{{ id_server_name }}-tab">
{% for config in config["CONFIG"][category] %}
{{ form_service_gen("edit", service["SERVER_NAME"], config["id"], config["label"], config["type"], service[config["env"]])|safe }}
{% endfor %}
</div>
{% if check.update({"class": ""}) %}
{% endif %}
{% endfor %}
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save</button>
</div>
</div>
</div>
</div>

View File

@ -5,6 +5,7 @@
<div class="row justify-content-center">
{% for service in services %}
<div class="col col-12 col-lg-4">
<div class="card border-primary mb-3" style="max-width: 80rem;">
<div class="card-header border-primary bg-primary text-white">
@ -38,40 +39,11 @@
</div>
</div>
</div>
<div class="modal fade" id="modal-edit-id-{{ service["SERVER_NAME"].replace(".", "-") }}" tabindex="-1" aria-labelledby="modal-edit-label-{{ service["SERVER_NAME"].replace(".", "-") }}" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modal-edit-label-{{ service["SERVER_NAME"].replace(".", "-") }}">View/edit {{ service["SERVER_NAME"] }} configuration</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
{{ service }}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save</button>
</div>
</div>
</div>
</div>
<div class="modal fade" id="modal-delete-id-{{ service["SERVER_NAME"].replace(".", "-") }}" tabindex="-1" aria-labelledby="modal-delete-label-{{ service["SERVER_NAME"].replace(".", "-") }}" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modal-delete-label-{{ service["SERVER_NAME"].replace(".", "-") }}">Delete {{ service["SERVER_NAME"] }} configuration</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
Are you sure you want to delete the configuration of {{ service["SERVER_NAME"] }} ?
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" class="btn btn-danger">Delete</button>
</div>
</div>
</div>
</div>
{% include "services-edit.html" %}
{% include "services-delete.html" %}
{% endfor %}
</div>

View File

@ -23,3 +23,19 @@ def env_to_summary_class(var, value) :
if re.search(value, var) :
return "check text-success"
return "times text-danger"
def form_service_gen(form, server, id, label, type, value) :
if form == "edit" :
new_id = "form-edit-" + server.replace(".", "-") + "-" + id
elif form == "new" :
new_id = "form-new-" + id
if type == "text" :
input = '<input type="%s" class="form-control" id="%s" value="%s">' % (type, new_id, value)
pt = ""
elif type == "checkbox" :
checked = ""
if value == "yes" :
checked = "checked"
input = '<div class="form-check form-switch"><input type="%s" class="form-check-input" id="%s" %s></div>' % (type, new_id, checked)
pt = "pt-0"
return '<div class="row mb-3"><label for="%s" class="col-4 col-form-label %s">%s</label><div class="col-8">%s</div></div>' % (new_id, pt, label, input)