UI - services backend started

This commit is contained in:
bunkerity 2020-12-23 22:29:50 +01:00
parent 569ad75c42
commit 0f520b8914
No known key found for this signature in database
GPG Key ID: 654FFF51CEF7CC47
9 changed files with 290 additions and 26 deletions

View File

@ -1,122 +1,146 @@
{ {
"Misc":{ "Misc":{
"id":"max-client-size", "id":"misc",
"params":[ "params":[
{
"type":"text",
"label":"Server name",
"env":"SERVER_NAME",
"regex":"^([a-z\\-0-9]+\\.?)+$",
"id":"server-name"
},
{ {
"type":"text", "type":"text",
"label":"Max client size", "label":"Max client size",
"env":"MAX_CLIENT_SIZE", "env":"MAX_CLIENT_SIZE",
"regex":"^[0-9]+(k|K|m|M|g|G)?$",
"id":"max-client-size" "id":"max-client-size"
}, },
{ {
"type":"text", "type":"text",
"label":"Allowed methods", "label":"Allowed methods",
"env":"ALLOWED_METHODS", "env":"ALLOWED_METHODS",
"regex":"^((GET|POST|HEAD|PUT|DELETE|CONNECT|OPTIONS|TRACE)\\|?)+$",
"id":"allowed-methods" "id":"allowed-methods"
}, },
{ {
"type":"checkbox", "type":"checkbox",
"label":"Serve files", "label":"Serve files",
"env":"SERVE_FILES", "env":"SERVE_FILES",
"regex":"^(yes|no)$",
"id":"serve-files" "id":"serve-files"
} }
] ]
}, },
"Info leak":{ "Info leak":{
"id":"remove-headers", "id":"info-leak",
"params":[ "params":[
{ {
"type":"text", "type":"text",
"label":"Remove headers", "label":"Remove headers",
"env":"REMOVE_HEADERS", "env":"REMOVE_HEADERS",
"regex":"^([A-Za-z0-9\\-] ?)*$",
"id":"remove-headers" "id":"remove-headers"
} }
] ]
}, },
"Basic auth":{ "Basic auth":{
"id":"use-auth-basic", "id":"auth-basic",
"params":[ "params":[
{ {
"type":"checkbox", "type":"checkbox",
"label":"Use auth basic", "label":"Use auth basic",
"env":"USE_AUTH_BASIC", "env":"USE_AUTH_BASIC",
"regex":"^(yes|no)$",
"id":"use-auth-basic" "id":"use-auth-basic"
}, },
{ {
"type":"text", "type":"text",
"label":"Auth basic location", "label":"Auth basic location",
"env":"AUTH_BASIC_LOCATION", "env":"AUTH_BASIC_LOCATION",
"regex":"^(sitewide|/[A-Za-z0-9/]*)$",
"id":"auth-basic-location" "id":"auth-basic-location"
}, },
{ {
"type":"text", "type":"text",
"label":"Auth basic user", "label":"Auth basic user",
"env":"AUTH_BASIC_USER", "env":"AUTH_BASIC_USER",
"regex":"^([A-Za-z0-9\\-_]+)$",
"id":"auth-basic-user" "id":"auth-basic-user"
}, },
{ {
"type":"text", "type":"text",
"label":"Auth basic password", "label":"Auth basic password",
"env":"AUTH_BASIC_PASSWORD", "env":"AUTH_BASIC_PASSWORD",
"regex":"^([\\S]+)$",
"id":"auth-basic-password" "id":"auth-basic-password"
}, },
{ {
"type":"text", "type":"text",
"label":"Auth basic text", "label":"Auth basic text",
"regex":"^([\\S ]+)$",
"env":"AUTH_BASIC_TEXT", "env":"AUTH_BASIC_TEXT",
"id":"auth-basic-text" "id":"auth-basic-text"
} }
] ]
}, },
"Reverse proxy":{ "Reverse proxy":{
"id":"use-reverse-proxy", "id":"reverse-proxy",
"params":[ "params":[
{ {
"type":"checkbox", "type":"checkbox",
"label":"Use reverse proxy", "label":"Use reverse proxy",
"env":"USE_REVERSE_PROXY", "env":"USE_REVERSE_PROXY",
"regex":"^(yes|no)$",
"id":"use-reverse-proxy" "id":"use-reverse-proxy"
}, },
{ {
"type":"text", "type":"text",
"label":"Reverse proxy url", "label":"Reverse proxy url",
"env":"REVERSE_PROXY_URL", "env":"REVERSE_PROXY_URL",
"regex":".*",
"id":"reverse-proxy-url" "id":"reverse-proxy-url"
}, },
{ {
"type":"text", "type":"text",
"label":"Reverse proxy host", "label":"Reverse proxy host",
"env":"REVERSE_PROXY_HOST", "env":"REVERSE_PROXY_HOST",
"regex":".*",
"id":"reverse-proxy-host" "id":"reverse-proxy-host"
}, },
{ {
"type":"checkbox", "type":"checkbox",
"label":"Reverse proxy ws", "label":"Reverse proxy ws",
"env":"REVERSE_PROXY_WS", "env":"REVERSE_PROXY_WS",
"regex":"^(yes|no)$",
"id":"reverse-proxy-ws" "id":"reverse-proxy-ws"
}, },
{ {
"type":"checkbox", "type":"checkbox",
"label":"Proxy real ip", "label":"Proxy real ip",
"env":"PROXY_REAL_IP", "env":"PROXY_REAL_IP",
"regex":"^(yes|no)$",
"id":"proxy-real-ip" "id":"proxy-real-ip"
}, },
{ {
"type":"text", "type":"text",
"label":"Proxy real ip from", "label":"Proxy real ip from",
"env":"PROXY_REAL_IP_FROM", "env":"PROXY_REAL_IP_FROM",
"regex":"^(\\d+.\\d+.\\d+.\\d+(/\\d+)? ?)*$",
"id":"proxy-real-ip-from" "id":"proxy-real-ip-from"
}, },
{ {
"type":"text", "type":"text",
"label":"Proxy real ip header", "label":"Proxy real ip header",
"env":"PROXY_REAL_IP_HEADER", "env":"PROXY_REAL_IP_HEADER",
"regex":"^([A-Za-z0-9\\-])+$",
"id":"proxy-real-ip-header" "id":"proxy-real-ip-header"
}, },
{ {
"type":"text", "type":"text",
"label":"Proxy real ip recursive", "label":"Proxy real ip recursive",
"env":"PROXY_REAL_IP_RECURSIVE", "env":"PROXY_REAL_IP_RECURSIVE",
"regex":"^(on|off)$",
"id":"proxy-real-ip-recursive" "id":"proxy-real-ip-recursive"
} }
] ]
@ -128,48 +152,56 @@
"type":"checkbox", "type":"checkbox",
"label":"Use gzip", "label":"Use gzip",
"env":"USE_GZIP", "env":"USE_GZIP",
"regex":"^(yes|no)$",
"id":"use-gzip" "id":"use-gzip"
}, },
{ {
"type":"text", "type":"text",
"label":"Gzip comp level", "label":"Gzip comp level",
"env":"GZIP_COMP_LEVEL", "env":"GZIP_COMP_LEVEL",
"regex":"^[1-9]$",
"id":"gzip-comp-level" "id":"gzip-comp-level"
}, },
{ {
"type":"text", "type":"text",
"label":"Gzip min length", "label":"Gzip min length",
"env":"GZIP_MIN_LENGTH", "env":"GZIP_MIN_LENGTH",
"regex":"^[0-9]+$",
"id":"gzip-min-length" "id":"gzip-min-length"
}, },
{ {
"type":"text", "type":"text",
"label":"Gzip types", "label":"Gzip types",
"env":"GZIP_TYPES", "env":"GZIP_TYPES",
"regex":"^([a-z/\\+\\-\\.] ?)*$",
"id":"gzip-types" "id":"gzip-types"
}, },
{ {
"type":"checkbox", "type":"checkbox",
"label":"Use brotli", "label":"Use brotli",
"env":"USE_BROTLI", "env":"USE_BROTLI",
"regex":"^(yes|no)$",
"id":"use-brotli" "id":"use-brotli"
}, },
{ {
"type":"text", "type":"text",
"label":"Brotli comp level", "label":"Brotli comp level",
"env":"BROTLI_COMP_LEVEL", "env":"BROTLI_COMP_LEVEL",
"regex":"^[1-9]$",
"id":"brotli-comp-level" "id":"brotli-comp-level"
}, },
{ {
"type":"text", "type":"text",
"label":"Brotli min length", "label":"Brotli min length",
"env":"BROTLI_MIN_LENGTH", "env":"BROTLI_MIN_LENGTH",
"regex":"^[0-9]+$",
"id":"brotli-min-length" "id":"brotli-min-length"
}, },
{ {
"type":"text", "type":"text",
"label":"Brotli types", "label":"Brotli types",
"env":"BROTLI_TYPES", "env":"BROTLI_TYPES",
"regex":"^([a-z/\\+\\-\\.] ?)*$",
"id":"brotli-types" "id":"brotli-types"
} }
] ]
@ -181,108 +213,126 @@
"type":"checkbox", "type":"checkbox",
"label":"Use client cache", "label":"Use client cache",
"env":"USE_CLIENT_CACHE", "env":"USE_CLIENT_CACHE",
"regex":"^(yes|no)$",
"id":"use-client-cache" "id":"use-client-cache"
}, },
{ {
"type":"text", "type":"text",
"label":"Client cache extensions", "label":"Client cache extensions",
"env":"CLIENT_CACHE_EXTENSIONS", "env":"CLIENT_CACHE_EXTENSIONS",
"regex":"^([a-z0-9]\\|?)*$",
"id":"client-cache-extensions" "id":"client-cache-extensions"
}, },
{ {
"type":"text", "type":"text",
"label":"Client cache control", "label":"Client cache control",
"env":"CLIENT_CACHE_CONTROL", "env":"CLIENT_CACHE_CONTROL",
"regex":"^([\\S ]*)$",
"id":"client-cache-control" "id":"client-cache-control"
}, },
{ {
"type":"text", "type":"text",
"label":"Client cache etag", "label":"Client cache etag",
"env":"CLIENT_CACHE_ETAG", "env":"CLIENT_CACHE_ETAG",
"regex":"^(on|off)$",
"id":"client-cache-etag" "id":"client-cache-etag"
}, },
{ {
"type":"checkbox", "type":"checkbox",
"label":"Use open file cache", "label":"Use open file cache",
"env":"USE_OPEN_FILE_CACHE", "env":"USE_OPEN_FILE_CACHE",
"regex":"^(yes|no)$",
"id":"use-open-file-cache" "id":"use-open-file-cache"
}, },
{ {
"type":"text", "type":"text",
"label":"Open file cache", "label":"Open file cache",
"env":"OPEN_FILE_CACHE", "env":"OPEN_FILE_CACHE",
"regex":"^([\\S ]*)$",
"id":"open-file-cache" "id":"open-file-cache"
}, },
{ {
"type":"text", "type":"text",
"label":"Open file cache errors", "label":"Open file cache errors",
"env":"OPEN_FILE_CACHE_ERRORS", "env":"OPEN_FILE_CACHE_ERRORS",
"regex":"^(on|off)$",
"id":"open-file-cache-errors" "id":"open-file-cache-errors"
}, },
{ {
"type":"text", "type":"text",
"label":"Open file cache min uses", "label":"Open file cache min uses",
"env":"OPEN_FILE_CACHE_MIN_USES", "env":"OPEN_FILE_CACHE_MIN_USES",
"regex":"^([1-9]+)$",
"id":"open-file-cache-min-uses" "id":"open-file-cache-min-uses"
}, },
{ {
"type":"text", "type":"text",
"label":"Open file cache valid", "label":"Open file cache valid",
"env":"OPEN_FILE_CACHE_VALID", "env":"OPEN_FILE_CACHE_VALID",
"regex":"^\\d+(ms|s|m|h|d|w|M|y)$",
"id":"open-file-cache-valid" "id":"open-file-cache-valid"
}, },
{ {
"type":"checkbox", "type":"checkbox",
"label":"Use proxy cache", "label":"Use proxy cache",
"env":"USE_PROXY_CACHE", "env":"USE_PROXY_CACHE",
"regex":"^(yes|no)$",
"id":"use-proxy-cache" "id":"use-proxy-cache"
}, },
{ {
"type":"text", "type":"text",
"label":"Proxy cache path zone size", "label":"Proxy cache path zone size",
"env":"PROXY_CACHE_PATH_ZONE_SIZE", "env":"PROXY_CACHE_PATH_ZONE_SIZE",
"regex":"^[0-9]+(k|K|m|M|g|G)?$",
"id":"proxy-cache-path-zone-size" "id":"proxy-cache-path-zone-size"
}, },
{ {
"type":"text", "type":"text",
"label":"Proxy cache path params", "label":"Proxy cache path params",
"env":"PROXY_CACHE_PATH_PARAMS", "env":"PROXY_CACHE_PATH_PARAMS",
"regex":"^([\\S ]*)$",
"id":"proxy-cache-path-params" "id":"proxy-cache-path-params"
}, },
{ {
"type":"text", "type":"text",
"label":"Proxy cache methods", "label":"Proxy cache methods",
"env":"PROXY_CACHE_METHODS", "env":"PROXY_CACHE_METHODS",
"regex":"^((GET|POST|HEAD|PUT|DELETE|CONNECT|OPTIONS|TRACE) ?)+$",
"id":"proxy-cache-methods" "id":"proxy-cache-methods"
}, },
{ {
"type":"text", "type":"text",
"label":"Proxy cache min uses", "label":"Proxy cache min uses",
"env":"PROXY_CACHE_MIN_USES", "env":"PROXY_CACHE_MIN_USES",
"regex":"^([1-9]+)$",
"id":"proxy-cache-min-uses" "id":"proxy-cache-min-uses"
}, },
{ {
"type":"text", "type":"text",
"label":"Proxy cache key", "label":"Proxy cache key",
"env":"PROXY_CACHE_KEY", "env":"PROXY_CACHE_KEY",
"regex":"^([\\S ]*)$",
"id":"proxy-cache-key" "id":"proxy-cache-key"
}, },
{ {
"type":"text", "type":"text",
"label":"Proxy cache valid", "label":"Proxy cache valid",
"env":"PROXY_CACHE_VALID", "env":"PROXY_CACHE_VALID",
"regex":"^(\\d{3}=\\d+(ms|s|m|h|d|w|M|y) ?)+$",
"id":"proxy-cache-valid" "id":"proxy-cache-valid"
}, },
{ {
"type":"text", "type":"text",
"label":"Proxy no cache", "label":"Proxy no cache",
"env":"PROXY_NO_CACHE", "env":"PROXY_NO_CACHE",
"regex":"^([\\S ]*)$",
"id":"proxy-no-cache" "id":"proxy-no-cache"
}, },
{ {
"type":"text", "type":"text",
"label":"Proxy cache bypass", "label":"Proxy cache bypass",
"env":"PROXY_CACHE_BYPASS", "env":"PROXY_CACHE_BYPASS",
"regex":"^([\\S ]*)$",
"id":"proxy-cache-bypass" "id":"proxy-cache-bypass"
} }
] ]
@ -294,36 +344,42 @@
"type":"checkbox", "type":"checkbox",
"label":"Auto lets encrypt", "label":"Auto lets encrypt",
"env":"AUTO_LETS_ENCRYPT", "env":"AUTO_LETS_ENCRYPT",
"regex":"^(yes|no)$",
"id":"auto-lets-encrypt" "id":"auto-lets-encrypt"
}, },
{ {
"type":"text", "type":"text",
"label":"Email lets encrypt", "label":"Email lets encrypt",
"env":"EMAIL_LETS_ENCRYPT", "env":"EMAIL_LETS_ENCRYPT",
"regex":"^([a-z0-9\\-\\.]+@([a-z\\-0-9]+\\.?)|.{0})$",
"id":"email-lets-encrypt" "id":"email-lets-encrypt"
}, },
{ {
"type":"checkbox", "type":"checkbox",
"label":"Redirect http to https", "label":"Redirect http to https",
"env":"REDIRECT_HTTP_TO_HTTPS", "env":"REDIRECT_HTTP_TO_HTTPS",
"regex":"^(yes|no)$",
"id":"redirect-http-to-https" "id":"redirect-http-to-https"
}, },
{ {
"type":"checkbox", "type":"checkbox",
"label":"HTTP2", "label":"HTTP2",
"env":"HTTP2", "env":"HTTP2",
"regex":"^(yes|no)$",
"id":"http2" "id":"http2"
}, },
{ {
"type":"text", "type":"text",
"label":"HTTPS protocols", "label":"HTTPS protocols",
"env":"HTTPS_PROTOCOLS", "env":"HTTPS_PROTOCOLS",
"regex":"^([\\S ]*)$",
"id":"https-protocols" "id":"https-protocols"
}, },
{ {
"type":"checkbox", "type":"checkbox",
"label":"Listen http", "label":"Listen http",
"env":"LISTEN_HTTP", "env":"LISTEN_HTTP",
"regex":"^(yes|no)$",
"id":"listen-http" "id":"listen-http"
} }
] ]
@ -335,12 +391,14 @@
"type":"checkbox", "type":"checkbox",
"label":"Use modsecurity", "label":"Use modsecurity",
"env":"USE_MODSECURITY", "env":"USE_MODSECURITY",
"regex":"^(yes|no)$",
"id":"use-modsecurity" "id":"use-modsecurity"
}, },
{ {
"type":"checkbox", "type":"checkbox",
"label":"Use modsecurity crs", "label":"Use modsecurity crs",
"env":"USE_MODSECURITY_CRS", "env":"USE_MODSECURITY_CRS",
"regex":"^(yes|no)$",
"id":"use-modsecurity-crs" "id":"use-modsecurity-crs"
} }
] ]
@ -352,60 +410,70 @@
"type":"text", "type":"text",
"label":"X frame options", "label":"X frame options",
"env":"X_FRAME_OPTIONS", "env":"X_FRAME_OPTIONS",
"regex":"^([\\S ]*)$",
"id":"x-frame-options" "id":"x-frame-options"
}, },
{ {
"type":"text", "type":"text",
"label":"X xss protection", "label":"X xss protection",
"env":"X_XSS_PROTECTION", "env":"X_XSS_PROTECTION",
"regex":"^([\\S ]*)$",
"id":"x-xss-protection" "id":"x-xss-protection"
}, },
{ {
"type":"text", "type":"text",
"label":"X content type options", "label":"X content type options",
"env":"X_CONTENT_TYPE_OPTIONS", "env":"X_CONTENT_TYPE_OPTIONS",
"regex":"^([\\S ]*)$",
"id":"x-content-type-options" "id":"x-content-type-options"
}, },
{ {
"type":"text", "type":"text",
"label":"Referrer policy", "label":"Referrer policy",
"env":"REFERRER_POLICY", "env":"REFERRER_POLICY",
"regex":"^([\\S ]*)$",
"id":"referrer-policy" "id":"referrer-policy"
}, },
{ {
"type":"text", "type":"text",
"label":"Feature policy", "label":"Feature policy",
"env":"FEATURE_POLICY", "env":"FEATURE_POLICY",
"regex":"^([\\S ]*)$",
"id":"feature-policy" "id":"feature-policy"
}, },
{ {
"type":"text", "type":"text",
"label":"Permissions policy", "label":"Permissions policy",
"env":"PERMISSIONS_POLICY", "env":"PERMISSIONS_POLICY",
"regex":"^([\\S ]*)$",
"id":"permissions-policy" "id":"permissions-policy"
}, },
{ {
"type":"text", "type":"text",
"label":"Cookie flags", "label":"Cookie flags",
"env":"COOKIE_FLAGS", "env":"COOKIE_FLAGS",
"regex":"^([\\S ]*)$",
"id":"cookie-flags" "id":"cookie-flags"
}, },
{ {
"type":"checkbox", "type":"checkbox",
"label":"Cookie auto secure flag", "label":"Cookie auto secure flag",
"env":"COOKIE_AUTO_SECURE_FLAG", "env":"COOKIE_AUTO_SECURE_FLAG",
"regex":"^(yes|no)$",
"id":"cookie-auto-secure-flag" "id":"cookie-auto-secure-flag"
}, },
{ {
"type":"text", "type":"text",
"label":"Strict transport security", "label":"Strict transport security",
"env":"STRICT_TRANSPORT_SECURITY", "env":"STRICT_TRANSPORT_SECURITY",
"regex":"^([\\S ]*)$",
"id":"strict-transport-security" "id":"strict-transport-security"
}, },
{ {
"type":"text", "type":"text",
"label":"Content security policy", "label":"Content security policy",
"env":"CONTENT_SECURITY_POLICY", "env":"CONTENT_SECURITY_POLICY",
"regex":"^([\\S ]*)$",
"id":"content-security-policy" "id":"content-security-policy"
} }
] ]
@ -417,24 +485,28 @@
"type":"text", "type":"text",
"label":"Use antibot", "label":"Use antibot",
"env":"USE_ANTIBOT", "env":"USE_ANTIBOT",
"regex":"^(no|cookie|javascript|captcha|recaptcha)$",
"id":"use-antibot" "id":"use-antibot"
}, },
{ {
"type":"text", "type":"text",
"label":"Antibot uri", "label":"Antibot uri",
"env":"ANTIBOT_URI", "env":"ANTIBOT_URI",
"regex":"^/([A-Za-z0-9\\-]/?)*$",
"id":"antibot-uri" "id":"antibot-uri"
}, },
{ {
"type":"text", "type":"text",
"label":"Antibot session secret", "label":"Antibot session secret",
"env":"ANTIBOT_SESSION_SECRET", "env":"ANTIBOT_SESSION_SECRET",
"regex":"^([\\S]+)$",
"id":"antibot-session-secret" "id":"antibot-session-secret"
}, },
{ {
"type":"text", "type":"text",
"label":"Antibot recaptcha score", "label":"Antibot recaptcha score",
"env":"ANTIBOT_RECAPTCHA_SCORE", "env":"ANTIBOT_RECAPTCHA_SCORE",
"regex":"^0\\.\\d$",
"id":"antibot-recaptcha-score" "id":"antibot-recaptcha-score"
} }
] ]
@ -446,30 +518,35 @@
"type":"checkbox", "type":"checkbox",
"label":"Block user agent", "label":"Block user agent",
"env":"BLOCK_USER_AGENT", "env":"BLOCK_USER_AGENT",
"regex":"^(yes|no)$",
"id":"block-user-agent" "id":"block-user-agent"
}, },
{ {
"type":"checkbox", "type":"checkbox",
"label":"Block tor exit node", "label":"Block tor exit node",
"env":"BLOCK_TOR_EXIT_NODE", "env":"BLOCK_TOR_EXIT_NODE",
"regex":"^(yes|no)$",
"id":"block-tor-exit-node" "id":"block-tor-exit-node"
}, },
{ {
"type":"checkbox", "type":"checkbox",
"label":"Block proxies", "label":"Block proxies",
"env":"BLOCK_PROXIES", "env":"BLOCK_PROXIES",
"regex":"^(yes|no)$",
"id":"block-proxies" "id":"block-proxies"
}, },
{ {
"type":"checkbox", "type":"checkbox",
"label":"Block abusers", "label":"Block abusers",
"env":"BLOCK_ABUSERS", "env":"BLOCK_ABUSERS",
"regex":"^(yes|no)$",
"id":"block-abusers" "id":"block-abusers"
}, },
{ {
"type":"checkbox", "type":"checkbox",
"label":"Block referrer", "label":"Block referrer",
"env":"BLOCK_REFERRER", "env":"BLOCK_REFERRER",
"regex":"^(yes|no)$",
"id":"block-referrer" "id":"block-referrer"
} }
] ]
@ -481,6 +558,7 @@
"type":"checkbox", "type":"checkbox",
"label":"Use dnsbl", "label":"Use dnsbl",
"env":"USE_DNSBL", "env":"USE_DNSBL",
"regex":"^(yes|no)$",
"id":"use-dnsbl" "id":"use-dnsbl"
} }
] ]
@ -492,6 +570,7 @@
"type":"checkbox", "type":"checkbox",
"label":"Use crowdsec", "label":"Use crowdsec",
"env":"USE_CROWDSEC", "env":"USE_CROWDSEC",
"regex":"^(yes|no)$",
"id":"use-crowdsec" "id":"use-crowdsec"
} }
] ]
@ -503,18 +582,21 @@
"type":"checkbox", "type":"checkbox",
"label":"Use whitelist ip", "label":"Use whitelist ip",
"env":"USE_WHITELIST_IP", "env":"USE_WHITELIST_IP",
"regex":"^(yes|no)$",
"id":"use-whitelist-ip" "id":"use-whitelist-ip"
}, },
{ {
"type":"checkbox", "type":"checkbox",
"label":"Use whitelist reverse", "label":"Use whitelist reverse",
"env":"USE_WHITELIST_REVERSE", "env":"USE_WHITELIST_REVERSE",
"regex":"^(yes|no)$",
"id":"use-whitelist-reverse" "id":"use-whitelist-reverse"
}, },
{ {
"type":"text", "type":"text",
"label":"Whitelist country", "label":"Whitelist country",
"env":"WHITELIST_COUNTRY", "env":"WHITELIST_COUNTRY",
"regex":"^([A-Z]{2} ?)*$",
"id":"whitelist-country" "id":"whitelist-country"
} }
] ]
@ -526,18 +608,21 @@
"type":"checkbox", "type":"checkbox",
"label":"Use blacklist ip", "label":"Use blacklist ip",
"env":"USE_BLACKLIST_IP", "env":"USE_BLACKLIST_IP",
"regex":"^(yes|no)$",
"id":"use-blacklist-ip" "id":"use-blacklist-ip"
}, },
{ {
"type":"checkbox", "type":"checkbox",
"label":"Use blacklist reverse", "label":"Use blacklist reverse",
"env":"USE_BLACKLIST_REVERSE", "env":"USE_BLACKLIST_REVERSE",
"regex":"^(yes|no)$",
"id":"use-blacklist-reverse" "id":"use-blacklist-reverse"
}, },
{ {
"type":"text", "type":"text",
"label":"Blacklist country", "label":"Blacklist country",
"env":"BLACKLIST_COUNTRY", "env":"BLACKLIST_COUNTRY",
"regex":"^([A-Z]{2} ?)*$",
"id":"blacklist-country" "id":"blacklist-country"
} }
] ]
@ -549,18 +634,21 @@
"type":"checkbox", "type":"checkbox",
"label":"Use limit req", "label":"Use limit req",
"env":"USE_LIMIT_REQ", "env":"USE_LIMIT_REQ",
"regex":"^(yes|no)$",
"id":"use-limit-req" "id":"use-limit-req"
}, },
{ {
"type":"text", "type":"text",
"label":"Limit req rate", "label":"Limit req rate",
"env":"LIMIT_REQ_RATE", "env":"LIMIT_REQ_RATE",
"regex":"^\\d+r/(ms|s|m|h|d)$",
"id":"limit-req-rate" "id":"limit-req-rate"
}, },
{ {
"type":"text", "type":"text",
"label":"Limit req burst", "label":"Limit req burst",
"env":"LIMIT_REQ_BURST", "env":"LIMIT_REQ_BURST",
"regex":"^\\d+$",
"id":"limit-req-burst" "id":"limit-req-burst"
} }
] ]
@ -572,12 +660,14 @@
"type":"text", "type":"text",
"label":"Remote php", "label":"Remote php",
"env":"REMOTE_PHP", "env":"REMOTE_PHP",
"regex":"^([a-z\\-0-9]+\\.?)*$",
"id":"remote-php" "id":"remote-php"
}, },
{ {
"type":"text", "type":"text",
"label":"Remote php path", "label":"Remote php path",
"env":"REMOTE_PHP_PATH", "env":"REMOTE_PHP_PATH",
"regex":"^/([A-Za-z0-9\\-]/?)*$",
"id":"remote-php-path" "id":"remote-php-path"
} }
] ]
@ -589,6 +679,7 @@
"type":"checkbox", "type":"checkbox",
"label":"Use fail2ban", "label":"Use fail2ban",
"env":"USE_FAIL2BAN", "env":"USE_FAIL2BAN",
"regex":"^(yes|no)$",
"id":"use-fail2ban" "id":"use-fail2ban"
} }
] ]
@ -600,6 +691,7 @@
"type":"checkbox", "type":"checkbox",
"label":"Use clamav upload", "label":"Use clamav upload",
"env":"USE_CLAMAV_UPLOAD", "env":"USE_CLAMAV_UPLOAD",
"regex":"^(yes|no)$",
"id":"use-clamav-upload" "id":"use-clamav-upload"
} }
] ]

