From a4d5415034aae0333ad1f45a2c724ffbba1efdea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D1=82=D0=BE=D0=BD=20=D0=A2=D1=80=D0=BE=D1=88?= =?UTF-8?q?=D0=B8=D0=BD?= Date: Mon, 21 Sep 2026 23:10:52 +0300 Subject: [PATCH] esim: local eUICC operations in the Phone simulator tab (v2.8.0) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New eSIM pill (Phone simulator) for SGP.22/32 cards, built on pySim's ES10 static API — no lpac, no new dependencies, no pysim patches, no SM-DP+ interaction: - Chip: EID, EUICCInfo1/2, configured addresses (ES10a/b). - Profiles: GetProfilesInfo with metadata (state, nickname, provider, ICCID, ISD-P AID, class, owner, icon). - Notifications: read-only ListNotification viewer. - Switch: Enable/DisableProfile with RefreshFlag=1; the card's REFRESH (fetched/answered/logged by the transport's proactive handler) or an ok result triggers _esim_reinit() — reset + equip + _apply_equipped_card — so the ICCID, network state and cached views are re-read. - Server: pysim_simple_server/esim.py, GET /api/esim/chip|profiles| notifications, POST /api/esim/profile (all under _CARD_LOCK; 400 not_an_euicc), euicc/eid in /api/status. - Tests: tests/test_esim.py (fake scc, monkeypatched store_data_tlv), frontend/tests/esim.test.js; help EN/RU, docs/api.md, AGENTS. --- docs/api.md | 35 ++++ frontend/help-ru.html | 11 +- frontend/help.html | 11 +- frontend/index.html | 301 +++++++++++++++++++++++++++++- frontend/sw.js | 2 +- frontend/tests/esim.test.js | 94 ++++++++++ frontend/tests/phone_tabs.test.js | 4 + pyproject.toml | 2 +- pysim_simple_server/esim.py | 246 ++++++++++++++++++++++++ pysim_simple_server/server.py | 157 +++++++++++++++- tests/test_esim.py | 196 +++++++++++++++++++ 11 files changed, 1051 insertions(+), 8 deletions(-) create mode 100644 frontend/tests/esim.test.js create mode 100644 pysim_simple_server/esim.py create mode 100644 tests/test_esim.py diff --git a/docs/api.md b/docs/api.md index 20e9fc2..f043b22 100644 --- a/docs/api.md +++ b/docs/api.md @@ -31,6 +31,10 @@ a 2.x PWA). | `/api/write` | POST | Write raw hex data to a file | | `/api/apdu` | POST | Raw APDU send | | `/api/verify-adm` | POST | Verify the card's ADM PIN (from the matched card preset) | +| `/api/esim/chip` | GET | eUICC chip details (EID, EUICCInfo1/2, configured addresses) | +| `/api/esim/profiles` | GET | Installed eSIM profiles with their metadata | +| `/api/esim/notifications` | GET | Pending eSIM notifications (read-only) | +| `/api/esim/profile` | POST | Enable/disable an eSIM profile (card re-initialized after the switch) | | `/api/help` | POST | pySim help for a given command | | `/api/send-ota` | POST | SCP80 OTA secured packet delivery | | `/api/ram-install` | POST | Install a Java Card `.cap` file via SCP80 (INSTALL[for load] → LOAD ×N → INSTALL[for install]) | @@ -162,6 +166,37 @@ On a wrong key (`63Cx`, x attempts left): A blocked ADM (`6983`/`9804`) reports `{"ok": false, "sw": "9804", "blocked": true}` and cannot be recovered without the card's unblock key. +### eSIM / LPA (local ES10 operations) + +These endpoints work only when the equipped card is an eUICC (SGP.22/32); +otherwise they answer `400` with `{"error": "The equipped card is not an +eUICC"}`. They use pySim's ES10 static API — no lpac, no SM-DP+ contact, no +profile downloads and no notification processing. All run under the card +lock; `GET /api/status` reports `euicc` and `eid` for the PWA. + +- `GET /api/esim/chip` — `{"eid": "8904…", "info1": {…}, "info2": {…}, + "addresses": {"default_dp_address": …, "root_ds_address": …}, + "errors": {"": ""}}` (a part the card does not support is + reported in `errors` instead of failing the whole request). +- `GET /api/esim/profiles` — `{"profiles": [{"iccid": "8970…", + "isdp_aid": "A000…", "state": "enabled"|"disabled", "nickname": …, + "provider": …, "name": …, "class": "test"|"provisioning"|"operational", + "owner": "250-99", "icon_type": "png"|"jpg"}], "error": null}`. +- `GET /api/esim/notifications` — `{"notifications": [{"seq_number": 3, + "operations": ["enable"], "address": "smdp.example.org", + "iccid": "8970…"}], "error": null}`. +- `POST /api/esim/profile` — `{"action": "enable"|"disable", "iccid"?: …, + "isdp_aid"?: …, "refresh"?: true}` (one identifier required). The card + usually answers with a REFRESH proactive command first (logged in + `/api/proactive-log`); after a successful switch — or whenever a REFRESH + was seen — the server re-initializes the card like an equip (reset, + re-read ICCID/network state, new `card_session`) and returns + `{"ok": true, "result": "ok", "refresh_seen": true, "reinitialized": true, + "iccid": …, "card_session": N}`. Failures carry the ES10c result code + (`iccidOrAidNotFound`, `profileNotInDisabledState`, + `profileNotInEnabledState`, `disallowedByPolicy`, `wrongProfileReenabling`, + `catBusy`, `undefinedError`) and a short `message`. + ### `POST /api/help` Get structured help for a shell command. diff --git a/frontend/help-ru.html b/frontend/help-ru.html index ae0693f..89c8fe5 100644 --- a/frontend/help-ru.html +++ b/frontend/help-ru.html @@ -444,7 +444,7 @@

8. Симулятор телефона

-

Работа с сессией Card Application Toolkit. Две подвкладки: «Телефон» (меню STK, STATUS и опрос, подписанные события, журнал проактивных команд) и «Конфигурация TR» (данные ответов, подставляемые в TERMINAL RESPONSE для проактивных команд).

+

Работа с сессией Card Application Toolkit. Три подвкладки: «Телефон» (меню STK, STATUS и опрос, подписанные события, журнал проактивных команд), «Конфигурация TR» (данные ответов, подставляемые в TERMINAL RESPONSE для проактивных команд) и «eSIM» (локальные операции с eUICC).

8.1 Меню STK

Если карта выдала команду SET UP MENU, вверху этого представления появляется блок «Меню STK» с изумрудной кнопкой STK: <название>, открывающей оверлей меню (браузер STK-меню карты). Если карта не задала меню, вместо кнопки показывается «Меню не задано картой». Состояние меню обновляется при каждом открытии представления. Интерактивные проактивные команды всегда получают TERMINAL RESPONSE: оверлей ждёт вашего выбора, и если вы не ответили и не нажали Timeout, сервер сам отвечает результатом timeout через --menu-timeout секунд (по умолчанию 60, 0 отключает). Назад и Timeout продолжают диалог с картой: если карта в ответ выдаёт следующую проактивную команду (SELECT ITEM или DISPLAY TEXT), панель показывает её; кэшированное верхнее меню появляется только когда карте больше нечего выполнять.

@@ -494,6 +494,15 @@

Монитор сетевого состояния

Рядом с кнопками симуляции компактная панель «Сетевое состояние» показывает, что сейчас хранит карта и что было сэмулировано последним. В заголовке — сэмулированное состояние сервиса: Не определено, пока его не задаст сценарий или событие Location status, затем Обычный сервис (зелёный), Ограниченный сервис (жёлтый) или Нет сервиса (красный), с красной пометкой PLMN не разрешён, если location-файлы или EF.FPLMN указывают на отказ регистрации — плюс текущее местоположение: PLMN, страна и оператор (из необязательного мирового списка MCC/MNC, если он загружен), LAI/RAI/TAI и класс роуминга (Домашняя сеть, если PLMN совпадает с HPLMN; Эквивалентная домашней, если он есть в EF.EHPLMN; иначе Гостевая (роуминг)). Ниже — по одной компактной строке на контролируемый файл (IMSI, EHPLMN, SPDI, HPLMNwAcT, LOCI, PSLOCI, EPSLOCI, EPSNSC, CBMI, CBMIR, SMSstatus, FPLMN) с декодированной сводкой и признаком последнего обновления (init, write, read, refresh); при наведении — все декодированные поля; длинные списки PLMN сокращаются (EF.HPLMNwAcT показывает только первую сеть и пометку … +N, а технологии доступа — в подсказке). Панель читает файлы один раз при подключении карты (только если ICCID читается), обновляет их на месте по записанным симулятором байтам, перечитывает EF.IMSI после каждого сценария и события Location status (мульти-IMSI апплеты) и никогда не опрашивает карту — кнопка «Обновить» перечитывает все файлы по требованию.

+

8.8 eSIM / LPA (локальные операции)

+

Для eUICC (SGP.22/SGP.32) подвкладка «eSIM» читает чип и управляет установленными профилями через локальный интерфейс ES10 (через pySim, без обращения к SM-DP+):

+
    +
  • Чип — EID, EUICCInfo1/2 (версия профиля, SVN, прошивка, версия GlobalPlatform, возможности RSP, категория, …) и настроенные адреса SM-DP+ по умолчанию / корневого DS.
  • +
  • Профили — все профили с состоянием (включён/отключён), ником, оператором, именем, ICCID, ISD-P AID, классом, владельцем и типом значка. Кнопки «Включить»/«Отключить» переключают профиль; карта обычно сначала отправляет REFRESH (виден в журнале проактивных команд), а после переключения сессия карты переинициализируется как при equip — ICCID, сетевое состояние и все кэшированные данные перечитываются.
  • +
  • Уведомления — список ожидающих уведомлений только для чтения (номер последовательности, операция, адрес, ICCID); ничего не обрабатывается и не удаляется.
  • +
+

Никаких загрузок профилей, обработки уведомлений и взаимодействия с SM-DP+ — используются только локальные функции ES10a/b/c. Если карта не eUICC, подвкладка сообщает об этом.

+
diff --git a/frontend/help.html b/frontend/help.html index da68092..f68b6b0 100644 --- a/frontend/help.html +++ b/frontend/help.html @@ -444,7 +444,7 @@

8. Phone simulator

-

Interacts with the Card Application Toolkit session. The view has two pills: Phone (STK menu, STATUS and polling, subscribed events, proactive command log) and TR Config (response data injected into TERMINAL RESPONSEs for proactive commands).

+

Interacts with the Card Application Toolkit session. The view has three pills: Phone (STK menu, STATUS and polling, subscribed events, proactive command log), TR Config (response data injected into TERMINAL RESPONSEs for proactive commands) and eSIM (local eUICC operations).

8.1 STK menu

When the card has issued a SET UP MENU command, a “STK menu” block appears at the top of this view with an emerald STK: <title> button that opens the menu overlay (same as the card’s STK menu browser). If the card has not set up a menu, the block shows “No menu set by the card” instead. The menu state is refreshed each time the view is opened. User-interactive proactive commands always get a TERMINAL RESPONSE: the overlay pauses for your choice, and if you neither answer nor press Timeout, the server answers with a timeout result after the --menu-timeout seconds (default 60, 0 disables). Back and Timeout keep the dialogue with the card going: when the card replies with a further proactive command (SELECT ITEM or DISPLAY TEXT) the panel shows it; the cached top menu appears only when the card has nothing more to execute.

@@ -494,6 +494,15 @@

Network state monitor

Next to the simulation buttons a compact Network state panel shows what the card currently holds and what was last simulated. Its header carries the simulated service stateUndefined until a scenario or a Location status event sets it, then Normal service (green), Limited service (amber) or No service (red), with a red PLMN not allowed marker when the location files or EF.FPLMN show a rejection — plus the current location: PLMN, country and operator (from the optional worldwide MCC/MNC list when loaded), the LAI/RAI/TAI, and the roaming class (Home when the PLMN equals the HPLMN, Home equivalent when it is in EF.EHPLMN, otherwise Guest). Below it, one compact line per monitored file (IMSI, EHPLMN, SPDI, HPLMNwAcT, LOCI, PSLOCI, EPSLOCI, EPSNSC, CBMI, CBMIR, SMSstatus, FPLMN) with its decoded summary and how it was last updated (init, write, read, refresh); hover for the full decoded fields — long PLMN lists are abbreviated (EF.HPLMNwAcT shows only the first network plus a … +N counter, with the access technologies in the tooltip). The panel reads the files once at equip (only when the ICCID was readable), updates them in place from the bytes the simulator wrote, re-reads EF.IMSI after every scenario and Location-status event (multi-IMSI applets) and never polls the card — use Refresh to re-read all files on demand.

+

8.8 eSIM / LPA (local operations)

+

For an eUICC (SGP.22/SGP.32) the eSIM pill reads the chip and manages the installed profiles through the local ES10 interface (via pySim, no SM-DP+ contact):

+
    +
  • Chip — EID, EUICCInfo1/2 (profile version, SVN, firmware, GlobalPlatform version, RSP capabilities, category, …) and the configured default SM-DP+ / root DS addresses.
  • +
  • Profiles — every profile with its state (enabled/disabled), nickname, provider, name, ICCID, ISD-P AID, class, owner and icon type. Enable/Disable switches a profile; the card usually sends REFRESH first (logged in the proactive command log) and after the switch the card session is re-initialized like an equip, so the ICCID, network state and every cached card view are re-read.
  • +
  • Notifications — read-only list of pending notifications (sequence number, operation, address, ICCID); nothing is processed or removed.
  • +
+

No profile downloads, no notification handling and no SM-DP+ interaction — only the local ES10a/b/c functions are used. The card must be an eUICC; otherwise the pill says so.

+
diff --git a/frontend/index.html b/frontend/index.html index eb81e5b..8a969ab 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -906,6 +906,7 @@
+
@@ -1055,6 +1056,27 @@ Loading...
+