Skip to content

Commit

Permalink
Merge pull request #1519 from NL-TCH/REST-API
Browse files Browse the repository at this point in the history
RestAPI installer integrated
  • Loading branch information
billz authored Mar 9, 2024
2 parents 95f74c5 + d1be0ca commit 2de012c
Show file tree
Hide file tree
Showing 32 changed files with 1,003 additions and 3 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ yarn-error.log
includes/config.php
rootCA.pem
vendor
.env
24 changes: 24 additions & 0 deletions api/auth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import os
from fastapi.security.api_key import APIKeyHeader
from fastapi import Security, HTTPException
from starlette.status import HTTP_403_FORBIDDEN
from dotenv import load_dotenv

load_dotenv()

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"
)

156 changes: 156 additions & 0 deletions api/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
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


tags_metadata = [
]
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(api_key: APIKey = Depends(auth.get_api_key)):
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/hotspot"])
async def get_ap(api_key: APIKey = Depends(auth.get_api_key)):
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.get("/clients/{wireless_interface}", tags=["Clients"])
async def get_clients(wireless_interface, api_key: APIKey = Depends(auth.get_api_key)):
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(api_key: APIKey = Depends(auth.get_api_key)):
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(api_key: APIKey = Depends(auth.get_api_key)):
return{
'domains': json.loads(dns.adblockdomains())
}

@app.get("/dns/hostnames", tags=["DNS"])
async def get_hostnames(api_key: APIKey = Depends(auth.get_api_key)):
return{
'hostnames': json.loads(dns.adblockhostnames())
}

@app.get("/dns/upstream", tags=["DNS"])
async def get_upstream(api_key: APIKey = Depends(auth.get_api_key)):
return{
'upstream_nameserver': dns.upstream_nameserver()
}

@app.get("/dns/logs", tags=["DNS"])
async def get_dnsmasq_logs(api_key: APIKey = Depends(auth.get_api_key)):
return(dns.dnsmasq_logs())


@app.get("/ddns", tags=["DDNS"])
async def get_ddns(api_key: APIKey = Depends(auth.get_api_key)):
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(api_key: APIKey = Depends(auth.get_api_key)):
return json.loads(firewall.firewall_rules())

@app.get("/networking", tags=["Networking"])
async def get_networking(api_key: APIKey = Depends(auth.get_api_key)):
return{
'interfaces': json.loads(networking.interfaces()),
'throughput': json.loads(networking.throughput())
}

@app.get("/openvpn", tags=["OpenVPN"])
async def get_openvpn(api_key: APIKey = Depends(auth.get_api_key)):
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, api_key: APIKey = Depends(auth.get_api_key)):
return{
'client_config': openvpn.client_config_list(config)
}

@app.get("/wireguard", tags=["WireGuard"])
async def get_wireguard(api_key: APIKey = Depends(auth.get_api_key)):
return{
'client_configs': wireguard.configs(),
'client_config_names': wireguard.client_config_names(),
'client_config_active': wireguard.client_config_active()
}

64 changes: 64 additions & 0 deletions api/modules/ap.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
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 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 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 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 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 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 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 channel():
return subprocess.run("cat /etc/hostapd/hostapd.conf | grep channel= | cut -d'=' -f2", 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 ieee80211n():
return subprocess.run("cat /etc/hostapd/hostapd.conf | grep ieee80211n= | cut -d'=' -f2", 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 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 wpa():
return subprocess.run("cat /etc/hostapd/hostapd.conf | grep wpa= | cut -d'=' -f2", 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 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 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 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)
38 changes: 38 additions & 0 deletions api/modules/client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import subprocess
import json

def get_active_clients_amount(interface):
arp_output = subprocess.run(['arp', '-i', interface], capture_output=True, text=True)
mac_addresses = arp_output.stdout.splitlines()

if mac_addresses:
grep_pattern = '|'.join(mac_addresses)
output = subprocess.run(['grep', '-iwE', grep_pattern, '/var/lib/misc/dnsmasq.leases'], capture_output=True, text=True)
return len(output.stdout.splitlines())
else:
return 0

def get_active_clients(interface):
arp_output = subprocess.run(['arp', '-i', interface], capture_output=True, text=True)
arp_mac_addresses = set(line.split()[2] for line in arp_output.stdout.splitlines()[1:])

dnsmasq_output = subprocess.run(['cat', '/var/lib/misc/dnsmasq.leases'], capture_output=True, text=True)
active_clients = []

for line in dnsmasq_output.stdout.splitlines():
fields = line.split()
mac_address = fields[1]

if mac_address in arp_mac_addresses:
client_data = {
"timestamp": int(fields[0]),
"mac_address": fields[1],
"ip_address": fields[2],
"hostname": fields[3],
"client_id": fields[4],
}
active_clients.append(client_data)

json_output = json.dumps(active_clients, indent=2)
return json_output

24 changes: 24 additions & 0 deletions api/modules/ddns.py
Original file line number Diff line number Diff line change
@@ -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 changes: 30 additions & 0 deletions api/modules/dhcp.py
Original file line number Diff line number Diff line change
@@ -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 changes: 38 additions & 0 deletions api/modules/dns.py
Original file line number Diff line number Diff line change
@@ -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 changes: 4 additions & 0 deletions api/modules/firewall.py
Original file line number Diff line number Diff line change
@@ -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()
Loading

0 comments on commit 2de012c

Please sign in to comment.