fork: initialize Mycellium UI Private from Mycell-UI@5229e2c

This repo is a hard fork of mycellium-ui dedicated to the
mycelium-private experimental track upstream. The two apps coexist
on the same machine via distinct app identifiers, polkit actions,
and binary names.

Renames
- package + crate: mycellium-ui → mycellium-ui-private
- bundle identifier: tech.threefold.mycellium-ui-private
- daemon binary: mycelium-private (separate upstream release tarball)
- bootstrap wrapper: /usr/bin/mycellium-bootstrap-private
- polkit policy file + action id

Functional changes
- SidecarConfig.network_name field (UTF-8, 2..=64 bytes)
- start() refuses to spawn without a network name AND a 32-byte
  key file at app_data_dir/network_key.bin; surfaces a clear
  error rather than letting mycelium-private fail mid-startup
- network_key_status / generate / import / export / delete
  commands; uses OS RNG (rand) and writes 0600
- empty default peers list (no Threefold seed for private overlays)
- new Settings → Private network panel: name input, key generate /
  reveal-hex / import / delete, status indicator

Adapted bootstrap script kills both `mycelium` and
`mycelium-private` orphans (cross-clash on UDP/9650 + TCP/8990).

CI workflow + sidebar branding updated. The README explains the
divergence model and how to cherry-pick upstream fixes.
This commit is contained in:
syoul
2026-04-27 01:35:11 +02:00
parent 5229e2c774
commit 8b83fc10d5
22 changed files with 610 additions and 183 deletions

135
README.md
View File

