initial install test

This commit is contained in:
NL-TCH 2024-02-08 23:24:30 +01:00
parent ce63e48445
commit 2ce8351b1a
17 changed files with 767 additions and 0 deletions

20
api/auth.py Normal file
View file

@ -0,0 +1,20 @@
import os
from fastapi.security.api_key import APIKeyHeader
from fastapi import Security, HTTPException
from starlette.status import HTTP_403_FORBIDDEN
apikey=os.getenv('RASPAP_API_KEY')
#if env not set, set the api key to "insecure"
if apikey == None:
apikey = "insecure"
print(apikey)
api_key_header = APIKeyHeader(name="access_token", auto_error=False)
async def get_api_key(api_key_header: str = Security(api_key_header)):
if api_key_header ==apikey:
return api_key_header
else:
raise HTTPException(
status_code=HTTP_403_FORBIDDEN, detail="403: Unauthorized"
)

229
api/main.py Normal file
View file

@ -0,0 +1,229 @@
from fastapi import FastAPI, Depends
from fastapi.security.api_key import APIKey
import auth
import json
import modules.system as system
import modules.ap as ap
import modules.client as client
import modules.dns as dns
import modules.dhcp as dhcp
import modules.ddns as ddns
import modules.firewall as firewall
import modules.networking as networking
import modules.openvpn as openvpn
import modules.wireguard as wireguard
import modules.restart as restart
tags_metadata = [
{
"name": "system",
"description": "All information regarding the underlying system."
},
{
"name": "accesspoint/hostpost",
"description": "Get and change all information regarding the hotspot"
}
]
app = FastAPI(
title="API for Raspap",
openapi_tags=tags_metadata,
version="0.0.1",
license_info={
"name": "Apache 2.0",
"url": "https://www.apache.org/licenses/LICENSE-2.0.html",
}
)
@app.get("/system", tags=["system"])
async def get_system():
return{
'hostname': system.hostname(),
'uptime': system.uptime(),
'systime': system.systime(),
'usedMemory': system.usedMemory(),
'processorCount': system.processorCount(),
'LoadAvg1Min': system.LoadAvg1Min(),
'systemLoadPercentage': system.systemLoadPercentage(),
'systemTemperature': system.systemTemperature(),
'hostapdStatus': system.hostapdStatus(),
'operatingSystem': system.operatingSystem(),
'kernelVersion': system.kernelVersion(),
'rpiRevision': system.rpiRevision()
}
@app.get("/ap", tags=["accesspoint/hostpost"])
async def get_ap():
return{
'driver': ap.driver(),
'ctrl_interface': ap.ctrl_interface(),
'ctrl_interface_group': ap.ctrl_interface_group(),
'auth_algs': ap.auth_algs(),
'wpa_key_mgmt': ap.wpa_key_mgmt(),
'beacon_int': ap.beacon_int(),
'ssid': ap.ssid(),
'channel': ap.channel(),
'hw_mode': ap.hw_mode(),
'ieee80211n': ap.ieee80211n(),
'wpa_passphrase': ap.wpa_passphrase(),
'interface': ap.interface(),
'wpa': ap.wpa(),
'wpa_pairwise': ap.wpa_pairwise(),
'country_code': ap.country_code(),
'ignore_broadcast_ssid': ap.ignore_broadcast_ssid()
}
@app.post("/ap", tags=["accesspoint/hostpost"])
async def post_ap(driver=None,
ctrl_interface=None,
ctrl_interface_group=None,
auth_algs=None,
wpa_key_mgmt=None,
beacon_int=None,
ssid=None,
channel=None,
hw_mode=None,
ieee80211n=None,
wpa_passphrase=None,
interface=None,
wpa=None,
wpa_pairwise=None,
country_code=None,
ignore_broadcast_ssid=None,
api_key: APIKey = Depends(auth.get_api_key)):
if driver != None:
ap.set_driver(driver)
if ctrl_interface != None:
ap.set_ctrl_interface(ctrl_interface)
if ctrl_interface_group !=None:
ap.set_ctrl_interface_group(ctrl_interface_group)
if auth_algs != None:
ap.set_auth_algs(auth_algs)
if wpa_key_mgmt != None:
ap.set_wpa_key_mgmt(wpa_key_mgmt)
if beacon_int != None:
ap.set_beacon_int(beacon_int)
if ssid != None:
ap.set_ssid(ssid)
if channel != None:
ap.set_channel(channel)
if hw_mode != None:
ap.set_hw_mode(hw_mode)
if ieee80211n != None:
ap.set_ieee80211n(ieee80211n)
if wpa_passphrase != None:
ap.set_wpa_passphrase(wpa_passphrase)
if interface != None:
ap.set_interface(interface)
if wpa != None:
ap.set_wpa(wpa)
if wpa_pairwise != None:
ap.set_wpa_pairwise(wpa_pairwise)
if country_code != None:
ap.set_country_code(country_code)
if ignore_broadcast_ssid != None:
ap.set_ignore_broadcast_ssid(ignore_broadcast_ssid)
@app.get("/clients/{wireless_interface}", tags=["Clients"])
async def get_clients(wireless_interface):
return{
'active_clients_amount': client.get_active_clients_amount(wireless_interface),
'active_clients': json.loads(client.get_active_clients(wireless_interface))
}
@app.get("/dhcp", tags=["DHCP"])
async def get_dhcp():
return{
'range_start': dhcp.range_start(),
'range_end': dhcp.range_end(),
'range_subnet_mask': dhcp.range_subnet_mask(),
'range_lease_time': dhcp.range_lease_time(),
'range_gateway': dhcp.range_gateway(),
'range_nameservers': dhcp.range_nameservers()
}
@app.get("/dns/domains", tags=["DNS"])
async def get_domains():
return{
'domains': json.loads(dns.adblockdomains())
}
@app.get("/dns/hostnames", tags=["DNS"])
async def get_hostnames():
return{
'hostnames': json.loads(dns.adblockhostnames())
}
@app.get("/dns/upstream", tags=["DNS"])
async def get_upstream():
return{
'upstream_nameserver': dns.upstream_nameserver()
}
@app.get("/dns/logs", tags=["DNS"])
async def get_dnsmasq_logs():
return(dns.dnsmasq_logs())
@app.get("/ddns", tags=["DDNS"])
async def get_ddns():
return{
'use': ddns.use(),
'method': ddns.method(),
'protocol': ddns.protocol(),
'server': ddns.server(),
'login': ddns.login(),
'password': ddns.password(),
'domain': ddns.domain()
}
@app.get("/firewall", tags=["Firewall"])
async def get_firewall():
return json.loads(firewall.firewall_rules())
@app.get("/networking", tags=["Networking"])
async def get_networking():
return{
'interfaces': json.loads(networking.interfaces()),
'throughput': json.loads(networking.throughput())
}
@app.get("/openvpn", tags=["OpenVPN"])
async def get_openvpn():
return{
'client_configs': openvpn.client_configs(),
'client_config_names': openvpn.client_config_names(),
'client_config_active': openvpn.client_config_active(),
'client_login_names': openvpn.client_login_names(),
'client_login_active': openvpn.client_login_active()
}
@app.get("/openvpn/{config}", tags=["OpenVPN"])
async def client_config_list(config):
return{
'client_config': openvpn.client_config_list(config)
}
@app.get("/wireguard", tags=["WireGuard"])
async def get_wireguard():
return{
'client_configs': wireguard.configs(),
'client_config_names': wireguard.client_config_names(),
'client_config_active': wireguard.client_config_active()
}
@app.get("/wireguard/{config}", tags=["WireGuard"])
async def client_config_list(config):
return{
'client_config': wireguard.client_config_list(config)
}
@app.post("/restart/webgui")
async def restart_webgui():
restart.webgui()
@app.post("/restart/adblock")
async def restart_adblock():
restart.adblock()

