ui: start the SELECT picker session in MF for both RFM builders

The file picker's implicit current DF now defaults to MF for SIM RFM and
USIM RFM alike (the real context follows the TAR the packet is sent to,
TS 102 226 7.2/7.3, so the default is neutral and the per-row "starts in"
selector covers ADF sessions - ADF.USIM files appear once it is switched).
Tests set the ADF session explicitly where they exercise ADF-relative fills
plus a new default assertion; help 2.1 EN/RU, READMEs and AGENTS updated.
sw cache -> simple-v244; version stays 3.4.0.
This commit is contained in:
2026-09-23 08:34:27 +03:00
parent 1035bf069d
commit a5f7ca840d
7 changed files with 19 additions and 8 deletions
+1 -1
View File
@@ -82,7 +82,7 @@ CLA = `A0` (GSM 11.11 / ISO 7816-4).
Every SELECT row offers a file picker: a filter box, an **all files** toggle, the session start root with the current DF, and the file list grouped by root (`MF`, `ADF.USIM`, ...). Picking a file fills the fields for the current method; when the method cannot express the selection the picker switches to one that can - preferring **path** (one SELECT), then **chain** - and says so, e.g. `7F106F40` (path from MF) or `7F20,6F46` (relative FID chain). Every SELECT row offers a file picker: a filter box, an **all files** toggle, the session start root with the current DF, and the file list grouped by root (`MF`, `ADF.USIM`, ...). Picking a file fills the fields for the current method; when the method cannot express the selection the picker switches to one that can - preferring **path** (one SELECT), then **chain** - and says so, e.g. `7F106F40` (path from MF) or `7F20,6F46` (relative FID chain).
- **List source**: with a card equipped the loaded file-manager tree wins (card names, probed presence; probed-absent files are hidden). Without a card, or for branches the tree has not loaded, the shipped standard list is used: `uicc_files.json`, generated from pySim's profiles/application classes by `pysim_simple_server/uicc_files.py` and drift-guarded by `tests/test_uicc_files.py`. It is specs-default until **Probe all files** runs in the file manager. Custom files are always merged. - **List source**: with a card equipped the loaded file-manager tree wins (card names, probed presence; probed-absent files are hidden). Without a card, or for branches the tree has not loaded, the shipped standard list is used: `uicc_files.json`, generated from pySim's profiles/application classes by `pysim_simple_server/uicc_files.py` and drift-guarded by `tests/test_uicc_files.py`. It is specs-default until **Probe all files** runs in the file manager. Custom files are always merged.
- **Session start**: the implicit current DF follows the TAR the secured packet is sent to (UICC Shared File System RFM -> MF, TS 102 226 §7.2; ADF RFM -> its ADF, §7.3). Defaults: MF here, ADF.USIM for USIM RFM; changeable per row. - **Session start**: the implicit current DF follows the TAR the secured packet is sent to (UICC Shared File System RFM -> MF, TS 102 226 §7.2; ADF RFM -> its ADF, §7.3). Defaults: MF for both builders; changeable per row (pick the ADF to work in an ADF session).
- **Path** is the FID sequence from MF without the MF identifier (ISO 7816-4); the USIM "from current DF" variant uses the relative tail. **Chain** stays relative to the current DF and follows the TS 102 221 §11.1.1.2 FID search order (children, parent, siblings). - **Path** is the FID sequence from MF without the MF identifier (ISO 7816-4); the USIM "from current DF" variant uses the relative tail. **Chain** stays relative to the current DF and follows the TS 102 221 §11.1.1.2 FID search order (children, parent, siblings).
- ADF roots are not pickable - an application is selected by AID, which the **By AID** method keeps manual (TS 102 226 §7.1 forbids P1=`04` for RFM). - ADF roots are not pickable - an application is selected by AID, which the **By AID** method keeps manual (TS 102 226 §7.1 forbids P1=`04` for RFM).
+1 -1
View File
@@ -82,7 +82,7 @@ CLA = `A0` (GSM 11.11 / ISO 7816-4).
У каждой строки SELECT есть выбор файла: поле фильтра, переключатель **all files**, корень начала сессии с текущим DF и список файлов по корням (`MF`, `ADF.USIM`, ...). Выбор файла заполняет поля текущего метода; если метод не может выразить выбор, помощник переключается на подходящий - предпочитая **path** (один SELECT), затем **chain** - и сообщает об этом, например `7F106F40` (путь от MF) или `7F20,6F46` (относительная цепочка FID). У каждой строки SELECT есть выбор файла: поле фильтра, переключатель **all files**, корень начала сессии с текущим DF и список файлов по корням (`MF`, `ADF.USIM`, ...). Выбор файла заполняет поля текущего метода; если метод не может выразить выбор, помощник переключается на подходящий - предпочитая **path** (один SELECT), затем **chain** - и сообщает об этом, например `7F106F40` (путь от MF) или `7F20,6F46` (относительная цепочка FID).
- **Источник списка**: при подключённой карте приоритет у загруженного дерева файлового менеджера (имена карты, проверенное наличие; отсутствующие скрываются). Без карты и для незагруженных ветвей используется поставляемый стандартный список: `uicc_files.json`, собранный из профилей/классов приложений pySim скриптом `pysim_simple_server/uicc_files.py` и проверяемый `tests/test_uicc_files.py`. До запуска **«Проверить все файлы»** список соответствует спецификациям. Пользовательские файлы добавляются всегда. - **Источник списка**: при подключённой карте приоритет у загруженного дерева файлового менеджера (имена карты, проверенное наличие; отсутствующие скрываются). Без карты и для незагруженных ветвей используется поставляемый стандартный список: `uicc_files.json`, собранный из профилей/классов приложений pySim скриптом `pysim_simple_server/uicc_files.py` и проверяемый `tests/test_uicc_files.py`. До запуска **«Проверить все файлы»** список соответствует спецификациям. Пользовательские файлы добавляются всегда.
- **Начало сессии**: неявный текущий DF зависит от TAR, на который отправляется защищённый пакет (UICC Shared File System RFM -> MF, TS 102 226 §7.2; ADF RFM -> свой ADF, §7.3). По умолчанию: MF здесь и ADF.USIM для USIM RFM; меняется для каждой строки. - **Начало сессии**: неявный текущий DF зависит от TAR, на который отправляется защищённый пакет (UICC Shared File System RFM -> MF, TS 102 226 §7.2; ADF RFM -> свой ADF, §7.3). По умолчанию: MF для обоих конструкторов; меняется для каждой строки (выберите ADF для работы в сессии ADF).
- **Path** - последовательность FID от MF без идентификатора MF (ISO 7816-4); вариант USIM «from current DF» использует относительный хвост. **Chain** остаётся относительным к текущему DF и следует порядку поиска FID из TS 102 221 §11.1.1.2 (дети, родитель, соседи). - **Path** - последовательность FID от MF без идентификатора MF (ISO 7816-4); вариант USIM «from current DF» использует относительный хвост. **Chain** остаётся относительным к текущему DF и следует порядку поиска FID из TS 102 221 §11.1.1.2 (дети, родитель, соседи).
- Корни ADF не выбираются - приложение выбирается по AID, и метод **By AID** остаётся ручным (TS 102 226 §7.1 запрещает P1=`04` для RFM). - Корни ADF не выбираются - приложение выбирается по AID, и метод **By AID** остаётся ручным (TS 102 226 §7.1 запрещает P1=`04` для RFM).
+1 -1
View File
@@ -98,7 +98,7 @@
<p class="text-sm mb-2">У каждой строки SELECT под полями метода есть выбор файла: поле фильтра, переключатель <strong>all files</strong>, корень начала сессии с текущим DF и список файлов, сгруппированный по корню (<code class="font-mono text-sm">MF</code>, <code class="font-mono text-sm">ADF.USIM</code>, &hellip;). Выбор файла заполняет поля текущего метода; если метод не может выразить выбор, помощник переключается на подходящий &mdash; предпочитая <strong>path</strong> (один SELECT), затем <strong>chain</strong> &mdash; и пишет об этом в строке примечания, например файл из другого DF становится <code class="font-mono text-sm">7F106F40</code> (путь от MF) или <code class="font-mono text-sm">7F20,6F46</code> (относительная цепочка FID).</p> <p class="text-sm mb-2">У каждой строки SELECT под полями метода есть выбор файла: поле фильтра, переключатель <strong>all files</strong>, корень начала сессии с текущим DF и список файлов, сгруппированный по корню (<code class="font-mono text-sm">MF</code>, <code class="font-mono text-sm">ADF.USIM</code>, &hellip;). Выбор файла заполняет поля текущего метода; если метод не может выразить выбор, помощник переключается на подходящий &mdash; предпочитая <strong>path</strong> (один SELECT), затем <strong>chain</strong> &mdash; и пишет об этом в строке примечания, например файл из другого DF становится <code class="font-mono text-sm">7F106F40</code> (путь от MF) или <code class="font-mono text-sm">7F20,6F46</code> (относительная цепочка FID).</p>
<ul class="list-disc list-inside text-sm space-y-1 mb-3"> <ul class="list-disc list-inside text-sm space-y-1 mb-3">
<li><strong>Источник списка</strong>: при подключённой карте приоритет у загруженного дерева файлового менеджера (имена карты и проверенное наличие; отсутствующие файлы скрываются). Без карты и для незагруженных ветвей используется поставляемый стандартный список &mdash; <code class="font-mono text-sm">uicc_files.json</code>, собранный из профилей/классов приложений pySim скриптом <code class="font-mono text-sm">pysim_simple_server/uicc_files.py</code> и проверяемый тестом. До запуска <strong>&laquo;Проверить все файлы&raquo;</strong> в файловом менеджере список соответствует спецификациям. Пользовательские файлы добавляются всегда.</li> <li><strong>Источник списка</strong>: при подключённой карте приоритет у загруженного дерева файлового менеджера (имена карты и проверенное наличие; отсутствующие файлы скрываются). Без карты и для незагруженных ветвей используется поставляемый стандартный список &mdash; <code class="font-mono text-sm">uicc_files.json</code>, собранный из профилей/классов приложений pySim скриптом <code class="font-mono text-sm">pysim_simple_server/uicc_files.py</code> и проверяемый тестом. До запуска <strong>&laquo;Проверить все файлы&raquo;</strong> в файловом менеджере список соответствует спецификациям. Пользовательские файлы добавляются всегда.</li>
<li><strong>Начало сессии</strong>: неявный текущий DF зависит от <em>TAR</em>, на который отправляется защищённый пакет &mdash; приложение UICC Shared File System RFM начинает с MF (TS 102 226 &sect;7.2), приложение ADF RFM &mdash; со своего ADF (&sect;7.3). По умолчанию помощник берёт MF для этого конструктора и ADF.USIM для USIM RFM (в соответствии с TAR пресетов); можно изменить для каждой строки.</li> <li><strong>Начало сессии</strong>: неявный текущий DF зависит от <em>TAR</em>, на который отправляется защищённый пакет &mdash; приложение UICC Shared File System RFM начинает с MF (TS 102 226 &sect;7.2), приложение ADF RFM &mdash; со своего ADF (&sect;7.3). По умолчанию помощник берёт MF для обоих конструкторов; можно изменить для каждой строки (выберите ADF для работы в сессии ADF).</li>
<li><strong>Path</strong> &mdash; последовательность FID от MF <em>без</em> идентификатора MF (ISO 7816-4: &laquo;select from the MF &mdash; path without the MF identifier&raquo;); вариант USIM <strong>from current DF</strong> использует относительный хвост. <strong>Chain</strong> остаётся относительным к текущему DF и следует порядку поиска FID из TS 102 221 &sect;11.1.1.2 (дети &rarr; родитель &rarr; соседи), поэтому переход к общему предку не нужен.</li> <li><strong>Path</strong> &mdash; последовательность FID от MF <em>без</em> идентификатора MF (ISO 7816-4: &laquo;select from the MF &mdash; path without the MF identifier&raquo;); вариант USIM <strong>from current DF</strong> использует относительный хвост. <strong>Chain</strong> остаётся относительным к текущему DF и следует порядку поиска FID из TS 102 221 &sect;11.1.1.2 (дети &rarr; родитель &rarr; соседи), поэтому переход к общему предку не нужен.</li>
<li>Корни ADF не выбираются: приложение выбирается по AID, и метод <strong>By AID</strong> остаётся ручным (TS 102 226 &sect;7.1 запрещает P1=<code class="font-mono text-sm">04</code> для RFM).</li> <li>Корни ADF не выбираются: приложение выбирается по AID, и метод <strong>By AID</strong> остаётся ручным (TS 102 226 &sect;7.1 запрещает P1=<code class="font-mono text-sm">04</code> для RFM).</li>
</ul> </ul>
+1 -1
View File
@@ -98,7 +98,7 @@
<p class="text-sm mb-2">Every SELECT row has a file picker below the method fields: a filter box, an <strong>all files</strong> toggle, the session start root with the current DF, and the file list grouped by root (<code class="font-mono text-sm">MF</code>, <code class="font-mono text-sm">ADF.USIM</code>, &hellip;). Picking a file fills the fields for the current method; when the method cannot express the selection the picker switches to one that can &mdash; preferring <strong>path</strong> (one SELECT), else <strong>chain</strong> &mdash; and says so in the note line, e.g. a file under another DF becomes <code class="font-mono text-sm">7F106F40</code> (path from MF) or <code class="font-mono text-sm">7F20,6F46</code> (relative FID chain).</p> <p class="text-sm mb-2">Every SELECT row has a file picker below the method fields: a filter box, an <strong>all files</strong> toggle, the session start root with the current DF, and the file list grouped by root (<code class="font-mono text-sm">MF</code>, <code class="font-mono text-sm">ADF.USIM</code>, &hellip;). Picking a file fills the fields for the current method; when the method cannot express the selection the picker switches to one that can &mdash; preferring <strong>path</strong> (one SELECT), else <strong>chain</strong> &mdash; and says so in the note line, e.g. a file under another DF becomes <code class="font-mono text-sm">7F106F40</code> (path from MF) or <code class="font-mono text-sm">7F20,6F46</code> (relative FID chain).</p>
<ul class="list-disc list-inside text-sm space-y-1 mb-3"> <ul class="list-disc list-inside text-sm space-y-1 mb-3">
<li><strong>List source</strong>: with a card equipped the loaded file-manager tree wins (card names and probed presence; probed-absent files are hidden). Without a card, or for branches the tree has not loaded, the shipped standard list is used &mdash; <code class="font-mono text-sm">uicc_files.json</code>, generated from pySim's profiles/application classes by <code class="font-mono text-sm">pysim_simple_server/uicc_files.py</code> and kept in sync by a test. The list is specs-default until you run <strong>Probe all files</strong> in the file manager. Custom files are always merged.</li> <li><strong>List source</strong>: with a card equipped the loaded file-manager tree wins (card names and probed presence; probed-absent files are hidden). Without a card, or for branches the tree has not loaded, the shipped standard list is used &mdash; <code class="font-mono text-sm">uicc_files.json</code>, generated from pySim's profiles/application classes by <code class="font-mono text-sm">pysim_simple_server/uicc_files.py</code> and kept in sync by a test. The list is specs-default until you run <strong>Probe all files</strong> in the file manager. Custom files are always merged.</li>
<li><strong>Session start</strong>: the implicit current DF depends on the <em>TAR</em> the secured packet is sent to &mdash; the UICC Shared File System RFM application starts in MF (TS 102 226 &sect;7.2), an ADF RFM application in its ADF (&sect;7.3). The picker defaults to MF for this builder and ADF.USIM for USIM RFM (matching the preset TARs) and can be changed per row.</li> <li><strong>Session start</strong>: the implicit current DF depends on the <em>TAR</em> the secured packet is sent to &mdash; the UICC Shared File System RFM application starts in MF (TS 102 226 &sect;7.2), an ADF RFM application in its ADF (&sect;7.3). The picker defaults to MF for both builders and can be changed per row (select the ADF to work in an ADF session).</li>
<li><strong>Path</strong> is the FID sequence from MF <em>without</em> the MF identifier (ISO 7816-4: &ldquo;select from the MF &mdash; path without the MF identifier&rdquo;); the USIM <strong>from current DF</strong> variant uses the relative tail. <strong>Chain</strong> stays relative to the current DF and follows the FID search order of TS 102 221 &sect;11.1.1.2 (children &rarr; parent &rarr; siblings), so it never needs a hop to the common ancestor itself.</li> <li><strong>Path</strong> is the FID sequence from MF <em>without</em> the MF identifier (ISO 7816-4: &ldquo;select from the MF &mdash; path without the MF identifier&rdquo;); the USIM <strong>from current DF</strong> variant uses the relative tail. <strong>Chain</strong> stays relative to the current DF and follows the FID search order of TS 102 221 &sect;11.1.1.2 (children &rarr; parent &rarr; siblings), so it never needs a hop to the common ancestor itself.</li>
<li>ADF roots are not pickable: an application is selected by AID, which the <strong>By AID</strong> method keeps manual (TS 102 226 &sect;7.1 forbids P1=<code class="font-mono text-sm">04</code> for RFM).</li> <li>ADF roots are not pickable: an application is selected by AID, which the <strong>By AID</strong> method keeps manual (TS 102 226 &sect;7.1 forbids P1=<code class="font-mono text-sm">04</code> for RFM).</li>
</ul> </ul>
+4 -1
View File
@@ -3311,7 +3311,10 @@ function rfmFileEntries() {
// packet is sent to, not on the builder, so the picker lets it be changed. // packet is sent to, not on the builder, so the picker lets it be changed.
function rfmStartDf(chainId) { function rfmStartDf(chainId) {
if (!_rfmStartDf[chainId]) { if (!_rfmStartDf[chainId]) {
_rfmStartDf[chainId] = chainKind(chainId) === 'usim' ? 'ADF.USIM' : 'MF'; // MF for both builders: the real implicit DF follows the TAR the
// secured packet is sent to (TS 102 226 7.2/7.3), so the picker
// starts neutral and the per-row selector covers ADF sessions.
_rfmStartDf[chainId] = 'MF';
} }
return _rfmStartDf[chainId]; return _rfmStartDf[chainId];
} }
+1 -1
View File
@@ -1,4 +1,4 @@
const CACHE = 'simple-v243'; const CACHE = 'simple-v244';
const URLS = [ const URLS = [
'index.html', 'index.html',
'help.html', 'help.html',
+10 -2
View File
@@ -112,8 +112,10 @@ test('rfmSelectFill prefers path when the method has to switch', () => {
assert.deepStrictEqual(fill, { method: 'path', fields: { path: '7F106F40', base: 'mf' }, switched: true }); assert.deepStrictEqual(fill, { method: 'path', fields: { path: '7F106F40', base: 'mf' }, switched: true });
// ADF entry cannot be reached from MF by FID/path/chain. // ADF entry cannot be reached from MF by FID/path/chain.
assert.strictEqual(rfmSelectFill('chain-sim', 0, entry('ADF.USIM/6F07'), rfmFileEntries()), null); assert.strictEqual(rfmSelectFill('chain-sim', 0, entry('ADF.USIM/6F07'), rfmFileEntries()), null);
// USIM RFM starts in ADF.USIM: its files are direct children, deep ones use // USIM RFM in an ADF session (the picker defaults to MF for both
// the relative path from the current DF. // builders, so the ADF context is selected explicitly): ADF files are
// direct children, deep ones use the relative path from the current DF.
rfmSetStartDf('chain-usim', 'ADF.USIM');
setChain('chain-usim', [row('select', { method: 'fid' })]); setChain('chain-usim', [row('select', { method: 'fid' })]);
fill = rfmSelectFill('chain-usim', 0, entry('ADF.USIM/6F07'), rfmFileEntries()); fill = rfmSelectFill('chain-usim', 0, entry('ADF.USIM/6F07'), rfmFileEntries());
assert.deepStrictEqual(fill, { method: 'fid', fields: { fid: '6F07' }, switched: false }); assert.deepStrictEqual(fill, { method: 'fid', fields: { fid: '6F07' }, switched: false });
@@ -131,6 +133,7 @@ test('rfmSelectFill falls back to chain when path cannot express it', () => {
// DF.GSM-ACCESS branch is not under the current DF and not in the MF tree, // DF.GSM-ACCESS branch is not under the current DF and not in the MF tree,
// so only the relative chain works. // so only the relative chain works.
const list = rfmFileEntries(); const list = rfmFileEntries();
rfmSetStartDf('chain-usim', 'ADF.USIM');
setChain('chain-usim', [row('select', { method: 'path', path: '5F3A', base: 'df' })]); setChain('chain-usim', [row('select', { method: 'path', path: '5F3A', base: 'df' })]);
const fill = rfmSelectFill('chain-usim', 1, entry('ADF.USIM/5F3B/4F20'), list); const fill = rfmSelectFill('chain-usim', 1, entry('ADF.USIM/5F3B/4F20'), list);
assert.strictEqual(fill.method, 'chain'); assert.strictEqual(fill.method, 'chain');
@@ -153,6 +156,10 @@ test('rfmCurrentDf tracks the session context across rows', () => {
assert.strictEqual(rfmCurrentDf('chain-sim', 2, list), 'MF/7F10'); assert.strictEqual(rfmCurrentDf('chain-sim', 2, list), 'MF/7F10');
// A path select sets the DF to the file's parent. // A path select sets the DF to the file's parent.
assert.strictEqual(rfmCurrentDf('chain-sim', 3, list), 'MF/7F10'); assert.strictEqual(rfmCurrentDf('chain-sim', 3, list), 'MF/7F10');
// The picker defaults to MF for both builders; an ADF session is explicit.
delete _rfmStartDf['chain-usim'];
assert.strictEqual(rfmStartDf('chain-usim'), 'MF');
rfmSetStartDf('chain-usim', 'ADF.USIM');
setChain('chain-usim', [ setChain('chain-usim', [
row('select', { method: 'path', path: '5F3A', base: 'df' }), row('select', { method: 'path', path: '5F3A', base: 'df' }),
row('select', { method: 'chain', chain: '4F22' }), row('select', { method: 'chain', chain: '4F22' }),
@@ -196,6 +203,7 @@ test('rfmFileEntries merges card tree, custom files and the standard list', () =
test('rfmFileOptionsHtml labels files with their path within the root', () => { test('rfmFileOptionsHtml labels files with their path within the root', () => {
const list = rfmFileEntries(); const list = rfmFileEntries();
rfmSetStartDf('chain-usim', 'ADF.USIM');
setChain('chain-usim', [row('select', { method: 'fid' })]); setChain('chain-usim', [row('select', { method: 'fid' })]);
const opts = rfmFileOptionsHtml('chain-usim', 0, list); const opts = rfmFileOptionsHtml('chain-usim', 0, list);
// ADF.USIM session: EF.IMSI is a direct child of the root. // ADF.USIM session: EF.IMSI is a direct child of the root.