release: v3.9.0 - the operation start buttons wait for a preset and a keyset

Gating: the SCP80 "Send to Card", the RAM Execute and the TAR-probe Execute
buttons carry `data-needs-keyset`; pysimApplyAvailability() disables them
(with the hint "Select a card preset and its keyset" when the card itself is
fine) unless the view's preset is selected and the form's keyset number is one
of its keysets - `spKeysetStartReady`, the same rule the click-time guards
enforce, which stay as the last line of defence.  spKeysetSync() refreshes the
gate on every preset/keyset change, and the KIc/KID index selects now call
spKeysetSync() so the keyset selector follows a manual index change too.

Version 3.9.0: server VERSION, pyproject.toml and the PWA header; sw cache
simple-v346; the workspace AGENTS gains its v3.9.0 history entry.

Tests: indicator.test.js drives the gate (no preset -> disabled with the hint,
an undefined keyset -> disabled, a matching keyset -> enabled) and guards the
three buttons' attribute; the cards/keysets/ram sandboxes stub
pysimApplyAvailability.  Help EN/RU notes the disabled start buttons.
This commit is contained in:
2026-10-01 22:03:36 +03:00
parent f261695b86
commit 0cccd62230
11 changed files with 91 additions and 15 deletions
+3 -3
View File
@@ -282,7 +282,7 @@
<p class="mb-3">Верхнеуровневая вкладка <strong>SCP80</strong> объединяет разделы, связанные с SCP80. Переключение — тремя переключателями: <strong>Secured Packet</strong>, <strong>RAM</strong> и <strong>TAR-сканер</strong>. Собирает защищённые пакеты SCP80 по ETSI TS 102 225. При подключении карты сервер читает её <strong>EF.ICCID</strong> (2FE2); если в пресете указан тот же номер (цифрами или сырым hex из EF), он автоматически выбирается во всех трёх представлениях SCP80. Вердикт <strong>низкого счётчика</strong> (<code class="font-mono text-sm">cntr_low</code> или предупреждающий ответ ENVELOPE, в котором всё ещё есть такой PoR) <em>не</em> исправляется повторной отправкой: любая операция SCP80/RAM немедленно останавливается, результат показывает счётчик карты и кнопку <strong>К пресету</strong>, открывающую соответствующий пресет на вкладке Cards, где счётчик нужно поднять выше &mdash; автоматически ничего не записывается.</p>
<h3 id="secured-packet" class="text-lg font-medium mb-2">3.1 Secured Packet</h3>
<p class="mb-2">Собирает защищённые пакеты SCP80 по ETSI TS 102 225. Селектор <strong>Keyset</strong> рядом с выбором пресета указывает, из какого keyset берутся ключи и счётчик; отправка отклоняется, если в пресете нет такого номера keyset или KIc/KID несут разные номера (TS 102 225 A.2). Селектор недоступен, пока не выбран пресет карты.</p>
<p class="mb-2">Собирает защищённые пакеты SCP80 по ETSI TS 102 225. Селектор <strong>Keyset</strong> рядом с выбором пресета указывает, из какого keyset берутся ключи и счётчик; отправка отклоняется, если в пресете нет такого номера keyset или KIc/KID несут разные номера (TS 102 225 A.2). Селектор недоступен, пока не выбран пресет карты. Кнопка запуска недоступна, пока не выбран пресет карты и один из его keysets.</p>
<h4 id="packet-structure" class="font-medium mb-1">Структура пакета</h4>
<table class="w-full text-sm mb-3 border-collapse">
<thead><tr class="border-b border-gray-300 dark:border-slate-700"><th class="text-left py-1 px-2">Поле</th><th class="text-left py-1 px-2">Размер</th><th class="text-left py-1 px-2">Описание</th></tr></thead>
@@ -314,7 +314,7 @@
<p class="text-sm mb-3">Кнопка <strong>Проверить в pySim</strong> сверяет собранный пакет с эталонной реализацией <code class="font-mono text-sm">OtaDialectSms.encode_cmd</code>. Кнопка <strong>Отправить на карту</strong> доставляет пакет через ENVELOPE SMS-PP-DOWNLOAD (при подключении к серверу). 2-байтовый префикс CPL передаётся, когда пакет зашифрован или несёт RC/CC/DS (входит в их входные данные), а также при конкатенации SMS; одиночное незащищённое SMS сохраняет форму pySim, начинающуюся с CHL (TS 31.115 Table 1 NOTE). Под полем пакета показывается его размер и число SMS; пакет, не помещающийся в одно SMS, отправляется <strong>конкатенированной</strong> загрузкой (TS 31.115 &sect;4.3) &mdash; пакет делится на части SMS-пользовательских данных (первое SMS 132 октета, последующие по 134; первое дополнительно несёт информационные элементы конкатенации и CPI), и сегменты отправляются по порядку. Более 5 сегментов отклоняется: это практический предел буфера конкатенации карты. Полученный Proof of Receipt декодируется и показывается строкой статуса PoR (статус, TAR, счётчик, сырой PoR); статусное слово и данные ответа последней команды подставляются в подвкладку <strong>&laquo;Разбор R-APDU&raquo;</strong> (Remote APDU &rarr; &laquo;Разбор&raquo;), а успешный PoR увеличивает счётчик повторов (когда в SPI1 есть проверка счётчика &mdash; b5 b4 &ne; 00; без неё счётчик не увеличивается и не сохраняется) и очищает пакет.</p>
<h3 id="ram" class="text-lg font-medium mb-2">3.2 RAM</h3>
<p class="mb-2">Выполняет операции удалённого управления приложениями (Remote Application Management) как защищённые пакеты SCP80 через SMS-PP-DOWNLOAD ENVELOPE. Карта должна поддерживать SCP03 (AES или 3DES). Пресет карты со вкладки <strong>Карты</strong> обеспечивает SPI, ключи, TAR и счётчик (RAM использует <strong>ISD TAR</strong> пресета, по умолчанию <code class="font-mono text-sm">000000</code>). Селектор <strong>Keyset</strong> рядом с выбором пресета указывает, из какого keyset берутся ключи и счётчик операции. Селектор недоступен, пока не выбран пресет карты.</p>
<p class="mb-2">Выполняет операции удалённого управления приложениями (Remote Application Management) как защищённые пакеты SCP80 через SMS-PP-DOWNLOAD ENVELOPE. Карта должна поддерживать SCP03 (AES или 3DES). Пресет карты со вкладки <strong>Карты</strong> обеспечивает SPI, ключи, TAR и счётчик (RAM использует <strong>ISD TAR</strong> пресета, по умолчанию <code class="font-mono text-sm">000000</code>). Селектор <strong>Keyset</strong> рядом с выбором пресета указывает, из какого keyset берутся ключи и счётчик операции. Селектор недоступен, пока не выбран пресет карты. Кнопка запуска недоступна, пока не выбран пресет карты и один из его keysets.</p>
<h4 id="ram-operations" class="font-medium mb-1">Операции</h4>
<table class="w-full text-sm mb-3 border-collapse">
@@ -340,7 +340,7 @@
</section>
<section class="mb-10">
<h3 id="tar-probe" class="text-lg font-medium mb-2">3.3 TAR-сканер</h3>
<p class="mb-2">Третья пилюля вкладки SCP80 показывает, <strong>какие OTA-приложения зарегистрированы на карте</strong>: отправляется <strong>по одному защищённому пакету на каждый выбранный TAR</strong> &mdash; стандартные значения из TS 101 220 V18.3.0 Annex D, Table D.1, каждая строка несёт документ-источник &mdash; с безобидной C-APDU (по умолчанию <code class="font-mono text-sm">SELECT MF</code>), пресетом и keyset этого представления, SPI <code class="font-mono text-sm">16/01</code> (проверка счётчика + PoR).</p>
<p class="mb-2">Третья пилюля вкладки SCP80 показывает, <strong>какие OTA-приложения зарегистрированы на карте</strong>: отправляется <strong>по одному защищённому пакету на каждый выбранный TAR</strong> &mdash; стандартные значения из TS 101 220 V18.3.0 Annex D, Table D.1, каждая строка несёт документ-источник &mdash; с безобидной C-APDU (по умолчанию <code class="font-mono text-sm">SELECT MF</code>), пресетом и keyset этого представления, SPI <code class="font-mono text-sm">16/01</code> (проверка счётчика + PoR). Кнопка <strong>Execute</strong> недоступна, пока не выбран пресет карты и один из его keysets.</p>
<p class="mb-2">Список предзаполнен стандартными TAR (все отмечены; кнопки <strong>Выбрать все</strong> / <strong>Снять все</strong> переключают быстро), свои TAR добавляются кнопкой <strong>Добавить TAR</strong> (три hex-байта и необязательное описание). Пользовательские записи хранятся в <code class="font-mono text-sm">localStorage</code> по возможности &mdash; их потеря безвредна.</p>
<p class="mb-2">Каждый TAR классифицируется по ответу карты: <strong>зарегистрировано</strong> (ENVELOPE 9000 + PoR со SW и данными приложения), <strong>принято, нет ответа</strong> (PoR без R-APDU), <strong>принято, нет PoR</strong> (пакет молча отброшен) и <strong>отклонено</strong> (ENVELOPE не 9000, обычно <code class="font-mono text-sm">6200</code> для TAR без зарегистрированного приложения). Таблица результата появляется в окне операции; строка под кнопкой Execute показывает <code class="font-mono text-sm">зарегистрировано N / M</code>.</p>
<p class="mb-2">Каждый принятый картой пакет <strong>расходует счётчик</strong>, который сохраняется в keyset пресета &mdash; проба отклоняется, если в SPI1 нет проверки счётчика или в пресете нет такого номера keyset. На живой карте: <code class="font-mono text-sm">000000</code>, <code class="font-mono text-sm">B00000</code> и <code class="font-mono text-sm">B00001</code> зарегистрированы (приложения компактного формата), расширенный формат, USAT, мультиплексирование и CASD отклонены с <code class="font-mono text-sm">6200</code>.</p>