From 36281e02fd46a35def0ff08249319d3641ec616e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D1=82=D0=BE=D0=BD=20=D0=A2=D1=80=D0=BE=D1=88?= =?UTF-8?q?=D0=B8=D0=BD?= Date: Fri, 11 Sep 2026 21:52:57 +0300 Subject: [PATCH] profiler scan: check/uncheck-all toggle for the ignore-contents list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds an 'All' header checkbox next to 'Ignore contents of files:' that checks or unchecks every file; it reflects the list state (checked only when all are checked, indeterminate on a mixed selection) and updates on individual checkbox changes. RU label: 'Все'. Docs synced, tests for the toggle/state helpers. SW cache v77 -> v78. --- frontend/help-ru.html | 2 +- frontend/help.html | 2 +- frontend/index.html | 26 +++++++++++++++++++++++-- frontend/sw.js | 2 +- frontend/tests/profiler.test.js | 34 ++++++++++++++++++++++++++++++++- 5 files changed, 60 insertions(+), 6 deletions(-) diff --git a/frontend/help-ru.html b/frontend/help-ru.html index a9f9f12..455ac22 100644 --- a/frontend/help-ru.html +++ b/frontend/help-ru.html @@ -383,7 +383,7 @@

Проверить карту выполняет каждое правило на подключённой карте и показывает строку прогресса и отчёт прохождения. Рядом с путём файла указывается, что именно проверялось (например, тип файла и размер, содержимое или полный FCI); если часть проверок прошла, а часть нет — каждый аспект помечается (тип файла ✓, размер ✗, содержимое ✓), а расхождения расписываются ниже. Несовпавшие сырые данные (FCI, содержимое, данные записей) показываются как поля только для чтения с моноширинным шрифтом — ожидаемое над фактическим, в одной и той же колонке — для удобного сравнения; для расхождений FCI дополнительно показывается декодированное сравнение по параметрам (размер файла, дескриптор/структура, жизненный цикл, FID, SFI, проприетарные параметры…). Декодированный просмотр FCI также отображается рядом с полем FCI hex при редактировании правила. Если данные FCI повреждены, показывается всё, что удалось декодировать до места ошибки, вместе с явным сообщением об ошибке декодирования. Для record-файлов при расхождении содержимого добавляется пометка совпадающие записи: 1-5, 7-10 со списком записей, которые совпали.

Опции сканирования «Профиль с карты»

-

Диалог сканирования запрашивает имя профиля и предлагает селектор «Проверка FCP/FCI» (те же три режима, по умолчанию Тип файла + размер (FCP)), применяемый ко всем создаваемым правилам, а также список «Игнорировать содержимое файлов» (все отмечены по умолчанию, кроме EF.ARR) часто перезаписываемых файлов, содержимое которых пропускается: EF.LOCI, EF.PSLOCI, EF.EPSLOCI, EF.5GS3GPPLOCI, EF.Keys, EF.KeysPS, EF.SMS, EF.Kc, EF.KcGPRS, EF.LOCIGPRS, EF.CBMID, EF.SMSS, EF.ACC, EF.EPSNSC, EF.START-HFN, EF.ARR. Ещё две отмеченные по умолчанию опции «Сравнивать первые 4 байта для» EF.IMSI и EF.ICCID захватывают содержимое этих файлов как маску только первых 4 байт (снимите для точного сравнения). Строка прогресса показывает N / всего файлов с текущим путём файла во время сканирования; при сканировании опции скрываются, а кнопки блокируются. Правила создаются только для файлов, которые реально существуют на карте (возвращён FCP-шаблон); отсутствующие файлы пропускаются. Пользовательские файлы из подвкладки «Пользовательские файлы» включаются с той же проверкой существования.

+

Диалог сканирования запрашивает имя профиля и предлагает селектор «Проверка FCP/FCI» (те же три режима, по умолчанию Тип файла + размер (FCP)), применяемый ко всем создаваемым правилам, а также список «Игнорировать содержимое файлов» (все отмечены по умолчанию, кроме EF.ARR; флажок в заголовке отмечает или снимает весь список) часто перезаписываемых файлов, содержимое которых пропускается: EF.LOCI, EF.PSLOCI, EF.EPSLOCI, EF.5GS3GPPLOCI, EF.Keys, EF.KeysPS, EF.SMS, EF.Kc, EF.KcGPRS, EF.LOCIGPRS, EF.CBMID, EF.SMSS, EF.ACC, EF.EPSNSC, EF.START-HFN, EF.ARR. Ещё две отмеченные по умолчанию опции «Сравнивать первые 4 байта для» EF.IMSI и EF.ICCID захватывают содержимое этих файлов как маску только первых 4 байт (снимите для точного сравнения). Строка прогресса показывает N / всего файлов с текущим путём файла во время сканирования; при сканировании опции скрываются, а кнопки блокируются. Правила создаются только для файлов, которые реально существуют на карте (возвращён FCP-шаблон); отсутствующие файлы пропускаются. Пользовательские файлы из подвкладки «Пользовательские файлы» включаются с той же проверкой существования.

