Push Tracker
ria-ran--sim-drop/plan/11-readme.md
A ashkan@beigi.net 8672b0de6b Add Phase-1 eSIM provisioning implementation
Full working closed-loop eSIM provisioning stack (spec in claude.md / plan/):
Flask API, SQLite subscriber store, credential/profile generator, Open5GS
and free5gc core adapters, captive portal, operational scripts, systemd
units, network configs, and a 44-test suite.

Profile generation currently returns a mock JSON profile; real SGP.22
generation via pySim is the planned Phase-2 upgrade.

Fixes two bugs found while getting the suite green:
- generate_imsi hardcoded a 10-digit MSIN, producing 16-digit IMSIs for a
  3-digit MNC; MSIN length is now 15 - len(mcc) - len(mnc).
- check_rate_limit compared timestamps as strings across mismatched formats
  (SQLite CURRENT_TIMESTAMP vs Python isoformat); both sides now normalized
  via SQLite datetime() so the window check is chronologically correct.

Add .gitignore for venv, caches, runtime config.yaml, and databases.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 05:56:31 +00:00

5.2 KiB

Unit 11 — README.md

Goal

Write the main README.md at the project root. This is the last unit — written after all code exists.

File

  • README.md

Required Sections

Header

  • Project name + one-line description
  • Badges (optional): Python version, license

Architecture Diagram

Copy from design.md:

┌─────────────────────────────────────────┐
│  Server Host (srsRAN gNB)               │
│  - srsRAN gNB                           │
│  - Open5GS Core (or free5gc)            │
│  - Subscriber database                  │
└─────────────┬───────────────────────────┘
              │ 5G NR
              ▼
┌─────────────────────────────────────────┐
│  UE WiFi AP Drop                        │
│  (Android device or Raspberry Pi)       │
│  - WiFi AP (open network)               │
│  - eSIM Provisioning Server             │
│  - Captive Portal                       │
└─────────────┬───────────────────────────┘
              │ WiFi
              ▼
       End User Devices

User Flow (numbered list)

  1. User connects to open WiFi Emergency-5G
  2. Captive portal auto-redirects to activation page
  3. User taps "Activate eSIM"
  4. Server generates IMSI/Ki/OPc/ICCID
  5. eSIM profile downloaded to device
  6. User installs profile via Settings
  7. Device connects to 5G network automatically

System Requirements

Raspberry Pi:

  • Raspberry Pi 4 (4GB+ RAM)
  • Quectel RM500Q 5G modem (or compatible)
  • Raspberry Pi OS Lite 64-bit
  • Python 3.11+

Android:

  • Android 9+ with Termux (F-Droid)
  • 5G-capable device
  • Pre-provisioned SIM for gNB backhaul

End-user devices:

  • eSIM-capable device (eUICC support)
  • Any OS (Android, iOS, Windows)

Quick Start (5 commands)

git clone <repo>
cd esim-provisioning
python3 -m venv venv && source venv/bin/activate
pip install -r requirements.txt
cp config.yaml.example config.yaml   # edit as needed
python scripts/init_db.py
python -m server.app
# → Server running at http://localhost:5000

Configuration Guide

Key config.yaml fields:

Field Description Example
network.mcc Mobile Country Code "302"
network.mnc Mobile Network Code "720"
network.op_key Operator key (hex, 16 bytes) "63bfa..."
wifi.ip WiFi AP IP address "192.168.4.1"
database.path SQLite database path "/opt/.../subscribers.db"
rate_limiting.window_hours Rate limit window 1
core.type Core adapter "open5gs" / "none"
core.mongodb_uri MongoDB connection "mongodb://localhost:27017"

Raspberry Pi Installation

Reference scripts/setup_wifi_ap.sh for automated setup, or follow manual steps from configs/ directory.

Android / Termux Installation

bash android/termux_setup.sh
~/esim-provisioning/start.sh

See android/README.md for detailed instructions and limitations.

API Reference

Endpoint Method Description
/activate GET Captive portal page
/api/provision POST Generate eSIM profile
/api/profile/<id> GET Download profile
/api/export GET Export all subscribers (JSON)
/api/status GET Health check

Troubleshooting

Profile generation fails:

Check: python -c "from server.profile_generator import generate_ki; print(generate_ki().hex())"
Check: OP key is 32 hex chars (16 bytes) in config.yaml

Captive portal not showing:

Check: nslookup google.com 192.168.4.1  → should return 192.168.4.1
Check: systemctl status dnsmasq nginx
Check: iptables -t nat -L PREROUTING

5G authentication fails after eSIM install:

Check: IMSI/Ki/OPc in subscriber database matches what's in Open5GS
Check: PLMN (MCC+MNC) matches gNB configuration
Check: python scripts/sync_subscribers.py
Check: Open5GS UDM/AMF logs: journalctl -u open5gs-udmd

Rate limit blocking legitimate user:

-- Find and clear rate limit for a MAC:
sqlite3 /path/to/subscribers.db \
  "DELETE FROM subscribers WHERE mac_address='aa:bb:cc:dd:ee:ff';"

Architecture Notes

  • Adapter pattern: Adding a new core (e.g., srsRAN-CN) requires only a new class in server/core_adapters/
  • IMSI space: 10^10 possible MSINs per MCC+MNC — effectively unlimited for field use
  • Rate limiting: Per MAC address, 1 profile per hour window. SQLite-backed, survives restarts
  • Profile format: Phase 1 mock (JSON bytes). Phase 2: real SGP.22 via pySim for eUICC compatibility

License

MIT (or as appropriate for deployment context)


Writing Notes

When writing the actual README.md:

  • Keep it scannable — use tables, code blocks, headers
  • Lead with the architecture diagram
  • Quick Start must work in <5 minutes on a fresh Pi
  • Troubleshooting section is critical — include it prominently
  • Do not duplicate design.md — link to it for deep dives