feat: UICC file-access parameters in the install form (v3.6.11)
SIM toolkit applets installed while UICC-library applets failed at INSTALL [for install] with 6F00 - including with the reference tool's exact install parameters. The asymmetry: the SIM (CA) path grants file access via the Access Domain field (default 00 = full access), while the UICC (EA) path sent no '82' (UICC Access Application specific parameters) at all, and the reference's '82 00' is empty. An applet importing uicc.access (the failing CAP has 2 refs) can then fail inside its install(). - EA mode gains two checkboxes (RAM install form + the chain rows' toolkit block): "File system access (full)" appends '82 03 00 01 00' (shared file system + Access Domain Parameter 00 = full access, TS 102 226 8.2.1.3.2.2.2/8.2.1.3.2.5); "ADF.USIM access (full)" adds '07 A0000000871002 01 00' to it. Both default off. - tests: the access TLV shapes (with/without the ADF entry), the form -> hex path with the checkbox, and the toolkit-field wiring count (16 fields). 635 frontend / 496 Python green; version 3.6.11; sw simple-v284.
This commit is contained in:
+41
-4
@@ -809,6 +809,18 @@
|
||||
<label class="block mb-1 text-xs font-medium text-gray-700 dark:text-slate-300" data-l10n="Max services">Max services</label>
|
||||
<input id="rc-tk-services" oninput="updateStkParamsHex()" type="number" min="0" max="255" value="0" class="font-mono w-full border border-gray-300 dark:border-slate-600 text-xs rounded px-2 py-1.5 dark:bg-slate-800">
|
||||
</div>
|
||||
<div id="rc-tk-fsaccess-row" class="col-span-2">
|
||||
<label class="flex items-center gap-2 text-xs font-medium text-gray-700 dark:text-slate-300">
|
||||
<input id="rc-tk-fsaccess" type="checkbox" onchange="updateStkParamsHex()" class="rounded border-gray-300 dark:border-slate-600 dark:bg-slate-800">
|
||||
<span data-l10n="File system access (full)">File system access (full)</span>
|
||||
</label>
|
||||
</div>
|
||||
<div id="rc-tk-adfaccess-row" class="col-span-2">
|
||||
<label class="flex items-center gap-2 text-xs font-medium text-gray-700 dark:text-slate-300">
|
||||
<input id="rc-tk-adfaccess" type="checkbox" onchange="updateStkParamsHex()" class="rounded border-gray-300 dark:border-slate-600 dark:bg-slate-800">
|
||||
<span data-l10n="ADF.USIM access (full)">ADF.USIM access (full)</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1665,7 +1677,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.6.10';
|
||||
const SIMPLE_VERSION = '3.6.11';
|
||||
document.getElementById('app-version').textContent = 'v' + SIMPLE_VERSION;
|
||||
|
||||
// ===== Tab switching =====
|
||||
@@ -2502,6 +2514,8 @@ function updateRcTkMode() {
|
||||
const isSim = document.getElementById('rc-tk-mode').value === 'ca';
|
||||
document.getElementById('rc-tk-ad-row').style.display = isSim ? '' : 'none';
|
||||
document.getElementById('rc-tk-services-row').style.display = isSim ? 'none' : '';
|
||||
document.getElementById('rc-tk-fsaccess-row').style.display = isSim ? 'none' : '';
|
||||
document.getElementById('rc-tk-adfaccess-row').style.display = isSim ? 'none' : '';
|
||||
}
|
||||
|
||||
// Pure SIM/UICC toolkit install-parameter builder shared by the RAM install
|
||||
@@ -2509,7 +2523,10 @@ function updateRcTkMode() {
|
||||
// `v` carries the field values; returns the CA/EA TLV hex, or null when a
|
||||
// value cannot be coded: each TAR is 3 bytes (6 hex digits), and menu item
|
||||
// identifiers 128..255 are reserved for the toolkit framework, so only
|
||||
// 01..7F may be requested (TS 102 226 8.2.1.3.2.3).
|
||||
// 01..7F may be requested (TS 102 226 8.2.1.3.2.3). In EA mode `v.fsAccess`
|
||||
// adds the UICC file-access parameters (tag '82') and `v.adfAccess` extends
|
||||
// them with an ADF.USIM entry; the SIM path grants access via the CA Access
|
||||
// Domain field instead.
|
||||
function stkParamsBuild(v) {
|
||||
const priority = parseInt(v.priority, 10) || 0;
|
||||
const timers = parseInt(v.timers, 10) || 0;
|
||||
@@ -2557,8 +2574,17 @@ function stkParamsBuild(v) {
|
||||
mslField +
|
||||
(tar ? (tar.length / 2).toString(16).padStart(2, '0') + tar : '00') +
|
||||
services.toString(16).padStart(2, '0');
|
||||
const innerTlv = '80' + berLenStr(tkPayload.length / 2) + tkPayload;
|
||||
return 'EA' + berLenStr(innerTlv.length / 2) + innerTlv;
|
||||
let eaValue = '80' + berLenStr(tkPayload.length / 2) + tkPayload;
|
||||
if (v.fsAccess) {
|
||||
// UICC Access Application specific parameters (TS 102 226
|
||||
// 8.2.1.3.2.2.2): [file system AID length 00 = shared file system]
|
||||
// [Access Domain length 01][ADP 00 = full access], optionally with an
|
||||
// ADF entry [AID length 07][ADF.USIM][AD length 01][ADP 00].
|
||||
let acc = '000100';
|
||||
if (v.adfAccess) acc += '07A00000008710020100';
|
||||
eaValue += '82' + berLenStr(acc.length / 2) + acc;
|
||||
}
|
||||
return 'EA' + berLenStr(eaValue.length / 2) + eaValue;
|
||||
}
|
||||
|
||||
// The RAM install form's toolkit fields -> the install parameters hex.
|
||||
@@ -2573,6 +2599,8 @@ function buildRcToolkitParams() {
|
||||
lastPos: g('rc-tk-lastpos'), lastId: g('rc-tk-lastid'),
|
||||
channels: g('rc-tk-channels'), msl: g('rc-tk-msl'),
|
||||
tar: g('rc-tk-tar'), ad: g('rc-tk-ad'), services: g('rc-tk-services'),
|
||||
fsAccess: document.getElementById('rc-tk-fsaccess').checked,
|
||||
adfAccess: document.getElementById('rc-tk-adfaccess').checked,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3437,6 +3465,12 @@ function chainRamToolkitHtml(chainId, idx, f, uf) {
|
||||
} else {
|
||||
html += '<div><label class="block text-gray-600 dark:text-slate-400 mb-0.5">Max services</label>' +
|
||||
'<input type="number" min="0" max="255" value="' + escHtml(services) + '" oninput="' + uf('tkServices') + '" class="w-full font-mono border border-gray-300 dark:border-slate-600 rounded px-1.5 py-0.5 dark:bg-slate-800"></div>';
|
||||
html += '<div class="col-span-4"><label class="flex items-center gap-1 text-gray-600 dark:text-slate-400">' +
|
||||
'<input type="checkbox"' + (f.tkFsAccess ? ' checked' : '') + ' onchange="chainUpdateField(\'' + chainId + '\',' + idx + ',\'tkFsAccess\',this.checked);chainRender(\'' + chainId + '\')" class="rounded">' +
|
||||
'File system access (full)</label></div>';
|
||||
html += '<div class="col-span-4"><label class="flex items-center gap-1 text-gray-600 dark:text-slate-400">' +
|
||||
'<input type="checkbox"' + (f.tkAdfAccess ? ' checked' : '') + ' onchange="chainUpdateField(\'' + chainId + '\',' + idx + ',\'tkAdfAccess\',this.checked);chainRender(\'' + chainId + '\')" class="rounded">' +
|
||||
'ADF.USIM access (full)</label></div>';
|
||||
}
|
||||
html += '</div></div>';
|
||||
return html;
|
||||
@@ -4055,6 +4089,7 @@ function chainRamBuildRowHex(idx, row) {
|
||||
lastPos: f.tkLastpos, lastId: f.tkLastid, channels: f.tkChannels,
|
||||
msl: f.tkMsl || '16', tar: f.tkTar, ad: f.tkAd,
|
||||
services: f.tkServices,
|
||||
fsAccess: f.tkFsAccess, adfAccess: f.tkAdfAccess,
|
||||
});
|
||||
}
|
||||
// INSTALL/LOAD are case-3 commands (no trailing Le), matching the
|
||||
@@ -16391,6 +16426,8 @@ const LANG_RU = {
|
||||
'Last menu ID (hex)': 'ID последнего пункта меню (hex)',
|
||||
'Channels (max)': 'Каналы (макс)',
|
||||
'Access domain (hex)': 'Домен доступа (hex)',
|
||||
'File system access (full)': 'Доступ к файловой системе (полный)',
|
||||
'ADF.USIM access (full)': 'Доступ к ADF.USIM (полный)',
|
||||
'Load data (hex)': 'Данные загрузки (hex)',
|
||||
'Block number': 'Номер блока',
|
||||
'Encryption': 'Шифрование',
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
const CACHE = 'simple-v283';
|
||||
const CACHE = 'simple-v284';
|
||||
const URLS = [
|
||||
'index.html',
|
||||
'help.html',
|
||||
|
||||
@@ -102,7 +102,7 @@ test('every toolkit field regenerates the STK parameters hex on edit', () => {
|
||||
assert.ok(/on(?:input|change)="[^"]*updateStkParamsHex/.test(m[0]),
|
||||
m[1] + ' does not refresh the hex: ' + m[0]);
|
||||
}
|
||||
assert.strictEqual(seen.length, 14, 'expected 14 toolkit fields, got ' + seen.join(', '));
|
||||
assert.strictEqual(seen.length, 16, 'expected 16 toolkit fields, got ' + seen.join(', '));
|
||||
});
|
||||
|
||||
test('the applet TAR field has no B00001 default or placeholder', () => {
|
||||
@@ -127,11 +127,13 @@ function fakeForm(values) {
|
||||
const ids = ['rc-toolkit-enable', 'rc-tk-mode', 'rc-tk-priority', 'rc-tk-timers',
|
||||
'rc-tk-textlen', 'rc-tk-menus', 'rc-tk-firstpos', 'rc-tk-firstid',
|
||||
'rc-tk-lastpos', 'rc-tk-lastid', 'rc-tk-channels', 'rc-tk-msl',
|
||||
'rc-tk-tar', 'rc-tk-ad', 'rc-tk-services', 'ram-stk-params'];
|
||||
'rc-tk-tar', 'rc-tk-ad', 'rc-tk-services', 'rc-tk-fsaccess',
|
||||
'rc-tk-adfaccess', 'ram-stk-params'];
|
||||
const checks = ['rc-toolkit-enable', 'rc-tk-fsaccess', 'rc-tk-adfaccess'];
|
||||
const els = {};
|
||||
for (const id of ids) els[id] = { value: '', checked: false, dataset: {} };
|
||||
for (const [id, v] of Object.entries(values || {})) {
|
||||
if (id === 'rc-toolkit-enable') els[id].checked = v;
|
||||
if (checks.indexOf(id) >= 0) els[id].checked = !!v;
|
||||
else els[id].value = v;
|
||||
}
|
||||
globalThis.document = { getElementById: id => els[id] || null };
|
||||
@@ -147,6 +149,34 @@ test('the RAM form fields build the live install parameters end to end', () => {
|
||||
assert.strictEqual(buildRcToolkitParams(), 'EA0F800D000000000102011203AF4D0100');
|
||||
});
|
||||
|
||||
test('UICC file-access parameters (82) are appended in EA mode', () => {
|
||||
// TS 102 226 8.2.1.3.2.2.2: [file system AID len 00 = shared FS]
|
||||
// [Access Domain len 01][ADP 00 = full access]; the SIM path grants the
|
||||
// same rights via the CA Access Domain field. The ADF entry is an
|
||||
// extension of the file-system entry.
|
||||
const base = vals({ channels: '1', msl: '12', tar: 'AF4D01' });
|
||||
assert.strictEqual(stkParamsBuild(Object.assign({}, base, { fsAccess: true })),
|
||||
'EA14800D000000000102011203AF4D01008203000100');
|
||||
assert.strictEqual(
|
||||
stkParamsBuild(Object.assign({}, base, { fsAccess: true, adfAccess: true })),
|
||||
'EA1E800D000000000102011203AF4D0100820D00010007A00000008710020100');
|
||||
assert.strictEqual(stkParamsBuild(base), 'EA0F800D000000000102011203AF4D0100');
|
||||
assert.strictEqual(stkParamsBuild(Object.assign({}, base, { adfAccess: true })),
|
||||
'EA0F800D000000000102011203AF4D0100');
|
||||
});
|
||||
|
||||
test('the RAM form emits full file access when the checkbox is ticked', () => {
|
||||
fakeForm({ 'rc-toolkit-enable': true, 'rc-tk-mode': 'ea', 'rc-tk-msl': '12',
|
||||
'rc-tk-tar': 'AF4D01', 'rc-tk-channels': '1', 'rc-tk-fsaccess': true });
|
||||
assert.strictEqual(buildRcToolkitParams(),
|
||||
'EA14800D000000000102011203AF4D01008203000100');
|
||||
fakeForm({ 'rc-toolkit-enable': true, 'rc-tk-mode': 'ea', 'rc-tk-msl': '12',
|
||||
'rc-tk-tar': 'AF4D01', 'rc-tk-channels': '1', 'rc-tk-fsaccess': true,
|
||||
'rc-tk-adfaccess': true });
|
||||
assert.strictEqual(buildRcToolkitParams(),
|
||||
'EA1E800D000000000102011203AF4D0100820D00010007A00000008710020100');
|
||||
});
|
||||
|
||||
test('updateStkParamsHex refreshes the field and clears the manual flag', () => {
|
||||
const els = fakeForm({ 'rc-toolkit-enable': true, 'rc-tk-mode': 'ea',
|
||||
'rc-tk-tar': 'AF4D01' });
|
||||
|
||||
Reference in New Issue
Block a user