# Meshagora — Deployment & Troubleshooting

---

## Version History

### v0.2 — IP Detection & Startup Transparency
- Replaced UDP routing trick with `ifconfig` parsing for hotspot IP detection. The UDP trick failed on the Samsung A25 (and likely other Android builds) because the hotspot interface routing entry may not exist at startup. `ifconfig` reads interface addresses directly via socket ioctls — no netlink, no root, no routing assumptions.
- Startup banner now lists all detected non-loopback IPs with interface names, so if the primary guess is wrong the alternatives are immediately visible.
- Added `install_termux.sh` — one-shot setup script for Termux.
- Added `net-tools` as an explicit dependency (`ifconfig` provider).

### v0.1 — Initial prototype
- Single-file Flask app, in-memory SQLite, runs on Android/Termux hotspot.

---

## Dependencies

### Termux (Android) — required packages

| Package | Source | Purpose |
|---------|--------|---------|
| `python` | `pkg` | Runtime |
| `net-tools` | `pkg` | `ifconfig` — hotspot IP detection |
| `libjpeg-turbo` | `pkg` | JPEG support for Pillow (required by `qrcode[pil]`) |
| `libpng` | `pkg` | PNG support for Pillow (required by `qrcode[pil]`) |
| `flask` | `pip` | Web framework |
| `qrcode[pil]` | `pip` | QR code generation at `/qr` |

### Desktop (testing only)

| Package | Source | Purpose |
|---------|--------|---------|
| `flask` | `pip` | Web framework |
| `qrcode[pil]` | `pip` | QR code generation |

`ifconfig` is standard on desktop Linux/macOS — no extra install needed.

---

## Quick Start (Termux)

**First time only — install dependencies:**
```
bash install_termux.sh
```
Or manually:
```
pkg install python net-tools libjpeg-turbo libpng
pip install flask "qrcode[pil]"
```

**Every session:**
1. Enable Android mobile hotspot.
2. Open Termux and run:
   ```
   python3 meshagora.py
   ```
3. Read the startup banner — note all three keys and the Join URL.
4. Open `http://[IP]:5000/qr` on the server device and display it for participants to scan.
5. Once everyone has joined, go to `/admin` → HIDE QR.

---

## Starting the Server

1. **Enable the Android mobile hotspot before running the script.**
   IP detection reads active interfaces at startup — if the hotspot is off, the banner URL will be wrong.

2. Run:
   ```
   python3 meshagora.py
   ```

3. The startup banner prints:
   ```
   ==================================================
   MESHAGORA v2.3 — SOCIAL SANDBOX
   Admin Post Key   : [4 emoji]
   Trusted Post Key : [2 emoji]
   Default Post Key : [2 emoji]
   --------------------------------------------------
   Join URL  : http://192.168.43.1:5000/join  (wlan0)
   Also try  : http://10.0.2.5:5000/join      (rmnet0)
   QR code   : http://192.168.43.1:5000/qr
   If no URL works, run:  ifconfig | grep inet
   ==================================================
   ```
   Write down or photograph all three keys. They cannot be recovered without restarting the server (which destroys the session).

   **Reading the banner:**
   - "Join URL" is the best-guess hotspot address (`192.168.x.x` preferred).
   - "Also try" lines show other detected interfaces. The `rmnet` / `10.x.x.x` entries are mobile data — participants on the hotspot WiFi cannot reach those.
   - Samsung A25 hotspot is typically `192.168.43.1` on `wlan0`.

4. Navigate to `http://[IP]:5000/qr` on the server device and display the QR code for participants to scan.

5. Once all participants have joined, hide the QR code from the Admin Panel (`/admin` → HIDE QR).

---

## Connecting Participants

