diff --git a/apps/be9700-api/build/README.md b/apps/be9700-api/build/README.md new file mode 100644 index 0000000..a5bab50 --- /dev/null +++ b/apps/be9700-api/build/README.md @@ -0,0 +1,34 @@ +# be9700-api — Build Notes + +## Image + +`git.alexzaw.dev/alexz/be9700-api:` + +## Source + +`/home/alexz/be9700-api` (also mirrored to `https://git.alexzaw.dev/alexz/be9700-api`) + +The Dockerfile lives in the root of the source directory alongside `server.js`. + +## Architecture + +- **amd64 only** — the app is pure Node.js (no native addons) but the image is + only built and tested on the amd64 host. Add `--platform linux/arm64` to the + build command and push a separate tag to add arm64 support. + +## Security + +`.dockerignore` excludes `.env`, `.env.*`, `.git`, `scripts/`, `*.log`, `*.curl`, +`network-captures.js`. The image contains no router credentials. + +## Build + +```bash +# From this directory: +bash build.sh + +# Or with overrides: +IMAGE_TAG=1.0.1 bash build.sh --no-cache +``` + +Requires the Docker daemon to be authenticated to `git.alexzaw.dev`. diff --git a/apps/be9700-api/build/build.sh b/apps/be9700-api/build/build.sh new file mode 100644 index 0000000..42b14ba --- /dev/null +++ b/apps/be9700-api/build/build.sh @@ -0,0 +1,26 @@ +#!/bin/bash +# Build and push the be9700-api Docker image from the source in /home/alexz/be9700-api. +# The Dockerfile lives alongside the source (not in this build/ dir). + +set -euo pipefail + +IMAGE_NAME="${IMAGE_NAME:-git.alexzaw.dev/alexz/be9700-api}" +IMAGE_TAG="${IMAGE_TAG:-1.0.0}" +SOURCE_DIR="${SOURCE_DIR:-/home/alexz/be9700-api}" + +echo "==> Building ${IMAGE_NAME}:${IMAGE_TAG}" +docker build "$@" \ + -t "${IMAGE_NAME}:${IMAGE_TAG}" \ + -t "${IMAGE_NAME}:latest" \ + "${SOURCE_DIR}" + +echo "==> Pushing ${IMAGE_NAME}:${IMAGE_TAG}" +docker push "${IMAGE_NAME}:${IMAGE_TAG}" +echo "==> Pushing ${IMAGE_NAME}:latest" +docker push "${IMAGE_NAME}:latest" + +echo "" +echo "Done. To update on Runtipi:" +echo " cd /etc/runtipi/repos/runtipi && sudo git add . && sudo git commit -m 'be9700-api: bump' && sudo git push origin main" +echo " sudo /etc/runtipi/runtipi-cli appstore update" +echo " sudo /etc/runtipi/runtipi-cli app update be9700-api:runtipi" diff --git a/apps/be9700-api/config.json b/apps/be9700-api/config.json new file mode 100644 index 0000000..8c4d858 --- /dev/null +++ b/apps/be9700-api/config.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://schemas.runtipi.io/app-info.json", + "name": "BE9700 Router API", + "id": "be9700-api", + "available": true, + "short_desc": "Stateless proxy + Scalar API docs for the TP-Link BE9700 WiFi 7 router", + "author": "alexz", + "port": 8347, + "categories": ["network", "utilities"], + "description": "A stateless Node.js proxy server that exposes the TP-Link BE9700 WiFi 7 router's internal API as a clean REST surface with interactive Scalar docs at /docs. Credentials are never stored — callers pass X-Router-Host and X-Router-Password (or X-Router-Session) per request. Covers 203 endpoints: wireless bands (2.4 GHz / 5 GHz / 6 GHz), LAN/DHCP, NAT, UPnP, time, and diagnostics.", + "tipi_version": 1, + "version": "1.0.0", + "source": "https://git.alexzaw.dev/alexz/be9700-api", + "website": "https://git.alexzaw.dev/alexz/be9700-api", + "exposable": true, + "dynamic_config": true, + "no_gui": false, + "form_fields": [], + "supported_architectures": ["amd64"], + "min_tipi_version": "4.0.0" +} diff --git a/apps/be9700-api/docker-compose.json b/apps/be9700-api/docker-compose.json new file mode 100644 index 0000000..7c48f2e --- /dev/null +++ b/apps/be9700-api/docker-compose.json @@ -0,0 +1,24 @@ +{ + "$schema": "https://schemas.runtipi.io/dynamic-compose.json", + "schemaVersion": 2, + "services": [ + { + "name": "be9700-api", + "image": "git.alexzaw.dev/alexz/be9700-api:1.0.0", + "isMain": true, + "internalPort": 3000, + "environment": [ + { "key": "PORT", "value": "3000" }, + { "key": "TZ", "value": "${TZ}" }, + { "key": "NODE_ENV", "value": "production" } + ], + "healthCheck": { + "test": "wget -qO- http://127.0.0.1:3000/ >/dev/null 2>&1 || exit 1", + "interval": "30s", + "timeout": "5s", + "retries": 3, + "startPeriod": "15s" + } + } + ] +} diff --git a/apps/be9700-api/metadata/description.md b/apps/be9700-api/metadata/description.md new file mode 100644 index 0000000..b5eb036 --- /dev/null +++ b/apps/be9700-api/metadata/description.md @@ -0,0 +1,40 @@ +# BE9700 Router API + +A stateless Node.js proxy and interactive API documentation server for the +**TP-Link BE9700 WiFi 7** router. + +## What it does + +- Exposes the router's internal API as a clean, resource-oriented REST surface + (`/api/*`) covering **203 endpoints** across wireless bands (2.4 GHz / 5 GHz / + 6 GHz), LAN/DHCP, NAT, UPnP, system time, and diagnostics. +- Serves **interactive Scalar API docs** at `/docs` — explore and try every + endpoint directly in the browser. +- Returns the OpenAPI 3.1 specification at `/openapi.json` for use with any + compatible tooling. +- Health/status JSON at `/`. + +## Stateless header-auth model + +No router credentials are stored in the container or in Runtipi form fields. +Every request to `/api/*` must carry: + +| Header | Purpose | +|--------|---------| +| `X-Router-Host` | Router IP or hostname (e.g. `192.168.0.1`) | +| `X-Router-Password` | Router admin password (for fresh sessions) | +| `X-Router-Session` | Reuse a session token returned by a previous call (JSON) | + +This means the container itself holds no secrets and is safe to expose via +Traefik without any additional auth middleware — just use the API from clients +that supply the headers. + +## Quick start + +Once installed, open the **Scalar docs** at `http://:8347/docs` +and authenticate each request with the `X-Router-Host` and +`X-Router-Password` headers. + +## Source + +`https://git.alexzaw.dev/alexz/be9700-api` diff --git a/apps/be9700-api/metadata/logo.jpg b/apps/be9700-api/metadata/logo.jpg new file mode 100644 index 0000000..11647cc Binary files /dev/null and b/apps/be9700-api/metadata/logo.jpg differ