diff --git a/.travis.yml b/.travis.yml index 3f1090e37..d78ea5d9f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,20 @@ before_install: - export WAPPALYZER_NODE_PATH=$TRAVIS_BUILD_DIR - export PATH=$PATH:$TRAVIS_BUILD_DIR/bin - ln -s docker/node/package.json package.json +before_script: npm i -g manifoldjs +after_success: + - sha256sum build/* > build/SHA256SUMS + - cat build/SHA256SUMS +deploy: + provider: releases + api_key: + secure: mco1ycbfGXZEiBywOmM5A50Y1QPFawj4i0gdB9JDkXDvY7N2kPZyCdAeOQOMEJuetGT3HvJuTG0Ll47sithZfPqq6wx/4EeP8YQYYFIyoOlsIGi5MDR1kS5ZOqKDWGe5+x+/rUZbmuMHvgHWNSjPG8mBrp5xWmON6ETkLWfVB0c= + file_glob: true + file: build/* + skip_cleanup: true + on: + repo: AliasIO/Wappalyzer + tags: true after_script: ls -l --block-size=kB build cache: directories: diff --git a/README.md b/README.md index 4911a745c..dbc8eaa5c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Wappalyzer [![Travis](https://img.shields.io/travis/AliasIO/Wappalyzer.svg?style=flat-square)](https://travis-ci.org/AliasIO/Wappalyzer/) +# Wappalyzer [![Travis](https://img.shields.io/travis/AliasIO/Wappalyzer.svg)](https://travis-ci.org/AliasIO/Wappalyzer/) [![Scrutinizer](https://scrutinizer-ci.com/g/AliasIO/Wappalyzer/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/AliasIO/Wappalyzer/?branch=master) [Wappalyzer](https://wappalyzer.com/) is a [cross-platform](https://github.com/AliasIO/Wappalyzer/wiki/Drivers) utility that uncovers the diff --git a/bin/wappalyzer-build b/bin/wappalyzer-build index b526af24b..a07a85b59 100755 --- a/bin/wappalyzer-build +++ b/bin/wappalyzer-build @@ -55,13 +55,42 @@ wappalyzer links # WebExtension echo "Building WebExtension driver..." -pushd $WAPPALYZER_ROOT/src/drivers/webextension > /dev/null +webextension_dir=$WAPPALYZER_ROOT/src/drivers/webextension -zip -qr $WAPPALYZER_ROOT/build/wappalyzer_webextension.zip . -x manifest.edge.json +pushd $webextension_dir > /dev/null -zip -qr $WAPPALYZER_ROOT/build/wappalyzer_webextension.edge.zip . -x manifest.json +zip -qr $WAPPALYZER_ROOT/build/wappalyzer_webextension.zip . -printf "@ manifest.edge.json\n@=manifest.json\n" | zipnote -w $WAPPALYZER_ROOT/build/wappalyzer_webextension.edge.zip +popd > /dev/null + +# Edge + +pushd $WAPPALYZER_ROOT/build > /dev/null + +mv $webextension_dir/manifest.json $webextension_dir/manifest.webextension.json +mv $webextension_dir/manifest.edge.json $webextension_dir/manifest.json + +manifoldjs -l debug -p edgeextension -f edgeextension -m $webextension_dir/manifest.json + +mv $webextension_dir/manifest.json $webextension_dir/manifest.edge.json +mv $webextension_dir/manifest.webextension.json $webextension_dir/manifest.json + +manifest_dir="Wappalyzer/edgeextension/manifest" + +sed -i 's/INSERT-YOUR-PACKAGE-IDENTITY-NAME-HERE/Wappalyzer/' $manifest_dir/appxmanifest.xml +sed -i 's/INSERT-YOUR-PACKAGE-IDENTITY-PUBLISHER-HERE/Wappalyzer/' $manifest_dir/appxmanifest.xml +sed -i 's/INSERT-YOUR-PACKAGE-PROPERTIES-PUBLISHERDISPLAYNAME-HERE/Wappalyzer/' $manifest_dir/appxmanifest.xml +sed -i 's/Version="0.\([^"]\+\)/Version="\1.0/' $manifest_dir/appxmanifest.xml + +cp $webextension_dir/images/icon_44.png $manifest_dir/Assets/Square44x44Logo.png +cp $webextension_dir/images/icon_150.png $manifest_dir/Assets/Square150x150Logo.png +cp $webextension_dir/images/icon_50.png $manifest_dir/Assets/StoreLogo.png + +manifoldjs -l debug -p edgeextension package $manifest_dir + +mv Wappalyzer/edgeextension/package/edgeExtension.appx wappalyzer_edge.appx + +rm -rf Wappalyzer popd > /dev/null diff --git a/bin/wappalyzer-validate-icons b/bin/wappalyzer-validate-icons index 3ec796ac6..185511826 100755 --- a/bin/wappalyzer-validate-icons +++ b/bin/wappalyzer-validate-icons @@ -12,43 +12,43 @@ var for (app in json.apps) { (function(app) { var basePath = process.env.WAPPALYZER_ROOT + '/src/icons/'; - var iconPath = json.apps[app].icon; - var path = basePath + iconPath; - - var type; - if (path.substr(path.length - 4) === '.png') { - type = "PNG"; - } - else if (path.substr(path.length - 4) === '.svg') { - type = "SVG"; - } - else { - var err = new Error('Icon file extension specified for app "' + app + '" is not ".png" or ".svg": src/icons/' + iconPath); - throw err; - } - + var iconPath = json.apps[app].icon || 'default.svg'; + var path = basePath + iconPath; + + var type; + if (path.substr(path.length - 4) === '.png') { + type = "PNG"; + } + else if (path.substr(path.length - 4) === '.svg') { + type = "SVG"; + } + else { + var err = new Error('Icon file extension specified for app "' + app + '" is not ".png" or ".svg": src/icons/' + iconPath); + throw err; + } + fs.exists(path, function(exists) { if (exists) { - if (type === "PNG") { - var buffer = fileType(readChunk.sync(path, 0, 262)); - if (buffer === null) { - var err = new Error('Unknown mimetype or bad file for "' + app + '": src/icons/' + iconPath); - throw err; - } - else if (buffer.mime !== 'image/png') { - var err = new Error('Incorrect mimetype "' + buffer.mime + '" when expected PNG for app "' + app + '": src/icons/' + iconPath); - throw err; - } - } - else if (type === "SVG") { - if (!isSvg(fs.readFileSync(path))) { - var err = new Error('Incorrect mimetype when expected SVG for app "' + app + '": src/icons/' + iconPath); - throw err; - } - } + if (type === "PNG") { + var buffer = fileType(readChunk.sync(path, 0, 262)); + if (buffer === null) { + var err = new Error('Unknown mimetype or bad file for "' + app + '": src/icons/' + iconPath); + throw err; + } + else if (buffer.mime !== 'image/png') { + var err = new Error('Incorrect mimetype "' + buffer.mime + '" when expected PNG for app "' + app + '": src/icons/' + iconPath); + throw err; + } + } + else if (type === "SVG") { + if (!isSvg(fs.readFileSync(path))) { + var err = new Error('Incorrect mimetype when expected SVG for app "' + app + '": src/icons/' + iconPath); + throw err; + } + } } else { var err = new Error('Missing file for app "' + app + '": src/icons/' + iconPath); - throw err; + throw err; } }); }(app)); diff --git a/docker/Dockerfile b/docker/Dockerfile index ec435c0bd..c35776024 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -8,11 +8,19 @@ ENV WAPPALYZER_ROOT /home/wappalyzer/synced ENV WAPPALYZER_NODE_PATH /home/wappalyzer/node # Install packages +RUN sed -i 's/^deb-src\ /\#deb-src\ /g' /etc/apt/sources.list RUN sed -i 's/archive\.ubuntu\.com/au.archive.ubuntu.com/g' /etc/apt/sources.list -RUN apt-get update && apt-get install -y sudo curl -RUN curl -sL https://deb.nodesource.com/setup_6.x | bash - -RUN apt-get install -y nodejs bzip2 zip libfreetype6 libfontconfig rsync -RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* +RUN sed -i 's/security\.ubuntu\.com/au.archive.ubuntu.com/g' /etc/apt/sources.list +RUN curl -sL https://deb.nodesource.com/setup_6.x | bash - && \ + apt-get install -y \ + nodejs \ + bzip2 \ + zip \ + libfreetype6 \ + libfontconfig \ + rsync && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* # Add user @@ -42,6 +50,8 @@ ADD node/package.json $WAPPALYZER_NODE_PATH/package.json RUN su wappalyzer -c "cd $WAPPALYZER_NODE_PATH && npm i" +RUN npm i -g manifoldjs + # SSH RUN rm -f /etc/service/sshd/down diff --git a/schema.json b/schema.json index c70605b61..ac366218f 100644 --- a/schema.json +++ b/schema.json @@ -85,8 +85,7 @@ "required": true }, "icon": { - "type": "string", - "required": true + "type": "string" } } } diff --git a/src/apps.json b/src/apps.json index 105484c2a..dffea9b8f 100755 --- a/src/apps.json +++ b/src/apps.json @@ -865,7 +865,6 @@ "3" ], "html": "", @@ -6269,7 +6302,6 @@ "25" ], "env": "^protovis$", - "icon": "default.svg", "script": "protovis.*\\.js", "website": "http://mbostock.github.com/protovis" }, @@ -6404,7 +6436,6 @@ "headers": { "Server": "RAID HTTPServer(?:/([\\d.]+))?\\;version:\\1" }, - "icon": "default.svg", "website": "http://example.com" }, "RBS Change": { @@ -6514,7 +6545,6 @@ "headers": { "Server": "Rapid Logic(?:/([\\d.]+))?\\;version:\\1" }, - "icon": "default.svg", "website": "http://example.com" }, "React": { @@ -6599,7 +6629,8 @@ ], "env": "^Reveal$", "icon": "Reveal.js.png", - "script": "reveal(?:\\.min)?\\.js", + "implies": "Highlight.js", + "script": "(?:^|/)reveal(?:\\.min)?\\.js", "website": "http://lab.hakim.se/reveal-js" }, "Revel": { @@ -6618,7 +6649,6 @@ "25" ], "env": "^Rickshaw$", - "icon": "default.svg", "implies": "D3", "script": "rickshaw(?:\\.min)?\\.js", "website": "http://code.shutterstock.com/rickshaw/" @@ -6953,6 +6983,16 @@ ], "website": "http://schneider-electric.com" }, + "Scholica": { + "cats": [ + "21" + ], + "headers": { + "X-Scholica-Version": "" + }, + "icon": "Scholica.svg", + "website": "http://scholica.com" + }, "Scientific Linux": { "cats": [ "28" @@ -6978,7 +7018,6 @@ "cats": [ "12" ], - "icon": "default.svg", "implies": "jQuery", "script": "select2.*\\.js", "website": "http://select2.github.io" @@ -7197,7 +7236,6 @@ "headers": { "Server": "SimpleHTTP(?:/([\\d.]+))?\\;version:\\1" }, - "icon": "default.svg", "website": "http://example.com" }, "Site Meter": { @@ -7270,7 +7308,6 @@ }, "Slimbox": { "cats": [ - "7", "12" ], "html": "]*href=\"[^/]*slimbox(?:-rtl)?\\.css", @@ -7281,7 +7318,6 @@ }, "Slimbox 2": { "cats": [ - "7", "12" ], "html": "]*href=\"[^/]*slimbox2(?:-rtl)?\\.css", @@ -7644,7 +7680,6 @@ }, "Supersized": { "cats": [ - "7", "25" ], "icon": "Supersized.png", @@ -8053,7 +8088,6 @@ "25" ], "env": "^twemoji$", - "icon": "default.svg", "script": "twemoji(?:\\.min)?\\.js", "website": "http://twitter.github.io/twemoji/" }, @@ -8087,6 +8121,15 @@ "url": "typepad\\.com", "website": "http://www.typepad.com" }, + "Typecho": { + "cats": [ + "11" + ], + "icon": "typecho.svg", + "implies": "PHP", + "url": "/admin/login\\.php?referer=http%3A%2F%2F", + "website": "http://typecho.org/" + }, "Typekit": { "cats": [ "17" @@ -8357,6 +8400,18 @@ "icon": "Vimeo.png", "website": "http://vimeo.com" }, + + "Vinala": { + "cats": [ + "18" + ], + "headers": { + "Set-Cookie": "vinala_version" + }, + "icon": "Vinala.png", + "implies": "PHP", + "website": "https://github.com/vinala/vinala" + }, "Virata EmWeb": { "cats": [ "22" @@ -8364,7 +8419,6 @@ "headers": { "Server": "Virata-EmWeb(?:/(R?[\\d._]+))?\\;version:\\1" }, - "icon": "default.svg", "implies": [ "HP" ], @@ -8671,7 +8725,6 @@ "Server": "Winstone Servlet (?:Container|Engine) v?([\\d.]+)?\\;version:\\1", "X-Powered-By": "Winstone(?:.([\\d.]+))?\\;version:\\1" }, - "icon": "default.svg", "website": "http://winstone.sourceforge.net" }, "Wix": { @@ -9259,7 +9312,6 @@ "headers": { "Server": "dwhttpd\\/?([\\d\\.a-z]+)?\\;version:\\1" }, - "icon": "default.svg", "website": "http://example.com" }, "e107": { @@ -9292,7 +9344,6 @@ "headers": { "Server": "\beHTTP(?: v?([\\d\\.]+))?\\;version:\\1" }, - "icon": "default.svg", "implies": "HP ProCurve", "website": "http://example.com" }, @@ -9354,7 +9405,6 @@ "47" ], "html": "

Powered by ]+>GitList ([\\d.]+)\\;version:\\1", - "icon": "default.svg", "implies": [ "PHP", "git" @@ -9489,7 +9539,6 @@ "cats": [ "25" ], - "icon": "default.svg", "implies": "jQuery", "script": "jquery\\.sparkline.*\\.js", "website": "http://omnipotent.net/jquery.sparkline/" @@ -9874,7 +9923,6 @@ }, "prettyPhoto": { "cats": [ - "7", "12" ], "env": "pp_(?:alreadyInitialized|descriptions|images|titles)", @@ -9935,20 +9983,9 @@ "25" ], "env": "^Shine$", - "icon": "default.svg", "script": "shine(?:\\.min)?\\.js", "website": "http://bigspaceship.github.io/shine.js/" }, - "spin.js": { - "cats": [ - "12", - "25" - ], - "env": "^Spinner$", - "icon": "spin.js.png", - "script": "spin(?:\\.min)?\\.js", - "website": "http://fgnass.github.io/spin.js/" - }, "swift.engine": { "cats": [ "1" @@ -10053,19 +10090,8 @@ "1" ], "html": "powered by ]+viennacms", - "icon": "default.svg", "website": "http://www.viennacms.nl" }, - "vis.js": { - "cats": [ - "25" - ], - "env": "^vis$", - "html": "]+?href=\"[^\"]+vis(?:\\.min)?\\.css", - "icon": "vis.js.png", - "script": "vis(?:\\.min)?\\.js", - "website": "http://visjs.org" - }, "webEdition": { "cats": [ "1" @@ -10107,7 +10133,6 @@ ], "env": "^xChart$", "html": "]* href=\"[^\"]*xcharts(?:\\.min)?\\.css", - "icon": "default.svg", "implies": "D3", "script": "xcharts\\.js", "website": "http://tenxer.github.io/xcharts/" diff --git a/src/drivers/bookmarklet/driver.js b/src/drivers/bookmarklet/driver.js index 05b92a81a..230ff6aaf 100644 --- a/src/drivers/bookmarklet/driver.js +++ b/src/drivers/bookmarklet/driver.js @@ -1,7 +1,10 @@ /** - * Bookmarklet driver + * WebExtension driver */ +/** global: wappalyzer */ +/** global: XMLHttpRequest */ + (function() { if ( typeof wappalyzer === 'undefined' ) { return; @@ -112,7 +115,7 @@ '

' + '' + '' + - ' ' + app + + ' ' + app + '' + ''; diff --git a/src/drivers/phantomjs/driver.js b/src/drivers/phantomjs/driver.js index a99f2612d..d7138b4b9 100644 --- a/src/drivers/phantomjs/driver.js +++ b/src/drivers/phantomjs/driver.js @@ -1,3 +1,10 @@ +/** + * PhantomJS driver + */ + +/** global: phantom */ +/** global: wappalyzer */ + (function() { var url, @@ -15,8 +22,10 @@ require('fs').changeWorkingDirectory(scriptDir); - require('system').args.forEach(function(arg, i) { - var arr = /^(--[^=]+)=(.+)$/.exec(arg); + require('system').args.forEach(function(arg) { + var + value, + arr = /^(--[^=]+)=(.+)$/.exec(arg); if ( arr && arr.length === 3 ) { arg = arr[1]; @@ -35,7 +44,9 @@ break; case '--resource-timeout': - resourceTimeout = value; + if ( value ) { + resourceTimeout = value; + } break; default: @@ -73,31 +84,28 @@ displayApps: function() { var app, cats, - apps = [], - count = wappalyzer.detected[url] ? Object.keys(wappalyzer.detected[url]).length : 0; + apps = []; wappalyzer.log('driver.displayApps'); - if ( count ) { - for ( app in wappalyzer.detected[url] ) { - cats = []; - - wappalyzer.apps[app].cats.forEach(function(cat) { - cats.push(wappalyzer.categories[cat].name); - }); - - apps.push({ - name: app, - confidence: wappalyzer.detected[url][app].confidenceTotal.toString(), - version: wappalyzer.detected[url][app].version, - icon: wappalyzer.apps[app].icon, - website: wappalyzer.apps[app].website, - categories: cats - }); - } - - wappalyzer.driver.sendResponse(apps); + for ( app in wappalyzer.detected[url] ) { + cats = []; + + wappalyzer.apps[app].cats.forEach(function(cat) { + cats.push(wappalyzer.categories[cat].name); + }); + + apps.push({ + name: app, + confidence: wappalyzer.detected[url][app].confidenceTotal.toString(), + version: wappalyzer.detected[url][app].version, + icon: wappalyzer.apps[app].icon || 'default.svg', + website: wappalyzer.apps[app].website, + categories: cats + }); } + + wappalyzer.driver.sendResponse(apps); }, /** @@ -115,7 +123,7 @@ init: function() { var page, hostname, - headers = {}; + headers = {}, a = document.createElement('a'), json = JSON.parse(require('fs').read('apps.json')); @@ -167,7 +175,7 @@ }; page.open(url, function(status) { - var html, environmentVars; + var html, environmentVars = ''; if ( status === 'success' ) { html = page.content; @@ -178,7 +186,7 @@ // Collect environment variables environmentVars = page.evaluate(function() { - var i, environmentVars; + var i, environmentVars = ''; for ( i in window ) { environmentVars += i + ' '; diff --git a/src/drivers/phantomjs/package.json b/src/drivers/phantomjs/package.json index f055bf0af..eed2410c6 100644 --- a/src/drivers/phantomjs/package.json +++ b/src/drivers/phantomjs/package.json @@ -2,7 +2,7 @@ "name": "wappalyzer", "description": "Uncovers the technologies used on websites", "homepage": "https://github.com/AliasIO/Wappalyzer", - "version": "3.0.9", + "version": "3.0.10", "author": "Elbert Alias", "license": "GPL-3.0", "repository": { diff --git a/src/drivers/webextension/_locales/el/messages.json b/src/drivers/webextension/_locales/el/messages.json index e7bbcdef3..41058767a 100644 --- a/src/drivers/webextension/_locales/el/messages.json +++ b/src/drivers/webextension/_locales/el/messages.json @@ -6,6 +6,7 @@ "optionsSave": { "message": "Ρυθμίσεις αποθήκευσης" }, "optionsSaved": { "message": "Αποθηκεύτηκε" }, "optionUpgradeMessage": { "message": "Ενημερώστε με για αναβαθμίσεις" }, + "optionDynamicIcon": { "message": "Use application icon instead of Wappalyzer logo" }, "optionTracking": { "message": "Ανώνυμη αποστολή αναφορών για εντοπισμένες εφαρμογές στο wappalyzer.com για έρευνα" }, "nothingToDo": { "message": "Καμία ενέργεια." }, "noAppsDetected": { "message": "Δεν ανιχνεύθηκαν εφαρμογές." }, diff --git a/src/drivers/webextension/_locales/en/messages.json b/src/drivers/webextension/_locales/en/messages.json index 7a5ebe100..3edc49047 100644 --- a/src/drivers/webextension/_locales/en/messages.json +++ b/src/drivers/webextension/_locales/en/messages.json @@ -6,6 +6,7 @@ "optionsSave": { "message": "Save options" }, "optionsSaved": { "message": "Saved" }, "optionUpgradeMessage": { "message": "Tell me about upgrades" }, + "optionDynamicIcon": { "message": "Use application icon instead of Wappalyzer logo" }, "optionTracking": { "message": "Anonymously send reports on detected applications to wappalyzer.com for research" }, "nothingToDo": { "message": "Nothing to do here." }, "noAppsDetected": { "message": "No applications detected." }, @@ -14,6 +15,10 @@ "categoryName3": { "message": "Database Manager" }, "categoryName4": { "message": "Documentation Tool" }, "categoryName5": { "message": "Widget" }, + "categoryName6": { "message": "Ecommerce" }, + "categoryName7": { "message": "Photo Galleries" }, + "categoryName8": { "message": "Wikis" }, + "categoryName9": { "message": "Hostin Panels" }, "categoryName10": { "message": "Analytics" }, "categoryName11": { "message": "Blog" }, "categoryName12": { "message": "JavaScript Framework" }, diff --git a/src/drivers/webextension/_locales/es/messages.json b/src/drivers/webextension/_locales/es/messages.json index d175e0e55..9a2639722 100644 --- a/src/drivers/webextension/_locales/es/messages.json +++ b/src/drivers/webextension/_locales/es/messages.json @@ -6,6 +6,7 @@ "optionsSave": { "message": "Guardar opciones" }, "optionsSaved": { "message": "Guardado" }, "optionUpgradeMessage": { "message": "Indicarme actualizaciones" }, + "optionDynamicIcon": { "message": "Use application icon instead of Wappalyzer logo" }, "optionTracking": { "message": "Enviar informes anónimos sobre las aplicaciones detectadas a wappalyzer.com para análisis" }, "nothingToDo": { "message": "Nada que hacer aquí." }, "noAppsDetected": { "message": "Aplicaciones no detectadas." }, diff --git a/src/drivers/webextension/_locales/fr/messages.json b/src/drivers/webextension/_locales/fr/messages.json index 05de10bf8..5c5fdf456 100644 --- a/src/drivers/webextension/_locales/fr/messages.json +++ b/src/drivers/webextension/_locales/fr/messages.json @@ -4,6 +4,7 @@ "nothingToDo": { "message": "Rien à faire ici." }, "optionTracking": { "message": "Envoyer anonymement des rapports sur les applications détectées à wappalyzer.com pour la recherche" }, "optionUpgradeMessage": { "message": "M'afficher les mises à jour" }, + "optionDynamicIcon": { "message": "Use application icon instead of Wappalyzer logo" }, "options": { "message": "Options" }, "optionsSave": { "message": "Sauver les options" }, "optionsSaved": { "message": "Sauvé" }, diff --git a/src/drivers/webextension/_locales/gr/messages.json b/src/drivers/webextension/_locales/gr/messages.json index 4b13de522..055cb2b95 100644 --- a/src/drivers/webextension/_locales/gr/messages.json +++ b/src/drivers/webextension/_locales/gr/messages.json @@ -6,6 +6,7 @@ "optionsSave": { "message": "Ρυθμίσεις αποθήκευσης" }, "optionsSaved": { "message": "Αποθηκεύτηκε" }, "optionUpgradeMessage": { "message": "Ενημερώστε με για αναβαθμίσεις" }, + "optionDynamicIcon": { "message": "Use application icon instead of Wappalyzer logo" }, "optionTracking": { "message": "Ανώνυμη αποστολή αναφορών για εντοπισμένες εφαρμογές στο wappalyzer.com για έρευνα" }, "nothingToDo": { "message": "Καμία ενέργεια." }, "noAppsDetected": { "message": "Δεν ανιχνεύθηκαν εφαρμογές." }, diff --git a/src/drivers/webextension/_locales/it/messages.json b/src/drivers/webextension/_locales/it/messages.json index 04a7acf97..b93fea5d8 100644 --- a/src/drivers/webextension/_locales/it/messages.json +++ b/src/drivers/webextension/_locales/it/messages.json @@ -6,6 +6,7 @@ "optionsSave": { "message": "Salva opzioni" }, "optionsSaved": { "message": "Salvato" }, "optionUpgradeMessage": { "message": "Parlami dell'upgrade" }, + "optionDynamicIcon": { "message": "Use application icon instead of Wappalyzer logo" }, "optionTracking": { "message": "Inviare anonimamente un report sulle applicazioni rilevate a wappalyzer.com per l'analisi" }, "nothingToDo": { "message": "Niente da fare qui." }, "noAppsDetected": { "message": "Nessuna applicazione rilevata." }, diff --git a/src/drivers/webextension/_locales/pl/messages.json b/src/drivers/webextension/_locales/pl/messages.json index 84fe6cc73..f70d54208 100644 --- a/src/drivers/webextension/_locales/pl/messages.json +++ b/src/drivers/webextension/_locales/pl/messages.json @@ -6,6 +6,7 @@ "optionsSave": { "message": "Zapisz opcje" }, "optionsSaved": { "message": "Zapisano" }, "optionUpgradeMessage": { "message": "Powiadamiaj mnie o aktualizacjach" }, + "optionDynamicIcon": { "message": "Use application icon instead of Wappalyzer logo" }, "optionTracking": { "message": "Przesyłaj anonimowe statystyki aplikacji wykrytych przez Wappalyzer do twórców" }, "nothingToDo": { "message": "Nic tu nie ma." }, "noAppsDetected": { "message": "Nie wykryto żadnych aplikacji." }, diff --git a/src/drivers/webextension/_locales/ro/messages.json b/src/drivers/webextension/_locales/ro/messages.json index f9d732bdf..48fd99b91 100644 --- a/src/drivers/webextension/_locales/ro/messages.json +++ b/src/drivers/webextension/_locales/ro/messages.json @@ -6,6 +6,7 @@ "optionsSave": { "message": "Salvează opțiuni" }, "optionsSaved": { "message": "Salvat" }, "optionUpgradeMessage": { "message": "Anunță-mă dacă sunt actualizări" }, + "optionDynamicIcon": { "message": "Use application icon instead of Wappalyzer logo" }, "optionTracking": { "message": "Trimite rapoarte anonime despre aplicațiile detectate către wappalyzer.com pentru cercetare" }, "nothingToDo": { "message": "Nimic de făcut pe pagina curentă." }, "noAppsDetected": { "message": "Nici o aplicație detectată." }, diff --git a/src/drivers/webextension/css/options.css b/src/drivers/webextension/css/options.css index a5398318c..090242223 100644 --- a/src/drivers/webextension/css/options.css +++ b/src/drivers/webextension/css/options.css @@ -83,7 +83,7 @@ a:active { #about { border-top: 1px solid #dbdbdb; - margin-top: 2.5rem; + margin-top: 1.5rem; padding: 1.5rem 0 0 0; } diff --git a/src/drivers/webextension/images/icon_150.png b/src/drivers/webextension/images/icon_150.png new file mode 100644 index 000000000..7028f9c5e Binary files /dev/null and b/src/drivers/webextension/images/icon_150.png differ diff --git a/src/drivers/webextension/images/icon_44.png b/src/drivers/webextension/images/icon_44.png new file mode 100644 index 000000000..9a6321eaa Binary files /dev/null and b/src/drivers/webextension/images/icon_44.png differ diff --git a/src/drivers/webextension/images/icon_50.png b/src/drivers/webextension/images/icon_50.png new file mode 100644 index 000000000..935b35b72 Binary files /dev/null and b/src/drivers/webextension/images/icon_50.png differ diff --git a/src/drivers/webextension/js/content.js b/src/drivers/webextension/js/content.js index e394e8eb7..ac21ee724 100644 --- a/src/drivers/webextension/js/content.js +++ b/src/drivers/webextension/js/content.js @@ -1,3 +1,5 @@ +/** global: browser */ + (function() { var c = { init: function() { diff --git a/src/drivers/webextension/js/defaults.js b/src/drivers/webextension/js/defaults.js deleted file mode 100644 index 3ec2d3e09..000000000 --- a/src/drivers/webextension/js/defaults.js +++ /dev/null @@ -1,5 +0,0 @@ -var defaults = { - autoAnalyzeHeaders: 0, - upgradeMessage: 1, - tracking: 1 -}; diff --git a/src/drivers/webextension/js/driver.js b/src/drivers/webextension/js/driver.js index cf4ae7b9f..4dee2dd54 100644 --- a/src/drivers/webextension/js/driver.js +++ b/src/drivers/webextension/js/driver.js @@ -1,7 +1,12 @@ /** - * Chrome driver + * WebExtension driver */ +/** global: browser */ +/** global: chrome */ +/** global: wappalyzer */ +/** global: XMLHttpRequest */ + (function() { if ( wappalyzer == null ) { return; @@ -24,6 +29,26 @@ console.log('[wappalyzer ' + args.type + '] ' + args.message); }, + /** + * Get a value from localStorage + */ + getOption: function(name, defaultValue, callback) { + browser.storage.local.get(name).then(function(item) { + callback(item.hasOwnProperty(name) ? item[name] : defaultValue); + }); + }, + + /** + * Set a value in localStorage + */ + setOption: function(name, value) { + var option = {}; + + option[name] = value; + + browser.storage.local.set(option); + }, + /** * Initialize */ @@ -54,19 +79,27 @@ try { var version = browser.runtime.getManifest().version; - if ( localStorage['version'] == null ) { - firstRun = true; - - // Set defaults - for ( var option in defaults ) { - localStorage[option] = defaults[option]; + w.driver.getOption('version', null, function(previousVersion) { + if ( previousVersion === null ) { + w.driver.goToURL({ + url: w.config.websiteURL + 'installed' + }); + } else if ( version !== previousVersion ) { + w.driver.getOption('upgradeMessage', true, function(upgradeMessage) { + if ( upgradeMessage ) { + w.driver.goToURL({ + url: w.config.websiteURL + 'upgraded', + background: true + }); + } + }); } - } else if ( version !== localStorage['version'] && parseInt(localStorage['upgradeMessage'], 10) ) { - upgraded = true; - } - localStorage['version'] = version; - } catch(e) { } + w.driver.setOption('version', version); + }); + } catch(e) { + // Do nothing + } if ( typeof chrome === 'undefined' ) { browser.runtime.onMessage.addListener(w.driver.onMessage); @@ -74,13 +107,19 @@ chrome.runtime.onMessage.addListener(w.driver.onMessage); } - browser.tabs.query({}).then(function(tabs) { + var callback = function(tabs) { tabs.forEach(function(tab) { if ( tab.url.match(/^https?:\/\//) ) { browser.tabs.executeScript(tab.id, { file: 'js/content.js' }); } }) - }); + }; + + try { + browser.tabs.query({}).then(callback); + } catch ( e ) { + browser.tabs.query({}, callback); + } browser.tabs.onRemoved.addListener(function(tabId) { w.log('remove tab'); @@ -109,7 +148,9 @@ } for ( var header in responseHeaders ) { - headersCache[uri][header] = responseHeaders[header]; + if ( responseHeaders.hasOwnProperty(header) ) { + headersCache[uri][header] = responseHeaders[header]; + } } } @@ -170,6 +211,7 @@ }; break; + default: } sendResponse(response); @@ -177,10 +219,14 @@ }, + /** + * Open a tab + */ goToURL: function(args) { - var url = args.url + ( typeof args.medium === 'undefined' ? '' : '?pk_campaign=chrome&pk_kwd=' + args.medium); - - browser.tabs.create({ url: url, active: args.background === undefined || !args.background }); + browser.tabs.create({ + url: args.url, + active: args.background === undefined || !args.background + }); }, /** @@ -202,33 +248,42 @@ tabCache[tab.id].appsDetected = w.detected[url]; if ( count > 0 ) { - // Find the main application to display - var appName, found = false; + w.driver.getOption('dynamicIcon', true, function(dynamicIcon) { + var appName, found = false; - w.driver.categoryOrder.forEach(function(match) { - for ( appName in w.detected[url] ) { - w.apps[appName].cats.forEach(function(cat) { - var icon = w.apps[appName].icon; + // Find the main application to display + w.driver.categoryOrder.forEach(function(match) { + for ( appName in w.detected[url] ) { + w.apps[appName].cats.forEach(function(cat) { + var icon = w.apps[appName].icon || 'default.svg'; - if ( cat == match && !found ) { - if ( /\.svg$/i.test(icon) ) { - icon = 'converted/' + icon + '.png'; + if ( !dynamicIcon ) { + icon = 'default.svg'; } - browser.pageAction.setIcon({ tabId: tab.id, path: 'images/icons/' + icon }); + if ( cat === match && !found ) { + if ( /\.svg$/i.test(icon) ) { + icon = 'converted/' + icon + '.png'; + } - found = true; - } - }); + browser.pageAction.setIcon({ + tabId: tab.id, + path: 'images/icons/' + icon + }); + + found = true; + } + }); + } + }); + + if ( typeof chrome !== 'undefined' ) { + // Browser polyfill doesn't seem to work here + chrome.pageAction.show(tab.id); + } else { + browser.pageAction.show(tab.id); } }); - - if ( typeof chrome !== 'undefined' ) { - // Browser polyfill doesn't seem to work here - chrome.pageAction.show(tab.id); - } else { - browser.pageAction.show(tab.id); - } }; }, @@ -236,17 +291,19 @@ * Anonymously track detected applications for research purposes */ ping: function() { - if ( Object.keys(w.ping.hostnames).length && parseInt(localStorage['tracking'], 10) ) { - w.driver.post('http://ping.wappalyzer.com/v2/', w.ping); + w.driver.getOption('tracking', true, function(tracking) { + if ( Object.keys(w.ping.hostnames).length && tracking ) { + w.driver.post('http://ping.wappalyzer.com/v2/', w.ping); - w.log('w.driver.ping: ' + JSON.stringify(w.ping)); + w.log('w.driver.ping: ' + JSON.stringify(w.ping)); - w.ping = { hostnames: {} }; + w.ping = { hostnames: {} }; - w.driver.post('https://ad.wappalyzer.com/log/wp/', w.adCache); + w.driver.post('https://ad.wappalyzer.com/log/wp/', w.adCache); - w.adCache = []; - } + w.adCache = []; + } + }); }, /** @@ -259,7 +316,7 @@ xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); - xhr.onreadystatechange = function(e) { + xhr.onreadystatechange = function() { if ( xhr.readyState == 4 ) { w.log('w.driver.post: status ' + xhr.status + ' (' + url + ')'); } diff --git a/src/drivers/webextension/js/i18n.js b/src/drivers/webextension/js/i18n.js index bf9c7e2bc..1b69f9f58 100644 --- a/src/drivers/webextension/js/i18n.js +++ b/src/drivers/webextension/js/i18n.js @@ -1,11 +1,13 @@ +/** global: browser */ + document.addEventListener('DOMContentLoaded', function() { var i, value, - nodes = document.getElementsByTagName('*'); + nodes = document.querySelector('*'); for ( i = 0; i < nodes.length; i ++ ) { - if ( attr = nodes[i].dataset.i18n ) { - nodes[i].innerHTML = browser.i18n.getMessage(attr); + if ( value = nodes[i].dataset.i18n ) { + nodes[i].innerHTML = browser.i18n.getMessage(value); } } }); diff --git a/src/drivers/webextension/js/iframe.js b/src/drivers/webextension/js/iframe.js deleted file mode 100644 index d37f91ef1..000000000 --- a/src/drivers/webextension/js/iframe.js +++ /dev/null @@ -1,1166 +0,0 @@ -'use strict'; - -(function(win) { - -var exports = {}; - -(function(exports) { - - var utils = { - normalizeUrl: function(url) { - - return this.hashUrl(url) || null; - - }, - - getReferrer: function() { - return this.normalizeUrl(document.referrer); - }, - - getPageUrl: function() { - return this.normalizeUrl(window.location.href); - }, - hashUrl: function(url) { - var a, - result; - - if ( !url || url.indexOf('http') !== 0 ) { - return null; - } - - a = document.createElement('a'); - a.href = url; - - result = a.protocol + '//' + a.hostname + '/'; - - if ( a.pathname && a.pathname !== '/' ) { - result += this.hashCode(a.pathname); - } - - if ( a.search ) { - result += '?' + this.hashCode(a.search); - } - - if ( a.hash ) { - result += '#' + this.hashCode(a.hash); - } - - return result; - }, - - hashCode: function(str) { - var hash = 0, - kar, - i; - - if ( str.length === 0 ) { - return hash; - } - - for ( i = 0; i < str.length; i++ ) { - kar = str.charCodeAt(i); - hash = ((hash << 5) - hash) + kar; - hash = hash & hash; - } - - return hash + Math.pow(2, 32); - }, - - realArray: function(a) { - return Array.prototype.slice.apply(a); - }, - - onDocLoaded: function(doc, callback) { - if ( doc.readyState === 'loading' ) { - doc.addEventListener('DOMContentLoaded', callback); - } else { - callback(); - } - }, - - SCRIPT_IN_WINDOW_TOP: window === window.top, - - isFriendlyWindow: function(win) { - - var href; - try { - href = win.location.href; - } catch(e) { - return false; - } - return true; - }, - - elementWindow: function(el) { - return el.ownerDocument.defaultView; - }, - - viewport: function(win) { - return {width: win.innerWidth, height: win.innerHeight}; - }, - - parseQS: function(qs) { - if ( qs.indexOf('http') === 0 ) { - qs = qs.split('?')[1]; - } - var i, kvs, key, val; - var dict = {}; - qs = qs.split('&'); - for ( i = 0; i < qs.length; i++ ) { - kvs = qs[i].split('='); - key = kvs[0]; - val = kvs.slice(1).join('='); - try { - dict[key] = window.decodeURIComponent(val); - } catch (e) { - - continue; - } - } - return dict; - }, - sendToBackground: function(message, event, responseMessage, onResponse) { - if ( typeof browser !== 'undefined' ) { - var response = browser.runtime.sendMessage(message); - response.then(onResponse); - } else if ( typeof chrome !== 'undefined' ) { - chrome.runtime.sendMessage(message, onResponse); - } else if ( window.self.port ) { - window.self.port.on(responseMessage, onResponse); - window.self.port.emit(event, message); - } - }, - - ifTrackingEnabled: function(callback, elseCallback) { - - this.sendToBackground( - 'is_tracking_enabled', - '', - 'tracking_enabled_response', - function(message) { - if ( message.tracking_enabled ) { - - callback(); - } else { - - elseCallback(); - } - } - ); - - } - }; - - utils.SCRIPT_IN_FRIENDLY_IFRAME = !utils.SCRIPT_IN_WINDOW_TOP && utils.isFriendlyWindow(window.parent); - utils.SCRIPT_IN_HOSTILE_IFRAME = !utils.SCRIPT_IN_WINDOW_TOP && !utils.SCRIPT_IN_FRIENDLY_IFRAME; - - function LogGenerator() { - this.msgNum = 0; - this.pageMeta = { - 'url': utils.getPageUrl(), - 'isHP': window.location.pathname === '/', - 'referrer': utils.getReferrer(), - 'rand': Math.floor(Math.random() * 10e12), - 'startTime': new Date().getTime() - }; - } - - LogGenerator.prototype = { - log: function(event, opt_assets, opt_pageTags) { - var opt_video_assets; - if ( event === 'video' || event === 'invalid-video' ) { - opt_video_assets = opt_assets || []; - opt_assets = []; - } else { - opt_video_assets = []; - opt_assets = opt_assets || []; - } - var result = { - doc: this.pageMeta, - event: event, - video_assets: opt_video_assets, - assets: opt_assets, - version: '3', - mrev: '9c4d5b3-c', - msgNum: this.msgNum, - timestamp: new Date().getTime(), - pageVis: document.visibilityState, - pageFoc: document.hasFocus(), - pageTags: opt_pageTags || [] - }; - this.msgNum++; - return result; - } - }; - - utils.LogGenerator = LogGenerator; - - exports.utils = utils; -})(exports); - -(function(exports) { - - var SizeMatcher = { - VALID_AD_SIZES: [ - [300, 50], - [320, 50], - [160, 600], - [300, 250], - [300, 600], - [300, 1050], - [336, 280], - [336, 850], - [468, 60], - [728, 90], - [728, 250], - [728, 270], - [970, 66], - [970, 90], - [970, 125], - [970, 250], - [970, 400], - [970, 415], - [1280, 100] - ], - - PX_SIZE_TOL: 10, - - getMatchedAdSize: function(width, height) { - - if ( !this.set ) { - this.set = this._makeSizeSet(); - } - - return this.set[Math.round(width) + 'x' + Math.round(height)]; - }, - - elementIsAdShaped: function(el) { - return !!this.getMatchedAdSizeForElement(el); - }, - - getMatchedAdSizeForElement: function(el) { - var rect = el.getBoundingClientRect(); - return this.getMatchedAdSize(rect.width, rect.height); - }, - - _makeSizeSet: function() { - var set = {}; - var i; - var xfuz; - var yfuz; - var size; - var width; - var height; - - for ( i = 0; i < this.VALID_AD_SIZES.length; i++ ) { - for ( xfuz = -this.PX_SIZE_TOL; xfuz <= this.PX_SIZE_TOL; xfuz++ ) { - for ( yfuz = -this.PX_SIZE_TOL; yfuz <= this.PX_SIZE_TOL; yfuz++ ) { - size = this.VALID_AD_SIZES[i]; - width = size[0] + xfuz; - height = size[1] + yfuz; - set[width + 'x' + height] = size; - } - } - } - return set; - } - }; - - var Throttler = { - MAX_SEARCHES_PER_WINDOW: 10, - MAX_SEARCHES_PER_ELEMENT: 2, - - countSearch: function(el) { - if ( typeof el.searches !== 'number' ) { - el.searches = 0; - } - - el.searches += 1; - }, - - throttle: function(el, max) { - if ( typeof el.searches === 'number' && el.searches >= max ) { - return true; - } - return false; - }, - - throttleElement: function(el) { - return this.throttle(el, this.MAX_SEARCHES_PER_ELEMENT); - }, - - throttleWin: function(win) { - return this.throttle(win, this.MAX_SEARCHES_PER_WINDOW); - }, - - getCount: function(el) { - return el.searches || 0; - } - }; - - function TopSearcher(win) { - this.win = win; - this.doc = win.document; - } - - TopSearcher.prototype.search = function() { - var candidates = exports.utils.realArray(this.doc.querySelectorAll('img, object, embed')), - html5Ad, - ads = []; - - ads = ads.concat(candidates.filter(function(el) { - if ( !el.mpAdFound && !Throttler.throttleElement(el) ) { - Throttler.countSearch(el); - if ( (el.tagName !== 'IMG' || isStandardImage(el)) && SizeMatcher.elementIsAdShaped(el) ) { - el.mpAdFound = true; - return true; - } - } - return false; - })); - - html5Ad = this._mainGetHTMLAd(); - if ( html5Ad ) { - html5Ad.html5 = true; - html5Ad.mpAdFound = true; - ads.push(html5Ad); - } - - return ads; - }; - - TopSearcher.prototype._mainGetHTMLAd = function() { - var styles = this.doc.querySelectorAll('div > style, div > link[rel="stylesheet"]'), - i, div; - for ( i = 0; i < styles.length; i++ ) { - div = styles[i].parentNode; - if ( !div.mpAdFound && SizeMatcher.elementIsAdShaped(div) && this._jumpedOut(div) ) { - return div; - } - } - }; - - TopSearcher.prototype._jumpedOut = function(el) { - var siblings, ifrs; - siblings = exports.utils.realArray(el.parentNode.children); - ifrs = siblings.filter(function(el) { - return el.tagName === 'IFRAME' && el.offsetWidth === 0 && el.offsetHeight === 0; - }); - return ifrs.length > 0; - }; - - function IframeSearcher(win) { - this.MIN_AD_AREA = 14000; - this.MIN_WINDOW_PX = 10; - - this.win = win; - this.doc = win.document; - this.body = win.document.body; - this.winClickTag = win.clickTag; - this.adSizeMeta = this._getAdSizeMeta(); - this.numElementsInBody = (this.body && this.body.querySelectorAll('*').length) || 0; - - this.shouldSearchWindow = false; - if ( !this.win.mpAdFound && this.body && !Throttler.throttleWin(this.win) ) { - this.winWidth = this.win.innerWidth; - this.winHeight = this.win.innerHeight; - if ( this._meetsMinAdSize(this.winWidth, this.winHeight) && !this._containsLargeIframes() ) { - this.shouldSearchWindow = true; - } - } - - } - - IframeSearcher.prototype.search = function() { - var ad; - - if ( this.shouldSearchWindow ) { - ad = this._search(); - if ( ad ) { - ad.mpAdFound = true; - win.mpAdFound = true; - return ad; - } - Throttler.countSearch(this.win); - } - - return null; - }; - - IframeSearcher.prototype._search = function() { - var _this = this, - stdCandidates, - html5Candidates, - stdEl, - html5El; - - stdCandidates = this.body.querySelectorAll('img, object, embed'); - - stdEl = getFirst(stdCandidates, function(el) { - if ( !el.mpAdFound && - !Throttler.throttleElement(el) && - (el.tagName !== 'IMG' || isStandardImage(el)) && - _this._elementIsAtLeastAsBigAsWindow(el)) - { - return true; - } - Throttler.countSearch(el); - return false; - }); - - if ( stdEl ) { - return stdEl; - } - - if ( this._isHTML5Iframe() ) { - html5Candidates = this.doc.querySelectorAll('body, canvas, button, video, svg, div'); - html5El = getFirst(html5Candidates, function(el) { - - if ( _this._elementIsAtLeastAsBigAsWindow(el) ) { - return true; - } - Throttler.countSearch(el); - return false; - }); - } - - if ( html5El ) { - html5El.html5 = true; - html5El.winClickTag = this.winClickTag; - html5El.adSizeMeta = this.adSizeMeta; - return html5El; - } - - return null; - }; - - IframeSearcher.prototype._isHTML5Iframe = function() { - if ( this.winClickTag || this.adSizeMeta ) { - return true; - } - - if ( this.doc.querySelectorAll('canvas', 'button', 'video', 'svg').length > 0 ) { - return true; - } - - if ( this.numElementsInBody >= 5 && Throttler.getCount(this.win) > 0 && this.doc.querySelectorAll('div').length > 0 ) { - return true; - } - - return false; - }; - - IframeSearcher.prototype._elementIsAtLeastAsBigAsWindow = function(el) { - var rect = el.getBoundingClientRect(), - tol = 0.95; - - return rect.width >= (tol * this.winWidth) && rect.height >= (tol * this.winHeight); - }; - - IframeSearcher.prototype._meetsMinAdSize = function(width, height) { - return (width * height) >= this.MIN_AD_AREA; - }; - - IframeSearcher.prototype._containsLargeIframes = function() { - var iframes = this.doc.querySelectorAll('iframe'); - var rect; - var i; - for ( i = 0; i < iframes.length; i++ ) { - rect = iframes[i].getBoundingClientRect(); - if ( rect.width > this.MIN_WINDOW_PX || rect.height > this.MIN_WINDOW_PX ) { - return true; - } - } - return false; - }; - - IframeSearcher.prototype._getAdSizeMeta = function() { - var adSizeMeta = this.doc.querySelectorAll('meta[name="ad.size"]'); - if ( adSizeMeta.length > 0 ) { - return adSizeMeta[0].content; - } else { - return null; - } - }; - - function getFirst(arr, testFn) { - var i, el; - for ( i = 0; i < arr.length; i++ ) { - el = arr[i]; - if ( testFn(el) ) { - return el; - } - } - return null; - } - - function isStandardImage(img) { - - return img.src && (img.parentNode.tagName === 'A' || img.getAttribute('onclick')); - } - - function getFriendlyIframes(win) { - var iframes = win.document.querySelectorAll('iframe'); - iframes = exports.utils.realArray(iframes); - var friendlyIframes = iframes.filter(function(ifr) { - return exports.utils.isFriendlyWindow(ifr.contentWindow); - }); - return friendlyIframes; - } - - function findAds(win) { - var i, - iframes, - searcher, - ad, - ads = []; - - if ( win === win.top ) { - searcher = new TopSearcher(win); - ads = ads.concat(searcher.search()); - } else { - searcher = new IframeSearcher(win); - ad = searcher.search(); - if ( ad ) { - ads.push(ad); - } - } - - iframes = getFriendlyIframes(win); - for ( i = 0; i < iframes.length; i++ ) { - ads = ads.concat(findAds(iframes[i].contentWindow)); - } - - return ads; - } - - exports.adfinder = { - getMatchedAdSize: SizeMatcher.getMatchedAdSize.bind(SizeMatcher), - findAds: findAds - }; -})(exports); - -(function(exports) { - - var parser = { - TAGS_WITH_SRC_ATTR: { - 'IMG': true, - 'SCRIPT': true, - 'IFRAME': true, - 'EMBED': true - }, - - MAX_ATTR_LEN: 100, - - getUrl: function(el, params) { - var url; - - if ( this.TAGS_WITH_SRC_ATTR.hasOwnProperty(el.tagName) ) { - url = el.src; - - } else if ( el.tagName === 'OBJECT' ) { - url = el.data || (params && params.movie) || null; - - } else if ( el.tagName === 'A' ) { - url = el.href; - } - - if ( url && url.indexOf('http') === 0 ) { - return url; - } else { - return null; - } - }, - - getParams: function(el) { - if ( el.tagName !== 'OBJECT' ) { - return null; - } - - var i, child; - var params = {}; - var children = el.children; - for ( i = 0; i < children.length; i++ ) { - child = children[i]; - if ( child.tagName === 'PARAM' && child.name ) { - - params[child.name.toLowerCase()] = child.value; - } - } - return params; - }, - - getPosition: function(el) { - var rect = el.getBoundingClientRect(); - var win = exports.utils.elementWindow(el); - - return { - width: Math.round(rect.width), - height: Math.round(rect.height), - left: Math.round(rect.left + win.pageXOffset), - top: Math.round(rect.top + win.pageYOffset) - }; - }, - - getFlashvars: function(el, params, url) { - var flashvars; - var urlQS = url && url.split('?')[1]; - - if ( el.tagName === 'EMBED' ) { - flashvars = el.getAttribute('flashvars') || urlQS; - - } else if ( el.tagName === 'OBJECT' ) { - flashvars = params.flashvars || el.getAttribute('flashvars') || urlQS; - } - - return (flashvars && exports.utils.parseQS(flashvars)) || null; - }, - - findClickThru: function(el, flashvars) { - var key; - if ( el.tagName === 'IMG' && el.parentElement.tagName === 'A' ) { - return el.parentElement.href; - } else if ( flashvars ) { - for ( key in flashvars ) { - if ( flashvars.hasOwnProperty(key) ) { - - if ( key.toLowerCase().indexOf('clicktag') === 0 ) { - return flashvars[key]; - } - } - } - } - return null; - }, - - getAttr: function(el, name) { - var val = el.getAttribute(name); - - if ( val && val.slice && val.toString ) { - - return val.slice(0, this.MAX_ATTR_LEN).toString(); - } else { - return null; - } - }, - - putPropIfExists: function(obj, name, val) { - if ( val ) { - obj[name] = val; - } - }, - - putAttrIfExists: function(obj, el, name) { - var val = this.getAttr(el, name); - this.putPropIfExists(obj, name, val); - }, - - elementToJSON: function(el, opt_findClickThru) { - var pos = this.getPosition(el); - var params = this.getParams(el); - var url = this.getUrl(el, params); - var flashvars = this.getFlashvars(el, params, url); - var clickThru = opt_findClickThru && this.findClickThru(el, flashvars); - var json = { - tagName: el.tagName, - width: pos.width, - height: pos.height, - left: pos.left, - top: pos.top, - children: [] - }; - - if ( params ) { - - delete params.flashvars; - } - - this.putAttrIfExists(json, el, 'id'); - this.putAttrIfExists(json, el, 'class'); - this.putAttrIfExists(json, el, 'name'); - - this.putPropIfExists(json, 'flashvars', flashvars); - this.putPropIfExists(json, 'url', url); - this.putPropIfExists(json, 'params', params); - this.putPropIfExists(json, 'clickThru', clickThru); - - return json; - } - }; - - exports.parser = { elementToJSON: parser.elementToJSON.bind(parser) }; -})(exports); - -(function(exports) { - - var ContextManager = function(adData) { - this.adData = adData; - }; - - ContextManager.prototype = { - CONTAINER_SIZE_TOL: 0.4, - ASPECT_RATIO_FOR_LEADERBOARDS: 2, - - isValidContainer: function(el, opt_curWin) { - - var cWidth = el.clientWidth; - var cHeight = el.clientHeight; - - var adWidth = this.adData.width; - var adHeight = this.adData.height; - - var winWidth = opt_curWin && opt_curWin.innerWidth; - var winHeight = opt_curWin && opt_curWin.innerHeight; - var similarWin = opt_curWin && this.withinTol(adWidth, winWidth) && this.withinTol(adHeight, winHeight); - - var similarSizeX = this.withinTol(adWidth, cWidth); - var similarSizeY = this.withinTol(adHeight, cHeight); - var adAspect = adWidth / adHeight; - - return similarWin || el.tagName === 'A' || (adAspect >= this.ASPECT_RATIO_FOR_LEADERBOARDS && similarSizeY) || (similarSizeX && similarSizeY); - }, - - withinTol: function(adlen, conlen) { - var pct = (conlen - adlen) / adlen; - - return pct <= this.CONTAINER_SIZE_TOL; - }, - - serializeElements: function(el) { - if ( !el ) { - return; - } - var i; - var ifrWin; - var adId = this.adData.adId; - var elIsAd = false; - - if ( adId && el[adId] && el[adId].isAd === true ) { - elIsAd = true; - } - - var json = exports.parser.elementToJSON(el, elIsAd); - var childJSON; - - if ( elIsAd ) { - json.adId = adId; - this.adData.element = {}; - - var keys = Object.keys(json); - for ( i = 0; i < keys.length; i++ ) { - var key = keys[i]; - if ( key !== 'children' && key !== 'contents' ) { - this.adData.element[key] = json[key]; - } - } - } - - var children = exports.utils.realArray(el.children).filter(function(el) { - var param = el.tagName === 'PARAM'; - var inlineScript = el.tagName === 'SCRIPT' && !(el.src && el.src.indexOf('http') >= 0); - var noScript = el.tagName === 'NOSCRIPT'; - return !(param || inlineScript || noScript); - }); - - for ( i = 0; i < children.length; i++ ) { - childJSON = this.serializeElements(children[i]); - if ( childJSON ) { - json.children.push(childJSON); - } - } - - if ( el.tagName === 'IFRAME' ) { - ifrWin = el.contentWindow; - - if ( adId && el[adId] && el[adId].needsWindow ) { - - json.contents = this.adData.serializedIframeContents; - el[adId].needsWindow = false; - delete this.adData.serializedIframeContents; - - } else if ( exports.utils.isFriendlyWindow(ifrWin) ) { - - childJSON = this.serializeElements(ifrWin.document.documentElement); - if ( childJSON ) { - json.contents = childJSON; - } - } - } - - if ( json.children.length > 0 || json.adId || json.tagName === 'IFRAME' || json.url ) { - return json; - } else { - return null; - } - }, - - captureHTML: function(containerEl) { - this.adData.context = this.serializeElements(containerEl); - }, - - nodeCount: function(el) { - return el.getElementsByTagName('*').length + 1; - }, - - highestContainer: function(curWin, referenceElement) { - var curContainer = referenceElement; - var docEl = curWin.document.documentElement; - var parentContainer; - - if ( curWin !== curWin.top && this.isValidContainer(docEl, curWin) ) { - return docEl; - } - - while ( true ) { - parentContainer = curContainer.parentElement; - if ( parentContainer && this.isValidContainer(parentContainer) ) { - curContainer = parentContainer; - } else { - return curContainer; - } - } - } - }; - - var tagfinder = { - - setPositions: function(adData, opt_el, opt_winPos) { - var el = opt_el || adData.context; - var winPos = opt_winPos || {left: 0, top: 0}; - var ifrPos; - - el.left += winPos.left; - el.top += winPos.top; - - if ( el.children ) { - el.children.forEach(function(child) { - this.setPositions(adData, child, winPos); - }, this); - } - - if ( el.contents ) { - ifrPos = {left: el.left, top: el.top}; - this.setPositions(adData, el.contents, ifrPos); - } - - if ( el.adId === adData.adId ) { - adData.element.left = el.left; - adData.element.top = el.top; - } - }, - - appendTags: function(adData, referenceElement) { - var mgr = new ContextManager(adData); - var curWin = exports.utils.elementWindow(referenceElement); - var highestContainer; - - while ( true ) { - highestContainer = mgr.highestContainer(curWin, referenceElement); - mgr.captureHTML(highestContainer); - if ( curWin === curWin.top ) { - break; - } else { - - curWin.mpAdFound = true; - - mgr.adData.serializedIframeContents = mgr.adData.context; - - if ( exports.utils.isFriendlyWindow(curWin.parent) ) { - referenceElement = curWin.frameElement; - referenceElement[mgr.adData.adId] = {needsWindow: true}; - curWin = curWin.parent; - } else { - break; - } - } - } - return { - referenceElement:referenceElement, - highestContainer: highestContainer - }; - } - }; - - exports.tagfinder = tagfinder; -})(exports); - -(function(exports) { - var _onAdFound; - var _logGen = new exports.utils.LogGenerator(); - var _pageTags; - var INIT_MS_BW_SEARCHES = 2000; - var PAGE_TAG_RE = new RegExp('gpt|oascentral'); - var POST_MSG_ID = '1490888598-28717-31700-14775-21098'; - var AD_SERVER_RE = new RegExp('^(google_ads_iframe|oas_frame|atwAdFrame)'); - - function getPageTags(doc) { - var scripts = doc.getElementsByTagName('script'); - var pageTags = []; - scripts = exports.utils.realArray(scripts); - scripts.forEach(function(script) { - if ( PAGE_TAG_RE.exec(script.src) ) { - pageTags.push({'tagName': 'SCRIPT', 'url': script.src}); - } - }); - return pageTags; - } - - function messageAllParentFrames(adData) { - - adData.postMessageId = POST_MSG_ID; - - adData = JSON.stringify(adData); - - var win = window; - while ( win !== win.top ) { - win = win.parent; - win.postMessage(adData, '*'); - } - } - - function appendTagsAndSendToParent(adData, referenceElement) { - var results = exports.tagfinder.appendTags(adData, referenceElement); - if ( exports.utils.SCRIPT_IN_HOSTILE_IFRAME ) { - messageAllParentFrames(adData); - - } else if ( exports.utils.SCRIPT_IN_WINDOW_TOP ) { - - exports.tagfinder.setPositions(adData); - - adData.matchedSize = exports.adfinder.getMatchedAdSize(adData.width, adData.height); - if ( !adData.matchedSize ) { - - if ( AD_SERVER_RE.exec(results.referenceElement.id) ) { - adData.matchedSize = [adData.width, adData.height]; - adData.oddSize = true; - } else { - - return; - } - } - delete adData.width; - delete adData.height; - adData.curPageUrl = exports.utils.getPageUrl(); - _pageTags = _pageTags || getPageTags(document); - var log = _logGen.log('ad', [adData], _pageTags); - - if ( _onAdFound ) { - - _onAdFound(log, results.referenceElement); - - } - } - } - - function extractAdsWrapper() { - if ( exports.utils.SCRIPT_IN_WINDOW_TOP || document.readyState === 'complete' ) { - extractAds(); - } - setTimeout( - function() { extractAdsWrapper(); }, INIT_MS_BW_SEARCHES - ); - } - - function extractAds() { - var ads = exports.adfinder.findAds(window); - ads.forEach(function(ad) { - - var startTime = new Date().getTime(); - var adId = startTime + '-' + Math.floor(Math.random() * 10e12); - - var adData = { - width: Math.round(ad.offsetWidth), - height: Math.round(ad.offsetHeight), - startTime: startTime, - adId: adId, - html5: ad.html5 || false - }; - - if ( ad.html5 ) { - adData.adSizeMeta = ad.adSizeMeta || null; - adData.winClickTag = ad.winClickTag || null; - } - - ad[adId] = { isAd: true }; - - appendTagsAndSendToParent(adData, ad); - }); - } - - function isChildWin(myWin, otherWin) { - var parentWin = otherWin.parent; - while ( parentWin !== otherWin ) { - if ( parentWin === myWin ) { - return true; - } - otherWin = parentWin; - parentWin = parentWin.parent; - } - return false; - } - - function iframeFromWindow(win, winToMatch) { - var i, ifr, ifrWin, - iframes = win.document.querySelectorAll('iframe'); - - for ( i = 0; i < iframes.length; i++ ) { - ifr = iframes[i]; - if ( ifr.contentWindow === winToMatch ) { - return ifr; - } - } - - for ( i = 0; i < iframes.length; i++ ) { - ifrWin = iframes[i].contentWindow; - if ( exports.utils.isFriendlyWindow(ifrWin) ) { - ifr = iframeFromWindow(ifrWin, winToMatch); - if ( ifr ) { - return ifr; - } - } - } - } - - function onPostMessage(event) { - var adData, - ifrWin = event.source, - - myWin = window.document.defaultView, - ifrTag; - - try { - - adData = JSON.parse(event.data); - } catch(e) { - - return; - } - - if ( adData.postMessageId === POST_MSG_ID ) { - - delete adData.postMessageId; - - event.stopImmediatePropagation(); - - if ( isChildWin(myWin, ifrWin) ) { - if ( exports.utils.isFriendlyWindow(ifrWin) ) { - ifrTag = ifrWin.frameElement; - } else { - ifrTag = iframeFromWindow(myWin, ifrWin); - } - - if ( ifrTag ) { - ifrTag[adData.adId] = {needsWindow: true}; - appendTagsAndSendToParent(adData, ifrTag); - } - } - } - } - - function onVideoMessage(msg, sender, callback) { - var log; - if ( msg.event === 'new-video-ad' ) { - msg.assets.forEach(function(asset) { - - }); - log = _logGen.log('video', msg.assets); - } else { - log = _logGen.log('invalid-video', msg.assets); - } - - msg.assets.forEach(function(a) {delete a.isVideo;}); - log.displayAdFound = msg.displayAdFound; - log.requests = msg.requests; - log.data = msg.event_data; - - log.doc.finalPageUrl = log.doc.url; - log.doc.url = exports.utils.normalizeUrl(msg.origUrl); - - _onAdFound(log); - } - - function addBackgroundListener(event, callback) { - if ( typeof browser !== 'undefined' ) { - browser.runtime.onMessage.addListener(function(msg) { - if ( msg.event === event ) { - callback(msg); - } - }); - } else if ( typeof chrome !== 'undefined' ) { - chrome.runtime.onMessage.addListener(function(msg) { - if ( msg.event === event ) { - callback(msg); - } - }); - } else if ( window.self.port ) { - window.self.port.on(event, callback); - } - } - - exports.coordinator = { - addPostMessageListener: function() { - if ( !exports.utils.SCRIPT_IN_FRIENDLY_IFRAME ) { - window.addEventListener('message', onPostMessage, false); - } - }, - - init: function(onAdFound) { - - if ( exports.utils.SCRIPT_IN_FRIENDLY_IFRAME ) { - return false; - } - - _onAdFound = onAdFound; - if ( exports.utils.SCRIPT_IN_WINDOW_TOP ) { - var log = _logGen.log('page'); - onAdFound(log); - - window.addEventListener('beforeunload', function(event) { - var log = _logGen.log('unload'); - log.timing = window.performance.timing; - onAdFound(log); - }); - - addBackgroundListener('new-video-ad', onVideoMessage); - addBackgroundListener('new-invalid-video-ad', onVideoMessage); - - } - - exports.utils.onDocLoaded(document, extractAdsWrapper); - } - }; - -})(exports); - -if ( exports.utils.SCRIPT_IN_WINDOW_TOP ) { - window.adparser = { - init: exports.coordinator.init, - addPostMessageListener: exports.coordinator.addPostMessageListener, - ifTrackingEnabled: exports.utils.ifTrackingEnabled, - sendToBackground: exports.utils.sendToBackground - }; -} else { - exports.coordinator.addPostMessageListener(); - exports.utils.ifTrackingEnabled( - function() { - exports.coordinator.init(function() {}); - }, - function() {} - ); -} -})(window); -(function(adparser) { - function onAdFound(log) { - adparser.sendToBackground({ id: 'ad_log', subject: log }, 'ad_log', '', function(){}); - } - - if ( window === window.top ) { - adparser.addPostMessageListener(); - adparser.ifTrackingEnabled( - function() { - adparser.init(onAdFound); - }, - function() {} - ) - } -})(window.adparser); diff --git a/src/drivers/webextension/js/inject.js b/src/drivers/webextension/js/inject.js index fd734182e..2369c2583 100644 --- a/src/drivers/webextension/js/inject.js +++ b/src/drivers/webextension/js/inject.js @@ -10,5 +10,7 @@ document.getElementById('wappalyzerData').appendChild(document.createComment(environmentVars)); document.getElementById('wappalyzerData').dispatchEvent(e); - } catch(e) { } + } catch(e) { + // Fail quietly + } }()); diff --git a/src/drivers/webextension/js/ms_background_scripts_api_bridge.js b/src/drivers/webextension/js/ms_background_scripts_api_bridge.js new file mode 100644 index 000000000..d023cf1b0 --- /dev/null +++ b/src/drivers/webextension/js/ms_background_scripts_api_bridge.js @@ -0,0 +1,846 @@ +if (!Range.prototype["intersectsNode"]) { + Range.prototype["intersectsNode"] = function (node) { + let range = document.createRange(); + range.selectNode(node); + return 0 > this.compareBoundaryPoints(Range.END_TO_START, range) + && 0 < this.compareBoundaryPoints(Range.START_TO_END, range); + }; +} +var getExtensionProtocol = function () { + if (typeof browser == "undefined") { + if (typeof chrome !== "undefined") + return "chrome-extension://"; + } + else { + return "ms-browser-extension://"; + } +}; +class FakeEvent { + addListener(callback) { } + addRules(rules, callback) { } + getRules(ruleIdentifiers, callback) { } + hasListener(callback) { return false; } + hasListeners() { return false; } + removeRules(ruleIdentifiers, callback) { } + removeListener(callback) { } +} +class EdgeBridgeHelper { + constructor() { + this.fakeEvent = new FakeEvent(); + } + toAbsolutePath(relativePath) { + if (relativePath.indexOf("ms-browser-extension://") == 0) { + return relativePath.replace(myBrowser.runtime.getURL(""), ""); + } + else if (relativePath.indexOf("/") != 0) { + var absolutePath = ""; + var documentPath = document.location.pathname; + absolutePath = documentPath.substring(0, documentPath.lastIndexOf("/") + 1); + absolutePath += relativePath; + return absolutePath; + } + return relativePath; + } +} +var bridgeHelper = new EdgeBridgeHelper(); +class EdgeBridgeDebugLog { + constructor() { + this.CatchOnException = true; + this.VerboseLogging = true; + this.FailedCalls = {}; + this.SuccededCalls = {}; + this.DeprecatedCalls = {}; + this.BridgedCalls = {}; + this.UnavailableApis = {}; + this.EdgeIssues = {}; + } + log(message) { + try { + if (this.VerboseLogging) { + console.log(message); + } + } + catch (e) { + } + } + info(message) { + try { + if (this.VerboseLogging) { + console.info(message); + } + } + catch (e) { + } + } + warn(message) { + try { + if (this.VerboseLogging) { + console.warn(message); + } + } + catch (e) { + } + } + error(message) { + try { + if (this.VerboseLogging) { + console.error(message); + } + } + catch (e) { + } + } + DoActionAndLog(action, name, deprecatedTo, bridgedTo) { + var result; + try { + result = action(); + this.AddToCalledDictionary(this.SuccededCalls, name); + if (typeof deprecatedTo !== "undefined" && typeof deprecatedTo !== "null") { + this.warn("API Call Deprecated - Name: " + name + ", Please use " + deprecatedTo + " instead!"); + this.AddToCalledDictionary(this.DeprecatedCalls, name); + } + if (typeof bridgedTo !== "undefined" && typeof bridgedTo !== "null") { + this.info("API Call '" + name + "' has been bridged to another Edge API: " + bridgedTo); + this.AddToCalledDictionary(this.BridgedCalls, name); + } + return result; + } + catch (ex) { + this.AddToCalledDictionary(this.FailedCalls, name); + if (this.CatchOnException) + this.error("API Call Failed: " + name + " - " + ex); + else + throw ex; + } + } + LogEdgeIssue(name, message) { + this.warn(message); + this.AddToCalledDictionary(this.EdgeIssues, name); + } + LogUnavailbleApi(name, deprecatedTo) { + this.warn("API Call '" + name + "' is not supported in Edge"); + this.AddToCalledDictionary(this.UnavailableApis, name); + if (typeof deprecatedTo !== "undefined" && typeof deprecatedTo !== "null") { + this.warn("API Call Deprecated - Name: " + name + ", Please use " + deprecatedTo + " instead!"); + this.AddToCalledDictionary(this.DeprecatedCalls, name); + } + } + AddToCalledDictionary(dictionary, name) { + if (typeof dictionary[name] !== "undefined") { + dictionary[name]++; + } + else { + dictionary[name] = 1; + } + } +} +var bridgeLog = new EdgeBridgeDebugLog(); +class EdgeChromeAppBridge { + getDetails() { + return bridgeLog.DoActionAndLog(() => { + return EdgeChromeRuntimeBridge.prototype.getManifest(); + }, "app.getManifest", undefined, "runtime.getManifest"); + } + get isInstalled() { return bridgeLog.DoActionAndLog(() => { throw "app.isInstalled is not available in Edge"; }, "app.isInstalled"); } + getIsInstalled() { return bridgeLog.DoActionAndLog(() => { throw "app.getIsInstalled is not available in the Edge"; }, "app.getIsInstalled"); } + installState() { return bridgeLog.DoActionAndLog(() => { throw "app.installState is not available in Edge"; }, "app.installState"); } + runningState() { return bridgeLog.DoActionAndLog(() => { throw "app.runningState is not available in Edge"; }, "app.runningState"); } +} +class EdgeBrowserActionBridge { + get onClicked() { return bridgeLog.DoActionAndLog(() => { return myBrowser.browserAction.onClicked; }, "browserAction.onClicked"); } + disable(tabId) { + bridgeLog.DoActionAndLog(() => { + myBrowser.browserAction.disable(tabId); + }, "browserAction.disable"); + } + enable(tabId) { + bridgeLog.DoActionAndLog(() => { + if (typeof tabId !== "undefined" && typeof tabId !== "null") { + myBrowser.browserAction.enable(tabId); + } + else { + myBrowser.browserAction.enable(); + } + }, "browserAction.Enable"); + } + getBadgeBackgroundColor(details, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.browserAction.getBadgeBackgroundColor(details, callback); + }, "browserAction.getBadgeBackgroundColor"); + } + getBadgeText(details, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.browserAction.getBadgeText(details, callback); + }, "browserAction.getBadgeText"); + } + setBadgeBackgroundColor(details) { + bridgeLog.DoActionAndLog(() => { + myBrowser.browserAction.setBadgeBackgroundColor(details); + }, "browserAction.setBadgeBackgroundColor"); + } + setBadgeText(details) { + bridgeLog.DoActionAndLog(() => { + myBrowser.browserAction.setBadgeText(details); + }, "browserAction.setBadgeText"); + } + setIcon(details, callback) { + bridgeLog.DoActionAndLog(() => { + if (typeof details.path !== "undefined") { + if (typeof details.path === "object") { + for (var key in details.path) { + if (details.path.hasOwnProperty(key)) { + details.path[key] = bridgeHelper.toAbsolutePath(details.path[key]); + } + } + } + else { + details.path = bridgeHelper.toAbsolutePath(details.path); + } + } + if (typeof callback !== "undefined" && typeof callback !== "null") { + myBrowser.browserAction.setIcon(details, callback); + } + else { + myBrowser.browserAction.setIcon(details); + } + }, "browserAction.setIcon", undefined, "browserAction.setIcon with absolute path"); + } + setPopup(details) { + bridgeLog.DoActionAndLog(() => { + myBrowser.browserAction.setPopup(details); + }, "browserAction.setPopup"); + } +} +class EdgeChromeBrowserActionBridge extends EdgeBrowserActionBridge { + getPopup(details, callback) { + bridgeLog.LogUnavailbleApi("browserAction.getPopup"); + } + getTitle(details, callback) { + bridgeLog.LogUnavailbleApi("browserAction.getTitle"); + } + setTitle(details) { + bridgeLog.LogUnavailbleApi("browserAction.setTitle"); + } +} +class EdgeContextMenusBridge { + get ACTION_MENU_TOP_LEVEL_LIMIT() { return bridgeLog.DoActionAndLog(() => { return myBrowser.contextMenus.ACTION_MENU_TOP_LEVEL_LIMIT; }, "contextMenus.ACTION_MENU_TOP_LEVEL_LIMIT"); } + get onClicked() { return bridgeLog.DoActionAndLog(() => { return myBrowser.contextMenus.onClicked; }, "contextMenus.onClicked"); } + create(createProperties, callback) { + bridgeLog.DoActionAndLog(() => { + if (typeof callback !== "undefined" && typeof callback !== "null") { + myBrowser.contextMenus.create(createProperties, callback); + } + else { + myBrowser.contextMenus.create(createProperties); + } + }, "contextMenus.create"); + } + remove(menuItemId, callback) { + bridgeLog.DoActionAndLog(() => { + if (typeof callback !== "undefined" && typeof callback !== "null") { + myBrowser.contextMenus.remove(menuItemId, callback); + } + else { + myBrowser.contextMenus.remove(menuItemId); + } + }, "contextMenus.remove"); + } + removeAll(callback) { + bridgeLog.DoActionAndLog(() => { + if (typeof callback !== "undefined" && typeof callback !== "null") { + myBrowser.contextMenus.removeAll(callback); + } + else { + myBrowser.contextMenus.removeAll(); + } + }, "contextMenus.removeAll"); + } + update(id, updateProperties, callback) { + bridgeLog.DoActionAndLog(() => { + if (typeof callback !== "undefined" && typeof callback !== "null") { + myBrowser.contextMenus.update(id, updateProperties, callback); + } + else { + myBrowser.contextMenus.update(id, updateProperties); + } + }, "contextMenus.update"); + } +} +class EdgeCookiesBridge { + get(details, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.cookies.get(details, callback); + }, "cookies.get"); + } + getAll(details, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.cookies.getAll(details, callback); + }, "cookies.getAll"); + } + remove(details, callback) { + bridgeLog.DoActionAndLog(() => { + if (typeof callback !== "undefined" && typeof callback !== "null") { + myBrowser.cookies.remove(details, callback); + } + else { + myBrowser.cookies.remove(details); + } + }, "cookies.remove"); + } + set(details, callback) { + bridgeLog.DoActionAndLog(() => { + if (typeof callback !== "undefined" && typeof callback !== "null") { + myBrowser.cookies.set(details, callback); + } + else { + myBrowser.cookies.set(details); + } + }, "cookies.set"); + } +} +class EdgeChromeCookiesBridge extends EdgeCookiesBridge { + get onChanged() { bridgeLog.LogUnavailbleApi("cookies.onChanged"); return bridgeHelper.fakeEvent; } +} +class EdgeExtensionBridge { + getBackgroundPage() { + return bridgeLog.DoActionAndLog(() => { + return myBrowser.extension.getBackgroundPage(); + }, "extension.getBackgroundPage"); + } + getURL(path) { + return bridgeLog.DoActionAndLog(() => { + return myBrowser.extension.getURL(path); + }, "extension.getURL"); + } + getViews(fetchProperties) { + return bridgeLog.DoActionAndLog(() => { + return myBrowser.extension.getViews(fetchProperties); + }, "extension.getViews"); + } +} +class EdgeChromeExtensionBridge extends EdgeExtensionBridge { + get onConnect() { return bridgeLog.DoActionAndLog(() => { return EdgeRuntimeBridge.prototype.onConnect; }, "extension.onConnect", "runtime.onConnect", "runtime.onConnect"); } + get onMessage() { return bridgeLog.DoActionAndLog(() => { return myBrowser.runtime.onMessage; }, "extension.onMessage", "runtime.onMessage", "runtime.onMessage"); } + get onRequest() { return bridgeLog.DoActionAndLog(() => { return myBrowser.runtime.onMessage; }, "extension.onRequest", "runtime.onMessage", "runtime.onMessage"); } + get onRequestExternal() { return bridgeLog.DoActionAndLog(() => { return myBrowser.runtime.onMessageExternal; }, "extension.onRequestExternal", "runtime.onMessageExternal", "runtime.onMessageExternal"); } + get inIncognitoContext() { return bridgeLog.DoActionAndLog(() => { return myBrowser.extension["inPrivateContext"]; }, "extension.inIncognitoContext", undefined, "extension.inPrivateContext"); } + get lastError() { return bridgeLog.DoActionAndLog(() => { return myBrowser.runtime.lastError; }, "extension.lastError", undefined, "runtime.lastError"); } + connect(extensionId, connectInfo) { + return bridgeLog.DoActionAndLog(() => { + return EdgeRuntimeBridge.prototype.connect(extensionId, connectInfo); + }, "extension.connect", "runtime.connect", "runtime.connect"); + } + sendMessage(message, responseCallback) { + return bridgeLog.DoActionAndLog(() => { + return EdgeRuntimeBridge.prototype.sendMessage(message, responseCallback, undefined, undefined); + }, "extension.sendMessage", "runtime.sendMessage", "runtime.sendMessage"); + } + sendRequest(extensionId, message, options, responseCallback) { + return bridgeLog.DoActionAndLog(() => { + return EdgeRuntimeBridge.prototype.sendMessage(extensionId, message, options, responseCallback); + }, "extension.sendRequest", "runtime.sendMessage", "runtime.sendMessage"); + } + isAllowedFileSchemeAccess(callback) { + bridgeLog.LogUnavailbleApi("extension.isAllowedFileSchemeAccess"); + } + isAllowedIncognitoAccess(callback) { + bridgeLog.LogUnavailbleApi("extension.isAllowedIncognitoAccess"); + } + setUpdateUrlData(data) { + bridgeLog.LogUnavailbleApi("extension.setUpdateUrlData"); + } +} +class EdgeHistoryBridge { + get onVisited() { bridgeLog.LogUnavailbleApi("history.onVisited"); return bridgeHelper.fakeEvent; } + get onVisitRemoved() { bridgeLog.LogUnavailbleApi("history.onVisitRemoved"); return bridgeHelper.fakeEvent; } + addUrl(details, callback) { + bridgeLog.LogUnavailbleApi("history.addUrl"); + } + deleteAll(callback) { + bridgeLog.LogUnavailbleApi("history.deleteAll"); + } + deleteRange(range, callback) { + bridgeLog.LogUnavailbleApi("history.deleteRange"); + } + deleteUrl(details, callback) { + bridgeLog.LogUnavailbleApi("history.deleteUrl"); + } + getVisits(details, callback) { + bridgeLog.LogUnavailbleApi("history.getVisits"); + } + search(query, callback) { + bridgeLog.LogUnavailbleApi("history.search"); + } +} +class EdgeI18nBridge { + getAcceptLanguages(callback) { + return bridgeLog.DoActionAndLog(() => { + return myBrowser.i18n.getAcceptLanguages(callback); + }, "i18n.getAcceptLanguages"); + } + getMessage(messageName, substitutions) { + return bridgeLog.DoActionAndLog(() => { + if (messageName.indexOf("@@extension_id") > -1) { + return myBrowser.runtime.id; + } + if (typeof substitutions !== "undefined" && typeof substitutions !== "null") { + return myBrowser.i18n.getMessage(messageName, substitutions); + } + else { + return myBrowser.i18n.getMessage(messageName); + } + }, "i18n.getMessage"); + } + getUILanguage() { + return bridgeLog.DoActionAndLog(() => { + return myBrowser.i18n.getUILanguage(); + }, "i18n.getUILanguage"); + } +} +class EdgeNotificationBridge { + get onButtonClicked() { bridgeLog.LogUnavailbleApi("notifications.onButtonClicked"); return bridgeHelper.fakeEvent; } + get onClicked() { bridgeLog.LogUnavailbleApi("notifications.onClicked"); return bridgeHelper.fakeEvent; } + get onClosed() { bridgeLog.LogUnavailbleApi("notifications.onClosed"); return bridgeHelper.fakeEvent; } + get onPermissionLevelChanged() { bridgeLog.LogUnavailbleApi("notifications.onPermissionLevelChanged"); return bridgeHelper.fakeEvent; } + get onShowSettings() { bridgeLog.LogUnavailbleApi("notifications.onShowSettings"); return bridgeHelper.fakeEvent; } + clear(notificationId, callback) { + bridgeLog.LogUnavailbleApi("notifications.clear"); + } + create(notificationId, options, callback) { + bridgeLog.LogUnavailbleApi("notifications.create"); + } + getAll(callback) { + bridgeLog.LogUnavailbleApi("notifications.getAll"); + } + getPermissionLevel(callback) { + bridgeLog.LogUnavailbleApi("notifications.getPermissionLevel"); + } + update(notificationId, options, callback) { + bridgeLog.LogUnavailbleApi("notifications.update"); + } +} +class EdgePageActionBridge { + get onClicked() { return bridgeLog.DoActionAndLog(() => { return myBrowser.pageAction.onClicked; }, "pageAction.onClicked"); } + getPopup(details, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.pageAction.getPopup(details, callback); + }, "pageAction.getPopup"); + } + getTitle(details, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.pageAction.getTitle(details, callback); + }, "pageAction.getTitle"); + } + hide(tabId) { + bridgeLog.DoActionAndLog(() => { + myBrowser.pageAction.hide(tabId); + }, "pageAction.hide"); + } + setTitle(details) { + bridgeLog.DoActionAndLog(() => { + myBrowser.pageAction.setTitle(details); + }, "pageAction.setTitle"); + } + setIcon(details, callback) { + bridgeLog.DoActionAndLog(() => { + if (typeof callback !== "undefined" && typeof callback !== "null") { + myBrowser.pageAction.setIcon(details, callback); + } + else { + myBrowser.pageAction.setIcon(details, callback); + } + }, "pageAction.setIcon"); + } + setPopup(details) { + bridgeLog.DoActionAndLog(() => { + myBrowser.pageAction.setPopup(details); + }, "pageAction.setPopup"); + } + show(tabId) { + bridgeLog.DoActionAndLog(() => { + myBrowser.pageAction.show(tabId); + }, "pageAction.show"); + } +} +class EdgePermissionsBridge { + get onAdded() { bridgeLog.LogUnavailbleApi("permissions.onAdded"); return bridgeHelper.fakeEvent; } + get onRemoved() { bridgeLog.LogUnavailbleApi("permissions.onRemoved"); return bridgeHelper.fakeEvent; } + contains(permissions, callback) { + bridgeLog.LogUnavailbleApi("permissions.contains"); + } + getAll(callback) { + bridgeLog.LogUnavailbleApi("permissions.getAll"); + } + remove(permissions, callback) { + bridgeLog.LogUnavailbleApi("permissions.remove"); + } + request(permissions, callback) { + bridgeLog.LogUnavailbleApi("permissions.request"); + } +} +class EdgeRuntimeBridge { + get id() { return bridgeLog.DoActionAndLog(() => { return myBrowser.runtime.id; }, "runtime.id"); } + get lastError() { return bridgeLog.DoActionAndLog(() => { return myBrowser.runtime.lastError; }, "runtime.lastError"); } + get onConnect() { return bridgeLog.DoActionAndLog(() => { return myBrowser.runtime.onConnect; }, "runtime.onConnect"); } + get onInstalled() { return bridgeLog.DoActionAndLog(() => { return myBrowser.runtime.onInstalled; }, "runtime.onInstalled"); } + get onMessage() { return bridgeLog.DoActionAndLog(() => { return myBrowser.runtime.onMessage; }, "runtime.onMessage"); } + get onMessageExternal() { return bridgeLog.DoActionAndLog(() => { return myBrowser.runtime.onMessageExternal; }, "runtime.onMessageExternal"); } + connect(extensionId, connectInfo) { + return bridgeLog.DoActionAndLog(() => { + if (typeof connectInfo !== "undefined" && typeof connectInfo !== "null") { + return myBrowser.runtime.connect(extensionId, connectInfo); + } + else { + return myBrowser.runtime.connect(extensionId); + } + }, "runtime.connect"); + } + getBackgroundPage(callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.runtime.getBackgroundPage(callback); + }, "runtime.getBackgroundPage"); + } + getManifest() { + return bridgeLog.DoActionAndLog(() => { + return myBrowser.runtime.getManifest(); + }, "runtime.getManifest"); + } + getURL(path) { + return bridgeLog.DoActionAndLog(() => { + return myBrowser.runtime.getURL(path); + }, "runtime.getURL"); + } + sendMessage(extensionId, message, options, responseCallback) { + bridgeLog.DoActionAndLog(() => { + if (typeof responseCallback !== "undefined" && typeof responseCallback !== "null") { + myBrowser.runtime.sendMessage(extensionId, message, options, responseCallback); + } + else if (typeof options !== "undefined" && typeof options !== "null") { + myBrowser.runtime.sendMessage(extensionId, message, options); + } + else if (typeof message !== "undefined" && typeof message !== "null") { + myBrowser.runtime.sendMessage(extensionId, message); + } + else { + myBrowser.runtime.sendMessage(undefined, extensionId); + } + }, "runtime.sendMessage"); + } +} +class EdgeChromeRuntimeBridge extends EdgeRuntimeBridge { + get onConnectExternal() { bridgeLog.LogUnavailbleApi("runtime.onConnectExternal"); return bridgeHelper.fakeEvent; } + get onRestartRequired() { bridgeLog.LogUnavailbleApi("runtime.onRestartRequired"); return bridgeHelper.fakeEvent; } + get onStartup() { bridgeLog.LogUnavailbleApi("runtime.onStartup"); return bridgeHelper.fakeEvent; } + get onSuspend() { bridgeLog.LogUnavailbleApi("runtime.onSuspend"); return bridgeHelper.fakeEvent; } + get onSuspendCanceled() { bridgeLog.LogUnavailbleApi("runtime.onSuspendCanceled"); return bridgeHelper.fakeEvent; } + get onUpdateAvailable() { bridgeLog.LogUnavailbleApi("runtime.onUpdateAvailable"); return bridgeHelper.fakeEvent; } + openOptionsPage(callback) { + bridgeLog.DoActionAndLog(() => { + var optionsPage = myBrowser.runtime.getManifest()["options_page"]; + var optionsPageUrl = myBrowser.runtime.getURL(optionsPage); + if (typeof callback !== "undefined" && typeof callback !== "null") { + myBrowser.tabs.create({ url: optionsPageUrl }, callback); + } + else { + myBrowser.tabs.create({ url: optionsPageUrl }); + } + }, "runtime.openOptionsPage", undefined, "tabs.create({ url: optionsPageUrl })"); + } + connectNative(application) { + bridgeLog.LogUnavailbleApi("runtime.connectNative"); + return null; + } + getPackageDirectoryEntry(callback) { + bridgeLog.LogUnavailbleApi("runtime.getPackageDirectoryEntry"); + } + getPlatformInfo(callback) { + bridgeLog.LogUnavailbleApi("runtime.getPlatformInfo"); + } + reload() { + bridgeLog.LogUnavailbleApi("runtime.reload"); + } + requestUpdateCheck(callback) { + bridgeLog.LogUnavailbleApi("runtime.requestUpdateCheck"); + } + restart() { + bridgeLog.LogUnavailbleApi("runtime.restart"); + } + setUninstallURL(url, callback) { + bridgeLog.LogUnavailbleApi("runtime.setUninstallURL"); + } + sendNativeMessage(application, message, responseCallback) { + bridgeLog.LogUnavailbleApi("runtime.sendNativeMessage"); + } +} +class EdgeStorageBridge { + get local() { return bridgeLog.DoActionAndLog(() => { return myBrowser.storage.local; }, "storage.local"); } + get onChanged() { return bridgeLog.DoActionAndLog(() => { return myBrowser.storage.onChanged; }, "storage.onChanged"); } +} +class EdgeChromeStorageBridge extends EdgeStorageBridge { + get managed() { return bridgeLog.DoActionAndLog(() => { return myBrowser.storage.local; }, "storage.managed", undefined, "storage.local"); } + get sync() { return bridgeLog.DoActionAndLog(() => { return myBrowser.storage.local; }, "storage.sync", undefined, "storage.local"); } +} +class EdgeTabsBridge { + get onActivated() { return bridgeLog.DoActionAndLog(() => { return myBrowser.tabs.onActivated; }, "tabs.onActivated"); } + get onCreated() { return bridgeLog.DoActionAndLog(() => { return myBrowser.tabs.onCreated; }, "tabs.onCreated"); } + get onRemoved() { return bridgeLog.DoActionAndLog(() => { return myBrowser.tabs.onRemoved; }, "tabs.onRemoved"); } + get onReplaced() { return bridgeLog.DoActionAndLog(() => { return myBrowser.tabs.onReplaced; }, "tabs.onReplaced"); } + get onUpdated() { return bridgeLog.DoActionAndLog(() => { return myBrowser.tabs.onUpdated; }, "tabs.onUpdated"); } + create(createProperties, callback) { + bridgeLog.DoActionAndLog(() => { + if (typeof callback !== "undefined" && typeof callback !== "null") { + myBrowser.tabs.create(createProperties, callback); + } + else { + myBrowser.tabs.create(createProperties); + } + }, "tabs.create"); + } + detectLanguage(tabId, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.tabs.detectLanguage(tabId, callback); + }, "tabs.detectLanguage"); + } + executeScript(tabId, details, callback) { + bridgeLog.DoActionAndLog(() => { + if (typeof callback !== "undefined" && typeof callback !== "null") { + myBrowser.tabs.executeScript(tabId, details, callback); + } + else { + myBrowser.tabs.executeScript(tabId, details); + } + }, "tabs.executeScript"); + } + get(tabId, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.tabs.get(tabId, callback); + }, "tabs.get"); + } + getCurrent(callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.tabs.getCurrent(callback); + }, "tabs.getCurrent"); + } + insertCSS(tabId, details, callback) { + bridgeLog.DoActionAndLog(() => { + if (typeof callback !== "undefined" && typeof callback !== "null") { + myBrowser.tabs.insertCSS(tabId, details, callback); + } + else { + myBrowser.tabs.insertCSS(tabId, details); + } + }, "tabs.insertCSS"); + } + query(queryInfo, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.tabs.query(queryInfo, callback); + }, "tabs.query"); + } + remove(tabId, callback) { + bridgeLog.DoActionAndLog(() => { + if (typeof callback !== "undefined" && typeof callback !== "null") { + myBrowser.tabs.remove(tabId, callback); + } + else { + myBrowser.tabs.remove(tabId); + } + }, "tabs.remove"); + } + sendMessage(tabId, message, responseCallback) { + bridgeLog.DoActionAndLog(() => { + if (typeof responseCallback !== "undefined" && typeof responseCallback !== "null") { + myBrowser.tabs.sendMessage(tabId, message, responseCallback); + } + else { + myBrowser.tabs.sendMessage(tabId, message); + } + }, "tabs.sendMessage"); + } + update(tabId, updateProperties, callback) { + bridgeLog.DoActionAndLog(() => { + if (typeof callback !== "undefined" && typeof callback !== "null") { + myBrowser.tabs.update(tabId, updateProperties, callback); + } + else { + myBrowser.tabs.update(tabId, updateProperties); + } + }, "tabs.update"); + } +} +class EdgeChromeTabsBridge extends EdgeTabsBridge { + get onAttached() { bridgeLog.LogUnavailbleApi("tabs.onAttached"); return bridgeHelper.fakeEvent; } + get onDetached() { bridgeLog.LogUnavailbleApi("tabs.onDetached"); return bridgeHelper.fakeEvent; } + get onHighlighted() { bridgeLog.LogUnavailbleApi("tabs.onHighlighted"); return bridgeHelper.fakeEvent; } + get onMoved() { bridgeLog.LogUnavailbleApi("tabs.onMoved"); return bridgeHelper.fakeEvent; } + get onSelectionChanged() { + return bridgeLog.DoActionAndLog(() => { + var fakeEvent = bridgeHelper.fakeEvent; + fakeEvent.addListener = (callback) => { + myBrowser.tabs.onActivated.addListener((activeInfo) => { + callback(activeInfo.tabId, { windowId: activeInfo.windowId }); + }); + }; + return fakeEvent; + }, "tabs.onSelectionChanged", "tabs.onActivated", "tabs.onActivated"); + } + duplicate(tabId, callback) { + bridgeLog.DoActionAndLog(() => { + this.get(tabId, function (tab) { + if (typeof callback !== "undefined" && typeof callback !== "null") { + myBrowser.tabs.create({ url: tab.url }, callback); + } + else { + myBrowser.tabs.create({ url: tab.url }); + } + }); + }, "tabs.duplicate", undefined, "tabs.create"); + } + getAllInWindow(windowId, callback) { + bridgeLog.DoActionAndLog(() => { + this.query({ windowId: windowId }, callback); + }, "tabs.getAllInWindow", "tabs.query", "tabs.query"); + } + getSelected(windowId, callback) { + bridgeLog.DoActionAndLog(() => { + this.query({ active: true }, (tabs) => callback(tabs[0])); + }, "tabs.getSelected", "tabs.query", "tabs.query"); + } + sendRequest(tabId, request, responseCallback) { + bridgeLog.DoActionAndLog(() => { + this.sendMessage(tabId, request, responseCallback); + }, "tabs.sendRequest", "tabs.sendMessage", "tabs.sendMessage"); + } + captureVisibleTab(windowId, options, callback) { + bridgeLog.LogUnavailbleApi("tabs.captureVisibleTab"); + } + connect(tabId, connectInfo) { + bridgeLog.LogUnavailbleApi("tabs.connect"); + return null; + } + highlight(highlightInfo, callback) { + bridgeLog.LogUnavailbleApi("tabs.highlight"); + } + move(tabId, moveProperties, callback) { + bridgeLog.LogUnavailbleApi("tabs.move"); + } + reload(tabId, reloadProperties, callback) { + bridgeLog.LogUnavailbleApi("tabs.reload"); + } +} +class EdgeWebNavigationBridge { + get onBeforeNavigate() { return bridgeLog.DoActionAndLog(() => { return myBrowser.webNavigation.onBeforeNavigate; }, "webNavigation.onBeforeNavigate"); } + get onCommitted() { return bridgeLog.DoActionAndLog(() => { return myBrowser.webNavigation.onCommitted; }, "webNavigation.onCommitted"); } + get onCompleted() { return bridgeLog.DoActionAndLog(() => { return myBrowser.webNavigation.onCompleted; }, "webNavigation.onCompleted"); } + get onCreatedNavigationTarget() { return bridgeLog.DoActionAndLog(() => { return myBrowser.webNavigation.onCreatedNavigationTarget; }, "webNavigation.onCreatedNavigationTarget"); } + get onDOMContentLoaded() { return bridgeLog.DoActionAndLog(() => { return myBrowser.webNavigation.onDOMContentLoaded; }, "webNavigation.onDOMContentLoaded"); } + get onErrorOccurred() { return bridgeLog.DoActionAndLog(() => { return myBrowser.webNavigation.onErrorOccurred; }, "webNavigation.onErrorOccurred"); } + get onHistoryStateUpdated() { return bridgeLog.DoActionAndLog(() => { return myBrowser.webNavigation.onHistoryStateUpdated; }, "webNavigation.onHistoryStateUpdated"); } + get onReferenceFragmentUpdated() { return bridgeLog.DoActionAndLog(() => { return myBrowser.webNavigation.onReferenceFragmentUpdated; }, "webNavigation.onReferenceFragmentUpdated"); } + get onTabReplaced() { return bridgeLog.DoActionAndLog(() => { return myBrowser.webNavigation.onTabReplaced; }, "webNavigation.onTabReplaced"); } + getAllFrames(details, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.webNavigation.getAllFrames(details, callback); + }, "webNavigation.getAllFrames"); + } + getFrame(details, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.webNavigation.getFrame(details, callback); + }, "webNavigation.getFrame"); + } +} +class EdgeWebRequestBridge { + get MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES() { return bridgeLog.DoActionAndLog(() => { return myBrowser.webRequest.MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES; }, "webNavigation.MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES"); } + get onAuthRequired() { return bridgeLog.DoActionAndLog(() => { return myBrowser.webRequest.onAuthRequired; }, "webNavigation.onAuthRequired"); } + get onBeforeRedirect() { return bridgeLog.DoActionAndLog(() => { return myBrowser.webRequest.onBeforeRedirect; }, "webNavigation.onBeforeRedirect"); } + get onBeforeRequest() { return bridgeLog.DoActionAndLog(() => { return myBrowser.webRequest.onBeforeRequest; }, "webNavigation.onBeforeRequest"); } + get onBeforeSendHeaders() { return bridgeLog.DoActionAndLog(() => { return myBrowser.webRequest.onBeforeSendHeaders; }, "webNavigation.onBeforeSendHeaders"); } + get onCompleted() { return bridgeLog.DoActionAndLog(() => { return myBrowser.webRequest.onCompleted; }, "webNavigation.onCompleted"); } + get onErrorOccurred() { return bridgeLog.DoActionAndLog(() => { return myBrowser.webRequest.onErrorOccurred; }, "webNavigation.onErrorOccurred"); } + get onHeadersReceived() { return bridgeLog.DoActionAndLog(() => { return myBrowser.webRequest.onHeadersReceived; }, "webNavigation.onHeadersReceived"); } + get onResponseStarted() { return bridgeLog.DoActionAndLog(() => { return myBrowser.webRequest.onResponseStarted; }, "webNavigation.onResponseStarted"); } + get onSendHeaders() { return bridgeLog.DoActionAndLog(() => { return myBrowser.webRequest.onSendHeaders; }, "webNavigation.onSendHeaders"); } + handlerBehaviorChanged(callback) { + bridgeLog.DoActionAndLog(() => { + if (typeof callback !== "undefined" && typeof callback !== "null") { + myBrowser.webRequest.handlerBehaviorChanged(callback); + } + else { + myBrowser.webRequest.handlerBehaviorChanged(); + } + }, "webRequest.handlerBehaviorChanged"); + } +} +class EdgeWindowsBridge { + get WINDOW_ID_CURRENT() { return bridgeLog.DoActionAndLog(() => { return myBrowser.windows.WINDOW_ID_CURRENT; }, "windows.WINDOW_ID_CURRENT"); } + get WINDOW_ID_NONE() { return bridgeLog.DoActionAndLog(() => { return myBrowser.windows.WINDOW_ID_NONE; }, "windows.WINDOW_ID_NONE"); } + get onCreated() { return bridgeLog.DoActionAndLog(() => { return myBrowser.windows.onCreated; }, "windows.onCreated"); } + get onFocusChanged() { return bridgeLog.DoActionAndLog(() => { return myBrowser.windows.onFocusChanged; }, "windows.onFocusChanged"); } + get onRemoved() { return bridgeLog.DoActionAndLog(() => { return myBrowser.windows.onRemoved; }, "windows.onRemoved"); } + create(createData, callback) { + bridgeLog.DoActionAndLog(() => { + if (typeof callback !== "undefined" && typeof callback !== "null") { + myBrowser.windows.create(createData, callback); + } + else { + myBrowser.windows.create(createData); + } + }, "windows.create"); + } + get(windowId, getInfo, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.windows.get(windowId, getInfo, callback); + }, "windows.get"); + } + getAll(getInfo, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.windows.getAll(getInfo, callback); + }, "windows.getAll"); + } + getCurrent(getInfo, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.windows.getCurrent(getInfo, callback); + }, "windows.getCurrent"); + } + getLastFocused(getInfo, callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.windows.getLastFocused(getInfo, callback); + }, "windows.getLastFocused"); + } + update(windowId, updateInfo, callback) { + bridgeLog.DoActionAndLog(() => { + if (typeof callback !== "undefined" && typeof callback !== "null") { + myBrowser.windows.update(windowId, updateInfo, callback); + } + else { + myBrowser.windows.update(windowId, updateInfo); + } + }, "windows.update"); + } +} +class EdgeChromeWindowsBridge extends EdgeWindowsBridge { + remove(windowId, callback) { + bridgeLog.LogUnavailbleApi("windows.remove"); + } +} +class EdgeBackgroundBridge { + constructor() { + this.app = new EdgeChromeAppBridge(); + this.browserAction = typeof browser.browserAction !== "undefined" ? new EdgeChromeBrowserActionBridge() : undefined; + this.contextMenus = typeof browser.contextMenus !== "undefined" ? new EdgeContextMenusBridge() : undefined; + this.cookies = typeof browser.cookies !== "undefined" ? new EdgeChromeCookiesBridge() : undefined; + this.extension = typeof browser.extension !== "undefined" ? new EdgeChromeExtensionBridge() : undefined; + this.history = typeof browser.history !== "undefined" ? new EdgeHistoryBridge() : undefined; + this.i18n = typeof browser.i18n !== "undefined" ? new EdgeI18nBridge() : undefined; + this.notifications = typeof browser.notifications !== "undefined" ? new EdgeNotificationBridge() : undefined; + this.pageAction = typeof browser.pageAction !== "undefined" ? new EdgePageActionBridge() : undefined; + this.permissions = typeof browser.permissions !== "undefined" ? new EdgePermissionsBridge() : undefined; + this.runtime = typeof browser.runtime !== "undefined" ? new EdgeChromeRuntimeBridge() : undefined; + this.storage = typeof browser.storage !== "undefined" ? new EdgeChromeStorageBridge() : undefined; + this.tabs = typeof browser.tabs !== "undefined" ? new EdgeChromeTabsBridge() : undefined; + this.webNavigation = typeof browser.webNavigation !== "undefined" ? new EdgeWebNavigationBridge() : undefined; + this.webRequest = typeof browser.webRequest !== "undefined" ? new EdgeWebRequestBridge() : undefined; + this.windows = typeof browser.windows !== "undefined" ? new EdgeChromeWindowsBridge() : undefined; + } +} +var myBrowser = browser; +var chrome = new EdgeBackgroundBridge(); diff --git a/src/drivers/webextension/js/ms_content_scripts_api_bridge.js b/src/drivers/webextension/js/ms_content_scripts_api_bridge.js new file mode 100644 index 000000000..183aafc02 --- /dev/null +++ b/src/drivers/webextension/js/ms_content_scripts_api_bridge.js @@ -0,0 +1,323 @@ +if (!Range.prototype["intersectsNode"]) { + Range.prototype["intersectsNode"] = function (node) { + let range = document.createRange(); + range.selectNode(node); + return 0 > this.compareBoundaryPoints(Range.END_TO_START, range) + && 0 < this.compareBoundaryPoints(Range.START_TO_END, range); + }; +} +var getExtensionProtocol = function () { + if (typeof browser == "undefined") { + if (typeof chrome !== "undefined") + return "chrome-extension://"; + } + else { + return "ms-browser-extension://"; + } +}; +class FakeEvent { + addListener(callback) { } + addRules(rules, callback) { } + getRules(ruleIdentifiers, callback) { } + hasListener(callback) { return false; } + hasListeners() { return false; } + removeRules(ruleIdentifiers, callback) { } + removeListener(callback) { } +} +class EdgeBridgeHelper { + constructor() { + this.fakeEvent = new FakeEvent(); + } + toAbsolutePath(relativePath) { + if (relativePath.indexOf("ms-browser-extension://") == 0) { + return relativePath.replace(myBrowser.runtime.getURL(""), ""); + } + else if (relativePath.indexOf("/") != 0) { + var absolutePath = ""; + var documentPath = document.location.pathname; + absolutePath = documentPath.substring(0, documentPath.lastIndexOf("/") + 1); + absolutePath += relativePath; + return absolutePath; + } + return relativePath; + } +} +var bridgeHelper = new EdgeBridgeHelper(); +class EdgeBridgeDebugLog { + constructor() { + this.CatchOnException = true; + this.VerboseLogging = true; + this.FailedCalls = {}; + this.SuccededCalls = {}; + this.DeprecatedCalls = {}; + this.BridgedCalls = {}; + this.UnavailableApis = {}; + this.EdgeIssues = {}; + } + log(message) { + try { + if (this.VerboseLogging) { + console.log(message); + } + } + catch (e) { + } + } + info(message) { + try { + if (this.VerboseLogging) { + console.info(message); + } + } + catch (e) { + } + } + warn(message) { + try { + if (this.VerboseLogging) { + console.warn(message); + } + } + catch (e) { + } + } + error(message) { + try { + if (this.VerboseLogging) { + console.error(message); + } + } + catch (e) { + } + } + DoActionAndLog(action, name, deprecatedTo, bridgedTo) { + var result; + try { + result = action(); + this.AddToCalledDictionary(this.SuccededCalls, name); + if (typeof deprecatedTo !== "undefined" && typeof deprecatedTo !== "null") { + this.warn("API Call Deprecated - Name: " + name + ", Please use " + deprecatedTo + " instead!"); + this.AddToCalledDictionary(this.DeprecatedCalls, name); + } + if (typeof bridgedTo !== "undefined" && typeof bridgedTo !== "null") { + this.info("API Call '" + name + "' has been bridged to another Edge API: " + bridgedTo); + this.AddToCalledDictionary(this.BridgedCalls, name); + } + return result; + } + catch (ex) { + this.AddToCalledDictionary(this.FailedCalls, name); + if (this.CatchOnException) + this.error("API Call Failed: " + name + " - " + ex); + else + throw ex; + } + } + LogEdgeIssue(name, message) { + this.warn(message); + this.AddToCalledDictionary(this.EdgeIssues, name); + } + LogUnavailbleApi(name, deprecatedTo) { + this.warn("API Call '" + name + "' is not supported in Edge"); + this.AddToCalledDictionary(this.UnavailableApis, name); + if (typeof deprecatedTo !== "undefined" && typeof deprecatedTo !== "null") { + this.warn("API Call Deprecated - Name: " + name + ", Please use " + deprecatedTo + " instead!"); + this.AddToCalledDictionary(this.DeprecatedCalls, name); + } + } + AddToCalledDictionary(dictionary, name) { + if (typeof dictionary[name] !== "undefined") { + dictionary[name]++; + } + else { + dictionary[name] = 1; + } + } +} +var bridgeLog = new EdgeBridgeDebugLog(); +class EdgeExtensionBridge { + getBackgroundPage() { + return bridgeLog.DoActionAndLog(() => { + return myBrowser.extension.getBackgroundPage(); + }, "extension.getBackgroundPage"); + } + getURL(path) { + return bridgeLog.DoActionAndLog(() => { + return myBrowser.extension.getURL(path); + }, "extension.getURL"); + } + getViews(fetchProperties) { + return bridgeLog.DoActionAndLog(() => { + return myBrowser.extension.getViews(fetchProperties); + }, "extension.getViews"); + } +} +class EdgeChromeExtensionBridge extends EdgeExtensionBridge { + get onConnect() { return bridgeLog.DoActionAndLog(() => { return EdgeRuntimeBridge.prototype.onConnect; }, "extension.onConnect", "runtime.onConnect", "runtime.onConnect"); } + get onMessage() { return bridgeLog.DoActionAndLog(() => { return myBrowser.runtime.onMessage; }, "extension.onMessage", "runtime.onMessage", "runtime.onMessage"); } + get onRequest() { return bridgeLog.DoActionAndLog(() => { return myBrowser.runtime.onMessage; }, "extension.onRequest", "runtime.onMessage", "runtime.onMessage"); } + get onRequestExternal() { return bridgeLog.DoActionAndLog(() => { return myBrowser.runtime.onMessageExternal; }, "extension.onRequestExternal", "runtime.onMessageExternal", "runtime.onMessageExternal"); } + get inIncognitoContext() { return bridgeLog.DoActionAndLog(() => { return myBrowser.extension["inPrivateContext"]; }, "extension.inIncognitoContext", undefined, "extension.inPrivateContext"); } + get lastError() { return bridgeLog.DoActionAndLog(() => { return myBrowser.runtime.lastError; }, "extension.lastError", undefined, "runtime.lastError"); } + connect(extensionId, connectInfo) { + return bridgeLog.DoActionAndLog(() => { + return EdgeRuntimeBridge.prototype.connect(extensionId, connectInfo); + }, "extension.connect", "runtime.connect", "runtime.connect"); + } + sendMessage(message, responseCallback) { + return bridgeLog.DoActionAndLog(() => { + return EdgeRuntimeBridge.prototype.sendMessage(message, responseCallback, undefined, undefined); + }, "extension.sendMessage", "runtime.sendMessage", "runtime.sendMessage"); + } + sendRequest(extensionId, message, options, responseCallback) { + return bridgeLog.DoActionAndLog(() => { + return EdgeRuntimeBridge.prototype.sendMessage(extensionId, message, options, responseCallback); + }, "extension.sendRequest", "runtime.sendMessage", "runtime.sendMessage"); + } + isAllowedFileSchemeAccess(callback) { + bridgeLog.LogUnavailbleApi("extension.isAllowedFileSchemeAccess"); + } + isAllowedIncognitoAccess(callback) { + bridgeLog.LogUnavailbleApi("extension.isAllowedIncognitoAccess"); + } + setUpdateUrlData(data) { + bridgeLog.LogUnavailbleApi("extension.setUpdateUrlData"); + } +} +class EdgeI18nBridge { + getAcceptLanguages(callback) { + return bridgeLog.DoActionAndLog(() => { + return myBrowser.i18n.getAcceptLanguages(callback); + }, "i18n.getAcceptLanguages"); + } + getMessage(messageName, substitutions) { + return bridgeLog.DoActionAndLog(() => { + if (messageName.indexOf("@@extension_id") > -1) { + return myBrowser.runtime.id; + } + if (typeof substitutions !== "undefined" && typeof substitutions !== "null") { + return myBrowser.i18n.getMessage(messageName, substitutions); + } + else { + return myBrowser.i18n.getMessage(messageName); + } + }, "i18n.getMessage"); + } + getUILanguage() { + return bridgeLog.DoActionAndLog(() => { + return myBrowser.i18n.getUILanguage(); + }, "i18n.getUILanguage"); + } +} +class EdgeRuntimeBridge { + get id() { return bridgeLog.DoActionAndLog(() => { return myBrowser.runtime.id; }, "runtime.id"); } + get lastError() { return bridgeLog.DoActionAndLog(() => { return myBrowser.runtime.lastError; }, "runtime.lastError"); } + get onConnect() { return bridgeLog.DoActionAndLog(() => { return myBrowser.runtime.onConnect; }, "runtime.onConnect"); } + get onInstalled() { return bridgeLog.DoActionAndLog(() => { return myBrowser.runtime.onInstalled; }, "runtime.onInstalled"); } + get onMessage() { return bridgeLog.DoActionAndLog(() => { return myBrowser.runtime.onMessage; }, "runtime.onMessage"); } + get onMessageExternal() { return bridgeLog.DoActionAndLog(() => { return myBrowser.runtime.onMessageExternal; }, "runtime.onMessageExternal"); } + connect(extensionId, connectInfo) { + return bridgeLog.DoActionAndLog(() => { + if (typeof connectInfo !== "undefined" && typeof connectInfo !== "null") { + return myBrowser.runtime.connect(extensionId, connectInfo); + } + else { + return myBrowser.runtime.connect(extensionId); + } + }, "runtime.connect"); + } + getBackgroundPage(callback) { + bridgeLog.DoActionAndLog(() => { + myBrowser.runtime.getBackgroundPage(callback); + }, "runtime.getBackgroundPage"); + } + getManifest() { + return bridgeLog.DoActionAndLog(() => { + return myBrowser.runtime.getManifest(); + }, "runtime.getManifest"); + } + getURL(path) { + return bridgeLog.DoActionAndLog(() => { + return myBrowser.runtime.getURL(path); + }, "runtime.getURL"); + } + sendMessage(extensionId, message, options, responseCallback) { + bridgeLog.DoActionAndLog(() => { + if (typeof responseCallback !== "undefined" && typeof responseCallback !== "null") { + myBrowser.runtime.sendMessage(extensionId, message, options, responseCallback); + } + else if (typeof options !== "undefined" && typeof options !== "null") { + myBrowser.runtime.sendMessage(extensionId, message, options); + } + else if (typeof message !== "undefined" && typeof message !== "null") { + myBrowser.runtime.sendMessage(extensionId, message); + } + else { + myBrowser.runtime.sendMessage(undefined, extensionId); + } + }, "runtime.sendMessage"); + } +} +class EdgeChromeRuntimeBridge extends EdgeRuntimeBridge { + get onConnectExternal() { bridgeLog.LogUnavailbleApi("runtime.onConnectExternal"); return bridgeHelper.fakeEvent; } + get onRestartRequired() { bridgeLog.LogUnavailbleApi("runtime.onRestartRequired"); return bridgeHelper.fakeEvent; } + get onStartup() { bridgeLog.LogUnavailbleApi("runtime.onStartup"); return bridgeHelper.fakeEvent; } + get onSuspend() { bridgeLog.LogUnavailbleApi("runtime.onSuspend"); return bridgeHelper.fakeEvent; } + get onSuspendCanceled() { bridgeLog.LogUnavailbleApi("runtime.onSuspendCanceled"); return bridgeHelper.fakeEvent; } + get onUpdateAvailable() { bridgeLog.LogUnavailbleApi("runtime.onUpdateAvailable"); return bridgeHelper.fakeEvent; } + openOptionsPage(callback) { + bridgeLog.DoActionAndLog(() => { + var optionsPage = myBrowser.runtime.getManifest()["options_page"]; + var optionsPageUrl = myBrowser.runtime.getURL(optionsPage); + if (typeof callback !== "undefined" && typeof callback !== "null") { + myBrowser.tabs.create({ url: optionsPageUrl }, callback); + } + else { + myBrowser.tabs.create({ url: optionsPageUrl }); + } + }, "runtime.openOptionsPage", undefined, "tabs.create({ url: optionsPageUrl })"); + } + connectNative(application) { + bridgeLog.LogUnavailbleApi("runtime.connectNative"); + return null; + } + getPackageDirectoryEntry(callback) { + bridgeLog.LogUnavailbleApi("runtime.getPackageDirectoryEntry"); + } + getPlatformInfo(callback) { + bridgeLog.LogUnavailbleApi("runtime.getPlatformInfo"); + } + reload() { + bridgeLog.LogUnavailbleApi("runtime.reload"); + } + requestUpdateCheck(callback) { + bridgeLog.LogUnavailbleApi("runtime.requestUpdateCheck"); + } + restart() { + bridgeLog.LogUnavailbleApi("runtime.restart"); + } + setUninstallURL(url, callback) { + bridgeLog.LogUnavailbleApi("runtime.setUninstallURL"); + } + sendNativeMessage(application, message, responseCallback) { + bridgeLog.LogUnavailbleApi("runtime.sendNativeMessage"); + } +} +class EdgeStorageBridge { + get local() { return bridgeLog.DoActionAndLog(() => { return myBrowser.storage.local; }, "storage.local"); } + get onChanged() { return bridgeLog.DoActionAndLog(() => { return myBrowser.storage.onChanged; }, "storage.onChanged"); } +} +class EdgeChromeStorageBridge extends EdgeStorageBridge { + get managed() { return bridgeLog.DoActionAndLog(() => { return myBrowser.storage.local; }, "storage.managed", undefined, "storage.local"); } + get sync() { return bridgeLog.DoActionAndLog(() => { return myBrowser.storage.local; }, "storage.sync", undefined, "storage.local"); } +} +class EdgeContentBridge { + constructor() { + this.extension = typeof browser.extension !== "undefined" ? new EdgeChromeExtensionBridge() : undefined; + this.i18n = typeof browser.i18n !== "undefined" ? new EdgeI18nBridge() : undefined; + this.runtime = typeof browser.runtime !== "undefined" ? new EdgeChromeRuntimeBridge() : undefined; + this.storage = typeof browser.storage !== "undefined" ? new EdgeChromeStorageBridge() : undefined; + } +} +var myBrowser = browser; +var chrome = new EdgeContentBridge(); diff --git a/src/drivers/webextension/js/network.js b/src/drivers/webextension/js/network.js deleted file mode 100644 index b2f2ea018..000000000 --- a/src/drivers/webextension/js/network.js +++ /dev/null @@ -1,784 +0,0 @@ -'use strict'; -(function() { - - function isChrome() { - return (typeof chrome !== 'undefined' && - window.navigator.userAgent.match(/Chrom(?:e|ium)\/([0-9\.]+)/)); - } - - var browserProxy; - if ( isChrome() ) { - browserProxy = chrome; - } else { - browserProxy = browser; - } - - var MIN_FF_MAJOR_VERSION = 51; - - var requiredBrowserApis = [ - browserProxy.webNavigation, - browserProxy.tabs, - browserProxy.webRequest, - browserProxy.runtime - ]; - var areListenersRegistered = false; - var secBefore = 2000; - var secAfter = 5000; - var secBetweenDupAssets = 10e3; - var minVidSize = 500e3; - var maxVidSize = 25e6; - var maxContentRange = 25e6; - var videoExtensions = [ - 'af', '3gp', 'asf', 'avchd', 'avi', 'cam', 'dsh', 'flv', 'm1v', 'm2v', - 'fla', 'flr', 'sol', 'm4v', 'mkv', 'wrap', 'mng', 'mov', 'mpeg', 'mpg', - 'mpe', 'mp4', 'mxf', 'nsv', 'ogg', 'rm', 'svi', 'smi', 'wmv', 'webm' - ]; - var extensionsReg = new RegExp('\\.' + videoExtensions.join('$|\\.') + '$'); - var videoContentTypesPrefixes = ['binary/octet-stream', 'video/', 'flv-application/', 'media']; - - var bannedContentTypes = ['video/mp2t','video/f4m','video/f4f']; - var bannedFiletypes = ['ts']; - var bannedFiletypesReg = new RegExp('\\.' + bannedFiletypes.join('$|\\.') + '$'); - var whitelistReqTypes = ['object', 'xmlhttprequest', 'other']; - - var topVideoAssetDomains = [ - '2mdn.net', - 'adap.tv', - 'adnxs.com', - 'adsrvr.org', - 'btrll.com', - 'celtra.com', - 'flashtalking.com', - 'flite.com', - 'innovid.com', - 'jivox.com', - 'mixpo.com', - 'nytimes.com', - 'playwire.com', - 'selectmedia.asia', - 'serving-sys.com', - 'solvemedia.com', - 'spotible.com', - 'teads.tv', - 'tribalfusion.com', - 'tubemogul.com', - 'videologygroup.com', - 'washingtonpost.com' - ]; - - if ( !String.prototype.endsWith ) { - String.prototype.endsWith = function(searchString, position) { - var subjectString = this.toString(); - if ( typeof position !== 'number' || !isFinite(position) || - Math.floor(position) !== position || position > subjectString.length) { - position = subjectString.length; - } - position -= searchString.length; - var lastIndex = subjectString.indexOf(searchString, position); - return lastIndex !== -1 && lastIndex === position; - }; - } - - function getFrame(getFrameDetails, callback) { - if ( typeof chrome !== 'undefined' ) { - chrome.webNavigation.getFrame(getFrameDetails, callback); - } else if ( typeof browser !== 'undefined' ) { - var gettingFrame = browser.webNavigation.getFrame(getFrameDetails); - gettingFrame.then(callback); - } - } - - function ifBrowserValid(callback, elseCallback) { - if ( isChrome() ) { - - callback(); - } else if ( typeof browser !== 'undefined' ) { - try { - var gettingInfo = browser.runtime.getBrowserInfo(); - gettingInfo.then(function(browserInfo) { - var browserVersion = parseInt(browserInfo.version.split('.')[0]); - - if ( browserInfo.name === 'Firefox' && - browserVersion >= MIN_FF_MAJOR_VERSION) { - callback(); - } else { - elseCallback(); - } - }); - } catch (err) { - - elseCallback(); - } - } else { - elseCallback(); - } - } - - function isTrackingEnabled() { - - return parseInt(localStorage.tracking, 10); - - } - - function isPixelRequest(request) { - return (request.type === 'image' || request.responseStatus === 204) && - request.size <= 1000; - } - - function isVpaidOrVastRequest(request) { - var lowerCaseUrl = request.url.toLowerCase(); - return lowerCaseUrl.indexOf('vpaid') !== -1 || lowerCaseUrl.indexOf('vast') !== -1; - } - - function hasValidRequestType(request) { - return whitelistReqTypes.indexOf(request.type) >= 0; - } - - function stripQueryParams(url) { - return url.split('?', 1)[0]; - } - - function parseHostnameFromUrl(url) { - var parser = document.createElement('a'); - parser.href = url; - return parser.hostname; - } - - function hasDomain(url, domain) { - return parseHostnameFromUrl(url).endsWith(domain); - } - - function findHeader(headers, key) { - var header; - for ( var i = 0; i < headers.length; i += 1 ) { - header = headers[i]; - if ( header.name.toLowerCase() === key ) { - return header; - } - } - return null; - } - - function validVideoType(vtype) { - var goodType = videoContentTypesPrefixes.some(function(prefix) { - return vtype.indexOf(prefix) === 0; - }); - return goodType; - } - - function assetMsgKey(assetReq) { - var url = stripQueryParams(assetReq.url); - var key = assetReq.frameId + '-' + url; - return key; - } - - var PageNetworkTrafficCollector = function(tabId) { - this.tabId = tabId; - this.displayAdFound = false; - this.requests = {}; - this.msgsBeingSent = {}; - this.assetsSeen = {}; - this.allRedirects = {}; - }; - - var globalPageContainer = { - collectors: {}, - dyingCollectors: {}, - - cleanupCollector: function(tabId) { - if ( tabId in this.collectors ) { - delete globalPageContainer.collectors[tabId]; - } - }, - - onNewNavigation: function(details) { - var tabId = details.tabId; - this.cleanupCollector(tabId); - - if ( isTrackingEnabled() ) { - if ( !areListenersRegistered ) { - - registerListeners(); - } - this.collectors[tabId] = new PageNetworkTrafficCollector(tabId); - } else { - if ( areListenersRegistered ) { - - unregisterListeners(); - } - } - }, - - onNavigationCommitted: function(details) { - - }, - - onNavigationCompleted: function(details) { - - }, - - onTabClose: function(tabId, closeInfo) { - - this.cleanupCollector(tabId); - delete this.collectors[tabId]; - }, - - onDisplayAdFound: function(tabId) { - this.collectors[tabId].displayAdFound = true; - }, - - getRandId: function() { - return String(Math.floor(Math.random() * 1e9)); - }, - - getCollector: function(tabId) { - if ( this.collectors.hasOwnProperty(tabId) ) { - return this.collectors[tabId]; - } - return null; - }, - - forwardCall: function(details, collectorMemberFunction) { - var collector = this.getCollector(details.tabId); - if ( collector !== null ) { - collectorMemberFunction.apply(collector, [details]); - } - } - }; - - PageNetworkTrafficCollector.prototype.sendLogMessageToTabConsole = function() { - var logMessage = Array.from(arguments).join(' '); - var message = {message: logMessage, event: 'console-log-message'}; - browserProxy.tabs.sendMessage(this.tabId, message); - }; - - PageNetworkTrafficCollector.prototype.sendToTab = function(assetReq, reqs, curPageUrl, isValidAd) { - var msg = {}; - msg.assets = []; - msg.event_data = {}; - if ( isValidAd ) { - msg.event = 'new-video-ad'; - msg.requests = reqs; - msg.requests.sort(function(reqA, reqB) {return reqA.requestTimestamp - reqB.requestTimestamp;}); - if ( assetReq ) { - msg.assets = [assetReq]; - } - } else { - msg.requests = reqs.map(function(request) { - return parseHostnameFromUrl(request.url); - }); - msg.assets = [{ - - url: parseHostnameFromUrl(assetReq.url), - - contentType: assetReq.contentType, - size: assetReq.size - }]; - msg.event = 'new-invalid-video-ad'; - } - msg.origUrl = curPageUrl; - msg.displayAdFound = this.displayAdFound; - - browserProxy.tabs.sendMessage(this.tabId, msg); - }; - - PageNetworkTrafficCollector.prototype.getRedirKey = function(url, frameId) { - return url + ':' + frameId; - }; - - PageNetworkTrafficCollector.prototype.seenBefore = function(request) { - var oldTime = this.assetsSeen[assetMsgKey(request)]; - if ( oldTime && (request.requestTimestamp-oldTime < secBetweenDupAssets)){ - - return true; - } - return false; - }; - - PageNetworkTrafficCollector.prototype.recordSeenAsset = function(request) { - this.assetsSeen[assetMsgKey(request)] = request.requestTimestamp; - }; - - PageNetworkTrafficCollector.prototype.onBeforeRequest = function(details) { - var req = { - url: details.url, - type: details.type, - httpMethod: details.method, - frameId: details.frameId, - parentFrameId: details.parentFrameId, - requestTimestamp: details.timeStamp, - }; - this.requests[details.requestId] = req; - }; - - PageNetworkTrafficCollector.prototype.onSendHeaders = function(details) { - var request, header; - request = this.requests[details.requestId]; - header = request && findHeader(details.requestHeaders, 'x-requested-with'); - if ( header && header.value.toLowerCase().indexOf('flash') > -1 ) { - request.from_flash = true; - } - }; - - PageNetworkTrafficCollector.prototype.onHeadersReceived = function(details) { - var getFrameDetails = { - tabId: details.tabId, - processId: null, - frameId: details.frameId - }; - var pageNetworkTrafficController = this; - getFrame(getFrameDetails, function(frameDetails) { - if ( frameDetails && frameDetails.url ) { - pageNetworkTrafficController._onHeadersReceived(details, frameDetails); - } - }); - }; - - PageNetworkTrafficCollector.prototype._onHeadersReceived = function(details, frameDetails) { - var contentSize, contentRange; - - var request = this.requests[details.requestId]; - if ( request ) { - var redirParent = this.allRedirects[this.getRedirKey(details.url, details.frameId)]; - var header = request && findHeader(details.responseHeaders, 'content-type'); - var contentType = header && header.value.toLowerCase(); - - if ( contentType){ - request.contentType = contentType; - } - header = request && findHeader(details.responseHeaders, 'content-length'); - contentSize = header && header.value; - if ( contentSize ) { - request.size = request.size || 0; - request.size += parseInt(contentSize); - } - header = request && findHeader(details.responseHeaders, 'content-range'); - contentRange = header && header.value; - if ( contentRange ) { - request.contentRange = parseInt(contentRange.split('/')[1]); - } - - var frameUrl = null; - if ( frameDetails && frameDetails.url ) { - frameUrl = frameDetails.url; - } - if ( !this.bannedRequest(request) && - (this.isVideoReq(frameUrl, request) || (redirParent && redirParent.isVideo))) { - request.isVideo = true; - } - } - }; - - PageNetworkTrafficCollector.prototype.onBeforeRedirect = function(details) { - var request = this.requests[details.requestId]; - if ( request ) { - if ( request.redirects ) { - request.redirects.push(details.redirectUrl); - } else { - request.redirects = [details.redirectUrl]; - } - this.allRedirects[this.getRedirKey(details.redirectUrl, details.frameId)] = request; - } - }; - - PageNetworkTrafficCollector.prototype.isYoutubeMastheadRequest = function(url) { - var re = /video_masthead/; - return this.hasYoutubeDomain(url) && re.test(url); - }; - PageNetworkTrafficCollector.prototype.isYoutubeVideoRequest = function(srcUrl, destUrl) { - if ( !this.hasYoutubeDomain(srcUrl) ) { - return false; - } - - var re = /https?:\/\/r.*?\.googlevideo\.com\/videoplayback\?/; - return re.test(destUrl); - }; - PageNetworkTrafficCollector.prototype.processResponse = function(requestDetails, frameDetails) { - var request; - if ( requestDetails ) { - request = this.requests[requestDetails.requestId]; - if ( request ) { - request.responseStatus = requestDetails.statusCode; - request.responseTimestamp = requestDetails.timeStamp; - - var frameUrl = null; - if ( frameDetails && frameDetails.url ) { - frameUrl = frameDetails.url; - } - - var requestUrl = null; - if ( request.url ) { - requestUrl = request.url; - } - - if ( this.isYoutubeAdReq(frameUrl, requestUrl) ) { - var videoId = this.parseYoutubeVideoIdFromUrl(requestUrl); - if ( videoId ) { - request.isYoutubeAd = true; - request.isVideo = true; - request.url = 'https://www.youtube.com/watch?v=' + this.parseYoutubeVideoIdFromUrl(requestUrl); - } - } else if ( !this.bannedRequest(request) && - (this.isVideo || this.isVideoReq(frameUrl, request))) { - request.isVideo = true; - } - - if ( request.isVideo ) { - - var msgKey = assetMsgKey(request); - this.msgsBeingSent[msgKey] = request; - if ( !this.seenBefore(request) ) { - this.sendMsgWhenQuiet(msgKey); - } - this.recordSeenAsset(request); - } - } - } - }; - - PageNetworkTrafficCollector.prototype.onResponseStarted = function(responseDetails) { - if ( responseDetails.frameId < 0 ) { - responseDetails.frameId = 99999; - - } - var getFrameDetails = { - tabId: responseDetails.tabId, - processId: null, - frameId: responseDetails.frameId - }; - var pageNetworkTrafficController = this; - getFrame(getFrameDetails, function(frameDetails) { - if ( frameDetails && frameDetails.url ) { - pageNetworkTrafficController.processResponse(responseDetails, frameDetails); - } - }); - }; - - PageNetworkTrafficCollector.prototype.hasBannedFiletype = function(request) { - var url = stripQueryParams(request.url); - if ( bannedFiletypesReg.exec(url) ) { - return true; - } else { - return false; - } - }; - - PageNetworkTrafficCollector.prototype.checkContentHeaders = function(request) { - if ( request.contentType && validVideoType(request.contentType) ) { - return true; - } - return false; - }; - - PageNetworkTrafficCollector.prototype.checkUrlExtension = function(request) { - var url = stripQueryParams(request.url); - if ( extensionsReg.exec(url) ) { - return true; - } else { - return false; - } - }; - - PageNetworkTrafficCollector.prototype.isVideoReq = function(srcUrl, request) { - if ( this.isYoutubeVideoRequest(srcUrl, request.url) ) { - return false; - } - return this.checkUrlExtension(request) || this.checkContentHeaders(request); - }; - PageNetworkTrafficCollector.prototype.hasYoutubeDomain = function(url) { - var hostname = parseHostnameFromUrl(url) ; - if ( hostname === 'www.youtube.com' ) { - return true; - } - return false; - }; - PageNetworkTrafficCollector.prototype.parseYoutubeVideoIdFromUrl = function(url) { - var re = /^https?:\/\/www\.youtube\.com\/get_video_info.*(?:\?|&)video_id=(.*?)(?:$|&)/; - var match = re.exec(url); - if ( match && match.length > 1 ) { - return match[1]; - } - - re = /^https?:\/\/www\.youtube\.com\/embed\/(.*?)(?:$|\?)/; - match = re.exec(url); - if ( match && match.length > 1 ) { - return match[1]; - } - - re = /^https?:\/\/www\.youtube\.com\/watch\?v=(.*$)/; - match = re.exec(url); - if ( match && match.length > 1 ) { - return match[1]; - } - return null; - }; - - PageNetworkTrafficCollector.prototype.isYoutubeGetVideoInfoReq = function(url) { - var re = /^https?:\/\/www\.youtube\.com\/get_video_info\?/; - return re.test(url); - }; - PageNetworkTrafficCollector.prototype.isYoutubeAdReq = function(srcUrl, destUrl) { - - if ( !this.hasYoutubeDomain(srcUrl) || - !this.isYoutubeGetVideoInfoReq(destUrl)) { - return false; - } - if ( this.parseYoutubeVideoIdFromUrl(srcUrl) === - this.parseYoutubeVideoIdFromUrl(destUrl) && - !this.isYoutubeMastheadRequest(destUrl)) { - return false; - } - return true; - }; - - PageNetworkTrafficCollector.prototype.bannedRequest = function(request) { - return this.bannedVideoType(request) || this.hasBannedFiletype(request) || this.bannedVideoSize(request); - }; - - PageNetworkTrafficCollector.prototype.bannedVideoType = function(request) { - var badType = false; - if ( request.contentType ) { - badType = bannedContentTypes.some(function(prefix) { - return request.contentType.indexOf(prefix) >= 0; - }); - } - return badType; - }; - - PageNetworkTrafficCollector.prototype.bannedVideoSize = function(request) { - if ( request.size !== null ) { - if ( request.size < minVidSize || request.size > maxVidSize || request.contentRange > maxContentRange ) { - return true; - } - } - return false; - }; - - PageNetworkTrafficCollector.prototype.grabTagReqs = function(tabRequests, assetRequest) { - var minTimestamp, maxTimestamp; - minTimestamp = assetRequest.requestTimestamp - secBefore; - maxTimestamp = assetRequest.requestTimestamp + secAfter; - - var filteredRequests = tabRequests.filter(function(request) { - return (request.requestTimestamp > minTimestamp && - request.requestTimestamp < maxTimestamp && - request.frameId === assetRequest.frameId && - request.url !== assetRequest.url && - (hasValidRequestType(request) || - isPixelRequest(request))); - }); - - return filteredRequests; - }; - - PageNetworkTrafficCollector.prototype.isValidVideoAd = function(assetRequest, tagRequests) { - var hasVpaidOrVastRequest = tagRequests.some(function(tagRequest) { - return isVpaidOrVastRequest(tagRequest); - }); - - if ( assetRequest.isYoutubeAd ) { - return true; - } - if ( hasVpaidOrVastRequest ) { - return true; - } - var hasTopVideoAssetDomain = topVideoAssetDomains.some(function(assetDomain) { - return hasDomain(assetRequest.url, assetDomain); - }); - - return hasTopVideoAssetDomain; - }; - - PageNetworkTrafficCollector.prototype.sendMsgWhenQuiet = function(msgKey) { - var _this = this, - origPageUrl, msgAssetReq; - msgAssetReq = this.msgsBeingSent[msgKey]; - browserProxy.tabs.get(this.tabId, function(tab) {origPageUrl = tab.url;}); - - setTimeout(function() { - var rawRequests = []; - if ( globalPageContainer.collectors[_this.tabId] === _this ) { - for ( var reqId in _this.requests ) { - rawRequests.push(_this.requests[reqId]); - } - var tagReqs = _this.grabTagReqs(rawRequests, msgAssetReq); - - if ( _this.isValidVideoAd(msgAssetReq, tagReqs) ) { - _this.sendToTab(msgAssetReq, tagReqs, origPageUrl, true); - } else { - - _this.sendToTab(msgAssetReq, tagReqs, origPageUrl, false); - } - - } else { - - } - delete _this.msgsBeingSent[msgKey]; - }, secAfter+secBefore); - }; - - PageNetworkTrafficCollector.prototype.existingMessage = function(candidateRequest) { - var frameMsg = this.msgsBeingSent[candidateRequest.frameId]; - if ( frameMsg ) { - return frameMsg; - } else { - return null; - } - }; - - function onBeforeRequestListener(details) { - globalPageContainer.forwardCall(details, PageNetworkTrafficCollector.prototype.onBeforeRequest); - } - - function onSendHeadersListener(details) { - globalPageContainer.forwardCall(details, PageNetworkTrafficCollector.prototype.onSendHeaders); - } - - function onHeadersReceivedListener(details) { - globalPageContainer.forwardCall(details, PageNetworkTrafficCollector.prototype.onHeadersReceived); - } - - function onBeforeRedirectListener(details) { - globalPageContainer.forwardCall(details, PageNetworkTrafficCollector.prototype.onBeforeRedirect); - } - - function onResponseStartedListener(details) { - globalPageContainer.forwardCall(details, PageNetworkTrafficCollector.prototype.onResponseStarted); - } - - function onCommittedListener(details) { - if ( details.frameId === 0 ) { - globalPageContainer.onNavigationCommitted(details); - } - } - - function onCompletedListener(details) { - if ( details.frameId === 0 ) { - globalPageContainer.onNavigationCompleted(details); - } - } - - function onRemovedListener(tabId, closeInfo) { - globalPageContainer.onTabClose(tabId, closeInfo); - } - - function onMessageListener(message, sender, sendResponse) { - if ( message.event === 'new-ad' && message.data.event === 'ad' ) { - var tabId = sender.tab.id; - if ( tabId ) { - globalPageContainer.onDisplayAdFound(tabId); - } - } - } - - function registerListeners() { - - browserProxy.webRequest.onBeforeRequest.addListener( - onBeforeRequestListener, - {urls: ['http://*/*', 'https://*/*']}, - [] - ); - - browserProxy.webRequest.onSendHeaders.addListener( - onSendHeadersListener, - {urls: ['http://*/*', 'https://*/*']}, - ['requestHeaders'] - ); - - browserProxy.webRequest.onHeadersReceived.addListener( - onHeadersReceivedListener, - {urls: ['http://*/*', 'https://*/*']}, - ['responseHeaders'] - ); - - browserProxy.webRequest.onBeforeRedirect.addListener( - onBeforeRedirectListener, - {urls: ['http://*/*', 'https://*/*']}, - [] - ); - - browserProxy.webRequest.onResponseStarted.addListener( - onResponseStartedListener, - {urls: ['http://*/*', 'https://*/*']}, - ['responseHeaders'] - ); - - browserProxy.webNavigation.onCommitted.addListener(onCommittedListener); - browserProxy.webNavigation.onCompleted.addListener(onCompletedListener); - browserProxy.tabs.onRemoved.addListener(onRemovedListener); - browserProxy.runtime.onMessage.addListener(onMessageListener); - - areListenersRegistered = true; - } - - function unregisterListeners() { - - browserProxy.webRequest.onBeforeRequest.removeListener( - onBeforeRequestListener - ); - - browserProxy.webRequest.onSendHeaders.removeListener( - onSendHeadersListener - ); - - browserProxy.webRequest.onHeadersReceived.removeListener( - onHeadersReceivedListener - ); - - browserProxy.webRequest.onBeforeRedirect.removeListener( - onBeforeRedirectListener - ); - - browserProxy.webRequest.onResponseStarted.removeListener( - onResponseStartedListener - ); - - browserProxy.webNavigation.onCommitted.removeListener(onCommittedListener); - browserProxy.webNavigation.onCompleted.removeListener(onCompletedListener); - browserProxy.tabs.onRemoved.removeListener(onRemovedListener); - browserProxy.runtime.onMessage.removeListener(onMessageListener); - - areListenersRegistered = false; - } - - function areRequiredBrowserApisAvailable() { - return requiredBrowserApis.every(function(api) { - return typeof api !== 'undefined'; - }); - } - - if ( areRequiredBrowserApisAvailable() ) { - ifBrowserValid( - function() { - browserProxy.webNavigation.onBeforeNavigate.addListener( - function(details) { - if ( details.frameId === 0 ) { - globalPageContainer.onNewNavigation(details); - } - }, - { - url: [{urlMatches: 'http://*/*'}, {urlMatches: 'https://*/*'}] - } - ); - }, function() { - - } - ); - } - - browserProxy.runtime.onMessage.addListener(function(request, sender, sendResponse) { - if ( request === 'is_browser_valid' ) { - ifBrowserValid( - sendResponse({'browser_valid': true}), - sendResponse({'browser_valid': false}) - ); - } - }); - - browserProxy.runtime.onMessage.addListener(function(request, sender, sendResponse) { - if ( request === 'is_tracking_enabled' ) { - sendResponse({'tracking_enabled': isTrackingEnabled()}); - } - }); - -})(); diff --git a/src/drivers/webextension/js/options.js b/src/drivers/webextension/js/options.js index 71974de97..064a20122 100644 --- a/src/drivers/webextension/js/options.js +++ b/src/drivers/webextension/js/options.js @@ -1,52 +1,70 @@ +/** global: browser */ +/** global: wappalyzer */ + document.addEventListener('DOMContentLoaded', function() { var d = document; var options = { - opts: defaults, - init: function() { options.load(); - d.getElementById('github' ).addEventListener('click', function() { window.open(wappalyzer.config.githubURL); }); - d.getElementById('twitter' ).addEventListener('click', function() { window.open(wappalyzer.config.twitterURL); }); - d.getElementById('wappalyzer').addEventListener('click', function() { window.open(wappalyzer.config.websiteURL + '?pk_campaign=chrome&pk_kwd=options'); }); + d.querySelector('#github').addEventListener('click', function() { + open(wappalyzer.config.githubURL); + }); + + d.querySelector('#twitter').addEventListener('click', function() { + open(wappalyzer.config.twitterURL); + }); - d.getElementById('options-save').addEventListener('click', options.save); + d.querySelector('#wappalyzer').addEventListener('click', function() { + open(wappalyzer.config.websiteURL); + }); }, - load: function() { - var option, value; + get: function(name, defaultValue, callback) { + browser.storage.local.get(name).then(function(item) { + callback(item.hasOwnProperty(name) ? item[name] : defaultValue); + }); + }, - for ( option in options.opts ) { - if ( value = localStorage[option] ) { - options.opts[option] = value; - } - } + set: function(name, value) { + var option = {}; - if ( parseInt(options.opts.upgradeMessage) ) { - d.getElementById('option-upgrade-message').setAttribute('checked', 'checked'); - } + option[name] = value; - if ( parseInt(options.opts.tracking) ) { - d.getElementById('option-tracking').setAttribute('checked', 'checked'); - } + browser.storage.local.set(option); }, - save: function() { - var option; + load: function() { + options.get('upgradeMessage', true, function(value) { + var el = d.querySelector('#option-upgrade-message'); + + el.checked = value; + + el.addEventListener('change', function() { + options.set('upgradeMessage', el.checked); + }); + }); + + options.get('dynamicIcon', true, function(value) { + var el = d.querySelector('#option-dynamic-icon'); + + el.checked = value; - options.opts.upgradeMessage = d.getElementById('option-upgrade-message').checked ? 1 : 0; - options.opts.tracking = d.getElementById('option-tracking' ).checked ? 1 : 0; + el.addEventListener('change', function() { + options.set('dynamicIcon', el.checked); + }); + }); - for ( option in options.opts ) { - localStorage[option] = options.opts[option]; - } + options.get('tracking', true, function(value) { + var el = d.querySelector('#option-tracking'); - d.getElementById('options-saved').style.display = 'inline'; + el.checked = value; - setTimeout(function(){ - d.getElementById('options-saved').style.display = 'none'; - }, 2000); + el.addEventListener('change', function() { + options.set('tracking', el.checked); + }); + }); } }; diff --git a/src/drivers/webextension/js/popup.js b/src/drivers/webextension/js/popup.js index dbb4444e0..70808bb53 100644 --- a/src/drivers/webextension/js/popup.js +++ b/src/drivers/webextension/js/popup.js @@ -1,3 +1,6 @@ +/** global: chrome */ +/** global: browser */ + document.addEventListener('DOMContentLoaded', function() { var slugify, popup, @@ -10,13 +13,21 @@ document.addEventListener('DOMContentLoaded', function() { popup = { init: function() { - browser.tabs.query({ active: true, currentWindow: true }).then(function(tabs) { + var callback = function(tabs) { if ( tabs[0].url.match(/https?:\/\//) ) { detectedApps.innerHTML = '
' + browser.i18n.getMessage('noAppsDetected') + '
'; } else { detectedApps.innerHTML = '
' + browser.i18n.getMessage('nothingToDo') + '
'; } - }); + }; + + try { + // Chrome, Firefox + browser.tabs.query({ active: true, currentWindow: true }).then(callback); + } catch ( e ) { + // Edge + browser.tabs.query({ active: true, currentWindow: true }, callback); + } popup.displayApps(); }, @@ -24,8 +35,10 @@ document.addEventListener('DOMContentLoaded', function() { displayApps: function() { var appName, confidence, version; - browser.tabs.query({ active: true, currentWindow: true }).then(function(tabs) { + var callback = function(tabs) { function sendGetApps(response) { + var html; + if ( response.tabCache && response.tabCache.count > 0 ) { detectedApps.innerHTML = ''; @@ -36,7 +49,7 @@ document.addEventListener('DOMContentLoaded', function() { html = '
' + '' + - '' + + '' + '' + appName + '' + ( version ? ' ' + version : '' ) + ( confidence < 100 ? ' (' + confidence + '% sure)' : '' ) + '' + ''; @@ -60,7 +73,15 @@ document.addEventListener('DOMContentLoaded', function() { } else { chrome.runtime.sendMessage({ id: 'get_apps', tab: tabs[0] }, sendGetApps); } - }); + }; + + try { + // Chrome, Firefox + browser.tabs.query({ active: true, currentWindow: true }).then(callback); + } catch ( e ) { + // Edge + browser.tabs.query({ active: true, currentWindow: true }, callback); + } } }; diff --git a/src/drivers/webextension/manifest.edge.json b/src/drivers/webextension/manifest.edge.json index 4c94099f2..9e9faf3a6 100644 --- a/src/drivers/webextension/manifest.edge.json +++ b/src/drivers/webextension/manifest.edge.json @@ -1,44 +1,51 @@ { "name": "Wappalyzer", - "short_name": "Wappalyzer", - "author": "Elbert Alias", + "short_name": "Wappalyzer", + "author": "Elbert Alias", "homepage_url": "https://wappalyzer.com/", "description": "Identify web technologies", - "version": "4", + "version": "4.0.1", "default_locale": "en", "manifest_version": 2, "icons": { - "16": "images/icon_16.png", - "19": "images/icon_19.png", - "32": "images/icon_32.png", - "38": "images/icon_38.png", + "16": "images/icon_16.png", + "19": "images/icon_19.png", + "32": "images/icon_32.png", + "38": "images/icon_38.png", "128": "images/icon_128.png" }, "page_action": { "default_icon": { - "16": "images/icon_16.png", - "19": "images/icon_19.png", - "32": "images/icon_32.png", - "38": "images/icon_38.png", - "128": "images/icon_128.png" - }, + "16": "images/icon_16.png", + "19": "images/icon_19.png", + "32": "images/icon_32.png", + "38": "images/icon_38.png", + "128": "images/icon_128.png" + }, "default_title": "Wappalyzer", "default_popup": "popup.html" }, "background": { "page": "background.html", - "persistent": true + "persistent": true }, "content_scripts": [ { - "matches": [ "http://*/*", "https://*/*" ], + "matches": [ + "http://*/*", + "https://*/*" + ], "js": [ "js/browser-polyfill.js", "js/content.js" ], "run_at": "document_idle" - }, { - "matches": [ "http://*/*", "https://*/*" ], + }, + { + "matches": [ + "http://*/*", + "https://*/*" + ], "js": [ "js/browser-polyfill.js", "js/iframe.js" @@ -50,7 +57,7 @@ "web_accessible_resources": [ "js/inject.js" ], - "options_page": "options.html", + "options_page": "options.html", "permissions": [ "tabs", "webRequest", @@ -58,5 +65,9 @@ "http://*/*", "https://*/*" ], - "content_security_policy": "script-src 'self'; object-src 'self'" + "content_security_policy": "script-src 'self'; object-src 'self'", + "-ms-preload": { + "backgroundScript": "js/ms_background_scripts_api_bridge.js", + "contentScript": "js/ms_content_scripts_api_bridge.js" + } } diff --git a/src/drivers/webextension/manifest.json b/src/drivers/webextension/manifest.json index 54d2a07e4..79d8409e9 100644 --- a/src/drivers/webextension/manifest.json +++ b/src/drivers/webextension/manifest.json @@ -1,27 +1,27 @@ { "name": "Wappalyzer", - "short_name": "Wappalyzer", - "author": "Elbert Alias", + "short_name": "Wappalyzer", + "author": "Elbert Alias", "homepage_url": "https://wappalyzer.com/", "description": "Identify web technologies", "version": "4.0.1", "default_locale": "en", "manifest_version": 2, "icons": { - "16": "images/icon_16.png", - "19": "images/icon_19.png", - "32": "images/icon_32.png", - "38": "images/icon_38.png", + "16": "images/icon_16.png", + "19": "images/icon_19.png", + "32": "images/icon_32.png", + "38": "images/icon_38.png", "128": "images/icon_128.png" }, "page_action": { "default_icon": { - "16": "images/icon_16.png", - "19": "images/icon_19.png", - "32": "images/icon_32.png", - "38": "images/icon_38.png", - "128": "images/icon_128.png" - }, + "16": "images/icon_16.png", + "19": "images/icon_19.png", + "32": "images/icon_32.png", + "38": "images/icon_38.png", + "128": "images/icon_128.png" + }, "default_title": "Wappalyzer", "default_popup": "popup.html" }, @@ -31,14 +31,21 @@ }, "content_scripts": [ { - "matches": [ "http://*/*", "https://*/*" ], + "matches": [ + "http://*/*", + "https://*/*" + ], "js": [ "js/browser-polyfill.js", "js/content.js" ], "run_at": "document_idle" - }, { - "matches": [ "http://*/*", "https://*/*" ], + }, + { + "matches": [ + "http://*/*", + "https://*/*" + ], "js": [ "js/browser-polyfill.js", "js/iframe.js" @@ -50,12 +57,13 @@ "web_accessible_resources": [ "js/inject.js" ], - "options_page": "options.html", + "options_page": "options.html", "options_ui": { - "page": "options.html", - "open_in_tab": false - }, + "page": "options.html", + "open_in_tab": false + }, "permissions": [ + "storage", "tabs", "webRequest", "webNavigation", @@ -64,3 +72,4 @@ ], "content_security_policy": "script-src 'self'; object-src 'self'" } + diff --git a/src/drivers/webextension/options.html b/src/drivers/webextension/options.html index 4b6817ce7..755b909e2 100644 --- a/src/drivers/webextension/options.html +++ b/src/drivers/webextension/options.html @@ -29,13 +29,10 @@

+

-

- Saved -

-

+ logo-green-icon + Created with Sketch. + + + + + + + + + \ No newline at end of file diff --git a/src/icons/Vinala.png b/src/icons/Vinala.png new file mode 100644 index 000000000..8aa46505e Binary files /dev/null and b/src/icons/Vinala.png differ diff --git a/src/icons/spin.js.png b/src/icons/spin.js.png deleted file mode 100644 index 4d79611b6..000000000 Binary files a/src/icons/spin.js.png and /dev/null differ diff --git a/src/icons/typecho.svg b/src/icons/typecho.svg new file mode 100644 index 000000000..b447bb51b --- /dev/null +++ b/src/icons/typecho.svg @@ -0,0 +1,10 @@ + + + typecho-logo + Created with Sketch (http://www.bohemiancoding.com/sketch) + + + + + + \ No newline at end of file diff --git a/src/icons/vis.js.png b/src/icons/vis.js.png deleted file mode 100644 index f40c5df55..000000000 Binary files a/src/icons/vis.js.png and /dev/null differ diff --git a/src/wappalyzer.js b/src/wappalyzer.js index 8eb4f289f..1ec8a4850 100644 --- a/src/wappalyzer.js +++ b/src/wappalyzer.js @@ -1,5 +1,5 @@ /** - * Wappalyzer v2 + * Wappalyzer v4 * * Created by Elbert Alias * @@ -102,33 +102,6 @@ var wappalyzer = (function() { } }; - var Profiler = function() { - this.regexCount = 0; - this.startTime = new Date().getTime(); - this.lastTime = new Date().getTime(); - this.slowest = { duration: null, app: '', type: '', pattern: '' }; - this.timedOut = false; - }; - - Profiler.prototype = { - checkPoint: function(app, type, regex) { - var duration = new Date().getTime() - this.lastTime; - - if ( !this.slowest.duration || duration > this.slowest.duration ) { - this.slowest.duration = duration; - this.slowest.app = app; - this.slowest.type = type; - this.slowest.regex = regex; - } - - this.regexCount++; - - this.lastTime = new Date().getTime(); - - this.timedOut = this.lastTime - this.startTime > w.driver.timeout; - } - }; - /** * Call driver functions */ @@ -149,42 +122,61 @@ var wappalyzer = (function() { /** * Parse apps.json patterns */ - var parse = function(patterns) { + var parsePatterns = function(patterns) { var - attrs, - parsed = []; + key, + parsed = {}; - // Convert single patterns to an array + // Convert array to object containing array + if ( patterns instanceof Array ) { + patterns = { main: patterns } + } + + // Convert string to object containing array containing string if ( typeof patterns === 'string' ) { - patterns = [ patterns ]; + patterns = { main: [ patterns ] }; } - patterns.forEach(function(pattern) { - attrs = {}; + for ( key in patterns ) { + parsed[key] = []; - pattern.split('\\;').forEach(function(attr, i) { - if ( i ) { - // Key value pairs - attr = attr.split(':'); + // Convert string to array containing string + if ( typeof patterns[key] === 'string' ) { + patterns[key] = [ patterns[key] ]; + } - if ( attr.length > 1 ) { - attrs[attr.shift()] = attr.join(':'); - } - } else { - attrs.string = attr; + patterns[key].forEach(function(pattern) { + var attrs = {}; + + pattern.split('\\;').forEach(function(attr, i) { + if ( i ) { + // Key value pairs + attr = attr.split(':'); - try { - attrs.regex = new RegExp(attr.replace('/', '\/'), 'i'); // Escape slashes in regular expression - } catch (e) { - attrs.regex = new RegExp(); + if ( attr.length > 1 ) { + attrs[attr.shift()] = attr.join(':'); + } + } else { + attrs.string = attr; + + try { + attrs.regex = new RegExp(attr.replace('/', '\/'), 'i'); // Escape slashes in regular expression + } catch (e) { + attrs.regex = new RegExp(); - w.log(e + ': ' + attr, 'error'); + w.log(e + ': ' + attr, 'error'); + } } - } + }); + + parsed[key].push(attrs); }); + } - parsed.push(attrs); - }); + // Convert back to array if the original pattern list was an array (or string) + if ( parsed.hasOwnProperty('main') ) { + parsed = parsed.main; + } return parsed; }; @@ -242,165 +234,75 @@ var wappalyzer = (function() { */ analyze: function(hostname, url, data) { var - i, app, confidence, type, regexMeta, regexScript, match, content, meta, header, version, id, - profiler = new Profiler(), - apps = {}, - excludes = [], - checkImplies = true; + app, + apps = {}; w.log('w.analyze'); - // Remove hash from URL - data.url = url = url.split('#')[0]; - if ( w.apps === undefined || w.categories === undefined ) { w.log('apps.json not loaded, check for syntax errors'); return; } + // Remove hash from URL + data.url = url = url.split('#')[0]; + + if ( typeof data.html !== 'string' ) { + data.html = ''; + } + if ( w.detected[url] === undefined ) { w.detected[url] = {}; } for ( app in w.apps ) { - // Exit loop after one second to prevent CPU hogging - // Remaining patterns will not be evaluated - if ( profiler.timedOut ) { - w.log('Timeout, exiting loop'); - - break; - } - apps[app] = w.detected[url] && w.detected[url][app] ? w.detected[url][app] : new Application(app); - for ( type in w.apps[app] ) { - switch ( type ) { - case 'url': - parse(w.apps[app][type]).forEach(function(pattern) { - if ( pattern.regex.test(url) ) { - apps[app].setDetected(pattern, type, url); - } - - profiler.checkPoint(app, type, pattern.regex); - }); - - break; - case 'html': - if ( typeof data[type] !== 'string' || !data.html ) { - break; - } - - parse(w.apps[app][type]).forEach(function(pattern) { - if ( pattern.regex.test(data[type]) ) { - apps[app].setDetected(pattern, type, data[type]); - } - - profiler.checkPoint(app, type, pattern.regex); - }); - - break; - case 'script': - if ( typeof data.html !== 'string' || !data.html ) { - break; - } - - regexScript = new RegExp(']+src=("|\')([^"\']+)', 'ig'); - - parse(w.apps[app][type]).forEach(function(pattern) { - while ( match = regexScript.exec(data.html) ) { - if ( pattern.regex.test(match[2]) ) { - apps[app].setDetected(pattern, type, match[2]); - } - } - - profiler.checkPoint(app, type, pattern.regex); - }); - - break; - case 'meta': - if ( typeof data.html !== 'string' || !data.html ) { - break; - } - - regexMeta = /]+>/ig; - - while ( match = regexMeta.exec(data.html) ) { - for ( meta in w.apps[app][type] ) { - profiler.checkPoint(app, type, regexMeta); - - if ( new RegExp('(name|property)=["\']' + meta + '["\']', 'i').test(match) ) { - content = match.toString().match(/content=("|')([^"']+)("|')/i); - - parse(w.apps[app].meta[meta]).forEach(function(pattern) { - if ( content && content.length === 4 && pattern.regex.test(content[2]) ) { - apps[app].setDetected(pattern, type, content[2], meta); - } - - profiler.checkPoint(app, type, pattern.regex); - }); - } - } - } - - break; - case 'headers': - if ( typeof data[type] !== 'object' || !data[type] ) { - break; - } - - for ( header in w.apps[app].headers ) { - parse(w.apps[app][type][header]).forEach(function(pattern) { - if ( data[type][header.toLowerCase()] instanceof Array ) { - data[type][header.toLowerCase()].forEach(function(el) { - if ( typeof el === 'string' && pattern.regex.test(el) ) { - apps[app].setDetected(pattern, type, data[type][header.toLowerCase()], header); - } - }); - } else { - if ( typeof data[type][header.toLowerCase()] === 'string' && pattern.regex.test(data[type][header.toLowerCase()]) ) { - apps[app].setDetected(pattern, type, data[type][header.toLowerCase()], header); - } - } - - profiler.checkPoint(app, type, pattern.regex); - }); - } - - break; - case 'env': - if ( typeof data[type] !== 'object' || !data[type] ) { - break; - } - - parse(w.apps[app][type]).forEach(function(pattern) { - for ( i in data[type] ) { + if ( url ) { + w.analyzeUrl(apps[app], url); + } - if ( pattern.regex.test(data[type][i]) ) { - apps[app].setDetected(pattern, type, data[type][i]); - } - } + if ( data.html ) { + w.analyzeHtml(apps[app], data.html); + w.analyzeScript(apps[app], data.html); + w.analyzeMeta(apps[app], data.html); + } - profiler.checkPoint(app, type, pattern.regex); - }); + if ( data.headers ) { + w.analyzeHeaders(apps[app], data.headers); + } - break; - } + if ( data.env ) { + w.analyzeEnv(apps[app], data.env); } } - w.log('[ profiler ] Tested ' + profiler.regexCount + ' regular expressions in ' + ( (new Date().getTime() - profiler.startTime) / 1000 ) + 's'); - w.log('[ profiler ] Slowest pattern took ' + ( profiler.slowest.duration / 1000 ) + 's: ' + profiler.slowest.app + ' | ' + profiler.slowest.type + ' | ' + profiler.slowest.regex); - for ( app in apps ) { if ( !apps[app].detected ) { delete apps[app]; } } + w.resolveExcludes(apps); + w.resolveImplies(apps, url); + + w.cacheDetectedApps(apps, url); + w.trackDetectedApps(apps, url, hostname, data.html); + + w.log(Object.keys(apps).length + ' apps detected: ' + Object.keys(apps).join(', ') + ' on ' + url); + + driver('displayApps'); + }, + + resolveExcludes: function(apps) { + var + app, + excludes = []; + // Exclude app in detected apps only for ( app in apps ) { - if (w.apps[app].excludes ) { + if ( w.apps[app].excludes ) { if ( typeof w.apps[app].excludes === 'string' ) { w.apps[app].excludes = [ w.apps[app].excludes ]; } @@ -417,6 +319,13 @@ var wappalyzer = (function() { delete apps[app]; } } + }, + + resolveImplies: function(apps, url) { + var + confidence, + id, + checkImplies = true; // Implied applications // Run several passes as implied apps may imply other apps @@ -433,7 +342,7 @@ var wappalyzer = (function() { } w.apps[app].implies.forEach(function(implied) { - implied = parse(implied)[0]; + implied = parsePatterns(implied)[0]; if ( !w.apps[implied.string] ) { w.log('Implied application ' + implied.string + ' does not exist', 'warn'); @@ -455,13 +364,16 @@ var wappalyzer = (function() { } } } + }, - w.log(Object.keys(apps).length + ' apps detected: ' + Object.keys(apps).join(', ') + ' on ' + url); + /** + * Cache detected applications + */ + cacheDetectedApps: function(apps, url) { + var app, id, confidence; - // Keep history of detected apps for ( app in apps ) { confidence = apps[app].confidence; - version = apps[app].version; // Per URL w.detected[url][app] = apps[app]; @@ -469,22 +381,35 @@ var wappalyzer = (function() { for ( id in confidence ) { w.detected[url][app].confidence[id] = confidence[id]; } + } + }, + + /** + * Track detected applications + */ + trackDetectedApps: function(apps, url, hostname, html) { + var app, match; + for ( app in apps ) { if ( w.detected[url][app].getConfidence() >= 100 ) { - // Per hostname if ( /(www.)?((.+?)\.(([a-z]{2,3}\.)?[a-z]{2,6}))$/.test(hostname) && !/((local|dev(elopment)?|stag(e|ing)?|test(ing)?|demo(shop)?|admin|google|cache)\.|\/admin|\.local)/.test(url) ) { if ( !w.ping.hostnames.hasOwnProperty(hostname) ) { - w.ping.hostnames[hostname] = { applications: {}, meta: {} }; + w.ping.hostnames[hostname] = { + applications: {}, + meta: {} + }; } if ( !w.ping.hostnames[hostname].applications.hasOwnProperty(app) ) { - w.ping.hostnames[hostname].applications[app] = { hits: 0 }; + w.ping.hostnames[hostname].applications[app] = { + hits: 0 + }; } w.ping.hostnames[hostname].applications[app].hits ++; - if ( version ) { - w.ping.hostnames[hostname].applications[app].version = version; + if ( apps[app].version ) { + w.ping.hostnames[hostname].applications[app].version = apps[app].version; } } else { w.log('Ignoring hostname "' + hostname + '"'); @@ -494,23 +419,133 @@ var wappalyzer = (function() { // Additional information if ( w.ping.hostnames.hasOwnProperty(hostname) ) { - if ( typeof data.html === 'string' && data.html ) { - match = data.html.match(/]*[: ]lang="([a-z]{2}((-|_)[A-Z]{2})?)"/i); + match = html.match(/]*[: ]lang="([a-z]{2}((-|_)[A-Z]{2})?)"/i); - if ( match && match.length ) { - w.ping.hostnames[hostname].meta['language'] = match[1]; - } + if ( match && match.length ) { + w.ping.hostnames[hostname].meta['language'] = match[1]; } } if ( Object.keys(w.ping.hostnames).length >= 50 || w.adCache.length >= 50 ) { driver('ping'); } + }, - apps = null; - data = null; + /** + * Analyze URL + */ + analyzeUrl: function(app, url) { + var patterns = parsePatterns(w.apps[app.app].url); - driver('displayApps'); + if ( patterns.length ) { + patterns.forEach(function(pattern) { + if ( pattern.regex.test(url) ) { + app.setDetected(pattern, 'url', url); + } + }); + } + }, + + /** + * Analyze HTML + */ + analyzeHtml: function(app, html) { + var patterns = parsePatterns(w.apps[app.app].html); + + if ( patterns.length ) { + patterns.forEach(function(pattern) { + if ( pattern.regex.test(html) ) { + app.setDetected(pattern, 'html', html); + } + }); + } + }, + + /** + * Analyze script tag + */ + analyzeScript: function(app, html) { + var + regex = new RegExp(']+src=("|\')([^"\']+)', 'ig'), + patterns = parsePatterns(w.apps[app.app].script); + + if ( patterns.length ) { + patterns.forEach(function(pattern) { + var match; + + while ( match = regex.exec(html) ) { + if ( pattern.regex.test(match[2]) ) { + app.setDetected(pattern, 'script', match[2]); + } + } + }); + } + }, + + /** + * Analyze meta tag + */ + analyzeMeta: function(app, html) { + var + content, match, meta, + regex = /]+>/ig, + patterns = parsePatterns(w.apps[app.app].meta); + + if ( patterns.length ) { + while ( match = regex.exec(html) ) { + for ( meta in patterns ) { + if ( new RegExp('(name|property)=["\']' + meta + '["\']', 'i').test(match) ) { + content = match.toString().match(/content=("|')([^"']+)("|')/i); + + patterns[meta].forEach(function(pattern) { + if ( content && content.length === 4 && pattern.regex.test(content[2]) ) { + app.setDetected(pattern, 'meta', content[2], meta); + } + }); + } + } + } + } + }, + + /** + * analyze response headers + */ + analyzeHeaders: function(app, headers) { + var + header, + patterns = parsePatterns(w.apps[app.app].headers); + + if ( patterns.length && headers ) { + for ( header in patterns ) { + patterns[header].forEach(function(pattern) { + header = header.toLowerCase(); + + if ( headers.hasOwnProperty(header) && pattern.regex.test(headers[header]) ) { + app.setDetected(pattern, 'headers', headers[header], header); + } + }); + } + } + }, + + /** + * Analyze environment variables + */ + analyzeEnv: function(app, envs) { + var patterns = parsePatterns(w.apps[app.app].env); + + if ( patterns.length ) { + patterns.forEach(function(pattern) { + var env; + + for ( env in envs ) { + if ( pattern.regex.test(envs[env]) ) { + app.setDetected(pattern, 'env', envs[env]); + } + } + }); + } } };