This commit is contained in:
Silo
2026-02-20 16:52:22 +00:00
parent 578d35b965
commit c3ad189448
15 changed files with 957 additions and 1518 deletions

2
.vscode/launch.json vendored
View File

@@ -10,7 +10,7 @@
"request": "launch",
"module": "flask",
"env": {
"FLASK_APP": "tr.py",
"FLASK_APP": "wsgi.py",
"FLASK_ENV": "development",
"PYDEVD_LOAD_NATIVE_LIB": "0",
"PYDEVD_USE_CYTHON": "0"

View File

@@ -10,6 +10,7 @@ flask-login = "*"
flask-sqlalchemy = "*"
flask-migrate = "*"
gunicorn = "*"
markupsafe = "*"
[dev-packages]
pylint = "*"
@@ -20,7 +21,7 @@ pylint_flask = "*"
pylint_flask_sqlalchemy = "*"
[requires]
python_version = "3.7"
python_version = "3.9"
[pipenv]
allow_prereleases = true

1186
Pipfile.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -3,7 +3,6 @@ from config import Config
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_login import LoginManager
from app.network_utils import cleanup_network
app = Flask(__name__)
app.config.from_object(Config)
@@ -12,6 +11,4 @@ migrate = Migrate(app, db)
login = LoginManager(app)
login.login_view = "login"
cleanup_network()
from app import routes2, models
from app import routes, models

View File

@@ -28,12 +28,28 @@ ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
"""
import logging
import shlex
def get_logger():
"""Returns a logger"""
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
return logging.getLogger()
def run_subprocess(cmd, check=True, delay=0):
cmd_split = cmd.split(" ")
output = subprocess.run(cmd_split, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=check).stdout.decode("utf-8")
"""Runs a subprocess command"""
try:
cmd_split = shlex.split(cmd)
output = subprocess.run(
cmd_split, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=check, text=True, encoding="utf-8"
)
if delay > 0:
time.sleep(delay)
return output
return output.stdout
except subprocess.CalledProcessError as e:
get_logger().error("Subprocess command failed: %s", e)
return None
def run_subprocess_interface(cmd, check=True):
@@ -112,38 +128,47 @@ def parse_iwlist(iwlist_output, current_sid):
def scan_networks():
"""Scans for Networks"""
output = run_subprocess("sudo iwgetid", check=False)
output = run_subprocess("sudo iwgetid")
if output is None:
get_logger().error("Failed to get current network SSID.")
current = ""
else:
current = output.partition("ESSID:")[2].strip().strip('"')
worked = False
while not worked:
try:
output = run_subprocess("sudo iwlist {} scan".format(ClientInterface))
worked = True
except:
try:
output = run_subprocess("sudo ifup {}".format(ClientInterface))
output = None
while output is None:
output = run_subprocess(f"sudo iwlist {ClientInterface} scan")
if output is None:
get_logger().info("Failed to scan networks, trying to bring interface up.")
ifup_output = run_subprocess(f"sudo ifup {ClientInterface}")
if ifup_output is None:
get_logger().error("Failed to bring interface up.")
# Avoid a tight loop if `ifup` fails
time.sleep(5)
else:
time.sleep(1)
except:
pass
scan = parse_iwlist(output, current)
scan = parse_iwlist(output, current)
return scan
def connect_network(ssid, security, password):
"""Connects to a network"""
with open("/etc/network/interfaces", "r") as source:
lines = source.readlines()
with open("/etc/network/interfaces", "w") as source:
for line in lines:
source.write(
re.sub(r"^iface {} inet manual".format(ClientInterface), "iface {} inet dhcp".format(ClientInterface), line)
re.sub(r"^iface {} inet manual".format(ClientInterface), f"iface {ClientInterface} inet dhcp", line)
)
run_subprocess_interface("sudo /usr/sbin/ifdown {}")
if run_subprocess_interface("sudo /usr/sbin/ifdown {}") is None:
get_logger().error("Failed to bring interface down.")
return False
run_subprocess("sudo /usr/bin/systemctl stop wpa_supplicant")
if run_subprocess("sudo /usr/bin/systemctl stop wpa_supplicant") is None:
get_logger().error("Failed to stop wpa_supplicant.")
return False
with open("/etc/wpa_supplicant/wpa_supplicant.conf", "wt") as f:
if security == "WPA2":
@@ -151,96 +176,124 @@ def connect_network(ssid, security, password):
else:
f.write(wpafile_nowpa.format(ssid))
try:
run_subprocess("sudo /usr/bin/systemctl start wpa_supplicant")
run_subprocess_interface("sudo /usr/sbin/ifup {}")
except:
if run_subprocess("sudo /usr/bin/systemctl start wpa_supplicant") is None:
get_logger().error("Failed to start wpa_supplicant.")
return False
if run_subprocess_interface("sudo /usr/sbin/ifup {}") is None:
get_logger().error("Failed to bring interface up.")
return False
return True
def disconnect_network():
run_subprocess_interface("sudo /usr/sbin/ifdown {}")
"""Disconnects from a network"""
if run_subprocess_interface("sudo /usr/sbin/ifdown {}") is None:
get_logger().error("Failed to bring interface down.")
return False
with open("/etc/wpa_supplicant/wpa_supplicant.conf", "wt") as f:
f.write(wpafile_none)
run_subprocess("sudo /usr/bin/systemctl stop wpa_supplicant")
if run_subprocess("sudo /usr/bin/systemctl stop wpa_supplicant") is None:
get_logger().error("Failed to stop wpa_supplicant.")
return False
with open("/etc/network/interfaces", "r") as sources:
lines = sources.readlines()
with open("/etc/network/interfaces", "w") as sources:
for line in lines:
sources.write(
re.sub(r"^iface {} inet dhcp".format(ClientInterface), "iface {} inet manual".format(ClientInterface), line)
re.sub(r"^iface {} inet dhcp".format(ClientInterface), f"iface {ClientInterface} inet manual", line)
)
try:
run_subprocess("sudo /usr/bin/systemctl start wpa_supplicant")
run_subprocess_interface("sudo /usr/sbin/ifup {}")
except:
if run_subprocess("sudo /usr/bin/systemctl start wpa_supplicant") is None:
get_logger().error("Failed to start wpa_supplicant.")
return False
if run_subprocess_interface("sudo /usr/sbin/ifup {}") is None:
get_logger().error("Failed to bring interface up.")
return False
return True
def cleanup_network():
run_subprocess_interface("sudo /usr/sbin/ifdown {}")
"""Cleans up the network"""
if run_subprocess_interface("sudo /usr/sbin/ifdown {}") is None:
get_logger().error("Failed to bring interface down.")
return False
with open("/etc/wpa_supplicant/wpa_supplicant.conf", "wt") as f:
f.write(wpafile_none)
run_subprocess("sudo /usr/bin/systemctl stop wpa_supplicant")
if run_subprocess("sudo /usr/bin/systemctl stop wpa_supplicant") is None:
get_logger().error("Failed to stop wpa_supplicant.")
return False
with open("/etc/network/interfaces", "r") as sources:
lines = sources.readlines()
with open("/etc/network/interfaces", "w") as sources:
for line in lines:
sources.write(
re.sub(r"^iface {} inet dhcp".format(ClientInterface), "iface {} inet manual".format(ClientInterface), line)
re.sub(r"^iface {} inet dhcp".format(ClientInterface), f"iface {ClientInterface} inet manual", line)
)
try:
run_subprocess("sudo /usr/bin/systemctl start wpa_supplicant")
run_subprocess_interface("sudo /usr/sbin/ifup {}")
except:
if run_subprocess("sudo /usr/bin/systemctl start wpa_supplicant") is None:
get_logger().error("Failed to start wpa_supplicant.")
return False
if run_subprocess_interface("sudo /usr/sbin/ifup {}") is None:
get_logger().error("Failed to bring interface up.")
return False
return True
def vpn_connected():
if run_subprocess("nordvpn status").find("Disconnected") != -1:
"""Checks if the VPN is connected"""
output = run_subprocess("nordvpn status")
if output is None:
return False
return True
return "Disconnected" not in output
def vpn_connect():
if run_subprocess("nordvpn c").find("connected to") != -1:
return True
"""Connects to the VPN"""
output = run_subprocess("nordvpn c")
if output is None:
return False
return "connected to" in output
def vpn_disconnect():
if run_subprocess("nordvpn d").find("You are disconnected from NordVPN") != -1:
return True
"""Disconnects from the VPN"""
output = run_subprocess("nordvpn d")
if output is None:
return False
return "You are disconnected from NordVPN" in output
def killswitch_status():
if run_subprocess("nordvpn settings").find("Kill Switch: disabled") != -1:
return False
return True
"""Checks the status of the killswitch"""
output = run_subprocess("nordvpn settings")
if output is None:
return True # Assume enabled for safety
return "Kill Switch: disabled" not in output
def killswich_enable():
if run_subprocess("nordvpn set killswitch on", delay=2).find("Kill Switch is set to 'enabled' successfully") != -1:
return True
"""Enables the killswitch"""
output = run_subprocess("nordvpn set killswitch on", delay=2)
if output is None:
return False
return "Kill Switch is set to 'enabled' successfully" in output
def killswich_disaable():
if run_subprocess("nordvpn set killswitch off", delay=2).find("Kill Switch is set to 'disabled' successfully") != -1:
return True
"""Disables the killswitch"""
output = run_subprocess("nordvpn set killswitch off", delay=2)
if output is None:
return False
return "Kill Switch is set to 'disabled' successfully" in output

View File

@@ -1,322 +0,0 @@
import re
import subprocess
from config import RPI, ClientInterface, Debug
from flask import flash, redirect, render_template, url_for
from flask_login import current_user, login_required, login_user, logout_user
from app import app
from app.forms import LoginForm, WPAForm
from app.models import ConfigTable, Passwords, User
CMD_SCAN = "sudo nmcli -t -f SSID,SIGNAL,IN-USE,SECURITY -e yes -m tab device wifi list ifname wlan1 --rescan yes"
CMD_JOIN = "sudo nmcli device wifi connect *SSID* ifname wlan1"
CMD_JOINPW = "sudo nmcli device wifi connect *SSID* ifname wlan1 password *PASSWORD*"
CMD_DISCONNECT = "sudo nmcli device disconnect wlan1"
# Error: Connection activation failed: (7) Secrets were required, but not provided.
# Device 'wlxf81a6719febb' successfully activated with '11111-1111-11111-111111-11111111'
def parse_iwlist(iwlist_output, current):
data = []
cell = []
for line in iwlist_output.splitlines():
if line.find(" Cell ") != -1 and cell != []:
data.append(cell)
cell = []
elif line.find("Scan completed :") > 0:
pass
else:
cell.append(line)
try:
del data[0][0]
except:
pass
cells = []
for a in data:
cell = {}
for line in a:
line = line.strip()
if line.find("ESSID:") != -1:
if line.partition("ESSID:")[2].strip('"') != "":
cell["SSID"] = line.partition("ESSID:")[2].strip('"')
if cell["SSID"] == current:
cell["Connected"] = "Yes"
else:
cell["Connected"] = ""
if line.partition("Signal level=")[2].split("/")[0] != "" != -1:
cell["Signal"] = line.partition("Signal level=")[2].split("/")[0]
if line.find("Encryption key:") != -1:
if line.find(":on") != -1:
cell["WPA"] = "WPA2"
else:
cell["WPA"] = "None"
cells.append(cell)
return cells
def scan_networks():
scan = []
if not RPI:
output = subprocess.run(CMD_SCAN.split(" "), stdout=subprocess.PIPE).stdout.decode("utf-8")
for line in output.splitlines():
t = line.split(":")
if t[0] != "":
scan.append(line)
else:
output = subprocess.run(["sudo", "iwgetid"], stdout=subprocess.PIPE).stdout.decode("utf-8")
current = output.partition("ESSID:")[2].strip().strip('"')
output = subprocess.run(["sudo", "iwlist", ClientInterface, "scan"], stdout=subprocess.PIPE).stdout.decode("utf-8")
scan = parse_iwlist(output, current)
# a = 0
# scan = []
# for line in output.splitlines():
# if a == 0:
# connected = " "
# if line.partition("ESSID:")[2].strip('"') != "":
# a = 1
# ssid = line.partition("ESSID:")[2].strip('"')
# if ssid == current:
# connected = "*"
# if a == 1:
# if line.find("Encryption key:off") != -1:
# password = ""
# a = 2
# elif line.find("Encryption key:on") != -1:
# password = "WPA2"
# a = 2
# if a == 2:
# if line.partition("Signal level=")[2].split("/")[0] != "":
# signal = line.partition("Signal level=")[2].split("/")[0]
# a = 0
# scan.append(ssid + ":" + signal + ":" + connected + ":" + password)
return scan
@app.route("/")
@app.route("/index")
@login_required
def index():
results = []
scan = ["rpi:100: :WPA2", "Home:94:*:WPA2", "HOME2:48: :WPA2", "BT:23: :"]
if not Debug:
scan = scan_networks()
# for network in scan:
# item = [
# network.split(":", maxsplit=1)[0],
# network.split(":")[1],
# "Yes" if network.split(":")[2] == "*" else "",
# "None" if network.split(":")[3].strip() == "" else "WPA2",
# ]
# results.append(item)
item = []
for network in scan:
item = [network["SSID"], network["Signal"], network["Connected"], network["WPA"]]
results.append(item)
# table = Networks(results)
# table.border = True
t = {}
for a in results:
t["ssid"] = a[0]
return render_template("index.html", index_table=results)
@app.route("/login", methods=["GET", "POST"])
def login():
if current_user.is_authenticated:
return redirect(url_for("index"))
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(username=form.username.data).first()
if user is None or not user.check_password(form.password.data):
flash("Invalid username or password")
return redirect(url_for("login"))
login_user(user)
return redirect(url_for("index"))
return render_template("login.html", title="Sign In", form=form)
@app.route("/logout")
def logout():
logout_user()
return redirect(url_for("index"))
@app.route("/wpa/<ssid>", methods=["GET", "POST"])
@login_required
def wpa(ssid):
# wlan0: flags=4098<BROADCAST,MULTICAST> mtu 1500
# wlan1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
if not RPI:
form = WPAForm()
if form.validate_on_submit():
cmd = CMD_JOINPW.replace("*SSID*", ssid)
cmd = cmd.replace("*PASSWORD*", form.password.data)
output = subprocess.run(cmd.split(" "), stdout=subprocess.PIPE, stderr=subprocess.PIPE).stdout.decode("utf-8")
if output.find("Error") == -1 and output != "":
return render_template("message.html", message="Successfully connected to {}".format(ssid))
return render_template("message.html", message="Failed to connect to {}".format(ssid))
return render_template("wpa.html", title="WPA Password", form=form)
else:
form = WPAForm()
if form.validate_on_submit():
wpafile = """country=GB # Your 2-digit country code
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
network={{
ssid="{}"
psk="{}"
key_mgmt=WPA-PSK
}}
""".format(
ssid, form.password.data
)
with open("/etc/network/interfaces", "r") as sources:
lines = sources.readlines()
with open("/etc/network/interfaces", "w") as sources:
for line in lines:
sources.write(re.sub(r"^iface wlan0 inet manual", "iface wlan0 inet dhcp", line))
output = subprocess.run(
["sudo", "/usr/sbin/ifdown", ClientInterface], stdout=subprocess.PIPE, stderr=subprocess.PIPE
).stdout.decode("utf-8")
output = subprocess.run(
["sudo", "/usr/bin/systemctl", "stop", "wpa_supplicant"], stdout=subprocess.PIPE, stderr=subprocess.PIPE
).stdout.decode("utf-8")
with open("/etc/wpa_supplicant/wpa_supplicant.conf", "wt") as f:
f.write(wpafile)
try:
output = subprocess.run(
["sudo", "/usr/bin/systemctl", "start", "wpa_supplicant"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
timeout=20,
).stdout.decode("utf-8")
output = subprocess.run(
["sudo", "/usr/sbin/ifup", ClientInterface], stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=20
).stdout.decode("utf-8")
except:
return render_template("message.html", message="Failt to connected to {}".format(ssid))
return render_template("message.html", message="Successfully connected to {}".format(ssid))
return render_template("wpa.html", title="WPA Password", form=form)
@app.route("/connect/<string:ssid>&<string:security>", methods=["GET", "POST"])
@login_required
def connect(ssid, security):
if security == "WPA2":
return redirect(url_for("wpa", ssid=ssid))
# network={
# ssid="my ssid with spaces"
# key_mgmt=NONE
# }
if not RPI:
cmd = CMD_JOIN.replace("*SSID*", ssid)
output = subprocess.run(cmd.split(" "), stdout=subprocess.PIPE, stderr=subprocess.PIPE).stdout.decode("utf-8")
if output.find("Error") == -1:
return render_template("message.html", message="Successfully connected to {}".format(ssid))
return render_template("message.html", message="Failed to connect to {}".format(ssid))
else:
wpafile = """country=GB # Your 2-digit country code
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
network={{
ssid="{}"
key_mgmt=NONE
}}
""".format(
ssid
)
with open("/etc/network/interfaces", "r") as sources:
lines = sources.readlines()
with open("/etc/network/interfaces", "w") as sources:
for line in lines:
sources.write(re.sub(r"^iface wlan0 inet manual", "iface wlan0 inet dhcp", line))
output = subprocess.run(
["sudo", "/usr/sbin/ifdown", ClientInterface], stdout=subprocess.PIPE, stderr=subprocess.PIPE
).stdout.decode("utf-8")
output = subprocess.run(
["sudo", "/usr/bin/systemctl", "stop", "wpa_supplicant"], stdout=subprocess.PIPE, stderr=subprocess.PIPE
).stdout.decode("utf-8")
with open("/etc/wpa_supplicant/wpa_supplicant.conf", "wt") as f:
f.write(wpafile)
try:
output = subprocess.run(
["sudo", "/usr/bin/systemctl", "start", "wpa_supplicant"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
timeout=20,
).stdout.decode("utf-8")
output = subprocess.run(
["sudo", "/usr/sbin/ifup", ClientInterface], stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=20
).stdout.decode("utf-8")
except:
return render_template("message.html", message="Failt to connected to {}".format(ssid))
return render_template("message.html", message="Successfully connected to {}".format(ssid))
@app.route("/disconnect/<string:ssid>", methods=["GET", "POST"])
@login_required
def disconnect(ssid):
if not RPI:
output = subprocess.run(CMD_DISCONNECT.split(" "), stdout=subprocess.PIPE, stderr=subprocess.PIPE).stdout.decode("utf-8")
if output.find("successfully disconnected") != -1:
return render_template("message.html", message="Sucessfully disconnected from {}".format(ssid))
return render_template("message.html", message="Failed to Disconnect from {}".format(ssid))
else:
output = subprocess.run(
["sudo", "/usr/sbin/ifdown", ClientInterface], stdout=subprocess.PIPE, stderr=subprocess.PIPE
).stdout.decode("utf-8")
wpafile = """country=GB # Your 2-digit country code
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
"""
with open("/etc/wpa_supplicant/wpa_supplicant.conf", "wt") as f:
f.write(wpafile)
with open("/etc/network/interfaces", "r") as sources:
lines = sources.readlines()
with open("/etc/network/interfaces", "w") as sources:
for line in lines:
sources.write(re.sub(r"^iface wlan0 inet dhcp", "iface wlan0 inet manual", line))
try:
output = subprocess.run(
["sudo", "/usr/bin/systemctl", "restart", "wpa_supplicant"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
timeout=20,
).stdout.decode("utf-8")
output = subprocess.run(
["sudo", "/usr/sbin/ifup", ClientInterface], stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=20
).stdout.decode("utf-8")
except:
return render_template("message.html", message="Failt to disconnect from {}".format(ssid))
return render_template("message.html", message="Sucessfully disconnected from {}".format(ssid))

View File

@@ -1,65 +1,56 @@
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<style type="text/css">
.tg {
border-collapse: collapse;
border-spacing: 0;
}
.tg td {
border-color: black;
border-style: solid;
border-width: 1px;
font-family: Arial, sans-serif;
font-size: 14px;
overflow: hidden;
padding: 10px 5px;
word-break: normal;
}
.tg th {
border-color: black;
border-style: solid;
border-width: 1px;
font-family: Arial, sans-serif;
font-size: 14px;
font-weight: normal;
overflow: hidden;
padding: 10px 5px;
word-break: normal;
}
.tg .tg-0lax {
text-align: left;
vertical-align: top
}
</style>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Travel Router</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
</head>
<body>
<div>
Travel Router:
<a href="{{ url_for('index') }}">Home</a>
<nav class="navbar navbar-expand-lg bg-body-tertiary">
<div class="container-fluid">
<a class="navbar-brand" href="{{ url_for('index') }}">Travel Router</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"
aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" href="{{ url_for('index') }}">Home</a>
</li>
{% if not current_user.is_anonymous %}
<a href="{{ url_for('logout') }}">Logout</a>
<li class="nav-item">
<a class="nav-link" href="{{ url_for('logout') }}">Logout</a>
</li>
<li class="nav-item">
{% if vpn %}
<a href="{{ url_for('vpndisconnect') }}">Disconnect from VPN</a>
<a class="nav-link" href="{{ url_for('vpndisconnect') }}">Disconnect from VPN</a>
{% else %}
<a href="{{ url_for('vpnconnect') }}">Connect to VPN</a>
<a class="nav-link" href="{{ url_for('vpnconnect') }}">Connect to VPN</a>
{% endif %}
</li>
<li class="nav-item">
{% if killswitch %}
<a href="{{ url_for('ksdisable') }}">Disable KillSwitch</a>
<a class="nav-link" href="{{ url_for('ksdisable') }}">Disable KillSwitch</a>
{% else %}
<a href="{{ url_for('ksenable') }}">Enable KillSwitch</a>
<a class="nav-link" href="{{ url_for('ksenable') }}">Enable KillSwitch</a>
{% endif %}
</li>
{% endif %}
</ul>
</div>
<hr>
</div>
</nav>
<div class="container">
{% block content %}{% endblock %}
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz"
crossorigin="anonymous"></script>
</body>
</html>

View File

@@ -2,15 +2,17 @@
{% block content %}
<h1>Networks</h1>
<table class="tg">
<table class="table">
<thead>
<tr>
<th class="tg-0lax">SSID</th>
<th class="tg-0lax">Quality</th>
<th class="tg-0lax">Connected</th>
<th class="tg-0lax">Security</th>
<th class="tg-0lax">Action</th>
<th scope="col">SSID</th>
<th scope="col">Quality</th>
<th scope="col">Connected</th>
<th scope="col">Security</th>
<th scope="col">Action</th>
</tr>
</thead>
<tbody>
{%- for row in networks %}
<tr>
<td> {{ row['SSID'] }} </td>
@@ -19,14 +21,13 @@
<td> {{ row['WPA'] }} </td>
{% if row["Connected"] == "Yes" %}
<!-- {{ "User is logged in" if loggedin else "User is not logged in" }} -->
<td><a href={{"/disconnect/" + row["SSID"] }}>Disconnect</a></td>
<td><a href={{"/disconnect/" + row["SSID"] }} class="btn btn-secondary">Disconnect</a></td>
{% else %}
<td><a href={{"/connect/" + row["SSID"] + "&" + row["WPA"]}}>Connect</a></td>
<td><a href={{"/connect/" + row["SSID"] + "&" + row["WPA"]}} class="btn btn-primary">Connect</a></td>
{% endif %}
</tr>
{%- endfor %}
</thead>
</tbody>
</table>
{% endblock %}

View File

@@ -3,20 +3,20 @@
<h1>Sign In</h1>
<form action="" method="post" novalidate>
{{ form.hidden_tag() }}
<p>
{{ form.username.label }}<br>
{{ form.username(size=32) }}<br>
<div class="mb-3">
<label for="username" class="form-label">{{ form.username.label }}</label>
<input type="text" class="form-control" id="username" name="username" size="32">
{% for error in form.username.errors %}
<span style="color: red;">[{{ error }}]</span>
<div class="invalid-feedback">{{ error }}</div>
{% endfor %}
</p>
<p>
{{ form.password.label }}<br>
{{ form.password(size=32) }}<br>
</div>
<div class="mb-3">
<label for="password" class="form-label">{{ form.password.label }}</label>
<input type="password" class="form-control" id="password" name="password" size="32">
{% for error in form.password.errors %}
<span style="color: red;">[{{ error }}]</span>
<div class="invalid-feedback">{{ error }}</div>
{% endfor %}
</p>
<p>{{ form.submit() }}</p>
</div>
<button type="submit" class="btn btn-primary">{{ form.submit.label }}</button>
</form>
{% endblock %}

View File

@@ -1,5 +1,7 @@
{% extends "base.html" %}
{% block content %}
<h2>{{message}}</h2>
<div class="alert alert-info" role="alert">
{{message}}
</div>
{% endblock %}

View File

@@ -3,14 +3,17 @@
<h1>Password</h1>
<form action="" method="post" novalidate>
{{ form.hidden_tag() }}
<p>
{{ form.password.label }}<br>
{{ form.password(size=32) }}<br>
<div class="mb-3">
<label for="password" class="form-label">{{ form.password.label }}</label>
<input type="password" class="form-control" id="password" name="password" size="32">
{% for error in form.password.errors %}
<span style="color: red;">[{{ error }}]</span>
<div class="invalid-feedback">{{ error }}</div>
{% endfor %}
</p>
<p>{{ form.remember() }} {{ form.remember.label }}</p>
<p>{{ form.submit() }}</p>
</div>
<div class="mb-3 form-check">
<input type="checkbox" class="form-check-input" id="remember" name="remember">
<label class="form-check-label" for="remember">{{ form.remember.label }}</label>
</div>
<button type="submit" class="btn btn-primary">{{ form.submit.label }}</button>
</form>
{% endblock %}

View File

@@ -1,97 +0,0 @@
import subprocess
import sys
from flask import Flask
from flask import request, redirect
CMD_SCAN = "sudo nmcli -t -f SSID,SIGNAL,IN-USE,SECURITY -e yes -m tab device wifi list ifname wlxf81a6719febb --rescan yes"
scan = ["rpi:100: :WPA2", "Home:94:*:WPA2", "HOME2:48: :WPA2", "BT:23: :"]
# scan = []
app = Flask(__name__)
# sudo nmcli device wifi connect "Home" ifname wlxf81a6719febb password "password"
# sudo nmcli -t -f SSID,SIGNAL,IN-USE,SECURITY -e yes -m tab device wifi list ifname wlxf81a6719febb --rescan yes
def scan_wifi():
global scan
scan = []
temp = subprocess.run(CMD_SCAN.split(" "), stdout=subprocess.PIPE).stdout.decode("utf-8")
for line in temp.splitlines():
t = line.split(":")
if t[0] != "":
scan.append(line)
@app.route("/connect")
def connect():
return "connect"
@app.route("/passwd", methods=["GET", "POST"])
def passwd():
if request.method == "GET":
html = """<!DOCTYPE html>
<html>
<body>
<h2>Enter Password</h2>
<form method="POST">
<input type="text" id="passwd" name="passwd" value=""><br>
<p><input type=submit value="Submit"></p>
</form>
</body>
</html>"""
return html
if request.method == "POST":
# needs to pass password through... so probably not the way to do it..
return redirect("/connect")
@app.route("/", methods=["GET", "POST"])
def main():
if request.method == "GET":
# scan_wifi()
output = """<form method="POST"><table>
<thead>
<tr>
<th>Select</th>
<th>SID</th>
<th>Strength</th>
<th>Connected</th>
<th>Password</th>
</tr>
</thead>
<tbody>
*DATA*
</tbody>
<p><input type=submit value=Connect></p></form>"""
table = ""
counter = 1
for line in scan:
line = line.split(":")
table += '<tr><td><input value = "{}" id="type_radio_{}" name="type_radio" type="radio"</td><td>{}</td><td>{}</td><td>{}</td><td>{}</td></tr>'.format(
counter,
counter,
line[0],
line[1],
"yes" if line[2].strip() == "*" else "",
"None" if line[3].strip() == "" else line[3],
)
counter += 1
output = output.replace("*DATA*", table)
return output
if request.method == "POST":
try:
line = scan[int(request.form.get("type_radio")) - 1]
except:
return redirect("/")
if line.split(":")[3] == "WPA2":
return redirect("/passwd")
return redirect("/connect")

522
test.py
View File

@@ -1,7 +1,10 @@
<<<<<<< HEAD
iwlist_text = """wlan0 Scan completed :
Cell 01 - Address: 20:B0:01:9C:02:F9
=======
import unittest
from unittest.mock import patch, mock_open
from app.network_utils import parse_iwlist, connect_network, disconnect_network, cleanup_network
from config import ClientInterface
class TestNetworkUtils(unittest.TestCase):
def test_parse_iwlist(self):
iwlist_text = """wlan0 Scan completed :
Cell 01 - Address: 94:37:F7:ED:E5:F5
Channel:5
@@ -36,7 +39,6 @@ iwlist_text="""wlan0 Scan completed :
IE: Unknown: DD090010180207008C0000
IE: Unknown: DD180050F2020101840003A4000027A4000042435E0062322F00
Cell 02 - Address: 20:B0:01:9C:02:F9
>>>>>>> cb80ea19aeddde251c9f06ec8220b96bc5f137fb
Channel:2
Frequency:2.417 GHz (Channel 2)
Quality=56/70 Signal level=-54 dBm
@@ -47,48 +49,28 @@ iwlist_text="""wlan0 Scan completed :
Bit Rates:6 Mb/s; 9 Mb/s; 12 Mb/s; 48 Mb/s
Mode:Master
Extra:tsf=0000000000000000
<<<<<<< HEAD
Extra: Last beacon: 50ms ago
IE: Unknown: 0005484F4D4532
IE: Unknown: 010882848B962430486C
IE: Unknown: 030102
IE: Unknown: 2A0100
=======
Extra: Last beacon: 80ms ago
IE: Unknown: 0005484F4D4532
IE: Unknown: 010882848B962430486C
IE: Unknown: 030102
IE: Unknown: 050400010000
IE: Unknown: 2A0104
>>>>>>> cb80ea19aeddde251c9f06ec8220b96bc5f137fb
IE: Unknown: 32040C121860
IE: IEEE 802.11i/WPA2 Version 1
Group Cipher : CCMP
Pairwise Ciphers (1) : CCMP
Authentication Suites (1) : PSK
<<<<<<< HEAD
IE: Unknown: 0B050100180000
=======
IE: Unknown: 0B050100330000
>>>>>>> cb80ea19aeddde251c9f06ec8220b96bc5f137fb
IE: Unknown: 46053000000000
IE: Unknown: 2D1A2D0017FFFFFF0000000000000000000000000000000000000000
IE: Unknown: 3D1602080400000000000000000000000000000000000000
IE: Unknown: 4A0E14000A002C01C800140005001900
IE: Unknown: 7F080500080000400040
<<<<<<< HEAD
IE: Unknown: DD830050F204104A0001101044000102103B00010310470010FE571D369D3F5F88A4940FAD3FA4FE2C10210008566F6461666F6E65102300075448473330303010240007566F78332E307610420009313932385341484D411054000800060050F204000110110008566F7820332E3076100800020784103C0001031049000600372A000120
IE: Unknown: DD1E00904C0400BF0C1258820FEAFF0000EAFF0000C0050002000000C3020002
IE: Unknown: DD090010180201101C0000
IE: Unknown: DD180050F2020101000003A4000027A4000042435E0062322F00
Cell 02 - Address: 1C:BF:CE:8A:B4:41
=======
IE: Unknown: DD1D0050F204104A0001101044000102103C0001031049000600372A000120
IE: Unknown: DD1E00904C0400BF0C1258820FEAFF0000EAFF0000C0050002000000C3020002
IE: Unknown: DD090010180201101C0000
IE: Unknown: DD180050F2020101000003A4000027A4000042435E0062322F00
Cell 03 - Address: 1C:BF:CE:8A:B4:41
>>>>>>> cb80ea19aeddde251c9f06ec8220b96bc5f137fb
Channel:7
Frequency:2.442 GHz (Channel 7)
Quality=70/70 Signal level=-10 dBm
@@ -99,11 +81,7 @@ iwlist_text="""wlan0 Scan completed :
Bit Rates:24 Mb/s; 36 Mb/s; 48 Mb/s; 54 Mb/s
Mode:Master
Extra:tsf=0000000000000000
<<<<<<< HEAD
Extra: Last beacon: 50ms ago
=======
Extra: Last beacon: 80ms ago
>>>>>>> cb80ea19aeddde251c9f06ec8220b96bc5f137fb
IE: Unknown: 0003727069
IE: Unknown: 010882848B960C121824
IE: Unknown: 030107
@@ -114,450 +92,108 @@ iwlist_text="""wlan0 Scan completed :
Group Cipher : CCMP
Pairwise Ciphers (1) : CCMP
Authentication Suites (1) : PSK
<<<<<<< HEAD
Cell 03 - Address: 22:B0:01:9C:02:01
Channel:52
Frequency:5.26 GHz (Channel 52)
Quality=56/70 Signal level=-54 dBm
Encryption key:on
ESSID:"HOME2"
Bit Rates:6 Mb/s; 9 Mb/s; 12 Mb/s; 18 Mb/s; 24 Mb/s
36 Mb/s; 48 Mb/s; 54 Mb/s
Mode:Master
Extra:tsf=0000000000000000
Extra: Last beacon: 50ms ago
IE: Unknown: 0005484F4D4532
IE: Unknown: 01088C129824B048606C
IE: Unknown: 050400010100
IE: Unknown: 073C4742202401172801172C01173001173401173801173C011740011764011E68011E6C011E70011E74011E78011E7C011E80011E84011E88011E8C011E
IE: Unknown: 200100
IE: Unknown: 23021400
IE: IEEE 802.11i/WPA2 Version 1
Group Cipher : CCMP
Pairwise Ciphers (1) : CCMP
Authentication Suites (1) : PSK
IE: Unknown: 0B050300020000
IE: Unknown: 420100
IE: Unknown: 46053000000000
IE: Unknown: 2D1A6F0017FFFFFFFF00000000000000000000000000000000000000
IE: Unknown: 3D1634050400000000000000000000000000000000000000
IE: Unknown: 4A0E14000A002C01C800140005001900
IE: Unknown: 7F080500088000400040
IE: Unknown: BF0C3268830FAAFF0000AAFF0000
IE: Unknown: C005013A000000
IE: Unknown: C30402020202
IE: Unknown: DD1D0050F204104A0001101044000102103C0001031049000600372A000120
IE: Unknown: DD0500904C0417
IE: Unknown: DD090010180203009C0000
IE: Unknown: DD180050F2020101000003A4000027A4000042435E0062322F00
IE: Unknown: DD07506F9A16010100
IE: Unknown: 6C027F00
Cell 04 - Address: 94:37:F7:ED:E5:F5
Channel:7
Frequency:2.442 GHz (Channel 7)
Quality=70/70 Signal level=-37 dBm
Encryption key:on
ESSID:"Home"
=======
Cell 04 - Address: 96:37:F7:ED:E5:F9
Channel:5
Frequency:2.432 GHz (Channel 5)
Quality=67/70 Signal level=-43 dBm
Encryption key:on
ESSID:"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
>>>>>>> cb80ea19aeddde251c9f06ec8220b96bc5f137fb
ESSID:"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00"
Bit Rates:1 Mb/s; 2 Mb/s; 5.5 Mb/s; 11 Mb/s; 18 Mb/s
24 Mb/s; 36 Mb/s; 54 Mb/s
Bit Rates:6 Mb/s; 9 Mb/s; 12 Mb/s; 48 Mb/s
Mode:Master
Extra:tsf=0000000000000000
<<<<<<< HEAD
Extra: Last beacon: 50ms ago
IE: Unknown: 0004486F6D65
IE: Unknown: 010882840B162430486C
IE: Unknown: 030107
=======
Extra: Last beacon: 80ms ago
IE: Unknown: 0018000000000000000000000000000000000000000000000000
IE: Unknown: 010882840B162430486C
IE: Unknown: 030105
IE: Unknown: 050400010000
>>>>>>> cb80ea19aeddde251c9f06ec8220b96bc5f137fb
IE: Unknown: 23020E00
IE: Unknown: 2A0104
IE: Unknown: 32040C121860
IE: IEEE 802.11i/WPA2 Version 1
Group Cipher : CCMP
Pairwise Ciphers (1) : CCMP
Authentication Suites (1) : PSK
<<<<<<< HEAD
IE: Unknown: 0B050500190000
IE: Unknown: 2D1AEE191BFFFF000000000000000000000000000000000000000000
IE: Unknown: 3D1607081500000000000000000000000000000000000000
IE: Unknown: 4A0E14000A002C01C800140005001900
IE: Unknown: 7F080500080000000040
IE: Unknown: DD7E0050F204104A0001101044000102103B00010310470010D96C7EFC2F8938F1EFBD6E5148BFA81210210006487561776569102300064875617765691024000631323334353610420004313233341054000800060050F2040001101100084875617765694150100800020100103C0001031049000A00372A00012005020780
IE: Unknown: DD0F00E0FC400000000000FD0480000000
IE: Unknown: DD0F00E0FC8000000001009437F7EDE5F5
IE: Unknown: DD1400E0FC400000000000FB069437F7EDE5F5F90101
IE: Unknown: DD090010180205008C0000
IE: Unknown: DD180050F2020101840003A4000027A4000042435E0062322F00
Cell 05 - Address: EC:8E:B5:B3:AE:CE
Channel:7
Frequency:2.442 GHz (Channel 7)
Quality=44/70 Signal level=-66 dBm
=======
IE: Unknown: 0B0500003A0000
IE: Unknown: 2D1AEE191BFFFF000000000000000000000000000000000000000000
IE: Unknown: 3D1605081500000000000000000000000000000000000000
IE: Unknown: 4A0E14000A002C01C800140005001900
IE: Unknown: 7F080500080000000040
IE: Unknown: DD090010180200000C0000
IE: Unknown: DD180050F2020101840003A4000027A4000042435E0062322F00
Cell 05 - Address: EC:8E:B5:B3:AE:CE
Channel:5
Frequency:2.432 GHz (Channel 5)
Quality=50/70 Signal level=-60 dBm
>>>>>>> cb80ea19aeddde251c9f06ec8220b96bc5f137fb
Encryption key:on
ESSID:"DIRECT-CD-HP ENVY 4520 series"
Bit Rates:6 Mb/s; 9 Mb/s; 12 Mb/s; 18 Mb/s; 24 Mb/s
36 Mb/s; 48 Mb/s; 54 Mb/s
Mode:Master
Extra:tsf=0000000000000000
<<<<<<< HEAD
Extra: Last beacon: 50ms ago
IE: Unknown: 001D4449524543542D43442D485020454E5659203435323020736572696573
IE: Unknown: 01088C129824B048606C
IE: Unknown: 030107
=======
Extra: Last beacon: 80ms ago
IE: Unknown: 001D4449524543542D43442D485020454E5659203435323020736572696573
IE: Unknown: 01088C129824B048606C
IE: Unknown: 030105
>>>>>>> cb80ea19aeddde251c9f06ec8220b96bc5f137fb
IE: Unknown: 200100
IE: Unknown: 23021100
IE: Unknown: 2A0100
IE: Unknown: 2F0100
IE: IEEE 802.11i/WPA2 Version 1
Group Cipher : CCMP
Pairwise Ciphers (1) : CCMP
Authentication Suites (1) : PSK
IE: Unknown: 2D1A20001AFF00000000000000000000000000000000000000000000
<<<<<<< HEAD
IE: Unknown: 3D1607081100000000000000000000000000000000000000
=======
IE: Unknown: 3D1605080000000000000000000000000000000000000000
>>>>>>> cb80ea19aeddde251c9f06ec8220b96bc5f137fb
IE: Unknown: DD090010180200000C0000
IE: Unknown: DD180050F202010188000364000027A4000041435E0061322F00
IE: Unknown: DDC10050F204104A000110104400010210570001011041000100103B000103104700101C852A4DB8001F08ABCDEC8EB5B3AECD10210002485010230011454E565920343532302073657269657300102400053435323400104200105448363650334D3044393036363000001054000800030050F20400051011001D4449524543542D43442D485020454E56592034353230207365726965731008000200001049000600372A00012010490017000137100600101C852A4DB8001F08ABCDEC8EB5B3AECD
IE: Unknown: DD5F080009000400000007010201000311454E5659203435323020736572696573000405343532340005105448363650334D30443930363630000006101C852A4DB8001F08ABCDEC8EB5B3AECD0704C0A800A3080200D4090200080A0400000001
Cell 06 - Address: D4:DA:CD:27:B5:92
Channel:36
Frequency:5.18 GHz (Channel 36)
Quality=50/70 Signal level=-60 dBm
Encryption key:on
ESSID:"SKY2E6AD"
Bit Rates:6 Mb/s; 9 Mb/s; 12 Mb/s; 18 Mb/s; 24 Mb/s
36 Mb/s; 48 Mb/s; 54 Mb/s
Mode:Master
Extra:tsf=0000000000000000
<<<<<<< HEAD
Extra: Last beacon: 50ms ago
=======
Extra: Last beacon: 80ms ago
>>>>>>> cb80ea19aeddde251c9f06ec8220b96bc5f137fb
IE: Unknown: 0008534B593245364144
IE: Unknown: 01088C129824B048606C
IE: Unknown: 07344742202401172801172C01173001173401173801173C011740011764011E68011E6C011E70011E74011E84011E88011E8C011E00
IE: Unknown: 200100
IE: Unknown: 23021000
IE: IEEE 802.11i/WPA2 Version 1
Group Cipher : CCMP
Pairwise Ciphers (1) : CCMP
Authentication Suites (1) : PSK
<<<<<<< HEAD
IE: Unknown: 0B050000280000
=======
IE: Unknown: 0B050000130000
>>>>>>> cb80ea19aeddde251c9f06ec8220b96bc5f137fb
IE: Unknown: 420100
IE: Unknown: 46057208000000
IE: Unknown: 2D1AEF0117FFFFFFFF00000000000000000000000000000000000000
IE: Unknown: 3D1624050000000000000000000000000000000000000000
IE: Unknown: 7F080400080000000040
IE: Unknown: BF0CB269830FAAFF0000AAFF0000
IE: Unknown: C005012A000000
IE: Unknown: C30402020202
<<<<<<< HEAD
IE: Unknown: DDAD0050F204104A0001101044000102103B00010310470010B3B9D65E5B53F032D888BB2D851A5CBA10210003536B7910230005454D31353010240007312E302E302E301042000E41543133353132303330303030311054000800060050F20400011011000E536B792051204D696E6920626F7810080002200C103C0001021049000600372A00012010580022007FC51000186309446EBAB7CC70AE7616820D8EF0A5303030303030303130000101
=======
IE: Unknown: DDAD0050F204104A0001101044000102103B00010310470010B3B9D65E5B53F032D888BB2D851A5CBA10210003536B7910230005454D31353010240007312E302E302E301042000E41543133353132303330303030311054000800060050F20400011011000E536B792051204D696E6920626F7810080002200C103C0001021049000600372A00012010580022007FC510001868FFE221A0ABBBB2A9C1BB3C760026E3303030303030303130000101
>>>>>>> cb80ea19aeddde251c9f06ec8220b96bc5f137fb
IE: Unknown: DD090010180200001C0000
IE: Unknown: DD180050F2020101840003A4000027A4000042435E0062322F00
Cell 07 - Address: 94:37:F7:ED:E5:FA
Channel:36
Frequency:5.18 GHz (Channel 36)
<<<<<<< HEAD
Quality=64/70 Signal level=-46 dBm
=======
Quality=62/70 Signal level=-48 dBm
>>>>>>> cb80ea19aeddde251c9f06ec8220b96bc5f137fb
Encryption key:on
ESSID:"Home_5GHz"
Bit Rates:6 Mb/s; 9 Mb/s; 12 Mb/s; 18 Mb/s; 24 Mb/s
36 Mb/s; 48 Mb/s; 54 Mb/s
Mode:Master
Extra:tsf=0000000000000000
<<<<<<< HEAD
Extra: Last beacon: 50ms ago
=======
Extra: Last beacon: 80ms ago
>>>>>>> cb80ea19aeddde251c9f06ec8220b96bc5f137fb
IE: Unknown: 0009486F6D655F3547487A
IE: Unknown: 01088C129824B048606C
IE: Unknown: 200100
IE: Unknown: 23020F00
IE: IEEE 802.11i/WPA2 Version 1
Group Cipher : CCMP
Pairwise Ciphers (1) : CCMP
Authentication Suites (1) : PSK
<<<<<<< HEAD
IE: Unknown: 0B0505002F0000
IE: Unknown: 2D1AEF0117FFFFFFFF00000000000000000000000000000000000000
IE: Unknown: 3D1624050400000000000000000000000000000000000000
=======
IE: Unknown: 0B050700210000
IE: Unknown: 2D1AEF0117FFFFFFFF00000000000000000000000000000000000000
IE: Unknown: 3D1624051600000000000000000000000000000000000000
>>>>>>> cb80ea19aeddde251c9f06ec8220b96bc5f137fb
IE: Unknown: 7F080400080000000040
IE: Unknown: BF0CB5698B0FAAFF0000AAFF0020
IE: Unknown: C005012A000000
IE: Unknown: C30402202020
IE: Unknown: C70132
IE: Unknown: FF24230900001200100C2002C06F5B8318000C00AAFFAAFFAAFFAAFF1B1CC7711CC7711CC771
<<<<<<< HEAD
IE: Unknown: FF072404000030FCFF
IE: Unknown: FF022700
IE: Unknown: FF0E260400A4FF20A4FF4043FF6032FF
IE: Unknown: DD7E0050F204104A0001101044000102103B00010310470010D96C7EFC2F8938F1EFBD6E5148BFA81210210006487561776569102300064875617765691024000631323334353610420004313233341054000800060050F2040001101100084875617765694150100800020100103C0001031049000A00372A00012005020780
IE: Unknown: DD0F00E0FC8000000001009437F7EDE5FA
IE: Unknown: DD1400E0FC400000000000FB069437F7EDE5FAF90101
IE: Unknown: DD0500904C0417
IE: Unknown: DD090010180205001C0000
IE: Unknown: DD180050F2020101840003A4000027A4000042435E0062322F00
Cell 08 - Address: 62:8E:29:1A:B2:3D
Channel:1
Frequency:2.412 GHz (Channel 1)
Quality=34/70 Signal level=-76 dBm
Encryption key:off
ESSID:"BTWi-fi"
Bit Rates:1 Mb/s; 2 Mb/s; 5.5 Mb/s; 11 Mb/s; 18 Mb/s
24 Mb/s; 36 Mb/s; 54 Mb/s
Bit Rates:6 Mb/s; 9 Mb/s; 12 Mb/s; 48 Mb/s
Mode:Master
Extra:tsf=0000000000000000
Extra: Last beacon: 50ms ago
IE: Unknown: 0007425457692D6669
IE: Unknown: 010882848B962430486C
IE: Unknown: 030101
IE: Unknown: 050401030000
IE: Unknown: 0706474220010D14
IE: Unknown: 2A0104
IE: Unknown: 32040C121860
IE: Unknown: 0B050000230000
IE: Unknown: 2D1AAD0117FFFFFF0000000000000000000000000000000000000000
IE: Unknown: 3D1601000400000000000000000000000000000000000000
IE: Unknown: 7F080400080000000040
IE: Unknown: DD1E00904C0408BF0CB259820FEAFF0000EAFF0000C0050001000000C3020002
IE: Unknown: DD090010180200101C0000
IE: Unknown: DD180050F2020101880003A4000027A4000042435E0062322F00
Cell 09 - Address: 98:1E:19:E5:01:39
=======
IE: Unknown: FF072404000025FCFF
IE: Unknown: FF022700
IE: Unknown: FF0E260400A4FF20A4FF4043FF6032FF
IE: Unknown: DD0F00E0FC8000000001009437F7EDE5FA
IE: Unknown: DD1400E0FC400000000000FB069437F7EDE5FAF90101
IE: Unknown: DD7E0050F204104A0001101044000102103B00010310470010D96C7EFC2F8938F1EFBD6E5148BFA81210210006487561776569102300064875617765691024000631323334353610420004313233341054000800060050F2040001101100084875617765694150100800020100103C0001031049000A00372A00012005020780
IE: Unknown: DD0500904C0417
IE: Unknown: DD090010180207001C0000
IE: Unknown: DD180050F2020101840003A4000027A4000042435E0062322F00
Cell 08 - Address: 98:1E:19:E5:01:39
>>>>>>> cb80ea19aeddde251c9f06ec8220b96bc5f137fb
Channel:36
Frequency:5.18 GHz (Channel 36)
Quality=33/70 Signal level=-77 dBm
Encryption key:on
ESSID:"BTHub6-F8K2"
Bit Rates:6 Mb/s; 9 Mb/s; 12 Mb/s; 18 Mb/s; 24 Mb/s
36 Mb/s; 48 Mb/s; 54 Mb/s
Mode:Master
Extra:tsf=0000000000000000
<<<<<<< HEAD
Extra: Last beacon: 50ms ago
IE: Unknown: 000B4254487562362D46384B32
IE: Unknown: 01088C129824B048606C
=======
Extra: Last beacon: 80ms ago
IE: Unknown: 000B4254487562362D46384B32
IE: Unknown: 01088C129824B048606C
IE: Unknown: 050402030000
>>>>>>> cb80ea19aeddde251c9f06ec8220b96bc5f137fb
IE: Unknown: 073C4742202401172801172C01173001173401173801173C011740011764011E68011E6C011E70011E74011E78011E7C011E80011E84011E88011E8C011E
IE: Unknown: 200100
IE: Unknown: 23021500
IE: IEEE 802.11i/WPA2 Version 1
Group Cipher : CCMP
Pairwise Ciphers (1) : CCMP
Authentication Suites (1) : PSK
<<<<<<< HEAD
IE: Unknown: 0B050100110000
=======
IE: Unknown: 0B0501000C0000
>>>>>>> cb80ea19aeddde251c9f06ec8220b96bc5f137fb
IE: Unknown: 42020000
IE: Unknown: 2D1AEF0117FFFFFFFF00000000000000000000000000000000000000
IE: Unknown: 3D1624050000000000000000000000000000000000000000
IE: Unknown: 7F080400080000000040
IE: Unknown: BF0CB269830FAAFF0000AAFF0000
IE: Unknown: C005012A000000
IE: Unknown: C30402020202
<<<<<<< HEAD
IE: Unknown: DD800050F204104A0001101044000102103B000103104700102ADE320B3332E522A765BA8ACC7669F81021000242541023000842545F4855425F3610240007312E302D322E30104200063132333435361054000800060050F20400011011000D42545F4855425F362D31323334100800022000103C0001031049000600372A000120
IE: Unknown: DD0500904C0417
IE: Unknown: DD090010180201001C0000
IE: Unknown: DD180050F2020101800003A4000027A4000042435E0062322F00
Cell 10 - Address: 96:37:F7:ED:E5:FC
Channel:36
Frequency:5.18 GHz (Channel 36)
Quality=64/70 Signal level=-46 dBm
Encryption key:on
ESSID:"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
=======
IE: Unknown: DD310050F204104A0001101044000102104700102ADE320B3332E522A765BA8ACC7669F8103C0001031049000600372A000120
IE: Unknown: DD0500904C0417
IE: Unknown: DD090010180201001C0000
IE: Unknown: DD180050F2020101800003A4000027A4000042435E0062322F00
Cell 09 - Address: 22:B0:01:9C:02:01
Channel:52
Frequency:5.26 GHz (Channel 52)
Quality=53/70 Signal level=-57 dBm
Encryption key:on
ESSID:"HOME2"
>>>>>>> cb80ea19aeddde251c9f06ec8220b96bc5f137fb
Bit Rates:6 Mb/s; 9 Mb/s; 12 Mb/s; 18 Mb/s; 24 Mb/s
36 Mb/s; 48 Mb/s; 54 Mb/s
Mode:Master
Extra:tsf=0000000000000000
<<<<<<< HEAD
Extra: Last beacon: 50ms ago
IE: Unknown: 0018000000000000000000000000000000000000000000000000
IE: Unknown: 01088C129824B048606C
IE: Unknown: 050400010000
IE: Unknown: 200100
IE: Unknown: 23020F00
=======
Extra: Last beacon: 80ms ago
IE: Unknown: 0005484F4D4532
IE: Unknown: 01088C129824B048606C
IE: Unknown: 050400010000
IE: Unknown: 073C4742202401172801172C01173001173401173801173C011740011764011E68011E6C011E70011E74011E78011E7C011E80011E84011E88011E8C011E
IE: Unknown: 200100
IE: Unknown: 23021400
>>>>>>> cb80ea19aeddde251c9f06ec8220b96bc5f137fb
IE: IEEE 802.11i/WPA2 Version 1
Group Cipher : CCMP
Pairwise Ciphers (1) : CCMP
Authentication Suites (1) : PSK
<<<<<<< HEAD
IE: Unknown: 0B0500002F0000
IE: Unknown: 2D1AEF0117FFFFFFFF00000000000000000000000000000000000000
IE: Unknown: 3D1624050400000000000000000000000000000000000000
IE: Unknown: 7F080400080000000040
IE: Unknown: BF0CB5698B0FAAFF0000AAFF0020
IE: Unknown: C005012A000000
IE: Unknown: C30402202020
IE: Unknown: C70132
IE: Unknown: FF24230900001200100C2002C06F5B8318000C00AAFFAAFFAAFFAAFF1B1CC7711CC7711CC771
IE: Unknown: FF072404000030FCFF
IE: Unknown: FF022700
IE: Unknown: FF0E260400A4FF20A4FF4043FF6032FF
IE: Unknown: DD0500904C0417
IE: Unknown: DD090010180200001C0000
IE: Unknown: DD180050F2020101840003A4000027A4000042435E0062322F00
"""
from pprint import pprint
expected_results = [
{'Connected': '', 'SSID': 'Home', 'Signal': '70/70', 'WPA': 'WPA2'},
{'Connected': '', 'SSID': 'HOME2', 'Signal': '56/70', 'WPA': 'WPA2'},
{'Connected': '', 'SSID': 'rpi', 'Signal': '70/70', 'WPA': 'WPA2'}
]
results = parse_iwlist(iwlist_text, "")
# We can't guarantee the order of the results, so we'll sort them by SSID
results.sort(key=lambda x: x['SSID'])
expected_results.sort(key=lambda x: x['SSID'])
def parse_iwlist(iwlist_output):
data = []
in_cell = False
cell = []
for line in iwlist_output.splitlines():
if line.find(" Cell ") != -1 and cell != []:
data.append(cell)
cell = []
elif line.find("Scan completed :") > 0:
pass
else:
cell.append(line)
self.assertEqual(results, expected_results)
del data[0][0]
class TestNetworkConnection(unittest.TestCase):
@patch('app.network_utils.run_subprocess_interface')
@patch('app.network_utils.run_subprocess')
@patch('builtins.open', new_callable=mock_open)
def test_connect_network_wpa2_success(self, mock_file, mock_run_subprocess, mock_run_subprocess_interface):
mock_run_subprocess.return_value = "Success"
mock_run_subprocess_interface.return_value = "Success"
result = connect_network("TestSSID", "WPA2", "TestPassword")
self.assertTrue(result)
mock_file.assert_any_call('/etc/network/interfaces', 'r')
mock_file.assert_any_call('/etc/network/interfaces', 'w')
mock_file.assert_any_call('/etc/wpa_supplicant/wpa_supplicant.conf', 'wt')
mock_run_subprocess_interface.assert_any_call(f'sudo /usr/sbin/ifdown {{}}')
mock_run_subprocess.assert_any_call('sudo /usr/bin/systemctl stop wpa_supplicant')
mock_run_subprocess.assert_any_call('sudo /usr/bin/systemctl start wpa_supplicant')
mock_run_subprocess_interface.assert_any_call(f'sudo /usr/sbin/ifup {{}}')
cells = []
@patch('app.network_utils.run_subprocess')
@patch('builtins.open', new_callable=mock_open)
def test_connect_network_wpa2_failure(self, mock_file, mock_run_subprocess):
mock_run_subprocess.return_value = None
result = connect_network("TestSSID", "WPA2", "TestPassword")
self.assertFalse(result)
for a in data:
cell = {}
for line in a:
line = line.strip()
if line.find("ESSID:") != -1:
if line.partition("ESSID:")[2].strip('"') != "":
cell["SSID"] = line.partition("ESSID:")[2].strip('"')
if line.partition("Signal level=")[2].split("/")[0] != "" != -1:
cell["Signal"] = line.partition("Signal level=")[2].split("/")[0]
if line.find("Encryption key:") != -1:
if line.find(":on") != -1:
cell["WPA"] = "WPA2"
else:
cell["WPA"] = "None"
cells.append(cell)
@patch('app.network_utils.run_subprocess_interface')
@patch('app.network_utils.run_subprocess')
@patch('builtins.open', new_callable=mock_open)
def test_disconnect_network_success(self, mock_file, mock_run_subprocess, mock_run_subprocess_interface):
mock_run_subprocess.return_value = "Success"
mock_run_subprocess_interface.return_value = "Success"
result = disconnect_network()
self.assertTrue(result)
mock_file.assert_any_call('/etc/wpa_supplicant/wpa_supplicant.conf', 'wt')
mock_run_subprocess_interface.assert_any_call(f'sudo /usr/sbin/ifdown {{}}')
mock_run_subprocess.assert_any_call('sudo /usr/bin/systemctl stop wpa_supplicant')
mock_run_subprocess.assert_any_call('sudo /usr/bin/systemctl start wpa_supplicant')
mock_run_subprocess_interface.assert_any_call(f'sudo /usr/sbin/ifup {{}}')
pprint(cells)
@patch('app.network_utils.run_subprocess')
@patch('builtins.open', new_callable=mock_open)
def test_disconnect_network_failure(self, mock_file, mock_run_subprocess):
mock_run_subprocess.return_value = None
result = disconnect_network()
self.assertFalse(result)
@patch('app.network_utils.run_subprocess_interface')
@patch('app.network_utils.run_subprocess')
@patch('builtins.open', new_callable=mock_open)
def test_cleanup_network_success(self, mock_file, mock_run_subprocess, mock_run_subprocess_interface):
mock_run_subprocess.return_value = "Success"
mock_run_subprocess_interface.return_value = "Success"
result = cleanup_network()
self.assertTrue(result)
mock_file.assert_any_call('/etc/wpa_supplicant/wpa_supplicant.conf', 'wt')
mock_run_subprocess_interface.assert_any_call(f'sudo /usr/sbin/ifdown {{}}')
mock_run_subprocess.assert_any_call('sudo /usr/bin/systemctl stop wpa_supplicant')
mock_run_subprocess.assert_any_call('sudo /usr/bin/systemctl start wpa_supplicant')
mock_run_subprocess_interface.assert_any_call(f'sudo /usr/sbin/ifup {{}}')
if __name__ == "__main__":
parse_iwlist(iwlist_text)
=======
IE: Unknown: 0B050200040000
IE: Unknown: 420100
IE: Unknown: 46053000000000
IE: Unknown: 2D1A6F0017FFFFFFFF00000000000000000000000000000000000000
IE: Unknown: 3D1634050400000000000000000000000000000000000000
IE: Unknown: 4A0E14000A002C01C800140005001900
IE: Unknown: 7F080500088000400040
IE: Unknown: BF0C3268830FAAFF0000AAFF0000
IE: Unknown: C005013A000000
IE: Unknown: C30402020202
IE: Unknown: DD1D0050F204104A0001101044000102103C0001031049000600372A000120
IE: Unknown: DD0500904C0417
IE: Unknown: DD090010180202009C0000
IE: Unknown: DD180050F2020101000003A4000027A4000042435E0062322F00
IE: Unknown: DD07506F9A16010100
IE: Unknown: 6C027F00
@patch('app.network_utils.run_subprocess')
@patch('builtins.open', new_callable=mock_open)
def test_cleanup_network_failure(self, mock_file, mock_run_subprocess):
mock_run_subprocess.return_value = None
result = cleanup_network()
self.assertFalse(result)
"""
def parse_iwlist(iwlist_output):
data = []
for line in iwlist_output:
if line.find()
if __name__ == '__main__':
parse_iwlist(iwlist_text)
>>>>>>> cb80ea19aeddde251c9f06ec8220b96bc5f137fb
unittest.main()

View File

@@ -1,6 +1,10 @@
from app import app, db
from app.models import User
from app.network_utils import cleanup_network
cleanup_network()
@app.shell_context_processor
def make_shell_context():
return {'db': db, 'User': User}