Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WebUI Enhancements and network setup page #42

Open
wants to merge 31 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
ffd0ffc
initial api integration
Nov 2, 2023
acfe8ca
Update network page, now scan results don't stop the page from loading
Dec 19, 2023
525d30d
Merge pull request #1 from Orbitix/master
Orbitix Dec 19, 2023
8abc1d1
fix missing code
Dec 28, 2023
1c0ceed
Merge branch 'dev' of https://github.com/Orbitix/wlanpi-webui into dev
Dec 28, 2023
0618efa
fix merge again
Orbitix Dec 28, 2023
c347c5d
add form to connect to network and make it look nice
Orbitix Dec 29, 2023
4276ed1
add status pill on navbar, and add more options to the network form
Orbitix Jan 3, 2024
ddacf66
add network_status.html file (whoops)
Orbitix Jan 20, 2024
280936f
add missing extends template for htmx
joshschmelzle Jan 26, 2024
5237b09
add missing netscan_iframe.html
Orbitix Jan 26, 2024
cda247d
add network_setup
Orbitix Jan 27, 2024
0ee9cf7
fix merge
Orbitix Jan 28, 2024
67f1fef
remove mode adds
joshschmelzle Jan 31, 2024
a9b893f
remove redundant class on div
joshschmelzle Jan 31, 2024
f174363
add missing new wlan setup to offcanvas nav
joshschmelzle Jan 31, 2024
e7fa2ea
refactor network code into individual files
joshschmelzle Jan 31, 2024
97afb1a
tox -e format on app.py
joshschmelzle Jan 31, 2024
5c61ab9
no longer needed after network refactor
joshschmelzle Jan 31, 2024
915b783
remove broken SAE-PSK field
joshschmelzle Jan 31, 2024
8bbe720
Renames and migrate from wpa/wpa2 fields to key_mgmt
joshschmelzle Jan 31, 2024
86365f8
fix file extention for installing reqs
Orbitix Aug 31, 2024
8e60a0d
form changes
Orbitix Sep 1, 2024
4529e26
start moving to js for network setup
Orbitix Sep 1, 2024
53c80e7
not work
Orbitix Sep 1, 2024
7c7b482
oops
Orbitix Sep 1, 2024
28859d1
continue network setup
Orbitix Sep 3, 2024
2b948b9
re-enable interface scanning and netscan iframe
Orbitix Sep 14, 2024
a90f9c7
add supplicant checking with start stop button
Orbitix Sep 15, 2024
0473143
add reloading of page to set interface properly
Orbitix Sep 15, 2024
650651c
fix 500 error when var is not assigned, set to a default error message
Orbitix Oct 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ Activate virtualenv
Install dependencies

```bash
pip install -r requirements
pip install -r requirements.txt
```

