From aa33d25466d2279e3775904d6862d066668b9b08 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: Wed, 16 Sep 2026 20:46:40 +0300 Subject: [PATCH] terminal profile at runtime + canonical custom-file paths (v2.2.3) TERMINAL PROFILE: - GET /api/terminal-profile returns the profile in effect + the CLI default; POST /api/terminal-profile validates ({profile}, hex, even, 1-255 bytes), stores it in memory and re-sends it, resetting the STK session like /api/rescue (the shared _resend_terminal_profile helper; rescue now delegates to it). __main__ keeps server.cli_terminal_profile. - Phone tab: a TERMINAL PROFILE block next to STATUS and Polling with the current hex/byte count, Send (re-send) and Configure. The Configure dialog has a device-model preset selector, a hex field and a per-bit form generated from a 264-entry table for TS 102 223 V18.3.0 5.2 bytes 1-33 (pySim's table as scaffold, later bytes/3GPP bits added from the spec; beyond the table generic RFU labels). Form <-> hex sync both ways, hex authoritative, bits preserved. Apply posts the new value. - Presets: Xiaomi Mi A1 (project default), Quectel GSM module example. In-memory only, no persistence. Custom files: - Canonical paths rooted at MF / ADF.USIM / ADF.ISIM; entries are {path, name, kind}. The editor now uses root + parent-DF selector + 4-hex FID + alias, requires the parent DF to be defined first, rejects duplicates, rewrites descendants when a DF's path changes and cascades deletes after a confirmation. - Legacy forms are normalized on load/import (3F00/... -> MF/..., relative a153/4954 resolved against the custom DFs); unresolvable entries are dropped and reported in the list. - Tree injection matches by exact parent path via the new pysimFsNodePath (same-FID DFs under different parents no longer collide); profilerCustomNameForPath uses the same normalization. SW cache otaman-v167; help EN/RU + docs/api.md + AGENTS updated. Tests: 236 Python + 371 frontend. --- docs/api.md | 31 +- frontend/help-ru.html | 9 +- frontend/help.html | 9 +- frontend/index.html | 598 +++++++++++++++++++++--- frontend/sw.js | 2 +- frontend/tests/custom_files.test.js | 264 +++++++---- frontend/tests/custom_inject.test.js | 102 ++++ frontend/tests/html.test.js | 5 + frontend/tests/phone_tabs.test.js | 6 +- frontend/tests/profiler.test.js | 2 +- frontend/tests/terminal_profile.test.js | 87 ++++ pyproject.toml | 2 +- pysim_otaman_server/__main__.py | 1 + pysim_otaman_server/server.py | 79 +++- tests/test_ota_helpers.py | 40 ++ 15 files changed, 1057 insertions(+), 180 deletions(-) create mode 100644 frontend/tests/custom_inject.test.js create mode 100644 frontend/tests/terminal_profile.test.js diff --git a/docs/api.md b/docs/api.md index 4fddea3..951724f 100644 --- a/docs/api.md +++ b/docs/api.md @@ -41,6 +41,8 @@ connect and warns if versions are incompatible. | `/api/proactive-log` | GET | Last 50 proactive commands | | `/api/status-poll` | POST | Manual STATUS poll + FETCH if 91XX | | `/api/rescue` | POST | Re-send TERMINAL PROFILE to recover CAT session | +| `/api/terminal-profile` | GET | Current TERMINAL PROFILE (hex) + CLI default | +| `/api/terminal-profile` | POST | Set and re-send the TERMINAL PROFILE at runtime (in-memory) | | `/api/poll-status` | GET | Background STATUS polling state | | `/api/poll-toggle` | POST | Enable/disable background polling | | `/api/pli-qualifiers` | GET | List of qualifier codes with descriptions | @@ -423,12 +425,37 @@ proactive chain (FETCH → TERMINAL RESPONSE) until it settles. Returns: ### `POST /api/rescue` Recovers a stuck CAT session by clearing the pending state and re-sending the -TERMINAL PROFILE. Returns whether a menu and event list were captured again: +TERMINAL PROFILE. Returns whether a menu and event list were captured again +(plus the profile used): ```json -{"menu": true, "events": [4, 5]} +{"ok": true, "profile": "FFFF...", "menu": true, "events": [4, 5]} ``` +### `GET /api/terminal-profile` + +The TERMINAL PROFILE currently in effect and the CLI default (for reference; +runtime changes are in-memory only): + +```json +{"profile": "FFFFFFFF7F9F00DFFF03021FE2000000C3FB000704117800710100000038428003", + "bytes": 33, + "cli_default": "FFFFFFFF7F9F00DFFF03021FE2000000C3FB000704117800710100000038428003"} +``` + +### `POST /api/terminal-profile` + +Sets the TERMINAL PROFILE at runtime (in-memory) and re-sends it to the card, +resetting the STK session state exactly like `/api/rescue`. Body with a new +profile, or `{}` to re-send the current one: + +```json +{"profile": "FFFFFFFF7F1F007FFF00001F230811060700"} +``` + +Hex, even number of digits, 1–255 bytes. Response is the same shape as +`/api/rescue` (with `ok: true`); invalid hex is a 400, no reader a 503. + ### `GET /api/poll-status` Background STATUS polling state. diff --git a/frontend/help-ru.html b/frontend/help-ru.html index 4d126e7..7db50f2 100644 --- a/frontend/help-ru.html +++ b/frontend/help-ru.html @@ -409,7 +409,7 @@

Пользовательские файлы

-

Добавление файлов, не покрытых моделью pySim: введите полный путь (например, 3F00/7F20/6F46) и псевдоним (например, EF.SPN), затем нажмите Добавить; добавленные файлы появляются в дереве «Файловый менеджер». В каждой строке есть кнопки «Редактировать» (загружает запись в форму — кнопка становится «Сохранить», появляется «Отмена») и «Удалить» (без подтверждения). Список сохраняется в localStorage; обмен — Экспорт в JSON / Экспорт в файл и Импорт из файла / Вставить и импортировать / Импорт JSON из буфера.

+

Добавление файлов, не покрытых моделью pySim. Пользовательский файл всегда имеет полный путь от MF или ADF (ADF.USIM, ADF.ISIM): выберите корень, родительский DF (сам корень или DF, уже добавленный здесь — родитель должен существовать до добавления его файлов), 4-hex FID и псевдоним (EF.…/DF.…; префикс определяет, EF это или DF). Канонический путь убирает прежнюю неоднозначность, когда один и тот же файл можно было описать и относительно, и абсолютно. Добавленные файлы появляются в дереве «Файловый менеджер»; в каждой строке есть «Редактировать» (путь + псевдоним; изменение пути DF перепривязывает дочерние записи — кнопка становится «Сохранить», «Отмена» отменяет) и «Удалить» (удаление DF удаляет и его дочерние записи после подтверждения). Список сохраняется в localStorage; обмен — Экспорт в JSON / Экспорт в файл / Импорт; старые относительные пути (например, a153/4954) разрешаются при загрузке, неразрешимые отбрасываются и отмечаются в списке.

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

@@ -431,10 +431,13 @@

6.3 Журнал проактивных команд

Хронологический список извлечённых проактивных команд. Каждая строка показывает время, код типа, имя и декодированный квалификатор (для команд, у которых он есть). Раскрытие строки показывает декодированную команду: текст и пункты DISPLAY TEXT / SELECT ITEM / SET UP MENU, параметры BIP-каналов, действия TIMER MANAGEMENT, названия квалификаторов PROVIDE LOCAL INFORMATION (все стандартные, включая ESN 07, MEID 0B и Supported RATs 1A) и SEND SHORT MESSAGE — разбирается SMS TPDU (тип, TP-MR, TP-DA, TP-PID, TP-DCS, срок действия, TP-UDL), а пользовательские данные показываются как текст для текстовых кодировок (GSM 7-бит, UCS2, 8-бит) или как secured-пакет (TS 31.115) при TP-PID = 7F (SIM data download); заголовки конкатенации UDH декодируются. Для команд с данными ответа показывается строка Ответ: с байтами TERMINAL RESPONSE (без служебных TLV); ответы PROVIDE LOCAL INFORMATION декодируются через словарь данных PLI.

-

6.4 Опрос STATUS

+

6.4 TERMINAL PROFILE

+

Блок TERMINAL PROFILE (рядом с «STATUS и опрос») показывает действующий профиль (hex + число байт) и кнопки «Отправить» (повторная отправка, как «Спасение») и «Настроить». В диалоге настройки: селектор пресетов (модели устройств, например профиль BIP-совместимого аппарата из этого проекта), поле hex и форма с флажком на каждый бит профиля по TS 102 223 §5.2 (байты 1–33; далее — обобщённые подписи); переключение бита обновляет hex, а правка hex перерисовывает форму — поле hex основное, неизвестные байты и биты сохраняются. Кнопка «Применить» отправляет новое значение на сервер (и далее на карту), сбрасывая STK-сессию как «Спасение»; изменение хранится только в памяти (значение --terminal-profile — стартовое по умолчанию).

+ +

6.5 Опрос STATUS

Кнопка Отправить STATUS отправляет STATUS (F2) вручную. Переключатель Опрос включает фоновый опрос: после настраиваемого интервала бездействия (аргумент сервера --poll-interval, 1–255 с, по умолчанию 30 с, 0 отключает опрос) сервер отправляет STATUS и обрабатывает любую ожидающую проактивную команду. При извлечении карты опрос останавливается, а состояние карты сбрасывается.

-

6.5 «Конфигурация TR» — данные ответа PROVIDE LOCAL INFORMATION

+

6.6 «Конфигурация TR» — данные ответа PROVIDE LOCAL INFORMATION

Редактируемые hex-значения для всех 22 квалификаторов PLI (TS 102 223 §8.6 + TS 131 111). У десяти квалификаторов есть встроенные формы декодирования/кодирования: