# WGRplane - WireGuard Remote Plane Control

**WGRplane** adalah aplikasi WireGuard Control Plane berbasis Go-native dengan frontend Vue 3. Single binary untuk backend, SPA untuk frontend, dilengkapi dynamic policy firewall dan glassmorphism UI.

---

## Fitur Utama

- **Arsitektur Go-Native**: Single Go binary (`main.go`) menangani semua API, database, webhook, scheduler, dan nftables. Tidak ada Python/Flask.
- **Peer CRUD Lengkap**: Tambah, edit, hapus peer. Generate QR code untuk import ke mobile client. Export file konfigurasi `.conf`.
- **Hybrid Mode**: Mode `forward` (nftables lokal) atau `standalone` (webhook ke server remote).
- **2-Column Policy UI**: Kolom "Allow Access" (firewall whitelist CIDR) dan "Allow Internet" (MASQUERADE toggle) per peer.
- **Real-time Monitoring**: WebSocket broadcast statistik peer dan trafik setiap 5 detik.
- **Automated Scheduling**: Cron job harian untuk hapus peer expired, restriksi peer over-limit, dan reset data usage bulanan.
- **Security**: Autentikasi API Key (`wg-rplane-datadunia`), JWT Bearer token, dan TOTP (2FA).
- **Webhook Engine**: Integrasi dengan server remote (Mikrotik, dll). Retry dengan exponential backoff, custom headers, Go template.
- **Plugin System**: Notifikasi Telegram, Slack, dan Traffic Logger.
- **i18n & Themes**: Multi-bahasa (English, Indonesian, Chinese). Dark/Light/Auto mode.
- **Glassmorphism UI**: Desain futuristik dengan frosted glass cards, buttons, dan inputs.

---

## Arsitektur

```
wg0.conf (dengan/tanpa #Access)
        ↓
┌─────────────────────────────────────────────┐
│  WGRplane (Go Binary :10087)                │
│  ┌───────────┐  ┌──────────┐  ┌──────────┐  │
│  │ Gorilla   │  │ GORM     │  │ nftables │  │
│  │ Mux Router│  │ SQLite   │  │ Engine   │  │
│  └───────────┘  └──────────┘  └──────────┘  │
│  ┌───────────┐  ┌──────────┐  ┌──────────┐  │
│  │ Webhook   │  │ Scheduler│  │ WebSocket│  │
│  │ Engine    │  │ Cron     │  │ Hub      │  │
│  └───────────┘  └──────────┘  └──────────┘  │
│  ┌───────────┐  ┌──────────┐  ┌──────────┐  │
│  │ Auth      │  │ SMTP     │  │ Plugins  │  │
│  │ JWT/TOTP  │  │ Email    │  │ TG/Slack │  │
│  └───────────┘  └──────────┘  └──────────┘  │
└─────────────────────────────────────────────┘
        ↓ HTTP/WebSocket
┌─────────────────────────────────────────────┐
│  Frontend (Vue 3 + TypeScript + Tailwind)   │
│  Glassmorphism UI, i18n, Dark/Light mode    │
└─────────────────────────────────────────────┘
```

### Data Flow Policy Firewall

