From 2a03c749411458fafc084a576912cae115128e87 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: Sat, 19 Sep 2026 00:15:18 +0300 Subject: [PATCH] cards: group the form into SCP80/SCP81 fieldsets, close the RU i18n gaps (v2.2.19) - The card create/edit form now surrounds the SCP80 parameters (KIc/KID, SPI1/SPI2, TAR, counter, keys) with a bordered
labelled 'SCP80 (GSM 03.48, ETSI TS 102 225)' and the PSK pair (with the listener explanation) with one labelled 'SCP81 (HTTP OTA)'; the name/ICCID row and the list stay outside the groups. - i18n: the SCP81 PSK note is translated now, plus the keys an audit found missing from the RU dictionary (Start, Clear, Loading..., Working..., APDU hex, CAP file (max 48 kB), Install from .cap, Card reader server is not connected, KIc/KID required messages, Memory (GET DATA FF21), the two no-secured-packet alerts, Select, event notification to the card?). - Tests: html.test.js guards both fieldsets, their legends and that the PSK note and fields live inside the SCP81 group (401 frontend tests). - Docs: help EN+RU Cards intro. SW cache otaman-v186. --- frontend/help-ru.html | 2 +- frontend/help.html | 2 +- frontend/index.html | 63 +++++++++++++++++++++++++---------- frontend/sw.js | 2 +- frontend/tests/html.test.js | 15 +++++++++ pyproject.toml | 2 +- pysim_otaman_server/server.py | 2 +- 7 files changed, 65 insertions(+), 23 deletions(-) diff --git a/frontend/help-ru.html b/frontend/help-ru.html index ab19d06..17c7fa1 100644 --- a/frontend/help-ru.html +++ b/frontend/help-ru.html @@ -298,7 +298,7 @@

4. Вкладка «Карты»

-

Хранит предустановки карт локально в браузере (localStorage), чтобы представление Secured Packet могло автоматически подставлять ключи и параметры, а слушатель SCP81 HTTP OTA — находить PSK-ключи. «Карты» — верхнеуровневая вкладка. При подключении карты читается её EF.ICCID, и предустановка с тем же ICCID автоматически выбирается в обоих представлениях SCP80.

+

Хранит предустановки карт локально в браузере (localStorage), чтобы представление Secured Packet могло автоматически подставлять ключи и параметры, а слушатель SCP81 HTTP OTA — находить PSK-ключи. «Карты» — верхнеуровневая вкладка. При подключении карты читается её EF.ICCID, и предустановка с тем же ICCID автоматически выбирается в обоих представлениях SCP80. Поля формы сгруппированы в два блока с рамкой: SCP80 (GSM 03.48, ETSI TS 102 225) (KIc/KID, SPI1/SPI2, TAR, счётчик и ключи) и SCP81 (HTTP OTA) (пара PSK identity/ключ с пояснением о выборе ключа).

diff --git a/frontend/help.html b/frontend/help.html index 393ef91..b56e2c0 100644 --- a/frontend/help.html +++ b/frontend/help.html @@ -298,7 +298,7 @@

4. Cards tab

-

Stores card presets locally in the browser (localStorage) so the Secured Packet view can auto-fill keys and parameters, and so the SCP81 HTTP OTA listener can look up PSK keys. Cards is a top-level tab. When the card is equipped its EF.ICCID is read and the preset with the same ICCID is selected automatically in both SCP80 views.

+

Stores card presets locally in the browser (localStorage) so the Secured Packet view can auto-fill keys and parameters, and so the SCP81 HTTP OTA listener can look up PSK keys. Cards is a top-level tab. When the card is equipped its EF.ICCID is read and the preset with the same ICCID is selected automatically in both SCP80 views. The form groups the fields into two bordered blocks: SCP80 (GSM 03.48, ETSI TS 102 225) (KIc/KID, SPI1/SPI2, TAR, counter and keys) and SCP81 (HTTP OTA) (the PSK identity/key pair with the key-selection note).

ПолеОписание
diff --git a/frontend/index.html b/frontend/index.html index a0945d6..c50e5ce 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -18,7 +18,7 @@
-

OTAMan SIM OTA with a Human Face v2.2.18

+

OTAMan SIM OTA with a Human Face v2.2.19

@@ -1141,23 +1141,29 @@
-
- - - - - - -
-
- - -
-
- - -
-

SCP81 HTTP OTA: the listener picks the key by the PSK identity the card sends in the TLS handshake. Cards without a PSK are ignored by the listener.

+
+ SCP80 (GSM 03.48, ETSI TS 102 225) +
+ + + + + + +
+
+ + +
+
+
+ SCP81 (HTTP OTA) +
+ + +
+

SCP81 HTTP OTA: the listener picks the key by the PSK identity the card sends in the TLS handshake. Cards without a PSK are ignored by the listener.