112
api/modules/ap.py Normal file
View file

@ -0,0 +1,112 @@
import subprocess
import json
def driver():
return subprocess.run("cat /etc/hostapd/hostapd.conf | grep driver= | cut -d'=' -f2", shell=True, capture_output=True, text=True).stdout.strip()
def set_driver(driver):
return subprocess.run(f"sudo sed -i 's/^driver=.*/driver={driver}/' /etc/hostapd/hostapd.conf", shell=True, capture_output=True, text=True).stdout.strip()
def ctrl_interface():
return subprocess.run("cat /etc/hostapd/hostapd.conf | grep ctrl_interface= | cut -d'=' -f2 | head -1", shell=True, capture_output=True, text=True).stdout.strip()
def set_ctrl_interface(ctrl_interface):
return subprocess.run(f"sudo sed -i 's/^ctrl_interface=.*/ctrl_interface={ctrl_interface}/' /etc/hostapd/hostapd.conf", shell=True, capture_output=True, text=True).stdout.strip()
def ctrl_interface_group():
return subprocess.run("cat /etc/hostapd/hostapd.conf | grep ctrl_interface_group= | cut -d'=' -f2", shell=True, capture_output=True, text=True).stdout.strip()
def set_ctrl_interface_group(ctrl_interface_group):
return subprocess.run(f"sudo sed -i 's/^ctrl_interface_group=.*/ctrl_interface_group={ctrl_interface_group}/' /etc/hostapd/hostapd.conf", shell=True, capture_output=True, text=True).stdout.strip()
def auth_algs():
return subprocess.run("cat /etc/hostapd/hostapd.conf | grep auth_algs= | cut -d'=' -f2", shell=True, capture_output=True, text=True).stdout.strip()
def set_auth_algs(auth_algs):
return subprocess.run(f"sudo sed -i 's/^auth_algs=.*/auth_algs={auth_algs}/' /etc/hostapd/hostapd.conf", shell=True, capture_output=True, text=True).stdout.strip()
def wpa_key_mgmt():
return subprocess.run("cat /etc/hostapd/hostapd.conf | grep wpa_key_mgmt= | cut -d'=' -f2", shell=True, capture_output=True, text=True).stdout.strip()
def set_wpa_key_mgmt(wpa_key_mgmt):
return subprocess.run(f"sudo sed -i 's/^wpa_key_mgmt=.*/wpa_key_mgmt={wpa_key_mgmt}/' /etc/hostapd/hostapd.conf", shell=True, capture_output=True, text=True).stdout.strip()
def beacon_int():
return subprocess.run("cat /etc/hostapd/hostapd.conf | grep beacon_int= | cut -d'=' -f2", shell=True, capture_output=True, text=True).stdout.strip()
def set_beacon_int(beacon_int):
return subprocess.run(f"sudo sed -i 's/^beacon_int=.*/beacon_int={beacon_int}/' /etc/hostapd/hostapd.conf", shell=True, capture_output=True, text=True).stdout.strip()
def ssid():
return subprocess.run("cat /etc/hostapd/hostapd.conf | grep ssid= | cut -d'=' -f2 | head -1", shell=True, capture_output=True, text=True).stdout.strip()
def set_ssid(ssid):
return subprocess.run(f"sudo sed -i 's/^ssid=.*/ssid={ssid}/' /etc/hostapd/hostapd.conf", shell=True, capture_output=True, text=True).stdout.strip()
def channel():
return subprocess.run("cat /etc/hostapd/hostapd.conf | grep channel= | cut -d'=' -f2", shell=True, capture_output=True, text=True).stdout.strip()
def set_channel(channel):
return subprocess.run(f"sudo sed -i 's/^channel=.*/channel={channel}/' /etc/hostapd/hostapd.conf", shell=True, capture_output=True, text=True).stdout.strip()
def hw_mode():
return subprocess.run("cat /etc/hostapd/hostapd.conf | grep hw_mode= | cut -d'=' -f2", shell=True, capture_output=True, text=True).stdout.strip()
def set_hw_mode(hw_mode):
return subprocess.run(f"sudo sed -i 's/^hw_mode=.*/hw_mode={hw_mode}/' /etc/hostapd/hostapd.conf", shell=True, capture_output=True, text=True).stdout.strip()
def ieee80211n():
return subprocess.run("cat /etc/hostapd/hostapd.conf | grep ieee80211n= | cut -d'=' -f2", shell=True, capture_output=True, text=True).stdout.strip()
def set_ieee80211n(ieee80211n):
return subprocess.run(f"sudo sed -i 's/^ieee80211n=.*/ieee80211n={ieee80211n}/' /etc/hostapd/hostapd.conf", shell=True, capture_output=True, text=True).stdout.strip()
def wpa_passphrase():
return subprocess.run("cat /etc/hostapd/hostapd.conf | grep wpa_passphrase= | cut -d'=' -f2", shell=True, capture_output=True, text=True).stdout.strip()
def set_wpa_passphrase(wpa_passphrase):
return subprocess.run(f"sudo sed -i 's/^wpa_passphrase=.*/wpa_passphrase={wpa_passphrase}/' /etc/hostapd/hostapd.conf", shell=True, capture_output=True, text=True).stdout.strip()
def interface():
return subprocess.run("cat /etc/hostapd/hostapd.conf | grep interface= | cut -d'=' -f2 | head -1", shell=True, capture_output=True, text=True).stdout.strip()
def set_interface(interface):
return subprocess.run(f"sudo sed -i 's/^interface=.*/interface={interface}/' /etc/hostapd/hostapd.conf", shell=True, capture_output=True, text=True).stdout.strip()
def wpa():
return subprocess.run("cat /etc/hostapd/hostapd.conf | grep wpa= | cut -d'=' -f2", shell=True, capture_output=True, text=True).stdout.strip()
def set_wpa(wpa):
return subprocess.run(f"sudo sed -i 's/^wpa=.*/wpa={wpa}/' /etc/hostapd/hostapd.conf", shell=True, capture_output=True, text=True).stdout.strip()
def wpa_pairwise():
return subprocess.run("cat /etc/hostapd/hostapd.conf | grep wpa_pairwise= | cut -d'=' -f2", shell=True, capture_output=True, text=True).stdout.strip()
def set_wpa_pairwise(wpa_pairwise):
return subprocess.run(f"sudo sed -i 's/^wpa_pairwise=.*/wpa_pairwise={wpa_pairwise}/' /etc/hostapd/hostapd.conf", shell=True, capture_output=True, text=True).stdout.strip()
def country_code():
return subprocess.run("cat /etc/hostapd/hostapd.conf | grep country_code= | cut -d'=' -f2", shell=True, capture_output=True, text=True).stdout.strip()
def set_country_code(country_code):
return subprocess.run(f"sudo sed -i 's/^country_code=.*/country_code={country_code}/' /etc/hostapd/hostapd.conf", shell=True, capture_output=True, text=True).stdout.strip()
def ignore_broadcast_ssid():
return subprocess.run("cat /etc/hostapd/hostapd.conf | grep ignore_broadcast_ssid= | cut -d'=' -f2", shell=True, capture_output=True, text=True).stdout.strip()
def set_ignore_broadcast_ssid(ignore_broadcast_ssid):
return subprocess.run(f"sudo sed -i 's/^ignore_broadcast_ssid=.*/ignore_broadcast_ssid={ignore_broadcast_ssid}/' /etc/hostapd/hostapd.conf", shell=True, capture_output=True, text=True).stdout.strip()
def logging():
log_output = subprocess.run(f"cat /tmp/hostapd.log", shell=True, capture_output=True, text=True).stdout.strip()
logs = {}
for line in log_output.split('\n'):
parts = line.split(': ')
if len(parts) >= 2:
interface, message = parts[0], parts[1]
if interface not in logs:
logs[interface] = []
logs[interface].append(message)
return json.dumps(logs, indent=2)