Participants need to:
1. Join the hotspot WiFi (name set by the server device's hotspot settings).
2. Open a browser and scan the QR code, or type the Join URL from the banner.
3. Go to `/join` — choose a username, Profile Key (2 emoji), and Friend Key (2 emoji).

No app install required. Works on any browser from Android 7.0+, iOS Safari, desktop Chrome/Firefox.

---

## Admin Panel

Navigate to `/admin` from any browser connected to the hotspot.
Enter the 4-emoji Admin Post Key when prompted. Authentication persists for that browser session.

**Actions available:**
- Restrict / Unrestrict / Promote / Demote individual users
- View the current Default Post Key (large, readable — copy to board or announce verbally)
- Rotate Default Key manually
- Trigger Flood Attack (creates 5 bot accounts with posts)
- Show / Hide the join QR code
- View raw database tables (users, posts, votes, reports, keys)
- **WHAT THE PLATFORM SEES** — surveillance dashboard (scroll to bottom of admin panel):
  - *Deanonymization table*: maps every session label (Anon #N) to real username, tier, post count, and net score
  - *Social graph*: all handshake pairs with CONFIRMED / PENDING status
  - *Behavioral correlations*: who voted for whom and who reported whom, cross-referenced with confirmed friendships — project mid-session for maximum pedagogical impact

---

## Stopping the Server

`Ctrl+C` in the Termux terminal. The in-memory database is destroyed immediately.
There is no persistent storage — every session starts clean.

---

## Troubleshooting

### Server prints `127.0.0.1` instead of the hotspot IP

**Important:** `127.0.0.1` is the loopback address — it only works in the browser on the server device itself. Participants on other devices will get "connection refused". Flask is still listening on all interfaces (`0.0.0.0`), so the server is reachable — you just need the correct IP.

**Step 1:** Enable the mobile hotspot *before* running `python3 meshagora.py`, then restart. The hotspot interface only appears after the hotspot is on.

**Step 2:** If still wrong, check all interfaces manually:
```
ifconfig | grep inet
```
Look for an address like `192.168.43.1` under `wlan0` — that's the hotspot gateway. Ignore `127.0.0.1` (loopback) and `10.x.x.x` under `rmnet` (mobile data).

Note: `ip addr` fails in Termux with "cannot bind netlink socket: permission denied" — always use `ifconfig` instead.

**Step 3:** Navigate to `http://[correct-ip]:5000/join` directly and distribute that URL to participants.

**Samsung A-series:** The A25 hotspot is typically `192.168.43.1` on `wlan0`. If the banner's "Join URL" shows a different address, check the "Also try" lines for the `192.168.43.1` entry.

---

### `ModuleNotFoundError: No module named 'qrcode'`

```
pip install "qrcode[pil]"
```

If it installs but the error persists:
```
python3 -m pip install "qrcode[pil]"
```

The server runs without qrcode — `/qr` returns a 404. Participants can type the join URL directly.

---

### `ModuleNotFoundError: No module named 'flask'`

```
pip install flask
```

---

### `ifconfig` command not found

```
pkg install net-tools
```

This is required for hotspot IP detection in Termux. Without it, the banner will fall back to `127.0.0.1`.

---

### Port 5000 already in use

Common on macOS (AirPlay Receiver uses 5000).

**Option A:** Kill the other process:
```
lsof -i :5000
kill [PID]
```

**Option B:** Change the port at the bottom of `meshagora.py`:
```python
app.run(host='0.0.0.0', port=5001, debug=False, threaded=False)
```
Update the join URL accordingly.

---

### Participants can't reach the server

1. Confirm participants are connected to the *hotspot WiFi*, not their mobile data or a different network.
2. Confirm the IP in the banner matches `ifconfig | grep inet` output for the `wlan0` interface.
3. Confirm port 5000 is not blocked by a firewall. On Termux this is rarely an issue on a local hotspot.
4. Try navigating to the URL from the server device's own browser first to confirm the server is responding.

---

### Android kills the server mid-session (Termux background kill)

Android aggressively kills background processes to save battery.

**Prevention:**
- In Android Settings → Apps → Termux → Battery → set to "Unrestricted" (wording varies by device).
- Keep Termux in the foreground with the screen on, or acquire a wakelock:
  ```
  termux-wake-lock
  ```
  (Requires the Termux:API app from F-Droid.)
- Keep the server device plugged in to power.

If the server is killed, all session data is lost. Restart with `python3 meshagora.py` — all keys rotate, all users must rejoin.

---

### Default Post Key stopped working for everyone

A user was restricted (by admin action or by 51% community reports). The Default Post Key rotates silently on every restriction. Check the Admin Panel for the new key and distribute it.

---

### Emoji picker doesn't appear / looks broken

The emoji picker is rendered as inline HTML buttons with basic CSS. No JavaScript framework required.

- If buttons appear but emoji don't render: the device font doesn't support those codepoints. This is rare on Android 7.0+ but possible on stripped-down browsers. Participants can type emoji directly into the visible input field.
- If the grid looks misaligned: the scroll container (`max-height: 160px; overflow-y: auto`) is intentional. Scroll within the picker to see all emoji.

---

### Post fails with "Post key incorrect." for a RESTRICTED user

RESTRICTED users require an admin co-sign. The admin must communicate the Admin Post Key directly to the restricted user for them to post. This is by design — it represents supervised posting access.

---

### Handshake says "One or both keys are incorrect."

- Both participants must submit from their own accounts (you cannot complete both sides from one account).
- Emoji must match exactly — the picker submits codepoints, not descriptions.
- Try clearing both fields and reselecting. The CLEAR button resets the hidden input.
- Verify both participants have submitted independently.

---

## Testing Checklist (Pre-Session)

- [ ] Hotspot enabled before starting server — correct IP appears in banner
- [ ] `/qr` loads a scannable QR code from the server device
- [ ] Join as User 1 from a phone — "Anon #1" assigned, Default Post Key shown on join confirmation
- [ ] Join as User 2 from a second device or incognito tab — "Anon #2" assigned
- [ ] Post from User 1 with correct Default Post Key — appears in feed
- [ ] Post from User 1 with wrong key — "Post key incorrect." error
- [ ] Vote from User 2 — score updates
- [ ] Report from User 2 — spoiler overlay appears, User 1 sees notification banner
- [ ] Admin panel accessible at `/admin` with 4-emoji Admin Post Key
- [ ] Admin restricts User 1 — Default Post Key rotates (new key visible in admin panel)
- [ ] User 1 post fails with old key, succeeds with new key (or admin co-sign)
- [ ] Handshake between User 1 and User 2 — confirmed, username appears on posts for the friend
- [ ] Friends-only toggle shows only friend posts
- [ ] Profile notes edit blocked without Profile Key, succeeds with correct key
- [ ] Hide QR via admin → `/qr` returns 404
- [ ] Flood Attack → 5 bot posts appear in feed
- [ ] Scroll to "WHAT THE PLATFORM SEES" in admin panel — all three panels render (deanonymization, social graph, behavioral correlations)
- [ ] Confirm panels are empty (no crash) on a fresh session with no posts/votes/reports
