diff --git a/.travis.yml b/.travis.yml index 1c9849477..9003839b8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,7 @@ env: matrix: - BROWSER=chromium EXT=zip - BROWSER=firefox EXT=xpi + - BROWSER=thunderbird EXT=xpi script: ./tools/make-${BROWSER}.sh ${TRAVIS_TAG} deploy: provider: releases diff --git a/platform/thunderbird/manifest.json b/platform/thunderbird/manifest.json new file mode 100644 index 000000000..84fcef1c2 --- /dev/null +++ b/platform/thunderbird/manifest.json @@ -0,0 +1,76 @@ +{ + "applications": { + "gecko": { + "id": "uBlock0@raymondhill.net", + "strict_min_version": "65.0" + } + }, + "author": "All uBlock Origin contributors", + "background": { + "page": "background.html" + }, + "browser_action": { + "browser_style": false, + "default_icon": { + "16": "img/icon_16.png", + "32": "img/icon_32.png" + }, + "default_title": "uBlock Origin", + "default_popup": "popup.html" + }, + "content_scripts": [ + { + "matches": [ + "http://*/*", + "https://*/*", + "file://*/*" + ], + "js": [ + "/js/vapi.js", + "/js/vapi-client.js", + "/js/contentscript.js" + ], + "run_at": "document_start", + "all_frames": true + }, + { + "matches": [ + "http://*/*", + "https://*/*" + ], + "js": [ + "/js/scriptlets/subscriber.js" + ], + "run_at": "document_idle", + "all_frames": false + } + ], + "default_locale": "en", + "description": "__MSG_extShortDesc__", + "icons": { + "16": "img/ublock.svg", + "48": "img/ublock.svg", + "96": "img/ublock.svg" + }, + "manifest_version": 2, + "name": "uBlock Origin", + "options_ui": { + "page": "dashboard.html", + "browser_style": false, + "open_in_tab": true + }, + "permissions": [ + "privacy", + "storage", + "tabs", + "webNavigation", + "webRequest", + "webRequestBlocking", + "" + ], + "short_name": "uBlockâ‚€", + "version": "1.9.15.101", + "web_accessible_resources": [ + "/web_accessible_resources/*" + ] +} diff --git a/platform/thunderbird/vapi-webrequest.js b/platform/thunderbird/vapi-webrequest.js new file mode 100644 index 000000000..674351735 --- /dev/null +++ b/platform/thunderbird/vapi-webrequest.js @@ -0,0 +1,184 @@ +/******************************************************************************* + + uBlock Origin - a browser extension to block requests. + Copyright (C) 2017-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +// For background page + +'use strict'; + +/******************************************************************************/ + +(function() { + + // https://github.com/gorhill/uBlock/issues/2950 + // Firefox 56 does not normalize URLs to ASCII, uBO must do this itself. + // https://bugzilla.mozilla.org/show_bug.cgi?id=945240 + const evalMustPunycode = function() { + return vAPI.webextFlavor.soup.has('firefox') && + vAPI.webextFlavor.major < 57; + }; + + let mustPunycode = evalMustPunycode(); + + // The real actual webextFlavor value may not be set in stone, so listen + // for possible future changes. + window.addEventListener('webextFlavor', ( ) => { + mustPunycode = evalMustPunycode(); + }, { once: true }); + + const denormalizeTypes = function(aa) { + if ( aa.length === 0 ) { + return Array.from(vAPI.net.validTypes); + } + const out = new Set(); + let i = aa.length; + while ( i-- ) { + let type = aa[i]; + if ( vAPI.net.validTypes.has(type) ) { + out.add(type); + } + if ( type === 'image' && vAPI.net.validTypes.has('imageset') ) { + out.add('imageset'); + } + if ( type === 'sub_frame' ) { + out.add('object'); + } + } + return Array.from(out); + }; + + const punycode = self.punycode; + const reAsciiHostname = /^https?:\/\/[0-9a-z_.:@-]+[/?#]/; + const parsedURL = new URL('about:blank'); + + vAPI.net.normalizeDetails = function(details) { + if ( mustPunycode && !reAsciiHostname.test(details.url) ) { + parsedURL.href = details.url; + details.url = details.url.replace( + parsedURL.hostname, + punycode.toASCII(parsedURL.hostname) + ); + } + + const type = details.type; + + // https://github.com/gorhill/uBlock/issues/1493 + // Chromium 49+/WebExtensions support a new request type: `ping`, + // which is fired as a result of using `navigator.sendBeacon`. + if ( type === 'ping' ) { + details.type = 'beacon'; + return; + } + + if ( type === 'imageset' ) { + details.type = 'image'; + return; + } + + // https://github.com/uBlockOrigin/uBlock-issues/issues/345 + // Re-categorize an embedded object as a `sub_frame` if its + // content type is that of a HTML document. + if ( type === 'object' && Array.isArray(details.responseHeaders) ) { + for ( const header of details.responseHeaders ) { + if ( header.name.toLowerCase() === 'content-type' ) { + if ( header.value.startsWith('text/html') ) { + details.type = 'sub_frame'; + } + break; + } + } + } + }; + + vAPI.net.denormalizeFilters = function(filters) { + let urls = filters.urls || [ '' ]; + if ( urls.indexOf('https://*/*') !== -1 ) { + urls = [ '' ]; + } + let types = filters.types; + if ( Array.isArray(types) ) { + types = denormalizeTypes(types); + } + if ( + (vAPI.net.validTypes.has('websocket')) && + (types === undefined || types.indexOf('websocket') !== -1) && + (urls.indexOf('') === -1) + ) { + if ( urls.indexOf('ws://*/*') === -1 ) { + urls.push('ws://*/*'); + } + if ( urls.indexOf('wss://*/*') === -1 ) { + urls.push('wss://*/*'); + } + } + return { types, urls }; + }; +})(); + +/******************************************************************************/ + +// Related issues: +// - https://github.com/gorhill/uBlock/issues/1327 +// - https://github.com/uBlockOrigin/uBlock-issues/issues/128 +// - https://bugzilla.mozilla.org/show_bug.cgi?id=1503721 + +vAPI.net.onBeforeReady = (function() { + let pendings; + + const handler = function(details) { + if ( pendings === undefined ) { return; } + if ( details.tabId < 0 ) { return; } + + const pending = { + details: Object.assign({}, details), + resolve: undefined, + promise: undefined + }; + + pending.promise = new Promise(function(resolve) { + pending.resolve = resolve; + }); + + pendings.push(pending); + + return pending.promise; + }; + + return { + start: function() { + pendings = []; + browser.webRequest.onBeforeRequest.addListener( + handler, + { urls: [ 'http://*/*', 'https://*/*' ] }, + [ 'blocking' ] + ); + }, + stop: function(resolver) { + if ( pendings === undefined ) { return; } + for ( const pending of pendings ) { + vAPI.net.normalizeDetails(pending.details); + pending.resolve(resolver(pending.details)); + } + pendings = undefined; + }, + }; +})(); + +/******************************************************************************/ diff --git a/tools/make-thunderbird.sh b/tools/make-thunderbird.sh new file mode 100755 index 000000000..9854e5cbb --- /dev/null +++ b/tools/make-thunderbird.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env bash +# +# This script assumes a linux environment + +echo "*** uBlock0.thunderbird: Creating web store package" +echo "*** uBlock0.thunderbird: Copying files" + +BLDIR=dist/build +DES="$BLDIR"/uBlock0.thunderbird +rm -rf $DES +mkdir -p $DES + +bash ./tools/make-assets.sh $DES + +cp -R src/css $DES/ +cp -R src/img $DES/ +cp -R src/js $DES/ +cp -R src/lib $DES/ +cp -R src/_locales $DES/ +cp -R $DES/_locales/nb $DES/_locales/no +cp src/*.html $DES/ +cp platform/chromium/*.js $DES/js/ +cp platform/chromium/*.html $DES/ +cp platform/chromium/*.json $DES/ +cp LICENSE.txt $DES/ + +cp platform/thunderbird/manifest.json $DES/ +cp platform/thunderbird/vapi-webrequest.js $DES/js/ +cp platform/firefox/vapi-usercss.js $DES/js/ + +echo "*** uBlock0.thunderbird: concatenating content scripts" +cat $DES/js/vapi-usercss.js > /tmp/contentscript.js +echo >> /tmp/contentscript.js +grep -v "^'use strict';$" $DES/js/vapi-usercss.real.js >> /tmp/contentscript.js +echo >> /tmp/contentscript.js +grep -v "^'use strict';$" $DES/js/contentscript.js >> /tmp/contentscript.js +mv /tmp/contentscript.js $DES/js/contentscript.js +rm $DES/js/vapi-usercss.js +rm $DES/js/vapi-usercss.real.js +rm $DES/js/vapi-usercss.pseudo.js + +# Firefox/webext-specific +rm $DES/img/icon_128.png + +echo "*** uBlock0.thunderbird: Generating web accessible resources..." +cp -R src/web_accessible_resources $DES/ +python3 tools/import-war.py $DES/ + +echo "*** uBlock0.thunderbird: Generating meta..." +python tools/make-firefox-meta.py $DES/ + +if [ "$1" = all ]; then + echo "*** uBlock0.thunderbird: Creating package..." + pushd $DES > /dev/null + zip ../$(basename $DES).xpi -qr * + popd > /dev/null +elif [ -n "$1" ]; then + echo "*** uBlock0.thunderbird: Creating versioned package..." + pushd $DES > /dev/null + zip ../$(basename $DES).xpi -qr * + popd > /dev/null + mv "$BLDIR"/uBlock0.thunderbird.xpi "$BLDIR"/uBlock0_"$1".thunderbird.xpi +fi + +echo "*** uBlock0.thunderbird: Package done."