From d9e6c6c9ddaa472c40b5089808afb191de138798 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, 26 Sep 2026 08:50:46 +0300 Subject: [PATCH] feat: CAP memory estimation with a confirm step before install (v3.5.8) Selecting a .cap in the RAM installer or the SCP81 "Install from .cap" template now runs a read-only analysis (POST /api/cap-info) before any APDU is built: the archive is validated structurally (a corrupt or wrong-format file fails here) and the bundled capmem analyzer estimates the code size and the persistent (NVRAM) / volatile (RAM) requirements, with the tool's suggested C6/C7/C8 quotas shown as information. The form's action button (Execute / Generate) stays disabled until the analysis succeeds - pressing it is the user's confirmation to continue. - pysim_simple_server/capmem.py: bundled analyzer (component parsers + JCVM opcode table + method-bytecode allocation scan), adapted to take the CAP archive as bytes and return report/memory dicts; output verified byte-identical to the workspace tool on 21 real CAPs. - _cap_info_body + POST /api/cap-info (read-only; the install endpoints stay unchanged and self-sufficient). - PWA: shared capAnalyzeFile/capMemHtml/capGateOk helpers, estimate box under both CAP inputs (reusing the idle #ram-cap-info div, new #scripts-cap-info), data-cap-gate gating in pysimApplyAvailability, stale-response guard, Retry, EN/RU strings. - Tests: tests/test_cap_memory.py (synthetic CAPs: new/newarray/ makeTransientByteArray/static fields/unknown-opcode warnings/corrupt input), frontend capmem.test.js (renderer, gate, analyze flow). - help EN/RU, docs/api.md, AGENTS; version 3.5.8; sw cache simple-v261. 567 frontend / 429 Python green. --- docs/api.md | 43 + frontend/help-ru.html | 4 +- frontend/help.html | 4 +- frontend/index.html | 168 ++- frontend/sw.js | 2 +- frontend/tests/capmem.test.js | 140 +++ pyproject.toml | 2 +- pysim_simple_server/capmem.py | 1831 +++++++++++++++++++++++++++++++++ pysim_simple_server/server.py | 36 +- tests/test_cap_memory.py | 244 +++++ 10 files changed, 2461 insertions(+), 13 deletions(-) create mode 100644 frontend/tests/capmem.test.js create mode 100755 pysim_simple_server/capmem.py create mode 100644 tests/test_cap_memory.py diff --git a/docs/api.md b/docs/api.md index a773a8e..ce7ccba 100644 --- a/docs/api.md +++ b/docs/api.md @@ -38,6 +38,7 @@ a 3.x PWA). | `/api/help` | POST | pySim help for a given command | | `/api/send-ota` | POST | SCP80 OTA secured packet delivery | | `/api/ram-install` | POST | Install a Java Card `.cap` file via SCP80 (INSTALL[for load] → LOAD ×N → INSTALL[for install]) | +| `/api/cap-info` | POST | Validate a `.cap` archive and estimate its code/NVRAM/RAM requirements (read-only) | | `/api/sp-verify` | POST | Verify secured packet against pySim reference | | `/api/menu` | GET | Current STK menu (title + items + active) | | `/api/menu-select` | POST | ENVELOPE(Menu Selection) with item_id | @@ -319,6 +320,48 @@ same `por` structure if decoding succeeds. The SPI2 `por_in_submit` bit (0x20) selects submit-mode PoR. +### `POST /api/cap-info` + +Validate a Java Card `.cap` archive and estimate its memory requirements. +Read-only: it runs the same structural parse as the install paths (so a +corrupt or wrong-format file fails here first) plus the bundled CAP analyzer +(`pysim_simple_server/capmem.py` — component parsers and a method-bytecode +allocation scan). It never touches the card, the SCP81 listener or the +scripts; the install endpoints stay self-sufficient and the estimate is not +used for installation. + +```json +{"cap_hex": "504B0304..."} +``` + +**Response (ok):** + +```json +{ + "ok": true, + "load_file_aid": "AA1902BC226001", "module_aid": "AA1902BC226001", + "load_file_bytes": 1234, + "memory": { + "package_aid": "AA1902BC226001", + "applet_count": 1, "applets": ["AA1902BC226001"], + "class_count": 3, "method_count": 12, + "code": {"method_component": 850}, + "nvram": {"static_image": 12, "array_init": 4, "install_objects": 100, + "header_overhead": 24, "ref_storage": 8, "total": 148, "runtime": 0}, + "ram": {"transient_arrays": 16, "runtime_transient": 0, "peak_frame": 8, "total": 24}, + "suggested": {"c6": 850, "c7": 272, "c8": 148}, + "warnings": [] + } +} +``` + +**Errors** (HTTP 200 with `ok: false`, like `/api/scp81/gen-install`): +`{"ok": false, "error": "cap parse failed: File is not a zip file"}` for a +corrupt/wrong archive, or `cap analysis failed: …` when a component passes +the structural parse but not the analyzer. The numbers are an estimate: +the model assumes 2-byte references, a 6-byte object header and NVM cell +rounding, and does not include applet-created runtime objects/arrays. + ### `POST /api/ram-install` Install a Java Card `.cap` file on the card via GlobalPlatform commands (INSTALL[for load] → LOAD ×N → INSTALL[for install (+ make selectable)]) wrapped in SCP80 secured packets. Each step is sent via ENVELOPE and its PoR is checked; the sequence aborts on the first PoR error. The `.cap` archive (a ZIP of nested components) is parsed server-side in `_cap_parse`; no external tooling is required. diff --git a/frontend/help-ru.html b/frontend/help-ru.html index d01b595..a8e22eb 100644 --- a/frontend/help-ru.html +++ b/frontend/help-ru.html @@ -319,7 +319,7 @@ ОперацияОписание Обзор карты (все данные GP)Запрос GET STATUS для ISD, приложений, ELF и модулей ELF, а также GET DATA FF21 для информации о памяти. Результаты отображаются в обзоре с кнопками Удалить для каждого элемента. - Установка пакета (.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. + Установка пакета (.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 / RAM); повреждённый файл не проходит анализ, и Execute остаётся недоступной до успешного анализа. @@ -376,7 +376,7 @@

