mirror of
git://f0xx.org/android_cast
synced 2026-07-29 04:38:53 +03:00
footer changes, remote access changes
This commit is contained in:
@@ -6,8 +6,10 @@ See the full proposal: [20260602_REVERSE_SSH_proposals_summary.md](20260602_REVE
|
||||
|
||||
<!-- toc -->
|
||||
- [App (developer settings)](#app-developer-settings)
|
||||
- [BE](#be)
|
||||
- [WireGuard third-party](#wireguard-third-party)
|
||||
- [BE control plane](#be-control-plane)
|
||||
- [Production deploy (no new nginx HTTP paths)](#production-deploy-no-new-nginx-http-paths)
|
||||
- [WireGuard data plane (UDP, not nginx)](#wireguard-data-plane-udp-not-nginx)
|
||||
- [WireGuard third-party (Android)](#wireguard-third-party-android)
|
||||
- [Tests](#tests)
|
||||
<!-- /toc -->
|
||||
|
||||
@@ -19,29 +21,130 @@ See the full proposal: [20260602_REVERSE_SSH_proposals_summary.md](20260602_REVE
|
||||
|
||||
- Dropdown: **Disabled** | **WireGuard** | **RSSH (greyed — not selectable)**
|
||||
- Pref key: `dev_remote_access_mode` (`AppPreferences`)
|
||||
- **Disabled:** stops `RemoteAccessService`, tears down VPN, POST `type:ra` + `status:disable`
|
||||
- **WireGuard:** foreground poll 1–7 min → `RemoteAccessService` → BE `heartbeat.php`
|
||||
- **Disabled:** notifies BE (`status:disable`), tears down VPN, stops `RemoteAccessService`
|
||||
- **WireGuard:** foreground service; jittered poll **1–7 min** → `heartbeat.php` with `type: ra`
|
||||
- Heartbeat URL derived from crash upload URL (`…/api/heartbeat.php`)
|
||||
- Session credentials persisted until `expires_at`; expiry tears down tunnel locally
|
||||
- Optional full userspace WG via `third-party/wireguard-android` (`:tunnel`); otherwise `RemoteAccessVpnService` TUN fallback
|
||||
|
||||
## BE
|
||||
## BE control plane
|
||||
|
||||
- Migration: `sql/migrations/007_remote_access.sql`
|
||||
- Repository: `src/RemoteAccessRepository.php`
|
||||
- Device API: `public/api/heartbeat.php` (`type: ra`)
|
||||
- Admin API: `public/api/remote_access.php`
|
||||
- UI: `?view=remote_access` (nav + hub card)
|
||||
- RBAC: `remote_access_view`, `remote_access_operate`, `remote_access_admin`
|
||||
Uses the **existing crashes vhost** — no new nginx `location` blocks for HTTP.
|
||||
|
||||
## WireGuard third-party
|
||||
| Piece | Path |
|
||||
|-------|------|
|
||||
| Migration | `sql/migrations/007_remote_access.sql` |
|
||||
| Repository | `src/RemoteAccessRepository.php` |
|
||||
| WG peers | `src/WireGuardPeerProvisioner.php` (`wg set wg0 peer …`) |
|
||||
| Device API | `public/api/heartbeat.php` (`type: ra`) |
|
||||
| Admin API | `public/api/remote_access.php` |
|
||||
| UI | `?view=remote_access` (nav + hub card) |
|
||||
| RBAC | `remote_access_view`, `remote_access_operate`, `remote_access_admin` |
|
||||
| RBAC admin UI | `?view=rbac` — global roles (root), company roles, privilege sets |
|
||||
| Cron | `scripts/purge_remote_access.php` (hourly recommended) |
|
||||
|
||||
**RBAC rules (enforced in API)**
|
||||
|
||||
| Permission | Scope |
|
||||
|------------|--------|
|
||||
| `remote_access_view` | List devices/sessions/events in allowed companies |
|
||||
| `remote_access_operate` | Open session; close **own** sessions |
|
||||
| `remote_access_admin` | Whitelist devices; close **any** session in company |
|
||||
| Global admin / root | All companies; root edits global roles via `?view=rbac` |
|
||||
|
||||
Privilege sets (`remote_access_user`, `remote_access_admin`) on `company_memberships.permissions_json` grant extra actions to `member` rows — see crash console README § RBAC.
|
||||
|
||||
**Flow**
|
||||
|
||||
1. Device polls with `{type:ra, status:enable, capabilities:[wireguard], tunnel_mode:wireguard}`.
|
||||
2. BE upserts `remote_access_devices`; returns `wait` until device is **whitelisted** and operator **opens session**.
|
||||
3. Next eligible poll returns `action:connect` + ephemeral WG credentials; BE runs `wg set` when `provision_peers=true`.
|
||||
4. Disable from app → `status:disable` → closes sessions, removes peers.
|
||||
|
||||
**URLs (production)**
|
||||
|
||||
- Dashboard: `https://apps.f0xx.org/app/androidcast_project/crashes/?view=remote_access`
|
||||
- Heartbeat: `…/crashes/api/heartbeat.php`
|
||||
- Admin API: `…/crashes/api/remote_access.php`
|
||||
|
||||
## Production deploy (no new nginx HTTP paths)
|
||||
|
||||
After syncing PHP/JS to the BE tree under
|
||||
`…/androidcast_project/android_cast/examples/crash_reporter/backend/`:
|
||||
|
||||
### 1. Database
|
||||
|
||||
Migration **007** (already applied on prod per deploy notes). Tables auto-create on SQLite dev; MariaDB should use the migration file once as root.
|
||||
|
||||
### 2. `config.php` — required keys
|
||||
|
||||
```php
|
||||
'remote_access' => [
|
||||
'wg_endpoint' => 'ra.apps.f0xx.org:51820', // public UDP hostname:port (FE DNAT → BE)
|
||||
'wg_server_public_key' => '…', // wg show wg0 public-key on BE — REQUIRED
|
||||
'wg_interface' => 'wg0',
|
||||
'provision_peers' => true, // wg set on connect/close
|
||||
'require_wg_tools' => true, // reject connect if wg genkey missing
|
||||
'session_ttl_s' => 3600,
|
||||
'min_poll_interval_s' => 45, // poll rate limit per device
|
||||
],
|
||||
```
|
||||
|
||||
**Critical:** `wg_server_public_key` must match the live `wg0` interface. Empty value makes connect credentials unusable on real devices.
|
||||
|
||||
### 3. BE packages and permissions
|
||||
|
||||
```sh
|
||||
apk add wireguard-tools wireguard-tools-wg
|
||||
# wg0 configured separately (Address 10.66.66.1/24, ListenPort 51820, etc.)
|
||||
|
||||
# PHP-FPM user must run wg when provision_peers=true (same as CLI test):
|
||||
sudo -u www-data wg show wg0
|
||||
```
|
||||
|
||||
### 4. Cron (session cleanup)
|
||||
|
||||
```cron
|
||||
0 * * * * cd /var/www/.../backend && php scripts/purge_remote_access.php --hours=24
|
||||
```
|
||||
|
||||
### 5. Verify
|
||||
|
||||
```bash
|
||||
cd examples/crash_reporter/backend
|
||||
chmod +x scripts/verify_remote_access_prod.sh scripts/test_remote_access_api.sh
|
||||
./scripts/verify_remote_access_prod.sh
|
||||
BASE=https://apps.f0xx.org/app/androidcast_project/crashes ./scripts/test_remote_access_api.sh
|
||||
```
|
||||
|
||||
### 6. Browser
|
||||
|
||||
Hard-refresh after deploying `public/assets/js/remote_access.js`.
|
||||
|
||||
## WireGuard data plane (UDP, not nginx)
|
||||
|
||||
HTTP control plane stays on FE→BE `:80`. **WireGuard traffic is UDP** — configure at the **FE firewall/DNAT**, not in nginx:
|
||||
|
||||
```text
|
||||
Internet UDP :51820 → FE DNAT → BE wg0 :51820
|
||||
```
|
||||
|
||||
Hostname `ra.apps.f0xx.org` (or similar) should resolve to the FE public IP. Devices use `wg_endpoint` from config/connect payload.
|
||||
|
||||
## WireGuard third-party (Android)
|
||||
|
||||
```bash
|
||||
bash scripts/init-wireguard-submodule.sh
|
||||
./gradlew :app:assembleDebug # includes :tunnel when submodule present
|
||||
```
|
||||
|
||||
Optional `:tunnel` module from `third-party/wireguard-android`. Without it, `WireGuardTunnelBridge` uses `RemoteAccessVpnService` (TUN fallback).
|
||||
Without the submodule, `WireGuardTunnelBridge` uses `RemoteAccessVpnService` (TUN only — sufficient for lab; prefer `:tunnel` for production tunnels).
|
||||
|
||||
## Tests
|
||||
|
||||
```bash
|
||||
./gradlew :app:testDebugUnitTest
|
||||
./gradlew :app:testDebugUnitTest --tests 'com.foxx.androidcast.remoteaccess.*'
|
||||
bash examples/crash_reporter/backend/scripts/test_rbac_api.sh
|
||||
bash examples/crash_reporter/backend/scripts/test_remote_access_api.sh
|
||||
BASE=https://apps.f0xx.org/app/androidcast_project/crashes bash examples/crash_reporter/backend/scripts/test_remote_access_api.sh
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user