From 6591682b1eca5a38bfa942529722f04925c3f3a3 Mon Sep 17 00:00:00 2001 From: Elbert Alias <77259+AliasIO@users.noreply.github.com> Date: Wed, 19 Jul 2023 10:17:59 +1000 Subject: [PATCH] Possible fix for empty popup bug --- src/drivers/webextension/html/background.html | 1 - src/drivers/webextension/js/background.js | 1 - src/drivers/webextension/js/driver.js | 23 - src/drivers/webextension/js/lib/iframe.js | 1546 ----------------- src/drivers/webextension/js/lib/network.js | 864 --------- src/drivers/webextension/js/popup.js | 16 +- src/drivers/webextension/manifest-v2.json | 11 - src/drivers/webextension/manifest-v3.json | 11 - src/wappalyzer.js | 2 +- 9 files changed, 13 insertions(+), 2462 deletions(-) delete mode 100644 src/drivers/webextension/js/lib/iframe.js delete mode 100644 src/drivers/webextension/js/lib/network.js diff --git a/src/drivers/webextension/html/background.html b/src/drivers/webextension/html/background.html index ef82f1b2c..0bb1bdf41 100644 --- a/src/drivers/webextension/html/background.html +++ b/src/drivers/webextension/html/background.html @@ -6,7 +6,6 @@ - diff --git a/src/drivers/webextension/js/background.js b/src/drivers/webextension/js/background.js index 1743427fc..c762b7cb0 100644 --- a/src/drivers/webextension/js/background.js +++ b/src/drivers/webextension/js/background.js @@ -3,4 +3,3 @@ importScripts(chrome.runtime.getURL('js/wappalyzer.js')) importScripts(chrome.runtime.getURL('js/utils.js')) importScripts(chrome.runtime.getURL('js/driver.js')) -importScripts(chrome.runtime.getURL('js/lib/network.js')) diff --git a/src/drivers/webextension/js/driver.js b/src/drivers/webextension/js/driver.js index 32867b562..a22fe5d96 100644 --- a/src/drivers/webextension/js/driver.js +++ b/src/drivers/webextension/js/driver.js @@ -79,7 +79,6 @@ const Driver = { {} ), robots: await getOption('robots', {}), - ads: [], } const { version } = chrome.runtime.getManifest() @@ -711,14 +710,6 @@ const Driver = { Driver.log({ hostname, technologies: resolved }) }, - /** - * Callback for onAd listener - * @param {Object} ad - */ - onAd(ad) { - Driver.cache.ads.push(ad) - }, - /** * Update the extension icon * @param {String} url @@ -1009,20 +1000,6 @@ const Driver = { Driver.cache.hostnames[hostname].hits = 0 }) } - - if (Driver.cache.ads.length > 25) { - try { - await Driver.post( - 'https://ad.wappalyzer.com/log/wp/', - Driver.cache.ads - ) - } catch (error) { - // eslint-disable-next-line no-console - console.error(error) - } - - Driver.cache.ads = [] - } } }, } diff --git a/src/drivers/webextension/js/lib/iframe.js b/src/drivers/webextension/js/lib/iframe.js deleted file mode 100644 index c883e4ffb..000000000 --- a/src/drivers/webextension/js/lib/iframe.js +++ /dev/null @@ -1,1546 +0,0 @@ -'use strict' -/* eslint-env browser */ -/* globals chrome */ -;(function (win) { - const exports = {} - - ;(function (exports) { - const utils = { - /** - * Normalize URL - * @param {String} url - */ - normalizeUrl(url) { - return this.hashUrl(url) || null - }, - - /** - * Get referrer. - */ - getReferrer() { - return this.normalizeUrl(document.referrer) - }, - - /** - * Get current page URL. - */ - getPageUrl() { - return this.normalizeUrl(window.location.href) - }, - - /** - * Generated hashed URL. - * @param {String} url - */ - hashUrl(url) { - let 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 - }, - - /** - * Generate random hash. - * @param {String} str - */ - hashCode(str) { - let hash = 0 - let kar - let 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) - }, - - /** - * Apply array function to non-array. - * @param {Object} a - */ - realArray(a) { - return Array.prototype.slice.apply(a) - }, - - /** - * Listener callback for onDocLoaded. - * @param {Object} doc - * @param {Function} callback - */ - onDocLoaded(doc, callback) { - if (doc.readyState === 'loading') { - doc.addEventListener('DOMContentLoaded', callback) - } else { - callback() - } - }, - - SCRIPT_IN_WINDOW_TOP: window === window.top, - - /** - * Check for href Window object. - * @param {Object} win - */ - isFriendlyWindow(win) { - let href - try { - href = win.location.href - } catch (e) { - return false - } - return true - }, - - /** - * Get default view from element. - * @param {Object} el - */ - elementWindow(el) { - return el.ownerDocument.defaultView - }, - - /** - * Get viewport size. - * @param {Object} win - */ - viewport(win) { - return { width: win.innerWidth, height: win.innerHeight } - }, - - /** - * Parse query string parameters. - * @param {String} qs - */ - parseQS(qs) { - if (qs.indexOf('http') === 0) { - qs = qs.split('?')[1] - } - let i, kvs, key, val - const 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 - }, - - /** - * Send PostMessage response. - * @param {Object} message - * @param {String} event - * @param {String} responseMessage - */ - sendToBackground(message, event, responseMessage) { - try { - chrome.runtime.sendMessage(message, (message) => { - if (message && typeof message.tracking_enabled !== 'undefined') { - if (message.tracking_enabled) { - utilCallback() - } else { - utilElseCallback() - } - } - }) - } catch (error) { - // Continue - } - }, - - /** - * Check if anonymous tracking is enabled. - * @param {Function} callback - * @param {Function} elseCallback - * @todo validate if utilCallback or utilElseCallback are being used. - */ - askIfTrackingEnabled(callback, elseCallback) { - utilCallback = callback - utilElseCallback = elseCallback - - this.sendToBackground( - 'is_tracking_enabled', - '', - 'tracking_enabled_response' - ) - }, - } - - 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 - - /** - * Generate new Logging object. - */ - 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 data. - * @param {String} event - * @param {Array} opt_assets - * @param {Array} opt_pageTags - */ - log(event, opt_assets, opt_pageTags) { - let opt_video_assets - if (event === 'video' || event === 'invalid-video') { - opt_video_assets = opt_assets || [] - opt_assets = [] - } else { - opt_video_assets = [] - opt_assets = opt_assets || [] - } - const result = { - doc: this.pageMeta, - event, - video_assets: opt_video_assets, - assets: opt_assets, - version: '3', - mrev: '15a9f21-d', - msgNum: this.msgNum, - timestamp: new Date().getTime(), - pageVis: document.visibilityState, - pageFoc: document.hasFocus(), - pageTags: opt_pageTags || [], - } - this.msgNum++ - return result - }, - } - - utils.LogGenerator = LogGenerator - - let utilCallback, utilElseCallback - - exports.utils = utils - })(exports) - ;(function (exports) { - const 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, - - /** - * Get ad size. - * @param {Int} width - * @param {Int} height - */ - getMatchedAdSize(width, height) { - if (!this.set) { - this.set = this._makeSizeSet() - } - - return this.set[Math.round(width) + 'x' + Math.round(height)] - }, - - /** - * Check element size. - * @param {HTMLElement} el - */ - elementIsAdShaped(el) { - return !!this.getMatchedAdSizeForElement(el) - }, - - /** - * Get ad size. - * @param {HTMLElement} el - * @todo better description - */ - getMatchedAdSizeForElement(el) { - const rect = el.getBoundingClientRect() - return this.getMatchedAdSize(rect.width, rect.height) - }, - - /** - * Generate ad sizes. - */ - _makeSizeSet() { - const set = {} - let i - let xfuz - let yfuz - let size - let width - let 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 - }, - } - - const Throttler = { - MAX_SEARCHES_PER_WINDOW: 10, - MAX_SEARCHES_PER_ELEMENT: 2, - - /** - * Count number of elements. - * @param {HTMLElement} el - */ - countSearch: (el) => { - if (typeof el.searches !== 'number') { - el.searches = 0 - } - - el.searches += 1 - }, - - /** - * - * @param {*} el - * @param {*} max - * - * @todo add description - */ - throttle(el, max) { - if (typeof el.searches === 'number' && el.searches >= max) { - return true - } - return false - }, - - /** - * - * @param {*} el - * - * @todo add description - */ - throttleElement(el) { - return this.throttle(el, this.MAX_SEARCHES_PER_ELEMENT) - }, - - /** - * - * @param {*} win - * - * @todo add description - */ - throttleWin(win) { - return this.throttle(win, this.MAX_SEARCHES_PER_WINDOW) - }, - - /** - * - * @param {*} el - * - * @todo add description - */ - getCount(el) { - return el.searches || 0 - }, - } - - /** - * Initialize window and document elements. - * @param {*} win - */ - function TopSearcher(win) { - this.win = win - this.doc = win.document - } - - /** - * Add search function. - */ - TopSearcher.prototype.search = function () { - const candidates = exports.utils.realArray( - this.doc.querySelectorAll('img, object, embed') - ) - let html5Ad - let 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 - } - - /** - * @todo add description - */ - TopSearcher.prototype._mainGetHTMLAd = function () { - const styles = this.doc.querySelectorAll( - 'div > style, div > link[rel="stylesheet"]' - ) - let i - let div - for (i = 0; i < styles.length; i++) { - div = styles[i].parentNode - if ( - !div.mpAdFound && - SizeMatcher.elementIsAdShaped(div) && - this._jumpedOut(div) - ) { - return div - } - } - } - - /** - * @todo add description - */ - TopSearcher.prototype._jumpedOut = function (el) { - let 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 - } - - /** - * - * @param {*} win - * - * @todo add description - */ - 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 - } - } - } - - /** - * @todo add description - */ - IframeSearcher.prototype.search = function () { - let ad - - if (this.shouldSearchWindow) { - ad = this._search() - if (ad) { - ad.mpAdFound = true - win.mpAdFound = true - return ad - } - Throttler.countSearch(this.win) - } - - return null - } - - /** - * @todo add description - */ - IframeSearcher.prototype._search = function () { - const _this = this - let stdCandidates - let html5Candidates - let stdEl - let 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 - } - - /** - * @todo add description - */ - 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 - } - - /** - * @todo add description - */ - IframeSearcher.prototype._elementIsAtLeastAsBigAsWindow = function (el) { - const rect = el.getBoundingClientRect() - const tol = 0.95 - - return ( - rect.width >= tol * this.winWidth && rect.height >= tol * this.winHeight - ) - } - - /** - * @todo add description - */ - IframeSearcher.prototype._meetsMinAdSize = function (width, height) { - return width * height >= this.MIN_AD_AREA - } - - /** - * @todo add description - */ - IframeSearcher.prototype._containsLargeIframes = function () { - const iframes = this.doc.querySelectorAll('iframe') - let rect - let 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 - } - - /** - * @todo add description - */ - IframeSearcher.prototype._getAdSizeMeta = function () { - const adSizeMeta = this.doc.querySelectorAll('meta[name="ad.size"]') - if (adSizeMeta.length > 0) { - return adSizeMeta[0].content - } else { - return null - } - } - - /** - * - * @param {*} arr - * @param {*} testFn - * - * @todo add description - */ - function getFirst(arr, testFn) { - let i, el - for (i = 0; i < arr.length; i++) { - el = arr[i] - if (testFn(el)) { - return el - } - } - return null - } - - /** - * Check for image attributes. - * @param {HTMLElement} img - */ - function isStandardImage(img) { - return ( - img.src && - (img.parentNode.tagName === 'A' || img.getAttribute('onclick')) - ) - } - - /** - * Extract iFrames from page. - * @param {Object} win - */ - function getFriendlyIframes(win) { - let iframes = win.document.querySelectorAll('iframe') - iframes = exports.utils.realArray(iframes) - const friendlyIframes = iframes.filter(function (ifr) { - return exports.utils.isFriendlyWindow(ifr.contentWindow) - }) - return friendlyIframes - } - - /** - * - * @param {*} win - */ - function findAds(win) { - let i - let iframes - let searcher - let ad - let 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, - } - })(exports) - ;(function (exports) { - const parser = { - TAGS_WITH_SRC_ATTR: { - IMG: true, - SCRIPT: true, - IFRAME: true, - EMBED: true, - }, - - MAX_ATTR_LEN: 100, - - /** - * - * @param {*} el - * @param {*} params - * - * @todo add description - */ - getUrl(el, params) { - let 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 - } - }, - - /** - * - * @param {*} el - * - * @todo add description - */ - getParams(el) { - if (el.tagName !== 'OBJECT') { - return null - } - - let i, child - const params = {} - const 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 - }, - - /** - * Get element position. - * @param {HTMLElement} el - */ - getPosition(el) { - const rect = el.getBoundingClientRect() - const 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), - } - }, - - /** - * - * @param {*} el - * @param {*} params - * @param {*} url - * - * @todo add description - */ - getFlashvars(el, params, url) { - let flashvars - const 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 - }, - - /** - * - * @param {*} el - * @param {*} flashvars - * - * @todo add description - */ - findClickThru(el, flashvars) { - let 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 - }, - - /** - * Get element attribute. - * @param {HTMLElement} el - * @param {String} name - */ - getAttr(el, name) { - const val = el.getAttribute(name) - - if (val && val.slice && val.toString) { - return val.slice(0, this.MAX_ATTR_LEN).toString() - } else { - return null - } - }, - - /** - * - * @param {*} obj - * @param {*} name - * @param {*} val - * - * @todo add description - */ - putPropIfExists(obj, name, val) { - if (val) { - obj[name] = val - } - }, - - /** - * - * @param {*} obj - * @param {*} el - * @param {*} name - * - * @todo add description - */ - putAttrIfExists(obj, el, name) { - const val = this.getAttr(el, name) - this.putPropIfExists(obj, name, val) - }, - - /** - * Convert Element to JSON - * @param {HTMLElement} el - * @param {Boolean} opt_findClickThru - */ - elementToJSON(el, opt_findClickThru) { - const pos = this.getPosition(el) - const params = this.getParams(el) - const url = this.getUrl(el, params) - const flashvars = this.getFlashvars(el, params, url) - const clickThru = opt_findClickThru && this.findClickThru(el, flashvars) - const 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) - - // Anonymous invocation. - ;(function (exports) { - /** - * Setter for ad data. - * @param {*} adData - */ - const ContextManager = function (adData) { - this.adData = adData - } - - ContextManager.prototype = { - CONTAINER_SIZE_TOL: 0.4, - ASPECT_RATIO_FOR_LEADERBOARDS: 2, - - /** - * Check if iframe is valid. - * @param {HTMLElement} el - * @param {HTMLElement} opt_curWin - */ - isValidContainer(el, opt_curWin) { - const cWidth = el.clientWidth - const cHeight = el.clientHeight - - const adWidth = this.adData.width - const adHeight = this.adData.height - - const winWidth = opt_curWin && opt_curWin.innerWidth - const winHeight = opt_curWin && opt_curWin.innerHeight - const similarWin = - opt_curWin && - this.withinTol(adWidth, winWidth) && - this.withinTol(adHeight, winHeight) - - const similarSizeX = this.withinTol(adWidth, cWidth) - const similarSizeY = this.withinTol(adHeight, cHeight) - const adAspect = adWidth / adHeight - - return ( - similarWin || - el.tagName === 'A' || - (adAspect >= this.ASPECT_RATIO_FOR_LEADERBOARDS && similarSizeY) || - (similarSizeX && similarSizeY) - ) - }, - - /** - * Check tolerance. - * @param {Int} adlen - * @param {Int} conlen - */ - withinTol(adlen, conlen) { - const pct = (conlen - adlen) / adlen - - return pct <= this.CONTAINER_SIZE_TOL - }, - - /** - * Serialize elements. - * @param {*} el - * @todo define parameter type. - */ - serializeElements(el) { - if (!el) { - return - } - let i - let ifrWin - const adId = this.adData.adId - let elIsAd = false - - if (adId && el[adId] && el[adId].isAd === true) { - elIsAd = true - } - - const json = exports.parser.elementToJSON(el, elIsAd) - let childJSON - - if (elIsAd) { - json.adId = adId - this.adData.element = {} - - const keys = Object.keys(json) - for (i = 0; i < keys.length; i++) { - const key = keys[i] - if (key !== 'children' && key !== 'contents') { - this.adData.element[key] = json[key] - } - } - } - - const children = exports.utils - .realArray(el.children) - .filter(function (el) { - const param = el.tagName === 'PARAM' - const inlineScript = - el.tagName === 'SCRIPT' && !(el.src && el.src.includes('http')) - const 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 - } - }, - - /** - * Get element containers. - * @param {*} containerEl - */ - captureHTML(containerEl) { - this.adData.context = this.serializeElements(containerEl) - }, - - /** - * Get number of Nodes. - * @param {HTMLElement} el - */ - nodeCount(el) { - return el.getElementsByTagName('*').length + 1 - }, - - /** - * - * @param {*} curWin - * @param {*} referenceElement - * - * @todo add description - */ - highestContainer(curWin, referenceElement) { - let curContainer = referenceElement - const docEl = curWin.document.documentElement - let 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 - } - } - }, - } - - const tagfinder = { - /** - * - * @param {*} adData - * @param {*} opt_el - * @param {*} opt_winPos - * - * @todo add description - */ - setPositions(adData, opt_el, opt_winPos) { - const el = opt_el || adData.context - const winPos = opt_winPos || { left: 0, top: 0 } - let 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 - } - }, - - /** - * - * @param {*} adData - * @param {*} referenceElement - * - * @todo add description - */ - appendTags: (adData, referenceElement) => { - const mgr = new ContextManager(adData) - let curWin = exports.utils.elementWindow(referenceElement) - let 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, - highestContainer, - } - }, - } - - exports.tagfinder = tagfinder - })(exports) - ;(function (exports) { - let _onAdFound - const _logGen = new exports.utils.LogGenerator() - let _pageTags - const INIT_MS_BW_SEARCHES = 2000 - const PAGE_TAG_RE = new RegExp('gpt|oascentral') - const POST_MSG_ID = '1554456894-8541-12665-19466-15909' - const AD_SERVER_RE = new RegExp('^(google_ads_iframe|oas_frame|atwAdFrame)') - - /** - * Get script tags from document. - * @param {Object} doc - */ - function getPageTags(doc) { - let scripts = doc.getElementsByTagName('script') - const 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 - } - - /** - * Send message to parent iFrames. - * @param {String} adData - */ - function messageAllParentFrames(adData) { - adData.postMessageId = POST_MSG_ID - - adData = JSON.stringify(adData) - - let win = window - while (win !== win.top) { - win = win.parent - win.postMessage(adData, '*') - } - } - - /** - * - * @param {String} adData - * @param {HTMLElement} referenceElement - * - * @todo update description - */ - function appendTagsAndSendToParent(adData, referenceElement) { - const 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) - const log = _logGen.log('ad', [adData], _pageTags) - - if (_onAdFound) { - _onAdFound(log, results.referenceElement) - } - } - } - - /** - * SetTimeout wrapper for extracting ads. - */ - function extractAdsWrapper() { - if ( - exports.utils.SCRIPT_IN_WINDOW_TOP || - document.readyState === 'complete' - ) { - extractAds() - } - setTimeout(function () { - extractAdsWrapper() - }, INIT_MS_BW_SEARCHES) - } - - /** - * Main function for extracting ads after loaded. - */ - function extractAds() { - const ads = exports.adfinder.findAds(window) - ads.forEach(function (ad) { - const startTime = new Date().getTime() - const adId = startTime + '-' + Math.floor(Math.random() * 10e12) - - const adData = { - width: Math.round(ad.offsetWidth), - height: Math.round(ad.offsetHeight), - startTime, - 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) - }) - } - - /** - * Check if window is child of parent. - * @param {Object} myWin - * @param {Object} otherWin - */ - function isChildWin(myWin, otherWin) { - let parentWin = otherWin.parent - while (parentWin !== otherWin) { - if (parentWin === myWin) { - return true - } - otherWin = parentWin - parentWin = parentWin.parent - } - return false - } - - /** - * - * @param {*} win - * @param {*} winToMatch - * - * @todo update description - */ - function iframeFromWindow(win, winToMatch) { - let i - let ifr - let ifrWin - const 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 - } - } - } - } - - /** - * - * @param {*} event - * - * @todo update description - */ - function onPostMessage(event) { - let adData - const ifrWin = event.source - const myWin = window.document.defaultView - let ifrTag - - if (typeof event.data === 'string' && event.data.includes(POST_MSG_ID)) { - try { - adData = JSON.parse(event.data) - } catch (e) { - return - } - } else 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) - } - } - } - } - - /** - * - * @param {*} msg - * @param {*} sender - * @param {*} callback - * - * @todo update description - */ - function onVideoMessage(msg, sender, callback) { - let 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) - } - - /** - * Add background listener. - * @param {String} event - * @param {Function} callback - */ - function addBackgroundListener(event, callback) { - chrome.runtime.onMessage.addListener(function (msg) { - if (msg.event === event) { - callback(msg) - } - }) - } - - exports.coordinator = { - /** - * @todo update description - */ - addPostMessageListener() { - if (!exports.utils.SCRIPT_IN_FRIENDLY_IFRAME) { - window.addEventListener('message', onPostMessage, false) - } - }, - - /** - * - * @param {*} sendFcn - * @param {*} origUrl - * - * @todo update description - */ - blockedRobotsMsgGen(sendFcn, origUrl) { - if (!origUrl.includes('google.com/_/chrome/newtab')) { - const onBlockedRobotsMessage = function () { - let log - log = _logGen.log('invalid-robotstxt', []) - log.doc.finalPageUrl = log.doc.url - log.doc.url = exports.utils.normalizeUrl(origUrl) - - sendFcn(log) - } - return onBlockedRobotsMessage - } else { - return function () {} - } - }, - - /** - * - * @param {*} onAdFound - */ - init(onAdFound) { - if (exports.utils.SCRIPT_IN_FRIENDLY_IFRAME) { - return false - } - - _onAdFound = onAdFound - if (exports.utils.SCRIPT_IN_WINDOW_TOP) { - const log = _logGen.log('page') - onAdFound(log) - - window.addEventListener('beforeunload', function (event) { - const 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, - askIfTrackingEnabled: exports.utils.askIfTrackingEnabled, - blockedRobotsMsgGen: exports.coordinator.blockedRobotsMsgGen, - inWindowTop: exports.utils.SCRIPT_IN_WINDOW_TOP, - sendToBackground: exports.utils.sendToBackground, - } - } else { - exports.coordinator.addPostMessageListener() - exports.utils.askIfTrackingEnabled( - function () { - exports.coordinator.init(function () {}) - }, - function () {} - ) - } -})(window) -;(function (adparser, pageUrl) { - function onAdFound(log) { - adparser.sendToBackground( - { source: 'iframe.js', func: 'onAd', args: [log] }, - 'onAd', - '', - function () {} - ) - } - - if (adparser && adparser.inWindowTop) { - adparser.addPostMessageListener() - adparser.askIfTrackingEnabled(function () { - adparser.init(onAdFound) - }, adparser.blockedRobotsMsgGen(onAdFound, pageUrl)) - } -})(window.adparser, window.location.href) diff --git a/src/drivers/webextension/js/lib/network.js b/src/drivers/webextension/js/lib/network.js deleted file mode 100644 index 258d821ef..000000000 --- a/src/drivers/webextension/js/lib/network.js +++ /dev/null @@ -1,864 +0,0 @@ -'use strict' -;(function () { - const MIN_FF_MAJOR_VERSION = 51 - - let areListenersRegistered = false - const secBefore = 2000 - const secAfter = 5000 - const secBetweenDupAssets = 10e3 - const minVidSize = 500e3 - const maxVidSize = 25e6 - const maxContentRange = 25e6 - const 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', - ] - const extensionsReg = new RegExp('\\.' + videoExtensions.join('$|\\.') + '$') - const videoContentTypesPrefixes = [ - 'binary/octet-stream', - 'video/', - 'flv-application/', - 'media', - ] - - const bannedContentTypes = ['video/mp2t', 'video/f4m', 'video/f4f'] - const bannedFiletypes = ['ts'] - const bannedFiletypesReg = new RegExp( - '\\.' + bannedFiletypes.join('$|\\.') + '$' - ) - const whitelistReqTypes = ['object', 'xmlhttprequest', 'other'] - - const 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', - ] - - const robotsTxtAllows = Driver.checkRobots - if (!String.prototype.endsWith) { - String.prototype.endsWith = function (searchString, position) { - const subjectString = this.toString() - if ( - typeof position !== 'number' || - !isFinite(position) || - Math.floor(position) !== position || - position > subjectString.length - ) { - position = subjectString.length - } - position -= searchString.length - const lastIndex = subjectString.indexOf(searchString, position) - return lastIndex !== -1 && lastIndex === position - } - } - - function getFrame(getFrameDetails, callback) { - chrome.webNavigation.getFrame(getFrameDetails, callback) - } - - function ifTrackingEnabled(details, ifCallback, elseCallback) { - const fullIfCallback = function () { - allowedByRobotsTxt(details, ifCallback, elseCallback) - } - - Utils.getOption('tracking', true).then(function (tracking) { - if (tracking) { - fullIfCallback() - } else { - elseCallback() - } - }) - } - - function allowedByRobotsTxt(details, ifCallback, elseCallback) { - if (details.url && !details.url.startsWith('chrome://')) { - Driver.checkRobots(details.url, details.url.startsWith('https:')) - .then(ifCallback) - .catch(elseCallback) - } else { - elseCallback() - } - } - - function isPixelRequest(request) { - return ( - (request.type === 'image' || request.responseStatus === 204) && - request.size <= 1000 - ) - } - - function isVpaidOrVastRequest(request) { - const lowerCaseUrl = request.url.toLowerCase() - return lowerCaseUrl.includes('vpaid') || lowerCaseUrl.includes('vast') - } - - function hasValidRequestType(request) { - return whitelistReqTypes.includes(request.type) - } - - function stripQueryParams(url) { - return url.split('?', 1)[0] - } - - function parseHostnameFromUrl(url) { - try { - const { hostname } = new URL(url) - - return hostname - } catch { - return '' - } - } - - function hasDomain(url, domain) { - return parseHostnameFromUrl(url).endsWith(domain) - } - - function findHeader(headers, key) { - let header - for (let i = 0; i < headers.length; i += 1) { - header = headers[i] - if (header.name.toLowerCase() === key) { - return header - } - } - return null - } - - function validVideoType(vtype) { - const goodType = videoContentTypesPrefixes.some(function (prefix) { - return vtype.indexOf(prefix) === 0 - }) - return goodType - } - - function assetMsgKey(assetReq) { - const url = stripQueryParams(assetReq.url) - const key = assetReq.frameId + '-' + url - return key - } - - const PageNetworkTrafficCollector = function (tabId) { - this.tabId = tabId - this.displayAdFound = false - this.requests = {} - this.msgsBeingSent = {} - this.assetsSeen = {} - this.allRedirects = {} - } - - var globalPageContainer = { - collectors: {}, - dyingCollectors: {}, - - cleanupCollector(tabId) { - if (tabId in this.collectors) { - delete globalPageContainer.collectors[tabId] - } - }, - - onNewNavigation(details) { - const tabId = details.tabId - this.cleanupCollector(tabId) - - ifTrackingEnabled( - details, - function () { - if (!areListenersRegistered) { - registerListeners() - } - this.collectors[tabId] = new PageNetworkTrafficCollector(tabId) - }.bind(this), - function () { - if (areListenersRegistered) { - unregisterListeners() - } - } - ) - }, - - onNavigationCommitted(details) {}, - - onNavigationCompleted(details) {}, - - onTabClose(tabId, closeInfo) { - this.cleanupCollector(tabId) - delete this.collectors[tabId] - }, - - onDisplayAdFound(tabId) { - this.collectors[tabId].displayAdFound = true - }, - - getRandId() { - return String(Math.floor(Math.random() * 1e9)) - }, - - getCollector(tabId) { - if (this.collectors.hasOwnProperty(tabId)) { - return this.collectors[tabId] - } - return null - }, - - forwardCall(details, collectorMemberFunction) { - const collector = this.getCollector(details.tabId) - if (collector !== null) { - collectorMemberFunction.apply(collector, [details]) - } - }, - } - - PageNetworkTrafficCollector.prototype.sendLogMessageToTabConsole = function () { - const logMessage = Array.from(arguments).join(' ') - const message = { message: logMessage, event: 'console-log-message' } - chrome.tabs.sendMessage(this.tabId, message) - } - - PageNetworkTrafficCollector.prototype.sendToTab = function ( - assetReq, - reqs, - curPageUrl, - adTrackingEvent - ) { - const msg = {} - msg.assets = [] - msg.requests = [] - msg.event_data = {} - msg.event = adTrackingEvent - if (adTrackingEvent === 'new-video-ad') { - msg.requests = reqs - msg.requests.sort(function (reqA, reqB) { - return reqA.requestTimestamp - reqB.requestTimestamp - }) - if (assetReq) { - msg.assets = [assetReq] - } - } else if (adTrackingEvent === 'new-invalid-video-ad') { - msg.requests = reqs.map(function (request) { - return parseHostnameFromUrl(request.url) - }) - msg.assets = [ - { - url: parseHostnameFromUrl(assetReq.url), - - contentType: assetReq.contentType, - size: assetReq.size, - }, - ] - } - msg.origUrl = curPageUrl - msg.displayAdFound = this.displayAdFound - - chrome.tabs.sendMessage(this.tabId, msg) - } - - PageNetworkTrafficCollector.prototype.getRedirKey = function (url, frameId) { - return url + ':' + frameId - } - - PageNetworkTrafficCollector.prototype.seenBefore = function (request) { - const 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) { - const 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) { - let request, header - request = this.requests[details.requestId] - header = request && findHeader(details.requestHeaders, 'x-requested-with') - if (header && header.value.toLowerCase().includes('flash')) { - request.from_flash = true - } - } - - PageNetworkTrafficCollector.prototype.onHeadersReceived = function (details) { - const getFrameDetails = { - tabId: details.tabId, - processId: null, - frameId: details.frameId, - } - const pageNetworkTrafficController = this - getFrame(getFrameDetails, function (frameDetails) { - if (frameDetails && frameDetails.url) { - pageNetworkTrafficController._onHeadersReceived(details, frameDetails) - } - }) - } - - PageNetworkTrafficCollector.prototype._onHeadersReceived = function ( - details, - frameDetails - ) { - let contentSize, contentRange - - const request = this.requests[details.requestId] - if (request) { - const redirParent = this.allRedirects[ - this.getRedirKey(details.url, details.frameId) - ] - let header = - request && findHeader(details.responseHeaders, 'content-type') - const 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]) - } - - let 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) { - const 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 - ) { - const re = /video_masthead/ - return this.hasYoutubeDomain(url) && re.test(url) - } - PageNetworkTrafficCollector.prototype.isYoutubeVideoRequest = function ( - srcUrl, - destUrl - ) { - if (!this.hasYoutubeDomain(srcUrl)) { - return false - } - - const re = /https?:\/\/r.*?\.googlevideo\.com\/videoplayback\?/ - return re.test(destUrl) - } - PageNetworkTrafficCollector.prototype.processResponse = function ( - requestDetails, - frameDetails - ) { - let request - if (requestDetails) { - request = this.requests[requestDetails.requestId] - if (request) { - request.responseStatus = requestDetails.statusCode - request.responseTimestamp = requestDetails.timeStamp - - let frameUrl = null - if (frameDetails && frameDetails.url) { - frameUrl = frameDetails.url - } - - let requestUrl = null - if (request.url) { - requestUrl = request.url - } - - if (this.isYoutubeAdReq(frameUrl, requestUrl)) { - const destVideoId = this.parseYoutubeVideoIdFromUrl(requestUrl) - const srcVideoId = this.parseYoutubeVideoIdFromUrl(frameUrl) - if (srcVideoId && destVideoId) { - request.isYoutubeAd = true - request.isVideo = true - request.rawSrcUrl = frameUrl - request.rawDestUrl = requestUrl - 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) { - const 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 - } - const getFrameDetails = { - tabId: responseDetails.tabId, - processId: null, - frameId: responseDetails.frameId, - } - const pageNetworkTrafficController = this - getFrame(getFrameDetails, function (frameDetails) { - if (frameDetails && frameDetails.url) { - pageNetworkTrafficController.processResponse( - responseDetails, - frameDetails - ) - } - }) - } - - PageNetworkTrafficCollector.prototype.hasBannedFiletype = function (request) { - const 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) { - const 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) { - const hostname = parseHostnameFromUrl(url) - if (hostname === 'www.youtube.com') { - return true - } - return false - } - PageNetworkTrafficCollector.prototype.parseYoutubeVideoIdFromUrl = function ( - url - ) { - let re = /^https?:\/\/www\.youtube\.com\/get_video_info.*(?:\?|&)video_id=(.*?)(?:$|&)/ - let 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 - ) { - const 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) { - let badType = false - if (request.contentType) { - badType = bannedContentTypes.some(function (prefix) { - return request.contentType.includes(prefix) - }) - } - 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 - ) { - let minTimestamp, maxTimestamp - minTimestamp = assetRequest.requestTimestamp - secBefore - maxTimestamp = assetRequest.requestTimestamp + secAfter - - const 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 - ) { - const hasVpaidOrVastRequest = tagRequests.some(function (tagRequest) { - return isVpaidOrVastRequest(tagRequest) - }) - - if (assetRequest.isYoutubeAd) { - return true - } - if (hasVpaidOrVastRequest) { - return true - } - const hasTopVideoAssetDomain = topVideoAssetDomains.some(function ( - assetDomain - ) { - return hasDomain(assetRequest.url, assetDomain) - }) - - return hasTopVideoAssetDomain - } - - PageNetworkTrafficCollector.prototype.sendMsgWhenQuiet = function (msgKey) { - const _this = this - let origPageUrl - let msgAssetReq - msgAssetReq = this.msgsBeingSent[msgKey] - chrome.tabs.get(this.tabId, function (tab) { - origPageUrl = tab.url - }) - - setTimeout(function () { - const rawRequests = [] - if (globalPageContainer.collectors[_this.tabId] === _this) { - for (const reqId in _this.requests) { - rawRequests.push(_this.requests[reqId]) - } - const tagReqs = _this.grabTagReqs(rawRequests, msgAssetReq) - - if (_this.isValidVideoAd(msgAssetReq, tagReqs)) { - _this.sendToTab(msgAssetReq, tagReqs, origPageUrl, 'new-video-ad') - } else { - _this.sendToTab( - msgAssetReq, - tagReqs, - origPageUrl, - 'new-invalid-video-ad' - ) - } - } else { - } - delete _this.msgsBeingSent[msgKey] - }, secAfter + secBefore) - } - - PageNetworkTrafficCollector.prototype.existingMessage = function ( - candidateRequest - ) { - const 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') { - const tabId = sender.tab.id - if (tabId) { - globalPageContainer.onDisplayAdFound(tabId) - } - } - } - - function registerListeners() { - chrome.webRequest.onBeforeRequest.addListener( - onBeforeRequestListener, - { urls: ['http://*/*', 'https://*/*'] }, - [] - ) - - chrome.webRequest.onSendHeaders.addListener( - onSendHeadersListener, - { urls: ['http://*/*', 'https://*/*'] }, - ['requestHeaders'] - ) - - chrome.webRequest.onHeadersReceived.addListener( - onHeadersReceivedListener, - { urls: ['http://*/*', 'https://*/*'] }, - ['responseHeaders'] - ) - - chrome.webRequest.onBeforeRedirect.addListener( - onBeforeRedirectListener, - { urls: ['http://*/*', 'https://*/*'] }, - [] - ) - - chrome.webRequest.onResponseStarted.addListener( - onResponseStartedListener, - { urls: ['http://*/*', 'https://*/*'] }, - ['responseHeaders'] - ) - - chrome.webNavigation.onCommitted.addListener(onCommittedListener) - chrome.webNavigation.onCompleted.addListener(onCompletedListener) - chrome.tabs.onRemoved.addListener(onRemovedListener) - chrome.runtime.onMessage.addListener(onMessageListener) - - areListenersRegistered = true - } - - function unregisterListeners() { - chrome.webRequest.onBeforeRequest.removeListener(onBeforeRequestListener) - - chrome.webRequest.onSendHeaders.removeListener(onSendHeadersListener) - - chrome.webRequest.onHeadersReceived.removeListener( - onHeadersReceivedListener - ) - - chrome.webRequest.onBeforeRedirect.removeListener(onBeforeRedirectListener) - - chrome.webRequest.onResponseStarted.removeListener( - onResponseStartedListener - ) - - chrome.webNavigation.onCommitted.removeListener(onCommittedListener) - chrome.webNavigation.onCompleted.removeListener(onCompletedListener) - chrome.tabs.onRemoved.removeListener(onRemovedListener) - chrome.runtime.onMessage.removeListener(onMessageListener) - areListenersRegistered = false - } - - chrome.webNavigation.onBeforeNavigate.addListener( - function (details) { - if (details.frameId === 0) { - globalPageContainer.onNewNavigation(details) - } - }, - { - url: [{ urlMatches: 'http://*/*' }, { urlMatches: 'https://*/*' }], - } - ) - - chrome.runtime.onMessage.addListener((message, sender, callback) => { - if (message === 'is_tracking_enabled') { - ifTrackingEnabled( - sender.tab, - function () { - try { - callback({ tracking_enabled: true }) - } catch (err) {} - }, - function () { - try { - callback({ tracking_enabled: false }) - } catch (err) {} - } - ) - } - return true - }) -})() diff --git a/src/drivers/webextension/js/popup.js b/src/drivers/webextension/js/popup.js index bea241e7e..73f9bf5da 100644 --- a/src/drivers/webextension/js/popup.js +++ b/src/drivers/webextension/js/popup.js @@ -585,8 +585,12 @@ const Popup = { el.issue.classList.remove('issue--hidden') el.plusDownload.classList.remove('plus-download--hidden') - while (el.detections.firstChild) { - el.detections.removeChild(detections.firstChild) + let firstChild + + while ((firstChild = el.detections.firstChild)) { + if (firstChild instanceof Node) { + el.detections.removeChild(firstChild) + } } const pinnedCategory = await getOption('pinnedCategory') @@ -722,8 +726,12 @@ const Popup = { el.crawl.classList.add('plus-crawl--hidden') el.error.classList.add('plus-error--hidden') - while (el.panels.lastElementChild) { - el.panels.removeChild(el.panels.lastElementChild) + let lastChild + + while ((lastChild = el.panels.lastElementChild)) { + if (lastChild instanceof Node) { + el.panels.removeChild(lastChild) + } } try { diff --git a/src/drivers/webextension/manifest-v2.json b/src/drivers/webextension/manifest-v2.json index d4bdc9e79..055605b99 100644 --- a/src/drivers/webextension/manifest-v2.json +++ b/src/drivers/webextension/manifest-v2.json @@ -46,17 +46,6 @@ "js/content.js" ], "run_at": "document_idle" - }, - { - "matches": [ - "http://*/*", - "https://*/*" - ], - "js": [ - "js/lib/iframe.js" - ], - "run_at": "document_start", - "all_frames": true } ], "web_accessible_resources": [ diff --git a/src/drivers/webextension/manifest-v3.json b/src/drivers/webextension/manifest-v3.json index 39ca6ea92..94d48fbef 100644 --- a/src/drivers/webextension/manifest-v3.json +++ b/src/drivers/webextension/manifest-v3.json @@ -46,17 +46,6 @@ "js/content.js" ], "run_at": "document_idle" - }, - { - "matches": [ - "http://*/*", - "https://*/*" - ], - "js": [ - "js/lib/iframe.js" - ], - "run_at": "document_start", - "all_frames": true } ], "web_accessible_resources": [ diff --git a/src/wappalyzer.js b/src/wappalyzer.js index 3ce82e235..f99a592f2 100644 --- a/src/wappalyzer.js +++ b/src/wappalyzer.js @@ -99,7 +99,7 @@ const Wappalyzer = { const resolved = detections.reduce((resolved, { technology, lastUrl }) => { if ( resolved.findIndex( - ({ technology: { name } }) => name === technology.name + ({ technology: { name } }) => name === technology?.name ) === -1 ) { let version = ''