fix: robust equip-state detection and review follow-ups (v3.5.4)
Code-review follow-ups for v3.5.2/v3.5.1, plus a test flake found while re-running the suites: - F1: a half-initialized equip is no longer reported as success. cmd2 swallows exceptions raised inside the equip command (and prints no traceback by default), while PysimApp.equip() assigns card/rs before it registers the command sets - so app.card alone once let the "CommandSet ... is already installed" abort pass as done while /api/tree stayed broken. The auto-equip attempt now captures the output with cmd2 debug on (a swallowed error prints a traceback), requires the new profile's command-set instances to be installed (_app_equip_complete), and the manual /api/command equip branch applies the post-equip refresh only when that check passes (and reports it in the output when it does not). - F3: SCARD_E_SHARING_VIOLATION is recoverable (a rebuild cannot free another process's claim) instead of transport-fatal. - F4: SPI1 b2b1 = 11 (Digital Signature) is refused instead of building an unsigned packet; help notes RC is CRC-32 only (KID CRC-16 not offered). - F5: _clear_app_card_state removes the muted stdout again when the app object had no stdout attribute. - F7: the watchdog re-arm keeps its rate-limit window when the trigger is busy/disabled instead of consuming it. - F2: stale docstring in _auto_equip_attempt. - tests: equip-state units, half-equip and captured-traceback failures, unequip-on-failure, busy trigger, sharing violation, DS refusal. - bonus: the MCC/MNC random-pick test could fail because a dict keyed by (mcc, mnc) keeps one of two entries (the bundled list carries both a real and an MVNO entry for 234/18 and 234/28); the picker was correct - the assertion now checks the pair against the non-MVNO pairs. 549 frontend / 421 Python green; version 3.5.4; sw cache simple-v256.
This commit is contained in:
@@ -304,7 +304,7 @@
|
||||
<li><strong>AES-CBC</strong> шифрование (нулевой ICV, дополнение нулями до 16), ключи 16/24/32 байта (TS 102 225 §5.1.2, KIc <code class="font-mono text-sm">x2</code>)</li>
|
||||
<li><strong>Retail MAC</strong> (ISO 9797-1, MAC algorithm 3) для контрольной суммы DES/3DES</li>
|
||||
<li><strong>AES-CMAC</strong> (NIST SP 800-38B, усечённый до 8 октетов) для контрольной суммы AES (TS 102 225 §5.1.3.1, KID <code class="font-mono text-sm">x2</code>)</li>
|
||||
<li><strong>Redundancy Check (RC)</strong> — CRC-32 по тому же кадру заголовка, что и CC (TS 102 225 §5.1.3.2; ключ не нужен, SPI1 b2b1 = <code class="font-mono text-sm">01</code>)</li>
|
||||
<li><strong>Redundancy Check (RC)</strong> — CRC-32 по тому же кадру заголовка, что и CC (TS 102 225 §5.1.3.2; ключ не нужен, SPI1 b2b1 = <code class="font-mono text-sm">01</code>). Реализована только CRC-32 (как в pySim); кодирование CRC-16 по KID не поддерживается.</li>
|
||||
<li>AES требует счётчик с защитой от повтора: биты SPI1 b5 b4 должны быть <code class="font-mono text-sm">10</code> (счётчик больше) или <code class="font-mono text-sm">11</code> (счётчик +1) согласно TS 102 225 §5.1.2/§5.1.3.1</li>
|
||||
<li>Байт паддинга настраивается (<code class="font-mono text-sm">00</code> по умолчанию или <code class="font-mono text-sm">FF</code>)</li>
|
||||
</ul>
|
||||
|
||||
+1
-1
@@ -303,7 +303,7 @@
|
||||
<li><strong>AES-CBC</strong> encryption (zero ICV, zero-padded to 16), 16/24/32-byte keys (TS 102 225 §5.1.2, KIc <code class="font-mono text-sm">x2</code>)</li>
|
||||
<li><strong>Retail MAC</strong> (ISO 9797-1 MAC algorithm 3) for the DES/3DES cryptographic checksum</li>
|
||||
<li><strong>AES-CMAC</strong> (NIST SP 800-38B, truncated to 8 octets) for the AES cryptographic checksum (TS 102 225 §5.1.3.1, KID <code class="font-mono text-sm">x2</code>)</li>
|
||||
<li><strong>Redundancy Check (RC)</strong> — CRC-32 over the same header frame as the CC (TS 102 225 §5.1.3.2; needs no key, SPI1 b2b1 = <code class="font-mono text-sm">01</code>)</li>
|
||||
<li><strong>Redundancy Check (RC)</strong> — CRC-32 over the same header frame as the CC (TS 102 225 §5.1.3.2; needs no key, SPI1 b2b1 = <code class="font-mono text-sm">01</code>). Only CRC-32 is implemented, matching pySim; the KID's CRC-16 coding is not offered.</li>
|
||||
<li>AES requires a replay-protected counter: SPI1 bits b5 b4 must be <code class="font-mono text-sm">10</code> (counter higher) or <code class="font-mono text-sm">11</code> (counter +1) per TS 102 225 §5.1.2/§5.1.3.1</li>
|
||||
<li>Padding byte configurable (<code class="font-mono text-sm">00</code> default, or <code class="font-mono text-sm">FF</code>)</li>
|
||||
</ul>
|
||||
|
||||
+9
-1
@@ -1559,7 +1559,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.5.3';
|
||||
const SIMPLE_VERSION = '3.5.4';
|
||||
document.getElementById('app-version').textContent = 'v' + SIMPLE_VERSION;
|
||||
|
||||
// ===== Tab switching =====
|
||||
@@ -4594,6 +4594,14 @@ function _genSpBuild() {
|
||||
|
||||
const resultEl = document.getElementById('sp-result');
|
||||
|
||||
// Digital Signature is not implemented (pySim has no DS dialect either):
|
||||
// refuse rather than build a packet whose SPI claims a signature that is
|
||||
// not present. The selector does not offer '11'; this guards the field.
|
||||
if (rcCcDs === 0x03) {
|
||||
resultEl.value = 'Error: SPI1 RC/CC/DS = 11 (Digital Signature) is not supported';
|
||||
return;
|
||||
}
|
||||
|
||||
// Rel-18: AES requires a replay-protected counter (SPI1 b5b4 = 10 or 11)
|
||||
if ((kicIsAes && ciphering) || (kidIsAes && hasMac)) {
|
||||
const counterBits = (spi1 >> 3) & 0x03;
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
const CACHE = 'simple-v255';
|
||||
const CACHE = 'simple-v256';
|
||||
const URLS = [
|
||||
'index.html',
|
||||
'help.html',
|
||||
|
||||
@@ -122,6 +122,10 @@ test('RC (SPI 01) computes CRC-32 over the CPL frame', () => {
|
||||
'00191101091515B0000000000000010050C942DC00A40000023F00');
|
||||
});
|
||||
|
||||
test('DS (SPI 03) is refused instead of building an unsigned packet', () => {
|
||||
assert.match(makeRun({ 'sp-spi1': '03' }), /Digital Signature/);
|
||||
});
|
||||
|
||||
test('crc32Bytes known answer (TS 102 225 Annex B)', () => {
|
||||
assert.strictEqual(bytesToHex(crc32Bytes(hexToBytes('0102030405'))), '470B99F4');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user