ui: verify the ADM PIN from the matched card preset (v2.7.8)
The preset ADM key was stored but never used: the header badge showed whether a key exists and whether the card was verified, yet the only way to verify was the pySim command line. - POST /api/verify-adm builds the TS 102 221 VERIFY itself (CHV number from the card model, short keys padded to 8 bytes with 'f') so the raw SW is reported: 63Cx -> attempts_left, 6983/9804 -> blocked, 6982 -> security error. The key is never stored and is redacted from request logs. - PWA: the header ADM badge is clickable when the matched preset has a key; a failed file-manager read/write (6982/9804) shows a Verify ADM button next to the error. Every retry after a failure asks for confirmation and shows the remaining attempts (stronger text on the last attempt); a blocked ADM disables both entry points until the card session changes. No automatic retries. - tests: tests/test_adm_verify.py (fake scc, APDU/SW mapping, redaction) and frontend/tests/adm_verify.test.js (retry prompt, SW classifier, wiring) + card_state indicator expectations - docs/api.md, help EN/RU, AGENTS; version trio 2.7.8; sw cache v211
This commit is contained in:
@@ -25,6 +25,9 @@ let code = 'var _pysimCardStateKey = null;\nvar _pysimCardSession = null;\n'
|
||||
+ 'var _pysimServerAvailable = null;\nvar _pysimCardEquipped = false;\n'
|
||||
+ 'var _pysimProactiveSeq = null;\nvar _pysimStkSig = null;\nvar _pysimAdmVerified = null;\n'
|
||||
+ 'var _pysimAdmKey = null;\n'
|
||||
+ 'var _pysimAdmCanVerify = false;\nvar _pysimAdmAttemptsLeft = null;\n'
|
||||
+ 'var _pysimAdmBlocked = false;\nvar _pysimAdmVerifying = false;\n'
|
||||
+ 'var _pysimAdmStateKey = null;\nvar _pysimLastStatus = null;\n'
|
||||
+ 'var _pysimHeaderIccid = undefined;\nvar _pysimHeaderScp80 = undefined;\nvar _pysimHeaderScp81 = undefined;\n'
|
||||
+ 'var _cardsAutoIccid = null;\nvar _pysimCardIccid = null;\n';
|
||||
code += extractFunc(html, 'pysimCardStateUpdate') + '\n';
|
||||
@@ -33,6 +36,7 @@ code += extractFunc(html, 'pysimControlDisabled') + '\n';
|
||||
code += extractFunc(html, 'pysimProactiveSeqChanged') + '\n';
|
||||
code += extractFunc(html, 'pysimStkStatusChanged') + '\n';
|
||||
code += extractFunc(html, 'pysimUpdateAdmIndicator') + '\n';
|
||||
code += extractFunc(html, 'pysimAdmResetAttempts') + '\n';
|
||||
code += extractFunc(html, 'pysimUpdateIccidIndicator') + '\n';
|
||||
code += extractFunc(html, 'pysimUpdatePresetIndicator') + '\n';
|
||||
code += extractFunc(html, 'pysimUpdatePresetIndicators') + '\n';
|
||||
@@ -72,6 +76,12 @@ function setup() {
|
||||
_pysimProactiveSeq = null;
|
||||
_pysimAdmVerified = null;
|
||||
_pysimAdmKey = null;
|
||||
_pysimAdmCanVerify = false;
|
||||
_pysimAdmAttemptsLeft = null;
|
||||
_pysimAdmBlocked = false;
|
||||
_pysimAdmVerifying = false;
|
||||
_pysimAdmStateKey = null;
|
||||
_pysimLastStatus = null;
|
||||
_pysimHeaderIccid = undefined;
|
||||
_pysimHeaderScp80 = undefined;
|
||||
_pysimHeaderScp81 = undefined;
|
||||
@@ -272,11 +282,12 @@ test('the ADM badge marks an ADM key in the matching preset', () => {
|
||||
globalThis.cardsFindByIccid = () => 0;
|
||||
pysimCardStateUpdate(st({ adm_verified: true }));
|
||||
assert.strictEqual(adm.textContent, 'ADM ✓ ⚿');
|
||||
assert.strictEqual(adm.title, 'ADM key in the card preset — verified');
|
||||
assert.strictEqual(adm.title, 'ADM key in the card preset — click to verify');
|
||||
assert.ok(adm.classes.has('cursor-pointer'), 'the badge is clickable with a preset key');
|
||||
// key present, verification lost (e.g. card reset)
|
||||
pysimCardStateUpdate(st({ adm_verified: false }));
|
||||
assert.strictEqual(adm.textContent, 'ADM ✗ ⚿');
|
||||
assert.strictEqual(adm.title, 'ADM key in the card preset — not verified');
|
||||
assert.strictEqual(adm.title, 'ADM key in the card preset — click to verify');
|
||||
// verified manually, preset has no ADM -> no key glyph
|
||||
globalThis.cards = [];
|
||||
pysimCardStateUpdate(st({ adm_verified: true }));
|
||||
|
||||
Reference in New Issue
Block a user