batch delete: report an already-absent object as such

A delete run whose DELETE answered 6A88/6A82 is still a success (the
object is gone, the goal is met) but it is no longer reported as a plain
"OK": the attempt result is 'already_absent', the counts gain that
bucket ("Deleted: N - Already absent: M"), the verdict reads "Already
absent" and the notice says the card was already absent.  A reinstall's
tolerated pre-delete keeps the install outcome (the install is the
point).

1024 Python + 1063 frontend; simple-v471.
This commit is contained in:
2026-10-23 21:23:55 +03:00
parent fb65644328
commit 110dc1f1ad
8 changed files with 108 additions and 10 deletions
+1 -1
View File
@@ -324,7 +324,7 @@
<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] &rarr; LOAD &times;N &rarr; INSTALL[for install (+make selectable)]. The load file is split into LOAD APDUs of the <strong>LOAD block size</strong> (1&ndash;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) &mdash; 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 &rarr; 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>): the failure hint and the popup then point at the <strong>CAP compatibility test</strong> (one click &mdash; the same <code class="font-mono text-sm">.cap</code> is still selected) to find the missing package and version; a smaller LOAD block only helps when the block exceeds the card's buffer. 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 &mdash; 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). The <strong>Delete the package before installing (with its applications)</strong> checkbox prepends a cascade GP <code class="font-mono text-sm">DELETE</code> on the package AID (the load file with its modules and applications, P2=<code class="font-mono text-sm">0x80</code>) &mdash; a leftover package blocks INSTALL[for load]; 'not found' (a fresh card) proceeds, any other delete failure stops the chain with its reason.</td></tr>
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">Batch install (.cap file, per card)</td><td class="py-1 px-2">The bulk workflow: one <code class="font-mono text-sm">.cap</code> and one set of install parameters, applied to card after card. <strong>Start batch</strong> needs no card &mdash; the server owns the loop: it waits for a card, installs the moment the equip finishes, then waits for the next one. Every card's <strong>preset is matched by ICCID</strong> and supplies the keyset (the ISD role TAR's default, v3.26.0), the keys and the counter; a card with no matching preset or no usable ISD keyset is reported and skipped. Each attempt lands in the list with its time, ICCID, preset, verdict and duration; a failure shows the failing step and the remote status word &mdash; the batch never retries and never stops on a failure (failures are yours to manage afterwards). A card is attempted <strong>once per run</strong>: re-equipping it reports &ldquo;already processed&rdquo; &mdash; restart the batch to retry it. <strong>Stop</strong> finishes the current card first (an interrupted LOAD chain can leave a half-loaded package) and then ends the run; <strong>Clear</strong> drops the finished report. The loop runs in the server, so closing the tab, switching views or reloading the page does not interrupt it; a server restart ends it. A batch and a test run exclude each other. The batch shares the install form, so the <strong>Delete the package before installing</strong> option applies to every card.</td></tr>
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">Batch reinstall app (per card)</td><td class="py-1 px-2">The repair workflow: for every equipped card, delete the applet instance (tolerating 'not found') and run INSTALL [for install] again from the already loaded package &mdash; no <code class="font-mono text-sm">.cap</code> and no LOAD. The fields are the single INSTALL [for install] parameters (Load File / Module / Instance AIDs, privileges, the toolkit/STK parameters, <em>make selectable</em>); the preset, keyset and counter come from each card's own preset like the other batch operations, and the attempts list shows both verdicts (delete and install).</td></tr>
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">Batch delete (per card)</td><td class="py-1 px-2">Deletes one object on every equipped card: an application (instance only, P2=<code class="font-mono text-sm">0x00</code>) or a package with its applications (cascade, P2=<code class="font-mono text-sm">0x80</code>). Fields: the AID and the target. A 'not found' result (the object is already gone) is reported as such and counted OK; any other failure is reported with the card's status word.</td></tr>
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">Batch delete (per card)</td><td class="py-1 px-2">Deletes one object on every equipped card: an application (instance only, P2=<code class="font-mono text-sm">0x00</code>) or a package with its applications (cascade, P2=<code class="font-mono text-sm">0x80</code>). Fields: the AID and the target. A 'not found' result (the object is already gone) is reported as <strong>Already absent</strong> and counted separately from real deletions &mdash; it is still a success (the goal is met) and the run continues; any other failure is reported with the card's status word.</td></tr>
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">CAP compatibility test</td><td class="py-1 px-2">Answers one question without installing anything: <strong>can this card satisfy the CAP's import list?</strong> The server runs the format check, INSTALL[for load] and the LOAD blocks only up to the block that completes the <strong>Import</strong> component &mdash; the point where the JCRE verifies the import list &mdash; then stops: no last-block flag and no INSTALL[for install], so nothing is committed and nothing has to be deleted afterwards. The <strong>Import versions to test</strong> list is pre-filled from the CAP analysis: <code class="font-mono text-sm">AID=version</code> rewrites an import's requested version, <code class="font-mono text-sm">+AID=version</code> appends a synthetic import (a card-capability query: the LOAD passes only if the card exports that package at &ge; that version), and <strong>Set all 0.0</strong> drops every requirement. Two-step use: press Set all 0.0 &mdash; if the test passes, the import list was the blocker; then restore one line at a time to find the package and version the card lacks. The verdict states it covers the <strong>LOAD/import gate only</strong>: the link gate (whether the applet's actual API calls exist) is what a real install checks at INSTALL[for install]. The run and its result appear in a popup (like the install): the step lines, the verdict and a per-AID detail block &mdash; on a rejection it names the CAP section the failing block covers (load-file byte range and components, and whether that block completes <strong>Import</strong>), the remote status word with its meaning, the import list exactly as tested (CAP versions, probe rewrites, appended synthetic entries, unmatched lines) and what the probe state implies; on success it lists the import list that passed.</td></tr>
<tr class="border-b border-gray-200 dark:border-slate-700"><td class="py-1 px-2">INSTALL [for install] (loaded package)</td><td class="py-1 px-2">For a package that is already loaded on the card (its Load File AID and Module AID, privileges, install/STK parameters and an optional <em>make selectable</em>). The applet instance is deleted first (tolerating 'not found' &mdash; a fresh card just installs; any other delete failure stops the chain with its reason), so the install parameters can be iterated without re-loading the <code class="font-mono text-sm">.cap</code>.</td></tr>
<tr><td class="py-1 px-2">INSTALL [for make selectable]</td><td class="py-1 px-2">One INSTALL [for make selectable] APDU (the instance AID) for an INSTALLED, non-selectable applet instance.</td></tr>