Таблица показывает имя, тип, число APDU и время создания каждого скрипта, а также кнопки Редактировать и Удалить; в редакторе есть поле имени и текстовая область APDU. В ходе сессии сервер отдаёт по одному C-APDU на каждый POST карты и отслеживает выполнение: карта сообщает статус в следующем POST (X-Admin-Script-Status), оборвавшаяся сессия досылает только невыполненные APDU (X-Admin-Resume продолжает, новый диалог начинает заново), а завершённый скрипт закрывается ответом 204 No Content. Конструктор RAM/GP вкладки Remote APDU может отправить цепочку команд прямо в прогон кнопкой «В очередь SCP81».

diff --git a/frontend/help.html b/frontend/help.html index efbbd4c..6a7c02e 100644 --- a/frontend/help.html +++ b/frontend/help.html @@ -318,7 +318,7 @@ OperationDescription Explore Card (all GP data)Queries GET STATUS for ISD, Applications, ELFs, and ELF Modules, plus GET DATA FF21 for memory info. Results appear in an explorer view with per-item Delete buttons. - 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. + 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 (code / NVRAM / RAM) in the form; a corrupt or wrong-format file fails the analysis, and Execute stays disabled until a successful analysis. @@ -375,7 +375,7 @@

The table lists each script with its kind, APDU count and creation time, plus Edit and Delete; the editor has a name field and the APDU textarea. Over a session the server serves one C-APDU per card POST and tracks execution: the card reports status in its next POST (X-Admin-Script-Status), a session that dies resends only the unexecuted APDUs (X-Admin-Resume continues, a fresh dialog restarts), and a completed script is closed with 204 No Content. The Remote APDU tab's RAM/GP builder can feed a command chain straight into the run with Queue in SCP81.

diff --git a/frontend/index.html b/frontend/index.html index 0605133..b591e7e 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -695,12 +695,12 @@ - +