- Keep-alive is no longer a setting: the TLS connection stays open between
POSTs for the whole dialog (the card, as HTTP client, may still dial a new
one at any time - GP Am. B 4.3.1) and only the 204 ends it, with a clean
close_notify while the response is still buffered, then FIN. Dropped
keep_alive/on_before_close/_scp81_wait_drained and the Connection-header
'close' value (the API, status and UI no longer carry a keep-alive knob).
- The Listener Options block is a collapsed <details> with a 'custom' badge
when anything differs from the reference defaults; the Reset button moved
into the body so it cannot toggle the panel.
- X-Admin-Targeted-Application is opt-in (checkbox + //aid/... field, field
disabled while off); X-Admin-Next-URI has a checkbox + hint explaining the
one-shot rule of GP Am. B 4.4.2; both dependent fields grey out when
unchecked.
- Labels/i18n: 'Chunked body (Transfer-Encoding: chunked)' stays English,
'Show link events (...)', 'Теги comprehension-required'; the compact-header
wording now spells out that it omits the optional space after ':' (legal
per RFC 7230 3.2 OWS; saves one byte per header).
- Tests: a 200 keeps the socket for the next POST; the 204 closes with a
mutual close_notify exchange; options helper/badge unit tests; removed the
close-per-response and drain-wait tests. SW cache otaman-v181.
Listener Options block (applied at Start, persisted in localStorage, Reset to
defaults): HTTP framing - chunked body, chunk size (0 = one TLS record),
keep-alive, Connection header, compact headers, Next-URI (unchecked = omit);
script framing - indefinite/definite Command Scripting template, CR tag,
targeted app; link events (now parsed on the common start path, so every mode
honors them). scp81OptionsFromForm() is unit-tested.
TLS is automatic: 'auto' (min 1.0, max 1.2 + :@SECLEVEL=0) is the new
default, all six PSK suites are offered and OpenSSL negotiates the highest;
the negotiated version/cipher is logged (tls-handshake) and reported as
version_seen/cipher_seen in /api/scp81/status, and a handshake failing for a
TLS/cipher reason logs tls-handshake-failed (post-handshake record errors
stay tls-error). tls_version/cipher/keylog/answer_delay stay as API-only pins.
Dropped the Apache-style header mimicry completely: no Date/Server/
X-Powered-By, no Content-Length-before-Content-Type ordering, no Content-Type
on 204 - the minimal response set is X-Admin-Protocol (+ X-Admin-Next-URI /
Targeted-Application), Content-Type on 200s, and Transfer-Encoding or
Content-Length per the chunked flag. Docs, help (EN/RU), READMEs and the
AGENTS notes updated; SW cache otaman-v180.
The former 'passthru' mode is now 'redirect': it pins the configured target
and every BIP channel is connected there (the card's requested address is
only logged; host/port required). The name 'passthru' now means the new mode:
no listener and no target - each channel dials the destination the card
requests in OPEN CHANNEL (Other address + Transport level port, TCP client,
remote, 0x02 only). The specs define no default port (TS 102 223 8.59), so an
incomplete or non-TCP request fails the channel with result 3A and an
open-fail log reason.
BipTerminal gains a mode (enable(host, port, mode=...), open(..., proto=...)),
reports it in status(), and the control API/status expose redirect (target)
and passthru (per-channel targets). The PWA mode selector shows four modes
with per-mode notes and disables Host/Port in passthru; the status line shows
each channel's actual target. Docs, help (EN/RU), READMEs and the AGENTS notes
updated; SW cache otaman-v179.
Breaking API change: mode:'passthru' has the new semantics - use
mode:'redirect' for the previous behavior (no alias).
The help pages had no SCP81 section and documented Cards as a 3.2 subsection
of the SCP80 tab. They now mirror the UI: 3 SCP80 (3.1 Secured Packet, 3.2
RAM), 4 Cards tab, 5 SCP81 tab (5.1 Listener, 5.2 Scripts), with the
following sections renumbered (6 Card reader, 7 Profiler, 8 Phone simulator,
9 Server, 10 Compatibility) and the TERMINAL PROFILE range corrected to bytes
1-39 (TS 102 223 5.2 + TS 31.111 5.2). The SCP81 tab and its sub-pills set
their own help anchors; a new test asserts every help anchor used by the UI
exists in help.html. READMEs: seven top-level tabs, SCP80 two pills, Cards
fields/buttons/SCP81 column, SCP81 modes (PSK TLS / pass-through / capture),
PSK pairs from presets, Scripts page and resume semantics. SW cache
otaman-v178.
- scp81.py: PSK TLS listener (stdlib ssl PSK callbacks) speaking the GP
HTTP administration dialog; configurable framing (chunked/Content-Length,
TLS record split, Apache-style/compact headers, Connection header,
keep-alive, Next-URI template with %d, TLS version/cipher, answer delay,
keylog for capture decryption)
- server.py: script responder + Response Scripting parsing (AF/AB, 80/23
TLVs), memory decoder, SCP81 start options, terminal-side timer
management, background-mode BIP events, permissive OPEN CHANNEL
- BIP fix: the RECEIVE DATA channel-data TLV length is BER long form
(36 81 <len>) above 127 bytes; a raw length byte is mis-parsed on the
card, so the large TLS records never reached its stack (a live card
fetched the script response and silently never processed it - endless
resume). The card now executes scripts and returns R-APDUs: memory
(13 applets, 50646 B NV free, 2402 B volatile), ISD, stored HTTP OTA
parameters, ELF and application registries
- frontend: SCP81 tab (listener, script selection, HTTP OTA log), phone
event forms, i18n; service worker v141
- docs: api.md, scp81-findings.md (attempt matrix + root cause analysis);
tools/scp81_decrypt.py decrypts listener captures via the keylog
- tests: 187 python + 337 frontend
- new 'Profile from snapshot' button in the Profiles toolbar: reuses the
snapshot picker (profilerSnapshotPickListHtml refactor) and then opens
the same scan form as Profile from card (profilerScanOpenForm), with
the profile name prefilled from the snapshot
- new profiler-build target 'profile-snapshot': the form's ignore list,
mask options and FCP/FCI mode apply to profilerScanSnapshot(), which
walks the snapshot's captured files instead of the card; uncaptured
contents produce rules without a content check, record files map to
exact record content, transparent files honor the masks
- profilerScanStart() pushes the generated profile and opens the editor
like the live scan; _scanSnapshot is cleared in the finally block
- RU entry 'Профиль из снимка'; tests for the snapshot rule builder
(exact/mask/ignore/uncaptured/record), the snapshot scan progress, the
picker wiring and the form title, plus a structural button check;
help EN/RU and READMEs updated; SW cache v130 -> v131.
- new profilerResultsHeaderText() builds the header from a structured
{kind, from, to}: profile checks read 'Profile verification results
for: <profile> -> <card ICCID | snapshot name>', snapshot comparison
reads 'Snapshot comparison results: <master> -> <checked>' (the arrow
matches the one already used in the compare header)
- profilerRunProfile() stores the header and profilerRenderResultsView()
writes it, so the header follows a language switch and the ICCID stays
current; RU keys added ('Результаты проверки профиля:',
'Результаты сравнения снимков:')
- tests: header builder variants + render wiring; flow tests now expect
header objects; help EN/RU and READMEs updated; SW cache v129 -> v130.
- new profilerLabelText() resolves expected/actual labels at render time;
profilerRenderReport and fcpDiffHtml (including the decode-failure
notes) use it, so a language switch keeps the labels localized
- Check card: reads EF.ICCID via /api/read (MF/2FE2) and labels the
report 'expected (<profile>)' / 'actual (<card ICCID>)'; the results
title becomes '<profile> — <ICCID>' (falls back to the plain title and
'actual' when EF.ICCID is unreadable)
- Check card snapshot: labels 'expected (<profile>)' / 'actual
(<snapshot name>)
- snapshot-vs-snapshot compare keeps verbatim master/check names;
the mismatch label column widens to w-48 for prefixed labels
- tests: profilerLabelText, prefixed report/diff labels, profilerCardIccid
decode/fallback, both check flows pass the labels; help EN/RU, READMEs
updated; SW cache v128 -> v129.
- selecting an EF now renders an info block between the File: title and
the contents: FID, file type, size, record length/count (nulls skipped)
followed by the decoded FCI via the existing profilerFciPreviewItems()
decoder (no raw hex), matching the snapshot detail view
- pysimFsInfoHtml() is pure and reused by pysimFsClickFile(); the [LF]
shorthand stays in the title; custom files get the same metadata from
the temporary select probe
- tests: pysimFsInfoHtml in profiler.test.js (full response, missing
fci_hex, skipped nulls) and a structural check for #pysim-fs-info;
help EN/RU and READMEs updated; SW cache v119 -> v120.
- pysimFsLoadChildren now treats {success:false,error} (and any error
payload) as a failed listing: absent DFs/ADFs render as a red cross
without an expand arrow instead of silently opening empty; the
/api/tree 500 body also carries exists:false for shape consistency
with /api/select
- an expanded directory with zero children shows a gray (empty)
placeholder
- new Probe all files button (data-needs=card) in the tree header:
walks the whole model tree from MF, verifies every DF/ADF via
/api/tree and every file (incl. custom entries) via /api/select,
skips subtrees of absent dirs, shows N/total progress, toggles to
Stop, and reports present/absent counts with elapsed time; results
colour the current tree only
- tests: fs_load (error/retry/empty), fs_render (red cross, (empty)),
fs_probe (flags, absent-dir skip, custom files, stop, summary);
html structural check; help EN/RU, READMEs, AGENTS updated;
SW cache v115 -> v116.
- each row now shows Edit and Delete buttons (same styling as the
profiler list buttons) instead of the red X glyph
- Edit reloads the entry into the top form: the Add button becomes
Save (data-l10n updated too) and a Cancel button appears; submit
updates the entry in place, recomputing fid/parentFid and excluding
the edited row from the duplicate-path check
- Delete removes without confirmation; deleting the row being edited
cancels the edit and an earlier deletion shifts the edit index
- pysimCustomAdd renamed to pysimCustomSubmit; tests for the whole
flow; SW cache v114 -> v115.
- top-level tab order is now Remote APDU, SCP80, Profiler, Card reader,
Phone simulator; the profiler view moved with its button so the DOM
order matches the tab strip
- docs (help EN/RU, READMEs) and the tab-order test updated; SW cache
v113 -> v114.
- pysimFsSortChildren() groups DFs above EFs, then sorts each group by
FID (default) or case-insensitive symbolic name; missing names fall
back to the FID as the sort key; deterministic tie-break; the input
array is not mutated
- render uses the sorted copy, so lazily loaded directories and custom
file injections are sorted too
- FID / Name pills above the tree (pysimFsSetSort) persist the choice in
localStorage (otaman_fs_sort) and re-render without refetching
- tests for the comparator (DF priority, both keys, fallbacks, custom
entries, no mutation) and the pill wiring; help/README updated;
SW cache v108 -> v109.
Availability model: server-down / server-up-no-card / card-equipped.
- header shows a symbolic indicator dot (red/yellow/green, tooltip)
- a 5s probe tracks /api/version+/api/status while not fully ready; the
2s status poll takes over once connected
- controls declare data-needs='server' or 'card'; disabled + tooltip when
the state does not satisfy them: equip (server), status/reset, file
manager read/save/edit, raw APDU, profile-from-card, new snapshot,
profiler list Check card, event Send, RAM install/explore delete,
STK menu, Send STATUS, Verify vs pySim (server), pySim execute (server),
PLI save/poll toggle (server)
- pysimConnect no longer conflates server and card: it records both and
Connect stays usable without a card
- ramSendOta/ramInstallCap now use pysimFetch instead of raw fetch
(relative /api URLs broke custom server URLs)
Custom files moved from the Card reader sub-tabs to the Profiler list
tabs (Profiles / Card snapshots / Custom files); help/README/AGENTS
updated. Tests: availability gating, indicator structure, moved tab.
SW cache v103 -> v104.
Snapshot comparison results now use the master/checked snapshot names
where profile checks keep expected/actual: the raw-data field rows, the
generic mismatch line and the decoded FCI comparison table headers
(profilerRenderReport/fcpDiffHtml take an optional {expected, actual}
labels object; the name column widens to w-40 and wraps). Labels are
stored with the results so the language switch and the Only mismatches
filter re-render correctly; Check card snapshot and live checks are
unchanged. Tests for both labeled and default rendering; help/README
updated; SW cache v101 -> v102.
Server measures every classified APDU (A4 select, B0 read binary, B2 read
record) from command to response: _collect_apdu_times() enables the tracer
(reattaching it if pySim nulled it) and /api/select + /api/read return
'apdu_times': [{type, ms}]. Collection is safe: handlers hold _CARD_LOCK.
Snapshots store per-file {select_ms, read_ms}, a ms value per record and
snapshot-level stats {select, read_binary, read_record}: {min, max, avg,
count} plus total_ms (wall time of the scan). The snapshot view gets a
summary under the title (files/records counts, scan time, min/avg/max per
command type) and shows select/read per file and read time per record.
Timings are display-only: checks, snapshots comparison and imports ignore
them (old snapshots simply show 'No timing data').
Tests: Python classifier/collection (tests/test_apdu_timing.py) and
frontend stats/accumulator/format/build-file/summary. SW cache v99 ->
v100; help, README and docs/api.md updated.
- Phone pill: STK menu, STATUS and polling and the subscribed-events list
in one row, proactive command log full-width below (room for more
elements)
- TR Config pill: response data injected into TERMINAL RESPONSEs;
currently the PROVIDE LOCAL INFORMATION dictionary, structured as
heading + body blocks for future proactive-command responses
- phoneSwitchSubtab() mirrors the other sub-tab switchers and sets help
anchors stk-menu / pli-dict; switchTab('phone') always opens Phone
- refreshDynamicI18n renders only the visible phone panel
- help EN/RU section 6 regrouped (6.4 STATUS polling under Phone, 6.5
TR Config response data), READMEs and AGENTS.md updated
- structural and behavioral tests (html.test.js, phone_tabs.test.js);
SW cache v93 -> v94
- C-APDU tab renamed Remote APDU (label untranslated EN/RU); Response
parser moved from a top-level tab to a pill under it
- Profiler moved from the Card reader sub-tabs to a top-level tab
- Proactive UICC moved to a top-level tab and renamed Phone simulator
- Card reader keeps File manager, Custom files, pySim command line,
Raw APDU
- modals (event send, profiler scan/snapshot, STK menu) moved outside
the tab containers so they can open from any tab
- STK overlay disables the top-level tabs while waiting for user input
- OTA PoR jump now goes to Remote APDU > Response parser
- help EN/RU restructured (2.8 Response parser, 5 Profiler, 6 Phone
simulator, subsequent sections renumbered, anchors kept); READMEs and
AGENTS.md updated
- html.test.js asserts the new tab/pill structure; SW cache v92 -> v93
- _apply_equipped_card() centralizes the post-equip refresh + TERMINAL
PROFILE (shared by the /api/command equip branch and auto-equip)
- server tracks card_session (bumped on equip and disconnect) and
equipping; /api/status exposes connected, card_present, card_session,
equipping, auto_equip and is exempt from _CARD_LOCK (pure cached state)
- auto-equip is on by default (--no-auto-equip; off with --no-card-init):
the presence observer spawns a one-shot worker after insertion, which
runs equip under _CARD_LOCK and applies the same refresh; the monitor
starts after the startup init so pyscard's initial 'already present'
event does not re-equip a fresh session
- UI: /api/status polls every 2s (other views stay at 5s); when
card_session changes it runs pysimResetCardData() (STK overlay, file
tree, events, proactive log, PLI, status) — the same reset as a manual
Equip; messages: initializing / press Equip / no card
Tests for the observer and auto-equip rules, session bumps,
_apply_equipped_card, and the UI state machine. SW cache v91 -> v92.
Fast init (fastinit.py) is now the default for startup and equip: all
profile probes run on one connection, RuntimeState uses a software reset
and only explicit equip/reset reconnect the card. Measured on the
reference reader: equip 1729ms vs 9850ms and zero RESET events vs 7-8.
--full-pysim-init restores pysim's stock init_card/equip for
compatibility/debugging; the former --fast-init flag is kept as a hidden
no-op alias so existing command lines keep parsing. Docs updated.
Every FETCHed proactive command must be answered, otherwise the card is
left in an unfinished session and stops issuing commands (e.g. it will
not deliver a PoR for SEND SM). The menu handlers now share
_menu_send_response, and a server-side watchdog (_arm_menu_timeout /
_menu_timeout_fire, --menu-timeout, default 60s, 0 disables) sends the
timeout result (0x12) when the user never answers. The timer is armed
while a command is pending and cancelled on any response, equip, rescue
and card disconnect.
Also fixes docs/api.md, which had back (0x11) and timeout (0x12) codes
swapped. Tests for arm/cancel/clamping and the flat timeout TR. SW cache
v89 -> v90.
pysim's init_card() resets the card once per profile candidate in
CardProfile.pick(), once in RuntimeState.__init__ and again in
PysimApp.equip(); on typical readers each reconnect costs ~1.3s and a
normal init/equip does 7-8 of them (measured: equip 9.85s, startup
~14.8s).
fastinit.py mirrors pySim.app.init_card() with the resets removed:
pick_profile_no_reset() runs all profile probes back-to-back on one
connection, FastRuntimeState.reset() is a software reset (select MF,
clear selected_adf/scp, ATR from the transport) and the equip/reset
commands are routed through do_equip_fast (one reconnect via
wait_for_card) and do_reset_fast (always a physical reset). Enabled
with --fast-init; stock behavior remains the default.
Tests for the reset-free pick, the soft reset and the explicit reset
paths. Docs updated; SW cache v88 -> v89.
README(.md/_RUS.md) gain the sections that existed only in the in-app
help: C-APDU Parser, HTTP OTA (GP GPC v2.2 Amd B v1.1 4.7), and the
Profiler subtree (profile list, filesystem rules, scan options, check
report incl. Only mismatches, card snapshots, Check card snapshot and
Compare snapshots). Also correct the tab/sub-tab counts and add
Theme/Localization sections to the English README.
docs/api.md: remove the duplicate /api/ram-install section, document
fci_hex/file_size/record_len/num_of_rec in /api/select, the records
shape of /api/read, bump the version example, and add the missing
endpoint sections (events, event-send, proactive-log, status-poll,
rescue, poll-status, poll-toggle, pli-qualifiers, pli-dict).
Docs:
- SCP80 tab is now a parent section (3) with subsections 3.1/3.2/3.3
- Renumbered sections: Response parser→4, Card reader→5, Server→6, Version compat→7
- Applied to help.html, help-ru.html, README.md, README_RUS.md
C-APDU/RAM form labels (GP + JavaCard terminology):
- AID → Application / Instance AID
- ELF AID → Load File AID / Package AID
- Module AID → Executable Module AID / Applet Class AID
SCP80/RAM explorer labels (GP + JavaCard terminology):
- ISD → ISD (Issuer Security Domain)
- Applications → Applications / Applet Instances
- Executable Load Files → Executable Load Files (ELFs) / Packages
- AID → Application/Instance AID or Load File AID/Package AID (context-dependent)
- Module AIDs → Executable Module AIDs / Applet Class AIDs
UX fixes:
- Delete All button now matches Delete button style (red)
- Explorer results cleared when switching away from Explore Card operation
- KIc/KID dropdowns (index + algorithm) now update when selecting saved card
- Added LANG_RU translations for new labels
- README/README_RUS: RAM tab now describes Explore Card + Install Package operations,
explorer view with inline Delete/Delete All buttons for Applications and ELFs
- docs/api.md: add full /api/ram-install endpoint documentation
- index.html: remove Delete from dropdown, add ramDeleteFromExplorer() with confirm dialog,
add Delete buttons in explorer for Apps and ELFs (ELFs get cascade option)
The Secured Packet and Cards views moved under a single top-level SCP80
tab switched by two pills. Update README and help (EN+RU) section
titles/descriptions to match; bump service-worker cache so the precached
help pages are re-fetched.
Server:
- Track all TERMINAL RESPONSEs (chain, TP, pySim auto-handler, menu-respond
link to paused entry) with shared _build_tr/_record_tr
- Log entry ids + cmd_num; server-side decode of fetched commands and TRs
(compact PLI port); Result CTLV extracted as tr_result/tr_result_name
- _LoggingApduTracer captures TR SW for pySim auto-handler responses
- _DefaultProactiveHandler answers PLI with editor data (no re-request)
- VERSION 1.8.0
Frontend:
- Expandable proactive log rows (click to expand, state survives re-render)
- Response section: Result name + hex, decoded fields, width-restrained
readonly hex inputs; no SW display
- Rename Expanded Script tab/pill/button/docs; proactive UICC view font
sizing increase; card reader pills text-sm