28
api/modules/client.py Normal file
View file

@ -0,0 +1,28 @@
import subprocess
import json
def get_active_clients_amount(interface):
output = subprocess.run(f'''cat '/var/lib/misc/dnsmasq.leases' | grep -iwE "$(arp -i '{interface}' | grep -oE "(([0-9]|[a-f]|[A-F]){{{2}}}:){{{5}}}([0-9]|[a-f]|[A-F]){{{2}}}")"''', shell=True, capture_output=True, text=True)
return(len(output.stdout.splitlines()))
def get_active_clients(interface):
#does not run like intended, but it works....
output = subprocess.run(f'''cat '/var/lib/misc/dnsmasq.leases' | grep -iwE "$(arp -i '{interface}' | grep -oE "(([0-9]|[a-f]|[A-F]){{{2}}}:){{{5}}}([0-9]|[a-f]|[A-F]){{{2}}}")"''', shell=True, capture_output=True, text=True)
clients_list = []
for line in output.stdout.splitlines():
fields = line.split()
client_data = {
"timestamp": int(fields[0]),
"mac_address": fields[1],
"ip_address": fields[2],
"hostname": fields[3],
"client_id": fields[4],
}
clients_list.append(client_data)
json_output = json.dumps(clients_list, indent=2)
return json_output

