diff --git a/frontend/index.html b/frontend/index.html index 798da0e..90d12d6 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -6672,6 +6672,13 @@ const PROFILER_IGNORE_FILES = [ { fid: '6F43', name: 'EF.SMSS' }, ]; +// Files where contents are captured as a mask matching only the first 4 bytes +// (the rest are '?' wildcards). Keyed by FID; display name is the pySim name. +const PROFILER_MASK_PREFIX4_FIDS = { + '6F07': 'EF.IMSI', + '2FE2': 'EF.ICCID', +}; + function profilerLoad() { try { const d = localStorage.getItem('otaman_profiles'); @@ -6717,6 +6724,13 @@ function profilerMatchMin(mode, expected, actual) { return profilerMatch(mode, e.slice(0, n), a.slice(0, n)); } +// Keep the first 4 bytes (8 hex chars) exact and mask the rest with '?'. +function profilerMaskPrefix4(hex) { + const h = profilerNormHex(hex); + if (h.length <= 8) return h; + return h.slice(0, 8) + '?'.repeat(h.length - 8); +} + function profilerValidateProfile(obj) { if (!obj || typeof obj !== 'object') return 'Not an object'; if (!obj.name) return 'Missing name'; @@ -6896,7 +6910,11 @@ async function profilerBuildFileRule(path, c, ignoreFids) { records: rd.records.map(r => ({ num: r.num, data: r.data })), }; } else if (rd.data) { - rule.content = { mode: 'exact', kind: 'transparent', expected: rd.data }; + if (PROFILER_MASK_PREFIX4_FIDS[fid]) { + rule.content = { mode: 'mask', kind: 'transparent', expected: profilerMaskPrefix4(rd.data) }; + } else { + rule.content = { mode: 'exact', kind: 'transparent', expected: rd.data }; + } } } } catch (e) {} diff --git a/frontend/sw.js b/frontend/sw.js index 764b916..a87b9ca 100644 --- a/frontend/sw.js +++ b/frontend/sw.js @@ -1,4 +1,4 @@ -const CACHE = 'otaman-v43'; +const CACHE = 'otaman-v44'; const URLS = [ 'index.html', 'help.html', diff --git a/frontend/tests/profiler.test.js b/frontend/tests/profiler.test.js index 3dc7eda..75f63f7 100644 --- a/frontend/tests/profiler.test.js +++ b/frontend/tests/profiler.test.js @@ -21,7 +21,7 @@ function extractFunc(src, name) { return src.slice(m.index, i + 1); } -const FNS = ['profilerNormHex', 'profilerMatch', 'profilerMatchMin', 'profilerValidateProfile']; +const FNS = ['profilerNormHex', 'profilerMatch', 'profilerMatchMin', 'profilerMaskPrefix4', 'profilerValidateProfile']; let code = ''; for (const f of FNS) code += extractFunc(html, f) + '\n'; eval(code); @@ -68,6 +68,12 @@ test('profilerMatchMin compares the shorter overlapping portion', () => { assert.ok(!profilerMatchMin('mask', '08?91?AA', '091110')); }); +test('profilerMaskPrefix4 keeps first 4 bytes and masks the rest', () => { + assert.strictEqual(profilerMaskPrefix4('082905911234567890'), '08290591??????????'); + assert.strictEqual(profilerMaskPrefix4('08290591'), '08290591'); + assert.strictEqual(profilerMaskPrefix4('1234'), '1234'); +}); + test('profile validation', () => { assert.strictEqual(profilerValidateProfile(null), 'Not an object'); assert.strictEqual(profilerValidateProfile({ name: 'x' }), 'Missing rules array');