| Index: lib/contentPolicy.js | 
| =================================================================== | 
| --- a/lib/contentPolicy.js | 
| +++ b/lib/contentPolicy.js | 
| @@ -162,6 +162,7 @@ | 
| let wndLocation = originWindow.location.href; | 
| let docDomain = getHostname(wndLocation); | 
| let match = null; | 
| +    let [sitekey, sitekeyWnd] = getSitekey(wnd); | 
| if (!match && Prefs.enabled) | 
| { | 
| let testWnd = wnd; | 
| @@ -170,29 +171,7 @@ | 
| { | 
| let testWndLocation = parentWndLocation; | 
| parentWndLocation = (testWnd == testWnd.parent ? testWndLocation : getWindowLocation(testWnd.parent)); | 
| -        match = Policy.isWhitelisted(testWndLocation, parentWndLocation); | 
| - | 
| -        if (!(match instanceof WhitelistFilter)) | 
| -        { | 
| -          let keydata = (testWnd.document && testWnd.document.documentElement ? testWnd.document.documentElement.getAttribute("data-adblockkey") : null); | 
| -          if (keydata && keydata.indexOf("_") >= 0) | 
| -          { | 
| -            let [key, signature] = keydata.split("_", 2); | 
| -            let keyMatch = defaultMatcher.matchesByKey(testWndLocation, key.replace(/=/g, ""), docDomain); | 
| -            if (keyMatch && Utils.crypto) | 
| -            { | 
| -              // Website specifies a key that we know but is the signature valid? | 
| -              let uri = Services.io.newURI(testWndLocation, null, null); | 
| -              let params = [ | 
| -                uri.path.replace(/#.*/, ""),  // REQUEST_URI | 
| -                uri.asciiHost,                // HTTP_HOST | 
| -                Utils.httpProtocol.userAgent  // HTTP_USER_AGENT | 
| -              ]; | 
| -              if (Utils.verifySignature(key, signature, params.join("\0"))) | 
| -                match = keyMatch; | 
| -            } | 
| -          } | 
| -        } | 
| +        match = Policy.isWhitelisted(testWndLocation, parentWndLocation, sitekey); | 
|  | 
| if (match instanceof WhitelistFilter) | 
| { | 
| @@ -204,7 +183,11 @@ | 
| if (testWnd.parent == testWnd) | 
| break; | 
| else | 
| +        { | 
| +          if (testWnd == sitekeyWnd) | 
| +            [sitekey, sitekeyWnd] = getSitekey(testWnd.parent); | 
| testWnd = testWnd.parent; | 
| +        } | 
| } | 
| } | 
|  | 
| @@ -260,7 +243,7 @@ | 
|  | 
| if (!match && Prefs.enabled) | 
| { | 
| -      match = defaultMatcher.matchesAny(locationText, Policy.typeDescr[contentType] || "", docDomain, thirdParty); | 
| +      match = defaultMatcher.matchesAny(locationText, Policy.typeDescr[contentType] || "", docDomain, thirdParty, sitekey); | 
| if (match instanceof BlockingFilter && node.ownerDocument && !(contentType in Policy.nonVisual)) | 
| { | 
| let prefCollapse = (match.collapse != null ? match.collapse : !Prefs.fastcollapse); | 
| @@ -297,10 +280,11 @@ | 
| /** | 
| * Checks whether a page is whitelisted. | 
| * @param {String} url | 
| -   * @param {String} [parentUrl] location of the parent page | 
| +   * @param {String} (optional) parentUrl location of the parent page | 
| +   * @param {String} (optional) sitekey public key provided on the page | 
| * @return {Filter} filter that matched the URL or null if not whitelisted | 
| */ | 
| -  isWhitelisted: function(url, parentUrl) | 
| +  isWhitelisted: function(url, parentUrl, sitekey) | 
| { | 
| if (!url) | 
| return null; | 
| @@ -318,7 +302,7 @@ | 
| if (index >= 0) | 
| url = url.substring(0, index); | 
|  | 
| -    let result = defaultMatcher.matchesAny(url, "DOCUMENT", getHostname(parentUrl), false); | 
| +    let result = defaultMatcher.matchesAny(url, "DOCUMENT", getHostname(parentUrl), false, sitekey); | 
| return (result instanceof WhitelistFilter ? result : null); | 
| }, | 
|  | 
| @@ -329,10 +313,12 @@ | 
| */ | 
| isWindowWhitelisted: function(wnd) | 
| { | 
| -    return Policy.isWhitelisted(getWindowLocation(wnd)); | 
| +    let url = getWindowLocation(wnd); | 
| +    let parentUrl = (wnd.parent) ? getWindowLocation(wnd.parent) : url; | 
| +    let [sitekey, sitekeyWnd] = getSitekey(wnd); | 
| +    return Policy.isWhitelisted(url, parentUrl, sitekey); | 
| }, | 
|  | 
| - | 
| /** | 
| * Asynchronously re-checks filters for given nodes. | 
| */ | 
| @@ -691,6 +677,50 @@ | 
| } | 
|  | 
| /** | 
| + * Retrieves the sitekey of a window. | 
| + */ | 
| +function getSitekey(wnd) | 
| +{ | 
| +  let sitekey = null; | 
| + | 
| +  if (Utils.crypto) | 
| +  { | 
| +    while (wnd) | 
| +    { | 
| +      if (wnd.document && wnd.document.documentElement) | 
| +      { | 
| +        let foundKey = wnd.document.documentElement.getAttribute("data-adblockkey"); | 
| +        if (foundKey && foundKey.indexOf("_") > - 1) | 
| +        { | 
| +          let [key, signature] = foundKey.split("_", 2); | 
| + | 
| +          // Website specifies a key but is the signature valid? | 
| +          let uri = Services.io.newURI(getWindowLocation(wnd), null, null); | 
| +          let host = uri.asciiHost; | 
| +          if (uri.port > 0) | 
| +            host += ":" + uri.port; | 
| +          let params = [ | 
| +            uri.path.replace(/#.*/, ""),  // REQUEST_URI | 
| +            host,                         // HTTP_HOST | 
| +            Utils.httpProtocol.userAgent  // HTTP_USER_AGENT | 
| +          ]; | 
| +          if (Utils.verifySignature(key, signature, params.join("\0"))) | 
| +            sitekey = foundKey; | 
| +        } | 
| +        break; | 
| +      } | 
| + | 
| +      if (wnd === wnd.top) | 
| +        break; | 
| + | 
| +      wnd = wnd.parent; | 
| +    } | 
| +  } | 
| + | 
| +  return [sitekey, wnd]; | 
| +} | 
| + | 
| +/** | 
| * Retrieves the location of a window. | 
| * @param wnd {nsIDOMWindow} | 
| * @return {String} window location or null on failure | 
|  |