profiler: mask-match IMSI/ICCID contents on 'Profile from card'
When generating a ruleset from the card, capture EF.IMSI (6F07) and EF.ICCID (2FE2) contents as a mask matching only the first 4 bytes (e.g. 08290591??????????), the rest are '?' wildcards. Add profilerMaskPrefix4 helper + PROFILER_MASK_PREFIX4_FIDS map + tests. SW cache v44.
This commit is contained in:
+19
-1
@@ -6672,6 +6672,13 @@ const PROFILER_IGNORE_FILES = [
|
|||||||
{ fid: '6F43', name: 'EF.SMSS' },
|
{ 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() {
|
function profilerLoad() {
|
||||||
try {
|
try {
|
||||||
const d = localStorage.getItem('otaman_profiles');
|
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));
|
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) {
|
function profilerValidateProfile(obj) {
|
||||||
if (!obj || typeof obj !== 'object') return 'Not an object';
|
if (!obj || typeof obj !== 'object') return 'Not an object';
|
||||||
if (!obj.name) return 'Missing name';
|
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 })),
|
records: rd.records.map(r => ({ num: r.num, data: r.data })),
|
||||||
};
|
};
|
||||||
} else if (rd.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) {}
|
} catch (e) {}
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
const CACHE = 'otaman-v43';
|
const CACHE = 'otaman-v44';
|
||||||
const URLS = [
|
const URLS = [
|
||||||
'index.html',
|
'index.html',
|
||||||
'help.html',
|
'help.html',
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ function extractFunc(src, name) {
|
|||||||
return src.slice(m.index, i + 1);
|
return src.slice(m.index, i + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const FNS = ['profilerNormHex', 'profilerMatch', 'profilerMatchMin', 'profilerValidateProfile'];
|
const FNS = ['profilerNormHex', 'profilerMatch', 'profilerMatchMin', 'profilerMaskPrefix4', 'profilerValidateProfile'];
|
||||||
let code = '';
|
let code = '';
|
||||||
for (const f of FNS) code += extractFunc(html, f) + '\n';
|
for (const f of FNS) code += extractFunc(html, f) + '\n';
|
||||||
eval(code);
|
eval(code);
|
||||||
@@ -68,6 +68,12 @@ test('profilerMatchMin compares the shorter overlapping portion', () => {
|
|||||||
assert.ok(!profilerMatchMin('mask', '08?91?AA', '091110'));
|
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', () => {
|
test('profile validation', () => {
|
||||||
assert.strictEqual(profilerValidateProfile(null), 'Not an object');
|
assert.strictEqual(profilerValidateProfile(null), 'Not an object');
|
||||||
assert.strictEqual(profilerValidateProfile({ name: 'x' }), 'Missing rules array');
|
assert.strictEqual(profilerValidateProfile({ name: 'x' }), 'Missing rules array');
|
||||||
|
|||||||
Reference in New Issue
Block a user