@@ -1,37 +1,26 @@
# mycellium-ui
# mycellium-ui-private
Cross-platform desktop GUI for [Mycelium](https://github.com/threefoldtech/mycelium) — Threefold's end-to-end encrypted IPv6 overlay network.
Desktop GUI for joining a **private** [Mycelium](https://github.com/threefoldtech/mycelium) overlay network — a self-contained IPv6 mesh isolated from the public Mycelium network by a shared 32-byte key.
The app embeds the official `mycelium` binary as a Tauri sidecar and pilots it through its HTTP API on a loopback ephemeral port. Root privileges (required to create the TUN interface) are obtained via `pkexec`.
This is a fork of [`mycellium-ui`](https://git.open.us.org/syoul/Mycell-UI) (the public-network variant). Code structure is identical; only the bundled daemon (`mycelium-private` instead of `mycelium`), the default config (no public seed peer), and a new "Private network" panel in Settings differ.
The two apps are designed to **coexist** on the same machine: distinct app identifier (`tech.threefold.mycellium-ui-private`), distinct binary (`/usr/bin/mycellium-ui-private`), distinct polkit action.
## What's a private network?
Mycelium 0.6.1 ships an opt-in mode where every packet is wrapped under an additional symmetric key. Two nodes only see each other if:
1. They run the `mycelium-private` daemon (not the public `mycelium`).
2. They were both started with the same `--network-name` (UTF-8, 264 bytes — public, e.g. `acme-corp-private`).
3. They were both started with `--network-key-file` pointing at the same 32-byte secret.
Without the right name+key, peers reject each other at the handshake. There's no Threefold-operated bootstrap node for private networks — the operator distributes the key out-of-band and brings up at least one reachable peer (typically a VPS) that other nodes can dial.
## Status
v1, Linux-only. Implements the full `docs/api.yaml` surface of mycelium v0.6.1: admin, peers (CRUD), routes (selected/fallback/queried), messages (send/receive/reply/status), topics (default + whitelist + sources + forward), pubkey lookup.
v0.1, Linux-only. Same UI surface as the public variant. **Marked experimental upstream** (`docs/private_network.md` in the mycelium repo).
## Architecture
```
┌──────────────────────────────────────────────────────────────┐
│ WebView (Vue 3 + TS + Tailwind + radix-vue + Pinia) │
│ Status / Peers / Routes / Messages / Topics / Settings │
└────────────────┬─────────────────────────────────────────────┘
│ invoke() / Tauri events
┌────────────────┴─────────────────────────────────────────────┐
│ Tauri core (Rust, tokio + reqwest) │
│ • sidecar.rs — supervises mycelium via pkexec │
│ • api/* — typed REST client │
│ • poller.rs — emits peers://, stats://, routes://, messages://incoming │
└────────────────┬─────────────────────────────────────────────┘
│ HTTP loopback :ephemeral
┌────────────────┴─────────────────────────────────────────────┐
│ mycelium daemon (sidecar binary, runs as root via pkexec) │
│ TUN0 ◄─► overlay network │
└──────────────────────────────────────────────────────────────┘
```
There is no Unix socket / named pipe IPC — the daemon's own HTTP API is the integration point.
## Prerequisites (Debian / Ubuntu)
## Setup (dev)
```bash
sudo apt install -y \
@@ -40,72 +29,56 @@ sudo apt install -y \
build-essential curl wget file libssl-dev libgtk-3-dev libxdo-dev \
pkg-config policykit-1
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
```
Then Node 20+ and pnpm 10+.
## Setup
```bash
# 1. Install JS deps
pnpm install
# 2. Fetch the mycelium sidecar binary for your target triple
bash scripts/fetch-mycelium.sh # uses MYCELIUM_VERSION (default v0.6.1)
# or: MYCELIUM_VERSION=v0.6.1 bash scripts/fetch-mycelium.sh
# 3. Run in dev
bash scripts/fetch-mycelium.sh # downloads mycelium-private v0.6.1
pnpm tauri dev
```
The first start triggers a `pkexec` dialog asking you to authenticate; the polkit policy installed by the `.deb` caches the auth for the user session.
On first launch:
## Build
1. Open **Settings → Private network**.
2. Type a network name (e.g. `acme-corp-private`).
3. Click **Generate 32-byte key** (or **Import** a key already shared with you).
4. Click **Reveal hex** and share the hex string out-of-band with your other nodes.
5. Save daemon configuration (add at least one bootstrap peer).
6. Click **Start daemon** in the sidebar.
Other nodes paste the same hex into their **Import** field and use the same network name.
## Build a `.deb`
```bash
pnpm tauri build # → src-tauri/target/release/bundle/{deb,appimage}/
pnpm tauri build --bundles deb
# → src-tauri/target/release/bundle/deb/Mycellium UI Private_*.deb
```
The `.deb` declares `Depends: policykit-1` and ships the polkit policy under `/usr/share/polkit-1/actions/tech.threefold.mycellium-ui.policy`. The AppImage relies on `pkexec` being present on the host — on systems without polkit, fall back to running with `sudo` after disabling the sidecar's pkexec wrapper.
The `.deb` declares `Depends: pkexec | policykit-1` (Debian 12 + 13 covered) and ships:
- `/usr/bin/mycellium-ui-private` (GUI)
- `/usr/bin/mycelium-private` (daemon)
- `/usr/bin/mycellium-bootstrap-private` (cleanup wrapper for orphan handling)
- `/usr/share/polkit-1/actions/tech.threefold.mycellium-ui-private.policy`
## Layout
## Diverging from upstream
```
src/ # Vue 3 frontend
views/ # one file per nav item
components/ # shadcn-style UI primitives + dialogs
stores/ # Pinia: node, peers, routes, messages, topics, config
lib/ # api wrapper, events, base64 + format helpers
src-tauri/
src/
sidecar.rs # spawn + supervise mycelium
elevation.rs # pkexec command builder
poller.rs # 3 background loops (peers, routes, inbox long-poll)
api/ # REST client modules (admin, peers, routes,
# messages, topics, pubkey)
commands.rs # #[tauri::command] handlers, 1:1 with REST
error.rs # AppError + Serialize-as-string for invoke()
binaries/ # gitignored; populated by scripts/fetch-mycelium.sh
packaging/polkit/ # XML policy bundled into the .deb
scripts/fetch-mycelium.sh
.github/workflows/ci.yml # pnpm typecheck + cargo fmt/clippy/test
This fork tracks `Mycell-UI` upstream as `origin/upstream` (after running the `git remote add upstream ...` step). To pull bugfixes:
```bash
git fetch upstream
git cherry-pick <upstream-commit>
```
## Verification matrix
Most fixes will apply cleanly because the only divergence is in:
- `src-tauri/src/sidecar.rs` (network_name + key_file args)
- `src-tauri/src/commands.rs` (network_key_* commands)
- `src-tauri/packaging/` (different bootstrap script + polkit policy)
- `src-tauri/tauri.conf.json` (productName, identifier, externalBin)
- `src/views/Settings.vue` (Private network section)
- `src/stores/config.ts` (defaults)
| Test | How |
|------|-----|
| Sidecar starts under pkexec | `pnpm tauri dev`, daemon visible in `ps`, splash disappears in <10 s |
| Peers connect | Add `tcp://188.40.132.242:9651` from the Peers page; state turns to `alive` within ~10 s |
| Routes propagate | `Routes/Selected` becomes non-empty after ~30 s |
| Live event stream | Sidebar status dot tracks ready/idle, peers table updates without manual refresh |
| Bidirectional messages | Two instances on different VMs, exchange via Compose → Inbox |
| Identity regen | Settings → Regenerate; restart daemon; new IP appears on Status |
| `.deb` install | Fresh Ubuntu LTS / Debian 12; daemon spawns under polkit on first start |
## Known limitations (v0.1)
## Known limitations (v1)
- Linux only. Windows is reachable (sidecar via `runas` / Wintun driver) but not implemented.
- Auto-start at login isn't wired — the desktop entry installed by the `.deb` is the manual launcher.
- The TOML config editor in Settings only exposes `peers`, `tunName`, `noTun`. Other keys (`metricsApiAddress`, etc.) are passed-through if you edit the file directly at `~/.local/share/tech.threefold.mycellium-ui/mycelium.toml` and restart the daemon.
- `message_status` is forwarded as opaque JSON; the upstream schema isn't pinned in the spec, so we don't strongly type it.
- Linux only.
- The `mycelium-private` binary is upstream's experimental track; the API may shift in a future release.
- Network keys are stored in `$XDG_DATA_HOME/tech.threefold.mycellium-ui-private/network_key.bin` with mode `0600`. Not encrypted at rest — host-level disk encryption is the only layer.
- No multi-network support — one private overlay at a time.