24
api/modules/ddns.py Normal file
View file

@ -0,0 +1,24 @@
import subprocess
def use():
return subprocess.run("cat /etc/ddclient.conf | grep use= | cut -d'=' -f2", shell=True, capture_output=True, text=True).stdout.strip()
def method():
#get the contents of the line below "use="
return subprocess.run("awk '/^use=/ {getline; print}' /etc/ddclient.conf | cut -d'=' -f2", shell=True, capture_output=True, text=True).stdout.strip()
def protocol():
return subprocess.run("cat /etc/ddclient.conf | grep protocol= | cut -d'=' -f2", shell=True, capture_output=True, text=True).stdout.strip()
def server():
return subprocess.run("cat /etc/ddclient.conf | grep server= | cut -d'=' -f2", shell=True, capture_output=True, text=True).stdout.strip()
def login():
return subprocess.run("cat /etc/ddclient.conf | grep login= | cut -d'=' -f2", shell=True, capture_output=True, text=True).stdout.strip()
def password():
return subprocess.run("cat /etc/ddclient.conf | grep password= | cut -d'=' -f2", shell=True, capture_output=True, text=True).stdout.strip()
def domain():
#get the contents of the line below "password="
return subprocess.run("awk '/^password=/ {getline; print}' /etc/ddclient.conf", shell=True, capture_output=True, text=True).stdout.strip()

