Skip to content

Commit

Permalink
Merge pull request WLAN-Pi#6 from bentumbler/master
Browse files Browse the repository at this point in the history
Network API for scanning, setting and querying WPASupplicant to allow setup of wireless networks
  • Loading branch information
joshschmelzle authored Sep 11, 2024
2 parents 59a0e12 + c1e74c5 commit 05f800d
Show file tree
Hide file tree
Showing 19 changed files with 993 additions and 9 deletions.
4 changes: 3 additions & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
"wlanpi_core.asgi:app",
"--reload",
"--host",
"0.0.0.0"
"0.0.0.0",
"--port",
"31415"
],
"jinja": true,
"sudo": true
Expand Down
6 changes: 6 additions & 0 deletions debian/changelog
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
wlanpi-core (1.0.1) UNRELEASED; urgency=medium

* Add Network APIs for managing wlan0 via DBUS

-- Ben Toner <[email protected]> Wed, 11 Sep 2024 10:32:40 -0500

wlanpi-core (1.0.0-7) unstable; urgency=medium

* Add "wlanpi-grafana-wispy-*" and "wlanpi-grafana-wipry-*" to allowlist.
Expand Down
5 changes: 4 additions & 1 deletion debian/control
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ Build-Depends: debhelper (>= 11),
dbus,
libdbus-1-dev,
libdbus-glib-1-dev,
libglib2.0-dev
libglib2.0-dev,
libcairo2-dev,
libgirepository1.0-dev,
libffi-dev
Standards-Version: 4.6.0
X-Python3-Version: >= 3.9
Homepage: https://github.com/WLAN-Pi/wlanpi-core
Expand Down
4 changes: 4 additions & 0 deletions debian/rules
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ SDIST_DIR=debian/$(PACKAGE)-$(VERSION)

.PHONY: override_dh_virtualenv override_dh_installexamples

# ensure that the systemd services are handled by systemd.
override_dh_installsystemd:
dh_installsystemd --name=wpa_supplicant@wlan0 [email protected]

# we don't really want to strip the symbols from our object files.
override_dh_strip:

Expand Down
3 changes: 2 additions & 1 deletion debian/wlanpi-core.install
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/install/etc/wlanpi-core/nginx/nginx-sample.conf /etc/wlanpi-core/nginx
/install/etc/wlanpi-core/nginx/wlanpi_core.conf /etc/wlanpi-core/nginx/sites-enabled
/install/etc/wlanpi-core/nginx/link.sh /etc/wlanpi-core/scripts
/install/etc/wlanpi-core/nginx/unlink.sh /etc/wlanpi-core/scripts
/install/etc/wlanpi-core/nginx/unlink.sh /etc/wlanpi-core/scripts
/install/etc/wpa_supplicant/wpa_supplicant-wlan0.conf /etc/wpa_supplicant
2 changes: 1 addition & 1 deletion debian/wlanpi-core.substvars
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
shlibs:Depends=libc6 (>= 2.17), libdbus-1-3 (>= 1.9.14), libgcc-s1 (>= 4.2), libglib2.0-0 (>= 2.16.0)
shlibs:Depends=libc6 (>= 2.17), libcairo-gobject2 (>= 1.12.16), libcairo2 (>= 1.15.12), libdbus-1-3 (>= 1.9.14), libffi7 (>= 3.3~20180313), libgcc-s1 (>= 4.2), libgirepository-1.0-1 (>= 1.62.0-4~), libglib2.0-0 (>= 2.53.1)
misc:Depends=
misc:Pre-Depends=
20 changes: 20 additions & 0 deletions debian/[email protected]
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#DBUS Managed WPA_Supplicant Service on WLAN0

[Unit]
Description=WPA supplicant daemon (interface-specific version)
Requires=sys-subsystem-net-devices-%i.device
After=sys-subsystem-net-devices-%i.device
Before=network.target
Wants=network.target

# NetworkManager users will probably want the dbus version instead.

