mirror of
https://github.com/bunkerity/bunkerweb
synced 2026-05-24 09:28:37 +00:00
Add UI tests for the profile page and the Wizard
This commit is contained in:
parent
13f477b758
commit
d1d82aa300
5 changed files with 306 additions and 31 deletions
|
|
@ -7,9 +7,8 @@ services:
|
|||
dockerfile: src/bw/Dockerfile
|
||||
ports:
|
||||
- 80:80
|
||||
- 443:8443
|
||||
environment:
|
||||
SERVER_NAME: "www.example.com"
|
||||
SERVER_NAME: ""
|
||||
MULTISITE: "yes"
|
||||
HTTP_PORT: "80"
|
||||
API_WHITELIST_IP: "127.0.0.0/8 10.20.30.0/24"
|
||||
|
|
@ -20,12 +19,7 @@ services:
|
|||
USE_CLIENT_CACHE: "yes"
|
||||
USE_GZIP: "yes"
|
||||
DATASTORE_MEMORY_SIZE: "384m"
|
||||
www.example.com_USE_UI: "yes"
|
||||
www.example.com_SERVE_FILES: "no"
|
||||
www.example.com_USE_REVERSE_PROXY: "yes"
|
||||
www.example.com_REVERSE_PROXY_URL: "/admin"
|
||||
www.example.com_REVERSE_PROXY_HOST: "http://bw-ui:7000"
|
||||
www.example.com_INTERCEPTED_ERROR_CODES: "400 405 413 429 500 501 502 503 504"
|
||||
UI_HOST: "http://bw-ui:7000"
|
||||
labels:
|
||||
- "bunkerweb.INSTANCE=yes"
|
||||
networks:
|
||||
|
|
@ -57,8 +51,6 @@ services:
|
|||
volumes:
|
||||
- bw-data:/data
|
||||
environment:
|
||||
ADMIN_USERNAME: "admin"
|
||||
ADMIN_PASSWORD: "S$$cr3tP@ssw0rd"
|
||||
DOCKER_HOST: "tcp://docker-proxy:2375"
|
||||
networks:
|
||||
- net-docker
|
||||
|
|
|
|||
|
|
@ -6,9 +6,8 @@ services:
|
|||
pull_policy: never
|
||||
ports:
|
||||
- 80:80
|
||||
- 443:8443
|
||||
environment:
|
||||
SERVER_NAME: "www.example.com"
|
||||
SERVER_NAME: ""
|
||||
MULTISITE: "yes"
|
||||
HTTP_PORT: "80"
|
||||
API_WHITELIST_IP: "127.0.0.0/8 10.20.30.0/24"
|
||||
|
|
@ -20,13 +19,8 @@ services:
|
|||
USE_CLIENT_CACHE: "yes"
|
||||
USE_GZIP: "yes"
|
||||
DATASTORE_MEMORY_SIZE: "384m"
|
||||
www.example.com_USE_UI: "yes"
|
||||
www.example.com_SERVE_FILES: "no"
|
||||
www.example.com_USE_REVERSE_PROXY: "yes"
|
||||
www.example.com_REVERSE_PROXY_URL: "/admin"
|
||||
www.example.com_REVERSE_PROXY_HOST: "http://bw-ui:7000"
|
||||
www.example.com_INTERCEPTED_ERROR_CODES: "400 405 413 429 500 501 502 503 504"
|
||||
CUSTOM_CONF_SERVER_HTTP_port-redirect: "port_in_redirect on;"
|
||||
UI_HOST: "http://bw-ui:7000"
|
||||
labels:
|
||||
- "bunkerweb.INSTANCE=yes"
|
||||
networks:
|
||||
|
|
@ -54,8 +48,6 @@ services:
|
|||
- bw
|
||||
- bw-docker-proxy
|
||||
environment:
|
||||
ADMIN_USERNAME: "admin"
|
||||
ADMIN_PASSWORD: "S$$cr3tP@ssw0rd"
|
||||
DOCKER_HOST: "tcp://bw-docker-proxy:2375"
|
||||
volumes:
|
||||
- bw-data:/data
|
||||
|
|
|
|||
308
tests/ui/main.py
308
tests/ui/main.py
|
|
@ -7,6 +7,7 @@ from pathlib import Path
|
|||
from time import sleep
|
||||
from traceback import format_exc
|
||||
from typing import List, Union
|
||||
from pyotp import TOTP
|
||||
from requests import get
|
||||
from requests.exceptions import RequestException
|
||||
from selenium import webdriver
|
||||
|
|
@ -23,7 +24,7 @@ ready = False
|
|||
retries = 0
|
||||
while not ready:
|
||||
with suppress(RequestException):
|
||||
status_code = get("http://www.example.com/admin/login").status_code
|
||||
status_code = get("http://127.0.0.1/setup").status_code
|
||||
|
||||
if status_code > 500 and status_code != 502:
|
||||
print("An error occurred with the server, exiting ...", flush=True)
|
||||
|
|
@ -178,9 +179,41 @@ with driver_func() as driver:
|
|||
driver.maximize_window()
|
||||
driver_wait = WebDriverWait(driver, 60)
|
||||
|
||||
print("Navigating to http://www.example.com/admin/login ...", flush=True)
|
||||
print("Navigating to http://127.0.0.1/setup ...", flush=True)
|
||||
|
||||
driver.get("http://www.example.com/admin/login")
|
||||
driver.get("http://127.0.0.1/setup")
|
||||
|
||||
### WIZARD PAGE
|
||||
|
||||
try:
|
||||
title = driver_wait.until(EC.presence_of_element_located((By.XPATH, "/html/body/main/div/div/h1")))
|
||||
|
||||
if title.text != "Setup Wizard":
|
||||
print("Didn't get redirected to setup page, exiting ...", flush=True)
|
||||
exit(1)
|
||||
except TimeoutException:
|
||||
print("Didn't get redirected to setup page, exiting ...", flush=True)
|
||||
exit(1)
|
||||
|
||||
print("Setup page loaded successfully, filling the form ...", flush=True)
|
||||
|
||||
admin_username_input = safe_get_element(driver, By.ID, "admin_username")
|
||||
password_input = safe_get_element(driver, By.ID, "admin_password")
|
||||
password_check_input = safe_get_element(driver, By.ID, "admin_password_check")
|
||||
ui_url = safe_get_element(driver, By.ID, "ui_url").get_attribute("value")
|
||||
|
||||
admin_username_input.send_keys("admin")
|
||||
password_input.send_keys("S$cr3tP@ssw0rd")
|
||||
password_check_input.send_keys("S$cr3tP@ssw0rd")
|
||||
|
||||
assert_button_click(driver, "//button[@id='setup-button']")
|
||||
|
||||
print("Submitted the form, waiting for the wizard to finish ...", flush=True)
|
||||
|
||||
current_time = datetime.now()
|
||||
|
||||
while current_time + timedelta(minutes=5) > datetime.now() and not driver.current_url.endswith("/login"):
|
||||
sleep(1)
|
||||
|
||||
### LOGIN PAGE
|
||||
|
||||
|
|
@ -197,7 +230,7 @@ with driver_func() as driver:
|
|||
flush=True,
|
||||
)
|
||||
|
||||
driver.get("http://www.example.com/admin/home")
|
||||
driver.get(f"http://www.example.com{ui_url}/home")
|
||||
|
||||
print("Waiting for toast ...", flush=True)
|
||||
|
||||
|
|
@ -508,9 +541,9 @@ with driver_func() as driver:
|
|||
print("The service is not present, exiting ...", flush=True)
|
||||
exit(1)
|
||||
|
||||
if service.find_element(By.TAG_NAME, "h6").text.strip() != "scheduler":
|
||||
if service.find_element(By.TAG_NAME, "h6").text.strip() != "ui":
|
||||
print(
|
||||
"The service should have been created by the scheduler, exiting ...",
|
||||
"The service should have been created by the ui, exiting ...",
|
||||
flush=True,
|
||||
)
|
||||
exit(1)
|
||||
|
|
@ -1260,8 +1293,8 @@ location /hello {
|
|||
|
||||
current_date = datetime.now()
|
||||
resp = get(
|
||||
f"http://www.example.com/admin/logs/{first_instance}?from_date={int(current_date.timestamp() - 86400000)}&to_date={int((current_date - timedelta(days=1)).timestamp())}",
|
||||
headers={"Host": "www.example.com"},
|
||||
f"http://www.example.com{ui_url}/logs/{first_instance}?from_date={int(current_date.timestamp() - 86400000)}&to_date={int((current_date - timedelta(days=1)).timestamp())}",
|
||||
headers={"Host": "www.example.com", "User-Agent": driver.execute_script("return navigator.userAgent;")},
|
||||
cookies={"session": driver.get_cookies()[0]["value"]},
|
||||
)
|
||||
|
||||
|
|
@ -1396,13 +1429,173 @@ location /hello {
|
|||
|
||||
sleep(0.3)
|
||||
|
||||
resp = get("http://www.example.com/admin/jobs/download?job_name=mmdb-country&file_name=country.mmdb")
|
||||
resp = get(f"http://www.example.com{ui_url}/jobs/download?job_name=mmdb-country&file_name=country.mmdb")
|
||||
|
||||
if resp.status_code != 200:
|
||||
print("The cache download is not working, exiting ...", flush=True)
|
||||
exit(1)
|
||||
|
||||
print("Cache download is working, trying to log out ...", flush=True)
|
||||
print("Cache download is working, trying profile page ...", flush=True)
|
||||
|
||||
access_page(driver, driver_wait, "/html/body/aside[1]/div[1]/div[2]/ul/li[10]/a", "profile")
|
||||
|
||||
### PROFILE PAGE
|
||||
|
||||
username_input = safe_get_element(driver, By.ID, "admin_username")
|
||||
|
||||
if username_input.get_attribute("value") != "admin":
|
||||
print("The username is not correct, exiting ...", flush=True)
|
||||
exit(1)
|
||||
|
||||
username_input.clear()
|
||||
username_input.send_keys("admin2")
|
||||
|
||||
password_input = safe_get_element(driver, By.ID, "curr_password")
|
||||
|
||||
if password_input.get_attribute("value") != "":
|
||||
print("The current password is not empty, exiting ...", flush=True)
|
||||
exit(1)
|
||||
|
||||
password_input.send_keys("S$cr3tP@ssw0rd")
|
||||
|
||||
assert_button_click(driver, "//button[@id='profile-button' and @class='edit-btn']")
|
||||
|
||||
try:
|
||||
title = driver_wait.until(EC.presence_of_element_located((By.XPATH, "/html/body/main/div[1]/div/h1")))
|
||||
|
||||
if title.text != "Log in":
|
||||
print("Didn't get redirected to login page, exiting ...", flush=True)
|
||||
exit(1)
|
||||
except TimeoutException:
|
||||
print("Login page didn't load in time, exiting ...", flush=True)
|
||||
exit(1)
|
||||
|
||||
print("Successfully changed username, trying to log in with new username ...", flush=True)
|
||||
|
||||
username_input = safe_get_element(driver, By.ID, "username")
|
||||
password_input = safe_get_element(driver, By.ID, "password")
|
||||
username_input.send_keys("admin2")
|
||||
password_input.send_keys("S$cr3tP@ssw0rd")
|
||||
|
||||
access_page(
|
||||
driver,
|
||||
driver_wait,
|
||||
"//button[@value='login']",
|
||||
"profile",
|
||||
)
|
||||
|
||||
username_input = safe_get_element(driver, By.ID, "admin_username")
|
||||
|
||||
if username_input.get_attribute("value") != "admin2":
|
||||
print("The username is not correct, exiting ...", flush=True)
|
||||
exit(1)
|
||||
|
||||
print("Successfully logged in with new username, trying to change password ...", flush=True)
|
||||
|
||||
password_input = safe_get_element(driver, By.ID, "curr_password")
|
||||
|
||||
if password_input.get_attribute("value") != "":
|
||||
print("The current password is not empty, exiting ...", flush=True)
|
||||
exit(1)
|
||||
|
||||
password_input.send_keys("S$cr3tP@ssw0rd")
|
||||
|
||||
new_password_input = safe_get_element(driver, By.ID, "admin_password")
|
||||
|
||||
if new_password_input.get_attribute("value") != "":
|
||||
print("The new password is not empty, exiting ...", flush=True)
|
||||
exit(1)
|
||||
|
||||
new_password_input.send_keys("P@ssw0rd")
|
||||
|
||||
new_password_check_input = safe_get_element(driver, By.ID, "admin_password_check")
|
||||
|
||||
if new_password_check_input.get_attribute("value") != "":
|
||||
print("The new password check is not empty, exiting ...", flush=True)
|
||||
exit(1)
|
||||
|
||||
new_password_check_input.send_keys("P@ssw0rd")
|
||||
|
||||
assert_button_click(driver, "//button[@id='profile-button' and @class='edit-btn']")
|
||||
|
||||
try:
|
||||
title = driver_wait.until(EC.presence_of_element_located((By.XPATH, "/html/body/main/div[1]/div/h1")))
|
||||
|
||||
if title.text != "Log in":
|
||||
print("Didn't get redirected to login page, exiting ...", flush=True)
|
||||
exit(1)
|
||||
except TimeoutException:
|
||||
print("Login page didn't load in time, exiting ...", flush=True)
|
||||
exit(1)
|
||||
|
||||
print("Successfully changed username, trying to log in with new password ...", flush=True)
|
||||
|
||||
username_input = safe_get_element(driver, By.ID, "username")
|
||||
password_input = safe_get_element(driver, By.ID, "password")
|
||||
username_input.send_keys("admin2")
|
||||
password_input.send_keys("P@ssw0rd")
|
||||
|
||||
access_page(
|
||||
driver,
|
||||
driver_wait,
|
||||
"//button[@value='login']",
|
||||
"profile",
|
||||
)
|
||||
|
||||
print("Successfully logged in with new password, trying 2FA ...", flush=True)
|
||||
|
||||
assert_button_click(driver, "//button[@data-tab-handler='totp']")
|
||||
|
||||
secret_token_input = safe_get_element(driver, By.ID, "secret_token")
|
||||
secret_token = secret_token_input.get_attribute("value")
|
||||
|
||||
driver.refresh()
|
||||
|
||||
driver_wait.until(EC.presence_of_element_located((By.XPATH, "/html/body/div/header/div/nav/h6")))
|
||||
|
||||
assert_button_click(driver, "//button[@data-tab-handler='totp']")
|
||||
|
||||
secret_token_input = safe_get_element(driver, By.ID, "secret_token")
|
||||
new_secret_token = secret_token_input.get_attribute("value")
|
||||
|
||||
if new_secret_token == secret_token:
|
||||
print("The secret token hasn't been changed, exiting ...", flush=True)
|
||||
exit(1)
|
||||
|
||||
print("The secret token has been changed, trying to activate 2FA ...", flush=True)
|
||||
|
||||
totp = TOTP(new_secret_token)
|
||||
totp_input = safe_get_element(driver, By.ID, "totp_token")
|
||||
totp_input.send_keys(totp.now())
|
||||
|
||||
password_input = safe_get_element(driver, By.ID, "totp_password")
|
||||
|
||||
if password_input.get_attribute("value") != "":
|
||||
print("The new password check is not empty, exiting ...", flush=True)
|
||||
exit(1)
|
||||
|
||||
password_input.send_keys("P@ssw0rd")
|
||||
|
||||
access_page(
|
||||
driver,
|
||||
driver_wait,
|
||||
"//button[@id='profile-button' and @class='valid-btn']",
|
||||
"profile",
|
||||
)
|
||||
|
||||
assert_button_click(driver, "//button[@data-tab-handler='totp']")
|
||||
|
||||
try:
|
||||
totp_state = safe_get_element(driver, By.XPATH, "/html/body/main/div/div/form[2]/h5")
|
||||
|
||||
if totp_state.text != "TOTP IS CURRENTLY ON":
|
||||
print("TOTP is not activated, exiting ...", flush=True)
|
||||
exit(1)
|
||||
except TimeoutException:
|
||||
print("TOTP has not been activated, exiting ...", flush=True)
|
||||
exit(1)
|
||||
|
||||
print("2FA has been activated, trying to log out ...", flush=True)
|
||||
|
||||
assert_button_click(driver, "//a[@href='logout']")
|
||||
|
||||
|
|
@ -1416,7 +1609,100 @@ location /hello {
|
|||
print("Login page didn't load in time, exiting ...", flush=True)
|
||||
exit(1)
|
||||
|
||||
print("Successfully logged out, tests are done", flush=True)
|
||||
print("Successfully logged out, trying to log in with 2FA ...", flush=True)
|
||||
|
||||
username_input = safe_get_element(driver, By.ID, "username")
|
||||
password_input = safe_get_element(driver, By.ID, "password")
|
||||
username_input.send_keys("admin2")
|
||||
password_input.send_keys("P@ssw0rd")
|
||||
|
||||
assert_button_click(driver, "//button[@value='login']")
|
||||
|
||||
try:
|
||||
totp_input = safe_get_element(driver, By.ID, "totp_token")
|
||||
except TimeoutException:
|
||||
print("Didn't get redirected to 2FA page, exiting ...", flush=True)
|
||||
exit(1)
|
||||
|
||||
totp_input.send_keys("0000000")
|
||||
assert_button_click(driver, "//button[@value='login']")
|
||||
|
||||
sleep(5)
|
||||
|
||||
if not driver.current_url.endswith("/totp"):
|
||||
print("Didn't get redirected back to 2FA page, exiting ...", flush=True)
|
||||
exit(1)
|
||||
|
||||
totp_input = safe_get_element(driver, By.ID, "totp_token")
|
||||
totp_input.send_keys(totp.now())
|
||||
|
||||
access_page(
|
||||
driver,
|
||||
driver_wait,
|
||||
"//button[@value='login']",
|
||||
"home",
|
||||
)
|
||||
|
||||
print("Successfully logged in with 2FA, trying to deactivate 2FA ...", flush=True)
|
||||
|
||||
access_page(driver, driver_wait, "/html/body/aside[1]/div[1]/div[2]/ul/li[10]/a", "profile")
|
||||
|
||||
assert_button_click(driver, "//button[@data-tab-handler='totp']")
|
||||
|
||||
totp_input = safe_get_element(driver, By.ID, "totp_token")
|
||||
totp_input.send_keys(totp.now())
|
||||
|
||||
password_input = safe_get_element(driver, By.ID, "totp_password")
|
||||
password_input.send_keys("P@ssw0rd")
|
||||
|
||||
access_page(
|
||||
driver,
|
||||
driver_wait,
|
||||
"//button[@id='profile-button' and @class='delete-btn']",
|
||||
"profile",
|
||||
)
|
||||
|
||||
assert_button_click(driver, "//button[@data-tab-handler='totp']")
|
||||
|
||||
try:
|
||||
totp_state = safe_get_element(driver, By.XPATH, "/html/body/main/div/div/form[2]/h5")
|
||||
|
||||
if totp_state.text != "TOTP IS CURRENTLY OFF":
|
||||
print("TOTP is not deactivated, exiting ...", flush=True)
|
||||
exit(1)
|
||||
except TimeoutException:
|
||||
print("TOTP has not been deactivated, exiting ...", flush=True)
|
||||
exit(1)
|
||||
|
||||
print("2FA has been deactivated, trying to log out ...", flush=True)
|
||||
|
||||
assert_button_click(driver, "//a[@href='logout']")
|
||||
|
||||
try:
|
||||
title = driver_wait.until(EC.presence_of_element_located((By.XPATH, "/html/body/main/div[1]/div/h1")))
|
||||
|
||||
if title.text != "Log in":
|
||||
print("Didn't get redirected to login page, exiting ...", flush=True)
|
||||
exit(1)
|
||||
except TimeoutException:
|
||||
print("Login page didn't load in time, exiting ...", flush=True)
|
||||
exit(1)
|
||||
|
||||
print("Successfully logged out, trying to log in without 2FA ...", flush=True)
|
||||
|
||||
username_input = safe_get_element(driver, By.ID, "username")
|
||||
password_input = safe_get_element(driver, By.ID, "password")
|
||||
username_input.send_keys("admin2")
|
||||
password_input.send_keys("P@ssw0rd")
|
||||
|
||||
access_page(
|
||||
driver,
|
||||
driver_wait,
|
||||
"//button[@value='login']",
|
||||
"home",
|
||||
)
|
||||
|
||||
print("Successfully logged in without 2FA, tests are done, exiting ...", flush=True)
|
||||
except SystemExit:
|
||||
exit(1)
|
||||
except:
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
pyotp==2.9.0
|
||||
requests==2.31.0
|
||||
selenium==4.16.0
|
||||
|
|
|
|||
|
|
@ -128,6 +128,10 @@ outcome==1.3.0.post0 \
|
|||
--hash=sha256:9dcf02e65f2971b80047b377468e72a268e15c0af3cf1238e6ff14f7f91143b8 \
|
||||
--hash=sha256:e771c5ce06d1415e356078d3bdd68523f284b4ce5419828922b6871e65eda82b
|
||||
# via trio
|
||||
pyotp==2.9.0 \
|
||||
--hash=sha256:346b6642e0dbdde3b4ff5a930b664ca82abfa116356ed48cc42c7d6590d36f63 \
|
||||
--hash=sha256:81c2e5865b8ac55e825b0358e496e1d9387c811e85bb40e71a3b29b288963612
|
||||
# via -r requirements.in
|
||||
pysocks==1.7.1 \
|
||||
--hash=sha256:08e69f092cc6dbe92a0fdd16eeb9b9ffbc13cadfe5ca4c7bd92ffb078b293299 \
|
||||
--hash=sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5 \
|
||||
|
|
|
|||
Loading…
Reference in a new issue