diff --git a/frontend/help-ru.html b/frontend/help-ru.html index a412cd8..e2c01ab 100644 --- a/frontend/help-ru.html +++ b/frontend/help-ru.html @@ -381,7 +381,7 @@
  • Атрибуты файла — тип файла, размер, длина записи и число записей из FCP-шаблона (любой можно оставить незаданным).
  • Проверить содержимое (опционально) — Точное (точное совпадение hex) или Маска, где ? — шаблон на один полубайт (маска без ? — совпадение префикса, например 0891 для MCC/MNC из IMSI). Для record-файлов хранится список по записям.
  • -

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

    +

    Проверить карту выполняет каждое правило на подключённой карте и показывает строку прогресса и отчёт прохождения. Рядом с путём файла указывается, что именно проверялось (например, тип файла и размер, содержимое или полный 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-шаблон); отсутствующие файлы пропускаются. Пользовательские файлы из подвкладки «Пользовательские файлы» включаются с той же проверкой существования.

    diff --git a/frontend/help.html b/frontend/help.html index f8da7db..58a8fb6 100644 --- a/frontend/help.html +++ b/frontend/help.html @@ -381,7 +381,7 @@
  • File attributes — file type, size, record length and record count, taken from the FCP template (any may be left unset).
  • Check contents (optional) — Exact hex equality, or Mask where ? is a per-nibble wildcard (a mask with no ? is a prefix match, e.g. 0891 for the IMSI MCC/MNC). Record files store a per-record list.
  • -

    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.

    +

    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. An Only mismatches option in the results header hides all passing files and keeps only failures and errors.

    “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; 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.

    diff --git a/frontend/index.html b/frontend/index.html index 33d1734..c58d3e4 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -848,6 +848,10 @@
    +
    @@ -6988,6 +6992,7 @@ let profilerView = 'list'; let profilerEditId = null; let profilerDraft = null; let profilerResults = null; +let profilerMismatchOnly = false; let snapshots = []; let snapshotViewId = null; let _scanTarget = 'profile'; @@ -7932,6 +7937,15 @@ async function profilerCheckSnapshot(i, si) { await profilerRunProfile(p, profilerSnapshotSource(s), p.name + ' — ' + s.name); } +function profilerToggleMismatchOnly(checked) { + profilerMismatchOnly = checked; + profilerRenderResultsView(); +} + +function profilerVisibleResults(results, mismatchOnly) { + return mismatchOnly ? results.filter(r => r.status !== 'pass') : results; +} + function profilerRenderResultsView() { if (!profilerResults) return; let passed = 0, failed = 0, errors = 0; @@ -7943,7 +7957,10 @@ function profilerRenderResultsView() { document.getElementById('profiler-summary').innerHTML = '' + passed + ' ' + t('passed') + '' + ' · ' + failed + ' ' + t('failed') + '' + ' · ' + errors + ' ' + t('errors') + ''; - document.getElementById('profiler-report').innerHTML = profilerRenderReport(profilerResults); + const shown = profilerVisibleResults(profilerResults, profilerMismatchOnly); + document.getElementById('profiler-report').innerHTML = shown.length + ? profilerRenderReport(shown) + : '
    ' + esc(t('No mismatches')) + '
    '; } function profilerLiveSource() { @@ -8730,6 +8747,8 @@ const LANG_RU = { 'passed': 'пройдено', 'failed': 'не пройдено', 'errors': 'ошибок', + 'Only mismatches': 'Только расхождения', + 'No mismatches': 'Расхождений нет', 'expected': 'ожидалось', 'actual': 'фактически', 'HTTP OTA': 'HTTP OTA', diff --git a/frontend/sw.js b/frontend/sw.js index e6c501d..1103bb3 100644 --- a/frontend/sw.js +++ b/frontend/sw.js @@ -1,4 +1,4 @@ -const CACHE = 'otaman-v86'; +const CACHE = 'otaman-v87'; const URLS = [ 'index.html', 'help.html', diff --git a/frontend/tests/profiler.test.js b/frontend/tests/profiler.test.js index 5bb23b4..01317da 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', 'profilerScanToggleAll', 'profilerScanIgnoreAllState', 'swapNibbles', 'decIccid', 'profilerSnapshotIccid', 'profilerValidateSnapshot', 'profilerListSwitch', 'profilerScanRefreshOptions', 'profilerLiveSource', 'profilerSnapshotSource']; +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', 'swapNibbles', 'decIccid', 'profilerSnapshotIccid', 'profilerValidateSnapshot', 'profilerListSwitch', 'profilerScanRefreshOptions', 'profilerLiveSource', 'profilerSnapshotSource', 'profilerVisibleResults']; let code = ''; for (const f of FNS) code += extractFunc(html, f) + '\n'; code += extractFunc(html, 'profilerBuildFileRule', true) + '\n'; @@ -1029,3 +1029,10 @@ test('profilerRunRule against a snapshot reports uncaptured content as an error' assert.ok(res.checks.some(c => c.label === 'content' && c.ok === false)); delete global.t; }); + +test('profilerVisibleResults hides passing files when mismatch-only is on', () => { + const results = [{ status: 'pass' }, { status: 'fail' }, { status: 'error' }, { status: 'pass' }]; + assert.strictEqual(profilerVisibleResults(results, false).length, 4); + assert.deepStrictEqual(profilerVisibleResults(results, true).map(r => r.status), ['fail', 'error']); + assert.strictEqual(profilerVisibleResults([{ status: 'pass' }], true).length, 0); +});