mirror of
https://github.com/bunkerity/bunkerweb
synced 2026-05-24 09:28:37 +00:00
init poc with wtforms
This commit is contained in:
parent
3062142f5d
commit
e9b3e60c77
4 changed files with 463 additions and 0 deletions
82
forms.py
Normal file
82
forms.py
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
from wtforms import Form
|
||||
from wtforms.fields import Field, StringField, BooleanField, SelectField, PasswordField
|
||||
from wtforms.validators import Regexp
|
||||
from wtforms.widgets import CheckboxInput
|
||||
|
||||
class BWBooleanField(Field):
|
||||
|
||||
widget = CheckboxInput()
|
||||
false_values = (False, "false", "")
|
||||
|
||||
def __init__(self, label=None, validators=None, false_values=None, **kwargs):
|
||||
super().__init__(label, validators, **kwargs)
|
||||
if false_values is not None:
|
||||
self.false_values = false_values
|
||||
|
||||
def pre_validate(self, form):
|
||||
if isinstance(self.data, bool):
|
||||
self.data = "no"
|
||||
|
||||
def process_data(self, value):
|
||||
self.data = value
|
||||
|
||||
def process_formdata(self, valuelist):
|
||||
if not valuelist or valuelist[0] in self.false_values:
|
||||
self.data = False
|
||||
else:
|
||||
self.data = "yes"
|
||||
|
||||
def _value(self):
|
||||
if self.raw_data:
|
||||
return str(self.raw_data[0])
|
||||
return "yes"
|
||||
|
||||
def settings_to_form(settings):
|
||||
class SettingsForm(Form):
|
||||
pass
|
||||
for setting, data in settings.items():
|
||||
field_type = None
|
||||
field_data = dict(
|
||||
label=data["label"],
|
||||
validators=[Regexp(data["regex"])],
|
||||
description=data["help"],
|
||||
id=setting,
|
||||
default=data["default"],
|
||||
# widget=None,
|
||||
render_kw={
|
||||
"custom-attributes-1": "custom-value-1",
|
||||
"custom-attributes-2": "custom-value-2",
|
||||
},
|
||||
name=setting,
|
||||
# _form=None,
|
||||
# _prefix='',
|
||||
# _translations=None,
|
||||
# _meta=None
|
||||
)
|
||||
if data["type"] == "text":
|
||||
field_type = StringField
|
||||
elif data["type"] == "check":
|
||||
field_type = BWBooleanField
|
||||
del field_data["default"]
|
||||
if data["default"] == "yes":
|
||||
field_data["default"] = "checked"
|
||||
field_data["render_kw"]["checked"] = ""
|
||||
field_data["false_values"] = ("no")
|
||||
elif data["type"] == "select":
|
||||
field_type = SelectField
|
||||
field_data["choices"] = data["select"]
|
||||
elif data["type"] == "password":
|
||||
field_type = PasswordField
|
||||
else:
|
||||
print(f"unsupported type {data['type']}")
|
||||
continue
|
||||
setattr(
|
||||
SettingsForm,
|
||||
setting,
|
||||
field_type(
|
||||
**field_data
|
||||
)
|
||||
)
|
||||
return SettingsForm
|
||||
|
||||
|
||||
20
main.py
Normal file
20
main.py
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
from flask import Flask, render_template, request
|
||||
from json import loads
|
||||
|
||||
from forms import settings_to_form
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
@app.route("/global", methods=['GET', 'POST'])
|
||||
def login():
|
||||
with open("settings.json") as f:
|
||||
settings = loads(f.read())
|
||||
form = settings_to_form(settings)(request.form)
|
||||
if request.method == "POST" and form.validate():
|
||||
for field in form:
|
||||
print(f"field {field.id} = {field.data}")
|
||||
print(form.errors)
|
||||
return render_template("global.html", form=form)
|
||||
|
||||
app.debug = True
|
||||
app.run(host='0.0.0.0')
|
||||
329
settings.json
Normal file
329
settings.json
Normal file
|
|
@ -0,0 +1,329 @@
|
|||
{
|
||||
"IS_LOADING": {
|
||||
"context": "global",
|
||||
"default": "no",
|
||||
"help": "Internal use : set to yes when BW is loading.",
|
||||
"id": "internal-use-loading",
|
||||
"label": "internal use loading",
|
||||
"regex": "^(yes|no)$",
|
||||
"type": "check"
|
||||
},
|
||||
"NGINX_PREFIX": {
|
||||
"context": "global",
|
||||
"default": "/etc/nginx/",
|
||||
"help": "Where nginx will search for configurations.",
|
||||
"id": "nginx-prefix",
|
||||
"label": "nginx prefix",
|
||||
"regex": "^(\\/[\\-\\w.\\s]+)*\\/$",
|
||||
"type": "text"
|
||||
},
|
||||
"HTTP_PORT": {
|
||||
"context": "global",
|
||||
"default": "8080",
|
||||
"help": "HTTP port number which bunkerweb binds to.",
|
||||
"id": "http-port",
|
||||
"label": "HTTP port",
|
||||
"regex": "^\\d+$",
|
||||
"type": "text"
|
||||
},
|
||||
"HTTPS_PORT": {
|
||||
"context": "global",
|
||||
"default": "8443",
|
||||
"help": "HTTPS port number which bunkerweb binds to.",
|
||||
"id": "https-port",
|
||||
"label": "HTTPS port",
|
||||
"regex": "^\\d+$",
|
||||
"type": "text"
|
||||
},
|
||||
"MULTISITE": {
|
||||
"context": "global",
|
||||
"default": "no",
|
||||
"help": "Multi site activation.",
|
||||
"id": "multisite",
|
||||
"label": "Multisite",
|
||||
"regex": "^(yes|no)$",
|
||||
"type": "check"
|
||||
},
|
||||
"SERVER_NAME": {
|
||||
"context": "multisite",
|
||||
"default": "www.example.com",
|
||||
"help": "List of the virtual hosts served by bunkerweb.",
|
||||
"id": "server-name",
|
||||
"label": "Server name",
|
||||
"regex": "^((\\S{1,255})(?!.*\\s\\2(\\s|$)))?(\\s(\\S{1,255})(?!.*\\s\\5(\\s|$)))*$",
|
||||
"type": "text"
|
||||
},
|
||||
"WORKER_PROCESSES": {
|
||||
"context": "global",
|
||||
"default": "auto",
|
||||
"help": "Number of worker processes.",
|
||||
"id": "worker-processes",
|
||||
"label": "Worker processes",
|
||||
"regex": "^(auto|\\d+)$",
|
||||
"type": "text"
|
||||
},
|
||||
"WORKER_RLIMIT_NOFILE": {
|
||||
"context": "global",
|
||||
"default": "2048",
|
||||
"help": "Maximum number of open files for worker processes.",
|
||||
"id": "worker-rlimit-nofile",
|
||||
"label": "Open files per worker",
|
||||
"regex": "^\\d+$",
|
||||
"type": "text"
|
||||
},
|
||||
"WORKER_CONNECTIONS": {
|
||||
"context": "global",
|
||||
"default": "1024",
|
||||
"help": "Maximum number of connections per worker.",
|
||||
"id": "worker-connections",
|
||||
"label": "Connections per worker",
|
||||
"regex": "^\\d+$",
|
||||
"type": "text"
|
||||
},
|
||||
"LOG_FORMAT": {
|
||||
"context": "global",
|
||||
"default": "$host $remote_addr - $remote_user [$time_local] \"$request\" $status $body_bytes_sent \"$http_referer\" \"$http_user_agent\"",
|
||||
"help": "The format to use for access logs.",
|
||||
"id": "log-format",
|
||||
"label": "Log format",
|
||||
"regex": "^.*$",
|
||||
"type": "text"
|
||||
},
|
||||
"LOG_LEVEL": {
|
||||
"context": "global",
|
||||
"default": "notice",
|
||||
"help": "The level to use for error logs.",
|
||||
"id": "log-level",
|
||||
"label": "Log level",
|
||||
"regex": "^(debug|info|notice|warn|error|crit|alert|emerg)$",
|
||||
"type": "select",
|
||||
"select": [
|
||||
"debug",
|
||||
"info",
|
||||
"notice",
|
||||
"warn",
|
||||
"error",
|
||||
"crit",
|
||||
"alert",
|
||||
"emerg"
|
||||
]
|
||||
},
|
||||
"DNS_RESOLVERS": {
|
||||
"context": "global",
|
||||
"default": "127.0.0.11",
|
||||
"help": "DNS addresses of resolvers to use.",
|
||||
"id": "dns-resolvers",
|
||||
"label": "DNS resolvers",
|
||||
"regex": "^(?! )(( *[^ ]+)(?!.*\\2))*$",
|
||||
"type": "text"
|
||||
},
|
||||
"DATASTORE_MEMORY_SIZE": {
|
||||
"context": "global",
|
||||
"default": "64m",
|
||||
"help": "Size of the internal datastore.",
|
||||
"id": "datastore-memory-size",
|
||||
"label": "Datastore memory size",
|
||||
"regex": "^\\d+[kKmMgG]?$",
|
||||
"type": "text"
|
||||
},
|
||||
"CACHESTORE_MEMORY_SIZE": {
|
||||
"context": "global",
|
||||
"default": "64m",
|
||||
"help": "Size of the internal cachestore.",
|
||||
"id": "cachestore-memory-size",
|
||||
"label": "Cachestore memory size",
|
||||
"regex": "^\\d+[kKmMgG]?$",
|
||||
"type": "text"
|
||||
},
|
||||
"CACHESTORE_IPC_MEMORY_SIZE": {
|
||||
"context": "global",
|
||||
"default": "16m",
|
||||
"help": "Size of the internal cachestore (ipc).",
|
||||
"id": "cachestore-ipc-memory-size",
|
||||
"label": "Cachestore ipc memory size",
|
||||
"regex": "^\\d+[kKmMgG]?$",
|
||||
"type": "text"
|
||||
},
|
||||
"CACHESTORE_MISS_MEMORY_SIZE": {
|
||||
"context": "global",
|
||||
"default": "16m",
|
||||
"help": "Size of the internal cachestore (miss).",
|
||||
"id": "cachestore-miss-memory-size",
|
||||
"label": "Cachestore miss memory size",
|
||||
"regex": "^\\d+[kKmMgG]?$",
|
||||
"type": "text"
|
||||
},
|
||||
"CACHESTORE_LOCKS_MEMORY_SIZE": {
|
||||
"context": "global",
|
||||
"default": "16m",
|
||||
"help": "Size of the internal cachestore (locks).",
|
||||
"id": "cachestore-locks-memory-size",
|
||||
"label": "Cachestore locks memory size",
|
||||
"regex": "^\\d+[kKmMgG]?$",
|
||||
"type": "text"
|
||||
},
|
||||
"USE_API": {
|
||||
"context": "global",
|
||||
"default": "yes",
|
||||
"help": "Activate the API to control BunkerWeb.",
|
||||
"id": "use-api",
|
||||
"label": "Activate API",
|
||||
"regex": "^(yes|no)$",
|
||||
"type": "check"
|
||||
},
|
||||
"API_HTTP_PORT": {
|
||||
"context": "global",
|
||||
"default": "5000",
|
||||
"help": "Listen port number for the API.",
|
||||
"id": "api-http-listen",
|
||||
"label": "API port number",
|
||||
"regex": "^\\d+$",
|
||||
"type": "text"
|
||||
},
|
||||
"API_LISTEN_IP": {
|
||||
"context": "global",
|
||||
"default": "0.0.0.0",
|
||||
"help": "Listen IP address for the API.",
|
||||
"id": "api-ip-listen",
|
||||
"label": "API listen IP",
|
||||
"regex": "^.*$",
|
||||
"type": "text"
|
||||
},
|
||||
"API_SERVER_NAME": {
|
||||
"context": "global",
|
||||
"default": "bwapi",
|
||||
"help": "Server name (virtual host) for the API.",
|
||||
"id": "api-server-name",
|
||||
"label": "API server name",
|
||||
"regex": "^[^ ]{1,255}$",
|
||||
"type": "text"
|
||||
},
|
||||
"API_WHITELIST_IP": {
|
||||
"context": "global",
|
||||
"default": "127.0.0.0/8",
|
||||
"help": "List of IP/network allowed to contact the API.",
|
||||
"id": "api-whitelist-ip",
|
||||
"label": "API whitelist IP",
|
||||
"regex": "^(?! )( *(((\\b25[0-5]|\\b2[0-4]\\d|\\b[01]?\\d\\d?)(\\.(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)){3})(\\/([1-2][0-9]?|3[0-2]?|[04-9]))?|(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]Z{0,4}){0,4}%[0-9a-zA-Z]+|::(ffff(:0{1,4})?:)?((25[0-5]|(2[0-4]|1?\\d)?\\d)\\.){3}(25[0-5]|(2[0-4]|1?\\d)?\\d)|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1?\\d)?\\d)\\.){3}(25[0-5]|(2[0-4]|1?\\d)?\\d))(\\/(12[0-8]|1[01][0-9]|[0-9][0-9]?))?)(?!.*\\D\\2([^\\d\\/]|$)) *)*$",
|
||||
"type": "text"
|
||||
},
|
||||
"AUTOCONF_MODE": {
|
||||
"context": "global",
|
||||
"default": "no",
|
||||
"help": "Enable Autoconf Docker integration.",
|
||||
"id": "autoconf-mode",
|
||||
"label": "Autoconf mode",
|
||||
"regex": "^(yes|no)$",
|
||||
"type": "check"
|
||||
},
|
||||
"SWARM_MODE": {
|
||||
"context": "global",
|
||||
"default": "no",
|
||||
"help": "Enable Docker Swarm integration.",
|
||||
"id": "swarm-mode",
|
||||
"label": "Swarm mode",
|
||||
"regex": "^(yes|no)$",
|
||||
"type": "check"
|
||||
},
|
||||
"KUBERNETES_MODE": {
|
||||
"context": "global",
|
||||
"default": "no",
|
||||
"help": "Enable Kubernetes integration.",
|
||||
"id": "kubernetes-mode",
|
||||
"label": "Kubernetes mode",
|
||||
"regex": "^(yes|no)$",
|
||||
"type": "check"
|
||||
},
|
||||
"SERVER_TYPE": {
|
||||
"context": "multisite",
|
||||
"default": "http",
|
||||
"help": "Server type : http or stream.",
|
||||
"id": "server-type",
|
||||
"label": "Server type",
|
||||
"regex": "^(http|stream)$",
|
||||
"type": "select",
|
||||
"select": ["http", "stream"]
|
||||
},
|
||||
"LISTEN_STREAM": {
|
||||
"context": "multisite",
|
||||
"default": "yes",
|
||||
"help": "Enable listening for non-ssl (passthrough).",
|
||||
"id": "listen-stream",
|
||||
"label": "Listen stream",
|
||||
"regex": "^(yes|no)$",
|
||||
"type": "check"
|
||||
},
|
||||
"LISTEN_STREAM_PORT": {
|
||||
"context": "multisite",
|
||||
"default": "1337",
|
||||
"help": "Listening port for non-ssl (passthrough).",
|
||||
"id": "listen-stream-port",
|
||||
"label": "Listen stream port",
|
||||
"regex": "^[0-9]+$",
|
||||
"type": "text"
|
||||
},
|
||||
"LISTEN_STREAM_PORT_SSL": {
|
||||
"context": "multisite",
|
||||
"default": "4242",
|
||||
"help": "Listening port for ssl (passthrough).",
|
||||
"id": "listen-stream-port-ssl",
|
||||
"label": "Listen stream port ssl",
|
||||
"regex": "^[0-9]+$",
|
||||
"type": "text"
|
||||
},
|
||||
"USE_UDP": {
|
||||
"context": "multisite",
|
||||
"default": "no",
|
||||
"help": "UDP listen instead of TCP (stream).",
|
||||
"id": "use-udp",
|
||||
"label": "Listen UDP",
|
||||
"regex": "^(yes|no)$",
|
||||
"type": "check"
|
||||
},
|
||||
"USE_IPV6": {
|
||||
"context": "global",
|
||||
"default": "no",
|
||||
"help": "Enable IPv6 connectivity.",
|
||||
"id": "use-ipv6",
|
||||
"label": "Use IPv6",
|
||||
"regex": "^(yes|no)$",
|
||||
"type": "check"
|
||||
},
|
||||
"IS_DRAFT": {
|
||||
"context": "multisite",
|
||||
"default": "no",
|
||||
"help": "Internal use : set to yes when the service is in draft mode.",
|
||||
"id": "internal-use-draft",
|
||||
"label": "internal use draft",
|
||||
"regex": "^(yes|no)$",
|
||||
"type": "check"
|
||||
},
|
||||
"TIMERS_LOG_LEVEL": {
|
||||
"context": "global",
|
||||
"default": "debug",
|
||||
"help": "Log level for timers.",
|
||||
"id": "timers-log-level",
|
||||
"label": "Timers log level",
|
||||
"regex": "^(debug|info|notice|warn|err|crit|alert|emerg)$",
|
||||
"type": "select",
|
||||
"select": [
|
||||
"debug",
|
||||
"info",
|
||||
"notice",
|
||||
"warn",
|
||||
"err",
|
||||
"crit",
|
||||
"alert",
|
||||
"emerg"
|
||||
]
|
||||
},
|
||||
"OVERRIDE_INSTANCES": {
|
||||
"context": "global",
|
||||
"default": "",
|
||||
"help": "List of BunkerWeb instances separated with spaces (format : fqdn-or-ip:5000 fqdn-or-ip:5000)",
|
||||
"id": "override-instances",
|
||||
"label": "Override instances",
|
||||
"regex": "^.*$",
|
||||
"type": "text"
|
||||
}
|
||||
}
|
||||
32
templates/global.html
Normal file
32
templates/global.html
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
<form method="POST" action="/global" id="global-form">
|
||||
{% for field in form %}
|
||||
<div>Label is {{ field.label }}</div>
|
||||
<div>Description is {{ field.description }}</div>
|
||||
<div>Name is {{ field.name }}</div>
|
||||
<div>Value is {{ field.default }}</div>
|
||||
<div>Raw HTML is : {{ field }}</div>
|
||||
<hr>
|
||||
{% endfor %}
|
||||
<input type="submit" value="send">
|
||||
</form>
|
||||
|
||||
<script type="text/javascript">
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
document.querySelector('#global-form').addEventListener("submit", (event) => {
|
||||
console.log("ok");
|
||||
event.preventDefault();
|
||||
document.querySelectorAll('#global-form input[type=checkbox]').forEach( (checkbox) => {
|
||||
console.log(checkbox.name);
|
||||
if (!checkbox.checked) {
|
||||
var input = document.createElement("input");
|
||||
input.setAttribute("type", "hidden");
|
||||
input.setAttribute("name", checkbox.name);
|
||||
input.setAttribute("value", "no");
|
||||
checkbox.after(input);
|
||||
}
|
||||
});
|
||||
event.currentTarget.submit();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
Loading…
Reference in a new issue