Files
simple/frontend/tests/ram_grants.test.js
T
catarrh daaddf21cb fix: install-form grant hygiene + correct 82 access coding (v3.6.12)
Live findings (2026-09-28): a browser-restored Receipt Generation privilege
bit (third byte, ISD-only per GP Table 6-2) was silently sent and produced
6985, and the '82' access entries were missing the mandatory "Length of
Access Domain DAP" byte, so the card rejected the ADF.USIM entry with 6A80.

- ramResetGrants() clears the privilege / toolkit-enable / file-access
  checkboxes and refreshes the aggregates on load; ramInstallCap re-derives
  the privileges from the checkboxes at send time - no stale or
  browser-restored grant can be sent.
- the privileges aggregate emits 1 or 3 bytes, never the invalid 2-byte
  form (GP Table 11-43), in both updateRcPriv and the chain's computePriv.
- '82' entries carry the DAP-length byte: '00 01 00 00' (shared FS) and
  '<len> <ADF AID> 01 00 00' (ADF); the ADF AID is editable
  (rc-tk-adfaid, default A0000000871002 = ADF.USIM, 5..16 bytes enforced).
- tests: ram_grants.test.js (aggregate forms, the send-time derivation, the
  load-time reset) and the updated access-parameter shapes in
  stk_params.test.js.

638 frontend / 496 Python green; version 3.6.12; sw simple-v285.
2026-09-28 02:56:11 +03:00

79 lines
3.1 KiB
JavaScript

const { test } = require('node:test');
const assert = require('node:assert');
const fs = require('node:fs');
const path = require('node:path');
const html = fs.readFileSync(path.join(__dirname, '..', 'index.html'), 'utf8');
function extractFunc(src, name) {
const re = new RegExp('(?:async\\s+)?function\\s+' + name + '\\s*\\([^)]*\\)\\s*\\{');
const m = re.exec(src);
if (!m) throw new Error('function ' + name + ' not found');
let i = m.index + m[0].length - 1;
let depth = 0;
for (; i < src.length; i++) {
if (src[i] === '{') depth++;
else if (src[i] === '}') {
depth--;
if (depth === 0) break;
}
}
return src.slice(m.index, i + 1);
}
let code = '';
for (const fn of ['updateRcPriv']) code += extractFunc(html, fn) + '\n';
eval(code);
// The install form's grants are per-session choices: the privileges are an
// aggregate of the checkboxes, derived at send time (a browser-restored
// Receipt Generation bit produced 6985 on the live card, 2026-09-28).
function fakeEnv(checked) {
const els = { 'rc-priv': { value: '' } };
const boxes = checked.map(([cls, val]) => ({ className: cls, value: val, checked: true }));
globalThis.document = {
getElementById: id => els[id] || null,
querySelectorAll: sel => boxes.filter(b => sel.indexOf('.' + b.className) >= 0),
};
return els;
}
test('updateRcPriv aggregates the checked privilege boxes', () => {
let els = fakeEnv([]);
updateRcPriv();
assert.strictEqual(els['rc-priv'].value, '00');
els = fakeEnv([['rc-priv-b3', '80']]);
updateRcPriv();
assert.strictEqual(els['rc-priv'].value, '000080', 'Receipt Generation is the third byte');
els = fakeEnv([['rc-priv-b1', '80'], ['rc-priv-b3', '80']]);
updateRcPriv();
assert.strictEqual(els['rc-priv'].value, '800080');
els = fakeEnv([['rc-priv-b1', '04'], ['rc-priv-b2', '80']]);
updateRcPriv();
assert.strictEqual(els['rc-priv'].value, '048000');
els = fakeEnv([['rc-priv-b1', '80'], ['rc-priv-b1', '40'], ['rc-priv-b2', '80']]);
updateRcPriv();
assert.strictEqual(els['rc-priv'].value, 'C08000', 'bits within a byte are OR-ed');
});
test('the install derives the privileges at send time', () => {
const fn = extractFunc(html, 'ramInstallCap');
const iPriv = fn.indexOf('updateRcPriv();');
const iBody = fn.indexOf('const body = {');
assert.ok(iPriv >= 0, 'ramInstallCap must call updateRcPriv()');
assert.ok(iBody >= 0, 'ramInstallCap body not found');
assert.ok(iPriv < iBody, 'the privileges must be derived before the request body');
});
test('the form resets the restored grants on load', () => {
assert.ok(/function ramResetGrants\(\)/.test(html), 'ramResetGrants is missing');
assert.ok(/querySelectorAll\('\.rc-priv-b1, \.rc-priv-b2, \.rc-priv-b3'\)/.test(html),
'the privilege checkboxes must be cleared');
assert.ok(/chainInit\('chain-ram'\);\s*\n\s*ramResetGrants\(\);/.test(html),
'ramResetGrants must run on load');
assert.ok(/getElementById\('rc-toolkit-enable'\)\.checked = false;/.test(html),
'the toolkit enable must be cleared');
assert.ok(/getElementById\('rc-tk-fsaccess'\)\.checked = false;/.test(html),
'the file-access grant must be cleared');
});