diff --git a/frontend/index.html b/frontend/index.html
index 760204a..e82f91f 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -809,6 +809,18 @@
+
+
+
+
+
+
@@ -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 += '' +
'
';
+ html += '';
+ html += '';
}
html += '';
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': 'Шифрование',
diff --git a/frontend/sw.js b/frontend/sw.js
index 89819fa..bd5f77b 100644
--- a/frontend/sw.js
+++ b/frontend/sw.js
@@ -1,4 +1,4 @@
-const CACHE = 'simple-v283';
+const CACHE = 'simple-v284';
const URLS = [
'index.html',
'help.html',
diff --git a/frontend/tests/stk_params.test.js b/frontend/tests/stk_params.test.js
index 03d334c..f9ac60d 100644
--- a/frontend/tests/stk_params.test.js
+++ b/frontend/tests/stk_params.test.js
@@ -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' });
diff --git a/pyproject.toml b/pyproject.toml
index ed757bd..1f9d0a3 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "pysim-simple-server"
-version = "3.6.10"
+version = "3.6.11"
description = "HTTP REST server wrapping pysim for the SIMple PWA"
requires-python = ">=3.8"
# pysim is a git-only dependency installed explicitly by setup.bat/setup.sh.
diff --git a/pysim_simple_server/server.py b/pysim_simple_server/server.py
index 3729fd2..ff26824 100644
--- a/pysim_simple_server/server.py
+++ b/pysim_simple_server/server.py
@@ -31,7 +31,7 @@ from osmocom.tlv import BER_TLV_IE
from osmocom.utils import rpad
-VERSION = '3.6.10'
+VERSION = '3.6.11'
MAX_ENVELOPE_SEGMENTS = 5 # max SMS segments for outgoing C-APDU in ENVELOPE