A
8672b0de6b
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>
5.2 KiB
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)
- User connects to open WiFi
Emergency-5G - Captive portal auto-redirects to activation page
- User taps "Activate eSIM"
- Server generates IMSI/Ki/OPc/ICCID
- eSIM profile downloaded to device
- User installs profile via Settings
- 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