feat: remote-script command palette — RFM/RAM commands in Expanded Script, TS 102 226 §9 PUSH (v3.3.0)
Phase 1 — the Expanded Script C-APDU rows are no longer hex-only: - chain containers gained a kind (chainKind/chainIsEmbedded/chainCommands), so the SIM RFM / USIM RFM / RAM-GP row editors and hex builders can be embedded as one-row "virtual" chains (ber-<kind>-<uid>) with a listener hook (chainListen/chainNotify) refreshing the owning row. - the C-APDU row offers Hex / SIM RFM / USIM RFM / RAM-GP; the built APDU is echoed next to the picker and wrapped in the 22 Command TLV. GET RESPONSE is not offered in the embedded pickers (TS 102 226 5.2.1.1). Phase 2 — "→ Expanded Script" in the SIM RFM / USIM RFM / RAM-GP views imports the built chain as C-APDU rows (chainApduList drops GET RESPONSE and splits multi-APDU FID-chain selects; the RAM "To expanded" preview stays). Phase 3 — the TS 102 226 table 7.1/8.1/9.1 gaps: - RFM: SEARCH RECORD (TS 102 221 11.1.7 / SEEK per TS 151 011 9.2.7), INCREASE (11.1.8 / TS 151 011 9.2.8), CREATE FILE / DELETE FILE / RESIZE FILE (TS 102 222 6.3/6.4/6.10, with an FCP skeleton builder and CLA 80 for RESIZE), SET DATA / RETRIEVE DATA (11.3, block + SFI coding); - RAM: PUT KEY (GP Card Spec 11.8) and the TS 102 226 §9 PUSH command (80 EC 01 P2) with BIP opening (optional OPEN CHANNEL TLVs), CAT_TP (3C/39/36), TCP (35/3C/3E/47) and identification-packet variants. Tests: new frontend/tests/ts102226.test.js (byte-exact spec vectors for every new command, the FCP skeletons, chainApduList) plus C-APDU row tests in ber.test.js; 530 frontend / 390 Python green. Help EN/RU, README/RUS and AGENTS document the Command TLV taxonomy (Tables 5.5/5.9 limits), the picker and the new commands.
This commit is contained in:
@@ -103,7 +103,7 @@ function buildPcHtml(extraFields) {
|
||||
}
|
||||
|
||||
const FNS = ['berLenStr', 'gsm7TextToSeptets', 'gsm7Encode', 'genBerPcValue', 'genErrorActionValue',
|
||||
'genScriptChainingValue'];
|
||||
'genScriptChainingValue', 'chainKind', 'chainIsEmbedded', 'chainCommands', 'berCmdChainId', 'genBerCmdApdu', 'genBerRowValue'];
|
||||
let code = '';
|
||||
for (const f of FNS) code += extractFunc(html, f) + '\n';
|
||||
const berTagsMatch = html.match(/const BER_TAGS = \{[^}]*\};/);
|
||||
@@ -116,6 +116,16 @@ for (const m of [berTagsMatch, berQualMatch, berDevMatch, berTonesMatch, gsm7Alp
|
||||
if (!m) throw new Error('constant not found');
|
||||
code = m[0] + '\n' + code;
|
||||
}
|
||||
for (const c of ['CHAIN_CMDS_SIM', 'CHAIN_CMDS_USIM', 'CHAIN_CMDS_RAM']) {
|
||||
const m = html.match(new RegExp('const ' + c + ' = \\[[\\s\\S]*?\\n\\];'));
|
||||
if (!m) throw new Error('catalog not found: ' + c);
|
||||
code += m[0].replace('const ', 'var ') + '\n';
|
||||
}
|
||||
code += html.match(/const _chains = \{\};/)[0].replace('const ', 'var ') + '\n';
|
||||
code += html.match(/const CHAIN_LISTENERS = \{\};/)[0].replace('const ', 'var ') + '\n';
|
||||
// The embedded command chain is built by the shared command builders, which
|
||||
// are covered by ts102226.test.js; here only the C-APDU row wiring matters.
|
||||
code += 'function chainBuildRowHex(chainId) { return chainId === \'ber-ram-7\' ? \'80D0010101AA\' : \'\'; }\n';
|
||||
code += '\nvar __berConsts = {BER_TAGS, BER_QUAL, BER_DEVICES, BER_TONES, GSM7_ALPHABET, GSM7_EXT_MAP};';
|
||||
eval(code);
|
||||
const {BER_TAGS, BER_QUAL, BER_DEVICES, BER_TONES, GSM7_ALPHABET, GSM7_EXT_MAP} = __berConsts;
|
||||
@@ -277,4 +287,37 @@ test('genScriptChainingValue no position emits empty', () => {
|
||||
keep.name = 'chaining-0-keep';
|
||||
row.children.push(first, interm, last, keep, el('chaining-script-id'), el('chaining-additional'));
|
||||
assert.strictEqual(genScriptChainingValue(row, '83'), '');
|
||||
});
|
||||
|
||||
// ===== Expanded Script C-APDU rows (TS 102 226 5.2.1.0/5.2.1.1) =====
|
||||
|
||||
function cmdRow(mode, value) {
|
||||
const row = new StubEl();
|
||||
row.dataset = { berUid: '7' };
|
||||
const modeEl = el('ber-cmd-mode', mode);
|
||||
const hexEl = el('ber-hex', value || '');
|
||||
const typeEl = el('ber-type', 'c-apdu');
|
||||
row.children.push(typeEl, modeEl, hexEl);
|
||||
row.querySelector = sel => ({ '.ber-type': typeEl, '.ber-cmd-mode': modeEl, '.ber-hex': hexEl })[sel] || null;
|
||||
return row;
|
||||
}
|
||||
|
||||
test('genBerCmdApdu reads pasted hex or the embedded command chain', () => {
|
||||
assert.strictEqual(genBerCmdApdu(cmdRow('hex', '80 ca ff21 00')), '80CAFF2100');
|
||||
assert.strictEqual(genBerCmdApdu(cmdRow('ram', 'ignored')), '80D0010101AA');
|
||||
assert.strictEqual(genBerCmdApdu(cmdRow('hex', '')), '');
|
||||
});
|
||||
|
||||
test('genBerRowValue wraps a C-APDU row in the 22 command TLV', () => {
|
||||
assert.strictEqual(genBerRowValue(cmdRow('ram', '')), '220680D0010101AA');
|
||||
assert.strictEqual(genBerRowValue(cmdRow('hex', '80C AFF2100')), '220580CAFF2100');
|
||||
assert.strictEqual(genBerRowValue(cmdRow('hex', '')), '');
|
||||
});
|
||||
|
||||
test('the embedded pickers offer the RFM/RAM command sets without GET RESPONSE', () => {
|
||||
assert.ok(chainCommands('ber-sim-1').some(c => c.value === 'select'));
|
||||
assert.ok(chainCommands('ber-usim-1').some(c => c.value === 'create-file'));
|
||||
assert.ok(chainCommands('ber-ram-1').some(c => c.value === 'push'));
|
||||
assert.ok(!chainCommands('ber-ram-1').some(c => c.value === 'get-response'));
|
||||
assert.ok(chainCommands('chain-ram').some(c => c.value === 'get-response'));
|
||||
});
|
||||
Reference in New Issue
Block a user