feat: add Docker deployment, update install script, and project configs

- Add Dockerfile and docker-compose.yml for containerized deployment
- Rewrite install.sh for Docker-based setup (multi-distro support)
- Add Go module files (go.mod, go.sum) for WGRplane backend
- Add wgrplane.service systemd unit for Go backend
- Add CI verification scripts in scripts/
- Update README.md with Docker deployment docs
- Update .gitignore for binaries and .sisyphus/
This commit is contained in:
datadunia
2026-05-03 23:37:36 +07:00
parent 6d8899a078
commit 6e94e7338e
10 changed files with 852 additions and 1401 deletions
+2
View File
@@ -1 +1,3 @@
.test/
wgrplane
.sisyphus/
+29
View File
@@ -0,0 +1,29 @@
## Multi-stage Dockerfile for WGRplane
## Stage 1: Go backend build
FROM --platform=$BUILDPLATFORM golang:1.21-alpine AS builder-go
WORKDIR /src
COPY go.mod go.sum ./
RUN --mount=type=cache,target=/root/.cache/go-build \
go mod download
COPY app ./app
ENV CGO_ENABLED=0
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
go build -o /bin/wgrplane ./app
## Stage 2: Frontend build (Vue 3)
FROM node:20-alpine AS frontend-builder
WORKDIR /src/app/frontend
COPY app/frontend/package*.json ./
RUN npm ci
COPY app/frontend/ .
RUN npm run build
## Stage 3: Production image
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root
COPY --from=builder-go /bin/wgrplane /usr/local/bin/wgrplane
COPY --from=frontend-builder /src/app/frontend/dist /var/www/frontend
ENV APP_FRONTEND_DIR=/var/www/frontend
EXPOSE 10087
ENTRYPOINT ["/usr/local/bin/wgrplane"]
+400 -98
View File
@@ -1,68 +1,337 @@
# WireGuard Dynamic Policy Firewall
# WGRplane
A lightweight, robust, and highly dynamic iptables/ipset policy firewall engine designed to restrict and control WireGuard peer traffic (egress traffic mapping) straight from `wg0.conf`.
**WireGuard Control Plane with Dynamic Policy Firewall.**
Rather than allowing all VPN clients to reach any part of your internal network, this tool isolates clients from each other by default and reads a custom `#Access` comment inside `wg0.conf` to automatically generate strict `iptables` rules and `ipset` whitelists per-client on the fly.
WGRplane is a Go-native WireGuard management dashboard paired with a shell-based dynamic iptables/ipset policy engine. It gives you full peer lifecycle management, per-peer firewall policies, webhook integrations, and a glassmorphism-styled Vue 3 frontend.
---
## 🎯 Architecture & Data Flow
## Overview
1. **`wg0.conf`**: The standard WireGuard configuration. Contains standard `[Peer]` configs alongside a custom `#Access` tag.
2. **`wg-sync-policy.sh`**: Safely parses `wg0.conf` and generates a structured `/etc/wireguard/policy.json` atomically.
3. **`wg-policy-engine.sh`**: Reads `policy.json` to generate robust rules, applying `iptables` and `ipset` directly to the system.
4. **Watcher Daemon**: Monitors `wg0.conf` for changes via `inotifywait` and triggers the pipeline seamlessly when updates are made.
WGRplane operates in two complementary layers:
| Layer | What it does |
|-------|-------------|
| **WGRplane (Go + Vue 3)** | Web dashboard and REST API for managing WireGuard servers, peers, webhooks, SMTP, and scheduling. |
| **Policy Firewall (Shell)** | Dynamic iptables/ipset engine that reads `#Access` comments from `wg0.conf` to enforce per-peer egress rules. |
### Hybrid Mode
The Go backend supports two server modes:
- **`forward`** -- The WGRplane instance directly applies nftables rules on the local machine. Peer access policies are enforced immediately via `nft` commands.
- **`standalone`** -- The instance acts as a control plane that triggers webhooks to remote WireGuard servers. Policy enforcement happens on the remote side.
### 2-Column Policy
Each peer has two independent policy columns:
| Column | Purpose |
|--------|---------|
| **AllowAccess** | List of CIDRs the peer can reach (internal targets). |
| **AllowInternet** | Boolean flag. When `true`, the peer gets unrestricted internet egress. |
Peers with neither rule are isolated from each other and from the internet by default.
---
## 📁 Installation
## Architecture
The easiest way to install is using the provided `install.sh` script, which automatically installs dependencies, copies all scripts to `/usr/local/bin/`, sets up the systemd daemon, and enables the service.
```mermaid
graph TB
subgraph "WGRplane Dashboard"
A[Vue 3 Frontend] -->|HTTP/WebSocket| B[Go REST API :10087]
end
subgraph "Go Backend"
B --> C[(SQLite DB)]
B --> D[Webhook Engine]
B --> E[Scheduler Cron]
B --> F[nftables Engine]
B --> G[SMTP / Email]
B --> H[Plugin Manager]
end
subgraph "Policy Firewall"
I[wg0.conf #Access] -->|inotifywait| J[wg-sync-watch.sh]
J --> K[wg-sync-policy.sh]
K -->|atomic write| L[policy.json]
L --> M[wg-policy-engine.sh]
M --> N[iptables / ipset]
end
D -.->|peer_created/updated/deleted| O[External Webhooks]
F -.->|forward mode| N
E -.->|daily/monthly| P[Peer Lifecycle]
```
### Data Flow
```
wg0.conf (#Access comments)
↓ inotifywait detects change
wg-sync-watch.sh (debounced trigger)
wg-sync-policy.sh (parses wg0.conf → policy.json, atomic write)
wg-policy-engine.sh (reads policy.json → iptables/ipset rules)
Active firewall rules (WG_POLICY chain)
```
### Tech Stack
| Component | Technology |
|-----------|------------|
| **Backend** | Go 1.25, Gorilla Mux, GORM (SQLite) |
| **Frontend** | Vue 3, TypeScript, Vite, TailwindCSS 4, vue-i18n 9 |
| **Auth** | JWT (golang-jwt), TOTP (pquerna/otp), API Key |
| **Webhooks** | Go net/http with retry + exponential backoff |
| **Scheduling** | robfig/cron v3 |
| **Firewall** | Bash, iptables, ipset, nftables, inotify-tools, jq |
| **Container** | Docker (multi-stage build), docker-compose |
---
## Quick Start
### Option 1: Docker Compose (Recommended)
```bash
# Install everything
# Clone the repository
git clone https://git.datadunia.com/hainzero/WGRplane.git
cd 03.wireguard-policy
# Start both WGRplane and WireGuard
docker compose up -d
# Access the dashboard
# http://localhost:10087
```
The compose stack runs:
- **WGRplane** on port `10087` (Go API + Vue frontend)
- **WireGuard** container with host networking for kernel module access
### Option 2: Install Script
```bash
# Run the automated installer (Ubuntu/Debian/CentOS)
sudo ./install.sh install
# Uninstall everything
# Uninstall
sudo ./install.sh uninstall
```
### Building the Installer (For Developers)
The install script handles Docker installation, repository cloning, `.env` creation, and service startup.
If you modify any of the source `.sh` or `.service` files, you must rebuild the `install.sh` script using the provided builders.
### Option 3: Manual Build
**On Linux (Bash):**
```bash
./build.sh
# Build the Go binary
cd app
go build -o ../wgrplane .
cd ..
# Build the frontend
cd app/frontend
npm install && npm run build
cd ../..
# Run
./wgrplane
# Server starts on :10087
```
**On Windows (CMD/PowerShell):**
```cmd
build.bat
### Option 4: Systemd Service
```bash
# Install the service file
sudo cp wgrplane.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable wgrplane.service
sudo systemctl start wgrplane.service
# View logs
journalctl -u wgrplane.service -f
```
---
## 📦 Prerequisites
## API Documentation
| Package | Required | Install |
|---------|----------|---------|
| `jq` | **Yes** | `apt install jq` |
| `inotify-tools` | **Yes** (for watcher daemon) | `apt install inotify-tools` |
| `ipset` | Optional | `apt install ipset` |
All API endpoints are served on port `10087`. Authentication is via API key header (`wg-rplane-datadunia`) or JWT Bearer token with optional TOTP.
If `ipset` is not installed, the engine will automatically fall back to per-rule `iptables` whitelist entries. This works fine for small deployments. For large numbers of clients/targets, `ipset` is recommended for O(1) lookup performance.
### Authentication
| Method | Header | Notes |
|--------|--------|-------|
| API Key | `wg-rplane-datadunia: <KEY>` | Set via `WG_API_KEY` env var. Default: `test-api-key`. |
| JWT | `Authorization: Bearer <TOKEN>` | 15-minute expiry. Set secret via `JWT_SECRET` env var. |
| TOTP | `X-TOTP: <CODE>` | Required if user has TOTP enabled. |
### Servers
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/api/servers` | `GET` | List all registered WireGuard servers. |
| `/api/servers` | `POST` | Create a new server entry. Body: `{name, mode, publicKey, endpoint}`. |
| `/api/servers/{id}` | `GET` | Get a single server by ID. |
| `/api/servers/{id}` | `PUT` | Update server fields (name, mode, publicKey, endpoint). |
| `/api/servers/{id}` | `DELETE` | Delete a server and cascade-remove its peers and webhooks. |
### Peers
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/api/servers/{id}/peers` | `GET` | List all peers for a server. |
| `/api/servers/{id}/peers` | `POST` | Create a new peer. Body: `{publicKey, ip, allowAccess, allowInternet}`. Applies nftables rules in `forward` mode or triggers webhooks in `standalone` mode. |
| `/api/peers/{id}` | `PUT` | Update a peer. Computes diffs and applies incremental nftables changes. |
| `/api/peers/{id}` | `DELETE` | Delete a peer. Cleans up nftables rules and triggers webhooks. |
| `/api/peers/{id}/config` | `GET` | Download the peer's WireGuard `.conf` file. |
| `/api/peers/{id}/qrcode` | `GET` | Get a QR code PNG image of the peer config (for mobile import). |
### Webhooks
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/api/servers/{id}/webhooks` | `GET` | List webhooks for a server. |
| `/api/servers/{id}/webhooks` | `POST` | Create a webhook. Body: `{name, url, template, customBody, customHeaders, subscribedActions, isEnabled, verifySSL}`. |
| `/api/webhooks/{id}` | `DELETE` | Delete a webhook. |
### SMTP Settings
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/api/settings/smtp` | `GET` | Get current SMTP configuration. |
| `/api/settings/smtp` | `POST` | Save SMTP settings for email notifications. |
### Statistics
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/api/stats` | `GET` | Global stats: total servers, peers, webhooks. |
| `/api/servers/{id}/stats` | `GET` | Per-server stats: peer count, webhook count, server details. |
### WebSocket
| Endpoint | Protocol | Description |
|----------|----------|-------------|
| `/ws/stats` | WebSocket | Real-time stats broadcast (5-second interval). Connects to the Hub for live peer/traffic updates. |
---
## ⚙️ Integrasi ke `wg0.conf`
## Webhook Payload Spec
To integrate the engine, you need to append hooks into your `wg0.conf` interface block, and declare the `#Access` tags under each peer.
Webhooks are triggered on peer lifecycle events (`peer_created`, `peer_updated`, `peer_deleted`, `policy_changed`). The engine supports three template modes: `default` (raw JSON), `mikrotik` (RouterOS-formatted), and `custom` (Go template).
### 1. Interface Block (Hooks)
Add the `PostUp` and `PostDown` scripts so the engine initializes correctly during VPN startup and removes traces upon shutdown.
### Default Payload
> **⚠️ WireGuard does NOT support multiline values.** Every command must be on a `PostUp = ...` or `PostDown = ...` line. Bare commands without the `PostUp =` prefix will cause `Configuration parsing error`.
```json
{
"event": "peer_created",
"timestamp": "2026-05-03T10:30:00Z",
"server": {
"id": 1,
"name": "wg-server-01",
"mode": "forward",
"publicKey": "abc123...",
"endpoint": "vpn.example.com:51820"
},
"peer": {
"id": 2,
"publicKey": "xyz789...",
"ip": "10.0.0.2",
"allowAccess": ["192.168.1.0/24", "10.10.0.0/16"],
"allowInternet": true,
"enabled": true,
"dataLimitGB": 0,
"expiresAt": "0001-01-01T00:00:00Z"
},
"policy": {
"action": "created",
"changes": ["peer_created"]
}
}
```
### Mikrotik Template
```json
{
"action": "created",
"peer": {
"public_key": "xyz789...",
"ip": "10.0.0.2",
"allow_access": "[\"192.168.1.0/24\"]",
"allow_internet": true
},
"server": {
"name": "wg-server-01",
"mode": "forward"
}
}
```
### Webhook Features
- **Retry with backoff**: Failed deliveries retry up to 3 times with exponential backoff (2s, 4s, 8s).
- **SSL verification**: Toggleable per-webhook via `verifySSL`.
- **Custom headers**: Per-webhook header injection via `customHeaders` JSON.
- **Global webhooks**: Set `isGlobal: true` to fire across all servers.
- **Action filtering**: Subscribe to specific events via `subscribedActions` array.
---
## UI Features
The frontend is a Vue 3 + TypeScript SPA with a glassmorphism design language.
### Design System
- **Glassmorphism**: Frosted glass cards, buttons, and inputs with backdrop blur effects.
- **TailwindCSS 4**: Utility-first styling with full dark mode support via `dark:` variants.
- **Responsive**: Mobile-first layout that adapts to all screen sizes.
### Features
| Feature | Description |
|---------|-------------|
| **Multi-language (i18n)** | English, Indonesian, and Chinese via vue-i18n 9. Locale auto-detected from browser. |
| **Theme Switching** | Dark / Light / Auto (follows system preference) via `@vueuse/core`. |
| **Real-time Stats** | WebSocket connection broadcasts live peer counts and traffic data every 5 seconds. |
| **Charts** | Traffic visualization via Chart.js + vue-chartjs. |
| **Toast Notifications** | Non-intrusive alerts via vue-sonner. |
| **QR Code Import** | Generate scannable QR codes for quick mobile WireGuard client setup. |
### Frontend Structure
```
app/frontend/src/
├── App.vue # Root component with theme/i18n providers
├── main.ts # App bootstrap (Vue, Router, i18n)
├── router/ # Vue Router definitions
├── i18n/ # Locale files (en.json, id.json, zh.json)
├── components/ # Glass UI components (Card, Button, Input, Toggle)
├── composables/ # Vue composables (useTheme, etc.)
├── views/ # Page components (Dashboard, Servers, Peers, Settings)
└── types/ # TypeScript type definitions
```
---
## Policy Firewall (`#Access`)
The shell-based policy engine enforces per-peer firewall rules directly from `wg0.conf`.
### How It Works
1. Add `#Access` comments under each `[Peer]` block in `wg0.conf`.
2. The watcher daemon (`wg-sync-watch.sh`) detects file changes via `inotifywait`.
3. `wg-sync-policy.sh` parses the config and writes `policy.json` atomically.
4. `wg-policy-engine.sh` reads the JSON and applies iptables/ipset rules.
### Example `wg0.conf`
```ini
[Interface]
@@ -70,20 +339,9 @@ Address = 10.0.0.1/24
ListenPort = 51820
PrivateKey = <SERVER_PRIVATE_KEY>
# Policy engine: auto-handles NAT, IP forwarding, and dynamic firewall rules
PostUp = /usr/local/bin/wg-sync-policy.sh; /usr/local/bin/wg-policy-engine.sh
# Policy engine: cleanup all firewall and routing traces
PostDown = /usr/local/bin/wg-policy-cleanup.sh
```
### 2. Peer Block (`#Access` Tags)
For each client, use the `#Access` comment line. Define the destinations (targets) the peer is allowed to access. You can separate multiple IPs or CIDRs with commas or semicolons.
> **⚠️ WARNING: Do NOT use `SaveConfig = true`!**
> WireGuard's `SaveConfig` feature overwrites `wg0.conf` directly and **strips all comments**, which will permanently delete all `#Access` tags. If you are using a Web UI/Dashboard, make sure it does not strip unknown comments when saving.
```ini
[Peer]
PublicKey = <CLIENT_1_PUBKEY>
AllowedIPs = 10.0.0.2/32
@@ -92,82 +350,126 @@ AllowedIPs = 10.0.0.2/32
[Peer]
PublicKey = <CLIENT_2_PUBKEY>
AllowedIPs = 10.0.0.3/32
#Access = 10.0.0.1/32
#Access 10.0.0.1/32
[Peer]
PublicKey = <CLIENT_3_PUBKEY>
AllowedIPs = 10.0.0.4/32
#Access
# ^ (Empty Access implies internet-only, client isolation applies)
#Access
# Empty Access = internet-only, client isolation applies
```
**⚠️ Important constraint:** Why `#Access` instead of just using `AllowedIPs` directly?
WireGuard uses `AllowedIPs` for Cryptokey Routing (deciding which tunnel interface to route outbound packets). If you put an internal server IP inside the server's `wg0.conf` AllowedIPs block, WireGuard will aggressively capture and redirect packets bound for that internal server into the VPN client's tunnel. The `#Access` comment separates routing parameters from firewall parameters cleanly.
### Why `#Access` Instead of `AllowedIPs`?
WireGuard uses `AllowedIPs` for Cryptokey Routing. Putting destination IPs in the server's `AllowedIPs` would cause WireGuard to route traffic for those IPs into the client tunnel. The `#Access` comment cleanly separates firewall policy from routing configuration.
### CLI: `wg-policy-ctl`
```bash
wg-policy-ctl status # Health check, lock status, rule counts
wg-policy-ctl policy # View raw policy.json
wg-policy-ctl rules # Inspect active iptables rules
wg-policy-ctl ipset # View ipset mappings
wg-policy-ctl reload # Force re-sync and re-apply
wg-policy-ctl log # View dropped packet logs
wg-policy-ctl stats # Connection statistics
wg-policy-ctl validate # Validate policy.json schema
```
### Prerequisites
| Package | Required | Install |
|---------|----------|---------|
| `jq` | Yes | `apt install jq` |
| `inotify-tools` | Yes (watcher daemon) | `apt install inotify-tools` |
| `ipset` | Optional | `apt install ipset` |
Without `ipset`, the engine falls back to per-rule iptables entries. This works for small deployments. For large peer counts, `ipset` provides O(1) lookup performance.
---
## 🛠 `wg-policy-ctl` CLI Usage
## Scheduler
You don't need to manually interact with `iptables` or `.json` files. Use the `wg-policy-ctl` wrapper.
The Go backend runs three background cron jobs:
```bash
# View the health of the firewall engine and active locks
wg-policy-ctl status
| Schedule | Job | Action |
|----------|-----|--------|
| Daily 2:00 AM | `deleteExpiredPeers` | Removes peers past their `ExpiresAt` date. |
| Daily 3:00 AM | `restrictOverLimitPeers` | Disables peers that exceeded `DataLimitGB`. |
| 1st of month | `resetMonthlyUsage` | Resets `CurrentDataUsageBytes` to zero for all peers. |
# View the raw, parsed JSON policy
wg-policy-ctl policy
---
# Inspect active iptables rules
wg-policy-ctl rules
## Plugins
# Check memory sets mapping IP targets (ipset)
wg-policy-ctl ipset
The plugin system provides a simple notification interface. Built-in plugins include:
# Manually re-sync rules immediately
wg-policy-ctl reload
- **TelegramNotifier** -- Sends Telegram messages on events.
- **SlackNotifier** -- Sends Slack messages on events.
- **TrafficLogger** -- Logs traffic events for debugging.
# Inspect dropped packets (rate-limited log output)
wg-policy-ctl log
Plugins are loaded at startup via `PluginManager.LoadPlugins()` and receive events through `Trigger(event, payload)`.
# See connection statistics, how many targets loaded
wg-policy-ctl stats
---
# Force validation of the policy schema
wg-policy-ctl validate
## Configuration
### Environment Variables
| Variable | Default | Description |
|----------|---------|-------------|
| `WG_API_KEY` | `test-api-key` | API key for header-based authentication. |
| `JWT_SECRET` | `secret` | Secret for JWT token signing. |
| `APP_FRONTEND_DIR` | `/var/www/frontend` | Path to built frontend assets. |
| `WG_RPLANE_MODE` | `forward` | Default server mode (`forward` or `standalone`). |
### Database
WGRplane uses SQLite by default (`wgrplane.db`). Models auto-migrate on startup:
- **Server** -- WireGuard server entries with mode and endpoint.
- **Peer** -- Peer entries with IP, access rules, data limits, expiry.
- **Webhook** -- Webhook configurations with templates and action filters.
- **SMTPSettings** -- SMTP server configuration for email notifications.
---
## Project Structure
```
03.wireguard-policy/
├── app/ # Go backend + Vue frontend
│ ├── handlers.go # REST API route handlers
│ ├── main.go # Server bootstrap, routes
│ ├── models.go # GORM models (Server, Peer, Webhook, SMTP)
│ ├── auth.go # JWT, TOTP, API key auth middleware
│ ├── nftables.go # nftables rule management (forward mode)
│ ├── webhook.go # Webhook engine with retry/backoff
│ ├── scheduler.go # Cron jobs (expiry, data limit, reset)
│ ├── stats.go # WebSocket Hub for real-time stats
│ ├── email.go # SMTP email notifications
│ ├── plugins.go # Plugin system (Telegram, Slack, Logger)
│ ├── validation.go # Input validators (IP, CIDR, PublicKey)
│ ├── wg.go # WireGuard key generation, config export
│ ├── i18n.go # Backend i18n (en/id/zh)
│ ├── frontend/ # Vue 3 SPA (TypeScript, TailwindCSS)
│ └── active.{en,id,zh}.json # Translation files
├── wg-sync-policy.sh # Parses wg0.conf → policy.json
├── wg-policy-engine.sh # Applies policy.json → iptables/ipset
├── wg-sync-watch.sh # inotifywait watcher daemon
├── wg-policy-ctl # CLI wrapper for management
├── wg-policy-cleanup.sh # Cleanup script for PostDown
├── wg-policy.service # Systemd unit for watcher daemon
├── wgrplane.service # Systemd unit for Go backend
├── install.sh # Automated installer (Docker + services)
├── Dockerfile # Multi-stage Docker build
├── docker-compose.yml # Docker Compose stack
├── build.sh / build.bat # Installer rebuild scripts
└── README.md # This file
```
---
## 🔧 Systemd Integration (Watcher Daemon)
## License
If you use the `install.sh` script, the daemon is automatically installed, enabled, and started for you. It monitors `wg0.conf` for changes and triggers the pipeline seamlessly.
### Manual File Installation (If not using install.sh)
Place the three provided systemd unit files into `/etc/systemd/system/`.
| Systemd File | Location | Description |
|--------------|----------|-------------|
| `wg-policy.service` | `/etc/systemd/system/wg-policy.service` | The main daemon that runs `wg-sync-watch.sh` |
| `wg-policy-health.timer` | `/etc/systemd/system/wg-policy-health.timer` | Triggers the health check every 5 minutes |
| `wg-policy-health.service`| `/etc/systemd/system/wg-policy-health.service`| Executes the actual health check logic |
```bash
# Example copy command
cp wg-policy.service wg-policy-health.timer wg-policy-health.service /etc/systemd/system/
```
### 2. Enable & Start Services
After copying the files, reload systemd to recognize them, then enable and start the services.
```bash
systemctl daemon-reload
systemctl enable wg-policy.service
systemctl enable wg-policy-health.timer
systemctl start wg-policy.service
systemctl start wg-policy-health.timer
```
Check the watcher logs:
```bash
journalctl -u wg-policy.service -f
```
This project builds upon concepts from WGDashboard (donaldzou/WGDashboard) with modifications for policy.json API integration and dynamic firewall enforcement.
+30
View File
@@ -0,0 +1,30 @@
version: "3.8"
services:
wgrplane:
build:
context: .
dockerfile: Dockerfile
ports:
- "10087:10087"
volumes:
- ./wgrplane-data:/var/lib/wgrplane
- ./wireguard-config:/etc/wireguard
depends_on:
- wireguard
restart: unless-stopped
wireguard:
image: ghcr.io/linuxserver/wireguard:latest
container_name: wireguard
cap_add:
- NET_ADMIN
- SYS_MODULE
network_mode: "host"
volumes:
- /etc/wireguard:/config
- /lib/modules:/lib/modules
environment:
- PUID=1000
- PGID=1000
- TZ=UTC
restart: unless-stopped
+39
View File
@@ -0,0 +1,39 @@
module github.com/your-org/03.wireguard-policy
go 1.25.0
require (
github.com/golang-jwt/jwt/v5 v5.3.1
github.com/gorilla/mux v1.8.1
github.com/gorilla/websocket v1.5.3
github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible
github.com/nicksnyder/go-i18n/v2 v2.6.1
github.com/pquerna/otp v1.5.0
github.com/robfig/cron/v3 v3.0.1
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
github.com/swaggo/http-swagger v1.3.4
github.com/swaggo/swag v1.16.6
golang.org/x/text v0.36.0
gorm.io/driver/sqlite v1.6.0
gorm.io/gorm v1.31.1
)
require (
github.com/KyleBanks/depth v1.2.1 // indirect
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/jsonreference v0.20.0 // indirect
github.com/go-openapi/spec v0.20.6 // indirect
github.com/go-openapi/swag v0.19.15 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/mailru/easyjson v0.7.6 // indirect
github.com/mattn/go-sqlite3 v1.14.22 // indirect
github.com/swaggo/files v1.0.1 // indirect
golang.org/x/mod v0.34.0 // indirect
golang.org/x/net v0.52.0 // indirect
golang.org/x/sync v0.20.0 // indirect
golang.org/x/tools v0.43.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)
+124
View File
@@ -0,0 +1,124 @@
github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk=
github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI=
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA=
github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo=
github.com/go-openapi/spec v0.20.6 h1:ich1RQ3WDbfoeTqTAb+5EIxNmpKVJZWBNah9RAT0jIQ=
github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM=
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY=
github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible h1:jdpOPRN1zP63Td1hDQbZW73xKmzDvZHzVdNYxhnTMDA=
github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible/go.mod h1:1c7szIrayyPPB/987hsnvNzLushdWf4o/79s3P08L8A=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/nicksnyder/go-i18n/v2 v2.6.1 h1:JDEJraFsQE17Dut9HFDHzCoAWGEQJom5s0TRd17NIEQ=
github.com/nicksnyder/go-i18n/v2 v2.6.1/go.mod h1:Vee0/9RD3Quc/NmwEjzzD7VTZ+Ir7QbXocrkhOzmUKA=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pquerna/otp v1.5.0 h1:NMMR+WrmaqXU4EzdGJEE1aUUI0AMRzsp96fFFWNPwxs=
github.com/pquerna/otp v1.5.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE=
github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg=
github.com/swaggo/http-swagger v1.3.4 h1:q7t/XLx0n15H1Q9/tk3Y9L4n210XzJF5WtnDX64a5ww=
github.com/swaggo/http-swagger v1.3.4/go.mod h1:9dAh0unqMBAlbp1uE2Uc2mQTxNMU/ha4UbucIg1MFkQ=
github.com/swaggo/swag v1.16.6 h1:qBNcx53ZaX+M5dxVyTrgQ0PJ/ACK+NzhwcbieTt+9yI=
github.com/swaggo/swag v1.16.6/go.mod h1:ngP2etMK5a0P3QBizic5MEwpRmluJZPHjXcMoj4Xesg=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI=
golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=
golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s=
golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA=
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/sqlite v1.6.0 h1:WHRRrIiulaPiPFmDcod6prc4l2VGVWHz80KspNsxSfQ=
gorm.io/driver/sqlite v1.6.0/go.mod h1:AO9V1qIQddBESngQUKWL9yoH93HIeA1X6V633rBwyT8=
gorm.io/gorm v1.31.1 h1:7CA8FTFz/gRfgqgpeKIBcervUn3xSyPUmr6B2WXJ7kg=
gorm.io/gorm v1.31.1/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs=
+120 -1303
View File
File diff suppressed because it is too large Load Diff
+45
View File
@@ -0,0 +1,45 @@
#!/usr/bin/env bash
set -euo pipefail
echo "[CI] Verifying Gorilla dependencies and WebSocket endpoint (WS) in Go-enabled environment"
cd app
echo ">> Checking Go toolchain..."
if ! command -v go >/dev/null 2>&1; then
echo "Go is not installed in this environment. Exiting.";
exit 0
fi
echo ">> Fetching dependencies..."
go get -u github.com/gorilla/mux
go get -u github.com/gorilla/websocket
echo ">> Tidying modules..."
go mod tidy
echo ">> Building project..."
go build ./...
echo ">> Running server in background..."
go run main.go &
PID=$!
echo "[CI] Server PID: $PID"
sleep 2
echo ">> Testing WebSocket endpoint (ws://localhost:8080/ws/stats) using simple client..."
if command -v websocat >/dev/null 2>&1; then
websocat -b ws://localhost:8080/ws/stats >/tmp/ws_test.txt &
WS_PID=$!
sleep 6
kill $WS_PID 2>/dev/null || true
echo "Captured output:"; head -n 5 /tmp/ws_test.txt || true
else
echo "websocat not installed. Install to run WS test or use another client."
fi
echo ">> Cleaning up server process..."
kill $PID 2>/dev/null || true
wait $PID 2>/dev/null || true
echo "[CI] Verification script completed."
+49
View File
@@ -0,0 +1,49 @@
#!/usr/bin/env bash
set -euo pipefail
###########################################
# End-to-end verification for /api/peers/*
# Requires: curl, jq, xxd, file (coreutils)
###########################################
API_KEY="${WG_API_KEY:-test-api-key}"
BASE_URL="${WG_BASE_URL:-http://127.0.0.1:8080}"
echo "[VERIF-EE] Starting end-to-end verification against ${BASE_URL}"
echo "[STEP] Seed server"
SERVER_PAYLOAD='{"name":"test-server","mode":"forward","PublicKey":"SERVER_PUBLIC_KEY_BASE64","Endpoint":"server.example:51820"}'
SERVER_ID=$(curl -s -H "wg-rplane-datadunia: ${API_KEY}" -H "Content-Type: application/json" -d "$SERVER_PAYLOAD" "$BASE_URL/api/servers" | jq -r '.id')
echo "[INFO] SERVER_ID=${SERVER_ID}"
echo "[STEP] Seed peer"
PEER_PAYLOAD='{"PublicKey":"PEER_PUBLIC_KEY_BASE64","IP":"10.0.0.2","AllowAccess":"[]","AllowInternet":false}'
PEER_ID=$(curl -s -H "wg-rplane-datadunia: ${API_KEY}" -H "Content-Type: application/json" -d "$PEER_PAYLOAD" "$BASE_URL/api/servers/${SERVER_ID}/peers" | jq -r '.id')
echo "[INFO] PEER_ID=${PEER_ID}"
echo "[STEP] Fetch config"
CONFIG_JSON=$(curl -s -w "%{http_code}" -H "wg-rplane-datadunia: ${API_KEY}" "$BASE_URL/api/peers/${PEER_ID}/config")
STATUS=$(tail -c 3 <<< "$CONFIG_JSON");
CONFIG_BODY=$(echo "$CONFIG_JSON" | sed '$d')
if [ "$STATUS" != "200" ]; then
echo "[ERROR] Config endpoint returned status code ${STATUS}"; exit 1
fi
echo "$CONFIG_BODY" > /tmp/peer_config.conf
echo "[STEP] Validate config content"
grep -q "^\\[Interface\\]" /tmp/peer_config.conf || { echo "Config missing [Interface]"; exit 1; }
grep -q "^\\[Peer\\]" /tmp/peer_config.conf || { echo "Config missing [Peer]"; exit 1; }
echo "[STEP] Fetch QR code"
curl -s -o /tmp/peer.png -D /tmp/peer_headers.txt -H "wg-rplane-datadunia: ${API_KEY}" "$BASE_URL/api/peers/${PEER_ID}/qrcode" || { echo "Failed to fetch QR code"; exit 1; }
echo "[INFO] QR code saved to /tmp/peer.png"
echo "[STEP] Validate PNG file"
if file /tmp/peer.png | grep -qi png; then
echo "[OK] PNG detected"
else
echo "[ERROR] Not a PNG file"
exit 1
fi
echo "[VERIF-EE] End-to-end verification completed successfully."
+14
View File
@@ -0,0 +1,14 @@
[Unit]
Description=WGRPlane Go Gateway Service
Wants=network-online.target
After=network-online.target
[Service]
Type=simple
Environment=WG_RPLANE_MODE=forward
ExecStart=/usr/local/bin/wgrplane
Restart=always
RestartSec=5s
[Install]
WantedBy=multi-user.target