-
Notifications
You must be signed in to change notification settings - Fork 1
/
background.ts
116 lines (104 loc) · 4.04 KB
/
background.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/**
* `background.ts` is where the adblocker actually lives. It is started once
* and keeps the state in memory. From there we can monitor network requests
* using the webRequest API and communicate with the `content-script.ts` to
* specify which actions should be taken (e.g.: injecting custom stylesheets or
* scriptlets in pages).
*/
import { get, set } from 'idb-keyval';
import { browser } from 'webextension-polyfill-ts';
import { Badge } from '@remusao/badger';
import { WebExtensionBlocker, fullLists } from '@cliqz/adblocker-webextension';
function disable(
blocker: WebExtensionBlocker,
incrementBlockedCounter: (_: { tabId: number }) => void,
) {
blocker.disableBlockingInBrowser(browser);
blocker.unsubscribe('request-blocked', incrementBlockedCounter);
blocker.unsubscribe('request-redirected', incrementBlockedCounter);
}
function enable(
blocker: WebExtensionBlocker,
incrementBlockedCounter: (_: { tabId: number }) => void,
) {
blocker.enableBlockingInBrowser(browser);
blocker.on('request-blocked', incrementBlockedCounter);
blocker.on('request-redirected', incrementBlockedCounter);
}
async function load(): Promise<WebExtensionBlocker> {
try {
const serialized = await get('engine');
if (serialized !== undefined) {
return WebExtensionBlocker.deserialize(serialized);
}
} catch (ex) {
/* No valid cached engine */
}
return WebExtensionBlocker.deserialize(
new Uint8Array(
await (await fetch(browser.runtime.getURL('engine.bin'))).arrayBuffer(),
),
);
}
(async () => {
let blocker = WebExtensionBlocker.empty();
const badge = new Badge({
badgeTextColor: 'white',
badgeBackgroundColor: [0, 174, 240, 255],
iconDisabled: './icons/icon-off.png',
iconEnabled: './icons/icon-o-0.png',
// NOTE: disable animated icon for now.
// [
// './icons/icon-o-0.png',
// './icons/icon-o-1.png',
// './icons/icon-o-3.png',
// './icons/icon-o-5.png',
// './icons/icon-o-6.png',
// ],
minimumUpdateLatency: 300,
});
const incrementBlockedCounter = ({ tabId }: { tabId: number }) =>
badge.incr(tabId);
badge.enable();
enable(blocker, incrementBlockedCounter);
// Handle toggling of blocking based on clicking on the icon. The behavior is
// currently to disable or enable the adblocker globally (and not on a per-tab
// basis as might be expected); this is in line with the bare-bone spirit of
// this extension.
browser.browserAction.onClicked.addListener(async () => {
if (blocker.isBlockingEnabled(browser)) {
badge.disable();
disable(blocker, incrementBlockedCounter);
} else {
badge.enable();
enable(blocker, incrementBlockedCounter);
}
});
// Handle hot-swapping an adblocker instance for another. It will gracefully
// enable blocking with the new instance and disable the previous one. The new
// instance is then stored globally in `blocker`.
const upgrade = (newBlocker: WebExtensionBlocker) => {
// We only enable blocking with newBlocker if we were already blocking in
// `browser`. This allows to make sure we respect the toggling ON/OFF of the
// adblocker, even on updates.
if (blocker.isBlockingEnabled(browser)) {
enable(newBlocker, incrementBlockedCounter);
disable(blocker, incrementBlockedCounter);
}
// Keep new instance globally (and garbage collect previous one).
blocker = newBlocker;
};
// Load from cache (IndexedBD) or pre-built in extension (a serialized engine
// is shipped as part of the XPI and allows to initialize the adblocker very
// fast on cold start). This allows to start the extension in less than 200ms.
upgrade(await load());
// Update from remote lists, we then wait a few seconds (~5 seconds) and
// attempt a full update of the engine based on remote lists. This usually
// takes a couple of seconds, mostly to fetch the resources.
setTimeout(async () => {
upgrade(
await WebExtensionBlocker.fromLists(fetch, fullLists, blocker.config),
);
await set('engine', blocker.serialize());
}, 5000);
})();