chore: blog full QR output + dashboard screenshot, hero script phone setup scene
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -132,20 +132,41 @@ $ numa setup-phone
|
|||||||
|
|
||||||
Numa Phone Setup
|
Numa Phone Setup
|
||||||
|
|
||||||
Profile URL: http://192.168.1.16:8765/mobileconfig
|
Profile URL: http://192.168.1.10:8765/mobileconfig
|
||||||
|
|
||||||
█▀▀▀▀▀▀▀█▀▀██ ██ ▀█▀▀▀▀▀▀▀█
|
█████████████████████████████████████
|
||||||
█ █▀▀▀█ █▀▄▀▀▀▀▄▄█ █▀▀▀█ █
|
█████████████████████████████████████
|
||||||
...
|
████ ▄▄▄▄▄ ██ ▀█ ▀▀▀▄▀ ▀▀█ ▄▄▄▄▄ ████
|
||||||
|
████ █ █ █ ▄▀ ▄█▀▄▀█▄▀█ █ █ ████
|
||||||
|
████ █▄▄▄█ █ ▀▄▄ ▀ █▄▀▀█▀█ █▄▄▄█ ████
|
||||||
|
████▄▄▄▄▄▄▄█ ▀▄▀▄█▄█ █▄█▄█▄▄▄▄▄▄▄████
|
||||||
|
████ ▀▄▄▄▄▄█▀ ▀██▄ ▄ ▄▀█▀█ ▄ ▄▄█▀████
|
||||||
|
█████▄▄▀▄▀▄▄█▄ ▀████▀▄▄▀█▀▀▄ ██▀█████
|
||||||
|
████▄██▄ ▀▄ █ █ █▀█▄▄██ ▄▄▀▄▀▄ █▀████
|
||||||
|
█████ ▀ ▄▀ ▄▀▄ ▄▄▀ ██ ▄▀██▄▀█████
|
||||||
|
████ ▀▀ █▄█▄▀ ▄ █▄ ▄█▀▄ ▀█▀▀ █▀████
|
||||||
|
████ ██▀█ ▄▄▀█▄▄██▀▄▀ ▀█▄▀ █▀▄▄▀█████
|
||||||
|
████▄█▄▄▄▄▄█▀▄█▄█▀▀ ▀██▀ ▄▄▄ ▀ ████
|
||||||
|
████ ▄▄▄▄▄ █▀▀▀▀ ▄█▀ ▀▄ █▄█ ▄▄▀█████
|
||||||
|
████ █ █ █ ▄ ██▀▄ ▄▄██ ▄ ▄▄▄██████
|
||||||
|
████ █▄▄▄█ █▄ ▄▀▀▄▄█▀▄▀▄ ▀▄▀ ▄█ █████
|
||||||
|
████▄▄▄▄▄▄▄█▄▄█▄▄▄█▄█▄▄██████▄▄██████
|
||||||
|
█████████████████████████████████████
|
||||||
|
|
||||||
On your iPhone:
|
On your iPhone:
|
||||||
1. Open Camera, point at the QR code, tap the yellow banner
|
1. Open Camera, point at the QR code, tap the yellow banner
|
||||||
2. Allow the download when Safari asks
|
2. Allow the download when Safari asks
|
||||||
3. Settings → "Profile Downloaded" → Install
|
3. Open Settings — tap "Profile Downloaded" near the top
|
||||||
4. Settings → General → About → Certificate Trust Settings
|
(or: Settings → General → VPN & Device Management → Numa DNS)
|
||||||
|
4. Tap Install (top right), enter passcode, Install again
|
||||||
|
5. Settings → General → About → Certificate Trust Settings
|
||||||
Toggle ON "Numa Local CA" — required for DoT to work
|
Toggle ON "Numa Local CA" — required for DoT to work
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The same QR is available in the dashboard — click "Phone Setup" in the header and the popover renders an SVG QR code pointing at the mobileconfig URL. On mobile viewports it shows a direct download link instead.
|
||||||
|
|
||||||
|
<img src="../phone-setup-dashboard.png" alt="Numa dashboard with Phone Setup popover showing QR code and install instructions">
|
||||||
|
|
||||||
Step 4 is non-negotiable. Even though the CA is bundled in the same profile that installs the DNS settings, iOS still requires the user to explicitly toggle trust in Certificate Trust Settings. It's a deliberate iOS policy to prevent profile-based trust injection — annoying, and correct.
|
Step 4 is non-negotiable. Even though the CA is bundled in the same profile that installs the DNS settings, iOS still requires the user to explicitly toggle trust in Certificate Trust Settings. It's a deliberate iOS policy to prevent profile-based trust injection — annoying, and correct.
|
||||||
|
|
||||||
I've been dogfooding this since v0.10 shipped in early April. The phone resolves through Numa over DoT whenever I'm home; persistent connections are visible in the log as a single source port living through dozens of queries. The one real caveat: if the laptop's LAN IP changes, the profile breaks. [RFC 9462 DDR](https://datatracker.ietf.org/doc/html/rfc9462) fixes that — Numa can respond to `_dns.resolver.arpa IN SVCB` with its current IP and iOS picks it up on each network join. Next piece of work.
|
I've been dogfooding this since v0.10 shipped in early April. The phone resolves through Numa over DoT whenever I'm home; persistent connections are visible in the log as a single source port living through dozens of queries. The one real caveat: if the laptop's LAN IP changes, the profile breaks. [RFC 9462 DDR](https://datatracker.ietf.org/doc/html/rfc9462) fixes that — Numa can respond to `_dns.resolver.arpa IN SVCB` with its current IP and iOS picks it up on each network join. Next piece of work.
|
||||||
|
|||||||
@@ -7,18 +7,19 @@
|
|||||||
# The script:
|
# The script:
|
||||||
# 1. Opens the dashboard in Chrome --app mode (clean, no address bar)
|
# 1. Opens the dashboard in Chrome --app mode (clean, no address bar)
|
||||||
# 2. Generates DNS traffic (forward, cache hit, blocked)
|
# 2. Generates DNS traffic (forward, cache hit, blocked)
|
||||||
# 3. Types "peekm" / "6419" into the Local Services form on camera
|
# 3. Opens Phone Setup QR popover
|
||||||
# 4. Shows LAN accessibility badge ("local only" / "LAN")
|
# 4. Types "peekm" / "6419" into the Local Services form on camera
|
||||||
# 5. Checks a blocked domain
|
# 5. Shows LAN accessibility badge ("local only" / "LAN")
|
||||||
# 6. Opens peekm.numa to show the proxy working
|
# 6. Checks a blocked domain
|
||||||
# 7. Records via ffmpeg and converts to optimized GIF
|
# 7. Opens peekm.numa to show the proxy working
|
||||||
|
# 8. Records via ffmpeg and converts to optimized GIF
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
# --------------- Configuration ---------------
|
# --------------- Configuration ---------------
|
||||||
OUTPUT="${1:-assets/hero-demo.gif}"
|
OUTPUT="${1:-assets/hero-demo.gif}"
|
||||||
PORT=5380
|
PORT=5380
|
||||||
RECORD_SECONDS=20
|
RECORD_SECONDS=24
|
||||||
VIEWPORT_W=1800
|
VIEWPORT_W=1800
|
||||||
VIEWPORT_H=1100
|
VIEWPORT_H=1100
|
||||||
FPS=12
|
FPS=12
|
||||||
@@ -230,8 +231,16 @@ dig @127.0.0.1 github.com +short > /dev/null 2>&1
|
|||||||
dig @127.0.0.1 ad.doubleclick.net +short > /dev/null 2>&1
|
dig @127.0.0.1 ad.doubleclick.net +short > /dev/null 2>&1
|
||||||
sleep 3
|
sleep 3
|
||||||
|
|
||||||
# --------------- Scene 2: Add peekm service via UI (3-7s) ---------------
|
# --------------- Scene 2: Phone Setup popover (3-7s) ---------------
|
||||||
log "Scene 2: Adding peekm.numa service..."
|
log "Scene 2: Phone Setup QR popover..."
|
||||||
|
run_js "document.querySelector('#phoneSetup button').click();"
|
||||||
|
sleep 3
|
||||||
|
# Dismiss popover
|
||||||
|
run_js "document.getElementById('phoneSetupPopover').style.display = 'none';"
|
||||||
|
sleep 1
|
||||||
|
|
||||||
|
# --------------- Scene 3: Add peekm service via UI (7-11s) ---------------
|
||||||
|
log "Scene 3: Adding peekm.numa service..."
|
||||||
|
|
||||||
# Services panel is now first — scroll to it
|
# Services panel is now first — scroll to it
|
||||||
run_js "
|
run_js "
|
||||||
@@ -249,18 +258,18 @@ sleep 0.3
|
|||||||
run_js "document.querySelector('#serviceForm .btn-add').click();"
|
run_js "document.querySelector('#serviceForm .btn-add').click();"
|
||||||
sleep 2
|
sleep 2
|
||||||
|
|
||||||
# --------------- Scene 3: Open peekm.numa (7-11s) ---------------
|
# --------------- Scene 4: Open peekm.numa (11-15s) ---------------
|
||||||
log "Scene 3: Opening peekm.numa in browser..."
|
log "Scene 4: Opening peekm.numa in browser..."
|
||||||
open "http://peekm.numa/view/peekm/README.md" 2>/dev/null || true
|
open "http://peekm.numa/view/peekm/README.md" 2>/dev/null || true
|
||||||
sleep 4
|
sleep 4
|
||||||
|
|
||||||
# --------------- Scene 4: Back to dashboard (11-14s) ---------------
|
# --------------- Scene 5: Back to dashboard (15-18s) ---------------
|
||||||
log "Scene 4: Back to dashboard — LAN badges + LOCAL queries visible..."
|
log "Scene 5: Back to dashboard — LAN badges + LOCAL queries visible..."
|
||||||
osascript -e "tell application \"System Events\" to set frontmost of (first process whose unix id is $CHROME_PID) to true" 2>/dev/null || true
|
osascript -e "tell application \"System Events\" to set frontmost of (first process whose unix id is $CHROME_PID) to true" 2>/dev/null || true
|
||||||
sleep 3
|
sleep 3
|
||||||
|
|
||||||
# --------------- Scene 5: Check Domain blocker (14-17s) ---------------
|
# --------------- Scene 6: Check Domain blocker (18-21s) ---------------
|
||||||
log "Scene 5: Check Domain — blocked tracker..."
|
log "Scene 6: Check Domain — blocked tracker..."
|
||||||
# Scroll down to blocking panel
|
# Scroll down to blocking panel
|
||||||
run_js "
|
run_js "
|
||||||
var blockPanel = document.getElementById('blockingPanel');
|
var blockPanel = document.getElementById('blockingPanel');
|
||||||
@@ -273,8 +282,8 @@ sleep 0.3
|
|||||||
run_js "document.querySelector('#checkDomainInput').closest('form').querySelector('.btn').click();"
|
run_js "document.querySelector('#checkDomainInput').closest('form').querySelector('.btn').click();"
|
||||||
sleep 2
|
sleep 2
|
||||||
|
|
||||||
# --------------- Scene 6: Terminal-style dig overlay (17-20s) ---------------
|
# --------------- Scene 7: Terminal-style dig overlay (21-24s) ---------------
|
||||||
log "Scene 6: dig proof overlay..."
|
log "Scene 7: dig proof overlay..."
|
||||||
DIG_RESULT=$(dig @127.0.0.1 peekm.numa +short 2>/dev/null | head -1)
|
DIG_RESULT=$(dig @127.0.0.1 peekm.numa +short 2>/dev/null | head -1)
|
||||||
run_js "
|
run_js "
|
||||||
var overlay = document.createElement('div');
|
var overlay = document.createElement('div');
|
||||||
|
|||||||
BIN
site/blog/phone-setup-dashboard.png
Normal file
BIN
site/blog/phone-setup-dashboard.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 310 KiB |
Reference in New Issue
Block a user