diff --git a/README.md b/README.md index 12b59e3..ba43b57 100644 --- a/README.md +++ b/README.md @@ -186,6 +186,35 @@ one. Exchanges larger than 255 bytes (extended-length APDUs) cannot be represented in the stored wire shape and are skipped with a note in the import report. +### Files view (per-file tracking) + +The Trace tab's side panel has a view selector (*Map* / *Stats* / **Files**; +a drop-down, since three tab captions no longer fit). The Files view is a +trace-wide timeline of file operations — every **Read**, **Update** and +**Changed (card)** row shows the same file name as the Map view, and clicking +a row jumps to the APDU in the trace. A *Changed (card)* row carries a Δ +button that opens the changed ranges with the previous and the new bytes. + +The data comes from `simtrace_analyser/filetrack.py` +(`GET /api/sessions//files`), a single-pass tracker over the decoded +session that keeps, keyed by (DF, FID) and **across card resets**: access +counters (`select`/`read`/`update`, successful operations only), a sparse image +of the observed contents and the change log. Device-initiated changes are the +UPDATE operations seen in the trace; card-initiated ones are inferred when a +read returns bytes differing from what the image already knew — bytes never +seen before just fill the image (an observation, not a change). Files reached +by SFI share the entry of their path/FID accesses: the SFI ↔ FID relations come +from the normative tables (TS 102 221 Annex H, TS 31.102 Annex H) and from every +surfaced FCP carrying the `88` DO, including the spec's "SFI = the 5 LSBs of the +FID" rule when the DO is absent; an SFI used before its relation is learned +stays provisional and merges into the resolved entry. A file's DF context +follows TS 102 221 §8.4/Table 8.2 (selecting an EF leaves its parent DF current, +a path selection included); applications selected by an unknown AID get the AID +as their DF identity, named from EF.DIR when the trace surfaced it. Bounds: the +image freezes past 64 KB of observed bytes per file (`image_truncated`) and the +change log keeps the last 1000 events per file (`changes_total` keeps counting). +Counters are returned by the API but not shown in this view yet. + Server options: ``` diff --git a/README_RUS.md b/README_RUS.md index 54a0314..6a42a34 100644 --- a/README_RUS.md +++ b/README_RUS.md @@ -191,6 +191,36 @@ Application Layer* — два отдельных поля выбора, имен Обмены длиннее 255 байт (APDU с расширенной длиной) невозможно представить в хранимом «проводном» виде — они пропускаются с пометкой в отчёте импорта. +### Просмотр файлов (сопровождение состояния файлов) + +В боковой панели вкладки «Трассировка» появился выбор вида (*Map* / *Stats* / +**Files** — выпадающий список, три подписи-вкладки уже не помещались). Вид +Files — это таймлайн файловых операций по всей трассе: строки **Read**, +**Update** и **Changed (card)** показывают те же имена файлов, что и вид Map, +а щелчок по строке переходит к APDU в трассе. У строки *Changed (card)* есть +кнопка Δ, открывающая изменённые диапазоны с прежними и новыми байтами. + +Данные даёт `simtrace_analyser/filetrack.py` (`GET /api/sessions//files`) — +однопроходный анализатор сессии, который ведёт по ключу (DF, FID) и **через +сбросы карты**: счётчики доступа (`select`/`read`/`update`, только успешные +операции), разреженный образ наблюдаемого содержимого и журнал изменений. +Изменения со стороны устройства — это операции UPDATE из трассы; изменения со +стороны карты выводятся, когда чтение возвращает байты, отличающиеся от уже +известных образу (никогда не виденные байты просто заполняют образ — это +наблюдение, а не изменение). Файлы, доступные по SFI, попадают в ту же +запись, что и доступ по пути/FID: соответствия SFI ↔ FID берутся из +нормативных таблиц (TS 102 221 Annex H, TS 31.102 Annex H) и из каждого +показанного FCP с DO `88`, включая правило спецификации «SFI = 5 младших бит +FID» при отсутствии DO; SFI, использованный до того, как связь выучена, +остаётся предварительным и сливается с разрешённой записью. Контекст DF +следует TS 102 221 §8.4/Table 8.2 (выбор EF оставляет текущим его родительский +DF, включая выбор по пути); приложения, выбранные по неизвестному AID, +получают в качестве идентичности DF сам AID и имя из EF.DIR, если он +показан в трассе. Ограничения: образ замораживается после 64 КБ +наблюдаемых байт на файл (`image_truncated`), журнал изменений хранит +последние 1000 событий на файл (`changes_total` продолжает считать). +Счётчики API отдаёт, но в этом виде пока не показываются. + Параметры сервера: ``` diff --git a/frontend/index.html b/frontend/index.html index 29ed8c6..2b0758b 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -181,6 +181,20 @@ body { font: 14px/1.5 system-ui, sans-serif; background: var(--bg); color: var(- .side-tabs { display: flex; margin-bottom: 8px; border-bottom: 1px solid var(--bg-input); } .side-tab { flex: 1; padding: 6px 0; background: none; border: none; color: var(--text-muted); cursor: pointer; font-size: 12px; text-transform: uppercase; letter-spacing: 1px; border-bottom: 2px solid transparent; } .side-tab.active { color: var(--accent); border-bottom-color: var(--accent); } +.side-view-select { width: 100%; margin-bottom: 8px; padding: 6px 8px; background: var(--bg-input); color: var(--text); + border: 1px solid var(--border); border-radius: 4px; font-size: 12px; text-transform: uppercase; letter-spacing: 1px; cursor: pointer; } +.file-op { display: flex; align-items: baseline; gap: 6px; padding: 3px 8px; cursor: pointer; border-radius: 4px; font-size: 13px; word-break: break-word; } +.file-op:hover { background: var(--bg-input); } +.file-op-read { color: var(--text-muted); } +.file-op-update { color: var(--accent); } +.file-op-card { color: var(--warn); } +.file-op .file-op-diff { margin-left: auto; background: none; border: none; color: var(--warn); cursor: pointer; font-size: 12px; padding: 0 2px; flex: 0 0 auto; } +.file-op .file-op-diff:hover { color: var(--accent); } +.file-diff-modal { max-width: 640px; } +.file-diff-body { max-height: 50vh; overflow-y: auto; margin-bottom: 16px; } +.file-diff-body table { font-size: 12px; } +.file-diff-body td { padding: 2px 8px 2px 0; vertical-align: top; } +.file-diff-body .file-diff-hex { font-family: ui-monospace, monospace; word-break: break-all; } .map-item { padding: 3px 8px; cursor: pointer; border-radius: 4px; font-size: 13px; color: var(--text); word-break: break-word; } .map-item:hover { background: var(--bg-input); } .map-files-toggle { color: var(--accent); cursor: pointer; } @@ -333,12 +347,14 @@ body { font: 14px/1.5 system-ui, sans-serif; background: var(--bg); color: var(-
-
- - -
+
—
+
@@ -419,8 +435,19 @@ body { font: 14px/1.5 system-ui, sans-serif; background: var(--bg); color: var(-
- -