30
api/modules/dhcp.py Normal file
View file

@ -0,0 +1,30 @@
import subprocess
import json
def range_start():
return subprocess.run("cat /etc/dnsmasq.d/090_wlan0.conf |grep dhcp-range= |cut -d'=' -f2| cut -d',' -f1", shell=True, capture_output=True, text=True).stdout.strip()
def range_end():
return subprocess.run("cat /etc/dnsmasq.d/090_wlan0.conf |grep dhcp-range= |cut -d'=' -f2| cut -d',' -f2", shell=True, capture_output=True, text=True).stdout.strip()
def range_subnet_mask():
return subprocess.run("cat /etc/dnsmasq.d/090_wlan0.conf |grep dhcp-range= |cut -d'=' -f2| cut -d',' -f3", shell=True, capture_output=True, text=True).stdout.strip()
def range_lease_time():
return subprocess.run("cat /etc/dnsmasq.d/090_wlan0.conf |grep dhcp-range= |cut -d'=' -f2| cut -d',' -f4", shell=True, capture_output=True, text=True).stdout.strip()
def range_gateway():
return subprocess.run("cat /etc/dhcpcd.conf | grep routers | cut -d'=' -f2", shell=True, capture_output=True, text=True).stdout.strip()
def range_nameservers():
output = subprocess.run("cat /etc/dhcpcd.conf", shell=True, capture_output=True, text=True).stdout.strip()
nameservers = []
lines = output.split('\n')
for line in lines:
if "static domain_name_server" in line:
servers = line.split('=')[1].strip().split()
nameservers.extend(servers)
return nameservers

38
api/modules/dns.py Normal file
View file

@ -0,0 +1,38 @@
import subprocess
import json
def adblockdomains():
output = subprocess.run("cat /etc/raspap/adblock/domains.txt", shell=True, capture_output=True, text=True).stdout.strip()
domains =output.split('\n')
domainlist=[]
for domain in domains:
if domain.startswith('#') or domain=="":
continue
domainlist.append(domain.split('=/')[1])
return domainlist
def adblockhostnames():
output = subprocess.run("cat /etc/raspap/adblock/hostnames.txt", shell=True, capture_output=True, text=True).stdout.strip()
hostnames = output.split('\n')
hostnamelist=[]
for hostname in hostnames:
if hostname.startswith('#') or hostname=="":
continue
hostnamelist.append(hostname.replace('0.0.0.0 ',''))
return hostnamelist
def upstream_nameserver():
return subprocess.run("awk '/nameserver/ {print $2}' /run/dnsmasq/resolv.conf", shell=True, capture_output=True, text=True).stdout.strip()
def dnsmasq_logs():
output = subprocess.run("cat /var/log/dnsmasq.log", shell=True, capture_output=True, text=True).stdout.strip()
log_entries = []
for line in output.split("\n"):
fields = line.split(" ")
log_dict = {
'timestamp': ' '.join(fields[:3]),
'process': fields[3][:-1], # Remove the trailing colon
'message': ' '.join(fields[4:]),
}
log_entries.append(log_dict)
return log_entries

