eyeo's Web Extension Ad Blocking Toolkit
This is a library that provides integration of eyeo's Ad Blocking Core
for Chromium and Firefox extensions (like Adblock Plus). The Ad
Blocking Core is in the core
directory. See the content of that directory
for further information.
Code of Conduct
All contributors to this project are required to read, and follow, our
code of conduct.
Getting started
The library comes in two parts, ewe-api.js
to be included in the extension's
background page, and ewe-content.js
to be loaded as a content script. Please
download the latest build (or build the library yourself).
With two versions of the API, Manifest V2 and Manifest V3, there are
two different manifest that are needed depending on which API you
target.
Supported browsers
The webext-sdk is tested on the following minimum versions:
Manifest V2:
- Chromium 77
- Firefox 68
- Edge 79
Manifest V3:
Manifest for V2
For Manifest V2, the extension's manifest.json
is required to
include the following configuration:
{
"manifest_version": 2,
"background": {
"scripts": [
"ewe-api.js"
]
},
"content_scripts": [
{
"all_frames": true,
"js": [
"ewe-content.js"
],
"match_about_blank": true,
"matches": [
"http://*/*",
"https://*/*"
],
"run_at": "document_start"
}
],
"permissions": [
"webNavigation",
"webRequest",
"webRequestBlocking",
"storage",
"unlimitedStorage",
"tabs",
"<all_urls>"
]
}
Manifest for V3
For Manifest V3, the extension's manifest.json
is required to
include the following configuration:
{
"manifest_version": 3,
"background": {
"service_worker": "background.js"
},
"content_scripts": [
{
"all_frames": true,
"js": [
"ewe-content.js"
],
"match_about_blank": true,
"matches": [
"http://*/*",
"https://*/*"
],
"run_at": "document_start"
}
],
"permissions": [
"declarativeNetRequest",
"scripting",
"storage",
"tabs",
"webNavigation",
"webRequest",
"unlimitedStorage"
],
"host_permissions": [
"<all_urls>"
],
"declarative_net_request": <output from "subs-generate" script>
}
The example above requires a couple of changes and can't be used
as-is.
The service_worker
value needs be set to your built file for the
background script, that includes ewe-api.js
.
Please note that for the sample above, you need to make sure to set
the value of declarative_net_request
properly, as shown in the
decalrativeNetRequest
documentation.
This mean you also need to add to your extension build the files that contains
the rulesets declared in this section, as well as the text filter lists. Refer
to the Manifest V3 documentation for more details.
The permission declarativeNetRequestWithHostAccess
requires the
host_permissions
to be <all_urls>
. You could use the
declarativeNetRequest
permission without setting
host_permissions
. But it would have the effect of preventing the
filtering of content and limiting the blocking to network requests to
those specified in host_permissions
. The default configuration
provided offers the most functionality.
Required permissions and why we need them
We require several permissions for the SDK to function correctly. The manifest
file templates above include the required permissions. Here is why we need each
one:
webNavigation
: Gives access to the Web Navigation API, which we use to
apply document-level allowing filters and to block popups.webRequest
: Gives access to the Web Request API. Used to apply URL filters
in MV2, and to report on URL filters in MV3. Also used to retrieve sitekeys
for a site.webRequestBlocking
(MV2 only): Allows blocking request based on URL filters
in MV2.declarativeNetRequest
(MV3 only): Gives access to the Declarative Net
Request API, which we use to apply URL filters in MV3.storage
: Gives access to storage APIs, which we use to store downloaded
subscriptions, user's custom filters, etc.unlimitedStorage
: By default, extensions are only allowed 5MB of storage,
which isn't enough for larger subscriptions. This permission removes that
limit.tabs
: Gives access to some tab metadata, including the tab's URL, which is
used to apply document-level allowing filters to the tab.scripting
(MV3 only): Used to apply content filters, including element
hiding filters and snippet filters.<all_urls>
: Allows the SDK to act on all websites. Note that in MV2
manifests this goes in the permissions
, but in MV3 manifests this goes in
the new host_permissions
section.
You can read more about browser extension permissions and their effects in
Google's docs for
MV2 permissions
and MV3 permissions
API
The API will be available in your own background scripts through the
global EWE
object. Please call EWE.start()
to start blocking ads.
Note that in MV3 extensions, EWE.start()
must be called in the first
turn of the event loop so that it can attach event listeners.
Module bundlers (optional)
ewe-api.js
is built as a UMD module (Universal Module Definition),
and so it can also be used with module bundlers.
If using a module bundler do not add ewe-api.js
to your manifest.json
.
Consequently, there won't be a global EWE
object.
CommonJS
const EWE = require("@eyeo/webext-sdk");
EWE.start();
ESM
import * as EWE from "@eyeo/webext-sdk";
EWE.start();
Snippet filters support
In order to enable support for snippet filters you have to get
the snippets library separately and make it available to EWE
:
import isolatedCode from "mv3.isolated.mjs";
import injectedCode from "mv3.injected.mjs";
EWE.snippets.setLibrary({isolatedCode, injectedCode});
Note mv3...
artifacts are required to be used for both MV2 and MV3.
The integration of the machine learning models is expected to be done by clients
of the snippet library.
Shared resources
There are some shared resources that are used by both webext-sdk & production code:
browser
- Global is set by webextension-polyfill version 0.8.0.
browser.runtime.connect()
/browser.runtime.onConnect
- Channel name is prefixed with "ewe:".
browser.runtime.sendMessage()
/browser.runtime.onMessage
- Our messages are objects with a "type" property whose value is prefixed with
"ewe:".
indexedDB.open()
- Database name is prefixed with "EWE".
- Web page links
browser.storage.local
and browser.storage.session
- Storage keys are prefixed with either "ewe:" or "abp:pref:".
During initialization webext-sdk migrates legacy data from local storage to
indexedDB. Files migrated have to be prefixed: file:
. Files prefixed with
file:///
will be ignored.
Notifications support
Using the notifications module is optional. To start
using it, an initialisation is required:
EWE.notifications.start();
One Click Allowlisting support
To enable One Click Allowlisting, you need to set the list of
authorized public keys that can be used to authenticate allowlisting
requests.
EWE.allowlisting.setAuthorizedKeys(keys);
See the allowlisting module docs for more
detail.
New keypairs can be created with the correct algorithm and settings by
using our keypair creation script.
npm run create-allowlisting-keypair
See the Development section below for details on running our scripts
and other EWE development tasks. Keys can also be generated using
other programs like OpenSSL. The keys use the RSASSA-PKCS1-v1_5
algorithm, SHA512 hash and 4096 bit long modulus. Additionally, when
passed to setAuthorizedKeys
, the keys should be base64 encoded
strings, in SPKI format.
Documentation
For more information, please refer to the API documention.
Development
Tested Browsers
The CI pipeline performs automated tests on the following browser versions:
- Manifest v2: Chromium: 77 - 109
- Manifest v3: Chromium 111
- Firefox: 68 - 109
- Edge v3 (linux): 108
- Edge v2 (windows): 79
Prerequisites
Installing/Updating dependencies
npm install
Building the library
npm run build
Running Locally (and watch for changes)
npx webpack --watch
Custom builds
Our build script is a CLI program with a few additional flags that can
be passed to it. It can list the options available if you ask for
--help
.
npm run build -- --help
There are some specific flags which might be useful to customise the
build:
# Build only sdk, no test extensions
npm run build -- --config-name sdk
# Don't generate any sourcemaps
npm run build -- --no-devtool
In the background, this script is using Webpack. You can also see the
webpack command line options for
further information on these flags.
Managing Bundled Subscriptions in the test build
In MV3 extensions (and the MV3 test extension), subscriptions are
bundled statically at build time. The bundled subscriptions are based
on the custom subscriptions
file. Bundled
subscription are updated by the build script if this file changes.
One case to look out for when working with bundled subscriptions in
tests is that subscriptions are NOT re-fetched if their filters have
changed. If you need to re-fetch new filters and the list of
subscriptions hasn't changed, you can use the
--force-subscription-update
flag to the build script.
npm run build -- --force-subscription-update
Using your own test-server instance
By default, the build script will start up the test server for
updating bundled subscriptions. If you prefer to use a test server
which is already running, you can use the --use-external-server
flag.
npm run test-server&
npm run build -- --use-external-server
Release builds
By default, debug builds are created. If building the library to be used
in another project you would want to create a release build.
npm run build -- --env release
Building the documentation
npm run docs
Linting the code
npm run lint
Events
The library provides the listeners to observe the events:
EWE.allowlisting.onUnauthorized
: Emitted when an allowlisting request is rejectedEWE.filters
:
onAdded
: Emitted when a new filter is addedonChanged
: Emitted when a filter is either enabled or disabled or
metadata changedonRemoved
: Emitted when a filter is removed
EWE.subscriptions
:
onAdded
: Emitted when a new subscription is addedonChanged
: Emitted when any property of the subscription has changedonRemoved
: Emitted when a subscription is removed
EWE.debugging.onLogEvent
: Emitted when having debug outputEWE.reporting.onBlockableItem
: Emitted when any blockable item is matched
Use addListener(...)
to subscribe and removeListener(...)
to unsubscribe.
Manifest V3
See the Manifest V3 documentation for further
explanations.
Testing
For full documentation about testing please refer to our testing document.