+
FieldDescription
@@ -11666,6 +11672,27 @@ const LANG_RU = { 'pending': 'ожидает', 'Name is required': 'Укажите имя', 'From card': 'С карты', + 'SCP80 (GSM 03.48, ETSI TS 102 225)': 'SCP80 (GSM 03.48, ETSI TS 102 225)', + 'SCP81 (HTTP OTA)': 'SCP81 (HTTP OTA)', + 'Start': 'Запустить', + 'Clear': 'Очистить', + 'Loading...': 'Загрузка...', + 'Working...': 'Выполняется...', + 'APDU hex': 'APDU (hex)', + 'CAP file (max 48 kB)': 'CAP-файл (не более 48 кБ)', + 'Install from .cap': 'Установить из .cap', + 'RAM': 'RAM', + 'SCP81': 'SCP81', + 'Secured packet': 'Secured packet', + 'Card reader server is not connected': 'Сервер картридера не подключён', + 'KIc and KID are required': 'Укажите KIc и KID', + 'KIc key and KID key are required': 'Укажите ключ KIc и ключ KID', + 'Memory (GET DATA FF21)': 'Память (GET DATA FF21)', + 'No secured packet to send. Generate a secure packet first.': 'Нет защищённого пакета для отправки. Сначала соберите пакет.', + 'No secured packet to verify. Generate a secure packet first.': 'Нет защищённого пакета для проверки. Сначала соберите пакет.', + 'Select': 'Выборка', + 'event notification to the card?': 'уведомление о событии на карту?', + 'SCP81 HTTP OTA: the listener picks the key by the PSK identity the card sends in the TLS handshake. Cards without a PSK are ignored by the listener.': 'SCP81 HTTP OTA: слушатель выбирает ключ по PSK identity, которую карта присылает в TLS-рукопожатии. Карты без PSK слушателем игнорируются.', 'Card with this ICCID already exists': 'Карта с таким ICCID уже есть в списке', 'Card equipped but its ICCID is not readable': 'Карта подключена, но её ICCID не читается', 'Saved.': 'Сохранено.', diff --git a/frontend/sw.js b/frontend/sw.js index 5b4f48a..102d73b 100644 --- a/frontend/sw.js +++ b/frontend/sw.js @@ -1,4 +1,4 @@ -const CACHE = 'otaman-v185'; +const CACHE = 'otaman-v186'; const URLS = [ 'index.html', 'help.html', diff --git a/frontend/tests/html.test.js b/frontend/tests/html.test.js index 62ba639..09ce94f 100644 --- a/frontend/tests/html.test.js +++ b/frontend/tests/html.test.js @@ -25,6 +25,21 @@ test('cards list shows the SCP81 PSK column with blue/red row buttons', () => { assert.match(fn[0], /cardsRemove\(' \+ i \+ '\)" class="[^"]*bg-red-600 text-white/); }); +test('the card form groups the SCP80 and SCP81 fields into labelled fieldsets', () => { + const fieldsets = [...html.matchAll(//g)].map(m => m[0]); + assert.strictEqual(fieldsets.length, 2); + assert.match(fieldsets[0], /]*data-l10n="SCP80 \(GSM 03\.48, ETSI TS 102 225\)"/); + assert.match(fieldsets[0], /id="cards-kic"/); + assert.match(fieldsets[0], /id="cards-kid-key"/); + assert.match(fieldsets[1], /]*data-l10n="SCP81 \(HTTP OTA\)"/); + assert.match(fieldsets[1], /id="cards-psk-id"/); + assert.match(fieldsets[1], /id="cards-psk-key"/); + // the PSK explanation lives inside the SCP81 group, not outside it + assert.match(fieldsets[1], /data-l10n="SCP81 HTTP OTA: the listener picks the key/); + // the ICCID field is not in either group + assert.ok(!fieldsets.some(f => f.includes('id="cards-iccid"'))); +}); + test('PLI qualifier tables cover all standard qualifiers', () => { // ESN (07), MEID (0B) and Supported RATs (1A) must at least be named, in // both the TR Config dictionary and the proactive-log short labels. diff --git a/pyproject.toml b/pyproject.toml index a2a2378..6b52c93 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "pysim-otaman-server" -version = "2.2.18" +version = "2.2.19" description = "HTTP REST server wrapping pysim for the OTAMan PWA" requires-python = ">=3.8" # pysim is a git-only dependency installed explicitly by setup.bat/setup.sh. diff --git a/pysim_otaman_server/server.py b/pysim_otaman_server/server.py index e6346c6..19928e8 100644 --- a/pysim_otaman_server/server.py +++ b/pysim_otaman_server/server.py @@ -21,7 +21,7 @@ from osmocom.construct import GsmOrUcs2Adapter from osmocom.tlv import BER_TLV_IE -VERSION = '2.2.18' +VERSION = '2.2.19' MAX_ENVELOPE_SEGMENTS = 5 # max SMS segments for outgoing C-APDU in ENVELOPE