Starting the development server
Expand Down
4 changes: 4 additions & 0 deletions wlanpi_webui/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"""

import logging
import subprocess

from flask import Flask, abort, send_from_directory
from flask_minify import Minify
Expand Down Expand Up @@ -82,6 +83,9 @@ def create_app(config_class=Config):
def inject_vars():
return {
"title": f"WLAN Pi: {get_hostname()}",
"mode": subprocess.check_output(
"cat /etc/wlanpi-state", shell=True
).decode(),
}

@app.route("/static/img/<path:filename>")
Expand Down
3 changes: 2 additions & 1 deletion wlanpi_webui/network/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@

bp = Blueprint("network", __name__)

from wlanpi_webui.network import network # noqa: F401
from wlanpi_webui.network import network_info # noqa: F401
from wlanpi_webui.network import network_setup # noqa: F401
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ def readlines(_file):
cdp = readlines(cdpneigh)
lldp = readlines(lldpneigh)

# netScan = get_wifi_scan('wlan0')
# netScan_html = json2html.convert(json=netScan)

script_results = dumpQueue(FPMS_QUEUE)
for result in script_results:
if "reachability" in str(result):
Expand All @@ -88,6 +91,7 @@ def readlines(_file):
"ipconfig": ipconfig,
"lldp": lldp,
"cdp": cdp,
# "scan": netScan_html,
}

if is_htmx(request):
Expand Down
298 changes: 298 additions & 0 deletions wlanpi_webui/network/network_setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,298 @@
import json
import time
import requests
from flask import current_app, redirect, render_template, request

from wlanpi_webui.network import bp
from wlanpi_webui.utils import (is_htmx, start_stop_service,
system_service_running_state,
systemd_service_message, wlanpi_core_warning)


@bp.route("/network/setup", methods=("GET", "POST"))
def netSetup():
messages = []
if request.method == "POST":
form_data = request.form

try:
body = {
"interface": form_data.get("interface"),
"netConfig": {
"ssid": form_data.get("ssid"),
"psk": form_data.get("psk"),
"proto": form_data.get("proto"),
"key_mgmt": form_data.get("key_mgmt"),
"ieee80211w": int(form_data.get("ieee80211w")),
},
"removeAllFirst": (
True if form_data.get("removeAllFirst") == "true" else False
),
}
except Exception as e:
return f"Fail: {e}"

set_result = set_network(body)

try:
set_json = json.loads(set_result)
messages.append(set_json)
except:
# this should not happen - only will if the set_network api returns a non-json response, like the nginx 502 Bad Gateway page
messages.append({"status": "Internal Server Error"})

interfaces_result = get_interfaces()

try:
interfaces_json = json.loads(interfaces_result)
except Exception as e:
return f"Error {e}"



try:
if interfaces_json:
interfaces = []
for interface in interfaces_json["interfaces"]:
interfaces.append(interface["interface"])

if is_htmx(request):
return render_template(
"/partials/network_setup.html", interfaces=interfaces, messages=messages
)
else:
return render_template(
"/extends/network_setup.html", interfaces=interfaces, messages=messages
)
except Exception as e:
return f"Error {e}"


@bp.route("/wpa_supplicant/setup")
def wpa_supplicant_setup():
if is_htmx(request):
supplicant_message = systemd_service_message("[email protected]")
supplicant_status = system_service_running_state("[email protected]")
supplicant_task_url = "/wpa_supplicant/startstop"
if supplicant_status:
# active
supplicant_task_anchor_text = "STOP"
else:
# not active
supplicant_task_anchor_text = "START"
args = {
"supplicant_message": supplicant_message,
"supplicant_task_url": supplicant_task_url,
"supplicant_task_anchor_text": supplicant_task_anchor_text,
}
if supplicant_status:
# active
html = """
<button class="uk-button uk-button-default" uk-tooltip="[email protected] is in the correct mode. Stop to restore default supplicant behaviour"
hx-get="{supplicant_task_url}"
hx-trigger="click delay:0.2s"
hx-swap="outerHTML"
hx-indicator=".progress">{supplicant_task_anchor_text}</button>
""".format(
**args
)
else:
# not active
html = """
<button class="uk-button uk-button-default" uk-tooltip="[email protected] must be running before attempting to connect to a network."
hx-get="{supplicant_task_url}"
hx-trigger="click delay:0.2s"
hx-swap="outerHTML"
hx-indicator=".progress">{supplicant_task_anchor_text}</button>
""".format(
**args
)
return html


@bp.route("/wpa_supplicant/startstop")
def wpa_supplicant_startstop():
if is_htmx(request):
supplicant_message = systemd_service_message("[email protected]")
supplicant_status = system_service_running_state("[email protected]")
supplicant_task_url = "/wpa_supplicant/startstop"
if supplicant_status:
# active
start_stop_service("stop", "[email protected]")
time.sleep(1)
start_stop_service("start", "wpa_supplicant.service")
supplicant_task_anchor_text = "START"
supplicant_tooltip = "[email protected] must be running before attempting to connect to a network."
else:
# not active
start_stop_service("stop", "wpa_supplicant.service")
time.sleep(1)
start_stop_service("start", "[email protected]")
supplicant_task_anchor_text = "STOP"
supplicant_tooltip = "[email protected] is in the correct mode. Stop to restore default supplicant behaviour"
args = {
"supplicant_message": supplicant_message,
"supplicant_task_url": supplicant_task_url,
"supplicant_task_anchor_text": supplicant_task_anchor_text,
"supplicant_tooltip": supplicant_tooltip,
}
if supplicant_status:
# active
html = """
<button class="uk-button uk-button-default" uk-tooltip="{supplicant_tooltip}"
hx-get="{supplicant_task_url}"
hx-trigger="click delay:0.2s"
hx-swap="outerHTML"
hx-indicator=".progress"
hx-on::after-settle=window.location.reload()>{supplicant_task_anchor_text}</button>
""".format(
**args
)
else:
# not active
html = """
<button class="uk-button uk-button-default" uk-tooltip="{supplicant_tooltip}"
hx-get="{supplicant_task_url}"
hx-trigger="click delay:0.2s"
hx-swap="outerHTML"
hx-indicator=".progress"
hx-on::after-settle=window.location.reload()>{supplicant_task_anchor_text}</button>
""".format(
**args
)
return html




@bp.route("/network/getscan")
def getscan():
netScan = get_wifi_scan("wlan0")

try:
netScan = json.loads(netScan)
print(netScan)
except:
return "Error"

grouped_scan = []
unique_ssids = []

for network in netScan["nets"]:
if ("\0" in network["ssid"]) or (network["ssid"] in [' ', ""]):
network["ssid"] = "<hidden>"
if not network["ssid"] in unique_ssids:
unique_ssids.append(network["ssid"])

idx = 0
for ssid in unique_ssids:
grouped_scan.append({"ssid": ssid, "scan": []})
for network in netScan["nets"]:
if network["ssid"] == ssid:
scan = {
"bssid": network["bssid"],
"key_mgmt": network["key_mgmt"],
"signal": network["signal"],
"freq": network["freq"],
}
grouped_scan[idx]["scan"].append(scan)
idx += 1

return render_template(
"netscan_iframe.html", netScan=netScan, groupedScan=grouped_scan
)


def get_wifi_scan(interface):
"""
Makes a request to do a wifi scan and returns the scan using wlanpi-core.
"""
headers = {
"accept": "application/json",
"content-type": "application/x-www-form-urlencoded",
}
params = {
"type": "active",
"interface": f"{interface}",
"timeout": 20
}

current_app.logger.info("calling network scan on interface %s", interface)
try:
start_url = "http://127.0.0.1:31415/api/v1/network/wlan/scan"
response = requests.get(
start_url,
params=params,
headers=headers,
)
if response.status_code != 200:
current_app.logger.info(
"systemd_service_message: %s",
systemd_service_message("wlanpi-core"),
)
current_app.logger.info(
"error: %s",
response.content,
)
current_app.logger.info("%s generated %s response", start_url, response)
return response.content
current_app.logger.info("%s generated %s response", start_url, response)
return json.dumps(response.json())
except requests.exceptions.RequestException:
current_app.logger.exception("requests error")
return redirect(request.referrer)


def set_network(body):
"""
Takes the body from a form and sets the network using wlanpi-core.
"""
headers = {
"accept": "application/json",
"content-type": "application/json",
}

current_app.logger.info("setting network with params: %s", body)
try:
start_url = "http://127.0.0.1:31415/api/v1/network/wlan/set"
response = requests.post(start_url, headers=headers, json=body)
if response.status_code != 200:
current_app.logger.info(
"systemd_service_message: %s",
systemd_service_message("wlanpi-core"),
)
current_app.logger.info("%s generated %s response", start_url, response.content)
current_app.logger.info("%s generated %s response", start_url, response.content)
return response.content
except requests.exceptions.RequestException:
current_app.logger.exception("requests error")
return redirect(request.referrer)


def get_interfaces():
"""
Gets all the interfaces using wlanpi-core.
"""
headers = {
"accept": "application/json",
"content-type": "application/x-www-form-urlencoded",
}

current_app.logger.info("getting interfaces")
try:
start_url = "http://127.0.0.1:31415/api/v1/network/wlan/getInterfaces"
response = requests.get(
start_url,
headers=headers,
)
if response.status_code != 200:
current_app.logger.info(
"systemd_service_message: %s",
systemd_service_message("wlanpi-core"),
)
current_app.logger.info("%s generated %s response", start_url, response)
current_app.logger.info("%s generated %s response", start_url, response)
return json.dumps(response.json())
except requests.exceptions.RequestException:
current_app.logger.exception("requests error")
return redirect(request.referrer)
22 changes: 17 additions & 5 deletions wlanpi_webui/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,19 @@
</ul>
</div>
</li>
<li><a hx-get="/network" hx-target="#content" hx-trigger="click" hx-indicator=".progress" hx-push-url="true"
hx-swap="innerHTML" style="color: white;">NETWORK</a></li>
<li>
<!-- <a hx-get="/network" hx-target="#content" hx-trigger="click" hx-indicator=".progress" hx-push-url="true"
hx-swap="innerHTML" style="color: white;">NETWORK</a> -->
<a href="#" style="color: white;">NETWORK <span uk-navbar-parent-icon></span></a>
<div class="uk-navbar-dropdown">
<ul class="uk-nav uk-navbar-dropdown-nav uk-navbar-dropdown-width-1" >
<li><a hx-get="/network" hx-target="#content" hx-swap="innerHTML" hx-push-url="true"
hx-indicator=".progress">INFO</a></li>
<li><a hx-get="/network/setup" hx-target="#content" hx-swap="innerHTML"
hx-push-url="true" hx-indicator=".progress">WLAN SETUP</a></li>
</ul>
</div>
</li>
<li>
<a href="#" style="color: white;">KISMET <span uk-navbar-parent-icon></span></a>
<div class="uk-navbar-dropdown"
Expand Down Expand Up @@ -118,8 +129,7 @@
</li>
<li class="uk-visible@m">
<a href="#" uk-icon="icon: settings; ratio: 1.5;"></a>
<div class="uk-navbar-dropdown"
class="uk-navbar-dropdown">
<div class="uk-navbar-dropdown">
<ul class="uk-nav uk-navbar-dropdown-nav">
<li class="uk-nav-header"><a hx-get="/about" hx-target="#content" hx-swap="innerHTML"
hx-push-url="true" hx-indicator=".progress">ABOUT</a></li>
Expand Down Expand Up @@ -195,7 +205,9 @@
</ul>
<li class="uk-divider-icon"></li>
<li><a hx-get="/network" hx-target="#content" hx-trigger="click" hx-indicator=".progress" hx-push-url="true"
hx-swap="innerHTML" style="color: white;">NETWORK</a></li>
hx-swap="innerHTML" style="color: white;">NETWORK INFO</a></li>
<li><a hx-get="/network/setup" hx-target="#content" hx-trigger="click" hx-indicator=".progress" hx-push-url="true"
hx-swap="innerHTML" style="color: white;">NETWORK WLAN SETUP</a></li>
<li class="uk-divider-icon"></li>
<ul class="uk-nav uk-navbar-dropdown-nav"
hx-get="/kismet/side_menu"
Expand Down
4 changes: 4 additions & 0 deletions wlanpi_webui/templates/extends/network_setup.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{% extends "base.html" %}
{% block content %}
{% include "partials/network_setup.html" %}
{% endblock %}
Loading