messaging.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804
  1. /*******************************************************************************
  2. ηMatrix - a browser extension to black/white list requests.
  3. Copyright (C) 2014-2019 Raymond Hill
  4. Copyright (C) 2019-2022 Alessio Vanni
  5. This program is free software: you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation, either version 3 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program. If not, see {http://www.gnu.org/licenses/}.
  15. Home: https://gitlab.com/vannilla/ematrix
  16. uMatrix Home: https://github.com/gorhill/uMatrix
  17. */
  18. 'use strict';
  19. (function () {
  20. Cu.import('chrome://ematrix/content/lib/UriTools.jsm');
  21. Cu.import('chrome://ematrix/content/lib/Tools.jsm');
  22. Cu.import('chrome://ematrix/content/lib/RowSnapshot.jsm');
  23. let ηm = ηMatrix;
  24. // I personally find this method better than a giant (or multiple
  25. // giant) switch statement(s), but all things considered it's not
  26. // as nice as when the language has proper macros. The idea is to
  27. // make a more flexible system, at the cost of a slightly more
  28. // verbose code and a bit more memory usage due to the new
  29. // function objects.
  30. // Method tables.
  31. // "Early" is for those methods that do not call the callback.
  32. let methods = {};
  33. let methodsEarly = {};
  34. // The message queue callback.
  35. let dispatchMethod = function (request, sender, cb) {
  36. let f = methods[request.what];
  37. let early = false;
  38. if (!f) {
  39. f = methodsEarly[request.what];
  40. if (!f) {
  41. return vAPI.messaging.UNHANDLED;
  42. }
  43. early = true;
  44. }
  45. let response = f(request, sender, cb);
  46. if (early === true) {
  47. return response;
  48. }
  49. cb(response);
  50. };
  51. // Used here to add dispatchable functions
  52. let addMethod = function (name, f, /* &optional */ early) {
  53. if (early) {
  54. methodsEarly[name] = f;
  55. } else {
  56. methods[name] = f;
  57. }
  58. }
  59. // Default
  60. addMethod('getAssetContent', function (request, sender, cb) {
  61. ηm.assets.get(request.url, {
  62. dontCache: true,
  63. }, cb);
  64. return undefined;
  65. }, true);
  66. addMethod('selectHostsFiles', function (request, sender, cb) {
  67. ηm.selectHostsFiles(request, cb);
  68. return undefined;
  69. }, true);
  70. addMethod('forceReloadTab', function (request, sender, cb) {
  71. ηm.forceReload(request.tabId, request.bypassCache);
  72. return undefined;
  73. });
  74. addMethod('forceUpdateAssets', function (request, sender, cb) {
  75. ηm.scheduleAssetUpdater(0);
  76. ηm.assets.updateStart({
  77. delay: 1000,
  78. });
  79. return undefined;
  80. });
  81. addMethod('getUserSettings', function (request, sender, cb) {
  82. let pmat = ηm.pMatrix;
  83. return {
  84. userSettings: ηm.userSettings,
  85. matrixSwitches: {
  86. 'https-strict': (pmat.evaluateSwitch('https-strict', '*')
  87. === 1),
  88. 'referrer-spoof': (pmat.evaluateSwitch('referrer-spoof', '*')
  89. === 1),
  90. 'noscript-spoof': (pmat.evaluateSwitch('noscript-spoof', '*')
  91. === 1),
  92. },
  93. };
  94. });
  95. addMethod('gotoExtensionURL', function (request, sender, cb) {
  96. Tools.gotoExtensionURL({
  97. api: vAPI,
  98. details: request,
  99. matrix: ηm,
  100. });
  101. return undefined;
  102. });
  103. addMethod('gotoURL', function (request, sender, cb) {
  104. Tools.gotoURL({
  105. api: vAPI,
  106. details: request,
  107. });
  108. return undefined;
  109. });
  110. addMethod('mustBlock', function (request, sender, cb) {
  111. return ηm.mustBlock(request.scope,
  112. request.hostname,
  113. request.type);
  114. });
  115. addMethod('readRawSettings', function (request, sender, cb) {
  116. return ηm.stringFromRawSettings();
  117. });
  118. addMethod('writeRawSettings', function (request, sender, cb) {
  119. ηm.rawSettingsFromString(request.content);
  120. return undefined;
  121. });
  122. addMethod('reloadHostsFiles', function (request, sender, cb) {
  123. ηm.reloadHostsFiles();
  124. return undefined;
  125. });
  126. addMethod('setMatrixSwitch', function (request, sender, cb) {
  127. ηm.tMatrix.setSwitch(request.switchName, '*', request.state);
  128. if (ηm.pMatrix.setSwitch(request.switchName, '*', request.state)) {
  129. ηm.saveMatrix();
  130. }
  131. return undefined;
  132. });
  133. addMethod('userSettings', function (request, sender, cb) {
  134. if (request.hasOwnProperty('value') === false) {
  135. request.value = undefined;
  136. }
  137. return ηm.changeUserSettings(request.name, request.value);
  138. });
  139. vAPI.messaging.setup(dispatchMethod);
  140. // popup.js begins here
  141. addMethod('matrixSnapshot', function (request, sender, cb) {
  142. let snapShot = function (store, details) {
  143. let user = ηm.userSettings;
  144. let indices = ηm.Matrix.columnHeaderIndices;
  145. let r = {
  146. appVersion: vAPI.app.version,
  147. blockedCount: store.requestStats.blocked.all,
  148. collapseAllDomains: user.popupCollapseAllDomains,
  149. collapseBlacklistedDomains: user.popupCollapseBlacklistedDomains,
  150. diff: [],
  151. domain: store.pageDomain,
  152. has3pReferrer: store.has3pReferrer,
  153. hasMixedContent: store.hasMixedContent,
  154. hasNoscriptTags: store.hasNoscriptTags,
  155. hasWebWorkers: store.hasWebWorkers,
  156. headerIndices: Array.from(indices),
  157. hostname: store.pageHostname,
  158. mtxContentModified: (store.mtxContentModifiedTime
  159. !== details.mtxContentModifiedTime),
  160. mtxCountModified: (store.mtxCountModifiedTime
  161. !== details.mtxCountModifiedTime),
  162. mtxContentModifiedTime: store.mtxContentModifiedTime,
  163. mtxCountModifiedTime: store.mtxCountModifiedTime,
  164. pMatrixModified: (ηm.pMatrix.modifiedTime
  165. !== details.pMatrixModifiedTime),
  166. pMatrixModifiedTime: ηm.pMatrix.modifiedTime,
  167. pSwitches: {},
  168. rows: {},
  169. rowCount: 0,
  170. scope: '*',
  171. tabId: store.tabId,
  172. tMatrixModified: (ηm.tMatrix.modifiedTime
  173. !== details.tMatrixModifiedTime),
  174. tMatrixModifiedTime: ηm.tMatrix.modifiedTime,
  175. tSwitches: {},
  176. url: store.pageUrl,
  177. userSettings: {
  178. colorBlindFriendly: user.colorBlindFriendly,
  179. displayTextSize: user.displayTextSize,
  180. popupScopeLevel: user.popupScopeLevel,
  181. },
  182. };
  183. if (typeof details.scope === 'string') {
  184. r.scope = details.scope;
  185. } else if (user.popupScopeLevel === 'site') {
  186. r.scope = r.hostname;
  187. } else if (user.popupScopeLevel === 'domain') {
  188. r.scope = r.domain;
  189. }
  190. for (let s of ηm.Matrix.switchNames) {
  191. r.tSwitches[s] = ηm.tMatrix.evaluateSwitchZ(s, r.scope);
  192. r.pSwitches[s] = ηm.pMatrix.evaluateSwitchZ(s, r.scope);
  193. }
  194. r.rows['*'] = new RowSnapshot(ηm, r.scope, '*', '*');
  195. r.rows['1st-party'] = new RowSnapshot(ηm, r.scope,
  196. '1st-party', '1st-party');
  197. r.rowCount += 1;
  198. let any = indices.get('*');
  199. for (let e of store.hostnameTypeCells) {
  200. let pos = e[0].indexOf(' ');
  201. let reqhn = e[0].slice(0, pos);
  202. let reqt = e[0].slice(pos+1);
  203. // Hostname can be empty in some cases
  204. // (reported from uMatrix)
  205. if (reqhn === '') {
  206. reqhn = store.pageHostname;
  207. }
  208. let reqd = UriTools.domainFromHostname(reqhn) || reqhn;
  209. let desthn = reqhn;
  210. while (true) {
  211. if (r.rows.hasOwnProperty(desthn) !== false) {
  212. break;
  213. }
  214. r.rows[desthn] = new RowSnapshot(ηm,
  215. r.scope,
  216. desthn,
  217. reqd);
  218. r.rowCount += 1;
  219. if (desthn === reqd) {
  220. break;
  221. }
  222. pos = desthn.indexOf('.');
  223. if (pos === -1) {
  224. break;
  225. }
  226. desthn = desthn.slice(pos + 1);
  227. }
  228. let count = e[1].size;
  229. let tindex = indices.get(reqt);
  230. let row = r.rows[reqhn];
  231. row.counts[tindex] += count;
  232. row.counts[any] += count;
  233. row = r.rows[reqd];
  234. row.totals[tindex] += count;
  235. row.totals[any] += count;
  236. row = r.rows['*'];
  237. row.totals[tindex] += count;
  238. row.totals[any] += count;
  239. }
  240. r.diff = ηm.tMatrix.diff(ηm.pMatrix,
  241. r.hostname,
  242. Object.keys(r.rows));
  243. return r;
  244. };
  245. let snapFromId = function (details, cb) {
  246. let snapIf = function (id, details) {
  247. let store = ηm.pageStoreFromTabId(id);
  248. if (store === null) {
  249. cb('ENOTFOUND');
  250. return;
  251. }
  252. let tmat = ηm.tMatrix;
  253. let pmat = ηm.pMatrix;
  254. let mtx = details.mtxContentModifiedTime;
  255. if (tmat.modifiedTime === details.tMatrixModifiedTime
  256. && pmat.modifiedTime === details.pMatrixModifiedTime
  257. && store.mtxContentModifiedTime === mtx
  258. && store.mtxCountModifiedTime === mtx) {
  259. cb('ENOCHANGE');
  260. return;
  261. }
  262. cb(snapShot(store, details));
  263. };
  264. if (details.tabId) {
  265. snapIf(details.tabId, details);
  266. return;
  267. }
  268. let onReady = function (tab) {
  269. if (tab instanceof Object === false) {
  270. cb('ENOTFOUND');
  271. return;
  272. }
  273. let id =
  274. tab.url.lastIndexOf(vAPI.getURL('dashboard.html'), 0) !== 0
  275. ? tab.id
  276. : vAPI.noTabId;
  277. snapIf(id, details);
  278. };
  279. vAPI.tabs.get(null, onReady);
  280. };
  281. snapFromId(request, cb);
  282. return undefined;
  283. }, true);
  284. addMethod('toggleMatrixSwitch', function (request, sender, cb) {
  285. let sz = ηm.tMatrix.evaluateSwitchZ(request.switchName,
  286. request.srcHostname);
  287. ηm.tMatrix.setSwitchZ(request.switchName,
  288. request.srcHostname,
  289. sz === false);
  290. return undefined;
  291. });
  292. addMethod('blacklistMatrixCell', function (request, sender, cb) {
  293. ηm.tMatrix.blacklistCell(request.srcHostname,
  294. request.desHostname,
  295. request.type);
  296. return undefined;
  297. });
  298. addMethod('whitelistMatrixCell', function (request, sender, cb) {
  299. ηm.tMatrix.whitelistCell(request.srcHostname,
  300. request.desHostname,
  301. request.type);
  302. return undefined;
  303. });
  304. addMethod('graylistMatrixCell', function (request, sender, cb) {
  305. ηm.tMatrix.graylistCell(request.srcHostname,
  306. request.desHostname,
  307. request.type);
  308. return undefined;
  309. });
  310. addMethod('applyDiffToPermanentMatrix', function (request, sender, cb) {
  311. if (ηm.pMatrix.applyDiff(request.diff, ηm.tMatrix)) {
  312. ηm.saveMatrix();
  313. }
  314. return undefined;
  315. });
  316. addMethod('applyDiffToTemporaryMatrix', function (request, sender, cb) {
  317. ηm.tMatrix.applyDiff(request.diff, ηm.pMatrix);
  318. return undefined;
  319. });
  320. addMethod('revertTemporaryMatrix', function (request, sender, cb) {
  321. ηm.tMatrix.assign(ηm.pMatrix);
  322. return undefined;
  323. });
  324. vAPI.messaging.listen('popup.js', dispatchMethod);
  325. // Content scripts handling begins here
  326. let placeholders = undefined;
  327. let phReadTime = 0;
  328. addMethod('contentScriptHasLocalStorage', function (request, sender, cb) {
  329. let contentScriptLocalStorageHandler = function (id, originURL) {
  330. let tabContext = ηm.tabContextManager.lookup(id);
  331. if (tabContext === null) {
  332. return;
  333. }
  334. let blocked = ηm.mustBlock(tabContext.rootHostname,
  335. UriTools.hostnameFromURI(originURL),
  336. 'cookie');
  337. let store = ηm.pageStoreFromTabId(id);
  338. if (store !== null) {
  339. let requestURL = originURL + '/{localStorage}';
  340. store.recordRequest('cookie', requestURL, blocked);
  341. ηm.logger.writeOne(id, 'net', tabContext.rootHostname,
  342. requestURL, 'cookie', blocked);
  343. }
  344. let removeStorage = blocked && ηm.userSettings.deleteLocalStorage;
  345. if (removeStorage) {
  346. ηm.localStorageRemovedCounter++;
  347. }
  348. return removeStorage;
  349. };
  350. let tabId = sender && sender.tab ? sender.tab.id || 0 : 0;
  351. return contentScriptLocalStorageHandler(tabId, request.originURL);
  352. });
  353. addMethod('lookupBlockedCollapsibles', function (request, sender, cb) {
  354. let lookupBlockedCollapsibles = function (id, requests) {
  355. if (phReadTime < ηm.rawSettingsWriteTime) {
  356. placeholders = undefined;
  357. }
  358. if (placeholders === undefined) {
  359. placeholders = {
  360. frame: ηm.rawSettings.framePlaceholder,
  361. image: ηm.rawSettings.imagePlaceholder,
  362. };
  363. if (placeholders.frame) {
  364. let doc = ηm.rawSettings.framePlaceholderDocument;
  365. let bg = ηm.rawSettings.framePlaceholderBackground;
  366. placeholders.frameDocument =
  367. doc.replace('{{bg}}',
  368. bg !== 'default'
  369. ? bg
  370. : ηm.rawSettings.placeHolderBackground);
  371. }
  372. if (placeholders.image) {
  373. placeholders.imageBorder =
  374. ηm.rawSettings.imagePlaceholderBorder !== 'default'
  375. ? ηm.rawSettings.imagePlaceholderBorder
  376. : ηm.rawSettings.placeholderBorder;
  377. placeholders.imageBackground =
  378. ηm.rawSettings.imagePlaceholderBackground !== 'default'
  379. ? ηm.rawSettings.imagePlaceholderBackground
  380. : ηm.rawSettings.placeholderBackground;
  381. }
  382. phReadTime = Date.now();
  383. }
  384. let response = {
  385. blockedResources: [],
  386. hash: requests.hash,
  387. id: requests.id,
  388. placeholders: placeholders,
  389. };
  390. let context = ηm.tabContextManager.lookup(id);
  391. if (context === null) {
  392. return response;
  393. }
  394. let store = ηm.pageStoreFromTabId(id);
  395. if (store !== null) {
  396. store.lookupBlockedCollapsibles(requests, response);
  397. }
  398. return response;
  399. };
  400. let tabId = sender && sender.tab ? sender.tab.id || 0 : 0;
  401. return lookupBlockedCollapsibles(tabId, request);
  402. });
  403. addMethod('mustRenderNoscriptTags?', function (request, sender, cb) {
  404. let tabId = sender && sender.tab ? sender.tab.id || 0 : 0;
  405. let tabContext = ηm.tabContextManager.lookup(tabId);
  406. let rootHostname = tabContext && tabContext.rootHostname;
  407. let pageStore = ηm.pageStoreFromTabId(tabId);
  408. if (tabContext === null) {
  409. return undefined;
  410. }
  411. let response =
  412. ηm.tMatrix.mustBlock(rootHostname, rootHostname, 'script')
  413. && ηm.tMatrix.evaluateSwitchZ('noscript-spoof', rootHostname);
  414. if (pageStore !== null) {
  415. pageStore.hasNoscriptTags = true;
  416. }
  417. // https://github.com/gorhill/uMatrix/issues/225
  418. // A good place to force an update of the page title, as
  419. // at this point the DOM has been loaded.
  420. ηm.updateTitle(tabId);
  421. return response;
  422. });
  423. addMethod('securityPolicyViolation', function (request, sender, cb) {
  424. let foundInlineCode = function (id, store, details, type) {
  425. if (store === null) {
  426. return;
  427. }
  428. let pageHostname = store.pageHostname;
  429. let uri = UriTools.set(details.documentURI);
  430. let frameURL = UriTools.normalizedURI();
  431. let blocked = details.blocked;
  432. if (blocked === undefined) {
  433. blocked = ηm.mustBlock(pageHostname, uri.hostname, type);
  434. }
  435. let mapTo = {
  436. css: 'style',
  437. script: 'script',
  438. };
  439. // https://github.com/gorhill/httpswitchboard/issues/333
  440. // Look-up here whether inline scripting is blocked for the frame.
  441. let url = frameURL + '{inline_' + mapTo[type] + '}';
  442. store.recordRequest(type, url, blocked);
  443. ηm.logger.writeOne(id, 'net', pageHostname, url, type, blocked);
  444. };
  445. let tabId = sender && sender.tab ? sender.tab.id || 0 : 0;
  446. let tabContext = ηm.tabContextManager.lookup(tabId);
  447. let rootHostname = tabContext && tabContext.rootHostname;
  448. let pageStore = ηm.pageStoreFromTabId(tabId);
  449. if (request.directive === 'worker-src') {
  450. let url = UriTools.hostnameFromURI(request.blockedURI) !== ''
  451. ? request.blockedURI
  452. : request.documentURI;
  453. if (pageStore !== null) {
  454. pageStore.hasWebWorkers = true;
  455. pageStore.recordRequest('script', url, request.blocked);
  456. }
  457. if (tabContext !== null) {
  458. ηm.logger.writeOne(tabId, 'net', rootHostname,
  459. url, 'worker', request.blocked);
  460. }
  461. } else if (request.directive === 'script-src') {
  462. foundInlineCode(tabId, pageStore, request, 'script');
  463. } else if (request.directive === 'style-src') {
  464. foundInlineCode(tabId, pageStore, request, 'css');
  465. }
  466. return undefined;
  467. });
  468. addMethod('shutdown?', function (request, sender, cb) {
  469. let tabId = sender && sender.tab ? sender.tab.id || 0 : 0;
  470. let tabContext = ηm.tabContextManager.lookup(tabId);
  471. let rootHostname = tabContext && tabContext.rootHostname;
  472. let response = undefined;
  473. if (tabContext !== null) {
  474. response =
  475. ηm.tMatrix.evaluateSwitchZ('matrixb-off', rootHostname);
  476. }
  477. return response;
  478. });
  479. vAPI.messaging.listen('contentscript.js', dispatchMethod);
  480. // cloud-ui.js begins here
  481. addMethod('cloudGetOptions', function (request, sender, cb) {
  482. vAPI.cloud.getOptions(function (options) {
  483. options.enabled = ηm.userSettings.cloudStorageEnabled === true;
  484. cb(options);
  485. });
  486. return undefined;
  487. }, true);
  488. addMethod('cloudSetOptions', function (request, sender, cb) {
  489. vAPI.cloud.setOptions(request.options, cb);
  490. return undefined;
  491. }, true);
  492. addMethod('cloudPull', function (request, sender, cb) {
  493. return vAPI.cloud.pull(request.datakey, cb);
  494. }, true);
  495. addMethod('cloudPush', function (request, sender, cb) {
  496. return vAPI.cloud.push(request.datakey, request.data, cb);
  497. }, true);
  498. vAPI.messaging.listen('cloud-ui.js', dispatchMethod);
  499. // user-rules.js begins here
  500. addMethod('getUserRules', function (request, sender, cb) {
  501. return {
  502. temporaryRules: ηm.tMatrix.toString(),
  503. permanentRules: ηm.pMatrix.toString(),
  504. };
  505. });
  506. addMethod('setUserRules', function (request, sender, cb) {
  507. if (typeof request.temporaryRules === 'string') {
  508. ηm.tMatrix.fromString(request.temporaryRules);
  509. }
  510. if (typeof request.permanentRules === 'string') {
  511. ηm.pMatrix.fromString(request.permanentRules);
  512. ηm.saveMatrix();
  513. }
  514. return {
  515. temporaryRules: ηm.tMatrix.toString(),
  516. permanentRules: ηm.pMatrix.toString(),
  517. };
  518. });
  519. vAPI.messaging.listen('user-rules.js', dispatchMethod);
  520. // hosts-files.js begins here
  521. addMethod('getLists', function (request, sender, cb) {
  522. let prepare = function (entries) {
  523. for (let e in entries) {
  524. if (entries.hasOwnProperty(e) === false) {
  525. continue;
  526. }
  527. let entry = entries[e];
  528. if (typeof entry.homeURL === 'string') {
  529. let homehost = UriTools.hostnameFromURI(entry.homeURL);
  530. entry.homeHostname = homehost
  531. entry.homeDomain = UriTools.domainFromHostname(homehost);
  532. }
  533. }
  534. };
  535. let getLists = function (cb) {
  536. let r = {
  537. autoUpdate: ηm.userSettings.autoUpdate,
  538. available: null,
  539. cache: null,
  540. current: ηm.liveHostsFiles,
  541. blockedHostnameCount: ηm.ubiquitousBlacklist.count,
  542. };
  543. let onMetadataReady = function (entries) {
  544. r.cache = entries;
  545. prepare(r.cache);
  546. cb(r);
  547. };
  548. let onHostsReady = function (lists) {
  549. r.available = lists;
  550. prepare(r.available);
  551. ηm.assets.metadata(onMetadataReady);
  552. };
  553. ηm.getAvailableHostsFiles(onHostsReady);
  554. };
  555. return getLists(cb);
  556. }, true);
  557. addMethod('purgeCache', function (request, sender, cb) {
  558. ηm.assets.purge(request.assetKey);
  559. ηm.assets.remove('cache/' + request.assetKey);
  560. return undefined;
  561. });
  562. addMethod('purgeAllCaches', function (request, sender, cb) {
  563. if (request.hard) {
  564. ηm.assets.remove(/./);
  565. } else {
  566. ηm.assets.purge(/./, 'public_suffix_list.dat');
  567. }
  568. return undefined;
  569. });
  570. vAPI.messaging.listen('hosts-files.js', dispatchMethod);
  571. // about.js begins here
  572. addMethod('getAllUserData', function (request, sender, cb) {
  573. return {
  574. app: vAPI.app.name,
  575. version: vAPI.app.version,
  576. when: Date.now(),
  577. settings: ηm.userSettings,
  578. rules: ηm.pMatrix.toString(),
  579. hostsFiles: ηm.liveHostsFiles,
  580. rawSettings: ηm.rawSettings,
  581. };
  582. });
  583. addMethod('getSomeStats', function (request, sender, cb) {
  584. return {
  585. version: vAPI.app.version,
  586. storageUsed: ηm.storageUsed
  587. };
  588. });
  589. addMethod('restoreAllUserData', function (request, sender, cb) {
  590. let restoreData = function (data) {
  591. let countdown = 4;
  592. let onCountdown = function () {
  593. countdown -= 1;
  594. if (countdown === 0) {
  595. vAPI.app.restart();
  596. }
  597. };
  598. let onAllRemoved = function () {
  599. vAPI.storage.set(data.settings, onCountdown);
  600. vAPI.storage.set({
  601. userMatrix: data.rules,
  602. }, onCountdown);
  603. vAPI.storage.set({
  604. liveHostsFiles: data.hostsFiles,
  605. }, onCountdown);
  606. if (data.rawSettings instanceof Object) {
  607. ηMatrix.saveRawSettings(data.rawSettings, onCountdown);
  608. }
  609. };
  610. // If we are going to restore all, might as well wipe out
  611. // clean local storage
  612. ηm.XAL.keyvalRemoveAll(onAllRemoved);
  613. };
  614. restoreData(request.userData);
  615. return undefined;
  616. });
  617. addMethod('resetAllUserData', function (request, sender, cb) {
  618. let onAllRemoved = function () {
  619. vAPI.app.restart();
  620. };
  621. ηm.XAL.keyvalRemoveAll(onAllRemoved);
  622. /* Let's also clear the database, just to really make it a reset */
  623. ηm.assets.rmrf();
  624. return undefined;
  625. });
  626. vAPI.messaging.listen('about.js', dispatchMethod);
  627. // logger-ui.js begins here
  628. let loggerURL = vAPI.getURL('logger-ui.html');
  629. addMethod('readMany', function (request, sender, cb) {
  630. if (ηm.logger.ownerId !== undefined
  631. && request.ownerId !== ηm.logger.ownerId) {
  632. return {
  633. unavailable: true,
  634. };
  635. }
  636. let tabIds = {};
  637. for (let id in ηm.pageStores) {
  638. let store = ηm.pageStoreFromTabId(id);
  639. if (store === null) {
  640. continue;
  641. }
  642. if (store.rawUrl.startsWith(loggerURL)) {
  643. continue;
  644. }
  645. tabIds[id] = store.title || store.rawUrl;
  646. }
  647. return {
  648. colorBlind: false,
  649. entries: ηm.logger.readAll(request.ownerId),
  650. maxLoggedRequests: ηm.userSettings.maxLoggedRequests,
  651. noTabId: vAPI.noTabId,
  652. tabIds: tabIds,
  653. tabIdsToken: ηm.pageStoresToken,
  654. };
  655. });
  656. addMethod('releaseView', function (request, sender, cb) {
  657. if (request.ownerId === ηm.logger.ownerId) {
  658. ηm.logger.ownerId = undefined;
  659. }
  660. return undefined;
  661. });
  662. vAPI.messaging.listen('logger-ui.js', dispatchMethod);
  663. })();