From 3db6f59e699f4f001b5a2d3f31ade1de215a490b 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: Thu, 15 Oct 2026 09:41:29 +0300 Subject: [PATCH] v3.30.2: the batch RU wording sweep completed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The v3.30.1 review follow-up. The sweep fixed the two batch-state strings but two more shared (kind-independent) batch strings were still install-specific, so a delete/reinstall batch started under an "install" label: - 'Start batch' was «Запустить пакетную установку» - the ram-batch-start button starts every kind - now «Запустить пакетную операцию» (aligning with the optgroup «Пакетные операции (по картам)»). - the shared panel hint's «...перезапустите пакетную установку» is now «...перезапустите пакетную операцию» (the EN was already neutral). The RU help quoted the old button label: its install row now says «Запустить пакетную операцию не требует карты», and the row's other generic "the batch" statements (never retries, the test-run exclusion) are neutral too; the genuinely install-specific ones (the workflow, the shared install form) stay. The v3.30.1 notes were corrected: the counts labels do follow the last run's kind after a clear (the values stay zero) - the AGENTS entry and the _ramBatchLastKind/ramBatchRender comments say so now. The cleared-title test seeds the state before opening the modal (no reliance on the previous test's sandbox leftovers). 930 frontend + 945 Python; sw cache simple-v452. --- frontend/help-ru.html | 2 +- frontend/index.html | 13 +++++++------ frontend/sw.js | 2 +- frontend/tests/ram_batch.test.js | 5 +++-- pyproject.toml | 2 +- pysim_simple_server/server.py | 2 +- 6 files changed, 14 insertions(+), 12 deletions(-) diff --git a/frontend/help-ru.html b/frontend/help-ru.html index c080c91..541451c 100644 --- a/frontend/help-ru.html +++ b/frontend/help-ru.html @@ -323,7 +323,7 @@ Обзор карты (все данные GP)Запрос GET STATUS для ISD, приложений, ELF и модулей ELF, а также GET DATA FF21 (расширенные ресурсы карты: число установленных приложений и свободная энергонезависимая/энергозависимая память). Компактный листинг содержит только AID, состояние жизненного цикла и привилегии (версии в устаревшем формате нет); если карта отвергает его (P2.b2=0, устаревший по GP), запросы повторяются в расширенном формате E3, а флажок Запрашивать расширенные данные реестра (связи load-файла и SD) дополнительно запрашивает их и объединяет расширенные поля: версию исполняемого load-файла, AID load-файла, AID Security Domain, списки модулей, пункты меню STK апплета (SCP Registry Data, TS 102 226 8.2.1.6) и любые другие объекты реестра, которые вернула карта (показываются как есть, без потерь) — он стоит несколько дополнительных защищённых пакетов на каждый обзор и включён по умолчанию (запоминается в браузере; снимите флажок, чтобы пропустить). Карты различаются в том, что принимают, поэтому расширенный запрос пробуется в трёх формах — эталонный список тегов (с EA по TS 102 226), тот же список без EA и вовсе без списка тегов (форма GlobalPlatformPro) — а обзор сообщает, какая форма сработала и где выполнен откат к компактному списку (версии пакетов тогда недоступны). Если строки ELF всё ещё без версий, формы со списком тегов повторяются для обоих P1=10 и P1=20, пропуская уже отклонённые комбинации, и обход останавливается, как только версия найдена. Результаты отображаются в обзоре (строка успеха минимальна, счётчики — в заголовках разделов) с кнопками Удалить для каждого элемента и определённым форматом команд RAM (подсказка при наведении объясняет compact и expanded). Установка пакета (.cap файл)Отправка .cap файла на карту через сервер: INSTALL[for load] → LOAD ×N → INSTALL[for install (+make selectable)]. Load-файл делится на LOAD APDU размера размер блока LOAD (1–240 байт полезной нагрузки, по умолчанию 240); каждый защищённый пакет доставляется одним SMS или, если он больше, конкатенированной SMS-PP загрузкой до 5 сегментов, так что большой .cap просто занимает несколько SMS. Сразу после выбора файл проверяется и в форме показывается оценка требований к памяти: требование NVRAM (образ кода + постоянные данные, сумма в стиле C6+C8 из GP Card Spec) и оценка RAM. Там же показаны библиотеки, с которыми слинкован CAP (его компонент Import: имя библиотеки, AID и минимальная версия ≥ x.y — имена стандартных библиотек и семейства подставляются, а где известно, даётся подсказка о версии Java Card), идентификаторы пакета и апплетов и разбивка по компонентам (размеры и доли в порядке load-файла) — всё сгруппировано по разделам Package, Requires, Memory и Components. Строка Platform показывает минимальный уровень Java Card, который должна предоставить карта (выводится из импорта javacard.framework; флаг int в заголовке дополнительно требует поддержки int — Java Card 2.2+), и релиз ETSI, из которого пришли импорты UICC API (версия uicc.toolkit → REL-N по корпусу sim-tools в рабочем каталоге; основание показано в скобках): JCRE проверяет каждый импорт по своим пакетам при верификации load-файла (JC VM spec 4.5.2), поэтому карта со старой платформой отклоняет LOAD сразу после завершения компонента Import (в строке шага виден remote SW карты и компонент, который завершил блок, например завершает Import): подсказка при ошибке и попап предлагают тест совместимости CAP (в один клик — тот же .cap уже выбран), чтобы найти отсутствующий пакет и версию; меньший размер блока LOAD помогает только если блок превышает буфер карты. Повреждённый файл не проходит анализ, и Execute остаётся недоступной до успешного анализа. Оценка носит справочный характер и никогда не используется при установке: NVRAM — это образ кода плюс постоянные данные (сумма в стиле C6+C8 по GP Table 11-48; управление памятью карты, округление и запись в реестре не учитываются, а образ статических полей входит в обе части); рекомендуемый C6 следует за load-файлом, а рекомендуемые квоты — это десятичные значения в байтах (шестнадцатеричное значение в скобках — это кодирование параметров установки C7/C8: C6 — энергонезависимый код, C7 — энергозависимая RAM, C8 — энергонезависимые данные). Флажок Удалить пакет перед установкой (с его приложениями) добавляет перед цепочкой каскадный GP DELETE по AID пакета (load-файл с его модулями и приложениями, P2=0x80) — оставшийся пакет блокирует INSTALL[for load]; «не найдено» (свежая карта) пропускается, любая другая ошибка удаления останавливает цепочку с её причиной. - Пакетная установка (.cap на множество карт)Массовый сценарий: один .cap и один набор параметров установки, применяемые карта за картой. Запустить пакетную установку не требует карты — цикл ведёт сервер: он ждёт карту, устанавливает сразу после завершения equip и затем ждёт следующую. Для каждой карты пресет находится по ICCID и задаёт keyset (по умолчанию из ролевой записи ISD TAR, v3.26.0), ключи и счётчик; карта без подходящего пресета или без пригодного keyset ISD TAR отмечается и пропускается. Каждая попытка попадает в список со временем, ICCID, пресетом, вердиктом и длительностью; при ошибке показаны шаг, на котором она произошла, и удалённый статусный байт — пакетная установка никогда не повторяет попытку и не останавливается при ошибке (ошибки остаются на ваше усмотрение). Карта обрабатывается один раз за запуск: повторная установка карты даёт «уже обработана» — для повтора перезапустите пакетную установку. Остановить завершает работу после окончания обработки текущей карты (прерванная цепочка LOAD может оставить полузагруженный пакет), а затем завершает запуск; Очистить удаляет отчёт завершённого запуска. Цикл работает на сервере, поэтому закрытие вкладки, переключение представлений или перезагрузка страницы его не прерывают; перезапуск сервера завершает запуск. Пакетная установка и тест-скрипт исключают друг друга. Пакетная установка использует ту же форму, поэтому параметр Удалить пакет перед установкой применяется к каждой карте. + Пакетная установка (.cap на множество карт)Массовый сценарий: один .cap и один набор параметров установки, применяемые карта за картой. Запустить пакетную операцию не требует карты — цикл ведёт сервер: он ждёт карту, устанавливает сразу после завершения equip и затем ждёт следующую. Для каждой карты пресет находится по ICCID и задаёт keyset (по умолчанию из ролевой записи ISD TAR, v3.26.0), ключи и счётчик; карта без подходящего пресета или без пригодного keyset ISD TAR отмечается и пропускается. Каждая попытка попадает в список со временем, ICCID, пресетом, вердиктом и длительностью; при ошибке показаны шаг, на котором она произошла, и удалённый статусный байт — пакетная операция никогда не повторяет попытку и не останавливается при ошибке (ошибки остаются на ваше усмотрение). Карта обрабатывается один раз за запуск: повторная установка карты даёт «уже обработана» — для повтора перезапустите пакетную операцию. Остановить завершает работу после окончания обработки текущей карты (прерванная цепочка LOAD может оставить полузагруженный пакет), а затем завершает запуск; Очистить удаляет отчёт завершённого запуска. Цикл работает на сервере, поэтому закрытие вкладки, переключение представлений или перезагрузка страницы его не прерывают; перезапуск сервера завершает запуск. Пакетная операция и тест-скрипт исключают друг друга. Пакетная установка использует ту же форму, поэтому параметр Удалить пакет перед установкой применяется к каждой карте. Пакетная переустановка приложения (по картам)Сценарий исправления: для каждой карты удаляется экземпляр приложения (с допуском «не найдено») и заново выполняется INSTALL [for install] из уже загруженного пакета — без .cap и без LOAD. Поля — параметры одиночного INSTALL [for install] (Load File / Module / Instance AID, привилегии, параметры toolkit/STK, make selectable); пресет, keyset и счётчик берутся из пресета каждой карты, как в остальных пакетных операциях, а список попыток показывает оба вердикта (удаление и установка). Пакетное удаление (по картам)Удаляет один объект на каждой карте: приложение (только экземпляр, P2=0x00) или пакет с его приложениями (каскадно, P2=0x80). Поля: AID и цель. Результат «не найдено» (объект уже отсутствует) отмечается как таковой и считается успешным; любая другая ошибка показывается со статусным словом карты. Проверка совместимости CAPОтвечает на один вопрос, ничего не устанавливая: может ли эта карта удовлетворить список импортов CAP? Сервер выполняет проверку формата, INSTALL[for load] и блоки LOAD только до блока, завершающего компонент Import — именно там JCRE проверяет список импортов — и останавливается: без флага последнего блока и без INSTALL[for install], поэтому ничего не фиксируется и удалять после этого ничего не нужно. Список «Версии импортов для проверки» предзаполняется из анализа CAP: AID=version переписывает запрошенную версию импорта, +AID=version добавляет синтетический импорт (запрос возможностей карты: LOAD проходит, только если карта экспортирует этот пакет версии ≥ указанной), а «Все 0.0» снимает все требования. Использование в два шага: нажмите «Все 0.0» — если проверка проходит, причиной был список импортов; затем возвращайте по одной строке, чтобы найти пакет и версию, которых не хватает карте. Вердикт явно указывает, что проверяется только этап LOAD/импортов: этап связывания (наличие реально вызываемых API) проверяет настоящая установка на INSTALL[for install]. Запуск и результат показываются в окне (как при установке): строки шагов, вердикт и блок деталей по каждому AID — при отказе он называет раздел CAP, который покрывает неудачный блок (диапазон байтов load-файла и компоненты, и завершает ли этот блок Import), SW команды с его значением, список импортов ровно в том виде, в каком он проверялся (версии CAP, правки пробы, добавленные синтетические записи, строки без совпадений) и что означает состояние пробы; при успехе — список импортов, который прошёл проверку. diff --git a/frontend/index.html b/frontend/index.html index 5d58271..1e3f7e2 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -1932,7 +1932,7 @@ // ===== Version ===== // Single source of truth for the PWA version: shown in the header and used // by the server version check in pysimConnect(). -const SIMPLE_VERSION = '3.30.1'; +const SIMPLE_VERSION = '3.30.2'; document.getElementById('app-version').textContent = 'v' + SIMPLE_VERSION; // ===== view history (the browser Back/Forward buttons) ===== @@ -10192,8 +10192,8 @@ let _ramBatchSummary = null; // /api/status.ram_batch let _ramBatchProgress = null; // /api/status.ram_progress let _ramBatchModalShown = false; // the batch status modal is open (v3.30.0) let _ramBatchLastKind = null; // the last seen run kind: a cleared report - // (kind: null) keeps the modal's title right - // (v3.30.1) + // (kind: null) keeps the modal's title and the + // counts labels on that kind (v3.30.1) // A fetch that never settled must not block the report forever (v3.28.7). const RAM_BATCH_FETCH_STALE_MS = 10000; @@ -10351,7 +10351,8 @@ function ramBatchRender() { const phase = st.phase || (active ? 'waiting_card' : 'idle'); // The success labels follow the operation (v3.29.0): the counts bucket is // 'installed' for every kind - "the operation succeeded". The last seen - // kind is remembered for the modal's title (v3.30.1). + // kind is remembered for the modal's title and these labels, so a cleared + // report keeps the run's kind (v3.30.1). if (st.kind) _ramBatchLastKind = st.kind; const kind = st.kind || _ramBatchLastKind || 'install-cap'; const okLabel = kind === 'delete' ? t('Deleted') @@ -24681,7 +24682,7 @@ const LANG_RU = { 'Delete the package before installing (with its applications)': 'Удалить пакет перед установкой (с его приложениями)', 'AID must be 5-16 bytes of hex': 'AID должен быть 5-16 байт hex', 'not found': 'не найдено', - 'Start batch': 'Запустить пакетную установку', + 'Start batch': 'Запустить пакетную операцию', 'Stopping...': 'Остановка…', 'Batch stopped': 'Пакетная операция остановлена', 'Batch finished': 'Пакетная операция завершена', @@ -24696,7 +24697,7 @@ const LANG_RU = { 'Skipped': 'Пропущено', 'attempts': 'попыток', 'No cards processed yet.': 'Карты ещё не обрабатывались.', - 'The preset, keyset and counter come from each card\'s own preset (matched by ICCID). A card is attempted once per run: re-equipping it reports it as already processed - restart the batch to retry. Stop finishes the current card first.': 'Пресет, keyset и счётчик берутся из пресета каждой карты (совпадение по ICCID). Карта обрабатывается один раз за запуск: повторная установка карты отмечается как уже обработанная — для повтора перезапустите пакетную установку. «Остановить» завершает работу после окончания обработки карты.', + 'The preset, keyset and counter come from each card\'s own preset (matched by ICCID). A card is attempted once per run: re-equipping it reports it as already processed - restart the batch to retry. Stop finishes the current card first.': 'Пресет, keyset и счётчик берутся из пресета каждой карты (совпадение по ICCID). Карта обрабатывается один раз за запуск: повторная установка карты отмечается как уже обработанная — для повтора перезапустите пакетную операцию. «Остановить» завершает работу после окончания обработки карты.', 'Do not close or reload this window while the operation is running.': 'Не закрывайте и не перезагружайте окно, пока операция выполняется.', 'Working...': 'Выполняется...', 'APDU hex': 'APDU (hex)', diff --git a/frontend/sw.js b/frontend/sw.js index b717b14..2f9b173 100644 --- a/frontend/sw.js +++ b/frontend/sw.js @@ -1,4 +1,4 @@ -const CACHE = 'simple-v451'; +const CACHE = 'simple-v452'; const URLS = [ 'index.html', 'help.html', diff --git a/frontend/tests/ram_batch.test.js b/frontend/tests/ram_batch.test.js index 885a72e..afdb8e2 100644 --- a/frontend/tests/ram_batch.test.js +++ b/frontend/tests/ram_batch.test.js @@ -578,10 +578,11 @@ test('a cleared report keeps the run kind in the modal title (v3.30.1)', () => { setModalEls(); setPanelEls(); app.setSummary(null); - app.ramBatchModalOpen(); + // the state is seeded before the window opens: no reliance on the sandbox + // leftovers of the previous test (the modal opens into the run's kind) app.setLast({ kind: 'delete', active: false, phase: 'finished', attempts: [], counts: { installed: 2 }, attempts_total: 2 }); - app.ramBatchRender(); + app.ramBatchModalOpen(); assert.strictEqual(els['ram-op-title'].textContent, 'Batch delete (per card)'); // Clear empties the state (kind: null): the title must not flip to install app.setLast({ kind: null, active: false, phase: 'idle', attempts: [], diff --git a/pyproject.toml b/pyproject.toml index b0fa5e6..fa1ef86 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "pysim-simple-server" -version = "3.30.1" +version = "3.30.2" description = "HTTP REST server wrapping pysim for the SIMple PWA" requires-python = ">=3.8" # pysim is a git-only dependency installed explicitly by setup.bat/setup.sh. diff --git a/pysim_simple_server/server.py b/pysim_simple_server/server.py index 72916bf..b4eb463 100644 --- a/pysim_simple_server/server.py +++ b/pysim_simple_server/server.py @@ -37,7 +37,7 @@ from osmocom.tlv import BER_TLV_IE from osmocom.utils import rpad -VERSION = '3.30.1' +VERSION = '3.30.2' MAX_ENVELOPE_SEGMENTS = 5 # max SMS segments for outgoing C-APDU in ENVELOPE