4
api/modules/firewall.py Normal file
View file

@ -0,0 +1,4 @@
import subprocess
def firewall_rules():
return subprocess.run("cat /etc/raspap/networking/firewall/iptables_rules.json", shell=True, capture_output=True, text=True).stdout.strip()

68
api/modules/networking.py Normal file
View file

@ -0,0 +1,68 @@
import psutil
import json
def throughput():
interface_info = {}
# Get network interfaces
interfaces = psutil.net_if_stats()
for interface, stats in interfaces.items():
if interface.startswith("lo") or interface.startswith("docker"):
# Skip loopback and docker interface
continue
try:
# Get network traffic statistics
traffic_stats = psutil.net_io_counters(pernic=True)[interface]
rx_packets = traffic_stats[1]
rx_bytes = traffic_stats[0]
tx_packets = traffic_stats[3]
tx_bytes = traffic_stats[4]
interface_info[interface] = {
"RX_packets": rx_packets,
"RX_bytes": rx_bytes,
"TX_packets": tx_packets,
"TX_bytes": tx_bytes
}
except KeyError:
# Handle the case where network interface statistics are not available
pass
return json.dumps(interface_info, indent=2)
def interfaces():
interface_info = {}
# Get network interfaces
interfaces = psutil.net_if_addrs()
for interface, addrs in interfaces.items():
if interface.startswith("lo") or interface.startswith("docker"):
# Skip loopback and docker interface
continue
ip_address = None
netmask = None
mac_address = None
for addr in addrs:
if addr.family == 2: # AF_INET corresponds to the integer value 2
# IPv4 address
ip_address = addr.address
netmask = addr.netmask
# Get MAC address
for addr in psutil.net_if_addrs().get(interface, []):
if addr.family == psutil.AF_LINK:
mac_address = addr.address
interface_info[interface] = {
"IP_address": ip_address,
"Netmask": netmask,
"MAC_address": mac_address
}
return json.dumps(interface_info, indent=2)
#TODO: migrate to vnstat, to lose psutil dependency

41
api/modules/openvpn.py Normal file
View file

@ -0,0 +1,41 @@
import subprocess
def client_configs():
return subprocess.run("find /etc/openvpn/client/ -type f | wc -l", shell=True, capture_output=True, text=True).stdout.strip()
def client_config_names():
config_names_list = []
output = subprocess.run('''ls /etc/openvpn/client/ | grep -v "^client.conf$"''', shell=True, capture_output=True, text=True).stdout.strip()
lines = output.split("\n")
for client in lines:
if "_client" in client:
config_names_dict ={'config':client}
config_names_list.append(config_names_dict)
return config_names_list
def client_login_names():
config_names_list = []
output = subprocess.run('''ls /etc/openvpn/client/ | grep -v "^client.conf$"''', shell=True, capture_output=True, text=True).stdout.strip()
lines = output.split("\n")
for client in lines:
if "_login" in client:
config_names_dict ={'login':client}
config_names_list.append(config_names_dict)
return config_names_list
def client_config_active():
output = subprocess.run('''ls -al /etc/openvpn/client/ | grep "client.conf -"''', shell=True, capture_output=True, text=True).stdout.strip()
active_config = output.split("/etc/openvpn/client/")
return(active_config[1])
def client_login_active():
output = subprocess.run('''ls -al /etc/openvpn/client/ | grep "login.conf -"''', shell=True, capture_output=True, text=True).stdout.strip()
active_config = output.split("/etc/openvpn/client/")
return(active_config[1])
def client_config_list(client_config):
output = subprocess.run(f"cat /etc/openvpn/client/{client_config}", shell=True, capture_output=True, text=True).stdout.strip()
return output.split('\n')
#TODO: where is the logfile??
#TODO: is service connected?

