# Captive Portal Deployment Notes

**Date**: 2026-01-06
**Status**: Ready to deploy on live Pi

## Summary

Added captive portal detection to nginx configuration. This enables automatic popup on devices when they connect to the Dangerous-Pi WiFi network.

## What Was Changed

### Files Modified

1. **pi-gen pipeline** (for future builds):
   - `pi-gen/stageDangerousPi/01-Wireless-AP/00-run-chroot.sh`

2. **Local nginx config** (reference):
   - `nginx/dangerous-pi.conf`

### Changes Made

Added OS connectivity check endpoints to nginx:

| Endpoint | OS/Browser | Response |
|----------|-----------|----------|
| `/generate_204` | Android/Chrome | 204 No Content |
| `/gen_204` | Android alternate | 204 No Content |
| `/connectivitycheck/gstatic/generate_204` | Google services | 204 No Content |
| `/hotspot-detect.html` | iOS/macOS | 200 + HTML |
| `/library/test/success.html` | iOS alternate | 200 + HTML |
| `/connecttest.txt` | Windows 10/11 | 200 + text |
| `/ncsi.txt` | Windows NCSI | 200 + text |
| `/success.txt` | Firefox | 200 + text |
| `/kindle-wifi/wifistub.html` | Kindle/Amazon | 200 + HTML |

## Deploy on Live Pi

### Option 1: Copy nginx config directly

```bash
# SSH into the Pi
ssh dt@dangerous-pi.local

# Backup existing config
sudo cp /etc/nginx/sites-available/dangerous-pi.conf /etc/nginx/sites-available/dangerous-pi.conf.bak

# Copy the new config (from your dev machine)
# On dev machine:
scp nginx/dangerous-pi.conf dt@dangerous-pi.local:/tmp/

# On Pi:
sudo cp /tmp/dangerous-pi.conf /etc/nginx/sites-available/dangerous-pi.conf

# Test nginx config
sudo nginx -t

# Reload nginx
sudo systemctl reload nginx
```

### Option 2: Manual edit on Pi

Add the following block to `/etc/nginx/sites-available/dangerous-pi.conf` **before** the `location /api/` block:

```nginx
    # ===========================================
    # CAPTIVE PORTAL DETECTION
    # ===========================================
    # These endpoints respond to OS connectivity checks.
    # When a device connects to the AP, the OS checks these URLs.
    # By responding correctly, we trigger the captive portal popup.

    # Android / Chrome OS connectivity check
    location = /generate_204 {
        return 204;
    }

    # Additional Android check paths
    location = /gen_204 {
        return 204;
    }

    # Google connectivity check
    location = /connectivitycheck/gstatic/generate_204 {
        return 204;
    }

    # iOS / macOS captive portal detection
    location = /hotspot-detect.html {
        return 200 '<HTML><HEAD><TITLE>Success</TITLE></HEAD><BODY>Success</BODY></HTML>';
        add_header Content-Type text/html;
    }

    # iOS alternate path
    location = /library/test/success.html {
        return 200 '<HTML><HEAD><TITLE>Success</TITLE></HEAD><BODY>Success</BODY></HTML>';
        add_header Content-Type text/html;
    }

    # Windows 10/11 connectivity check
    location = /connecttest.txt {
        return 200 'Microsoft Connect Test';
        add_header Content-Type text/plain;
    }

    # Windows NCSI check
    location = /ncsi.txt {
        return 200 'Microsoft NCSI';
        add_header Content-Type text/plain;
    }

    # Firefox / Mozilla connectivity check
    location = /success.txt {
        return 200 'success';
        add_header Content-Type text/plain;
    }

    # Kindle / Amazon devices
    location = /kindle-wifi/wifistub.html {
        return 200 '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"><html><head><title>Kindle</title></head><body>81ce4465-7167-4dcb-835b-dcc9e44c112a</body></html>';
        add_header Content-Type text/html;
    }

    # ===========================================
    # END CAPTIVE PORTAL DETECTION
    # ===========================================
```

Then reload nginx:
```bash
sudo nginx -t && sudo systemctl reload nginx
```

## Testing

### Test from a mobile device

1. Forget the "Dangerous-Pi" network on your phone
2. Reconnect to "Dangerous-Pi" WiFi
3. You should see a captive portal popup automatically
4. Clicking it should open the Dangerous Pi web interface

### Test manually with curl

```bash
# Android check (should return empty 204)
curl -v http://192.168.4.1/generate_204

# iOS check (should return HTML)
curl -v http://192.168.4.1/hotspot-detect.html

# Windows check (should return "Microsoft Connect Test")
curl -v http://192.168.4.1/connecttest.txt

# Firefox check (should return "success")
curl -v http://192.168.4.1/success.txt
```

## How It Works

1. **DNS**: dnsmasq already redirects ALL DNS queries to 192.168.4.1 (`address=/#/192.168.4.1`)
2. **HTTP**: When the OS checks connectivity URLs, nginx now responds correctly
3. **Detection**: OS sees the expected response and knows internet is available
4. **Popup**: Because DNS resolved to the AP but responses are correct, OS triggers captive portal UI

## Troubleshooting

### No popup appears

1. Check nginx is running: `sudo systemctl status nginx`
2. Check nginx config: `sudo nginx -t`
3. Check dnsmasq is running: `sudo systemctl status dnsmasq`
4. Verify DNS redirect: `nslookup google.com` (should resolve to 192.168.4.1)

### Popup appears but shows error

1. Check frontend is running: `curl http://localhost:3000`
2. Check backend is running: `curl http://localhost:8000/api/health`
3. Check nginx logs: `sudo tail -f /var/log/nginx/error.log`

### Some devices don't show popup

Different devices use different detection URLs. The current config covers:
- Android (all versions)
- iOS / macOS
- Windows 10/11
- Firefox
- Kindle

If a specific device doesn't work, check its connectivity check URL and add it to nginx.

## Future Improvements

- [ ] Add Samsung-specific detection URLs if needed
- [ ] Consider adding a redirect for unknown hosts to `/` (requires `if` statement)
- [ ] Monitor nginx access logs to discover new detection URLs