[Service]
Type=simple
#ExecStart=/sbin/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-%I.conf -i%I
ExecStart=/sbin/wpa_supplicant -u -s -O /run/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-%I.conf -i%I
ExecReload=/bin/kill -HUP \$MAINPID

[Install]
WantedBy=multi-user.target
Alias=dbus-fi.w1.wpa_supplicant1.service
64 changes: 64 additions & 0 deletions install/etc/wpa_supplicant/wpa_supplicant-wlan0.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
ctrl_interface=DIR=/run/wpa_supplicant
ap_scan=1
p2p_disabled=1

#######################################################################################
# NOTE: to use the templates below, remove the hash symbols at the start of each line
#######################################################################################

# WPA2 PSK Network sample (highest priority - joined first)
#network={
# ssid="enter SSID Name"
# psk="enter key"
# priority=10
#}

# WPA2 PSK Network sample (next priority - joined if first priority not available) - don't unhash this line

#network={
# ssid="enter SSID Name"
# psk="enter key"
# priority=3
#}

# WPA2 PEAP example (next priority - joined if second priority not available) - don't unhash this line

#network={
# ssid="enter SSID Name"
# key_mgmt=WPA-EAP
# eap=PEAP
# anonymous_identity="anonymous"
# identity="enter your username"
# password="enter your password"
# phase2="autheap=MSCHAPV2"
# priority=2
#}

# Open network example (lowest priority, only joined other 3 networks not available) - don't unhash this line

#network={
# ssid="enter SSID Name"
# key_mgmt=NONE
# priority=1
#}

# SAE mechanism for PWE derivation
# 0 = hunting-and-pecking (HNP) loop only (default without password identifier)
# 1 = hash-to-element (H2E) only (default with password identifier)
# 2 = both hunting-and-pecking loop and hash-to-element enabled
# Note: The default value is likely to change from 0 to 2 once the new
# hash-to-element mechanism has received more interoperability testing.
# When using SAE password identifier, the hash-to-element mechanism is used
# regardless of the sae_pwe parameter value.
#
#sae_pwe=0 <--- default value, change to 1 or 2 if AP forces H2E.

# WPA3 PSK network sample for 6 GHz (note SAE and PMF is required) - don't unhash this line

#network={
# ssid="6 GHz SSID"
# psk="password"
# priority=10
# key_mgmt=SAE
# ieee80211w=2
#}
3 changes: 2 additions & 1 deletion requirements.in
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ requests

# endpoint requires
psutil
dbus-python
dbus-python
PyGObject
4 changes: 4 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ packaging==23.1
# via gunicorn
psutil==5.9.5
# via -r requirements.in
pycairo==1.25.1
# via pygobject
pydantic==2.3.0
# via
# fastapi
Expand All @@ -60,6 +62,8 @@ pydantic-core==2.6.3
# via pydantic
pydantic-settings==2.0.3
# via -r requirements.in
pygobject==3.46.0
# via -r requirements.in
python-dotenv==1.0.0
# via
# -r requirements.in
Expand Down
21 changes: 20 additions & 1 deletion wlanpi_core/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,23 @@
from .__version__ import __version__


def port(port) -> int:
"""Check if the provided port is valid"""
try:
# make sure port is an int
port = int(port)
except ValueError:
raise ValueError("%s is not a number")

port_ranges = [(1024, 65353)]

for _range in port_ranges:
if _range[0] <= port <= _range[1]:
return port

raise ValueError("%s not a valid. Pick a port between %s.", port, port_ranges)


