Add PN532 toolkit firmware, web UI, and embedded SPIFFS assets

Includes ESP-IDF NFC stack (deep capture, 4K Classic geometry, UL write API,
open SoftAP), React dashboard with live tag diagnostics, and docs. README
updated for APIs and lab Wi-Fi defaults.

Made-with: Cursor
This commit is contained in:
drjones
2026-03-29 09:32:55 -07:00
parent d1068d965b
commit 8968560565
73 changed files with 8802 additions and 28 deletions

123
README.md
View File

@@ -1,16 +1,73 @@
# PN532 NFC Toolkit (ESP32-S3)
# PN532 NFC Toolkit
Production-style firmware and embedded web UI for **PN532** NFC controllers attached to **ESP32-S3** (and other ESP32-class targets with minor config tweaks).
**The browser-native NFC lab that fits in your pocket.**
ESP32-S3 + PN532 + a serious web UI — no desktop app, no dongle software, no mystery binaries. You join WiFi, open a URL, and youre operating the reader from **any phone or laptop**.
## Features
---
- **Wi-Fi AP** default: SSID `PN532-Toolkit`, password `nfc-toolkit`, URL [http://192.168.4.1](http://192.168.4.1)
- **mDNS** hostname `pn532tool.local` (HTTP port 80)
- **REST API**: poll tags, MIFARE Classic read/write, Ultralight page read, PN532 general status, raw command injection, OTA stub (`501` — extend with `esp_https_ota`)
- **WebSocket** `/ws`: continuous tag presence stream when enabled from the UI
- **Web UI** (Vite + React + Tailwind + Framer Motion): dashboard, read/analyze, write helpers, local tag library, key dictionary, raw console, settings
## Why this is the best tool for PN532 workflows
## Build — Web UI
1. **Full remote control in the browser** — Dashboard, live scan, deep capture, read/write helpers, raw PN532 frames, and status — all over HTTP + WebSocket. You can stand across the room with your phone while the hardware sits on the bench.
2. **“Deep capture” is actually deep (for a PN532)** — On each new tag we dont stop at UID: we pull **PN532 general status bytes**, **full inventory (ATQA/SAK/UID)**, then either a **MIFARE Classic sector sweep** (default key set, Key A and Key B per sector trailer) with **every readable block as hex**, or an **Ultralight/NTAG-style page sweep** until the tag stops responding. Unknown SAKs still get inventory + controller status so nothing is silently dropped.
3. **RAM session buffer with hard stop + phone download** — Captures are stored in **on-chip RAM** (default **48 KB** of NDJSON lines). When the buffer is full, **RF polling pauses** so you never lose data to silent overflow. You tap **Download NDJSON** on your phone, get a single file with every profile, then **Clear** to resume. That workflow is purpose-built for field audits and clone/research sessions.
4. **Self-hosted on the device** — Default **open SoftAP** SSID `PN532-Toolkit` (no password, lab default), **mDNS** `pn532tool.local`. No cloud, no account, no telemetry.
5. **Honest architecture** — ESP-IDF, explicit components (`pn532_host`, `nfc_engine`, `net_service`), embedded Vite/React UI flashed to SPIFFS. You can extend it like real firmware, not a black-box sketch.
6. **Raw frame escape hatch** — When the high-level UI isnt enough, hit **Raw** and send PN532 command bytes (frame wrapper handled in firmware). Thats how you stay aligned with the real chip, not a toy abstraction.
This stack is **not** a Proxmark replacement (no LF, no raw carrier manipulation). For **hosted NFC with PN532**, its built to be the **most complete pocket operator**: remote UI, deep reads, session export, and a path to grow.
---
## Remote deep capture (how to use it)
1. **Power on** → firmware starts **continuous scan** automatically (you can still toggle it on the Dashboard).
2. **Read-all** (Capture page) → enable **passive read-all** (`POST /api/session/deep`) when you want automatic full dumps per new tag into device RAM.
3. Present tags; each **new UID** appends one **NDJSON** line: full deep profile JSON.
4. When the **progress bar hits the end**, scanning **pauses** automatically.
5. Tap **Download NDJSON** on your phone (or laptop) — browser saves `pn532-deep-capture-*.ndjson`.
6. Tap **Clear buffer** to free RAM and **resume** scanning.
API (for automation):
| Method | Path | Purpose |
|--------|------|---------|
| `GET` | `/api/status` | Includes `session.usedBytes`, `maxBytes`, `lines`, `full`, `deepCapture` |
| `POST` | `/api/session/deep` | Body `{"enable":true}` — toggle deep capture |
| `GET` | `/api/session/export` | Attachment: all captured lines |
| `POST` | `/api/session/clear` | Wipe buffer, clear `full` |
WebSocket `/ws`: channels `scan` (inventory) and `capture` (recorded / bufferFull events).
### Browser memory log (nothing missed in the UI)
The SPA keeps the **last 5000** WebSocket events in **sessionStorage** (scan + capture + anything else the firmware pushes). Use the top bar **Download log JSON** to save a pretty file on your phone or PC without touching device RAM. Clear the log separately from the device capture buffer.
### “Maximum sensitivity” (firmware)
On init the PN532 is configured for **high passive-activation retries** (`RFConfiguration` 0x05), and the poll loop runs at **~65ms** when not doing deep capture — weak coupling / marginal tags get more chances to answer.
### Dictionary “brute” (Classic)
**Brute** page → pick **Classic 1K / 4K map**, optional **variations**, paste extra keys. Firmware runs **`POST /api/mifare/dictionary-attack`**: built-in **public default keys** (subset of community lists such as the [Proxmark3 mfc_default_keys.dic](https://github.com/RfidResearchGroup/proxmark3/blob/master/client/dictionaries/mfc_default_keys.dic)) plus your lines, Key **A** then **B** per sector trailer. **Variations** add bounded XOR / nibble tweaks — **not** a full 2⁴⁸ keyspace search. You will **not** magically open every door; you will systematically try keys people actually leak online. ### Emulation
**Emulate** sends raw **`TgInitAsTarget` (0x8C)** payloads via **`POST /api/nfc/emulate-raw`**. You are responsible for correct bytes (NXP UM0701). This is **experimental**; bad sequences can require a power cycle.
| Method | Path | Purpose |
|--------|------|---------|
| `POST` | `/api/mifare/dictionary-attack` | Body: `readerType`, `variations`, optional `keysHex[]` |
| `POST` | `/api/nfc/emulate-raw` | Body: `{ "hex": "8C..." }` |
| `POST` | `/api/ul/write-page` | Body: `{ "page": 4, "data": "AABBCCDD" }` (8 hex) |
---
## Build
### Web UI → flash image
```bash
cd web
@@ -18,37 +75,47 @@ npm install
npm run build:fw
```
This compiles the SPA and copies `dist/*` into `firmware/data/` for SPIFFS embedding.
## Build — Firmware (ESP-IDF 5.x)
### Firmware (ESP-IDF 5.x)
```bash
cd firmware
idf.py set-target esp32s3
idf.py menuconfig # PN532 Host SPI / I2C / UART pins (Kconfig)
idf.py menuconfig # PN532 Host: SPI / I2C / UART + pins
idf.py build flash monitor
```
Partition table targets a **8MB** flash module (adjust `partitions.csv` + `sdkconfig` for 4MB/16MB).
See [docs/FLASHING.md](docs/FLASHING.md) and [docs/PINOUT.md](docs/PINOUT.md).
## Hardware / Kconfig
---
Open **Component config → PN532 Host** in `menuconfig`:
## 9 meaningful upgrades we dont have yet (roadmap)
- **SPI** (default): MOSI / MISO / SCLK / CS + clock Hz (start **100 kHz** if unstable)
- **I2C**: SDA / SCL, **7-bit address `0x24`** (left-shifted to `0x48` on the wire)
- **UART (HSU)**: TX/RX, **115200**
1. **FeliCa / Type B surfaces** — More first-class UI for nonType A paths the PN532 can speak.
Refer to [docs/PINOUT.md](docs/PINOUT.md) for ESP32-S3-DevKitC-1 wiring notes.
2. **Configurable RAM budget + optional PSRAM** — Compile-time or NVS `maxBytes`, and external SPIRAM for **multihundredKB** sessions on N8R8 modules.
## Repository layout
3. **Chunked / resumable export** — HTTP range or multipart export so **multiMB** captures dont require one giant `httpd_resp_send`.
| Path | Purpose |
|------|---------|
| `firmware/` | ESP-IDF project, `components/pn532_host`, `nfc_engine`, `net_service` |
| `web/` | SPA source |
| `docs/` | Flashing, workflows, limitations |
4. **User-supplied key dictionary on device** — Upload common keys file to flash and run **automatic sector retries** without typing keys in the UI.
## Legal / ethics
5. **NDEF record editor** — Parse TLV/NDEF in the browser, edit records, write back through page/block APIs with lock-byte warnings.
Use only on tags and systems you own or are explicitly authorized to test.
6. **ISO14443-4 / Type B automation** — Higher-layer APDU helpers where PN532 allows; clearer UI for “Type A only” vs “RATS/PPS” paths.
7. **Wi-Fi STA onboarding** — Captive portal or dedicated SSID scan + save credentials to NVS (today defaults to AP).
8. **Real OTA from the UI** — Replace `501` stub with signed `esp_https_ota` + rollback partition sanity checks.
9. **Installable PWA + richer diagnostics**`manifest.json`, icons, `theme-color`, and UI for **error histograms / timing** from the PN532 status path.
10. **Magic UID / Gen2** — Not exposed; PN532 is a legitimate reader/writer, not a UID-spoofing modem.
---
## Repo layout
| Path | Role |
|------|------|
| `firmware/` | ESP-IDF: PN532 transport, NFC engine, **session RAM buffer**, **deep profile**, HTTP/WS |
| `web/` | React UI: Dashboard, **Capture**, Read/Write, Library, Keys, Raw, Settings |
| `docs/` | Flashing, pinout, workflows, limitations |