```
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

| Komponen | Teknologi |
|-----------|------------|
| **Backend** | Go, Gorilla Mux, GORM (SQLite via glebarez/sqlite) |
| **Frontend** | Vue 3, TypeScript, Vite, TailwindCSS 4, vue-i18n 9 |
| **Auth** | JWT (golang-jwt/v5), TOTP (pquerna/otp), API Key |
| **WebSockets** | gorilla/websocket |
| **Webhooks** | Go net/http dengan retry + exponential backoff |
| **Scheduling** | robfig/cron v3 |
| **QR Code** | skip2/go-qrcode |
| **Email** | jordan-wright/email (SMTP) |
| **Firewall** | Bash, iptables, ipset, nftables, inotify-tools, jq |
| **Container** | Docker (multi-stage build), docker-compose |

---

## Port & Autentikasi

| Service | Port | Autentikasi |
|---------|------|---------------|
| WGRplane (Go API + Frontend) | **10087** | API Key (`wg-rplane-datadunia`) atau JWT Bearer + TOTP opsional |

### Metode Autentikasi

| Metode | Header | Catatan |
|--------|--------|---------|
| API Key | `wg-rplane-datadunia: <KEY>` | Diatur via env var `WG_API_KEY`. Default: `test-api-key`. |
| JWT | `Authorization: Bearer <TOKEN>` | Expired 15 menit. Secret via env var `JWT_SECRET`. |
| TOTP | `X-TOTP: <CODE>` | Wajib jika user mengaktifkan TOTP. |

---

## API Endpoints

Semua endpoint dilayani di port `10087`.

### Servers

| Endpoint | Method | Deskripsi |
|----------|--------|-------------|
| `/api/servers` | `GET` | Daftar semua server WireGuard. |
| `/api/servers` | `POST` | Buat server baru. Body: `{name, mode, publicKey, endpoint}`. |
| `/api/servers/{id}` | `GET` | Ambil satu server berdasarkan ID. |
| `/api/servers/{id}` | `PUT` | Update server (name, mode, publicKey, endpoint). |
| `/api/servers/{id}` | `DELETE` | Hapus server beserta peer dan webhook-nya. |

### Peers

| Endpoint | Method | Deskripsi |
|----------|--------|-------------|
| `/api/servers/{id}/peers` | `GET` | Daftar semua peer untuk satu server. |
| `/api/servers/{id}/peers` | `POST` | Buat peer baru. Body: `{publicKey, ip, allowAccess, allowInternet}`. Mode `forward` langsung apply nftables, mode `standalone` trigger webhook. |
| `/api/peers/{id}` | `PUT` | Update peer. Hitung diff dan apply perubahan nftables incremental. |
| `/api/peers/{id}` | `DELETE` | Hapus peer. Bersihkan rule nftables dan trigger webhook. |
| `/api/peers/{id}/config` | `GET` | Download file konfigurasi WireGuard `.conf`. |
| `/api/peers/{id}/qrcode` | `GET` | Generate QR code PNG untuk import ke mobile client. |

### Webhooks

| Endpoint | Method | Deskripsi |
|----------|--------|-------------|
| `/api/servers/{id}/webhooks` | `GET` | Daftar webhook untuk satu server. |
| `/api/servers/{id}/webhooks` | `POST` | Buat webhook. Body: `{name, url, template, customBody, customHeaders, subscribedActions, isEnabled, verifySSL}`. |
| `/api/webhooks/{id}` | `DELETE` | Hapus webhook. |

### SMTP Settings

| Endpoint | Method | Deskripsi |
|----------|--------|-------------|
| `/api/settings/smtp` | `GET` | Ambil konfigurasi SMTP saat ini. |
| `/api/settings/smtp` | `POST` | Simpan/update pengaturan SMTP untuk notifikasi email. |

### Statistics

| Endpoint | Method | Deskripsi |
|----------|--------|-------------|
| `/api/stats` | `GET` | Statistik global: total server, peer, webhook. |
| `/api/servers/{id}/stats` | `GET` | Statistik per server: jumlah peer, webhook, detail server. |

### WebSocket

| Endpoint | Protokol | Deskripsi |
|----------|----------|-------------|
| `/ws/stats` | WebSocket | Broadcast statistik real-time (interval 5 detik). |

### TOTP Setup

| Endpoint | Method | Deskripsi |
|----------|--------|-------------|
| `/auth/setup-totp?user=<USER>` | `GET` | Generate TOTP secret dan provisioning URI untuk user. |

### Swagger Documentation

| Endpoint | Deskripsi |
|----------|-----------|
| `/swagger/` | Swagger UI untuk dokumentasi API interaktif. |

---

## Hybrid Mode

Backend Go mendukung dua mode server:

- **`forward`** -- Instance WGRplane langsung apply rule nftables di mesin lokal. Policy peer enforced langsung via perintah `nft`.
- **`standalone`** -- Instance bertindak sebagai control plane yang trigger webhook ke server WireGuard remote. Policy enforcement terjadi di sisi remote.

### 2-Column Policy

Setiap peer memiliki dua kolom policy independen:

| Kolom | Fungsi |
|-------|--------|
| **AllowAccess** | Daftar CIDR yang bisa dijangkau peer (target internal). |
| **AllowInternet** | Boolean flag. Jika `true`, peer mendapat akses internet tanpa batas (MASQUERADE). |

Peer yang tidak punya rule apapun terisolasi dari peer lain dan dari internet secara default.

---

## Instalasi

### Opsi 1: Docker Compose (Direkomendasikan)

```bash
# Clone repository
git clone https://git.datadunia.com/hainzero/WGRplane.git
cd 03.wireguard-policy

