fix: keep a hand-edited packet TAR in the SCP80 send (v3.6.21)

The plain "Send to Card" path refreshed the whole preset right before
sending (spRefreshFromPreset -> cardsApply -> cardsApplyFields) and
re-applied the preset's slot TAR - so a TAR typed for a push/link trigger,
an applet OTA message or the HTTP OTA admin params was silently replaced by
the preset's ISD TAR (the pack buttons for those sources deliberately leave
the TAR manual; the help even said so).

- spRefreshFromPreset(selId, keepTar): the plain send passes keepTar, so
  the form's TAR survives; the counter, keys and SPI are still re-read.
- selecting a card preset, ramApplyCard and the chain packs still set the
  TAR; the RAM operations keep the preset's ISD TAR by design.
- spParams()/getRamSpParams() normalise the TAR (strip/upper/pad to 6);
  only the preview padded before, a short TAR went to the server raw.
- help EN/RU clarified, cards_counter/ram tests updated, sw simple-v294.

652 frontend / 499 Python green; version 3.6.21.
This commit is contained in:
2026-09-28 21:43:57 +03:00
parent 2d268f024b
commit 5372a770eb
8 changed files with 45 additions and 22 deletions
+2 -2
View File
@@ -254,7 +254,7 @@
<p class="text-sm mb-2"><strong>Упаковать в Secured packet</strong> отправляет готовый payload на вкладку SCP80 для заполнения SPI/счётчика — там укажите TAR, который слушает SD (обычно TAR OTASD).</p> <p class="text-sm mb-2"><strong>Упаковать в Secured packet</strong> отправляет готовый payload на вкладку SCP80 для заполнения SPI/счётчика — там укажите TAR, который слушает SD (обычно TAR OTASD).</p>
<h4 id="push-ts102226" class="font-medium mb-1 mt-3">PUSH по TS 102 226 §9</h4> <h4 id="push-ts102226" class="font-medium mb-1 mt-3">PUSH по TS 102 226 §9</h4>
<p class="text-sm mb-2">Подвкладка <strong>&laquo;Триггер канала/линка&raquo;</strong> собирает запросы &sect;9 тем же кодировщиком, что и строка <strong>PUSH</strong> в цепочке RAM/GP, показывает предпросмотр C-APDU, и предлагает <strong>&laquo;Упаковать в Secured packet&raquo;</strong> (TAR остаётся ручным: запрос адресован целевому приложению, а не Security Domain) и <strong>&rarr; Расширенный скрипт</strong> (оборачивает каждый APDU в Command TLV <code class="font-mono text-sm">22</code> и добавляет их в конструктор Expanded Script).</p> <p class="text-sm mb-2">Подвкладка <strong>&laquo;Триггер канала/линка&raquo;</strong> собирает запросы &sect;9 тем же кодировщиком, что и строка <strong>PUSH</strong> в цепочке RAM/GP, показывает предпросмотр C-APDU, и предлагает <strong>&laquo;Упаковать в Secured packet&raquo;</strong> (TAR остаётся ручным: запрос адресован целевому приложению, а не Security Domain, и введённый TAR сохраняется при отправке) и <strong>&rarr; Расширенный скрипт</strong> (оборачивает каждый APDU в Command TLV <code class="font-mono text-sm">22</code> и добавляет их в конструктор Expanded Script).</p>
<ul class="list-disc list-inside text-sm space-y-1 mb-3"> <ul class="list-disc list-inside text-sm space-y-1 mb-3">
<li><strong>Открытие BIP-канала</strong> (<code class="font-mono text-sm">01</code>) &mdash; собирается в режиме <strong>Fields</strong> из самых употребительных параметров OPEN CHANNEL (Stepping Stones &sect;18.6.1): описание bearer, транспортный протокол (UDP или TCP, клиент UICC, удалённое соединение &mdash; только эти значения допускает команда) с портом назначения, адрес назначения, NAA/APN, размер буфера и alpha (флажок <em>прозрачный режим</em> отправляет нулевой alpha, т.е. без подтверждения пользователя); логин/пароль и остальное — в поле дополнительных TLV. <strong>Локальный адрес не отправляется никогда</strong> (&sect;9.2.1 и руководство это запрещают). Режим <strong>Hex</strong> принимает сырые COMPREHENSION-TLV. Проактивную команду OPEN CHANNEL выдаёт само приложение (&sect;9.1.1). SIMalliance Stepping Stones R7 &sect;18.6 рекомендует отправлять его <strong>вместе с CAT_TP-запросом в одном сообщении</strong> (параметры канала — в <code class="font-mono text-sm">01</code>, порт CAT_TP — в <code class="font-mono text-sm">02</code>), поэтому в форме есть флажок <em>&laquo;Также запросить установление соединения CAT_TP (02)&raquo;</em>; пара передаётся одним скриптом команд (конкатенированные SMS, если больше 140 октетов).</li> <li><strong>Открытие BIP-канала</strong> (<code class="font-mono text-sm">01</code>) &mdash; собирается в режиме <strong>Fields</strong> из самых употребительных параметров OPEN CHANNEL (Stepping Stones &sect;18.6.1): описание bearer, транспортный протокол (UDP или TCP, клиент UICC, удалённое соединение &mdash; только эти значения допускает команда) с портом назначения, адрес назначения, NAA/APN, размер буфера и alpha (флажок <em>прозрачный режим</em> отправляет нулевой alpha, т.е. без подтверждения пользователя); логин/пароль и остальное — в поле дополнительных TLV. <strong>Локальный адрес не отправляется никогда</strong> (&sect;9.2.1 и руководство это запрещают). Режим <strong>Hex</strong> принимает сырые COMPREHENSION-TLV. Проактивную команду OPEN CHANNEL выдаёт само приложение (&sect;9.1.1). SIMalliance Stepping Stones R7 &sect;18.6 рекомендует отправлять его <strong>вместе с CAT_TP-запросом в одном сообщении</strong> (параметры канала — в <code class="font-mono text-sm">01</code>, порт CAT_TP — в <code class="font-mono text-sm">02</code>), поэтому в форме есть флажок <em>&laquo;Также запросить установление соединения CAT_TP (02)&raquo;</em>; пара передаётся одним скриптом команд (конкатенированные SMS, если больше 140 октетов).</li>
<li><strong>Установление соединения CAT_TP</strong> (<code class="font-mono text-sm">02</code>) &mdash; порт назначения в transport level <code class="font-mono text-sm">3C</code> с типом протокола 00 (обязателен), необязательные buffer size <code class="font-mono text-sm">39</code> / данные идентификации <code class="font-mono text-sm">36</code>. Отдельно он полагается на предустановленные на карте умолчания канала/CAT_TP, против чего предостерегает руководство Stepping Stones; предпочтительна пара выше.</li> <li><strong>Установление соединения CAT_TP</strong> (<code class="font-mono text-sm">02</code>) &mdash; порт назначения в transport level <code class="font-mono text-sm">3C</code> с типом протокола 00 (обязателен), необязательные buffer size <code class="font-mono text-sm">39</code> / данные идентификации <code class="font-mono text-sm">36</code>. Отдельно он полагается на предустановленные на карте умолчания канала/CAT_TP, против чего предостерегает руководство Stepping Stones; предпочтительна пара выше.</li>
@@ -357,7 +357,7 @@
<tr><td class="py-1 px-2">PSK key</td><td class="py-1 px-2">SCP81 HTTP OTA: 32 hex-символа (16 байт) для PSK TLS-слушателя; ключ выбирается по идентификатору, который предъявляет карта</td></tr> <tr><td class="py-1 px-2">PSK key</td><td class="py-1 px-2">SCP81 HTTP OTA: 32 hex-символа (16 байт) для PSK TLS-слушателя; ключ выбирается по идентификатору, который предъявляет карта</td></tr>
</tbody> </tbody>
</table> </table>
<p class="text-sm mb-3">Столбец <strong>SCP81</strong> показывает, задана ли в предустановке рабочая пара PSK: <strong>&#10003;</strong> (зелёный) — идентификатор и ключ заданы; <strong>&#9888;</strong> (жёлтый) — задано только одно из двух, и слушатель такую предустановку игнорирует; <strong>&mdash;</strong> — PSK нет. Идентификатор и ключ PSK задаются вместе. Кнопка <strong>Редактировать</strong> загружает предустановку в форму (кнопка Add становится <strong>Сохранить</strong>; <strong>Отмена</strong> очищает форму), поэтому поля можно менять без повторного ввода карты; <strong>Удалить</strong> удаляет строку. Обмен предустановками: <strong>Экспорт в файл</strong> для выгрузки и <strong>Импорт из файла</strong> для загрузки. Выбранная предустановка автоматически заполняет форму Secured Packet и устанавливает TAR для операции (RAM/GP &rarr; ISD TAR, SIM RFM &rarr; UICC RFM TAR, USIM RFM &rarr; ADF RFM TAR); изменения сразу передаются работающему слушателю SCP81.</p> <p class="text-sm mb-3">Столбец <strong>SCP81</strong> показывает, задана ли в предустановке рабочая пара PSK: <strong>&#10003;</strong> (зелёный) — идентификатор и ключ заданы; <strong>&#9888;</strong> (жёлтый) — задано только одно из двух, и слушатель такую предустановку игнорирует; <strong>&mdash;</strong> — PSK нет. Идентификатор и ключ PSK задаются вместе. Кнопка <strong>Редактировать</strong> загружает предустановку в форму (кнопка Add становится <strong>Сохранить</strong>; <strong>Отмена</strong> очищает форму), поэтому поля можно менять без повторного ввода карты; <strong>Удалить</strong> удаляет строку. Обмен предустановками: <strong>Экспорт в файл</strong> для выгрузки и <strong>Импорт из файла</strong> для загрузки. Выбранная предустановка автоматически заполняет форму Secured Packet и устанавливает TAR для операции (RAM/GP &rarr; ISD TAR, SIM RFM &rarr; UICC RFM TAR, USIM RFM &rarr; ADF RFM TAR); TAR, введённый в форму Secured Packet вручную, сохраняется при отправке - счётчик, ключи и SPI по-прежнему берутся из предустановки; изменения сразу передаются работающему слушателю SCP81.</p>
</section> </section>
<section class="mb-10"> <section class="mb-10">
+2 -2
View File
@@ -253,7 +253,7 @@
<p class="text-sm mb-2"><strong>Pack into Secured packet</strong> sends the built payload to the SCP80 tab for SPI/counter filling &mdash; insert the TAR the SD listens on (typically the OTASD TAR) there.</p> <p class="text-sm mb-2"><strong>Pack into Secured packet</strong> sends the built payload to the SCP80 tab for SPI/counter filling &mdash; insert the TAR the SD listens on (typically the OTASD TAR) there.</p>
<h4 id="push-ts102226" class="font-medium mb-1 mt-3">TS 102 226 §9 PUSH</h4> <h4 id="push-ts102226" class="font-medium mb-1 mt-3">TS 102 226 §9 PUSH</h4>
<p class="text-sm mb-2">The <strong>Channel / link trigger</strong> sub-pill builds the &sect;9 requests with the same encoder as the RAM/GP chain's <strong>PUSH</strong> row, previews the C-APDU(s), and offers <strong>Pack into Secured packet</strong> (the TAR stays manual: the request is addressed to the target application, not the Security Domain) and <strong>&rarr; Expanded Script</strong> (wraps each APDU in the <code class="font-mono text-sm">22</code> Command TLV and appends them to the Expanded Script builder).</p> <p class="text-sm mb-2">The <strong>Channel / link trigger</strong> sub-pill builds the &sect;9 requests with the same encoder as the RAM/GP chain's <strong>PUSH</strong> row, previews the C-APDU(s), and offers <strong>Pack into Secured packet</strong> (the TAR stays manual: the request is addressed to the target application, not the Security Domain, and a typed TAR is kept when sending) and <strong>&rarr; Expanded Script</strong> (wraps each APDU in the <code class="font-mono text-sm">22</code> Command TLV and appends them to the Expanded Script builder).</p>
<ul class="list-disc list-inside text-sm space-y-1 mb-3"> <ul class="list-disc list-inside text-sm space-y-1 mb-3">
<li><strong>BIP channel opening</strong> (<code class="font-mono text-sm">01</code>) &mdash; built in <strong>Fields</strong> mode from the most-used OPEN CHANNEL parameters (Stepping Stones &sect;18.6.1): bearer description, transport protocol (UDP or TCP, UICC client, remote &mdash; the only values the command allows) with the destination port, destination address, NAA/APN, buffer size and alpha (a <em>transparent</em> checkbox sends the null alpha, i.e. no user confirmation); login/password and anything else go in the extra-TLVs field. The <strong>local address is never emitted</strong> (&sect;9.2.1 and the guide both forbid it). <strong>Hex</strong> mode takes the raw COMPREHENSION-TLVs instead. The application issues the proactive OPEN CHANNEL itself (&sect;9.1.1). SIMalliance Stepping Stones R7 &sect;18.6 recommends sending it <strong>together with the CAT_TP request in the same message</strong> (the channel parameters ride in <code class="font-mono text-sm">01</code>, the CAT_TP port in <code class="font-mono text-sm">02</code>), so the form has an <em>Also request the CAT_TP link establishment (02)</em> checkbox; the pair is one concatenated command script (concatenated SMS when it exceeds 140 octets).</li> <li><strong>BIP channel opening</strong> (<code class="font-mono text-sm">01</code>) &mdash; built in <strong>Fields</strong> mode from the most-used OPEN CHANNEL parameters (Stepping Stones &sect;18.6.1): bearer description, transport protocol (UDP or TCP, UICC client, remote &mdash; the only values the command allows) with the destination port, destination address, NAA/APN, buffer size and alpha (a <em>transparent</em> checkbox sends the null alpha, i.e. no user confirmation); login/password and anything else go in the extra-TLVs field. The <strong>local address is never emitted</strong> (&sect;9.2.1 and the guide both forbid it). <strong>Hex</strong> mode takes the raw COMPREHENSION-TLVs instead. The application issues the proactive OPEN CHANNEL itself (&sect;9.1.1). SIMalliance Stepping Stones R7 &sect;18.6 recommends sending it <strong>together with the CAT_TP request in the same message</strong> (the channel parameters ride in <code class="font-mono text-sm">01</code>, the CAT_TP port in <code class="font-mono text-sm">02</code>), so the form has an <em>Also request the CAT_TP link establishment (02)</em> checkbox; the pair is one concatenated command script (concatenated SMS when it exceeds 140 octets).</li>
<li><strong>CAT_TP link establishment</strong> (<code class="font-mono text-sm">02</code>) &mdash; destination port in transport level <code class="font-mono text-sm">3C</code> with protocol type 00 (mandatory), optional buffer size <code class="font-mono text-sm">39</code> / identification data <code class="font-mono text-sm">36</code>. Standalone it relies on card-provisioned channel/CAT_TP defaults, which the Stepping Stones guide advises against; prefer the pair above.</li> <li><strong>CAT_TP link establishment</strong> (<code class="font-mono text-sm">02</code>) &mdash; destination port in transport level <code class="font-mono text-sm">3C</code> with protocol type 00 (mandatory), optional buffer size <code class="font-mono text-sm">39</code> / identification data <code class="font-mono text-sm">36</code>. Standalone it relies on card-provisioned channel/CAT_TP defaults, which the Stepping Stones guide advises against; prefer the pair above.</li>
@@ -356,7 +356,7 @@
<tr><td class="py-1 px-2">PSK key</td><td class="py-1 px-2">SCP81 HTTP OTA: 32 hex chars (16 bytes) for the PSK TLS listener, picked by the identity the card presents</td></tr> <tr><td class="py-1 px-2">PSK key</td><td class="py-1 px-2">SCP81 HTTP OTA: 32 hex chars (16 bytes) for the PSK TLS listener, picked by the identity the card presents</td></tr>
</tbody> </tbody>
</table> </table>
<p class="text-sm mb-3">The <strong>SCP81</strong> column shows whether the preset supplies a usable PSK pair: <strong>&#10003;</strong> (green) — identity and key set; <strong>&#9888;</strong> (amber) — only one of the two, so the listener ignores the preset; <strong>&mdash;</strong> — no PSK. PSK identity and key must be set together. <strong>Edit</strong> loads a preset into the form (the Add button becomes <strong>Save</strong>; <strong>Cancel</strong> clears it) so fields can be changed without re-entering the card; <strong>Remove</strong> deletes the row. Presets can be shared with <strong>Export to file</strong> and restored with <strong>Import from file</strong>. The selected card preset auto-fills the Secured Packet form and sets the TAR for the operation (RAM/GP &rarr; ISD TAR, SIM RFM &rarr; UICC RFM TAR, USIM RFM &rarr; ADF RFM TAR); edits are pushed into a running SCP81 listener automatically.</p> <p class="text-sm mb-3">The <strong>SCP81</strong> column shows whether the preset supplies a usable PSK pair: <strong>&#10003;</strong> (green) — identity and key set; <strong>&#9888;</strong> (amber) — only one of the two, so the listener ignores the preset; <strong>&mdash;</strong> — no PSK. PSK identity and key must be set together. <strong>Edit</strong> loads a preset into the form (the Add button becomes <strong>Save</strong>; <strong>Cancel</strong> clears it) so fields can be changed without re-entering the card; <strong>Remove</strong> deletes the row. Presets can be shared with <strong>Export to file</strong> and restored with <strong>Import from file</strong>. The selected card preset auto-fills the Secured Packet form and sets the TAR for the operation (RAM/GP &rarr; ISD TAR, SIM RFM &rarr; UICC RFM TAR, USIM RFM &rarr; ADF RFM TAR); a TAR typed into the Secured Packet form by hand is kept when sending - the counter, keys and SPI are still re-read from the preset; edits are pushed into a running SCP81 listener automatically.</p>
</section> </section>
<section class="mb-10"> <section class="mb-10">
+20 -14
View File
@@ -1711,7 +1711,7 @@
// ===== Version ===== // ===== Version =====
// Single source of truth for the PWA version: shown in the header and used // Single source of truth for the PWA version: shown in the header and used
// by the server version check in pysimConnect(). // by the server version check in pysimConnect().
const SIMPLE_VERSION = '3.6.20'; const SIMPLE_VERSION = '3.6.21';
document.getElementById('app-version').textContent = 'v' + SIMPLE_VERSION; document.getElementById('app-version').textContent = 'v' + SIMPLE_VERSION;
// ===== Tab switching ===== // ===== Tab switching =====
@@ -4869,7 +4869,7 @@ function _genSpBuild() {
const spi2 = parseInt(document.getElementById('sp-spi2-hex').value, 16); const spi2 = parseInt(document.getElementById('sp-spi2-hex').value, 16);
const kicHex = document.getElementById('sp-kic-hex').value; const kicHex = document.getElementById('sp-kic-hex').value;
const kidHex = document.getElementById('sp-kid-hex').value; const kidHex = document.getElementById('sp-kid-hex').value;
const tarHex = (document.getElementById('sp-tar').value || '').replace(/[^0-9a-fA-F]/g, '').padEnd(6, '0').slice(0, 6); const tarHex = (document.getElementById('sp-tar').value || '').replace(/[^0-9a-fA-F]/g, '').toUpperCase().padEnd(6, '0').slice(0, 6);
const cntrHex = (document.getElementById('sp-cntr').value || '').replace(/[^0-9a-fA-F]/g, '').padStart(10, '0').slice(0, 10); const cntrHex = (document.getElementById('sp-cntr').value || '').replace(/[^0-9a-fA-F]/g, '').padStart(10, '0').slice(0, 10);
const kicKeyHex = (document.getElementById('sp-kic-key').value || '').replace(/[^0-9a-fA-F]/g, ''); const kicKeyHex = (document.getElementById('sp-kic-key').value || '').replace(/[^0-9a-fA-F]/g, '');
const kidKeyHex = (document.getElementById('sp-kid-key').value || '').replace(/[^0-9a-fA-F]/g, ''); const kidKeyHex = (document.getElementById('sp-kid-key').value || '').replace(/[^0-9a-fA-F]/g, '');
@@ -8037,7 +8037,7 @@ function spParams() {
spi2: document.getElementById('sp-spi2-hex').value, spi2: document.getElementById('sp-spi2-hex').value,
kic: document.getElementById('sp-kic-hex').value, kic: document.getElementById('sp-kic-hex').value,
kid: document.getElementById('sp-kid-hex').value, kid: document.getElementById('sp-kid-hex').value,
tar: document.getElementById('sp-tar').value, tar: (document.getElementById('sp-tar').value || '').replace(/[^0-9a-fA-F]/g, '').toUpperCase().padEnd(6, '0').slice(0, 6),
cntr: document.getElementById('sp-cntr').value, cntr: document.getElementById('sp-cntr').value,
kicKey: document.getElementById('sp-kic-key').value, kicKey: document.getElementById('sp-kic-key').value,
kidKey: document.getElementById('sp-kid-key').value, kidKey: document.getElementById('sp-kid-key').value,
@@ -8078,10 +8078,13 @@ async function pysimSendOta() {
alert('Card reader server is not connected'); alert('Card reader server is not connected');
return; return;
} }
// Re-read the preset (counter and keys) before sending: the Cards tab may // Re-read the preset (counter, keys, SPI) before sending: the Cards tab
// have changed it after the form was filled, and a stale counter is // may have changed it after the form was filled, and a stale counter is
// rejected by the card (cntr_low) and then written back over the preset. // rejected by the card (cntr_low) and then written back over the preset.
spRefreshFromPreset('sp-card-sel'); // The TAR is not re-applied: a packet may target a manually entered TAR
// (push/link triggers, applet OTA) - the preset sets it only when a card
// is picked or a chain is packed (v3.6.21).
spRefreshFromPreset('sp-card-sel', true);
const sp = document.getElementById('sp-result').value.replace(/[^0-9a-fA-F]/g, '').toUpperCase(); const sp = document.getElementById('sp-result').value.replace(/[^0-9a-fA-F]/g, '').toUpperCase();
if (!sp) { alert('No secured packet to send. Generate a secure packet first.'); return; } if (!sp) { alert('No secured packet to send. Generate a secure packet first.'); return; }
const sendResultEl = document.getElementById('sp-send-result'); const sendResultEl = document.getElementById('sp-send-result');
@@ -8476,7 +8479,7 @@ function getRamSpParams() {
spi2: document.getElementById('sp-spi2-hex').value, spi2: document.getElementById('sp-spi2-hex').value,
kic: document.getElementById('sp-kic-hex').value, kic: document.getElementById('sp-kic-hex').value,
kid: document.getElementById('sp-kid-hex').value, kid: document.getElementById('sp-kid-hex').value,
tar: (document.getElementById('sp-tar').value || '000000').replace(/[^0-9a-fA-F]/g, ''), tar: (document.getElementById('sp-tar').value || '').replace(/[^0-9a-fA-F]/g, '').toUpperCase().padEnd(6, '0').slice(0, 6),
cntr: (document.getElementById('sp-cntr').value || '0000000001').replace(/[^0-9a-fA-F]/g, ''), cntr: (document.getElementById('sp-cntr').value || '0000000001').replace(/[^0-9a-fA-F]/g, ''),
kicKey: (document.getElementById('sp-kic-key').value || '').replace(/[^0-9a-fA-F]/g, ''), kicKey: (document.getElementById('sp-kic-key').value || '').replace(/[^0-9a-fA-F]/g, ''),
kidKey: (document.getElementById('sp-kid-key').value || '').replace(/[^0-9a-fA-F]/g, ''), kidKey: (document.getElementById('sp-kid-key').value || '').replace(/[^0-9a-fA-F]/g, ''),
@@ -9762,8 +9765,11 @@ function cardsAutoSelectByIccid(iccid) {
} }
// Fill the SP form from the preset (no packet generation): the form is a // Fill the SP form from the preset (no packet generation): the form is a
// working copy, the preset stays the source of truth. // working copy, the preset stays the source of truth. `keepTar` leaves the
function cardsApplyFields(idx) { // packet TAR alone: the plain SCP80 send re-reads only the preset-owned
// counter/keys/SPI, a manually entered target TAR (push/link triggers,
// applet OTA) must survive.
function cardsApplyFields(idx, keepTar) {
const c = cards[parseInt(idx)]; const c = cards[parseInt(idx)];
if (!c) return false; if (!c) return false;
document.getElementById('sp-spi1').value = c.spi1; document.getElementById('sp-spi1').value = c.spi1;
@@ -9791,7 +9797,7 @@ function cardsApplyFields(idx) {
document.getElementById('sp-kid-idx').value = ((kidByte >> 4) & 0x0F).toString(16).toUpperCase(); document.getElementById('sp-kid-idx').value = ((kidByte >> 4) & 0x0F).toString(16).toUpperCase();
document.getElementById('sp-kid-alg').value = (kidByte & 0x0F).toString(16).padStart(2, '0'); document.getElementById('sp-kid-alg').value = (kidByte & 0x0F).toString(16).padStart(2, '0');
updateSpKid(); updateSpKid();
document.getElementById('sp-tar').value = cardsTarValue(_spTarKey, c[_spTarKey]); if (!keepTar) document.getElementById('sp-tar').value = cardsTarValue(_spTarKey, c[_spTarKey]);
document.getElementById('sp-cntr').value = c.cntr; document.getElementById('sp-cntr').value = c.cntr;
document.getElementById('sp-kic-key').value = c.kicKey; document.getElementById('sp-kic-key').value = c.kicKey;
document.getElementById('sp-kid-key').value = c.kidKey; document.getElementById('sp-kid-key').value = c.kidKey;
@@ -9800,8 +9806,8 @@ function cardsApplyFields(idx) {
return true; return true;
} }
function cardsApply(idx) { function cardsApply(idx, keepTar) {
if (!cardsApplyFields(idx)) return; if (!cardsApplyFields(idx, keepTar)) return;
genSp(); genSp();
} }
@@ -9810,12 +9816,12 @@ function cardsApply(idx) {
// filled, and a stale counter is rejected by the card (cntr_low) and would // filled, and a stale counter is rejected by the card (cntr_low) and would
// then be written back over the preset. Returns the preset counter ('' when // then be written back over the preset. Returns the preset counter ('' when
// no preset is selected). // no preset is selected).
function spRefreshFromPreset(selId) { function spRefreshFromPreset(selId, keepTar) {
const sel = document.getElementById(selId || 'sp-card-sel'); const sel = document.getElementById(selId || 'sp-card-sel');
const idx = sel ? parseInt(sel.value, 10) : NaN; const idx = sel ? parseInt(sel.value, 10) : NaN;
if (isNaN(idx) || !cards[idx]) return ''; if (isNaN(idx) || !cards[idx]) return '';
if (selId === 'ram-card-sel') _spTarKey = 'tar'; if (selId === 'ram-card-sel') _spTarKey = 'tar';
cardsApply(idx); cardsApply(idx, keepTar);
return cards[idx].cntr; return cards[idx].cntr;
} }
+1 -1
View File
@@ -1,4 +1,4 @@
const CACHE = 'simple-v293'; const CACHE = 'simple-v294';
const URLS = [ const URLS = [
'index.html', 'index.html',
'help.html', 'help.html',
+13 -1
View File
@@ -29,7 +29,8 @@ for (const fn of ['cardsTarValue', 'cardsApplyFields', 'cardsApply',
eval(code); eval(code);
// The SP form is a working copy: the preset is the source of truth, and // The SP form is a working copy: the preset is the source of truth, and
// every SCP80/RAM operation re-reads it before starting (v3.6.3). // every SCP80/RAM operation re-reads it before starting (v3.6.3). The plain
// SCP80 send keeps a hand-edited packet TAR (v3.6.21).
function fakeEnv(selValue, selId, presetCntr) { function fakeEnv(selValue, selId, presetCntr) {
const els = {}; const els = {};
for (const id of ['sp-spi1', 'sp-spi2-hex', 'sp-kic-idx', 'sp-kic-alg', for (const id of ['sp-spi1', 'sp-spi2-hex', 'sp-kic-idx', 'sp-kic-alg',
@@ -70,6 +71,17 @@ test('spRefreshFromPreset for the RAM selector targets the ISD TAR', () => {
assert.strictEqual(env.els['sp-tar'].value, '000000'); assert.strictEqual(env.els['sp-tar'].value, '000000');
}); });
test('the pre-send refresh keeps a hand-edited packet TAR (v3.6.21)', () => {
const env = fakeEnv('0', 'sp-card-sel', '0000000020');
env.els['sp-tar'].value = 'AF4D01'; // e.g. a push/link trigger target
assert.strictEqual(spRefreshFromPreset('sp-card-sel', true), '0000000020');
assert.strictEqual(env.els['sp-tar'].value, 'AF4D01', 'the typed TAR must survive the send');
assert.strictEqual(env.els['sp-cntr'].value, '0000000020', 'the counter still refreshes');
// an explicit preset apply (or a pack) still sets the TAR
cardsApplyFields(0);
assert.strictEqual(env.els['sp-tar'].value, 'B00000');
});
test('cardsApplyFields fills the form without generating a packet', () => { test('cardsApplyFields fills the form without generating a packet', () => {
const env = fakeEnv('0', 'sp-card-sel', '0000000007'); const env = fakeEnv('0', 'sp-card-sel', '0000000007');
env.els['sp-cntr'].value = 'nonsense'; env.els['sp-cntr'].value = 'nonsense';
+5
View File
@@ -499,6 +499,11 @@ test('getRamSpParams reads the computed SPI2 byte, not the base select', () => {
assert.ok(/spi2: document\.getElementById\('sp-spi2-hex'\)/.test(fn), fn); assert.ok(/spi2: document\.getElementById\('sp-spi2-hex'\)/.test(fn), fn);
}); });
test('getRamSpParams normalises the packet TAR to three bytes', () => {
const fn = extractFunc(html, 'getRamSpParams');
assert.ok(/tar:[\s\S]*?padEnd\(6, '0'\)\.slice\(0, 6\),/.test(fn), fn);
});
test('ramListingSpi2 requests the SMS-submit PoR for the listing queries', () => { test('ramListingSpi2 requests the SMS-submit PoR for the listing queries', () => {
// Apps (40) and ELF (20/10) listings can exceed the ENVELOPE response; // Apps (40) and ELF (20/10) listings can exceed the ENVELOPE response;
// with SPI2=0x01 the card answers actual_response_sms_submit and the data // with SPI2=0x01 the card answers actual_response_sms_submit and the data
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project] [project]
name = "pysim-simple-server" name = "pysim-simple-server"
version = "3.6.20" version = "3.6.21"
description = "HTTP REST server wrapping pysim for the SIMple PWA" description = "HTTP REST server wrapping pysim for the SIMple PWA"
requires-python = ">=3.8" requires-python = ">=3.8"
# pysim is a git-only dependency installed explicitly by setup.bat/setup.sh. # pysim is a git-only dependency installed explicitly by setup.bat/setup.sh.
+1 -1
View File
@@ -31,7 +31,7 @@ from osmocom.tlv import BER_TLV_IE
from osmocom.utils import rpad from osmocom.utils import rpad
VERSION = '3.6.20' VERSION = '3.6.21'
MAX_ENVELOPE_SEGMENTS = 5 # max SMS segments for outgoing C-APDU in ENVELOPE MAX_ENVELOPE_SEGMENTS = 5 # max SMS segments for outgoing C-APDU in ENVELOPE