View File

@ -1,9 +1,9 @@
#!/usr/bin/python3 #!/usr/bin/python3
from flask import Flask, render_template, current_app from flask import Flask, render_template, current_app, request
import wrappers, utils import wrappers, utils
import os, json import os, json, re
app = Flask(__name__, static_url_path="/", static_folder="static", template_folder="templates") app = Flask(__name__, static_url_path="/", static_folder="static", template_folder="templates")
ABSOLUTE_URI = "" ABSOLUTE_URI = ""
@ -33,9 +33,58 @@ def instances():
return render_template("error.html", title="Error", error=instances) return render_template("error.html", title="Error", error=instances)
return render_template("instances.html", title="Instances", instances=instances) return render_template("instances.html", title="Instances", instances=instances)
@app.route('/services') @app.route('/services', methods=["GET", "POST"])
def services(): def services():
# Manage services
operation = ""
if request.method == "POST" :
# Check operation
if not "operation" in request.form or not request.form["operation"] in ["new", "edit", "delete"] :
return render_template("error.html", title="Error", error="Missing operation parameter on /services.")
# Check that all fields are present and they match the corresponding regex
env = {}
if request.form["operation"] in ["new", "edit"] :
for category in current_app.config["CONFIG"] :
for param in current_app.config["CONFIG"][category]["params"] :
if not param["env"] in request.form :
return render_template("error.html", title="Error", error="Missing " + param["env"] + " parameter.")
if not re.search(param["regex"], request.form[param["env"]]) :
return render_template("error.html", title="Error", error="Parameter " + param["env"] + " doesn't match regex.")
env[param["env"]] = request.form[param["env"]]
if request.form["operation"] == "edit" :
if not "OLD_SERVER_NAME" in request.form :
return render_template("error.html", title="Error", error="Missing OLD_SERVER_NAME parameter.")
if not re.search("^([a-z\-0-9]+\.?)+$", request.form["OLD_SERVER_NAME"]) :
return render_template("error.html", title="Error", error="Parameter OLD_SERVER_NAME doesn't match regex.")
elif request.form["operation"] == "delete" :
if not "SERVER_NAME" in request.form :
return render_template("error.html", title="Error", error="Missing SERVER_NAME parameter.")
if not re.search("^([a-z\-0-9]+\.?)+$", request.form["SERVER_NAME"]) :
return render_template("error.html", title="Error", error="Parameter SERVER_NAME doesn't match regex.")
# Create new service
if request.form["operation"] == "new" :
check, operation = wrappers.new_service(env)
if not check :
render_template("error.html", title="Error", error=service)
# Edit existing service
elif request.form["operation"] == "edit" :
check, operation = wrappers.edit_service(request.form["OLD_SERVER_NAME"], env)
if not check :
render_template("error.html", title="Error", error=service)
# Delete existing service
elif request.form["operation"] == "delete" :
check, operation = wrappers.delete_service(request.form["SERVER_NAME"])
if not check :
render_template("error.html", title="Error", error=service)
# Display services
check, services = wrappers.get_services() check, services = wrappers.get_services()
if not check : if not check :
return render_template("error.html", title="Error", error=services) return render_template("error.html", title="Error", error=services)
return render_template("services.html", title="Services", services=services) return render_template("services.html", title="Services", services=services, operation=operation)