def setup_parser() -> argparse.ArgumentParser:
"""Set default values and handle arg parser"""
parser = argparse.ArgumentParser(
Expand All @@ -35,6 +52,8 @@ def setup_parser() -> argparse.ArgumentParser:
parser.add_argument(
"--reload", dest="livereload", action="store_true", default=False
)
parser.add_argument("--port", "-p", dest="port", type=port, default=8000)

parser.add_argument(
"--version", "-V", "-v", action="version", version=f"{__version__}"
)
Expand Down Expand Up @@ -68,7 +87,7 @@ def main() -> None:
if lets_go:
uvicorn.run(
"wlanpi_core.asgi:app",
port=8000,
port=args.port,
host="0.0.0.0",
reload=args.livereload,
log_level="debug",
Expand Down
2 changes: 1 addition & 1 deletion wlanpi_core/__version__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
__url__ = "https://github.com/wlan-pi/wlanpi-core"
__author__ = "Josh Schmelzle"
__author_email__ = "[email protected]"
__version__ = "1.0.0"
__version__ = "1.0.1"
__status__ = "alpha"
__license__ = "BSD-3-Clause"
__license_url__ = "https://opensource.org/licenses/BSD-3-Clause"
87 changes: 86 additions & 1 deletion wlanpi_core/api/api_v1/endpoints/network_api.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,92 @@
import logging

from fastapi import APIRouter
from fastapi import APIRouter, Response

from wlanpi_core.models.validation_error import ValidationError
from wlanpi_core.schemas import network
from wlanpi_core.services import network_service

router = APIRouter()

API_DEFAULT_TIMEOUT = 20

log = logging.getLogger("uvicorn")


@router.get("/wlan/getInterfaces", response_model=network.Interfaces)
async def get_a_systemd_network_interfaces(timeout: int = API_DEFAULT_TIMEOUT):
"""
Queries systemd via dbus to get the details of the currently connected network.
"""

try:
return await network_service.get_systemd_network_interfaces(timeout)
except ValidationError as ve:
return Response(content=ve.error_msg, status_code=ve.status_code)
except Exception as ex:
log.error(ex)
return Response(content="Internal Server Error", status_code=500)


@router.get(
"/wlan/scan", response_model=network.ScanResults, response_model_exclude_none=True
)
async def get_a_systemd_network_scan(
type: str, interface: str, timeout: int = API_DEFAULT_TIMEOUT
):
"""
Queries systemd via dbus to get a scan of the available networks.
"""

try:
# return await network_service.get_systemd_network_scan(type)
return await network_service.get_async_systemd_network_scan(
type, interface, timeout
)
except ValidationError as ve:
return Response(content=ve.error_msg, status_code=ve.status_code)
except Exception as ex:
log.error(ex)
return Response(content="Internal Server Error", status_code=500)


@router.post("/wlan/set", response_model=network.NetworkSetupStatus)
async def set_a_systemd_network(
setup: network.WlanInterfaceSetup, timeout: int = API_DEFAULT_TIMEOUT
):
"""
Queries systemd via dbus to set a single network.
"""

try:
return await network_service.set_systemd_network_addNetwork(
setup.interface, setup.netConfig, setup.removeAllFirst, timeout
)
except ValidationError as ve:
return Response(content=ve.error_msg, status_code=ve.status_code)
except Exception as ex:
log.error(ex)
return Response(content="Internal Server Error", status_code=500)


@router.get(
"/wlan/getConnected",
response_model=network.ConnectedNetwork,
response_model_exclude_none=True,
)
async def get_a_systemd_currentNetwork_details(
interface: str, timeout: int = API_DEFAULT_TIMEOUT
):
"""
Queries systemd via dbus to get the details of the currently connected network.
"""

try:
return await network_service.get_systemd_network_currentNetwork_details(
interface, timeout
)
except ValidationError as ve:
return Response(content=ve.error_msg, status_code=ve.status_code)
except Exception as ex:
log.error(ex)
return Response(content="Internal Server Error", status_code=500)
3 changes: 3 additions & 0 deletions wlanpi_core/core/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from dbus.mainloop.glib import DBusGMainLoop

DBusGMainLoop(set_as_default=True)
14 changes: 13 additions & 1 deletion wlanpi_core/schemas/network/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,13 @@
from .network import PublicIP
from .network import (
APIConfig,
ConnectedNetwork,
Interface,
Interfaces,
NetworkEvent,
NetworkSetupLog,
NetworkSetupStatus,
PublicIP,
ScanResults,
WlanConfig,
WlanInterfaceSetup,
)
Loading

0 comments on commit 05f800d

Please sign in to comment.