feat: clean up the Explore UX (v3.6.45)
- Explore runs inline: no blocking modal (that stays for the install operations, which can leave a half-loaded package; Explore leaves the card consistent). A test guards that ramExplore never calls the modal. - Minimal success line: just OK - the details live in the explorer below; error runs keep the detailed 'Partial - ...' line. - Counts moved into the section headings (Applications / Applet Instances (n), Executable Load Files (ELFs) / Packages (n)); the redundant '1 ISD' count is gone (P1=80 returns the ISD as a single occurrence, GP 11.4.2.1). - The RAM command format line gained a tooltip: compact = TS 102 226 5.2.1 command string, expanded = the AA/22 scripting template (5.2.1.0), detected per operation with a read-only GET STATUS probe. - The expanded-registry checkbox is relabelled 'Fetch expanded registry details (load-file / SD associations)' with a tooltip (extra secured packets, card support varies, the fallback is automatic) and is now a sticky per-browser preference (simple_ram_expanded). sw cache simple-v318; tests: 531 Python / 681 Node.
This commit is contained in:
File diff suppressed because one or more lines are too long
+1
-1
@@ -319,7 +319,7 @@
|
|||||||
<table class="w-full text-sm mb-3 border-collapse">
|
<table class="w-full text-sm mb-3 border-collapse">
|
||||||
<thead><tr class="border-b border-gray-300 dark:border-slate-700"><th class="text-left py-1 px-2">Operation</th><th class="text-left py-1 px-2">Description</th></tr></thead>
|
<thead><tr class="border-b border-gray-300 dark:border-slate-700"><th class="text-left py-1 px-2">Operation</th><th class="text-left py-1 px-2">Description</th></tr></thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">Explore Card (all GP data)</td><td class="py-1 px-2">Queries GET STATUS for ISD, Applications, ELFs, and ELF Modules, plus GET DATA FF21 (Extended Card Resources: the number of installed applications and the free non-volatile/volatile memory). If a card rejects the compact listing (<code class="font-mono text-sm">P2.b2=0</code>, deprecated by GP) the queries are retried in the expanded <code class="font-mono text-sm">E3</code> form; the <strong>Query expanded registry details (E3)</strong> checkbox also requests it as an extra pass and merges the expanded-only fields (privileges, ELF/SD associations, module lists). Results appear in an explorer view with per-item <strong>Delete</strong> buttons and the detected RAM command format.</td></tr>
|
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">Explore Card (all GP data)</td><td class="py-1 px-2">Queries GET STATUS for ISD, Applications, ELFs, and ELF Modules, plus GET DATA FF21 (Extended Card Resources: the number of installed applications and the free non-volatile/volatile memory). If a card rejects the compact listing (<code class="font-mono text-sm">P2.b2=0</code>, deprecated by GP) the queries are retried in the expanded <code class="font-mono text-sm">E3</code> form; the <strong>Fetch expanded registry details (load-file / SD associations)</strong> checkbox also requests it as an extra pass and merges the expanded-only fields (Load File AID, Security Domain AID, module lists) — it costs extra secured packets and some cards reject the expanded query, so it is off by default and remembered per browser. Results appear in an explorer view (the success line stays minimal; the counts are in the section headings) with per-item <strong>Delete</strong> buttons and the detected RAM command format (hover for what compact vs expanded means).</td></tr>
|
||||||
<tr><td class="py-1 px-2">Install Package (.cap file)</td><td class="py-1 px-2">Sends a <code class="font-mono text-sm">.cap</code> file to the card via the server: INSTALL[for load] → LOAD ×N → INSTALL[for install (+make selectable)]. The load file is split into LOAD APDUs of the <strong>LOAD block size</strong> (1–240 bytes of payload, 240 by default); each secured packet is delivered as a single SMS or, when larger, as a concatenated SMS-PP download of up to 5 segments, so a large <code class="font-mono text-sm">.cap</code> simply takes several SMS. As soon as the file is selected it is validated and its <strong>memory requirements are estimated</strong> in the form: the <strong>NVRAM requirement</strong> (the code image + persistent data, the GlobalPlatform Card Spec C6+C8 style total) and the RAM estimate. The same box reports the <strong>libraries the CAP is linked against</strong> (its Import component: library name, AID and the minimum version <code class="font-mono text-sm">≥ x.y</code>, with standard names and families resolved and a Java Card SDK hint where known), the package/applet identity and the component breakdown (sizes and shares in load-file order) — grouped under the <strong>Package</strong>, <strong>Requires</strong>, <strong>Memory</strong> and <strong>Components</strong> headings. The <strong>Platform</strong> line names the minimum Java Card level the card must provide (derived from the <code class="font-mono text-sm">javacard.framework</code> import; the header <code class="font-mono text-sm">int</code> flag additionally requires int support, Java Card 2.2+) and the <strong>ETSI release</strong> the UICC API imports come from (<code class="font-mono text-sm">uicc.toolkit</code> version → REL-N, per the workspace <code class="font-mono text-sm">sim-tools</code> corpus; shown with its basis in brackets): the JCRE checks every import against its own packages when it verifies the load file (JC VM spec 4.5.2), so a card whose platform is older rejects the LOAD as soon as the <strong>Import</strong> component is complete (the step line carries the card's remote SW and names the component the block completed, e.g. <em>completes Import</em>) — a smaller LOAD block only helps when the block exceeds the card's buffer. The <strong>Import probe</strong> fieldset (diagnostic) rewrites the CAP's requested import versions before the load — all entries to 0.0, or one at a time: since the card checks that list while it verifies the load file, this shows whether it is the rejection cause and, by bisection, which package and version the card lacks. Only the two version bytes per entry change (the load file length, the component sizes and every offset stay untouched), the probe is never used for a real install, and the applied changes are reported in the result line and the server log. Two-step use: press <strong>Set all 0.0</strong> and run the install — if the LOAD now passes, the card was refusing the import list; then put one line back to its CAP value at a time (e.g. <code class="font-mono text-sm">A0000000620101=1.3</code>) and retry: the line that makes it fail again names the package the card cannot provide at that version. A corrupt or wrong-format file fails the analysis, and <strong>Execute</strong> stays disabled until a successful analysis. The estimate is informational only and is never used for installation: NVRAM is the code image plus the persistent data (the GlobalPlatform C6+C8 style total, Table 11-48 — card memory management, rounding and the registry entry are not included, and the static field image is counted in both parts); the suggested <strong>C6</strong> follows the load file, and the suggested quotas are decimal byte counts (the hex in parentheses is how the C7/C8 install parameters encode them: C6 = non-volatile code, C7 = volatile RAM, C8 = non-volatile data).</td></tr>
|
<tr><td class="py-1 px-2">Install Package (.cap file)</td><td class="py-1 px-2">Sends a <code class="font-mono text-sm">.cap</code> file to the card via the server: INSTALL[for load] → LOAD ×N → INSTALL[for install (+make selectable)]. The load file is split into LOAD APDUs of the <strong>LOAD block size</strong> (1–240 bytes of payload, 240 by default); each secured packet is delivered as a single SMS or, when larger, as a concatenated SMS-PP download of up to 5 segments, so a large <code class="font-mono text-sm">.cap</code> simply takes several SMS. As soon as the file is selected it is validated and its <strong>memory requirements are estimated</strong> in the form: the <strong>NVRAM requirement</strong> (the code image + persistent data, the GlobalPlatform Card Spec C6+C8 style total) and the RAM estimate. The same box reports the <strong>libraries the CAP is linked against</strong> (its Import component: library name, AID and the minimum version <code class="font-mono text-sm">≥ x.y</code>, with standard names and families resolved and a Java Card SDK hint where known), the package/applet identity and the component breakdown (sizes and shares in load-file order) — grouped under the <strong>Package</strong>, <strong>Requires</strong>, <strong>Memory</strong> and <strong>Components</strong> headings. The <strong>Platform</strong> line names the minimum Java Card level the card must provide (derived from the <code class="font-mono text-sm">javacard.framework</code> import; the header <code class="font-mono text-sm">int</code> flag additionally requires int support, Java Card 2.2+) and the <strong>ETSI release</strong> the UICC API imports come from (<code class="font-mono text-sm">uicc.toolkit</code> version → REL-N, per the workspace <code class="font-mono text-sm">sim-tools</code> corpus; shown with its basis in brackets): the JCRE checks every import against its own packages when it verifies the load file (JC VM spec 4.5.2), so a card whose platform is older rejects the LOAD as soon as the <strong>Import</strong> component is complete (the step line carries the card's remote SW and names the component the block completed, e.g. <em>completes Import</em>) — a smaller LOAD block only helps when the block exceeds the card's buffer. The <strong>Import probe</strong> fieldset (diagnostic) rewrites the CAP's requested import versions before the load — all entries to 0.0, or one at a time: since the card checks that list while it verifies the load file, this shows whether it is the rejection cause and, by bisection, which package and version the card lacks. Only the two version bytes per entry change (the load file length, the component sizes and every offset stay untouched), the probe is never used for a real install, and the applied changes are reported in the result line and the server log. Two-step use: press <strong>Set all 0.0</strong> and run the install — if the LOAD now passes, the card was refusing the import list; then put one line back to its CAP value at a time (e.g. <code class="font-mono text-sm">A0000000620101=1.3</code>) and retry: the line that makes it fail again names the package the card cannot provide at that version. A corrupt or wrong-format file fails the analysis, and <strong>Execute</strong> stays disabled until a successful analysis. The estimate is informational only and is never used for installation: NVRAM is the code image plus the persistent data (the GlobalPlatform C6+C8 style total, Table 11-48 — card memory management, rounding and the registry entry are not included, and the static field image is counted in both parts); the suggested <strong>C6</strong> follows the load file, and the suggested quotas are decimal byte counts (the hex in parentheses is how the C7/C8 install parameters encode them: C6 = non-volatile code, C7 = volatile RAM, C8 = non-volatile data).</td></tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
+30
-13
@@ -703,7 +703,7 @@
|
|||||||
<button data-needs="card" data-cap-gate="ram" onclick="ramExecute()" class="px-5 py-1.5 bg-blue-600 text-white text-sm font-medium rounded hover:bg-blue-700 disabled:opacity-40 disabled:cursor-not-allowed" data-l10n="Execute">Execute</button>
|
<button data-needs="card" data-cap-gate="ram" onclick="ramExecute()" class="px-5 py-1.5 bg-blue-600 text-white text-sm font-medium rounded hover:bg-blue-700 disabled:opacity-40 disabled:cursor-not-allowed" data-l10n="Execute">Execute</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<label class="flex items-center gap-1 mb-3 text-sm text-gray-700 dark:text-slate-300"><input type="checkbox" id="ram-expanded-details" class="rounded border-gray-300 dark:border-slate-600"> <span data-l10n="Query expanded registry details (E3)">Query expanded registry details (E3)</span></label>
|
<label class="flex items-center gap-1 mb-3 text-sm text-gray-700 dark:text-slate-300" data-l10n-title="Runs one extra expanded query per listing (P2=02, tag list 4F 9F70 C5 C4 CC CE EA). The compact listing carries AID/lifecycle/privileges/version only; the expanded pass adds the Load File AID, Security Domain AID and module lists. It costs extra secured packets and some cards reject it - the Explore already uses it automatically when the compact listing returns nothing."><input type="checkbox" id="ram-expanded-details" class="rounded border-gray-300 dark:border-slate-600" onchange="ramExpandedDetailsChanged()"> <span data-l10n="Fetch expanded registry details (load-file / SD associations)">Fetch expanded registry details (load-file / SD associations)</span></label>
|
||||||
|
|
||||||
<div id="ram-install-params" class="hidden mb-3">
|
<div id="ram-install-params" class="hidden mb-3">
|
||||||
<div id="ram-cap-rows">
|
<div id="ram-cap-rows">
|
||||||
@@ -1747,7 +1747,7 @@
|
|||||||
// ===== Version =====
|
// ===== Version =====
|
||||||
// Single source of truth for the PWA version: shown in the header and used
|
// Single source of truth for the PWA version: shown in the header and used
|
||||||
// by the server version check in pysimConnect().
|
// by the server version check in pysimConnect().
|
||||||
const SIMPLE_VERSION = '3.6.44';
|
const SIMPLE_VERSION = '3.6.45';
|
||||||
document.getElementById('app-version').textContent = 'v' + SIMPLE_VERSION;
|
document.getElementById('app-version').textContent = 'v' + SIMPLE_VERSION;
|
||||||
|
|
||||||
// ===== Tab switching =====
|
// ===== Tab switching =====
|
||||||
@@ -8262,6 +8262,23 @@ function ramRender() {
|
|||||||
});
|
});
|
||||||
if (keep !== null && keep !== undefined && cards[keep]) sel.value = String(keep);
|
if (keep !== null && keep !== undefined && cards[keep]) sel.value = String(keep);
|
||||||
ramOpChanged();
|
ramOpChanged();
|
||||||
|
ramExpandedDetailsInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// The "Fetch expanded registry details" checkbox is a sticky preference: the
|
||||||
|
// expanded query costs extra secured packets and not every card accepts it,
|
||||||
|
// so it stays off unless the user asked for it (stored per browser).
|
||||||
|
function ramExpandedDetailsInit() {
|
||||||
|
const el = document.getElementById('ram-expanded-details');
|
||||||
|
if (!el) return;
|
||||||
|
let v = null;
|
||||||
|
try { v = localStorage.getItem('simple_ram_expanded'); } catch (e) { /* private mode */ }
|
||||||
|
if (v !== null) el.checked = v === '1';
|
||||||
|
}
|
||||||
|
|
||||||
|
function ramExpandedDetailsChanged() {
|
||||||
|
const el = document.getElementById('ram-expanded-details');
|
||||||
|
try { localStorage.setItem('simple_ram_expanded', el && el.checked ? '1' : '0'); } catch (e) { /* ignore */ }
|
||||||
}
|
}
|
||||||
|
|
||||||
function ramApplyCard(idx) {
|
function ramApplyCard(idx) {
|
||||||
@@ -9003,7 +9020,10 @@ function ramRenderExploreHtml(mem, isd, apps, elfs, fmt) {
|
|||||||
html += '<div>' + esc(t('Applications:')) + ' ' + (mem.appCount != null ? mem.appCount : '?') + '</div>';
|
html += '<div>' + esc(t('Applications:')) + ' ' + (mem.appCount != null ? mem.appCount : '?') + '</div>';
|
||||||
html += '<div>' + esc(t('Free NV:')) + ' ' + (mem.freeNV != null ? mem.freeNV + ' B' : '?') + '</div>';
|
html += '<div>' + esc(t('Free NV:')) + ' ' + (mem.freeNV != null ? mem.freeNV + ' B' : '?') + '</div>';
|
||||||
html += '<div>' + esc(t('Free Volatile:')) + ' ' + (mem.freeV != null ? mem.freeV + ' B' : '?') + '</div>';
|
html += '<div>' + esc(t('Free Volatile:')) + ' ' + (mem.freeV != null ? mem.freeV + ' B' : '?') + '</div>';
|
||||||
if (fmt) html += '<div>' + esc(t('RAM command format:')) + ' ' + esc(fmt) + '</div>';
|
if (fmt) {
|
||||||
|
html += '<div title="' + esc(t('compact = the TS 102 226 5.2.1 command string (one C-APDU per secured packet, e.g. GET STATUS + GET RESPONSE); expanded = the AA/22 Command Scripting template (5.2.1.0). Detected per operation with a read-only GET STATUS probe; a card that rejects the deprecated compact P2.b2=0 form answers the expanded one.')) + '">' +
|
||||||
|
esc(t('RAM command format:')) + ' ' + esc(fmt) + '</div>';
|
||||||
|
}
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
}
|
}
|
||||||
if (isd && isd.length) {
|
if (isd && isd.length) {
|
||||||
@@ -9021,7 +9041,7 @@ function ramRenderExploreHtml(mem, isd, apps, elfs, fmt) {
|
|||||||
}
|
}
|
||||||
if (apps && apps.length) {
|
if (apps && apps.length) {
|
||||||
html += '<div class="mb-4">';
|
html += '<div class="mb-4">';
|
||||||
html += '<div class="font-semibold text-sm mb-1">' + esc(t('Applications / Applet Instances')) + '</div>';
|
html += '<div class="font-semibold text-sm mb-1">' + esc(t('Applications / Applet Instances')) + ' (' + apps.length + ')</div>';
|
||||||
apps.forEach(o => {
|
apps.forEach(o => {
|
||||||
html += '<div class="mb-1 pl-2 pr-2 py-1 rounded bg-gray-50 dark:bg-slate-800/60 hover:bg-gray-100 dark:hover:bg-slate-700/50 border-l-2 border-green-400 flex items-start gap-3">';
|
html += '<div class="mb-1 pl-2 pr-2 py-1 rounded bg-gray-50 dark:bg-slate-800/60 hover:bg-gray-100 dark:hover:bg-slate-700/50 border-l-2 border-green-400 flex items-start gap-3">';
|
||||||
html += '<div class="flex-1 min-w-0">';
|
html += '<div class="flex-1 min-w-0">';
|
||||||
@@ -9045,7 +9065,7 @@ function ramRenderExploreHtml(mem, isd, apps, elfs, fmt) {
|
|||||||
}
|
}
|
||||||
if (elfs && elfs.length) {
|
if (elfs && elfs.length) {
|
||||||
html += '<div class="mb-4">';
|
html += '<div class="mb-4">';
|
||||||
html += '<div class="font-semibold text-sm mb-1">' + esc(t('Executable Load Files (ELFs) / Packages')) + '</div>';
|
html += '<div class="font-semibold text-sm mb-1">' + esc(t('Executable Load Files (ELFs) / Packages')) + ' (' + elfs.length + ')</div>';
|
||||||
elfs.forEach(o => {
|
elfs.forEach(o => {
|
||||||
html += '<div class="mb-1 pl-2 pr-2 py-1 rounded bg-gray-50 dark:bg-slate-800/60 hover:bg-gray-100 dark:hover:bg-slate-700/50 border-l-2 border-purple-400 flex items-start gap-3">';
|
html += '<div class="mb-1 pl-2 pr-2 py-1 rounded bg-gray-50 dark:bg-slate-800/60 hover:bg-gray-100 dark:hover:bg-slate-700/50 border-l-2 border-purple-400 flex items-start gap-3">';
|
||||||
html += '<div class="flex-1 min-w-0">';
|
html += '<div class="flex-1 min-w-0">';
|
||||||
@@ -9107,8 +9127,6 @@ async function ramExplore(sp) {
|
|||||||
const mem = { appCount: null, freeNV: null, freeV: null };
|
const mem = { appCount: null, freeNV: null, freeV: null };
|
||||||
const isd = [], apps = [], elfs = [];
|
const isd = [], apps = [], elfs = [];
|
||||||
|
|
||||||
ramOpModalBegin(t('Explore Card (all GP data)'));
|
|
||||||
|
|
||||||
async function paginate(p1, collector, parser, label, quiet) {
|
async function paginate(p1, collector, parser, label, quiet) {
|
||||||
// Compact listing format (GP 11.4.2.2: P2.b2=0) with the chained GET
|
// Compact listing format (GP 11.4.2.2: P2.b2=0) with the chained GET
|
||||||
// RESPONSE - see ramGetStatusApdu(). The card's SCP80 layer runs both
|
// RESPONSE - see ramGetStatusApdu(). The card's SCP80 layer runs both
|
||||||
@@ -9122,7 +9140,6 @@ async function ramExplore(sp) {
|
|||||||
while (guard++ < 32) {
|
while (guard++ < 32) {
|
||||||
const apdu = ramGetStatusApdu(p1, p2);
|
const apdu = ramGetStatusApdu(p1, p2);
|
||||||
ramShowProgress(label + ' P1=' + p1 + ' P2=' + p2 + '...');
|
ramShowProgress(label + ' P1=' + p1 + ' P2=' + p2 + '...');
|
||||||
ramOpModalStatus(label + ' P1=' + p1 + ' P2=' + p2);
|
|
||||||
const res = await ramSendOta(apdu, Object.assign({}, sp, { cntr, spi2 }));
|
const res = await ramSendOta(apdu, Object.assign({}, sp, { cntr, spi2 }));
|
||||||
// Reuse the format detected for the first packet of this run
|
// Reuse the format detected for the first packet of this run
|
||||||
if (res.ram_format) sp.ram_format = res.ram_format;
|
if (res.ram_format) sp.ram_format = res.ram_format;
|
||||||
@@ -9173,7 +9190,7 @@ async function ramExplore(sp) {
|
|||||||
// Expanded pass: the fallback when the compact listing produced
|
// Expanded pass: the fallback when the compact listing produced
|
||||||
// nothing (a card may reject P2.b2=0 - it is deprecated), and the
|
// nothing (a card may reject P2.b2=0 - it is deprecated), and the
|
||||||
// optional details source (privileges, ELF/SD associations) behind the
|
// optional details source (privileges, ELF/SD associations) behind the
|
||||||
// "Query expanded registry details (E3)" checkbox.
|
// "Fetch expanded registry details" checkbox.
|
||||||
const wantDetails = !!(document.getElementById('ram-expanded-details') || {}).checked;
|
const wantDetails = !!(document.getElementById('ram-expanded-details') || {}).checked;
|
||||||
if (collector.length === before || wantDetails) {
|
if (collector.length === before || wantDetails) {
|
||||||
ramShowProgress(label + ' P1=' + p1 + ' P2=02 (expanded)...');
|
ramShowProgress(label + ' P1=' + p1 + ' P2=02 (expanded)...');
|
||||||
@@ -9207,7 +9224,6 @@ async function ramExplore(sp) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ramShowProgress(t('Card resources (GET DATA FF21)') + '...');
|
ramShowProgress(t('Card resources (GET DATA FF21)') + '...');
|
||||||
ramOpModalStatus(t('Card resources (GET DATA FF21)'));
|
|
||||||
try {
|
try {
|
||||||
const memRes = await ramSendOta('80CAFF2100', Object.assign({}, sp, { spi2: '01' }));
|
const memRes = await ramSendOta('80CAFF2100', Object.assign({}, sp, { spi2: '01' }));
|
||||||
if (memRes.ram_format) sp.ram_format = memRes.ram_format;
|
if (memRes.ram_format) sp.ram_format = memRes.ram_format;
|
||||||
@@ -9257,13 +9273,12 @@ async function ramExplore(sp) {
|
|||||||
stepsEl.classList.remove('hidden');
|
stepsEl.classList.remove('hidden');
|
||||||
stepsEl.textContent = errors.join('\n');
|
stepsEl.textContent = errors.join('\n');
|
||||||
} else {
|
} else {
|
||||||
resultEl.textContent = t('OK') + ' — ' + isd.length + ' ' + t('ISD') + ', ' + apps.length + ' ' + t('Apps') + ', ' + elfs.length + ' ' + t('ELFs') + (mem.freeNV ? ', ' + mem.freeNV + ' ' + t('free NV') : '') + (sp.ram_format ? ' — ' + t('RAM command format:') + ' ' + sp.ram_format : '');
|
resultEl.textContent = t('OK');
|
||||||
resultEl.classList.remove('hidden', 'text-red-600'); resultEl.classList.add('text-green-600');
|
resultEl.classList.remove('hidden', 'text-red-600'); resultEl.classList.add('text-green-600');
|
||||||
}
|
}
|
||||||
|
|
||||||
_ramExplorerData = { mem: mem, isd: isd, apps: apps, elfs: elfs, fmt: sp.ram_format || '' };
|
_ramExplorerData = { mem: mem, isd: isd, apps: apps, elfs: elfs, fmt: sp.ram_format || '' };
|
||||||
ramRenderExplorer();
|
ramRenderExplorer();
|
||||||
ramOpModalFinish(resultEl.textContent, errors.length === 0, errors.join('\n'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GP DELETE (Card Spec v2.3.1 11.2, Tables 11-20/11-23): P1=00 (last/only
|
// GP DELETE (Card Spec v2.3.1 11.2, Tables 11-20/11-23): P1=00 (last/only
|
||||||
@@ -18067,7 +18082,9 @@ const LANG_RU = {
|
|||||||
'KIc and KID are required': 'Укажите KIc и KID',
|
'KIc and KID are required': 'Укажите KIc и KID',
|
||||||
'KIc key and KID key are required': 'Укажите ключ KIc и ключ KID',
|
'KIc key and KID key are required': 'Укажите ключ KIc и ключ KID',
|
||||||
'RAM command format:': 'Формат команд RAM:',
|
'RAM command format:': 'Формат команд RAM:',
|
||||||
'Query expanded registry details (E3)': 'Запрашивать расширенные данные реестра (E3)',
|
'Fetch expanded registry details (load-file / SD associations)': 'Запрашивать расширенные данные реестра (связи load-файла и SD)',
|
||||||
|
'Runs one extra expanded query per listing (P2=02, tag list 4F 9F70 C5 C4 CC CE EA). The compact listing carries AID/lifecycle/privileges/version only; the expanded pass adds the Load File AID, Security Domain AID and module lists. It costs extra secured packets and some cards reject it - the Explore already uses it automatically when the compact listing returns nothing.': 'Запускает дополнительный расширенный запрос для каждого списка (P2=02, список тегов 4F 9F70 C5 C4 CC CE EA). Компактный список содержит только AID/состояние/привилегии/версию; расширенный проход добавляет AID load-файла, AID Security Domain и списки модулей. Он расходует дополнительные защищённые пакеты, и не все карты его поддерживают — Explore и так применяет его автоматически, когда компактный список ничего не вернул.',
|
||||||
|
'compact = the TS 102 226 5.2.1 command string (one C-APDU per secured packet, e.g. GET STATUS + GET RESPONSE); expanded = the AA/22 Command Scripting template (5.2.1.0). Detected per operation with a read-only GET STATUS probe; a card that rejects the deprecated compact P2.b2=0 form answers the expanded one.': 'compact = командная строка по TS 102 226 5.2.1 (один C-APDU на защищённый пакет, например GET STATUS + GET RESPONSE); expanded = шаблон Command Scripting AA/22 (5.2.1.0). Определяется для каждой операции пробным чтением GET STATUS; карта, отклоняющая устаревшую компактную форму P2.b2=0, отвечает в расширенной.',
|
||||||
'Card resources (GET DATA FF21)': 'Ресурсы карты (GET DATA FF21)',
|
'Card resources (GET DATA FF21)': 'Ресурсы карты (GET DATA FF21)',
|
||||||
'Extended Card Resources (GP tag FF21, ETSI TS 102 226 8.2.1.7.2): installed applications, free non-volatile and free volatile memory': 'Расширенные ресурсы карты (тег GP FF21, ETSI TS 102 226 8.2.1.7.2): число установленных приложений, свободная энергонезависимая и свободная энергозависимая память',
|
'Extended Card Resources (GP tag FF21, ETSI TS 102 226 8.2.1.7.2): installed applications, free non-volatile and free volatile memory': 'Расширенные ресурсы карты (тег GP FF21, ETSI TS 102 226 8.2.1.7.2): число установленных приложений, свободная энергонезависимая и свободная энергозависимая память',
|
||||||
'No secured packet to send. Generate a secure packet first.': 'Нет защищённого пакета для отправки. Сначала соберите пакет.',
|
'No secured packet to send. Generate a secure packet first.': 'Нет защищённого пакета для отправки. Сначала соберите пакет.',
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
const CACHE = 'simple-v317';
|
const CACHE = 'simple-v318';
|
||||||
const URLS = [
|
const URLS = [
|
||||||
'index.html',
|
'index.html',
|
||||||
'help.html',
|
'help.html',
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ function extractFunc(src, name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Extract chain builder functions and dependencies
|
// Extract chain builder functions and dependencies
|
||||||
const FNS = ['berLenStr', 'buildApdu', 'escHtml', 'esc', 'chainInit', 'chainRamBuildRowHex', 'ramFmtLifecycle', 'ramFmtPrivileges', 'ramRenderExploreHtml', 'ramStepLine', 'ramStepComponents', 'ramInstallFailHint', 'ramProbeParse', 'ramGetStatusApdu', 'ramDeleteApdu',
|
const FNS = ['berLenStr', 'buildApdu', 'escHtml', 'esc', 'chainInit', 'chainRamBuildRowHex', 'ramFmtLifecycle', 'ramFmtPrivileges', 'ramRenderExploreHtml', 'ramStepLine', 'ramStepComponents', 'ramInstallFailHint', 'ramProbeParse', 'ramExpandedDetailsInit', 'ramExpandedDetailsChanged', 'ramGetStatusApdu', 'ramDeleteApdu',
|
||||||
'stkParamsBuild', 'ramRemoteSwOk', 'spPorAccepted', 'ramIncrementCntr', 'ramDeleteFromExplorer', 'ramListingSpi2', 'ramRemoveFromExplorer', 'ramHasInstance', 'ramExpandedQueryApdu',
|
'stkParamsBuild', 'ramRemoteSwOk', 'spPorAccepted', 'ramIncrementCntr', 'ramDeleteFromExplorer', 'ramListingSpi2', 'ramRemoveFromExplorer', 'ramHasInstance', 'ramExpandedQueryApdu',
|
||||||
'_parseRawElfEntry', '_parseRawAppEntry', 'ramParseElfStatus', 'ramParseAppStatus', 'parseTLV', '_parseE3Entry',
|
'_parseRawElfEntry', '_parseRawAppEntry', 'ramParseElfStatus', 'ramParseAppStatus', 'parseTLV', '_parseE3Entry',
|
||||||
'ramCardIdxAfterRemove', 'ramClearResults', 'ramHideProgress', 'ramOpChanged', 'ramRender', 'ramApplyCard', 'ramExecute', 'decodePrivileges', 'ramActionBtn', 'ramCapToolkitMode', 'ramOpProgressText',
|
'ramCardIdxAfterRemove', 'ramClearResults', 'ramHideProgress', 'ramOpChanged', 'ramRender', 'ramApplyCard', 'ramExecute', 'decodePrivileges', 'ramActionBtn', 'ramCapToolkitMode', 'ramOpProgressText',
|
||||||
@@ -788,3 +788,49 @@ test('ramProbeParse reads AID=version lines', () => {
|
|||||||
assert.ok(ramProbeParse('').error);
|
assert.ok(ramProbeParse('').error);
|
||||||
assert.ok(ramProbeParse(' \n# only comments\n').error);
|
assert.ok(ramProbeParse(' \n# only comments\n').error);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('ramRenderExploreHtml counts apps and ELFs in the section headings', () => {
|
||||||
|
global.t = s => s;
|
||||||
|
const out = ramRenderExploreHtml(null,
|
||||||
|
[{ aid: 'A1', lifecycle: '07' }],
|
||||||
|
[{ aid: 'A2', lifecycle: '07' }],
|
||||||
|
[{ aid: 'E1', lifecycle: '01', moduleAids: [] }]);
|
||||||
|
delete global.t;
|
||||||
|
assert.ok(out.includes('Applications / Applet Instances (1)'), out);
|
||||||
|
assert.ok(out.includes('Executable Load Files (ELFs) / Packages (1)'), out);
|
||||||
|
// the ISD is a single occurrence (GP 11.4.2.1): no count in its heading
|
||||||
|
assert.ok(out.includes('ISD (Issuer Security Domain)'), out);
|
||||||
|
assert.ok(!out.includes('ISD (Issuer Security Domain) ('), out);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('the RAM command format line explains compact vs expanded', () => {
|
||||||
|
global.t = s => s;
|
||||||
|
const out = ramRenderExploreHtml({ appCount: 1, freeNV: 1, freeV: 1 }, [], [], [], 'compact');
|
||||||
|
delete global.t;
|
||||||
|
assert.ok(out.includes('title="compact = the TS 102 226 5.2.1 command string'), out);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('ramExplore runs inline, without the blocking modal', () => {
|
||||||
|
const src = extractFunc(html, 'ramExplore');
|
||||||
|
assert.ok(!/ramOpModal(Begin|Finish|Status)/.test(src),
|
||||||
|
'Explore must not use the RAM modal (installs only)');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('the expanded-details checkbox is a sticky preference', () => {
|
||||||
|
const els = fakeRamDocument(['ram-expanded-details']);
|
||||||
|
const store = {};
|
||||||
|
globalThis.localStorage = {
|
||||||
|
getItem: k => (k in store ? store[k] : null),
|
||||||
|
setItem: (k, v) => { store[k] = String(v); },
|
||||||
|
};
|
||||||
|
els['ram-expanded-details'].checked = false;
|
||||||
|
ramExpandedDetailsInit();
|
||||||
|
assert.strictEqual(els['ram-expanded-details'].checked, false); // default: off
|
||||||
|
store['simple_ram_expanded'] = '1';
|
||||||
|
ramExpandedDetailsInit();
|
||||||
|
assert.strictEqual(els['ram-expanded-details'].checked, true); // stored choice applied
|
||||||
|
els['ram-expanded-details'].checked = false;
|
||||||
|
ramExpandedDetailsChanged();
|
||||||
|
assert.strictEqual(store['simple_ram_expanded'], '0'); // ticking stores it
|
||||||
|
delete globalThis.localStorage;
|
||||||
|
});
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "pysim-simple-server"
|
name = "pysim-simple-server"
|
||||||
version = "3.6.44"
|
version = "3.6.45"
|
||||||
description = "HTTP REST server wrapping pysim for the SIMple PWA"
|
description = "HTTP REST server wrapping pysim for the SIMple PWA"
|
||||||
requires-python = ">=3.8"
|
requires-python = ">=3.8"
|
||||||
# pysim is a git-only dependency installed explicitly by setup.bat/setup.sh.
|
# pysim is a git-only dependency installed explicitly by setup.bat/setup.sh.
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ from osmocom.tlv import BER_TLV_IE
|
|||||||
from osmocom.utils import rpad
|
from osmocom.utils import rpad
|
||||||
|
|
||||||
|
|
||||||
VERSION = '3.6.44'
|
VERSION = '3.6.45'
|
||||||
|
|
||||||
MAX_ENVELOPE_SEGMENTS = 5 # max SMS segments for outgoing C-APDU in ENVELOPE
|
MAX_ENVELOPE_SEGMENTS = 5 # max SMS segments for outgoing C-APDU in ENVELOPE
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user