Files
simtrace-analyser/frontend/sw.js
T
catarrh ac7519499a Audit fixes: FDB structure coding, FCP tags, ECC; new file decoders
Full APDU + file-data decoder audit against UICC_SPECS.md /
UICC_FILES.md (deep-verified against ISO 7816-4 Table 14 and
TS 102 221 V18.4 Tables 11.4/11.5, §11.1.1.4.8):

- EF structure per TS 221 T11.5 (overrides ISO): 100 = cyclic,
  110 = BER-TLV (was: 110 mislabeled cyclic, BER-TLV missing);
  comment documents the ISO divergence.
- FCP tag 'AB' = security attributes expanded format (was wrongly
  "short_ef_id"); add tags '86'/'87'/'8B'/'8C' (security attrs,
  extending EF id).
- EF_ECC: BCD digits(2) + ESC code(1) per record (was Annex-A text).
- APDU_SPEC +11: WRITE BINARY D0/D1, SEARCH BINARY A0/A1, READ
  RECORD odd B3, ENVELOPE odd C3, EXCHANGE CAPABILITIES 7A, RESIZE
  FILE D4 (TS 102 222), ERASE BINARY odd 0F, PSO 2A, GAKP 46.
- New file decoders per UICC_FILES.md: EF_Kc/KcGPRS (6F20/6F52,
  Kc + KSI nibble), EF_OPL (6FC6, PLMN + LAC range + PNN rec),
  EXT1-4/BDN-EXT (6F4A/B/C/E/55, 13-byte records), EF_AD (6FAD,
  op mode + MNC length), EF_ACL (6F57, 'DD' APN TLVs after count
  byte), EF_SMSP (6F42, alpha + PI-gated TP-DA/SCA/PID/DCS/VP),
  EF_SPDI (6FCD, 'A3' PLMN container); EF_CBMIR now decodes all
  4-byte ranges (was first only).

Audit false-positive noted: original file-type bit extraction
(b>>3, 1-based b6-b4) was correct — retained with clarifying
comment. Tests: +18 audit fixtures — 338 total. Version 1.16.0,
SW cache simtrace-analyser-v22.
2026-08-23 19:39:20 +03:00

49 lines
1.4 KiB
JavaScript

const CACHE = 'simtrace-analyser-v22';
const PRECACHE = [
'index.html',
'manifest.json',
'icon-192.png',
'icon-512.png',
'favicon.png',
'sim-analyser.svg',
'sim-analyser-light.svg',
];
self.addEventListener('install', e => {
self.skipWaiting();
e.waitUntil(
caches.open(CACHE)
.then(cache => cache.addAll(PRECACHE))
.then(() => console.log('SW: precache done'))
.catch(err => console.error('SW: precache failed', err))
);
});
self.addEventListener('activate', e => {
e.waitUntil(
caches.keys()
.then(keys => Promise.all(
keys.filter(k => k !== CACHE).map(k => caches.delete(k))
))
.then(() => self.clients.claim())
.then(() => console.log('SW: activated, controlling clients'))
);
});
self.addEventListener('fetch', e => {
// Network-first: the local server is always up, so always serve fresh
// content and fall back to cache only when offline.
if (!e.request.url.startsWith('http')) return;
if (e.request.method !== 'GET') return;
e.respondWith(
fetch(e.request)
.then(r => {
const clone = r.clone();
caches.open(CACHE).then(c => c.put(e.request, clone)).catch(() => {});
return r;
})
.catch(() => caches.match(e.request))
);
});