# Start WGRplane dan WireGuard
docker compose up -d

# Akses dashboard
# http://localhost:10087
```

Stack compose menjalankan:
- **WGRplane** di port `10087` (Go API + Vue frontend)
- **WireGuard** container dengan host networking untuk akses kernel module

### Opsi 2: Install Script

```bash
# Jalankan installer otomatis (Ubuntu/Debian/CentOS)
sudo ./install.sh install

# Uninstall
sudo ./install.sh uninstall
```

Install script menangani instalasi Docker, cloning repository, pembuatan `.env`, dan startup service.

### Opsi 3: Manual Build

```bash
# Build binary Go
cd app
go build -o ../wgrplane .
cd ..

# Build frontend
cd app/frontend
npm install && npm run build
cd ../..

# Jalankan
./wgrplane
# Server start di :10087
```

### Opsi 4: Systemd Service

```bash
# Install service file
sudo cp wgrplane.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable wgrplane.service
sudo systemctl start wgrplane.service

# Lihat log
journalctl -u wgrplane.service -f
```

---

## Konfigurasi

### Environment Variables

| Variable | Default | Deskripsi |
|----------|---------|-----------|
| `WG_API_KEY` | `test-api-key` | API key untuk autentikasi header-based. |
| `JWT_SECRET` | `secret` | Secret untuk signing JWT token. |
| `APP_FRONTEND_DIR` | `/var/www/frontend` | Path ke asset frontend yang sudah di-build. |
| `WG_RPLANE_MODE` | `forward` | Mode server default (`forward` atau `standalone`). |

### Database

WGRplane menggunakan SQLite secara default (`wgrplane.db`). Model auto-migrate saat startup:

- **Server** -- Entry server WireGuard dengan mode dan endpoint.
- **Peer** -- Entry peer dengan IP, rule akses, limit data, expiry.
- **Webhook** -- Konfigurasi webhook dengan template dan filter aksi.
- **SMTPSettings** -- Konfigurasi server SMTP untuk notifikasi email.

---

## Scheduler

Backend Go menjalankan tiga cron job:

| Jadwal | Job | Aksi |
|--------|-----|------|
| Setiap hari 02:00 | `deleteExpiredPeers` | Hapus peer yang sudah melewati `ExpiresAt`. |
| Setiap hari 03:00 | `restrictOverLimitPeers` | Disable peer yang melebihi `DataLimitGB`. |
| Tanggal 1 setiap bulan | `resetMonthlyUsage` | Reset `CurrentDataUsageBytes` ke nol untuk semua peer. |

---

## Webhook Payload

Webhook trigger pada event lifecycle peer (`peer_created`, `peer_updated`, `peer_deleted`, `policy_changed`). Engine mendukung tiga mode template: `default` (JSON mentah), `mikrotik` (format RouterOS), dan `custom` (Go template).

### Fitur Webhook

- **Retry dengan backoff**: Delivery gagal retry hingga 3 kali dengan exponential backoff (2s, 4s, 8s).
- **Verifikasi SSL**: Bisa di-toggle per-webhook via `verifySSL`.
- **Custom headers**: Inject header per-webhook via `customHeaders` JSON.
- **Global webhooks**: Set `isGlobal: true` untuk trigger di semua server.
- **Filter aksi**: Subscribe ke event spesifik via array `subscribedActions`.

---

## UI Frontend

Frontend adalah Vue 3 + TypeScript SPA dengan desain glassmorphism.

### Design System

- **Glassmorphism**: Frosted glass cards, buttons, dan inputs dengan efek backdrop blur.
- **TailwindCSS 4**: Utility-first styling dengan dukungan dark mode penuh via `dark:` variants.
- **Responsive**: Layout mobile-first yang adaptif di semua ukuran layar.

### Fitur UI

| Fitur | Deskripsi |
|-------|-----------|
| **Multi-bahasa (i18n)** | English, Indonesian, dan Chinese via vue-i18n 9. Locale auto-detect dari browser. |
| **Theme Switching** | Dark / Light / Auto (ikuti preferensi sistem) via `@vueuse/core`. |
| **Real-time Stats** | Koneksi WebSocket broadcast jumlah peer dan data trafik setiap 5 detik. |
| **Charts** | Visualisasi trafik via Chart.js + vue-chartjs. |
| **Toast Notifications** | Alert non-intrusif via vue-sonner. |
| **QR Code Import** | Generate QR code yang bisa di-scan untuk setup mobile WireGuard client. |

### Struktur Frontend

```
app/frontend/src/
├── App.vue              # Root component dengan provider theme/i18n
├── main.ts              # Bootstrap app (Vue, Router, i18n)
├── router/              # Definisi Vue Router
├── i18n/                # File locale (en.json, id.json, zh.json)
├── components/          # Komponen Glass UI (Card, Button, Input, Toggle)
├── composables/         # Vue composables (useTheme, useWebSocket)
├── views/               # Page components (Dashboard, Servers, Peers, Settings, Webhooks)
└── types/               # Definisi tipe TypeScript
```

---

## Policy Firewall (`#Access`)

