Commit Graph

7 Commits

Author SHA1 Message Date
catarrh 94d7cff485 v3.29.2: the strict row rule for the outfile import
The format is positional: an empty value drops its token, so the parser
now requires every data row to have exactly the header's column count.
That catches an empty value anywhere - including a middle one, which
would otherwise shift the following columns (a missing ADM made the KIC
columns read the KIK values: valid hex, wrong preset) - and a KICn/KIDn
pair declared in the header must carry a usable hex value in every row
(a placeholder fails).

A violation makes the whole file invalid: the report's error names the
line, no presets are returned, and an import (mode) answers 400 - it is
never partially imported.  The PWA disables the Import button while the
report carries an error and guards the call.

Unchanged per-row reports: a non-hex PIN/PUK/ADM/PSK value (dropped, the
card kept), an unsupported key size (that keyset skipped), a card whose
remaining keysets are unusable (skipped).  All three real samples satisfy
the rule exactly (11/11, 18/18, 18/18).

Docs: help EN/RU, api.md, the repo AGENTS.  Tests: the short/long row and
the placeholder-keyset file errors, the valid-file round trip, the
endpoint's refusal (nothing stored), the PWA's disabled button.
926 frontend + 945 Python; sw cache simple-v449.
2026-10-15 00:43:53 +03:00
catarrh 8a66ea5a0a v3.29.1: the per-row keysets in the outfile preview
The import applied one global default keyset to every TAR entry of every
imported card.  The preview's TAR table (TAR + MSL, the three role rows +
"+ TAR") now has a keyset select per row, mirroring the preset editor: an
empty "— none —" plus the keysets found in the file with their KIc/KID,
the first preselected, and the editor's amber warning when a non-zero MSL
has no keyset.  Each TAR's packets then use exactly the chosen keyset.

- PWA: the global "Default keyset for the TARs" select (and the request's
  tar_keyset) is gone; cardsOutfileTarsFromDom/FromForm carry each row's
  keyset; cardsOutfileKeysets() became cardsOutfileKeysetOptions() (the
  union with the KIc/KID bytes for the labels).
- Server: a `tars` entry's own `keyset` (1-15; an unusable value is a 400)
  wins, then the optional global `tar_keyset` (the API shorthand), then the
  card's first keyset - parse_outfile no longer clobbers per-entry keysets
  with the card-level fallback.  presets.normalise_keyset_ref() is
  module-level (one rule for the store and the parser).
- Docs: help EN/RU, api.md (the tars entry keyset + the global fallback),
  the repo AGENTS.  Tests: the per-entry/global/card fallbacks, the
  bad-keyset 400, the options helper, the row select and round-trip, the
  import body.  925 frontend + 944 Python; sw cache simple-v448.
2026-10-15 00:40:16 +03:00
catarrh a66493f9b7 v3.28.4: the Custom-mode FCI editor + the shared ADM pattern
The profile rule editor rendered the same "FCI hex (raw SELECT response)"
field for Exact and Custom, although the custom check never reads
`fciHex` (it compares the data objects against the card's live FCI) - so
the field looked like an expectation it was not.

- The raw-FCI field and its decoded preview are exact-mode-only now; the
  Custom mode shows just its data-object editor.
- Switching a rule to Custom seeds the data objects from its captured FCI
  when the list is empty (the same all-'value' seeding a captured profile
  gets); the "load from the captured FCI" link refills an emptied list,
  and a rule without a captured FCI still starts empty for manual rows.

From the v3.28.3 review: the ADM's byte-pair rule now lives in one
place, presets.ADM_PATTERN, used by /api/verify-adm and the outfile
import - two literals could drift and an imported ADM could silently
become unverifiable.  The RU help's ADM wording is "4-16 hex-цифр
(чётное число)".

Docs: help EN/RU, the repo AGENTS.  Tests: the mode switch (seed / keep /
no FCI / switch-away), the field-gating source pin, the pattern's shape
and the both-users pin.  917 frontend + 927 Python; sw cache simple-v442.
2026-10-14 21:14:16 +03:00
catarrh b023719555 v3.28.3: the outfile ADM byte-pair rule
The review of v3.28.2 found the parser accepting an odd-length ADM (e.g.
12345), while /api/verify-adm requires byte pairs
((?:[0-9A-F]{2}){2,8}) - the stored value could never verify and was
refused with a misleading "adm must be 4-16 hex digits".

The parser now applies the verifier's exact rule: an odd length (a half
byte) or a value over 16 digits is dropped at import time with "ADM is
not 4-16 hex digits in byte pairs".

Docs: help EN/RU, api.md and the repo AGENTS say "4-16 hex digits in
byte pairs".  Tests: the odd-length and the over-16 drop cases (both
real samples are even-length and unaffected: BAP 3632333239463337,
AM0027 CFA3DD9C6B7F0F8C).  915 frontend + 925 Python; sw cache
simple-v441.
2026-10-14 18:17:59 +03:00
catarrh 09d8a12add v3.28.2: the outfile ADM encoding fix
The ADM column carries the key's hex value (the length varies, 4-16 hex
digits) - the form the preset store and /api/verify-adm use (pySim pads
it with 'f' to the 8 CHV bytes).  The parser treated it as an ASCII
string hex-encoded and either mangled it (3632333239463337 -> 62329F37,
a wrong ADM that would fail VERIFY and consume an attempt) or dropped it
(CFA3DD9C6B7F0F8C - the live report with AM0027_alfa_dsa.out).

