mirror of
https://github.com/bunkerity/bunkerweb
synced 2026-05-24 09:28:37 +00:00
chore: Update web UI setup wizard to handle when a reverse proxy already exists but no UI user were configured
This commit is contained in:
parent
d665661012
commit
15fba7e026
4 changed files with 229 additions and 183 deletions
|
|
@ -38,6 +38,17 @@ location /setup/check {
|
|||
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;
|
||||
default_type 'text/plain';
|
||||
content_by_lua_block {
|
||||
-- Override CSP header
|
||||
ngx.header["Content-Security-Policy"] = "default-src 'none'; img-src 'self'; require-trusted-types-for 'script';"
|
||||
|
||||
-- Remove server header
|
||||
ngx.header["Server"] = nil
|
||||
|
||||
-- Override HSTS header
|
||||
if ngx.var.scheme == "https" then
|
||||
ngx.header["Strict-Transport-Security"] = "max-age=31536000; includeSubDomains; preload"
|
||||
end
|
||||
|
||||
local logger = require "bunkerweb.logger":new("UI")
|
||||
local args, err = ngx.req.get_uri_args(1)
|
||||
if err == "truncated" or not args["server_name"] or args["server_name"] == "" then
|
||||
|
|
|
|||
100
src/ui/main.py
100
src/ui/main.py
|
|
@ -213,7 +213,7 @@ def manage_bunkerweb(method: str, *args, operation: str = "reloads", is_draft: b
|
|||
elif operation == "delete":
|
||||
operation, error = app.config["CONFIG"].delete_service(args[2], check_changes=(was_draft != is_draft or not is_draft))
|
||||
elif method == "global_config":
|
||||
operation, error = app.config["CONFIG"].edit_global_conf(args[0])
|
||||
operation, error = app.config["CONFIG"].edit_global_conf(args[0], check_changes=True)
|
||||
|
||||
if operation == "reload":
|
||||
operation = app.config["INSTANCES"].reload_instance(args[0])
|
||||
|
|
@ -544,23 +544,29 @@ def check():
|
|||
|
||||
@app.route("/setup", methods=["GET", "POST"])
|
||||
def setup():
|
||||
db_config = app.config["CONFIG"].get_config(methods=False, filtered_settings=("SERVER_NAME", "USE_UI", "UI_HOST"))
|
||||
|
||||
for server_name in db_config["SERVER_NAME"].split(" "):
|
||||
if db_config.get(f"{server_name}_USE_UI", "no") == "yes":
|
||||
return redirect(url_for("login"), 301)
|
||||
db_config = app.config["CONFIG"].get_config(methods=False, filtered_settings=("SERVER_NAME", "MULTISITE", "USE_UI", "UI_HOST", "AUTO_LETS_ENCRYPT"))
|
||||
|
||||
admin_user = app.config["DB"].get_ui_user()
|
||||
if admin_user:
|
||||
admin_user = User(**admin_user)
|
||||
|
||||
ui_reverse_proxy = False
|
||||
for server_name in db_config["SERVER_NAME"].split(" "):
|
||||
if server_name and db_config.get(f"{server_name}_USE_UI", db_config.get("USE_UI", "no")) == "yes":
|
||||
if admin_user:
|
||||
return redirect(url_for("login"), 301)
|
||||
ui_reverse_proxy = True
|
||||
break
|
||||
|
||||
if request.method == "POST":
|
||||
if app.config["DB"].readonly:
|
||||
return redirect_flash_error("Database is in read-only mode", "setup")
|
||||
|
||||
is_request_form("setup")
|
||||
|
||||
required_keys = ["server_name", "ui_host", "ui_url"]
|
||||
required_keys = []
|
||||
if not ui_reverse_proxy:
|
||||
required_keys.extend(["server_name", "ui_host", "ui_url"])
|
||||
if not admin_user:
|
||||
required_keys.extend(["admin_username", "admin_password", "admin_password_check"])
|
||||
|
||||
|
|
@ -580,18 +586,6 @@ def setup():
|
|||
"setup",
|
||||
)
|
||||
|
||||
server_names = db_config["SERVER_NAME"].split(" ")
|
||||
if request.form["server_name"] in server_names:
|
||||
return redirect_flash_error(f"The hostname {request.form['server_name']} is already in use.", "setup")
|
||||
else:
|
||||
for server_name in server_names:
|
||||
if request.form["server_name"] in db_config.get(f"{server_name}_SERVER_NAME", "").split(" "):
|
||||
return redirect_flash_error(f"The hostname {request.form['server_name']} is already in use.", "setup")
|
||||
|
||||
if not REVERSE_PROXY_PATH.match(request.form["ui_host"]):
|
||||
return redirect_flash_error("The hostname is not valid.", "setup")
|
||||
|
||||
if not admin_user:
|
||||
admin_user = User(request.form["admin_username"], request.form["admin_password"], method="ui")
|
||||
|
||||
ret = app.config["DB"].create_ui_user(request.form["admin_username"], admin_user.password_hash, method="ui")
|
||||
|
|
@ -600,44 +594,62 @@ def setup():
|
|||
|
||||
flash("The admin user was created successfully", "success")
|
||||
|
||||
ui_data = get_ui_data()
|
||||
ui_data["RELOADING"] = True
|
||||
ui_data["LAST_RELOAD"] = time()
|
||||
if not ui_reverse_proxy:
|
||||
server_names = db_config["SERVER_NAME"].split(" ")
|
||||
if request.form["server_name"] in server_names:
|
||||
return redirect_flash_error(f"The hostname {request.form['server_name']} is already in use.", "setup")
|
||||
else:
|
||||
for server_name in server_names:
|
||||
if request.form["server_name"] in db_config.get(f"{server_name}_SERVER_NAME", "").split(" "):
|
||||
return redirect_flash_error(f"The hostname {request.form['server_name']} is already in use.", "setup")
|
||||
|
||||
config = {
|
||||
"SERVER_NAME": request.form["server_name"],
|
||||
"USE_UI": "yes",
|
||||
"USE_REVERSE_PROXY": "yes",
|
||||
"REVERSE_PROXY_HOST": request.form["ui_host"],
|
||||
"REVERSE_PROXY_URL": request.form["ui_url"] or "/",
|
||||
"INTERCEPTED_ERROR_CODES": "400 404 405 413 429 500 501 502 503 504",
|
||||
"MAX_CLIENT_SIZE": "50m",
|
||||
}
|
||||
if not REVERSE_PROXY_PATH.match(request.form["ui_host"]):
|
||||
return redirect_flash_error("The hostname is not valid.", "setup")
|
||||
|
||||
if request.form.get("auto_lets_encrypt", "no") == "yes":
|
||||
config["AUTO_LETS_ENCRYPT"] = "yes"
|
||||
else:
|
||||
config["GENERATE_SELF_SIGNED_SSL"] = "yes"
|
||||
ui_data = get_ui_data()
|
||||
ui_data["RELOADING"] = True
|
||||
ui_data["LAST_RELOAD"] = time()
|
||||
|
||||
# deepcode ignore MissingAPI: We don't need to check to wait for the thread to finish
|
||||
Thread(
|
||||
target=manage_bunkerweb,
|
||||
name="Reloading instances",
|
||||
args=("services", config, request.form["server_name"], request.form["server_name"]),
|
||||
kwargs={"operation": "new", "threaded": True},
|
||||
).start()
|
||||
config = {
|
||||
"SERVER_NAME": request.form["server_name"],
|
||||
"USE_UI": "yes",
|
||||
"USE_REVERSE_PROXY": "yes",
|
||||
"REVERSE_PROXY_HOST": request.form["ui_host"],
|
||||
"REVERSE_PROXY_URL": request.form["ui_url"] or "/",
|
||||
"INTERCEPTED_ERROR_CODES": "400 404 405 413 429 500 501 502 503 504",
|
||||
"MAX_CLIENT_SIZE": "50m",
|
||||
}
|
||||
|
||||
with LOCK:
|
||||
TMP_DATA_FILE.write_text(dumps(ui_data), encoding="utf-8")
|
||||
if request.form.get("auto_lets_encrypt", "no") == "yes":
|
||||
config["AUTO_LETS_ENCRYPT"] = "yes"
|
||||
else:
|
||||
config["GENERATE_SELF_SIGNED_SSL"] = "yes"
|
||||
config["SELF_SIGNED_SSL_SUBJ"] = f"/CN={request.form['server_name']}/"
|
||||
|
||||
if not config.get("MULTISITE", "no") == "yes":
|
||||
app.config["CONFIG"].edit_global_conf({"MULTISITE": "yes"}, check_changes=False)
|
||||
|
||||
# deepcode ignore MissingAPI: We don't need to check to wait for the thread to finish
|
||||
Thread(
|
||||
target=manage_bunkerweb,
|
||||
name="Reloading instances",
|
||||
args=("services", config, request.form["server_name"], request.form["server_name"]),
|
||||
kwargs={"operation": "new", "threaded": True},
|
||||
).start()
|
||||
|
||||
with LOCK:
|
||||
TMP_DATA_FILE.write_text(dumps(ui_data), encoding="utf-8")
|
||||
|
||||
return Response(status=200)
|
||||
|
||||
return render_template(
|
||||
"setup.html",
|
||||
ui_user=admin_user,
|
||||
ui_reverse_proxy=ui_reverse_proxy,
|
||||
username=getenv("ADMIN_USERNAME", ""),
|
||||
password=getenv("ADMIN_PASSWORD", ""),
|
||||
ui_host=db_config.get("UI_HOST", getenv("UI_HOST", "")),
|
||||
auto_lets_encrypt=db_config.get("AUTO_LETS_ENCRYPT", getenv("AUTO_LETS_ENCRYPT", "no")) == "yes",
|
||||
random_url=f"/{''.join(choice(ascii_letters + digits) for _ in range(10))}",
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -226,7 +226,7 @@ class Config:
|
|||
return ret, 1
|
||||
return f"Configuration for {old_server_name_splitted[0]} has been edited.", 0
|
||||
|
||||
def edit_global_conf(self, variables: dict) -> Tuple[str, int]:
|
||||
def edit_global_conf(self, variables: dict, *, check_changes: bool = True) -> Tuple[str, int]:
|
||||
"""Edits the global conf
|
||||
|
||||
Parameters
|
||||
|
|
@ -239,7 +239,7 @@ class Config:
|
|||
str
|
||||
the confirmation message
|
||||
"""
|
||||
ret = self.__gen_conf(self.get_config(methods=False) | variables, self.get_services(methods=False))
|
||||
ret = self.__gen_conf(self.get_config(methods=False) | variables, self.get_services(methods=False), check_changes=check_changes)
|
||||
if isinstance(ret, str):
|
||||
return ret, 1
|
||||
return "The global configuration has been edited.", 0
|
||||
|
|
|
|||
297
src/ui/templates/setup.html
vendored
297
src/ui/templates/setup.html
vendored
|
|
@ -180,105 +180,117 @@
|
|||
{% else %}
|
||||
<h6 class="col-span-12 block text-left font-bold mb-4 mt-2">🧑🚀 An admin user already exists</h6>
|
||||
{% endif %}
|
||||
<h2 class="col-span-12 block text-left font-bold mb-4 mt-2 text-2xl">Settings</h2>
|
||||
<!-- ui host-->
|
||||
<div class="flex flex-col relative col-span-12 my-3 mx-2 max-w-[400px] w-full">
|
||||
<h5 class="text-base my-1 transition duration-300 ease-in-out text-md font-bold m-0">
|
||||
UI Host (REVERSE_PROXY_HOST)<strong class="required-mark">*</strong>
|
||||
</h5>
|
||||
<label class="sr-only" for="ui_host">ui host</label>
|
||||
<input tabindex="1"
|
||||
type="text"
|
||||
id="ui_host"
|
||||
name="ui_host"
|
||||
value="{{ ui_host }}"
|
||||
class="col-span-12 disabled:opacity-75 focus:valid:border-green-500 focus:invalid:border-red-500 outline-none focus:border-primary text-sm leading-5.6 ease block w-full appearance-none rounded-lg border border-solid border-gray-300 bg-white bg-clip-padding px-4 py-2 font-normal text-gray-700 transition-all placeholder:text-gray-500"
|
||||
placeholder="http://[hostname](:[port])"
|
||||
pattern="^https?:\/\/.{1,255}(:((6553[0-5])|(655[0-2][0-9])|(65[0-4][0-9]{2})|(6[0-4][0-9]{3})|([1-5][0-9]{4})|([0-5]{0,5})|([0-9]{1,4})))?$"
|
||||
required />
|
||||
</div>
|
||||
<!-- end ui host-->
|
||||
<!-- ui url-->
|
||||
<div class="flex flex-col relative col-span-12 my-3 mx-2 max-w-[400px] w-full">
|
||||
<h5 class="text-base my-1 transition duration-300 ease-in-out text-md font-bold m-0">
|
||||
UI URL (REVERSE_PROXY_URL)<strong class="required-mark">*</strong>
|
||||
</h5>
|
||||
<label class="sr-only" for="ui_url">ui url</label>
|
||||
<input tabindex="1"
|
||||
type="text"
|
||||
id="ui_url"
|
||||
name="ui_url"
|
||||
class="col-span-12 disabled:opacity-75 focus:valid:border-green-500 focus:invalid:border-red-500 outline-none focus:border-primary text-sm leading-5.6 ease block w-full appearance-none rounded-lg border border-solid border-gray-300 bg-white bg-clip-padding px-4 py-2 font-normal text-gray-700 transition-all placeholder:text-gray-500"
|
||||
placeholder="/admin"
|
||||
value="{{ random_url }}"
|
||||
pattern="^\/([\/a-zA-Z0-9\-]{0,255})$"
|
||||
required />
|
||||
</div>
|
||||
<!-- end ui url-->
|
||||
<!-- server name-->
|
||||
<div class="flex flex-col relative col-span-12 my-3 mx-2 max-w-[400px] w-full">
|
||||
<h5 class="text-base my-1 transition duration-300 ease-in-out text-md font-bold m-0">
|
||||
Server name<strong class="required-mark">*</strong>
|
||||
</h5>
|
||||
<label class="sr-only" for="server_name">server name</label>
|
||||
<input tabindex="1"
|
||||
type="text"
|
||||
id="server_name"
|
||||
name="server_name"
|
||||
class="col-span-12 disabled:opacity-75 focus:valid:border-green-500 focus:invalid:border-red-500 outline-none focus:border-primary text-sm leading-5.6 ease block w-full appearance-none rounded-lg border border-solid border-gray-300 bg-white bg-clip-padding px-4 py-2 font-normal text-gray-700 transition-all placeholder:text-gray-500"
|
||||
placeholder="www.example.com"
|
||||
value="www.example.com"
|
||||
pattern=".*"
|
||||
minlength="1"
|
||||
required />
|
||||
</div>
|
||||
<!-- end server name-->
|
||||
<div class="flex flex-col relative col-span-12 my-3 mx-2 max-w-[400px] w-full">
|
||||
<h5 class="text-base my-1 transition duration-300 ease-in-out text-md font-bold m-0">Check server name DNS</h5>
|
||||
<div class="flex justify-start items-center">
|
||||
<button tabindex="1"
|
||||
id="check-server-name"
|
||||
class="flex justify-start w-fit tracking-wide inline-block px-6 py-3 font-bold text-center text-white uppercase align-middle transition-all rounded-lg cursor-pointer bg-primary hover:bg-primary/80 focus:bg-primary/80 leading-normal text-xs ease-in shadow-xs bg-150 bg-x-25 hover:-translate-y-px active:opacity-85 hover:shadow-md">
|
||||
<span>check</span>
|
||||
<span aria-check-color
|
||||
class="block ml-2 rounded-full w-4 h-4 bg-gray-300"
|
||||
aria-description="show state of server name"></span>
|
||||
<span class="sr-only" aria-check-result></span>
|
||||
</button>
|
||||
</div>
|
||||
<p class="mt-4">In case of issues, you can also click <a id="check_url" class="privacy-link" href="https://www.example.com/setup/check" target="_blank">here</a> to perform a manual check.</p>
|
||||
</div>
|
||||
<!-- auto let's encrypt-->
|
||||
<div class="flex flex-col relative col-span-12 my-3 mx-2 max-w-[400px] w-full">
|
||||
<h5 class="text-base my-1 transition duration-300 ease-in-out text-md font-bold m-0">Auto let's encrypt</h5>
|
||||
<label class="sr-only" for="auto_lets_encrypt">auto let's encrypt</label>
|
||||
<div data-checkbox-handler="auto_lets_encrypt"
|
||||
class="relative mb-7 md:mb-0 z-10">
|
||||
{% if not ui_reverse_proxy %}
|
||||
<h2 class="col-span-12 block text-left font-bold mb-4 mt-2 text-2xl">Settings</h2>
|
||||
<!-- ui host-->
|
||||
<div class="flex flex-col relative col-span-12 my-3 mx-2 max-w-[400px] w-full">
|
||||
<h5 class="text-base my-1 transition duration-300 ease-in-out text-md font-bold m-0">
|
||||
UI Host (REVERSE_PROXY_HOST)<strong class="required-mark">*</strong>
|
||||
</h5>
|
||||
<label class="sr-only" for="ui_host">ui host</label>
|
||||
<input tabindex="1"
|
||||
data-check
|
||||
type="checkbox"
|
||||
id="auto_lets_encrypt"
|
||||
name="auto_lets_encrypt"
|
||||
data-checked="false"
|
||||
class="checkbox"
|
||||
value="no" />
|
||||
<svg data-checkbox-handler="auto_lets_encrypt"
|
||||
class="pointer-events-none absolute fill-white left-0 top-0 translate-x-1 translate-y-2 h-3 w-3"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512">
|
||||
<path class="pointer-events-none" d="M470.6 105.4c12.5 12.5 12.5 32.8 0 45.3l-256 256c-12.5 12.5-32.8 12.5-45.3 0l-128-128c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0L192 338.7 425.4 105.4c12.5-12.5 32.8-12.5 45.3 0z">
|
||||
</path>
|
||||
</svg>
|
||||
type="text"
|
||||
id="ui_host"
|
||||
name="ui_host"
|
||||
value="{{ ui_host }}"
|
||||
class="col-span-12 disabled:opacity-75 focus:valid:border-green-500 focus:invalid:border-red-500 outline-none focus:border-primary text-sm leading-5.6 ease block w-full appearance-none rounded-lg border border-solid border-gray-300 bg-white bg-clip-padding px-4 py-2 font-normal text-gray-700 transition-all placeholder:text-gray-500"
|
||||
placeholder="http://[hostname](:[port])"
|
||||
pattern="^https?:\/\/.{1,255}(:((6553[0-5])|(655[0-2][0-9])|(65[0-4][0-9]{2})|(6[0-4][0-9]{3})|([1-5][0-9]{4})|([0-5]{0,5})|([0-9]{1,4})))?$"
|
||||
required />
|
||||
</div>
|
||||
</div>
|
||||
<!-- end auto let's encrypt-->
|
||||
<div class="p-2 col-span-12 bg-gray-200 mt-4 md:mt-6 mb-1 py-2 px-2 rounded flex flex-col justify-center items-center w-full max-w-[400px] overflow-hidden">
|
||||
<h5 class="text-sm md:text-base text-center mt-1 mb-2 transition duration-300 ease-in-out text-md font-bold m-0">
|
||||
Your BunkerWeb UI final URL will be
|
||||
</h5>
|
||||
<p class="family-text text-center text-sm md:text-base break-words w-full px-4"
|
||||
data-resume>https://</p>
|
||||
</div>
|
||||
<!-- end ui host-->
|
||||
<!-- ui url-->
|
||||
<div class="flex flex-col relative col-span-12 my-3 mx-2 max-w-[400px] w-full">
|
||||
<h5 class="text-base my-1 transition duration-300 ease-in-out text-md font-bold m-0">
|
||||
UI URL (REVERSE_PROXY_URL)<strong class="required-mark">*</strong>
|
||||
</h5>
|
||||
<label class="sr-only" for="ui_url">ui url</label>
|
||||
<input tabindex="1"
|
||||
type="text"
|
||||
id="ui_url"
|
||||
name="ui_url"
|
||||
class="col-span-12 disabled:opacity-75 focus:valid:border-green-500 focus:invalid:border-red-500 outline-none focus:border-primary text-sm leading-5.6 ease block w-full appearance-none rounded-lg border border-solid border-gray-300 bg-white bg-clip-padding px-4 py-2 font-normal text-gray-700 transition-all placeholder:text-gray-500"
|
||||
placeholder="/admin"
|
||||
value="{{ random_url }}"
|
||||
pattern="^\/([\/a-zA-Z0-9\-]{0,255})$"
|
||||
required />
|
||||
</div>
|
||||
<!-- end ui url-->
|
||||
<!-- server name-->
|
||||
<div class="flex flex-col relative col-span-12 my-3 mx-2 max-w-[400px] w-full">
|
||||
<h5 class="text-base my-1 transition duration-300 ease-in-out text-md font-bold m-0">
|
||||
Server name<strong class="required-mark">*</strong>
|
||||
</h5>
|
||||
<label class="sr-only" for="server_name">server name</label>
|
||||
<input tabindex="1"
|
||||
type="text"
|
||||
id="server_name"
|
||||
name="server_name"
|
||||
class="col-span-12 disabled:opacity-75 focus:valid:border-green-500 focus:invalid:border-red-500 outline-none focus:border-primary text-sm leading-5.6 ease block w-full appearance-none rounded-lg border border-solid border-gray-300 bg-white bg-clip-padding px-4 py-2 font-normal text-gray-700 transition-all placeholder:text-gray-500"
|
||||
placeholder="www.example.com"
|
||||
value="www.example.com"
|
||||
pattern=".*"
|
||||
minlength="1"
|
||||
required />
|
||||
</div>
|
||||
<!-- end server name-->
|
||||
<div class="flex flex-col relative col-span-12 my-3 mx-2 max-w-[400px] w-full">
|
||||
<h5 class="text-base my-1 transition duration-300 ease-in-out text-md font-bold m-0">Check server name DNS</h5>
|
||||
<div class="flex justify-start items-center">
|
||||
<button tabindex="1"
|
||||
id="check-server-name"
|
||||
class="flex justify-start w-fit tracking-wide inline-block px-6 py-3 font-bold text-center text-white uppercase align-middle transition-all rounded-lg cursor-pointer bg-primary hover:bg-primary/80 focus:bg-primary/80 leading-normal text-xs ease-in shadow-xs bg-150 bg-x-25 hover:-translate-y-px active:opacity-85 hover:shadow-md">
|
||||
<span>check</span>
|
||||
<span aria-check-color
|
||||
class="block ml-2 rounded-full w-4 h-4 bg-gray-300"
|
||||
aria-description="show state of server name"></span>
|
||||
<span class="sr-only" aria-check-result></span>
|
||||
</button>
|
||||
</div>
|
||||
<p class="mt-4">
|
||||
In case of issues, you can also click <a id="check_url"
|
||||
class="privacy-link"
|
||||
href="https://www.example.com/setup/check"
|
||||
target="_blank">here</a> to perform a manual check.
|
||||
</p>
|
||||
</div>
|
||||
<!-- auto let's encrypt-->
|
||||
<div class="flex flex-col relative col-span-12 my-3 mx-2 max-w-[400px] w-full">
|
||||
<h5 class="text-base my-1 transition duration-300 ease-in-out text-md font-bold m-0">Auto let's encrypt</h5>
|
||||
<label class="sr-only" for="auto_lets_encrypt">auto let's encrypt</label>
|
||||
<div data-checkbox-handler="auto_lets_encrypt"
|
||||
class="relative mb-7 md:mb-0 z-10">
|
||||
<input tabindex="1"
|
||||
data-check
|
||||
type="checkbox"
|
||||
id="auto_lets_encrypt"
|
||||
name="auto_lets_encrypt"
|
||||
data-checked="{% if auto_lets_encrypt %}true{% else %}false{% endif %}"
|
||||
{% if auto_lets_encrypt %}checked{% endif %}
|
||||
class="checkbox"
|
||||
value="no" />
|
||||
<svg data-checkbox-handler="auto_lets_encrypt"
|
||||
class="pointer-events-none absolute fill-white left-0 top-0 translate-x-1 translate-y-2 h-3 w-3"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512">
|
||||
<path class="pointer-events-none" d="M470.6 105.4c12.5 12.5 12.5 32.8 0 45.3l-256 256c-12.5 12.5-32.8 12.5-45.3 0l-128-128c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0L192 338.7 425.4 105.4c12.5-12.5 32.8-12.5 45.3 0z">
|
||||
</path>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end auto let's encrypt-->
|
||||
<div class="p-2 col-span-12 bg-gray-200 mt-4 md:mt-6 mb-1 py-2 px-2 rounded flex flex-col justify-center items-center w-full max-w-[400px] overflow-hidden">
|
||||
<h5 class="text-sm md:text-base text-center mt-1 mb-2 transition duration-300 ease-in-out text-md font-bold m-0">
|
||||
Your BunkerWeb UI final URL will be
|
||||
</h5>
|
||||
<p class="family-text text-center text-sm md:text-base break-words w-full px-4"
|
||||
data-resume>https://</p>
|
||||
</div>
|
||||
{% else %}
|
||||
<h6 class="col-span-12 block text-left font-bold mb-4 mt-2">
|
||||
↪️ A reverse proxy is already configured for the web interface
|
||||
</h6>
|
||||
{% endif %}
|
||||
<h2 class="col-span-12 block text-left font-bold my-4 text-2xl">Newsletter</h2>
|
||||
<!-- email inpt-->
|
||||
<div class="flex flex-col relative col-span-12 mx-2 max-w-[400px] w-full">
|
||||
|
|
@ -350,6 +362,7 @@
|
|||
</form>
|
||||
</main>
|
||||
<script nonce="{{ script_nonce }}">
|
||||
{% if not ui_reverse_proxy %}
|
||||
class ServerCheck {
|
||||
constructor() {
|
||||
this.servInp = document.querySelector("#server_name");
|
||||
|
|
@ -472,41 +485,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
class Loader {
|
||||
constructor() {
|
||||
this.menuContainer = document.querySelector("[data-menu-container]");
|
||||
this.loaderContainer = document.querySelector("[data-loader]");
|
||||
this.logoEl = document.querySelector("[data-loader-img]");
|
||||
this.isLoading = true;
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
this.loaderContainer.setAttribute("aria-hidden", "false");
|
||||
this.loading();
|
||||
window.addEventListener("load", (e) => {
|
||||
setTimeout(() => {
|
||||
this.loaderContainer.classList.add("opacity-0");
|
||||
}, 550);
|
||||
|
||||
setTimeout(() => {
|
||||
this.isLoading = false;
|
||||
this.loaderContainer.classList.add("hidden");
|
||||
this.loaderContainer.setAttribute("aria-hidden", "true");
|
||||
}, 850);
|
||||
});
|
||||
}
|
||||
|
||||
loading() {
|
||||
if ((this.isLoading = true)) {
|
||||
setTimeout(() => {
|
||||
this.logoEl.classList.toggle("scale-105");
|
||||
this.loading();
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Checkbox {
|
||||
constructor() {
|
||||
this.init();
|
||||
|
|
@ -549,18 +527,56 @@
|
|||
});
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
class Loader {
|
||||
constructor() {
|
||||
this.menuContainer = document.querySelector("[data-menu-container]");
|
||||
this.loaderContainer = document.querySelector("[data-loader]");
|
||||
this.logoEl = document.querySelector("[data-loader-img]");
|
||||
this.isLoading = true;
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
this.loaderContainer.setAttribute("aria-hidden", "false");
|
||||
this.loading();
|
||||
window.addEventListener("load", (e) => {
|
||||
setTimeout(() => {
|
||||
this.loaderContainer.classList.add("opacity-0");
|
||||
}, 550);
|
||||
|
||||
setTimeout(() => {
|
||||
this.isLoading = false;
|
||||
this.loaderContainer.classList.add("hidden");
|
||||
this.loaderContainer.setAttribute("aria-hidden", "true");
|
||||
}, 850);
|
||||
});
|
||||
}
|
||||
|
||||
loading() {
|
||||
if ((this.isLoading = true)) {
|
||||
setTimeout(() => {
|
||||
this.logoEl.classList.toggle("scale-105");
|
||||
this.loading();
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SubmitForm {
|
||||
constructor() {
|
||||
this.formEl = document.querySelector("#setup-form");
|
||||
{% if not ui_user %}
|
||||
this.pwEl = document.querySelector("#admin_password");
|
||||
this.pwCheckEl = document.querySelector("#admin_password_check");
|
||||
this.pwAlertEl = document.querySelector("[data-pw-alert]");
|
||||
{% endif %}
|
||||
this.formEl = document.querySelector("#setup-form");
|
||||
{% if not ui_reverse_proxy %}
|
||||
this.servInp = document.querySelector("#server_name");
|
||||
this.sslCheck = document.querySelector("#auto_lets_encrypt");
|
||||
this.urlInp = document.querySelector("#ui_url");
|
||||
{% endif %}
|
||||
this.newsForm = document.querySelector("#newsletter-form");
|
||||
this.emailInp = document.querySelector("#newsletter-email")
|
||||
this.checkEmailInp = document.querySelector("#newsletter-check");
|
||||
|
|
@ -623,7 +639,8 @@
|
|||
}
|
||||
|
||||
// send form and wait for response
|
||||
let api = `https://${this.servInp.value}`;
|
||||
{% if not ui_reverse_proxy %}
|
||||
var api = `https://${this.servInp.value}`;
|
||||
if (!this.urlInp.value.startsWith("/")) {
|
||||
api = `${api}/`;
|
||||
}
|
||||
|
|
@ -631,6 +648,10 @@
|
|||
if (!api.endsWith("/")) {
|
||||
api = `${api}/`;
|
||||
}
|
||||
var redirect = `https://${this.servInp.value}/setup/loading?target_uri=${this.urlInp.value}`;
|
||||
{% else %}
|
||||
var redirect = window.location.href.replace("setup", "login");
|
||||
{% endif %}
|
||||
|
||||
fetch(window.location.href, {
|
||||
method: "POST",
|
||||
|
|
@ -639,7 +660,7 @@
|
|||
})
|
||||
.then((res) => {
|
||||
if (res.status === 200) {
|
||||
window.location.href = `https://${this.servInp.value}/setup/loading?target_uri=${this.urlInp.value}`;
|
||||
window.location.href = redirect;
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
|
|
@ -759,11 +780,13 @@
|
|||
}
|
||||
}
|
||||
|
||||
const setFlash = new FlashMsg()
|
||||
const setLoader = new Loader();
|
||||
const setFlash = new FlashMsg();
|
||||
{% if not ui_reverse_proxy %}
|
||||
const setResume = new Resume();
|
||||
const setCheck = new Checkbox();
|
||||
const setStateServ = new ServerCheck();
|
||||
{% endif %}
|
||||
const setLoader = new Loader();
|
||||
const setSubmit = new SubmitForm();
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
|||
Loading…
Reference in a new issue