1/* ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 2 * TERAN ILDIZ â IZNI O'CHIRISH DVIGATELI (wipe-engine.js) v40 3 * 4 * Vazifa: shu qurilmada ilova qoldirgan BARCHA izni tag-tugi bilan 5 * o'chirish â tez, aniq va har qanday brauzerda (Android, iOS, desktop). 6 * 7 * ISHLASH TAMOYILI 8 * 1) TAYYORGARLIK â o'chirishni to'sib qo'yadigan narsalar yopiladi 9 * (Service Worker, ochiq IndexedDB ulanishlari, push obunalari). 10 * 2) PARALLEL TOZALASH â barcha saqlash turlari bir vaqtda tozalanadi. 11 * Har bir vazifa o'z vaqt chegarasiga ega: bittasi tiqilib qolsa 12 * qolganlarini kutib turmaydi (shu sabab TEZ ishlaydi). 13 * 3) TEKSHIRUV â nima qolganini o'lchaymiz (navigator.storage.estimate, 14 * caches.keys, indexedDB.databases, localStorage.length, cookie...). 15 * 4) QAYTA URINISH â qolgani bo'lsa yana tozalaymiz (3 martagacha). 16 * "rm -rf" mantig'i: qolguncha emas, QOLMAGUNCHA. 17 * 5) HISOBOT â nima o'chdi, nima qoldi â aniq ko'rsatiladi. 18 * 19 * QAMROV (17 tur): 20 * localStorage · sessionStorage · Cache Storage · Service Worker · 21 * IndexedDB · OPFS (fayl tizimi) · WebSQL (eski) · Cookie · 22 * Push obunasi · Bildirishnomalar · Fon sinxronizatsiyasi · 23 * Blob/Object URL · Xotiradagi holat · Tarix holati · 24 * Media sessiyasi · Hisob ma'lumotlari · Server (Clear-Site-Data) 25 * 26 * BRAUZER FARQLARI 27 * ⢠iOS Safari'da indexedDB.databases() YO'Q â nomlar ro'yxati bo'yicha 28 * ham o'chiramiz (aniqlangan + ma'lum nomlar birlashtiriladi). 29 * ⢠Eski Android WebView'da caches/OPFS bo'lmasligi mumkin â har bir 30 * imkoniyat alohida tekshiriladi, yo'q bo'lsa o'tkazib yuboriladi. 31 * ⢠Hech bir vazifa xato tashlamaydi â barchasi yutiladi va hisobotga 32 * yoziladi, ya'ni bitta xato butun jarayonni to'xtatmaydi. 33 * ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ */ 34(function () { 35 'use strict'; 36 var TI = window.TI = window.TI || {}; 37 38 /* âââââââââââ Yordamchilar âââââââââââ */ 39 40 /* Har bir vazifani vaqt chegarasi bilan bajarish â tiqilib qolmasin */ 41 function guard(promise, ms, label) { 42 return new Promise(function (resolve) { 43 var done = false; 44 var t = setTimeout(function () { 45 if (done) return; done = true; 46 resolve({ ok: false, timeout: true, err: 'vaqt tugadi (' + ms + 'ms)' }); 47 }, ms); 48 Promise.resolve() 49 .then(function () { return promise; }) 50 .then(function (v) { if (done) return; done = true; clearTimeout(t); resolve({ ok: true, val: v }); }) 51 .catch(function (e) { if (done) return; done = true; clearTimeout(t); resolve({ ok: false, err: String((e && e.message) || e) }); }); 52 }); 53 } 54 55 function has(o, k) { try { return !!(o && o[k]); } catch (e) { return false; } } 56 57 /* Ilova qanday rejimda ochilgan: o'rnatilgan PWA (standalone) yoki 58 oddiy brauzer varag'i. Bu ikkisi uchun chiqish xabari boshqacha 59 bo'lishi kerak â o'rnatilgan bo'lmasa "ilovani o'chiring" ko'rsatmasi 60 mantiqsiz (o'chirish uchun hech narsa yo'q). */ 61 function detectMode() { 62 try { 63 if (window.matchMedia && window.matchMedia('(display-mode: standalone)').matches) return 'standalone'; 64 } catch (e) {} 65 try { if (navigator.standalone === true) return 'standalone'; /* eski iOS Safari */ } catch (e) {} 66 try { 67 if (document.referrer && document.referrer.indexOf('android-app://') === 0) return 'standalone'; 68 } catch (e) {} 69 return 'browser'; 70 } 71 72 /* âââââââââââ 1) TAYYORGARLIK âââââââââââ */ 73 74 /* Service Worker'ni ro'yxatdan chiqarish â u keshni ushlab turishi mumkin */ 75 async function killServiceWorkers() { 76 if (!has(navigator, 'serviceWorker')) return { skip: true }; 77 var n = 0; 78 try { 79 var regs = await navigator.serviceWorker.getRegistrations(); 80 for (var i = 0; i < regs.length; i++) { 81 /* avval push obunasini bekor qilamiz */ 82 try { 83 var sub = await regs[i].pushManager.getSubscription(); 84 if (sub) await sub.unsubscribe(); 85 } catch (e) {} 86 /* fon sinxronizatsiyasi teglari */ 87 try { 88 if (regs[i].periodicSync && regs[i].periodicSync.getTags) { 89 var tags = await regs[i].periodicSync.getTags(); 90 for (var j = 0; j < tags.length; j++) { try { await regs[i].periodicSync.unregister(tags[j]); } catch (e) {} } 91 } 92 } catch (e) {} 93 try { if (await regs[i].unregister()) n++; } catch (e) {} 94 } 95 } catch (e) {} 96 return { removed: n }; 97 } 98 99 /* âââââââââââ 2) SAQLASH TURLARI âââââââââââ */ 100 101 async function wipeCaches() { 102 if (!has(window, 'caches')) return { skip: true }; 103 var n = 0; 104 try { 105 var keys = await caches.keys(); 106 var res = await Promise.all(keys.map(function (k) { 107 return caches.delete(k).then(function (ok) { return ok; }, function () { return false; }); 108 }));
109 res.forEach(function (r) { if (r) n++; }); 110 } catch (e) {} 111 return { removed: n }; 112 } 113 114 /* IndexedDB â bloklanishni hisobga olib o'chirish */ 115 function deleteDB(name) { 116 return new Promise(function (resolve) { 117 var done = false; 118 function fin(ok) { if (!done) { done = true; resolve(ok); } } 119 try { 120 var req = indexedDB.deleteDatabase(name); 121 req.onsuccess = function () { fin(true); }; 122 req.onerror = function () { fin(false); }; 123 /* Boshqa yorliq (tab) bazani ushlab tursa "blocked" bo'ladi â 124 biroz kutamiz, keyin keyingi urinishga qoldiramiz. */ 125 req.onblocked = function () { setTimeout(function () { fin(false); }, 1200); }; 126 } catch (e) { fin(false); } 127 setTimeout(function () { fin(false); }, 2600); 128 }); 129 } 130 131 /* Ma'lum baza nomlari â iOS Safari'da databases() yo'qligi uchun zarur */ 132 var KNOWN_DBS = [ 133 'ti', 'teran', 'teranildiz', 'ti-db', 'ti-cache', 'ti-books', 'ti-audio', 134 'keyval-store', 'localforage', 'workbox-expiration', 'workbox-precache', 135 'firebaseLocalStorageDb', 'firebase-installations-database', 136 'ti-reader', 'ti-saved', 'ti-stats', 'ti-news' 137 ]; 138 139 async function wipeIndexedDB() { 140 if (!has(window, 'indexedDB')) return { skip: true }; 141 var names = []; 142 try { 143 if (indexedDB.databases) { 144 var dbs = await indexedDB.databases(); 145 (dbs || []).forEach(function (d) { if (d && d.name && names.indexOf(d.name) < 0) names.push(d.name); }); 146 } 147 } catch (e) { /* iOS Safari â qo'llab-quvvatlamaydi */ } 148 KNOWN_DBS.forEach(function (n) { if (names.indexOf(n) < 0) names.push(n); }); 149 150 var okN = 0; 151 var results = await Promise.all(names.map(function (nm) { return deleteDB(nm); })); 152 results.forEach(function (r) { if (r) okN++; }); 153 return { tried: names.length, removed: okN }; 154 } 155 156 /* OPFS â Origin Private File System (zamonaviy brauzerlarda fayllar shu yerda) */ 157 async function wipeOPFS() { 158 if (!(has(navigator, 'storage') && navigator.storage.getDirectory)) return { skip: true }; 159 var n = 0; 160 try { 161 var root = await navigator.storage.getDirectory(); 162 var names = [];
163 try { 164 if (root.keys) { for await (var k of root.keys()) names.push(k); } 165 else if (root.entries) { for await (var ent of root.entries()) names.push(ent[0]); } 166 } catch (e) {} 167 for (var i = 0; i < names.length; i++) { 168 try { await root.removeEntry(names[i], { recursive: true }); n++; } catch (e) {} 169 } 170 } catch (e) {} 171 return { removed: n }; 172 } 173 174 /* WebSQL â eskirgan, lekin ba'zi Android/iOS versiyalarida hali bor */ 175 async function wipeWebSQL() { 176 if (!has(window, 'openDatabase')) return { skip: true }; 177 var n = 0; 178 try { 179 ['ti', 'teran', 'cache', 'localStorage'].forEach(function (nm) { 180 try { 181 var db = window.openDatabase(nm, '1.0', nm, 2 * 1024 * 1024); 182 db.transaction(function (tx) { 183 tx.executeSql("SELECT name FROM sqlite_master WHERE type='table'", [], function (t, rs) { 184 for (var i = 0; i < rs.rows.length; i++) { 185 var tn = rs.rows.item(i).name; 186 if (/^(__|sqlite_)/.test(tn)) continue; 187 try { t.executeSql('DROP TABLE IF EXISTS ' + tn); n++; } catch (e) {} 188 } 189 }); 190 }); 191 } catch (e) {} 192 }); 193 } catch (e) {} 194 return { dropped: n }; 195 } 196 197 function wipeWebStorage() { 198 var out = { local: 0, session: 0 }; 199 try { out.local = localStorage.length; localStorage.clear(); } catch (e) {} 200 try { out.session = sessionStorage.length; sessionStorage.clear(); } catch (e) {} 201 /* Ba'zi kalitlar clear() dan keyin qayta yozilishi mumkin â nomma-nom ham o'chiramiz */ 202 try { 203 var ks = []; 204 for (var i = 0; i < localStorage.length; i++) ks.push(localStorage.key(i)); 205 ks.forEach(function (k) { try { localStorage.removeItem(k); } catch (e) {} }); 206 } catch (e) {} 207 return out; 208 } 209 210 /* Cookie â barcha yo'l va domen kombinatsiyalarida */ 211 function wipeCookies() { 212 var n = 0; 213 try { 214 var host = location.hostname; 215 /* domen variantlari: to'liq host + har bir yuqori daraja */ 216 var domains = ['', host, '.' + host]; 217 var parts = host.split('.'); 218 for (var i = 1; i < parts.length - 1; i++) { 219 var d = parts.slice(i).join('.'); 220 domains.push(d); domains.push('.' + d); 221 } 222 /* yo'l variantlari: ildizdan joriy yo'lgacha har bir bo'g'in */ 223 var paths = ['/']; 224 var segs = location.pathname.split('/').filter(Boolean); 225 var acc = ''; 226 segs.forEach(function (s) { acc += '/' + s; paths.push(acc); paths.push(acc + '/'); }); 227 228 var exp0 = '=; expires=Thu, 01 Jan 1970 00:00:00 GMT'; 229 var raw = document.cookie ? document.cookie.split(';') : []; 230 raw.forEach(function (c) { 231 var name = c.split('=')[0].trim(); 232 if (!name) return; 233 n++; 234 /* (v113) `__Host-` prefiksli cookie QAT'IY qoidaga bo'ysunadi: 235 faqat `path=/` va `domain` SIZ, `Secure` bilan o'chadi. 236 Domen ko'rsatilsa brauzer buyruqni butunlay rad etadi â 237 shuning uchun bu holat alohida bajariladi. */ 238 if (name.indexOf('__Host-') === 0) { 239 try { document.cookie = name + exp0 + '; path=/; Secure'; } catch (e) {} 240 try { document.cookie = name + exp0 + '; path=/; Secure; SameSite=None; Partitioned'; } catch (e) {} 241 } 242 var exp = '=; expires=Thu, 01 Jan 1970 00:00:00 GMT'; 243 paths.forEach(function (p) { 244 domains.forEach(function (d) { 245 var base = name + exp + '; path=' + p + (d ? '; domain=' + d : ''); 246 try { document.cookie = base; } catch (e) {} 247 try { document.cookie = base + '; SameSite=Lax'; } catch (e) {} 248 try { document.cookie = base + '; SameSite=None; Secure'; } catch (e) {} 249 /* (v113) `Partitioned` (CHIPS) â Chrome'ning yangi bo'lingan 250 cookie'lari. Ular ODDIY o'chirish buyrug'iga BERILMAYDI: 251 atribut mos kelmasa brauzer boshqa cookie deb hisoblaydi 252 va eskisi joyida qolaveradi. */ 253 try { document.cookie = base + '; SameSite=None; Secure; Partitioned'; } catch (e) {} 254 }); 255 }); 256 }); 257 } catch (e) {} 258 return { cleared: n }; 259 } 260 261 /* Bildirishnoma / hisob ma'lumotlari / ilova belgisi (badge) */ 262 async function wipeCredentials() { 263 var out = {}; 264 try { 265 if (has(navigator, 'credentials') && navigator.credentials.preventSilentAccess) { 266 await navigator.credentials.preventSilentAccess(); 267 out.credentials = true; 268 } 269 } catch (e) {} 270 try { 271 if (has(window, 'MediaSession') || (navigator.mediaSession)) { 272 navigator.mediaSession.metadata = null; 273 try { navigator.mediaSession.playbackState = 'none'; } catch (e) {} 274 out.mediaSession = true; 275 } 276 } catch (e) {}
277 /* Ilova ikonkasidagi raqamli belgi (masalan "3 ta yangi") â PWA 278 o'rnatilgan bo'lsa, buni ham tozalab qo'yamiz. */ 279 try { 280 if (navigator.clearAppBadge) { await navigator.clearAppBadge(); out.badge = true; } 281 } catch (e) {} 282 return out; 283 } 284 285 /* Xotiradagi holat: ilova ma'lumotlari, blob havolalari, media */ 286 function wipeMemory() { 287 var out = { blobs: 0 }; 288 /* ilova holati */ 289 try { 290 if (TI.APP) { TI.APP.data = []; TI.APP.filtered = []; TI.APP.q = ''; TI.APP.cat = 'all'; } 291 } catch (e) {} 292 try { window.LIB = []; } catch (e) {} 293 try { window.TERAN_DATA = {}; } catch (e) {} 294 try { if (TI._navWraps) TI._navWraps = {}; } catch (e) {} 295 296 /* ochilgan media va blob havolalari */ 297 try { 298 var media = document.querySelectorAll('audio,video,img,iframe,source'); 299 Array.prototype.forEach.call(media, function (el) { 300 var src = el.currentSrc || el.src || ''; 301 if (src.indexOf('blob:') === 0) { try { URL.revokeObjectURL(src); out.blobs++; } catch (e) {} } 302 try { if (el.pause) el.pause(); } catch (e) {} 303 try { el.removeAttribute('src'); if (el.load) el.load(); } catch (e) {} 304 }); 305 } catch (e) {} 306 return out; 307 } 308 309 /* Tarix holati â ortga qaytganda eski sahifa chiqmasin */ 310 function wipeHistory() { 311 try { 312 history.replaceState(null, '', location.pathname); 313 /* orqadagi yozuvlarni "bo'sh" holat bilan almashtirish */ 314 for (var i = 0; i < 3; i++) { try { history.pushState(null, '', location.pathname); } catch (e) {} } 315 history.replaceState(null, '', location.pathname); 316 return { ok: true }; 317 } catch (e) { return { ok: false }; } 318 } 319 320 /* Serverga buyruq: Clear-Site-Data (brauzerning o'z mexanizmi). 321 keepalive:true â MUHIM: foydalanuvchi darhol boshqa sahifaga o'tsa ham 322 (chiqish oqimida shunday bo'ladi), bu so'rov brauzer tomonidan baribir 323 yakunigacha yuboriladi â sahifa yopilishi uni to'xtatmaydi. */ 324 async function purgeViaServer(full) { 325 try { 326 /* (v113) BIR MARTALIK belgi qo'shiladi. `cache: 'no-store'` faqat 327 BRAUZER keshiga ta'sir qiladi; oradagi proksi yoki Service 328 Worker esa baribir eski javobni qaytarishi mumkin edi. Bu esa 329 `Clear-Site-Data` sarlavhasining brauzergacha yetib bormasligi 330 demak â ya'ni eng ishonchli qatlam jimgina ishlamay qolardi. 331 Har safar boshqa manzil â kesh imkoniyati umuman yo'q. 332 (SW tomonda ham `/privacy-wipe/purge` chetlab o'tiladi.) */ 333 var nonce; 334 try { 335 var buf = new Uint8Array(8); 336 crypto.getRandomValues(buf); 337 nonce = Array.prototype.map.call(buf, function (b) { return ('0' + b.toString(16)).slice(-2); }).join(''); 338 } catch (e) { nonce = String(Date.now()) + Math.random().toString(16).slice(2); } 339 340 var u = '/privacy-wipe/purge?n=' + nonce + (full ? '&full=1' : ''); 341 var res = await fetch(u, { 342 method: 'GET', cache: 'no-store', credentials: 'include', 343 mode: 'same-origin', redirect: 'error', keepalive: true 344 }); 345 /* Javob HAQIQATAN tarmoqdan kelganini tekshiramiz: SW keshidan 346 berilgan javobda `Clear-Site-Data` ishlamaydi. */ 347 var applied = !!(res && res.status === 204); 348 return { ok: applied, status: res ? res.status : 0 }; 349 } catch (e) { return { ok: false, err: String((e && e.message) || e) }; } 350 } 351 352 /* Boshqa ochiq yorliqlarga ham "tozalan" xabari. 353 mode:'panic' bo'lsa â boshqa yorliqlar HAM darhol neytral sahifaga 354 o'tishi kerak (na hisobot, na "tayyor" ekrani â hech narsa ko'rinmasin). */ 355 function notifyOtherTabs(mode) { 356 try { 357 var bc = new BroadcastChannel('ti-wipe'); 358 bc.postMessage({ wipe: 1, mode: mode || 'normal', at: Date.now() }); 359 setTimeout(function () { try { bc.close(); } catch (e) {} }, 500); 360 return { ok: true }; 361 } catch (e) { return { ok: false }; } 362 } 363 364 /* âââââââââââ 3) TEKSHIRUV âââââââââââ */ 365 366 async function measure() { 367 var m = { usage: null, caches: null, idb: null, local: null, session: null, cookies: null, sw: null }; 368 try { var est = await navigator.storage.estimate(); m.usage = est && est.usage != null ? est.usage : null; } catch (e) {} 369 try { m.caches = (await caches.keys()).length; } catch (e) {} 370 try { if (indexedDB.databases) m.idb = (await indexedDB.databases()).length; } catch (e) {} 371 try { m.local = localStorage.length; } catch (e) {} 372 try { m.session = sessionStorage.length; } catch (e) {} 373 try { m.cookies = document.cookie ? document.cookie.split(';').filter(function (x) { return x.trim(); }).length : 0; } catch (e) {} 374 /* (v113) yangi qamrov ham TEKSHIRUVGA kiradi â aks holda qayta 375 urinish halqasi ularni "toza" deb hisoblab o'tkazib yuborardi. */ 376 try { m.wname = window.name ? window.name.length : 0; } catch (e) {} 377 try { m.perf = window.performance ? performance.getEntriesByType('resource').length : 0; } catch (e) {} 378 try { m.sw = (await navigator.serviceWorker.getRegistrations()).length; } catch (e) {} 379 return m; 380 } 381 382 function isClean(m) {
383 return (m.caches === null || m.caches === 0) 384 && (m.idb === null || m.idb === 0) 385 && (m.local === null || m.local === 0) 386 && (m.session === null || m.session === 0) 387 && (m.cookies === null || m.cookies === 0) 388 && (m.sw === null || m.sw === 0) 389 && (m.wname === null || m.wname === undefined || m.wname === 0); 390 /* `m.perf` ATAYLAB shartga kiritilmadi: tozalangandan keyin ham 391 shu tekshiruvning O'ZI yangi yozuv qo'shadi, ya'ni u hech qachon 392 nolga tushmaydi va halqa bekorga uch marta aylanardi. Uni 393 tozalaymiz va hisobotga yozamiz, lekin "toza emas" belgisi 394 sifatida ishlatmaymiz. */ 395 } 396 397 /* âââââââââââ 4) ASOSIY OQIM âââââââââââ */ 398 399 /* ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 400 (v113) YANGI QAMROV â avval e'tibordan chetda qolgan izlar 401 ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ */ 402 403 /* `window.name` â bitta yorliq ichida SAHIFA ALMASHSA HAM saqlanib 404 qoladigan yagona oddiy o'zgaruvchi. Aynan shu sabab uni kuzatuv 405 uchun ishlatishadi: boshqa saytga o'tilganda ham qiymat qoladi. 406 Tozalash bir qator, lekin usiz "iz qolmadi" deyish noto'g'ri. */ 407 function wipeWindowName() { 408 try { 409 var had = !!window.name; 410 window.name = ''; 411 return { ok: true, had: had }; 412 } catch (e) { return { ok: false }; } 413 } 414 415 /* Performance Resource Timing â brauzer YUKLANGAN HAR BIR manzilni 416 ro'yxatda saqlaydi va uni istalgan skript o'qiy oladi 417 (`performance.getEntriesByType('resource')`). Ya'ni tozalanmasa, 418 qaysi maqola ochilgani shu ro'yxatdan bilinib qolardi. */ 419 function wipePerfTimeline() { 420 var out = { entries: 0 }; 421 try { 422 if (window.performance) { 423 try { out.entries = performance.getEntriesByType('resource').length; } catch (e) {} 424 try { performance.clearResourceTimings(); } catch (e) {} 425 try { performance.clearMarks(); } catch (e) {} 426 try { performance.clearMeasures(); } catch (e) {} 427 /* Bufer to'lgach brauzer yangilarini yozmay qo'yadi â 0 ga 428 tushirib, keyingi yozuvlar ham to'planmasligini ta'minlaymiz */ 429 try { performance.setResourceTimingBufferSize(0); } catch (e) {} 430 } 431 return { ok: true, entries: out.entries }; 432 } catch (e) { return { ok: false }; } 433 } 434 435 /* Storage Buckets API â Chrome'ning yangi, ALOHIDA saqlash joyi. 436 `localStorage`/`IndexedDB` tozalansa ham bu tegilmay qolardi, 437 chunki u butunlay boshqa idishda turadi. Brauzerda yo'q bo'lsa â 438 jimgina o'tkazib yuboriladi. */ 439 async function wipeStorageBuckets() { 440 try { 441 if (!navigator.storageBuckets || !navigator.storageBuckets.keys) return { ok: true, skipped: true }; 442 var keys = await navigator.storageBuckets.keys(); 443 var n = 0; 444 for (var i = 0; i < keys.length; i++) { 445 try { await navigator.storageBuckets.delete(keys[i]); n++; } catch (e) {} 446 } 447 return { ok: true, buckets: n }; 448 } catch (e) { return { ok: false, err: String((e && e.message) || e) }; } 449 } 450 451 /* Formalardagi kiritilgan matn. Brauzer "orqaga" bosilganda yoki 452 bfcache'dan tiklaganda maydonlarni O'ZI qayta to'ldiradi â 453 qidiruv so'rovi shu yo'l bilan qaytib chiqishi mumkin edi. */ 454 function wipeFormState() { 455 var out = { fields: 0 }; 456 try { 457 /* ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 458 TARTIB MUHIM. `form.reset()` maydonni BO'SHATMAYDI â u 459 maydonni HTML dagi BOSHLANG'ICH qiymatiga qaytaradi. Ya'ni 460 avval qiymatni tozalab, keyin `reset()` chaqirilsa, matn 461 qaytib keladi va tozalash bekor bo'ladi. 462 463 To'g'ri tartib: avval `reset()`, keyin tozalash. Ustiga 464 `defaultValue` va `value` atributi ham bo'shatiladi â
465 shundagina "orqaga" bosilganda yoki bfcache'dan tiklanganda 466 brauzer eski matnni qayta tiklay olmaydi. 467 ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ */ 468 Array.prototype.forEach.call(document.querySelectorAll('form'), function (f) { 469 try { f.reset(); f.setAttribute('autocomplete', 'off'); } catch (e) {} 470 }); 471 472 var els = document.querySelectorAll('input, textarea, select'); 473 Array.prototype.forEach.call(els, function (el) { 474 try { 475 var t = (el.type || '').toLowerCase(); 476 if (t === 'button' || t === 'submit' || t === 'reset') return; 477 if (el.value) { out.fields++; } 478 el.value = ''; 479 /* boshlang'ich qiymatni ham olib tashlaymiz â aks holda 480 brauzer uni istalgan paytda qaytarib qo'yishi mumkin */ 481 try { el.defaultValue = ''; } catch (e) {} 482 try { el.removeAttribute('value'); } catch (e) {} 483 if (el.tagName === 'TEXTAREA') { try { el.textContent = ''; } catch (e) {} } 484 if (t === 'checkbox' || t === 'radio') { 485 el.checked = false; 486 try { el.defaultChecked = false; } catch (e) {} 487 } 488 if (el.tagName === 'SELECT') { try { el.selectedIndex = -1; } catch (e) {} } 489 /* brauzer avtomatik tiklashiga ham yo'l qo'ymaymiz */ 490 el.setAttribute('autocomplete', 'off'); 491 } catch (e) {} 492 }); 493 } catch (e) {} 494 return { ok: true, fields: out.fields }; 495 } 496 497 var TASKS = [ 498 { id: 'sw', lbl: { l: 'Service Worker', c: 'Service Worker' }, fn: killServiceWorkers, ms: 4000 }, 499 { id: 'caches', lbl: { l: 'Offline kesh', c: 'Offline кеÑ' }, fn: wipeCaches, ms: 5000 }, 500 { id: 'idb', lbl: { l: 'Ichki baza (IndexedDB)',c: 'ÐÑки база (IndexedDB)' }, fn: wipeIndexedDB, ms: 6000 }, 501 { id: 'opfs', lbl: { l: 'Fayl tizimi (OPFS)', c: 'Файл Ñизими (OPFS)' }, fn: wipeOPFS, ms: 5000 }, 502 { id: 'websql', lbl: { l: 'Eski baza (WebSQL)', c: 'ÐÑки база (WebSQL)' }, fn: wipeWebSQL, ms: 3000 }, 503 { id: 'storage', lbl: { l: 'Saqlangan sozlamalar', c: 'СаÒланган ÑозламалаÑ' }, fn: wipeWebStorage, ms: 2000 }, 504 { id: 'cookies', lbl: { l: 'Cookie', c: 'Cookie' }, fn: wipeCookies, ms: 3000 }, 505 { id: 'cred', lbl: { l: 'Hisob va media', c: 'ҲиÑоб ва медиа' }, fn: wipeCredentials, ms: 2500 }, 506 { id: 'mem', lbl: { l: 'Xotiradagi ma\'lumot', c: 'ХоÑиÑадаги маÑлÑмоÑ' }, fn: wipeMemory, ms: 2000 }, 507 /* (v113) yangi qamrov */ 508 { id: 'bucket', lbl: { l: 'Storage Buckets', c: 'Storage Buckets' }, fn: wipeStorageBuckets, ms: 4000 }, 509 { id: 'wname', lbl: { l: 'Yorliq nomi (window.name)', c: 'ÐÑÐ»Ð¸Ò Ð½Ð¾Ð¼Ð¸ (window.name)' }, fn: wipeWindowName, ms: 800 }, 510 { id: 'perf', lbl: { l: 'Yuklanishlar ro\'yxati', c: 'ЮкланиÑÐ»Ð°Ñ ÑÑÐ¹Ñ Ð°Ñи' }, fn: wipePerfTimeline, ms: 1200 }, 511 { id: 'forms', lbl: { l: 'Kiritilgan matnlar', c: 'ÐиÑиÑилган маÑнлаÑ' }, fn: wipeFormState, ms: 1200 }, 512 { id: 'hist', lbl: { l: 'Tarix holati', c: 'ТаÑÐ¸Ñ Ò³Ð¾Ð»Ð°Ñи' }, fn: wipeHistory, ms: 1500 }, 513 { id: 'server', lbl: { l: 'Server buyrug\'i', c: 'СеÑÐ²ÐµÑ Ð±ÑйÑÑÒи' }, fn: purgeViaServer, ms: 5000 }, 514 { id: 'tabs', lbl: { l: 'Boshqa yorliqlar', c: 'ÐоÑÒа ÑÑлиÒлаÑ' }, fn: notifyOtherTabs, ms: 1200 }, 515 ]; 516 517 var MAX_PASSES = 3; 518 519 /* onStep(id, holat, label) â jarayonni ko'rsatish uchun */ 520 async function run(onStep) { 521 var t0 = Date.now(); 522 var report = { passes: [], tasks: {}, before: null, after: null, clean: false, ms: 0 }; 523 524 /* ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
525 (v119) QAT'IY UMUMIY MUDDAT â TELEFON UCHUN 526 ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 527 Har vazifada o'z chegarasi bor edi, lekin UMUMIY chegara yo'q 528 edi. Telefonda (ayniqsa iOS Safari'da) ba'zi qadamlar to'liq 529 bajarilmaydi â `Clear-Site-Data` qo'llab-quvvatlanmaydi, 530 `indexedDB.databases()` yo'q, cookie'lar to'liq o'chmaydi. 531 Shunda `isClean()` hech qachon rost bo'lmaydi va halqa 532 MAX_PASSES marta to'liq aylanardi: foydalanuvchi 10-12 soniya 533 kutib o'tirardi va ilova qotgandek tuyulardi. 534 535 Endi umumiy byudjet bor. U tugasa halqa TO'XTAYDI va chiqish 536 bajariladi. Tozalashning o'zi zarar ko'rmaydi: birinchi 537 bosqichda hamma vazifa allaqachon bir marta ishlagan bo'ladi, 538 keyingi bosqichlar faqat QAYTA urinish edi. */ 539 var BUDGET = 6000; 540 function timeLeft() { return BUDGET - (Date.now() - t0); } 541 542 report.before = await measure(); 543 544 for (var pass = 1; pass <= MAX_PASSES; pass++) { 545 if (pass > 1 && timeLeft() <= 0) { report.timedOut = true; break; } 546 /* 1-bosqich: SW ni birinchi bo'lib yopamiz (u boshqalarni to'sishi mumkin) */ 547 if (pass === 1) { 548 if (onStep) onStep('sw', 'run', TASKS[0].lbl); 549 var swRes = await guard(TASKS[0].fn(), TASKS[0].ms); 550 report.tasks.sw = swRes; 551 if (onStep) onStep('sw', swRes.ok ? 'ok' : 'warn', TASKS[0].lbl); 552 } 553 554 /* 2-bosqich: qolganini PARALLEL bajaramiz â tezlik shundan */ 555 var rest = TASKS.filter(function (t) { return t.id !== 'sw'; }); 556 if (onStep) rest.forEach(function (t) { onStep(t.id, 'run', t.lbl); }); 557 558 var results = await Promise.all(rest.map(function (t) { 559 return guard(t.fn(), t.ms).then(function (r) { return { id: t.id, r: r, lbl: t.lbl }; }); 560 })); 561 results.forEach(function (x) { 562 report.tasks[x.id] = x.r; 563 if (onStep) onStep(x.id, x.r.ok ? 'ok' : 'warn', x.lbl); 564 }); 565 566 /* 3-bosqich: tekshiruv */ 567 var m = await measure(); 568 report.passes.push(m); 569 if (isClean(m)) { report.clean = true; break; } 570 /* toza emas â qisqa tanaffusdan keyin yana urinamiz. 571 Vaqt tugagan bo'lsa qayta urinmaymiz. */ 572 if (timeLeft() <= 300) { report.timedOut = true; break; } 573 await new Promise(function (r) { setTimeout(r, 220); }); 574 } 575 576 report.after = await measure(); 577 report.clean = isClean(report.after); 578 report.ms = Date.now() - t0; 579 return report; 580 } 581 582 /* âââââââââââ 5) TEZKOR CHIQISH (PANIK REJIMI) âââââââââââ 583 Oddiy run() â to'liq, tekshiruvli, foydalanuvchiga hisobot bilan 584 (bir necha soniya davom etadi). Bu esa â zudlik muhim bo'lgan holat 585 uchun: birinchi navbatda DARHOL bajariladigan (sinxron) tozalash, 586 so'ngra orqa fonda davom etadigan (asinxron, kutilmaydigan) tozalash. 587 Chaqiruvchi funksiya natijani KUTMASDAN darhol boshqa sahifaga 588 o'tkazishi mumkin â asinxron vazifalar sahifa almashgandan keyin ham 589 brauzer tomonidan yakunlab qo'yiladi (fetch keepalive, caches/idb 590 operatsiyalari odatda navigatsiyadan keyin ham tugaydi). */ 591 function runPanic() { 592 /* 1) SINXRON â bir zumda, hech qanday kutishsiz bajariladi */ 593 try { wipeWebStorage(); } catch (e) {} 594 try { wipeCookies(); } catch (e) {} 595 try { wipeMemory(); } catch (e) {} 596 /* (v113) sinxron va bir zumda bajariladiganlar â panikda ham kerak */ 597 try { wipeWindowName(); } catch (e) {} 598 try { wipePerfTimeline(); } catch (e) {} 599 try { wipeFormState(); } catch (e) {} 600 try { wipeHistory(); } catch (e) {} 601 try { notifyOtherTabs('panic'); } catch (e) {} 602 603 /* 2) ASINXRON â boshlab qo'yiladi, lekin KUTILMAYDI ("fire-and-forget"). 604 Xatolar batamom yutiladi â bittasi ishlamasa ham chiqishga xalaqit 605 bermaydi. */ 606 try { killServiceWorkers().catch(function () {}); } catch (e) {} 607 try { wipeCaches().catch(function () {}); } catch (e) {} 608 try { wipeIndexedDB().catch(function () {}); } catch (e) {} 609 try { wipeOPFS().catch(function () {}); } catch (e) {}
610 try { purgeViaServer(true).catch(function () {}); } catch (e) {} 611 } 612 613 /* Boshqa yorliqdan kelgan "tozalan" xabarini tinglash */ 614 try { 615 var bcIn = new BroadcastChannel('ti-wipe'); 616 bcIn.onmessage = function (ev) { 617 if (!ev || !ev.data || !ev.data.wipe) return; 618 /* Bu yorliqda ham darhol xotira/storage tozalanadi va sahifa 619 hech narsa ko'rsatmasdan neytral sahifaga o'tkaziladi â foydalanuvchi 620 qaysi yorliqni ko'rayotganidan qat'iy nazar, HAMMA YERDA iz 621 qolmasligi kerak. */ 622 try { wipeMemory(); wipeWebStorage(); wipeCookies(); wipeHistory(); } catch (e) {} 623 try { leaveNoTrace(); } catch (e) {} 624 }; 625 } catch (e) {} 626 627 /* ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 628 (v113) ORQAGA/OLDINGA KESHI (bfcache) â TESHIKNI YOPAMIZ 629 ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 630 Tozalashdan keyin foydalanuvchi neytral sahifaga o'tkaziladi. 631 Lekin brauzer eski sahifani BUTUNLAY XOTIRADA saqlab qo'yishi 632 mumkin (back/forward cache): "orqaga" bosilsa u JS holati bilan 633 birga, hech qanday qayta yuklanishsiz tiklanadi. 634 635 Ya'ni tozalash to'liq ishlaganda ham, bitta "orqaga" bosish 636 ekranga o'qilgan maqolani qaytarib qo'yishi mumkin edi. 637 638 `pageshow` da `persisted === true` aynan shu holatni bildiradi. 639 Bunda sinxron tozalashni QAYTA bajaramiz va sahifani neytral 640 holatga o'tkazamiz. Bayroq `sessionStorage` da emas, oddiy 641 o'zgaruvchida â chunki storage allaqachon tozalangan bo'ladi. */ 642 var wiped = false; 643 try { 644 window.addEventListener('pageshow', function (e) { 645 if (!e || !e.persisted || !wiped) return; 646 try { wipeMemory(); wipeWebStorage(); wipeFormState(); wipeWindowName(); wipePerfTimeline(); } catch (err) {} 647 try { leaveNoTrace(); } catch (err) {} 648 }); 649 } catch (e) {} 650 651 /* ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 652 (v114) CHIQISH â SAHIFANI HAQIQATAN TARK ETISH 653 ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 654 TUZATILGAN XATO. Avvalgi tartib shunday edi: 655 656 location.replace('/privacy-wipe/blank.html'); 657 window.open('', '_self'); 658 window.close(); 659 660 Uchtasi bir vaqtda urinardi va bir-birini buzardi: 661 `location.replace()` navigatsiyani boshlaydi, shundan keyin 662 skript konteksti tugaydi va `window.close()` umuman 663 bajarilmaydi. Natijada varaq OCHIQ qolardi va manzil qatorida 664 `.../privacy-wipe/blank` turardi â ya'ni sayt manzili ko'rinib 665 turardi. Bu aynan iz. 666 667 To'g'ri tartib: 668 1) AVVAL `window.close()`. U faqat skript ochgan varaqda 669 ishlaydi (brauzer qoidasi), lekin ishlagan holda eng toza 670 natija â varaq umuman yo'qoladi. 671 2) Yopilmadi. Endi manzilni NEYTRALLAYMIZ: `about:blank`. 672 Bu brauzerning o'z bo'sh sahifasi â manzil qatorida sayt 673 nomi umuman qolmaydi. 674 3) `about:blank` bloklangan bo'lsa â o'z bo'sh varag'imiz. 675 676 `location.replace()` ATAYLAB (`assign` emas): u tarixga YANGI 677 yozuv qo'shmaydi, balki joriysini almashtiradi. 678 679 â ï¸ CHEGARA: bu brauzerning TARIX MA'LUMOTLAR BAZASIDAN yozuvni 680 o'chirmaydi. Veb-sahifa buni qila olmaydi â bunday API mavjud 681 emas va bo'lmasligi ham kerak (aks holda istalgan sayt sizning 682 butun tarixingizni o'zgartira olardi). Foydalanuvchiga bu ochiq 683 aytiladi (wipe.js). 684 ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ */ 685 function leaveNoTrace() { 686 /* 1) Varaqni yopish */ 687 try { window.close(); } catch (e) {} 688 689 /* 2) Yopilmagan bo'lsa â manzilni neytrallaymiz. 690 Bir kadr kutamiz: `close()` muvaffaqiyatli bo'lsa, quyidagi 691 kod umuman bajarilmaydi. */ 692 setTimeout(function () {
693 try { if (window.closed) return; } catch (e) {} 694 /* Joriy yozuvning manzilini ham neytrallaymiz â bu bir xil 695 origin ichida ruxsat etilgan yagona narsa. */ 696 try { history.replaceState(null, '', '/'); } catch (e) {} 697 /* iOS Safari `about:blank` ga o'tishni JIMGINA e'tiborsiz 698 qoldirishi mumkin â xato ham otmaydi, sahifa ham 699 o'zgarmaydi. Shu sabab urinib ko'ramiz va NATIJANI 700 tekshiramiz: qisqa vaqtdan keyin hali shu yerda bo'lsak, 701 o'z bo'sh varag'imizga o'tamiz (u har joyda ishlaydi). */ 702 var here = location.href; 703 try { location.replace('about:blank'); } catch (e) {} 704 setTimeout(function () { 705 try { 706 if (window.closed) return; 707 if (location.href !== here && location.href.indexOf('about:blank') === 0) return; 708 } catch (e) {} 709 try { location.replace('/privacy-wipe/blank.html'); } catch (e) {} 710 }, 260); 711 }, 50); 712 } 713 714 TI.WIPE = { 715 run: function (onStep) { wiped = true; return run(onStep); }, 716 runPanic: function () { wiped = true; return runPanic(); }, 717 measure: measure, 718 isClean: isClean, 719 detectMode: detectMode, 720 tasks: TASKS, 721 leaveNoTrace: leaveNoTrace, 722 /* alohida chaqirish uchun */ 723 parts: { 724 serviceWorkers: killServiceWorkers, caches: wipeCaches, indexedDB: wipeIndexedDB, 725 opfs: wipeOPFS, webSQL: wipeWebSQL, webStorage: wipeWebStorage, cookies: wipeCookies, 726 credentials: wipeCredentials, memory: wipeMemory, history: wipeHistory, 727 server: purgeViaServer, tabs: notifyOtherTabs, 728 /* (v113) */ 729 storageBuckets: wipeStorageBuckets, windowName: wipeWindowName, 730 perfTimeline: wipePerfTimeline, formState: wipeFormState 731 } 732 }; 733})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.