diff --git a/frontend/help-ru.html b/frontend/help-ru.html index cdec770..a2de934 100644 --- a/frontend/help-ru.html +++ b/frontend/help-ru.html @@ -321,7 +321,7 @@ ОперацияОписание Обзор карты (все данные GP)Запрос GET STATUS для ISD, приложений, ELF и модулей ELF, а также GET DATA FF21 (расширенные ресурсы карты: число установленных приложений и свободная энергонезависимая/энергозависимая память). Если карта отвергает компактный формат листинга (P2.b2=0, устаревший по GP), запросы повторяются в расширенном формате E3; флажок Запрашивать расширенные данные реестра (E3) дополнительно запрашивает их и объединяет расширенные поля (привилегии, связи ELF/SD, списки модулей). Результаты отображаются в обзоре с кнопками Удалить для каждого элемента и определённым форматом команд RAM. - Установка пакета (.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. Повреждённый файл не проходит анализ, и Execute остаётся недоступной до успешного анализа. + Установка пакета (.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. Повреждённый файл не проходит анализ, и Execute остаётся недоступной до успешного анализа. Оценка носит справочный характер и никогда не используется при установке: NVRAM — это образ кода плюс постоянные данные (сумма в стиле C6+C8 по GP Table 11-48; управление памятью карты, округление и запись в реестре не учитываются, а образ статических полей входит в обе части); рекомендуемый C6 следует за load-файлом, а рекомендуемые квоты — это десятичные значения в байтах (шестнадцатеричное значение в скобках — это кодирование параметров установки C7/C8: C6 — энергонезависимый код, C7 — энергозависимая RAM, C8 — энергонезависимые данные). diff --git a/frontend/help.html b/frontend/help.html index f6f0045..53c4d6c 100644 --- a/frontend/help.html +++ b/frontend/help.html @@ -320,7 +320,7 @@ OperationDescription Explore Card (all GP data)Queries GET STATUS for ISD, Applications, ELFs, and ELF Modules, plus GET DATA FF21 (Extended Card Resources: the number of installed applications and the free non-volatile/volatile memory). If a card rejects the compact listing (P2.b2=0, deprecated by GP) the queries are retried in the expanded E3 form; the Query expanded registry details (E3) checkbox also requests it as an extra pass and merges the expanded-only fields (privileges, ELF/SD associations, module lists). Results appear in an explorer view with per-item Delete buttons and the detected RAM command format. - Install Package (.cap file)Sends a .cap file to the card via the server: INSTALL[for load] → LOAD ×N → INSTALL[for install (+make selectable)]. The load file is split into LOAD APDUs of the LOAD block size (1–240 bytes of payload, 240 by default); each secured packet is delivered as a single SMS or, when larger, as a concatenated SMS-PP download of up to 5 segments, so a large .cap simply takes several SMS. As soon as the file is selected it is validated and its memory requirements are estimated in the form: the NVRAM requirement (the code image + persistent data, the GlobalPlatform Card Spec C6+C8 style total) and the RAM estimate. The same box reports the libraries the CAP is linked against (its Import component: library name, AID and the minimum version ≥ x.y, with standard names and families resolved and a Java Card SDK hint where known), the package/applet identity and the component breakdown (sizes and shares in load-file order) — grouped under the Package, Requires, Memory and Components headings. A corrupt or wrong-format file fails the analysis, and Execute stays disabled until a successful analysis. + Install Package (.cap file)Sends a .cap file to the card via the server: INSTALL[for load] → LOAD ×N → INSTALL[for install (+make selectable)]. The load file is split into LOAD APDUs of the LOAD block size (1–240 bytes of payload, 240 by default); each secured packet is delivered as a single SMS or, when larger, as a concatenated SMS-PP download of up to 5 segments, so a large .cap simply takes several SMS. As soon as the file is selected it is validated and its memory requirements are estimated in the form: the NVRAM requirement (the code image + persistent data, the GlobalPlatform Card Spec C6+C8 style total) and the RAM estimate. The same box reports the libraries the CAP is linked against (its Import component: library name, AID and the minimum version ≥ x.y, with standard names and families resolved and a Java Card SDK hint where known), the package/applet identity and the component breakdown (sizes and shares in load-file order) — grouped under the Package, Requires, Memory and Components headings. A corrupt or wrong-format file fails the analysis, and Execute stays disabled until a successful analysis. The estimate is informational only and is never used for installation: NVRAM is the code image plus the persistent data (the GlobalPlatform C6+C8 style total, Table 11-48 — card memory management, rounding and the registry entry are not included, and the static field image is counted in both parts); the suggested C6 follows the load file, and the suggested quotas are decimal byte counts (the hex in parentheses is how the C7/C8 install parameters encode them: C6 = non-volatile code, C7 = volatile RAM, C8 = non-volatile data). diff --git a/frontend/index.html b/frontend/index.html index d2371af..77a242e 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -1714,7 +1714,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.6.32'; +const SIMPLE_VERSION = '3.6.33'; document.getElementById('app-version').textContent = 'v' + SIMPLE_VERSION; // ===== Tab switching ===== @@ -8326,10 +8326,21 @@ function capMemBytes(n) { // Estimate box body; pure apart from esc()/t(). `mem` is the server's // memory object (pysim_simple_server.capmem.memory_json). +// Suggested C6/C7/C8 quotas as one readable line: decimal bytes (what the +// install form takes and what GP 9.7 encodes) with the hex equivalent in +// parentheses (how the C7/C8 install parameters are coded). C6 = non-volatile +// code space (the load file), C7 = volatile (RAM), C8 = non-volatile data. +function capQuotaText(sug) { + sug = sug || {}; + const dec = v => String(Number(v) || 0); + const hex = v => '0x' + (Number(v) || 0).toString(16).toUpperCase().padStart(4, '0'); + return 'C6=' + dec(sug.c6) + ' B (' + hex(sug.c6) + ') \u00b7 C7=' + dec(sug.c7) + + ' B (' + hex(sug.c7) + ') \u00b7 C8=' + dec(sug.c8) + ' B (' + hex(sug.c8) + ')'; +} + function capMemHtml(mem) { if (!mem) return ''; const nv = mem.nvram || {}, ram = mem.ram || {}, code = mem.code || {}, sug = mem.suggested || {}; - const hex2 = v => (Number(v) || 0).toString(16).toUpperCase().padStart(4, '0'); const methodBytes = Number(code.method_component) || 0; // older server responses carry only the bytecode size: fall back to it const loadFile = Number(code.load_file) || methodBytes; @@ -8424,7 +8435,8 @@ function capMemHtml(mem) { t('peak method frame') + ' ' + capMemBytes(ram.peak_frame), ].join(' \u00b7 '))))); mrows.push(row(label(esc(t('Suggested quotas (informational)'))) + cell( - 'C6=' + esc(String(Number(sug.c6) || 0)) + ' C7=0x' + esc(hex2(sug.c7)) + ' C8=0x' + esc(hex2(sug.c8)), + '' + + esc(capQuotaText(sug)) + '', 'pl-4 font-mono', 2))); html += section(t('Memory')) + table(mrows.join('')); @@ -8446,10 +8458,8 @@ function capMemHtml(mem) { html += disclosure(t('Components') + ' (' + comps.length + ')') + table(crows) + ''; } - html += disclosure(t('Notes')) + - '
' + esc(t('NVRAM = code image + persistent data (GP Card Spec v2.3.1 Table 11-48, C6+C8 style); card memory management, rounding and the registry entry are not included, and the static field image appears in both parts.')) + '
' + - '
' + esc(t('Estimate only — memory values are not used for installation')) + '
' + - ''; + // Scan warnings only - the NVRAM definition and the "estimate only" note + // live in the help; the CAP details box stays compact (v3.6.33). (mem.warnings || []).forEach(w => { html += '
\u26a0 ' + esc(w) + '
'; }); diff --git a/frontend/sw.js b/frontend/sw.js index 52d071e..f21805a 100644 --- a/frontend/sw.js +++ b/frontend/sw.js @@ -1,4 +1,4 @@ -const CACHE = 'simple-v305'; +const CACHE = 'simple-v306'; const URLS = [ 'index.html', 'help.html', diff --git a/frontend/tests/capmem.test.js b/frontend/tests/capmem.test.js index de37e85..babe7dc 100644 --- a/frontend/tests/capmem.test.js +++ b/frontend/tests/capmem.test.js @@ -39,6 +39,7 @@ eval(extractFunc(html, 'jcAidNorm')); eval(extractFunc(html, 'jcAidName')); eval(extractFunc(html, 'jcAidFamily')); eval(extractFunc(html, 'capMemBytes')); +eval(extractFunc(html, 'capQuotaText')); eval(extractFunc(html, 'capMemHtml')); eval(extractFunc(html, 'capAnalyzeFile', true)); // The RAM CAP analysis also applies the detected toolkit mode (DOM-bound; its @@ -93,9 +94,9 @@ test('capMemHtml renders the grouped report: package, requires, memory, componen assert.ok(out.includes('>Requires (1)'), out); assert.ok(out.includes('>Memory'), out); assert.ok(out.includes('>Components (3)'), out); - assert.ok(out.includes('>Notes'), out); - assert.ok(out.includes('Table 11-48'), out); - assert.ok(out.includes('Estimate only'), out); + // the static notes moved to the help; only scan warnings stay in the box + assert.ok(!out.includes('>Notes'), out); + assert.ok(!out.includes('Table 11-48'), out); assert.ok(out.includes('unknown opcode 0xAA'), out); // memory: the C6+C8-style total once, with indented children assert.ok(out.includes('NVRAM requirement'), out); @@ -109,7 +110,7 @@ test('capMemHtml renders the grouped report: package, requires, memory, componen assert.ok(out.includes('reference storage 8 B'), out); assert.ok(out.includes('>24 B'), out); assert.ok(out.includes('peak method frame 8 B'), out); - assert.ok(out.includes('C6=3000 C7=0x0110 C8=0x0088'), out); + assert.ok(out.includes('C6=3000 B (0x0BB8) \u00b7 C7=272 B (0x0110) \u00b7 C8=136 B (0x0088)'), out); // requires: library name, AID, minimum version, family and refs const req = out.slice(out.indexOf('Requires (1)'), out.indexOf('Memory')); assert.ok(req.includes('>AID'), req); @@ -173,7 +174,13 @@ test('capMemHtml drops the components section without a component list', () => { delete mem.components; const out = capMemHtml(mem); assert.ok(!out.includes('>Components'), out); - assert.ok(out.includes('>Notes'), out); + assert.ok(out.includes('>Memory'), out); +}); + +test('capQuotaText renders decimal bytes with the hex coding', () => { + const txt = capQuotaText({ c6: 27246, c7: 270, c8: 5143 }); + assert.strictEqual(txt, 'C6=27246 B (0x6A6E) \u00b7 C7=270 B (0x010E) \u00b7 C8=5143 B (0x1417)'); + assert.strictEqual(capQuotaText({}), 'C6=0 B (0x0000) \u00b7 C7=0 B (0x0000) \u00b7 C8=0 B (0x0000)'); }); test('capGateOk gates the RAM install op and the scripts form', () => { diff --git a/pyproject.toml b/pyproject.toml index e7a5df6..22eb7d6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "pysim-simple-server" -version = "3.6.32" +version = "3.6.33" 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 7cc469e..b4488f3 100644 --- a/pysim_simple_server/server.py +++ b/pysim_simple_server/server.py @@ -31,7 +31,7 @@ from osmocom.tlv import BER_TLV_IE from osmocom.utils import rpad -VERSION = '3.6.32' +VERSION = '3.6.33' MAX_ENVELOPE_SEGMENTS = 5 # max SMS segments for outgoing C-APDU in ENVELOPE