Files
otaman/README_RUS.md
T
catarrh 6d30e7095e snapshots: measure SELECT / READ commands and show timing stats
Server measures every classified APDU (A4 select, B0 read binary, B2 read
record) from command to response: _collect_apdu_times() enables the tracer
(reattaching it if pySim nulled it) and /api/select + /api/read return
'apdu_times': [{type, ms}]. Collection is safe: handlers hold _CARD_LOCK.

Snapshots store per-file {select_ms, read_ms}, a ms value per record and
snapshot-level stats {select, read_binary, read_record}: {min, max, avg,
count} plus total_ms (wall time of the scan). The snapshot view gets a
summary under the title (files/records counts, scan time, min/avg/max per
command type) and shows select/read per file and read time per record.
Timings are display-only: checks, snapshots comparison and imports ignore
them (old snapshots simply show 'No timing data').

Tests: Python classifier/collection (tests/test_apdu_timing.py) and
frontend stats/accumulator/format/build-file/summary. SW cache v99 ->
v100; help, README and docs/api.md updated.
2026-09-12 14:56:59 +03:00

629 lines
39 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# OTAMan — SIM OTA toolkit: PWA + локальный сервер карт
OTAMan — автономный offline-PWA (HTML/JS) для создания APDU-команд (SIM, USIM, GlobalPlatform RAM), сборки защищённых пакетов SCP80 по ETSI TS 102 225 и построения Expanded Remote Application data format APDU по ETSI TS 102 226. В комплекте — [`pysim-otaman-server`](pysim_otaman_server/) — локальный HTTP-сервер поверх pySim для работы с картой: файловый менеджер, сырые APDU, меню SIM Toolkit и доставка OTA.
**Демо:** [otaman.atroshin.ru](https://otaman.atroshin.ru) — только PWA, для экспериментов. Для функций картридера установите сервер (ниже).
## Быстрый старт
**Только PWA (клиентские функции):** откройте `frontend/index.html` в любом браузере или раздайте `frontend/` любым статическим сервером. Python не нужен.
**Полная установка (PWA + сервер карт):**
```sh
git clone https://github.com/anttro/otaman.git
cd otaman
./setup.sh # или setup.bat в Windows — создаёт .venv, ставит pysim + сервер
./start.sh # или start.bat — запускает сервер (он же раздаёт PWA)
```
Затем откройте http://127.0.0.1:8080 — интерфейс и API на одном origin, поэтому CORS и разрешения браузера не нужны.
## Сборка
Для стилей используется Tailwind CSS. После клонирования пересоберите CSS:
```sh
cd frontend
npm install
npm run build
```
## Интерфейс
Пять вкладок: **Remote APDU**, **SCP80**, **Card reader**, **Profiler** и **Phone simulator**. Вкладки Remote APDU и SCP80 используют пиллы-подвкладки; во вкладке Card reader четыре подвкладки: **File manager**, **Custom files**, **pySim command line** и **Raw APDU**.
---
## Вкладка Remote APDU
Построение команд APDU (C-APDU). Семь подвкладок для разных поколений карт, наборов команд и инструментов разбора: **SIM RFM**, **USIM RFM**, **Expanded Script**, **RAM/GP**, **HTTP OTA**, **Разбор C-APDU** и **«Парсер ответов»**.
### SIM RFM
CLA = `A0` (GSM 11.11 / ISO 7816-4).
#### Команды
| Команда | INS | Описание |
|---|---|---|
| SELECT | A4 | Выбор EF/DF по FID, пути, dfname или цепочке |
| UPDATE RECORD | DC | Обновление записи |
| UPDATE BINARY | D6 | Обновление бинарных данных |
| READ RECORD | B2 | Чтение записи |
| READ BINARY | B0 | Чтение бинарных данных |
| ERASE BINARY | 0E | Стирание бинарных данных |
| ACTIVATE FILE | 44 | Активация файла |
| DEACTIVATE FILE | 04 | Деактивация файла |
| VERIFY PIN | 20 | Проверка PIN1 или PIN2 |
| CHANGE PIN | 24 | Смена PIN1 или PIN2 |
#### Методы SELECT
| Метод | P1 | P2 | Ввод |
|---|---|---|---|
| By FID | 00 | 00 | FID (4 hex) |
| By full path from MF | 08 | 00 | Полный путь от MF |
| By DF name / AID | 04 | 00 | AID |
| ADF RFM chain | 00 | 00 | FID через запятую |
#### Опции
- **Start with SELECT** — добавить SELECT перед командой.
- **Selection mode (P2)** — для record-команд: Absolute (04), Next (06), Previous (02).
- **Record size** — дополнить/обрезать данные до указанного размера.
- **Allow P1/P2 editing** — ручное редактирование P1/P2.
#### Ссылки
- ISO/IEC 7816-4: Organization, security and commands for interchange
- ETSI TS 102 226: Remote APDU structure for UICC based applications
- GSM 11.11: SIM-ME Interface
### USIM RFM
CLA = `00` (ETSI TS 102 221). Те же команды, что и SIM, но SELECT использует P1=09, P2=0C.
#### Ссылки
- ETSI TS 102 221: UICC-Terminal Interface
- ETSI TS 102 226: Remote APDU structure
### Expanded Script
Построение Expanded Remote Application data format по ETSI TS 102 226 §5.2.1.
#### Формат
- **Definite (AA)**: `AA` + длина + Command TLV
- **Indefinite (AE)**: `AE` + `80` + Command TLV + `00 00`
#### Command TLV
| Тип | Тег | Описание |
|---|---|---|
| C-APDU | 22 | APDU |
| Immediate Action | 81 | Proactive-команда или action indicator |
| Error Action | 82 | Proactive-команда при ошибке |
| Script Chaining | 83 | Данные для многопакетных скриптов |
#### Сборщик Immediate Action
- **Action indicator**: `81` / `82`
- **Proactive command**: REFRESH, DISPLAY TEXT, PLAY TONE
- **Custom hex**: ручной ввод
#### Ссылки
- ETSI TS 102 226 §5.2.1
- ETSI TS 102 223: Card Application Toolkit
- ETSI TS 101 220: BER-TLV tag assignments
### RAM/GP
CLA = `80` (GlobalPlatform v2.3.1). Удалённое управление содержимым карты через SCP80.
#### Справочник GP-команд
| Команда | INS | P1 | Описание |
|---|---|---|---|
| INSTALL [for load] | E6 | 02 | Регистрация загружаемого файла |
| INSTALL [for install] | E6 | 0C | Установка приложения или SD |
| INSTALL [for make selectable] | E6 | 10 | Сделать приложение выбираемым |
| INSTALL [for registry update] | E6 | 01 | Обновление реестра |
| INSTALL [for extradition] | E6 | 04 | Перемещение между SD |
| LOAD | E8 | 00 | Загрузка кода |
| DELETE | E4 | 00/80 | Удаление приложения или SD |
| GET STATUS | F2 | 80/40/20/10 | Статус карты |
| GET DATA | CA | tag | Чтение объектов данных |
| STORE DATA | E2 | 00/40/80/C0 | Запись данных |
| SET STATUS | F0 | 80/40/60 | Управление жизненным циклом |
| EXTERNAL AUTHENTICATE | 82 | 00 | Аутентификация SCP |
| INTERNAL AUTHENTICATE | 88 | 00 | Challenge-response |
#### Привилегии (INSTALL [for install])
Три байта привилегий по GP Spec Tables 11-7, 11-8, 11-9.
**Байт 1:**
| Бит | Привилегия |
|---|---|
| b8 | Security Domain |
| b7 | DAP Verification |
| b6 | Delegated Management |
| b5 | Card Lock |
| b4 | Card Terminate |
| b3 | Card Reset |
| b2 | CVM Management |
**Байт 2:**
| Бит | Привилегия |
|---|---|
| b8 | Trusted Path |
| b7 | Authorized Management |
| b6 | Token Verification |
| b5 | Global Delete |
| b4 | Global Lock |
| b3 | Global Registry |
| b2 | Final Application |
**Байт 3:**
| Бит | Привилегия |
|---|---|
| b8 | Receipt Generation |
#### Параметры SIM/UICC Toolkit
- **Tag `CA`** (SIM Toolkit): Priority, Timers, Text Length, Menu Entries, Positions, Channels, MSL, TAR, Access Domain
- **Tag `80`** (UICC Toolkit, внутри `EA`): те же поля без Access Domain
**MSL (Minimum Security Level):**
| Значение | Описание |
|---|---|
| 00 | Нет проверки |
| 11 | RC/CC/DS |
| 12 | RC/DS/CC |
| 15 | RC/DS/CC + MAC |
| 16 | RC/DS/CC + MAC + Cipher |
| 19 | RC/DS/CC + MAC + Cipher + DS |
#### GET STATUS P1
| Значение | Описание |
|---|---|
| 80 | Issuer Security Domain (ISD) |
| 40 | Applications и SSD |
| 20 | Executable Load Files |
| 10 | ELF и модули |
#### GET STATUS P2
| Значение | Описание |
|---|---|
| 40 | Первые/все, GP TLV (по умолчанию) |
| 42 | Следующие, GP TLV |
| 00 | Первые/все, старый формат (deprecated) |
| 02 | Следующие, старый формат (deprecated) |
#### GET DATA теги
| Тег | Объект данных |
|---|---|
| 42 | Issuer Identification Number (IIN) |
| 45 | Card Image Number (CIN) |
| 66 | Card Data / SD Management Data |
| 67 | Card Capability Information |
| E0 | Key Information Template |
| D3 | Current Security Level |
| 2F00 | List of Applications |
| FF21 | Extended Card Resources Info |
| 5F50 | SD Manager URL |
| C1 | Sequence Counter (SCP02/03) |
| C2 | Confirmation Counter |
| 7F21 | Certificate (SD public key) |
| 5031 | Certificate info (EF.OD) |
#### DELETE P1
| Значение | Описание |
|---|---|
| 00 | Только AID |
| 80 | AID и связанные объекты |
#### STORE DATA P1
| Значение | Описание |
|---|---|
| 00 | Последний блок, без шифрования |
| 40 | Ещё блоки, без шифрования |
| 80 | Последний блок, с шифрованием |
| C0 | Ещё блоки, с шифрованием |
#### SET STATUS
**P1:** 80 = ISD, 40 = Приложение или SSD, 60 = SD и его приложения
**P2:** 00 = Разблокировать, 80 = Заблокировать (LOCKED)
#### Ссылки
- GlobalPlatform Card Specification v2.3.1
- ETSI TS 102 226 §8.2.1.3.2: Параметры SIM/UICC Toolkit
### Конвертация (боковые панели SIM/USIM)
#### IMSI → EF.IMSI
15-значный IMSI → 9 байт EF.IMSI.
#### MSISDN → BCD
Удаление `+`, добавление `f`, обмен полубайтов.
#### ICCID → hex
Обмен полубайтов строки ICCID.
#### Provider Name → SPN
По 3GPP TS 31.102 §4.2.5. Три варианта кодирования:
1. GSM 7-bit packed
2. UCS2 non-BMP
3. UCS2 BMP non-GSM7
#### PLMN → EF_PLMNsel / PLMNwAcT
3-байтное BCD-кодирование + опциональный Access Technology.
#### Nibble swap
Обмен полубайтов hex-строки.
#### Ссылки
- 3GPP TS 31.102
- 3GPP TS 23.038
- ETSI TS 102 225
- pySim: enc_imsi()
### Разбор C-APDU
Вставьте сырой hex APDU — отобразится раскрывающееся дерево. Контейнер определяется автоматически: **Expanded Script** (ведущие `AA` или `AE80`, разбор по ETSI TS 102 226 §5.2.1) или **компактная цепочка C-APDU** (последовательность ISO 7816 C-APDU). У каждого узла — метка, hex и краткое описание; родительские узлы раскрываются до подэлементов.
### HTTP OTA
Сборка payload-ов Remote Application Management over HTTP по GlobalPlatform **GPC v2.2 Amendment B v1.1** (§4.7). Два режима:
- **Trigger (Push SMS)** — параметры запуска административной сессии (`81 > 83 > 84/[85]/[86]/89`, Table 4-3). Это сообщение просит Security Domain карты выйти в сеть и начать HTTP-сессию.
- **Store (SD admin params)** — запись тех же параметров как данных карты (Security Domain) через **STORE DATA в TLV-режиме** (`80 E2 90 00`, P1=90 = последний блок + BER-TLV по GP v2.2 Amendment B v1.1.3), обёрнутых в тег `85` (или `A5`) по Table 4-4.
| Секция | Тег | Содержимое |
|---|---|---|
| Параметры соединения | `84` | COMPREHENSION-TLV для открытия TCP-соединения (OPEN CHANNEL по TS 102 223): Device Identities `02`, Alpha `80`, Bearer `01`, вендорские TLV. Редактор строк + пресеты, редактируемый hex. |
| Параметры безопасности | `85` | Table 4-6: LV PSK Identity (текст), LV Key version/KID. Идентифицирует ключ PSK TLS (RFC 4279). |
| Политика повторов | `86` | Table 4-7: счётчик повторов (2 байта, напр. `B000`), задержка повтора как timer TLV TS 102 223 (`25 03 HH MM SS`), опциональный вендорский TLV отчёта об ошибке. |
| HTTP POST | `89` | Tables 4-8/9/10: заголовок Host (`8A`), X-Admin-From agent ID (`8B`), URI (`8C`) — текст преобразуется в октеты. |
Чекбокс **Command Scripting template** оборачивает всю команду `81` в формат Expanded Remote Application с определённой длиной (`AA`, ETSI TS 102 226 §5.2.1) для TAR, обрабатывающих расширенный формат. **Pack into Secured packet** отправляет собранный payload на вкладку SCP80 для заполнения SPI/счётчика — укажите там TAR, который слушает SD (обычно OTASD).
---
### Парсер ответов
Декодирование ответа команды: выберите отправленную команду, введите SW (например, `9000`) и данные ответа в hex, затем нажмите **Decode**.
- **Команда** — группа SIM/USIM (SELECT, STATUS, READ/UPDATE, операции с PIN, CAT-команды TERMINAL PROFILE/ENVELOPE/FETCH/TERMINAL RESPONSE, MANAGE CHANNEL, ...) или группа RAM/GP (INSTALL, LOAD, DELETE, GET/STORE DATA, аутентификация, команды SCP).
- **Декодирование SW** — статусные слова по картам generic, UICC (TS 102 221) и GlobalPlatform с автоопределением контекста.
- **Декодирование привилегий** — байты привилегий из ответов GET DATA / INSTALL в читаемые флаги.
- **Данные ответа** — hex с интерпретацией по команде (например, шаблоны FCP из SELECT).
---
## Вкладка SCP80
Вкладка **SCP80** группирует SCP80-виды, переключаемые тремя пиллами: **Secured Packet**, **Cards** и **RAM**. Сборка защищённых пакетов по ETSI TS 102 225.
### Secured Packet
Сборка защищённых пакетов SCP80 по ETSI TS 102 225.
#### Структура пакета
| Поле | Размер | Описание |
|---|---|---|
| CPI | 1 | Command Packet Identifier (`02`) |
| CPL | 1 | Command Packet Length |
| CHI | 1 | Command Header Identifier (`01`) |
| CHL | 1 | Command Header Length |
| SPI | 2 | Security Parameter Indicator |
| KIc | 1 | Key Identifier для шифрования |
| KID | 1 | Key Identifier для MAC |
| TAR | 3 | Toolkit Application Reference |
| CNTR | 5 | Счётчик повторов |
| PCNTR | 1 | Padding counter |
| RC/CC/DS | 8 | Контрольная сумма / MAC |
| Secured Data | переменная | APDU (с шифрованием при необходимости) |
#### SPI1 (Уровень безопасности)
Битовое поле SPI1 (TS 102 225 §5.1.1): `b8b6` — паддинг, `b5b4` — счётчик, `b3` — шифрование, `b2b1` — RC/CC/DS.
| Значение | Безопасность | Шифрование | Счётчик (b5 b4) |
|---|---|---|---|
| 00 | Нет | Нет | 00 нет |
| 01 | RC | Нет | 00 нет |
| 02 | CC/MAC | Нет | 00 нет |
| 06 | CC/MAC | Да | 00 нет |
| 0A | CC/MAC | Нет | 01 available |
| 0E | CC/MAC | Да | 01 available |
| 12 | CC/MAC | Нет | 10 higher |
| 16 | CC/MAC | Да | 10 higher |
| 1A | CC/MAC | Нет | 11 +1 |
| 1E | CC/MAC | Да | 11 +1 |
> **AES требует `b5 b4 = 10` (higher) или `11` (+1)** согласно TS 102 225 §5.1.2 и §5.1.3.1.
> Значения `00/01/02/06` (без счётчика) допустимы только для 3DES.
#### SPI2 (PoR)
| Значение | Режим |
|---|---|
| 00 | No PoR |
| 01 | PoR required, no security |
| 05 | PoR required, RC |
| 09 | PoR required, CC |
| 0D | PoR required, DS |
| 11 | PoR required, ciphered |
| 02 | PoR on error, no security |
| 06 | PoR on error, RC |
#### Крипто
- **3DES-CBC** шифрование, ключи 8/16/24 байт — устарело с Rel-18, но поддерживается для обратной совместимости
- **AES-CBC** шифрование (нулевой ICV, дополнение нулями до 16), ключи 16/24/32 байта (TS 102 225 §5.1.2, KIc `x2`)
- **Retail MAC** (ISO 9797-1 MAC algorithm 3) для DES/3DES
- **AES-CMAC** (NIST SP 800-38B, усечённый до 8 октетов) для AES (TS 102 225 §5.1.3.1, KID `x2`)
- Padding byte: `00` (по умолчанию) или `FF`
#### PoR (Proof of Reception)
PoR подтверждает, что карта получила и выполнила защищённый пакет. Два режима:
| SPI2 (бит 5) | Режим | Описание |
|---|---|---|
| `0x00` | Delivery PoR | PoR возвращается в ответе ENVELOPE (SW+данные) |
| `0x20` | Submit PoR | PoR отправляется обратно как SMS-SUBMIT через прокоманду FETCH |
Delivery PoR (SPI2 `01`) проще — карта возвращает PoR напрямую в ответе ENVELOPE. Submit PoR (SPI2 `21`) используется, когда карта не может ответить inline (ограничено пространство ответа ENVELOPE).
#### Ссылки
- ETSI TS 102 225 V18.1.0
- ETSI TS 102 226
- ISO 9797-1
- NIST SP 800-38B (CMAC)
### Cards
Пилл **Cards** управляет сохранёнными конфигурациями карт (пресеты). Каждый пресет хранит криптографические ключи, настройки TAR и счётчик повторов для SCP80-операций.
| Поле | Описание |
|---|---|
| SPI1 / SPI2 | Уровень безопасности и настройки PoR |
| Ключ KIc / KID | Hex ключи шифрования и MAC |
| Индекс KIc / KID | Номер версии ключа |
| TAR | Toolkit Application Reference (3 байта) |
| Счётчик (CNTR) | 10-значный hex счётчик повторов, автоматически увеличивается после каждой успешной отправки SCP80 |
**Добавить карту:** заполните имя, SPI1/SPI2, ключи KIc/KID и их индексы, TAR, нажмите **Add**. Карта появится в списке и станет доступна в выпаданом списке **Card preset** на RAM-вкладке.
**Редактировать карту:** выберите карту в списке, измените поля, нажмите **Save**.
**Удалить карту:** выберите карту, нажмите **Delete**. Удаляет пресет из `localStorage`.
**Счётчик:** 10-значный hex-счётчик (CNTR) автоматически увеличивается после каждой успешной отправки SCP80 (ручные отправки Secured Packet и RAM-операции). Обновлённый счётчик автоматически сохраняется обратно в пресет.
### RAM
Все операции RAM отправляются как защищённые пакеты SCP80 (ETSI TS 102 225) через SMS-PP-DOWNLOAD ENVELOPE. Карта должна поддерживать SCP03 (AES или 3DES) для безопасной транспортировки.
Выберите сохранённую конфигурацию карты из выпадающего списка **Card preset**. Если пресет не выбран, RAM-вкладка предупреждает и отказывается выполнять.
В RAM-подвкладке доступны две операции через выпадающий список **Operation**:
| Операция | Описание |
|---|---|
| **Explore Card (all GP data)** | Запрос GET STATUS для ISD, приложений, ELF и модулей ELF, а также GET DATA FF21 для информации о памяти. Результаты отображаются в обзоре с кнопками **Delete** для каждого элемента. |
| **Install Package (.cap file)** | Отправка `.cap` файла на карту через сервер: INSTALL\[for load\] → LOAD ×N → INSTALL\[for install (+make selectable)\]. |
#### Обзор карты (Explorer View)
После выполнения "Explore Card" отображается:
- **ISD** — AID, жизненный цикл, привилегии (без удаления; ISD нельзя удалить)
- **Приложения** — AID, жизненный цикл, привилегии, связанный ELF/SD. Каждое имеет кнопку **Delete** (GP `DELETE` по AID).
- **Executable Load Files** — AID, жизненный цикл, версии, AID модулей. Каждый имеет **Delete** (только ELF) и **Delete All** (каскадное: ELF + модули + установленные приложения, P2=0x80).
Удаление подтверждается через диалог браузера перед отправкой команды GP `DELETE` через SCP80. Обзор автоматически обновляется после успешного удаления.
---
## Card Reader (интеграция с pySim)
Подключение к встроенному [`pysim-otaman-server`](pysim_otaman_server/) для работы с картой.
> **Ограничение браузера:** если PWA раздаётся с публичного HTTPS-хоста, для доступа к локальному серверу (`http://127.0.0.1:8080`) нужны два условия: сервер должен отправлять `Access-Control-Allow-Private-Network: true` (pysim-otaman-server ≥ 1.6.1 делает это автоматически), и браузеру должно быть разрешено обращаться к локальной сети — в Chrome/Edge/Vivaldi: Настройки сайта → Доступ к локальной сети → разрешить сайт (или подтвердить запрос). Без разрешения браузера запрос к `127.0.0.1` блокируется ещё до отправки preflight.
### Файловый менеджер
Дерево файлов UICC. Отображаются имена, FID и AID (для ADF). Клик для чтения содержимого.
- **Read** — чтение файла (автоопределение transparent/record)
- **Edit** — режим редактирования, измените hex-данные и нажмите **Save** для записи
- **Raw / Decoded** — переключение между hex-дампом и декодированным JSON
### Пользовательские файлы
Файлы, отсутствующие в модели pysim, можно добавить вручную:
1. Перейдите на вкладку **Custom files**
2. Введите путь (например, `3F00/6F46`) и псевдоним (например, `EF.SPN`)
3. Нажмите **Add** — файл появится в дереве курсивом (непроверенный)
4. Кликните для проверки существования — при успехе работает как обычный файл
Пользовательские файлы сохраняются в `localStorage`. Экспорт/импорт в JSON для обмена.
### Подсказки команд
Введите имя команды в **pySim command line**. Подсказки по использованию появляются через 300 мс. Автодополнение команд — над полем ввода.
---
## Профайлер
Проверка соответствия карты именованному **профилю** — упорядоченному набору правил, описывающих ожидаемую файловую систему и (опционально) содержимое файлов. Профили хранятся в `localStorage`.
- **Новый профиль** создаёт пустой набор правил; **Профиль с карты** сканирует подключённую карту и создаёт по правилу на каждый существующий файл; **Импорт профиля** загружает набор из JSON (имя хранится внутри файла).
- В каждой строке профиля: **Проверить карту ▶** (на подключённой карте), **Проверить снимок карты** (offline по сохранённому снимку), **Редактировать**, **Экспорт** и **Удалить**.
Правило файловой системы задаётся:
- **Путь** — от `MF` (напр. `MF/7F10/6F3A`) или от AID ADF (напр. `A0000000871002/6F07`).
- **Проверка FCP/FCI** — **Только тип файла (FCP)**, **Тип файла + размер (FCP)** (добавляет размер файла или длину/число записей) либо **Полный FCI** (побайтовое сравнение сырого шаблона FCP `'62'` из ответа SELECT — ловит изменения FID/AID, life-cycle, security attributes и проприетарных параметров).
- **Атрибуты файла** — тип, размер, длина и число записей из шаблона FCP (любое можно не задавать).
- **Проверка содержимого** (опционально) — **Exact** (точное равенство hex) или **Mask**, где `?` — пониббловый джокер (маска без `?` — префиксное совпадение, напр. `0891` для MCC/MNC IMSI). Для record-файлов хранится список записей.
Отчёт проверки помечает каждый аспект (напр. *тип файла ✓, размер ✗, содержимое ✓*), показывает расхождения как поля только для чтения (ожидаемое/фактическое в одной колонке) и декодированное сравнение параметров FCI для расхождений FCI. Повреждённые FCI показывают всё, что удалось декодировать, плюс явное сообщение об ошибке; для записей указываются *совпадающие записи*. Опция **«Только расхождения»** скрывает все совпавшие файлы, оставляя несовпадения и ошибки.
#### Опции сканирования «Профиль с карты»
Диалог сканирования запрашивает имя профиля и предлагает режим FCP/FCI, список **«Игнорировать содержимое файлов»** (все включены, кроме `EF.ARR`; чекбокс в заголовке переключает весь список) — `EF.LOCI`, `EF.PSLOCI`, `EF.EPSLOCI`, `EF.5GS3GPPLOCI`, `EF.Keys`, `EF.KeysPS`, `EF.SMS`, `EF.Kc`, `EF.KcGPRS`, `EF.LOCIGPRS`, `EF.CBMID`, `EF.SMSS`, `EF.ACC`, `EF.EPSNSC`, `EF.START-HFN`, `EF.ARR` — и две включённые по умолчанию маски, сохраняющие только первые 4 байта `EF.IMSI` и `EF.ICCID`. Строка прогресса показывает *N / всего файлов* с текущим путём; во время сканирования опции заблокированы. Правила создаются только для существующих файлов; пользовательские файлы из подвкладки **Custom files** проверяются на существование так же.
#### Снимки карт
Представление списка имеет две вкладки — **«Профили»** и **«Снимки карт»**. Снимок — неизменяемая фиксация файловой системы: путь, символьное имя, тип, размер (или длина/число записей), сырой FCI и содержимое (если читается) каждого существующего файла. ICCID декодируется из EF.ICCID и показывается рядом с именем. При сканировании также измеряется время каждой команды карты (SELECT / READ BINARY / READ RECORD) от отправки до ответа; сохраняются min/сред/max по типам и общее время сканирования — они показываются в сводке снимка и по файлам/записям. Время носит информационный характер и не используется при проверках и сравнении.
- **Новый снимок** сканирует карту; **Импорт снимка** загружает JSON.
- В строке снимка: **Открыть** (все данные только для чтения, сырой FCI с декодированным и содержимое; редактируется только имя), **Экспорт**, **Удалить**.
- **Проверить снимок карты** в строке профиля выполняет правила профиля на выбранном снимке без картридера. Файлы без захваченного содержимого помечаются как непроверяемые ошибки.
- **Сравнить снимки** сравнивает два снимка offline так же, как проверка профиля: выберите *эталонный* снимок и *снимок для проверки*, при необходимости включите маску первых 4 байт EF.IMSI/EF.ICCID (включена по умолчанию). Всё должно совпадать точно (FCI, содержимое); файлы только в проверяемом снимке помечаются как лишние.
---
---
## Симулятор телефона
Вкладка **«Симулятор телефона»** обеспечивает взаимодействие с CAT-сессией в реальном времени. Две подвкладки: **«Телефон»** (меню STK, STATUS и опрос, подписанные события, журнал проактивных команд) и **«Конфигурация TR»** (данные ответов, подставляемые в TERMINAL RESPONSE для проактивных команд).
**Subscribed Events** — список событий SET UP EVENT LIST с кнопками **Send**. Клик открывает форму для конкретного типа события:
- **События без данных** (User Activity, Idle Screen и др.) — однократное уведомление
- **Location Status** — выпадающий список: Normal / Limited / No service
- **Access Technology Change** — 13 типов RAT
- **Network Rejection** — полная адаптивная форма: тип регистрации (LU / GPRS / EPS / 5GS), поля локации (MCC, MNC, LAC, RAC, TAC), доступные технологии, 53-позиционный выпадающий список причин отказа (EMM, GMM, 5GMM, LU)
**Proactive Command Log** — хронологический список проактивных команд. Каждая строка показывает время, код типа, имя и декодированный квалификатор.
**Конфигурация TR: словарь PLI** — редактируемые hex-значения для всех 22 квалификаторов PROVIDE LOCAL INFORMATION (TS 102 223 + TS 131 111). 10 квалификаторов имеют встроенные формы декодирования/кодирования:
| Код | Декодированные поля |
|------|--------------|
| 00 | MCC, MNC, LAC/TAC |
| 01 | IMEI (15 цифр) |
| 03 | Дата, время, TZ |
| 04 | Язык (2-символьный код) |
| 05 | ME Status, Timing Advance |
| 06 | Access Technology (выпадающий список) |
| 08 | IMEISV (16 цифр) |
| 09 | Search Mode (Auto/Manual) |
| 0A | Battery charge (%) |
| 0E | Multiple Access Technologies (список через запятую) |
Значения сохраняются на сервере до перезапуска. Apply → hex обновляется; Save → POST на сервер.
## PWA
OTAMan — Progressive Web App. Можно установить для offline-использования через кнопку **INSTALL PWA** или через браузер.
- Service worker кеширует все ресурсы при первом посещении
- Иконки 192×192 и 512×512
## Тема
Тёмная тема поддерживается. Следует системной теме, переключается вручную кнопкой (🌙/☀️). Выбор сохраняется в `localStorage`.
## Локализация
Интерфейс на английском с поддержкой русского языка. Язык определяется из `navigator.language`. Кнопка переключения (EN/RU) в заголовке сохраняет выбор в `localStorage`. При переключении языка динамические представления (списки профилей, отчёты проверок, снимки, карты, proactive) перерисовываются.
## Совместимость версий
| PWA (OTAMan) | Сервер | Статус |
|---|---|---|
| 1.x.x | 1.x.x | ✅ Совместимы |
| 1.x.x | 0.x.x | ❌ Сервер устарел |
| 1.x.x | 2.x.x+ | ⚠️ Сервер новее — обновите PWA |
PWA проверяет версию сервера при подключении через `GET /api/version`.
---
## Сервер (pysim-otaman-server)
Встроенный Python-сервер оборачивает [pySim](https://osmocom.org/projects/pysim/wiki) и раздаёт как PWA (из `frontend/`), так и JSON API по `/api/*`.
### Требования
- **Python 3.8+** с `pip`, и **Git**
- **Смарт-картридер** (PC/SC или serial/FTDI) — предпочтителен PC/SC (`pcsc-lite` + `ccid` на Linux)
- **Windows** — используйте Python 3.10–3.13 (рекомендуется 3.13): у `pyscard` есть готовые wheel. На 3.9 / 3.14 он собирается из исходников (нужны MSVC C++ Build Tools). SMPP-мост (`smpp.twisted3`) в Windows сознательно не ставится.
### Скрипты
| Скрипт | Назначение |
|--------|-------------|
| `setup.sh` / `setup.bat` | Создаёт `.venv/`, ставит pysim и сервер. Запускать один раз после клонирования. |
| `start.sh` / `start.bat` | Запускает сервер из venv (раздаёт PWA + API на `:8080`). |
`start.sh` автоопределяет ридер (PC/SC при работающем `pcscd`, иначе `/dev/ttyUSB0`); `start.bat` всегда использует `-p 0`. Без ридера сервер всё равно стартует («Reader: none») — карту можно инициализировать позже кнопкой **Equip**.
### Ручная установка
```sh
python3 -m venv .venv
source .venv/bin/activate # Linux/macOS (Windows: .venv\Scripts\activate)
pip install git+https://github.com/osmocom/pysim.git
pip install -e . # editable — раздаёт frontend/ из исходного дерева
pysim-otaman-server --http-port 8080
```
### Параметры CLI
| Параметр | Описание |
|----------|-------------|
| `--http-host` | Адрес привязки (по умолчанию `127.0.0.1`) |
| `--http-port` | Порт (по умолчанию `8080`) |
| `--web-dir` | Каталог со статикой PWA (по умолчанию `<repo>/frontend`) |
| `-p` / `--pcsc-device` | Номер слота PC/SC |
| `-d` / `--device` | Путь к serial-устройству |
| `--no-card-init` | Пропустить инициализацию карты (сохранить CAT-сессию) |
| `--apdu-trace` | Лог APDU-трафика в stderr |
| `--log-requests` | Лог запросов/ответов в stderr |
| `--poll-interval` | Интервал автоопроса STATUS (по умолчанию 30с; `0` отключает опрос) |
| `--full-pysim-init` | Штатная инициализация/equip из pysim (с лишними сбросами карты). По умолчанию инициализация без лишних сбросов — карта переподключается только по явным equip/reset |
| `--no-auto-equip` | Не инициализировать карту автоматически сразу после вставки (по умолчанию автоинициализация включена) |
| `--menu-timeout` | Автоответ timeout TERMINAL RESPONSE на приостановленную STK-команду (по умолчанию 60с; `0` отключает) |
| `--timing` | Лог длительности фаз, сбросов карты и счётчиков APDU с отметками времени |
### Устранение неполадок
- **"Failed to establish context: Access denied"** — `pcscd` не запущен или нет прав: `sudo systemctl enable --now pcscd && sudo usermod -a -G pcscd $USER`.
- **"device file /dev/ttyUSB0 does not exist"** — нет serial-ридера; подключите USB-ридер или укажите `-d`. Сервер всё равно стартует без ридера.
### Справочник API
Полный справочник endpoints: [docs/api.md](docs/api.md).