5.7 Сценарии использования

diff --git a/frontend/help.html b/frontend/help.html index 8128d50..f99b22a 100644 --- a/frontend/help.html +++ b/frontend/help.html @@ -383,7 +383,7 @@

Check card runs every rule against the equipped card and shows a live progress line plus a pass/fail report. Each row states exactly what was verified next to the file path (e.g. filetype and size, contents or exact FCI); when some checks pass and others fail, each aspect is marked (filetype ✓, size ✗, contents ✓) with the mismatches detailed below. Mismatched raw data (FCI, contents, record data) is shown as read-only monospace fields — expected above actual, aligned in the same column — for easy comparison; FCI mismatches additionally show a decoded per-parameter comparison (file size, file descriptor/structure, life cycle, FID, SFI, proprietary parameters…). A decoded FCI preview is also shown beside the FCI hex field while editing a rule. If the FCI data is corrupt, whatever was decoded before the faulty part is shown together with an explicit decode-failure note. For record files with a contents mismatch, a matching records: 1-5, 7-10 note lists the records that did match.

“Profile from card” scan options

-

The scan dialog asks for a profile name and offers a “FCP/FCI check” selector (the same three modes above, default Filetype + size) applied to every generated rule, plus an “Ignore contents of files” checklist (all checked by default except EF.ARR) of frequently-overwritten files whose contents are skipped: EF.LOCI, EF.PSLOCI, EF.EPSLOCI, EF.5GS3GPPLOCI, EF.Keys, EF.KeysPS, EF.SMS, EF.Kc, EF.KcGPRS, EF.LOCIGPRS, EF.CBMID, EF.SMSS, EF.ACC, EF.EPSNSC, EF.START-HFN, EF.ARR. Two further checked-by-default options “Match first 4 bytes for” EF.IMSI and EF.ICCID capture those files’ contents as a mask of only the first 4 bytes (uncheck for exact matching). A progress line shows N / total files with the current file path while scanning; during the scan the options are hidden and the buttons are locked. Rules are created only for files that actually exist on the card (a FCP template is returned); missing files are skipped. Custom files from the Custom files sub-tab are included under the same existence check.

+

The scan dialog asks for a profile name and offers a “FCP/FCI check” selector (the same three modes above, default Filetype + size) applied to every generated rule, plus an “Ignore contents of files” checklist (all checked by default except EF.ARR; the header checkbox checks or unchecks the whole list) of frequently-overwritten files whose contents are skipped: EF.LOCI, EF.PSLOCI, EF.EPSLOCI, EF.5GS3GPPLOCI, EF.Keys, EF.KeysPS, EF.SMS, EF.Kc, EF.KcGPRS, EF.LOCIGPRS, EF.CBMID, EF.SMSS, EF.ACC, EF.EPSNSC, EF.START-HFN, EF.ARR. Two further checked-by-default options “Match first 4 bytes for” EF.IMSI and EF.ICCID capture those files’ contents as a mask of only the first 4 bytes (uncheck for exact matching). A progress line shows N / total files with the current file path while scanning; during the scan the options are hidden and the buttons are locked. Rules are created only for files that actually exist on the card (a FCP template is returned); missing files are skipped. Custom files from the Custom files sub-tab are included under the same existence check.

5.7 Usage scenarios