View File

@ -3,3 +3,54 @@ var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl, { container: 'body' }) return new bootstrap.Tooltip(tooltipTriggerEl, { container: 'body' })
}) })
function post(operation, url, data) {
var form = document.createElement("form");
form.method = "POST";
form.action = url;
for (var key in data) {
var field = document.createElement("input");
field.type = "hidden";
field.name = key;
field.value = data[key];
form.appendChild(field);
}
var field = document.createElement("input");
field.type = "hidden";
field.name = "operation";
field.value = operation;
form.appendChild(field);
document.body.appendChild(form);
form.submit();
}
function getData(id) {
var elements = document.getElementById(id).elements;
var data = {};
for (var i = 0; i < elements.length; i++) {
element = elements[i];
if (element["type"] === "checkbox") {
if (element["value"] === "on") {
data[element["name"]] = "yes";
}
else {
data[element["name"]] = "no";
}
}
else {
data[element["name"]] = element["value"];
}
}
return data;
}
function postNew() {
post("new", "services", getData('form-new'));
}
function postEdit(id) {
post("edit", "services", getData('form-edit-' + id));
}
function postDelete(id) {
post("delete", "services", getData('form-delete-' + id));
}

View File

@ -1,16 +1,19 @@
<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 fade" id="modal-delete-id-{{ id_server_name }}" tabindex="-1" aria-labelledby="modal-delete-label-{{ id_server_name }}" aria-hidden="true">
<div class="modal-dialog"> <div class="modal-dialog">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<h5 class="modal-title" id="modal-delete-label-{{ service["SERVER_NAME"].replace(".", "-") }}">Delete {{ service["SERVER_NAME"] }} configuration</h5> <h5 class="modal-title" id="modal-delete-label-{{ id_server_name }}">Delete {{ service["SERVER_NAME"] }} configuration</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
Are you sure you want to delete the configuration of {{ service["SERVER_NAME"] }} ? Are you sure you want to delete the configuration of {{ service["SERVER_NAME"] }} ?
<form id="form-delete-{{ id_server_name }}">
<input type="hidden" value="{{ service["SERVER_NAME"] }}" name="SERVER_NAME">
</form>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" class="btn btn-danger">Delete</button> <button type="button" class="btn btn-danger" onClick="postDelete('{{ id_server_name }}');">Delete</button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,5 +1,3 @@
{% 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 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-dialog modal-lg">
<div class="modal-content"> <div class="modal-content">
@ -8,7 +6,7 @@
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<ul class="nav nav-pills mb-3" id="pills-tab" role="tablist"> <ul class="nav nav-pills mb-3" id="pills-tab-edit" role="tablist">
{% set check = {"active": "active", "selected": "true"} %} {% set check = {"active": "active", "selected": "true"} %}
{% for k, v in config["CONFIG"].items() %} {% for k, v in config["CONFIG"].items() %}
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
@ -18,22 +16,25 @@
{% endif %} {% endif %}
{% endfor %} {% endfor %}
</ul> </ul>
<div class="tab-content" id="edit-content-{{ id_server_name }}"> <form id="form-edit-{{ id_server_name }}">
<input type="hidden" value="{{ service["SERVER_NAME"] }}" name="OLD_SERVER_NAME">
<div class="tab-content" id="edit-content-{{ id_server_name }}">
{% set check = {"class": "show active"} %} {% set check = {"class": "show active"} %}
{% for k, v in config["CONFIG"].items() %} {% for k, v in config["CONFIG"].items() %}
<div class="tab-pane fade {{ check.class }}" id="edit-{{ v["id"] }}-{{ id_server_name }}" role="tabpanel" aria-labelledby="edit-{{ v["id"] }}-{{ id_server_name }}-tab"> <div class="tab-pane fade {{ check.class }}" id="edit-{{ v["id"] }}-{{ id_server_name }}" role="tabpanel" aria-labelledby="edit-{{ v["id"] }}-{{ id_server_name }}-tab">
{% for param in v["params"] %} {% for param in v["params"] %}
{{ form_service_gen("edit", id_server_name, param["id"], param["label"], param["type"], service[param["env"]])|safe }} {{ form_service_gen("edit", id_server_name, param["id"], param["label"], param["type"], service[param["env"]], param["env"])|safe }}
{% endfor %} {% endfor %}
</div> </div>
{% if check.update({"class": ""}) %} {% if check.update({"class": ""}) %}
{% endif %} {% endif %}
{% endfor %} {% endfor %}
</div> </div>
</form>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save</button> <button type="button" class="btn btn-primary" onClick="postEdit('{{ id_server_name }}');">Save</button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -0,0 +1,40 @@
<div class="modal fade" id="modal-new" tabindex="-1" aria-labelledby="modal-new-label" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modal-new-label">New 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-new" role="tablist">
{% set check = {"active": "active", "selected": "true"} %}
{% for k, v in config["CONFIG"].items() %}
<li class="nav-item" role="presentation">
<a class="nav-link {{ check.active }}" id="new-{{ v["id"] }}-tab" data-bs-toggle="pill" href="#new-{{ v["id"] }}" role="tab" aria-controls="new-{{ v["id"] }}" aria-selected="{{ check.selected }}">{{ k }}</a>
</li>
{% if check.update({"active": "", "selected": "false"}) %}
{% endif %}
{% endfor %}
</ul>
<form id="form-new">
<div class="tab-content" id="new-content">
{% set check = {"class": "show active"} %}
{% for k, v in config["CONFIG"].items() %}
<div class="tab-pane fade {{ check.class }}" id="new-{{ v["id"] }}" role="tabpanel" aria-labelledby="new-{{ v["id"] }}-tab">
{% for param in v["params"] %}
{{ form_service_gen("new", "", param["id"], param["label"], param["type"], "default", param["env"])|safe }}
{% endfor %}
</div>
{% if check.update({"class": ""}) %}
{% endif %}
{% endfor %}
</div>
</form>
</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" onClick="postNew();">Save</button>
</div>
</div>
</div>
</div>

View File

@ -2,16 +2,34 @@
{% block content %} {% block content %}
{% if operation != "" %}
<div class="row justify-content-center">
<div class="col col-4 mb-3 text-center">
<div class="alert alert-primary alert-dismissible fade show" role="alert">
{{ operation }}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
</div>
</div>
{% endif %}
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col col-12 mb-3 text-center">
<button class="btn btn-success" data-bs-toggle="modal" data-bs-target="#modal-new"><i class="fas fa-plus"></i> New</button>
</div>
{% for service in services %} {% for service in services %}
{% set id_server_name = service["SERVER_NAME"].replace(".", "-") %}
<div class="col col-12 col-lg-4"> <div class="col col-12 col-lg-4">
<div class="card border-primary mb-3" style="max-width: 80rem;"> <div class="card border-primary mb-3" style="max-width: 80rem;">
<div class="card-header border-primary bg-primary text-white"> <div class="card-header border-primary bg-primary text-white">
{{ service["SERVER_NAME"] }} {{ service["SERVER_NAME"] }}
<button class="btn btn-sm ms-2 float-end btn-light" data-bs-toggle="modal" data-bs-target="#modal-delete-id-{{ service["SERVER_NAME"].replace(".", "-") }}"><i class="fas fa-trash-alt"></i></button> <button class="btn btn-sm ms-2 float-end btn-light" data-bs-toggle="modal" data-bs-target="#modal-delete-id-{{ id_server_name }}"><i class="fas fa-trash-alt"></i></button>
<button class="btn btn-sm mx-2 float-end btn-light" data-bs-toggle="modal" data-bs-target="#modal-edit-id-{{ service["SERVER_NAME"].replace(".", "-") }}"><i class="fas fa-edit"></i></button> <button class="btn btn-sm mx-2 float-end btn-light" data-bs-toggle="modal" data-bs-target="#modal-edit-id-{{ id_server_name }}"><i class="fas fa-edit"></i></button>
<a class="btn btn-sm mx-2 float-end btn-light" href="http://{{ service["SERVER_NAME"] }}" target="_blank"><i class="fas fa-eye"></i></a> <a class="btn btn-sm mx-2 float-end btn-light" href="http://{{ service["SERVER_NAME"] }}" target="_blank"><i class="fas fa-eye"></i></a>
</div> </div>
<div class="card-body text-dark"> <div class="card-body text-dark">
@ -40,8 +58,8 @@
</div> </div>
</div> </div>
{% include "services-new.html" %}
{% include "services-edit.html" %} {% include "services-edit.html" %}
{% include "services-delete.html" %} {% include "services-delete.html" %}
{% endfor %} {% endfor %}

View File

@ -24,18 +24,18 @@ def env_to_summary_class(var, value) :
return "check text-success" return "check text-success"
return "times text-danger" return "times text-danger"
def form_service_gen(form, server, id, label, type, value) : def form_service_gen(form, server, id, label, type, value, name) :
if form == "edit" : if form == "edit" :
new_id = "form-edit-" + server + "-" + id new_id = "form-edit-" + server + "-" + id
elif form == "new" : elif form == "new" :
new_id = "form-new-" + id new_id = "form-new-" + id
if type == "text" : if type == "text" :
input = '<input type="%s" class="form-control" id="%s" value="%s">' % (type, new_id, value) input = '<input type="%s" class="form-control" id="%s" value="%s" name="%s">' % (type, new_id, value, name)
pt = "" pt = ""
elif type == "checkbox" : elif type == "checkbox" :
checked = "" checked = ""
if value == "yes" : if value == "yes" :
checked = "checked" checked = "checked"
input = '<div class="form-check form-switch"><input type="%s" class="form-check-input" id="%s" %s></div>' % (type, new_id, checked) input = '<div class="form-check form-switch"><input type="%s" class="form-check-input" id="%s" name="%s" %s></div>' % (type, new_id, name, checked)
pt = "pt-0" 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) 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)

View File

@ -43,3 +43,13 @@ def get_services() :
except Exception as e : except Exception as e :
return False, str(e) return False, str(e)
return True, services return True, services
def new_service(env) :
return True, "Web service " + env["SERVER_NAME"] + " has been added."
def edit_service(old_server_name, env) :
return True, "Web service " + old_server_name + " has been edited."
def delete_service(server_name) :
return True, "Web service " + env["SERVER_NAME"] + " has been deleted."