# Sharing Controls — Setup & Operations Guide

## What this system does

- Provides a dashboard panel (`/sharing.html`) to toggle Tailscale Funnel on/off
- Restricts sensitive pages (`/security.html`, `/sharing.html`) to LAN and Tailscale VPN only
- Auto-disables the Funnel after a configurable TTL (default 60 min)
- All funnel operations require an admin token header + LAN/Tailscale source IP

---

## 1. DASH_ADMIN_TOKEN setup (required before toggle works)

Generate a random token and add it to the edureach backend environment:

```bash
# Generate a token
openssl rand -hex 32

# Add to ~/edureach/.env (create if not exists):
echo "DASH_ADMIN_TOKEN=<your-token-here>" >> ~/edureach/.env

# OR export directly (not persistent across restarts):
export DASH_ADMIN_TOKEN=<your-token-here>
```

Then restart the backend container so it picks up the new env var:

```bash
cd ~/edureach && docker compose restart backend
```

> ⚠️  Never commit DASH_ADMIN_TOKEN to git. The .env file is already gitignored.

---

## 2. Install cron jobs (required for toggle + auto-disable)

Run `crontab -e` as jbaby and add:

```cron
# Funnel cron helper — processes queued enable/disable commands (every minute)
* * * * * /home/jbaby/server-dashboard/scripts/funnel-cron-helper.sh >> /tmp/funnel-cron.log 2>&1

# Funnel auto-stop — disables funnel when TTL expires (every 5 minutes)
*/5 * * * * /home/jbaby/server-dashboard/scripts/funnel-autostop.sh >> /tmp/funnel-autostop.log 2>&1
```

Make scripts executable:
```bash
chmod +x /home/jbaby/server-dashboard/scripts/funnel-*.sh
```

Verify cron is installed:
```bash
crontab -l | grep funnel
```

---

## 3. Sudoers (only needed if tailscale requires root)

Test first — on this system `jbaby` can typically run tailscale without sudo:
```bash
tailscale funnel status
```

If the above fails with "permission denied", add a sudoers rule:

```bash
# Create drop-in file (DO NOT edit /etc/sudoers directly):
sudo visudo -f /etc/sudoers.d/funnel-scripts
```

Add ONLY these lines (replace jbaby if your username differs):
```
# Allow jbaby to run funnel control scripts without password
jbaby ALL=(ALL) NOPASSWD: /home/jbaby/server-dashboard/scripts/funnel-enable.sh
jbaby ALL=(ALL) NOPASSWD: /home/jbaby/server-dashboard/scripts/funnel-disable.sh
jbaby ALL=(ALL) NOPASSWD: /home/jbaby/server-dashboard/scripts/funnel-cron-helper.sh
jbaby ALL=(ALL) NOPASSWD: /home/jbaby/server-dashboard/scripts/funnel-autostop.sh
```

Then update the scripts to use `sudo tailscale` instead of `tailscale`.

---

## 4. Initial state file

The sharing controls read from `~/edureach/data/sharing_state.json`.
On first run, the cron helper creates this file automatically.

To manually bootstrap (reflecting the current "funnel is ON" state):
```bash
cat > ~/edureach/data/sharing_state.json <<'EOF'
{
  "funnel_on": true,
  "last_toggled": null,
  "expires": null,
  "ttl_minutes": null,
  "target": "http://127.0.0.1:9000",
  "public_url": "https://brinkbox1.tail4dec02.ts.net",
  "actual_funnel_on": true,
  "last_state_sync": null,
  "note": "Bootstrapped manually — funnel was already on at deploy time"
}
EOF
```

---

## 5. How the toggle works (flow)

```
User clicks Enable on sharing.html (LAN/TS only)
  → POST /api/sharing/funnel/enable  {ttl_minutes: 60}
    → X-Dash-Admin-Token checked
    → IP checked (must be 10.0.0.0/24 or 100.64.0.0/10)
    → Rate limit: 5s cooldown
    → Writes ~/edureach/data/funnel_cmd.json = {action: "enable", ttl_minutes: 60}
    → Returns 200 {status: "queued"}

  Dashboard shows "⏳ Queued..." and polls every 5s

On the host, cron fires (within 60 seconds):
  funnel-cron-helper.sh
    → Reads funnel_cmd.json
    → Runs funnel-enable.sh (calls: tailscale funnel --bg 9000)
    → Updates sharing_state.json {funnel_on: true, expires: <now+60min>}
    → Deletes funnel_cmd.json

Dashboard next poll: shows "🌐 Funnel ON — Public demo mode"
```

---

## 6. Security page access restriction

`/security.html` and `/sharing.html` are restricted at the nginx level:
- Allowed: `10.0.0.0/24` (LAN)
- Allowed: `100.64.0.0/10` (Tailscale CGNAT — direct VPN peer access)
- Denied: everything else (includes Tailscale Funnel public traffic, which arrives as `127.0.0.1`)

Flask API endpoints `/api/sharing/*` enforce the same IP check at the app layer.

---

## 7. Verify funnel status manually

```bash
# Check current funnel state
tailscale funnel status

# Check serving config
tailscale serve status

# Run enable manually (host-side)
/home/jbaby/server-dashboard/scripts/funnel-enable.sh

# Run disable manually (host-side)
/home/jbaby/server-dashboard/scripts/funnel-disable.sh
```

---

## 8. Rollback

To remove all sharing-controls changes:

```bash
# server-dashboard repo
cd ~/server-dashboard && git checkout copy-edits

# edureach repo
cd ~/edureach && git checkout master

# Remove cron entries
crontab -e  # delete the two funnel lines

# Remove state files
rm -f ~/edureach/data/funnel_cmd.json ~/edureach/data/sharing_state.json

# Reload nginx (dashboard)
docker exec edureach-dashboard-1 nginx -s reload
```

---

## 9. Logs

| Log file | Contents |
|---|---|
| `/tmp/funnel-cron.log` | cron-helper output (command execution) |
| `/tmp/funnel-autostop.log` | auto-stop check output |

Tail both:
```bash
tail -f /tmp/funnel-cron.log /tmp/funnel-autostop.log
```