Engine policy berbasis shell enforcing rule firewall per-peer langsung dari `wg0.conf`.

### Cara Kerja

1. Tambahkan komentar `#Access` di bawah setiap blok `[Peer]` di `wg0.conf`.
2. Watcher daemon (`wg-sync-watch.sh`) mendeteksi perubahan file via `inotifywait`.
3. `wg-sync-policy.sh` parse config dan tulis `policy.json` secara atomik.
4. `wg-policy-engine.sh` baca JSON dan apply rule iptables/ipset.

### Contoh `wg0.conf`

```ini
[Interface]
Address = 10.0.0.1/24
ListenPort = 51820
PrivateKey = <SERVER_PRIVATE_KEY>

PostUp = /usr/local/bin/wg-sync-policy.sh; /usr/local/bin/wg-policy-engine.sh
PostDown = /usr/local/bin/wg-policy-cleanup.sh

[Peer]
PublicKey = <CLIENT_1_PUBKEY>
AllowedIPs = 10.0.0.2/32
#Access 192.168.1.10/32, 192.168.12.0/24

[Peer]
PublicKey = <CLIENT_2_PUBKEY>
AllowedIPs = 10.0.0.3/32
#Access 10.0.0.1/32

[Peer]
PublicKey = <CLIENT_3_PUBKEY>
AllowedIPs = 10.0.0.4/32
#Access
# Access kosong = internet-only, isolasi client berlaku
```

### Mengapa `#Access` Bukan `AllowedIPs`?

WireGuard menggunakan `AllowedIPs` untuk Cryptokey Routing. Memasukkan IP destinasi di `AllowedIPs` server akan menyebabkan WireGuard meroute traffic untuk IP tersebut ke dalam tunnel client. Komentar `#Access` memisahkan konfigurasi firewall dari routing secara bersih.

### CLI: `wg-policy-ctl`

```bash
wg-policy-ctl status     # Health check, status lock, jumlah rule
wg-policy-ctl policy     # Lihat raw policy.json
wg-policy-ctl rules      # Inspect rule iptables aktif
wg-policy-ctl ipset      # Lihat mapping ipset
wg-policy-ctl reload     # Force re-sync dan re-apply
wg-policy-ctl log        # Lihat log packet dropped
wg-policy-ctl stats      # Statistik koneksi
wg-policy-ctl validate   # Validasi schema policy.json
```

### Prerequisites

| Package | Diperlukan | Install |
|---------|------------|---------|
| `jq` | Ya | `apt install jq` |
| `inotify-tools` | Ya (watcher daemon) | `apt install inotify-tools` |
| `ipset` | Opsional | `apt install ipset` |