7
api/modules/restart.py Normal file
View file

@ -0,0 +1,7 @@
import subprocess
def webgui():
return subprocess.run("sudo /etc/raspap/lighttpd/configport.sh --restart", shell=True, capture_output=True, text=True).stdout.strip()
def adblock():
return subprocess.run("sudo /bin/systemctl restart dnsmasq.service", shell=True, capture_output=True, text=True).stdout.strip()

86
api/modules/system.py Normal file
View file

@ -0,0 +1,86 @@
import subprocess
revisions = {
'0002': 'Model B Revision 1.0',
'0003': 'Model B Revision 1.0 + ECN0001',
'0004': 'Model B Revision 2.0 (256 MB)',
'0005': 'Model B Revision 2.0 (256 MB)',
'0006': 'Model B Revision 2.0 (256 MB)',
'0007': 'Model A',
'0008': 'Model A',
'0009': 'Model A',
'000d': 'Model B Revision 2.0 (512 MB)',
'000e': 'Model B Revision 2.0 (512 MB)',
'000f': 'Model B Revision 2.0 (512 MB)',
'0010': 'Model B+',
'0013': 'Model B+',
'0011': 'Compute Module',
'0012': 'Model A+',
'a01041': 'a01041',
'a21041': 'a21041',
'900092': 'PiZero 1.2',
'900093': 'PiZero 1.3',
'9000c1': 'PiZero W',
'a02082': 'Pi 3 Model B',
'a22082': 'Pi 3 Model B',
'a32082': 'Pi 3 Model B',
'a52082': 'Pi 3 Model B',
'a020d3': 'Pi 3 Model B+',
'a220a0': 'Compute Module 3',
'a020a0': 'Compute Module 3',
'a02100': 'Compute Module 3+',
'a03111': 'Model 4B Revision 1.1 (1 GB)',
'b03111': 'Model 4B Revision 1.1 (2 GB)',
'c03111': 'Model 4B Revision 1.1 (4 GB)',
'c03111': 'Model 4B Revision 1.1 (4 GB)',
'a03140': 'Compute Module 4 (1 GB)',
'b03140': 'Compute Module 4 (2 GB)',
'c03140': 'Compute Module 4 (4 GB)',
'd03140': 'Compute Module 4 (8 GB)',
'c04170': 'Pi 5 (4 GB)',
'd04170': 'Pi 5 (8 GB)'
}
def hostname():
return subprocess.run("hostname", shell=True, capture_output=True, text=True).stdout.strip()
def uptime():
return subprocess.run("uptime -p", shell=True, capture_output=True, text=True).stdout.strip()
def systime():
return subprocess.run("date", shell=True, capture_output=True, text=True).stdout.strip()
def usedMemory():
return round(float(subprocess.run("free -m | awk 'NR==2{total=$2 ; used=$3 } END { print used/total*100}'", shell=True, capture_output=True, text=True).stdout.strip()),2)
def processorCount():
return int(subprocess.run("nproc --all", shell=True, capture_output=True, text=True).stdout.strip())
def LoadAvg1Min():
return round(float(subprocess.run("awk '{print $1}' /proc/loadavg", shell=True, capture_output=True, text=True).stdout.strip()),2)
def systemLoadPercentage():
return round((float(LoadAvg1Min())*100)/float(processorCount()),2)
def systemTemperature():
try:
output = subprocess.run("cat /sys/class/thermal/thermal_zone0/temp", shell=True, capture_output=True, text=True).stdout.strip()
return round(float(output)/1000,2)
except ValueError:
return 0
def hostapdStatus():
return int(subprocess.run("pidof hostapd | wc -l", shell=True, capture_output=True, text=True).stdout.strip())
def operatingSystem():
return subprocess.run('''grep PRETTY_NAME /etc/os-release | cut -d= -f2- | sed 's/"//g' ''', shell=True, capture_output=True, text=True).stdout.strip()
def kernelVersion():
return subprocess.run("uname -r", shell=True, capture_output=True, text=True).stdout.strip()
def rpiRevision():
output = subprocess.run("grep Revision /proc/cpuinfo | awk '{print $3}'", shell=True, capture_output=True, text=True).stdout.strip()
try:
return revisions[output]
except KeyError:
return 'Unknown Device'