diff --git a/frontend/index.html b/frontend/index.html index edb357a..ce03447 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -913,7 +913,13 @@
-
Ignore contents of files:
+
+ Ignore contents of files: + +
@@ -7100,6 +7106,20 @@ function profilerNew() { profilerEdit(profiles.length - 1); } +function profilerScanToggleAll(checked) { + document.querySelectorAll('#profiler-scan-ignore input[data-ignore-fid]').forEach(cb => { cb.checked = checked; }); +} + +function profilerScanIgnoreAllState() { + const boxes = document.querySelectorAll('#profiler-scan-ignore input[data-ignore-fid]'); + const all = document.getElementById('profiler-scan-ignore-all'); + if (!all) return; + let checked = 0; + boxes.forEach(cb => { if (cb.checked) checked++; }); + all.checked = boxes.length > 0 && checked === boxes.length; + all.indeterminate = checked > 0 && checked < boxes.length; +} + function profilerFromCard() { document.getElementById('profiler-scan-name').value = ''; document.getElementById('profiler-scan-name').readOnly = false; @@ -7108,10 +7128,11 @@ function profilerFromCard() { let html = ''; for (const f of PROFILER_IGNORE_FILES) { html += ''; } ignore.innerHTML = html; + profilerScanIgnoreAllState(); const mask = document.getElementById('profiler-scan-mask'); let mhtml = ''; for (const fid in PROFILER_MASK_PREFIX4_FIDS) { @@ -8268,6 +8289,7 @@ const LANG_RU = { 'Discovering...': 'Поиск файлов...', 'files': 'файлов', 'Ignore contents of files:': 'Игнорировать содержимое файлов:', + 'All': 'Все', 'Match first 4 bytes for': 'Сравнивать первые 4 байта для', 'FCP/FCI check': 'Проверка FCP/FCI', 'Filetype only (FCP)': 'Только тип файла (FCP)', diff --git a/frontend/sw.js b/frontend/sw.js index cfeab80..5c51a26 100644 --- a/frontend/sw.js +++ b/frontend/sw.js @@ -1,4 +1,4 @@ -const CACHE = 'otaman-v77'; +const CACHE = 'otaman-v78'; const URLS = [ 'index.html', 'help.html', diff --git a/frontend/tests/profiler.test.js b/frontend/tests/profiler.test.js index 289f9b2..d9e97df 100644 --- a/frontend/tests/profiler.test.js +++ b/frontend/tests/profiler.test.js @@ -21,7 +21,7 @@ function extractFunc(src, name, asyncFn) { return (asyncFn ? 'async ' : '') + src.slice(m.index, i + 1); } -const FNS = ['profilerNormHex', 'profilerNormHexStrict', 'profilerMatch', 'profilerMatchMin', 'profilerMaskPrefix4', 'profilerFileFields', 'profilerContentKindForFileType', 'profilerEmptyRecordContent', 'profilerValidateProfile', 'profilerCustomNameForPath', 'profilerUpdateRulePath', 'profilerResultAspects', 'profilerAspectSummary', 'profilerNumRanges', 'esc', 'escHtml', 'profilerRawDataCheck', 'profilerRenderReport', 'parseBerLen', 'parseTlvList', 'fcpInt', 'fcpParseTlvs', 'fcpFileDescriptor', 'fcpLifeCycle', 'fcpSfi', 'fcpDo', 'fcpDecode', 'fcpDiffHtml', 'profilerFciPreviewItems', 'profilerUpdateFciPreview', 'profilerUpdateRule', 'profilerFciInput']; +const FNS = ['profilerNormHex', 'profilerNormHexStrict', 'profilerMatch', 'profilerMatchMin', 'profilerMaskPrefix4', 'profilerFileFields', 'profilerContentKindForFileType', 'profilerEmptyRecordContent', 'profilerValidateProfile', 'profilerCustomNameForPath', 'profilerUpdateRulePath', 'profilerResultAspects', 'profilerAspectSummary', 'profilerNumRanges', 'esc', 'escHtml', 'profilerRawDataCheck', 'profilerRenderReport', 'parseBerLen', 'parseTlvList', 'fcpInt', 'fcpParseTlvs', 'fcpFileDescriptor', 'fcpLifeCycle', 'fcpSfi', 'fcpDo', 'fcpDecode', 'fcpDiffHtml', 'profilerFciPreviewItems', 'profilerUpdateFciPreview', 'profilerUpdateRule', 'profilerFciInput', 'profilerScanToggleAll', 'profilerScanIgnoreAllState']; let code = ''; for (const f of FNS) code += extractFunc(html, f) + '\n'; code += extractFunc(html, 'profilerBuildFileRule', true) + '\n'; @@ -787,3 +787,35 @@ test('fcpDiffHtml appends decode-failure notes for corrupt sides', () => { assert.strictEqual(fcpDiffHtml('', ''), ''); delete global.t; }); + +test('profilerScanToggleAll / profilerScanIgnoreAllState manage the ignore checkboxes', () => { + const boxes = [{ checked: true }, { checked: false }, { checked: true }]; + const header = { checked: false, indeterminate: false }; + global.document = { + querySelectorAll: sel => (sel === '#profiler-scan-ignore input[data-ignore-fid]' ? boxes : []), + getElementById: id => (id === 'profiler-scan-ignore-all' ? header : null), + }; + + profilerScanIgnoreAllState(); + assert.strictEqual(header.checked, false); + assert.strictEqual(header.indeterminate, true); + + boxes[1].checked = true; + profilerScanIgnoreAllState(); + assert.strictEqual(header.checked, true); + assert.strictEqual(header.indeterminate, false); + + profilerScanToggleAll(false); + assert.ok(boxes.every(b => !b.checked)); + profilerScanIgnoreAllState(); + assert.strictEqual(header.checked, false); + assert.strictEqual(header.indeterminate, false); + + profilerScanToggleAll(true); + assert.ok(boxes.every(b => b.checked)); + profilerScanIgnoreAllState(); + assert.strictEqual(header.checked, true); + assert.strictEqual(header.indeterminate, false); + + delete global.document; +});