Tanpa `ipset`, engine fallback ke entry iptables per-rule. Ini bekerja untuk deployment kecil. Untuk jumlah peer besar, `ipset` memberikan performa lookup O(1).

---

## Plugins

Sistem plugin menyediakan interface notifikasi sederhana. Plugin bawaan:

- **TelegramNotifier** -- Kirim pesan Telegram saat event.
- **SlackNotifier** -- Kirim pesan Slack saat event.
- **TrafficLogger** -- Log event traffic untuk debugging.

Plugin dimuat saat startup via `PluginManager.LoadPlugins()` dan menerima event melalui `Trigger(event, payload)`.

---

## Struktur Proyek

```
03.wireguard-policy/
├── app/                          # Go backend + Vue frontend
│   ├── main.go                   # Bootstrap server, routing, init DB
│   ├── handlers.go               # REST API route handlers
│   ├── models.go                 # GORM models (Server, Peer, Webhook, SMTP)
│   ├── auth.go                   # JWT, TOTP, API key auth middleware
│   ├── nftables.go               # nftables rule management (mode forward)
│   ├── webhook.go                # Webhook engine dengan retry/backoff
│   ├── scheduler.go              # Cron jobs (expiry, data limit, reset)
│   ├── stats.go                  # WebSocket Hub untuk real-time stats
│   ├── email.go                  # Notifikasi email SMTP
│   ├── 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)
│   ├── docs/                     # Swagger documentation
│   └── frontend/                 # Vue 3 SPA (TypeScript, TailwindCSS)
├── wg-sync-policy.sh             # Parse wg0.conf → policy.json
├── wg-policy-engine.sh           # Apply policy.json → iptables/ipset
├── wg-sync-watch.sh              # inotifywait watcher daemon
├── wg-policy-ctl                 # CLI wrapper untuk manajemen
├── wg-policy-cleanup.sh          # Cleanup script untuk PostDown
├── wg-policy.service             # Systemd unit untuk watcher daemon
├── wgrplane.service              # Systemd unit untuk Go backend
├── install.sh                    # Automated installer (Docker + services)
├── Dockerfile                    # Multi-stage Docker build
├── docker-compose.yml            # Docker Compose stack
├── build.sh / build.bat          # Script rebuild installer
└── README.md                     # Dokumentasi ini
```

---

## Testing

### Manual QA

```bash
# Test auth (tanpa header)
curl http://localhost:10087/api/servers
# Expected: 401 Unauthorized

# Test auth (header salah)
curl -H "wg-rplane-datadunia: wrong" http://localhost:10087/api/servers
# Expected: 401 Unauthorized

# Test auth (header benar)
curl -H "wg-rplane-datadunia: test-api-key" http://localhost:10087/api/servers
# Expected: 200 OK, daftar server

# Test buat server
curl -X POST \
  -H "Content-Type: application/json" \
  -H "wg-rplane-datadunia: test-api-key" \
  -d '{"name":"wg-01","mode":"forward","publicKey":"<PUBKEY>","endpoint":"vpn.example.com:51820"}' \
  http://localhost:10087/api/servers

# Test buat peer
curl -X POST \
  -H "Content-Type: application/json" \
  -H "wg-rplane-datadunia: test-api-key" \
  -d '{"publicKey":"<PEER_PUBKEY>","ip":"10.0.0.2","allowAccess":["192.168.1.0/24"],"allowInternet":true}' \
  http://localhost:10087/api/servers/1/peers

# Test QR code
curl -H "wg-rplane-datadunia: test-api-key" http://localhost:10087/api/peers/1/qrcode --output peer-qr.png

# Verifikasi rule iptables
wg-policy-ctl rules
```

---

## Dokumentasi Tambahan

- **Plan File**: `plan.md` (detail rencana implementasi)
- **AGENTS.md**: Panduan untuk AI agent dalam mengembangkan proyek ini
- **Parent Repo**: `https://git.datadunia.com/hainzero/WGRplane.git` (submodule di `/app`)

---

## Lisensi

Proyek ini membangun konsep dari WGDashboard (donaldzou/WGDashboard) dengan modifikasi untuk integrasi policy.json API dan dynamic firewall enforcement.