26
api/modules/wireguard.py Normal file
View file

@ -0,0 +1,26 @@
import subprocess
def configs():
#ignore symlinks, because wg0.conf is in production the main config, but in insiders it is a symlink
return subprocess.run("find /etc/wireguard/ -type f | wc -l", shell=True, capture_output=True, text=True).stdout.strip()
def client_config_names():
config_names_list = []
output = subprocess.run('''ls /etc/wireguard/ | grep -v "^wg0.conf$"''', shell=True, capture_output=True, text=True).stdout.strip()
lines = output.split("\n")
for client in lines:
config_names_dict ={'config':client}
config_names_list.append(config_names_dict)
return config_names_list
def client_config_active():
output = subprocess.run('''ls -al /etc/wireguard/ | grep "wg0.conf -"''', shell=True, capture_output=True, text=True).stdout.strip()
active_config = output.split("/etc/wireguard/")
return(active_config[1])
def client_config_list(client_config):
output = subprocess.run(f"cat /etc/wireguard/{client_config}", shell=True, capture_output=True, text=True).stdout.strip()
return output.split('\n')
#TODO: where is the logfile??
#TODO: is service connected?

3
api/requirements.txt Normal file
View file

@ -0,0 +1,3 @@
fastapi==0.109.0
uvicorn==0.25.0
psutil==5.9.8

View file

@ -57,6 +57,7 @@ function _install_raspap() {
_configure_networking
_prompt_install_adblock
_prompt_install_openvpn
_prompt_isntall_restapi
_install_extra_features
_prompt_install_wireguard
_prompt_install_vpn_providers
@ -502,6 +503,23 @@ function _prompt_install_openvpn() {
fi
}
# Prompt to install restapi
function _prompt_install_restapi() {
_install_log "Configure restapi"
echo -n "Install and enable RestAPI? [Y/n]: "
if [ "$assume_yes" == 0 ]; then
read answer < /dev/tty
if [ "$answer" != "${answer#[Nn]}" ]; then
_install_status 0 "(Skipped)"
else
_install_restapi
elif [ "$restapi_option" == 1 ]; then
_install_restapi
else
echo "(Skipped)"
fi
}
# Prompt to install WireGuard
function _prompt_install_wireguard() {
_install_log "Configure WireGuard support"
@ -562,6 +580,20 @@ function _create_openvpn_scripts() {
_install_status 0
}
# Install and enable RestAPI configuration option
function _install_restapi() {
_install_log "Installing and enabling RestAPI"
sudo cp -r "$webroot_dir/api" "$raspap_dir/api" || _install_status 1 "Unable to move api folder"
python -m pip install -r "$raspap_dir/api/requirements.txt" || _install_status 1 " Unable to install pip modules"
echo "Moving restapi systemd unit control file to /lib/systemd/system/"
sudo mv $webroot_dir/installers/restapi.service /lib/systemd/system/ || _install_status 1 "Unable to move restapi.service file"
sudo systemctl daemon-reload
sudo systemctl enable restapi.service || _install_status 1 "Failed to enable restapi.service"
_install_status 0
}
# Fetches latest files from github to webroot
function _download_latest_files() {
_install_log "Cloning latest files from GitHub"

View file

@ -94,6 +94,7 @@ function _parse_params() {
upgrade=0
update=0
ovpn_option=1
restapi_option=0
adblock_option=1
wg_option=1
insiders=0
@ -111,6 +112,10 @@ function _parse_params() {
ovpn_option="$2"
shift
;;
--api|--rest|--restapi)
restapi_option="$2"
shift
;;
-a|--adblock)
adblock_option="$2"
shift

View file

@ -0,0 +1,14 @@
[Unit]
Description=raspap-restapi
After=network.target
[Service]
User=root
WorkingDirectory=/etc/raspap/api
LimitNOFILE=4096
ExecStart=/usr/bin/python uvicorn main:app --host 0.0.0.0 --port 8081
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target