- The ADM is stored as-is: non-hex stripped, uppercased, [0-9A-F]{4,16};
  a non-hex or too-short value is dropped with "ADM is not 4-16 hex
  digits".
- _ascii_from_hex() is gone (its only user was the ADM column).
- Docs: help EN/RU, api.md and the repo AGENTS now say "the key's hex
  value, 4-16 hex digits (the length varies)".

Note: presets imported from a BAP-style file before this fix hold the
mangled ADM - re-import or correct them.

Tests: the BAP fixture (the hex as-is), the AM0027 shape, a
short/lowercase value and the drop cases.  Both real samples verified
(BAP 3632333239463337, AM0027 CFA3DD9C6B7F0F8C; the ALFA sample has no
ADM column and is unchanged).  915 frontend + 925 Python; sw cache
simple-v440.
2026-10-14 18:07:04 +03:00
catarrh 21d7f58f61 v3.27.0 review: the outfile import hardening
- The endpoint validates algorithm16 (3des2/aes, case-insensitive) and mode
  (merge/replace or omitted): a misspelled value answers 400 instead of
  silently picking 3DES2 or turning an import into a dry run.  The choices
  come from outfile.ALGORITHM16_CHOICES, derived from the algorithm map, so
  the validation and the parser cannot drift apart.
- A present but unusable PIN/PUK value is reported with its raw text: a value
  that strips to nothing (e.g. 'abcd') used to vanish without a report line,
  contradicting the "nothing is silently dropped" contract.  A column absent
  from a short row stays silent - it is not present.
- The column-line detection drops the arbitrary 8-character column-name cap:
  a candidate header must carry ICCID plus at least one column the import
  consumes (a fixed name or a numbered KIC/KID), so a long unknown column
  name next to a real one parses while 'ICCID <value>' and
  'ICCID CUSTOMER_NAME' config lines are still rejected.  Both real samples
  are unaffected.
- PWA: a chosen default keyset survives an empty or failed preview (it used
  to reset to null, and the import silently fell back to the card's first
  keyset); the select renders the preview's keysets plus a remembered value.
- PWA: the destructive Replace mode asks for confirmation first, matching the
  other store-wiping actions.
- api.md documents both validations.  Tests: the endpoint's 400s and the
  replace import, the raw-value report, the header guards, the keyset
  preservation and the declined confirmation.  906 frontend + 904 Python;
  sw cache simple-v437.
2026-10-14 13:50:30 +03:00
catarrh 212bfc24ac v3.27.0: the outfile import
Import many card presets at once from a card vendor's plain-text dump.
The new pure pysim_simple_server/outfile.py (parse_outfile) plus
POST /api/presets/import-outfile: without `mode` the call is a dry-run
preview returning the parsed presets and a report (nothing is stored),
with `merge`/`replace` the same parse runs and the presets go through
the preset store.

The parser: the data starts at the first line whose whitespace tokens
all look like column names and include ICCID (a leading `word:` prefix
is stripped, so a `var_out:IMSI ICCID ...` header line matches while a
config line naming a value - `ICCID:897...` or `ICCID 897...` - cannot);
one row per card follows.  Recognised columns (case-insensitive): ICCID,
PIN1/PIN2, PUK1/PUK2, ADM (the ASCII string, hex-encoded), PSK (32 hex;
an optional PSKID/PSK_ID names the identity, defaulting to the card's
ICCID) and KICn/KIDn - one keyset per numbered pair, up to 15;
IMSI*/EKI/KIKn are ignored.  The KIc/KID bytes are inferred: the keyset
number is the column number, the algorithm nibble follows the key size
(8 B DES, 16 B 3DES2 or AES - the preview's choice, 3DES2 default,
24 B 3DES3; anything else skips the keyset with a note), both bytes
carrying the same number (TS 102 225 A.2).  The TARs never come from the
file: the caller's table (default the three role entries) is applied
with one global default keyset written into every entry (the card's
first keyset when unset).  An invalid optional code is dropped with a
report line instead of failing the card; the report names the columns,
the rows read, the parsed keysets and every skip.

The ICCID normaliser fix (both sides, drift-guarded): the trailing F
(or Fs) is the odd-nibble padding - when the rest is digits only it is
the plain digit form (the vendors print the ICCID as digits+F),
otherwise the value is the raw nibble-swapped EF hex; a raw value never
ends in F, so the rule is unambiguous.

PWA: the Import outfile button in the Cards list, the hidden file input
and the preview panel (the common name, the 16-byte algorithm select,
the TAR table with the role defaults editable and + TAR / remove for
extras, the global default keyset select over the parsed keysets, the
merge/replace mode, the parsed cards table, the report, Refresh
preview, Import).  The panel joins refreshDynamicI18n for the language
switch.

Docs: help EN/RU (the term outfile stays untranslated in RU), api.md's
new section, the repo AGENTS.  Tests: the parser (both fixture shapes,
the column detection, the key-size inference, the options/TAR table,
the PSK identity, the skips, the store round-trip), the endpoint (the
preview, the import, the duplicate skip, the 400s), the normaliser on
both sides, the PWA helpers/wiring and the algorithm16 drift guard
against outfile.py.  904 frontend + 903 Python; sw cache simple-v436.
2026-10-14 13:37:27 +03:00