// Determine if aFirstURI is third party with respect to aSecondURI. See docs // for mozIThirdPartyUtil. NS_IMETHODIMP ThirdPartyUtil::IsThirdPartyURI(nsIURI* aFirstURI, nsIURI* aSecondURI, bool* aResult) { NS_ENSURE_ARG(aFirstURI); NS_ENSURE_ARG(aSecondURI); NS_ASSERTION(aResult, "null outparam pointer"); nsCString firstHost; nsresult rv = GetBaseDomain(aFirstURI, firstHost); if (NS_FAILED(rv)) return rv; return IsThirdPartyInternal(firstHost, aSecondURI, aResult); }
// Determine if aFirstDomain is a different base domain to aSecondURI; or, if // the concept of base domain does not apply, determine if the two hosts are not // string-identical. nsresult ThirdPartyUtil::IsThirdPartyInternal(const nsCString& aFirstDomain, nsIURI* aSecondURI, bool* aResult) { NS_ASSERTION(aSecondURI, "null URI!"); // Get the base domain for aSecondURI. nsCString secondDomain; nsresult rv = GetBaseDomain(aSecondURI, secondDomain); if (NS_FAILED(rv)) return rv; // Check strict equality. *aResult = aFirstDomain != secondDomain; return NS_OK; }
// Determine if aFirstDomain is a different base domain to aSecondURI; or, if // the concept of base domain does not apply, determine if the two hosts are not // string-identical. nsresult ThirdPartyUtil::IsThirdPartyInternal(const nsCString& aFirstDomain, nsIURI* aSecondURI, bool* aResult) { NS_ENSURE_ARG(aSecondURI); // Get the base domain for aSecondURI. nsCString secondDomain; nsresult rv = GetBaseDomain(aSecondURI, secondDomain); LOG(("ThirdPartyUtil::IsThirdPartyInternal %s =? %s", aFirstDomain.get(), secondDomain.get())); if (NS_FAILED(rv)) return rv; // Check strict equality. *aResult = aFirstDomain != secondDomain; return NS_OK; }
NS_IMETHODIMP ThirdPartyUtil::GetFirstPartyHostForIsolation(nsIURI *aFirstPartyURI, nsACString& aHost) { if (!aFirstPartyURI) return NS_ERROR_INVALID_ARG; if (!SchemeIsWhiteListed(aFirstPartyURI)) { nsresult rv = GetBaseDomain(aFirstPartyURI, aHost); return (aHost.Length() > 0) ? NS_OK : rv; } // This URI lacks a host, so construct and return a pseudo-host. aHost = "--NoFirstPartyHost-"; // Append the scheme. To ensure that the pseudo-hosts are consistent // when the hacky "moz-safe-about" scheme is used, map it back to "about". nsAutoCString scheme; nsresult rv = aFirstPartyURI->GetScheme(scheme); NS_ENSURE_SUCCESS(rv, rv); if (scheme.Equals("moz-safe-about")) aHost.Append("about"); else aHost.Append(scheme); // Append the URL's file name (e.g., -browser.xul) or its path (e.g., // -home for about:home) nsAutoCString s; nsCOMPtr<nsIURL> url = do_QueryInterface(aFirstPartyURI); if (url) url->GetFileName(s); else aFirstPartyURI->GetPath(s); if (s.Length() > 0) { aHost.Append("-"); aHost.Append(s); } aHost.Append("--"); return NS_OK; }
// Determine if any URI of the window hierarchy of aWindow is foreign with // respect to aSecondURI. See docs for mozIThirdPartyUtil. NS_IMETHODIMP ThirdPartyUtil::IsThirdPartyWindow(nsIDOMWindow* aWindow, nsIURI* aURI, bool* aResult) { NS_ENSURE_ARG(aWindow); NS_ASSERTION(aResult, "null outparam pointer"); bool result; // Get the URI of the window, and its base domain. nsCOMPtr<nsIURI> currentURI = GetURIFromWindow(aWindow); //NS_ENSURE_TRUE(currentURI, NS_ERROR_INVALID_ARG); nsCString bottomDomain; nsresult rv = GetBaseDomain(currentURI, bottomDomain); if (NS_FAILED(rv)) return rv; if (aURI) { // Determine whether aURI is foreign with respect to currentURI. rv = IsThirdPartyInternal(bottomDomain, aURI, &result); if (NS_FAILED(rv)) return rv; if (result) { *aResult = true; return NS_OK; } } nsCOMPtr<nsIDOMWindow> current = aWindow, parent; nsCOMPtr<nsIURI> parentURI; do { // We use GetScriptableParent rather than GetParent because we consider // <iframe mozbrowser/mozapp> to be a top-level frame. rv = current->GetScriptableParent(getter_AddRefs(parent)); NS_ENSURE_SUCCESS(rv, rv); if (SameCOMIdentity(parent, current)) { // We're at the topmost content window. We already know the answer. *aResult = false; return NS_OK; } parentURI = GetURIFromWindow(parent); NS_ENSURE_TRUE(parentURI, NS_ERROR_INVALID_ARG); rv = IsThirdPartyInternal(bottomDomain, parentURI, &result); if (NS_FAILED(rv)) return rv; if (result) { *aResult = true; return NS_OK; } current = parent; currentURI = parentURI; } while (1); NS_NOTREACHED("should've returned"); return NS_ERROR_UNEXPECTED; }
// Determine if the URI associated with aChannel or any URI of the window // hierarchy associated with the channel is foreign with respect to aSecondURI. // See docs for mozIThirdPartyUtil. NS_IMETHODIMP ThirdPartyUtil::IsThirdPartyChannel(nsIChannel* aChannel, nsIURI* aURI, bool* aResult) { NS_ENSURE_ARG(aChannel); NS_ASSERTION(aResult, "null outparam pointer"); nsresult rv; bool doForce = false; nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal = do_QueryInterface(aChannel); if (httpChannelInternal) { rv = httpChannelInternal->GetForceAllowThirdPartyCookie(&doForce); NS_ENSURE_SUCCESS(rv, rv); // If aURI was not supplied, and we're forcing, then we're by definition // not foreign. If aURI was supplied, we still want to check whether it's // foreign with respect to the channel URI. (The forcing only applies to // whatever window hierarchy exists above the channel.) if (doForce && !aURI) { *aResult = false; return NS_OK; } } // Obtain the URI from the channel, and its base domain. nsCOMPtr<nsIURI> channelURI; aChannel->GetURI(getter_AddRefs(channelURI)); NS_ENSURE_TRUE(channelURI, NS_ERROR_INVALID_ARG); nsCString channelDomain; rv = GetBaseDomain(channelURI, channelDomain); if (NS_FAILED(rv)) return rv; if (aURI) { // Determine whether aURI is foreign with respect to channelURI. bool result; rv = IsThirdPartyInternal(channelDomain, aURI, &result); if (NS_FAILED(rv)) return rv; // If it's foreign, or we're forcing, we're done. if (result || doForce) { *aResult = result; return NS_OK; } } // Find the associated window and its parent window. nsCOMPtr<nsILoadContext> ctx; NS_QueryNotificationCallbacks(aChannel, ctx); if (!ctx) return NS_ERROR_INVALID_ARG; // If there is no window, the consumer kicking off the load didn't provide one // to the channel. This is limited to loads of certain types of resources. If // those loads require cookies, the forceAllowThirdPartyCookie property should // be set on the channel. nsCOMPtr<nsIDOMWindow> ourWin, parentWin; ctx->GetAssociatedWindow(getter_AddRefs(ourWin)); if (!ourWin) return NS_ERROR_INVALID_ARG; // We use GetScriptableParent rather than GetParent because we consider // <iframe mozbrowser/mozapp> to be a top-level frame. ourWin->GetScriptableParent(getter_AddRefs(parentWin)); NS_ENSURE_TRUE(parentWin, NS_ERROR_INVALID_ARG); // Check whether this is the document channel for this window (representing a // load of a new page). In that situation we want to avoid comparing // channelURI to ourWin, since what's in ourWin right now will be replaced as // the channel loads. This covers the case of a freshly kicked-off load // (e.g. the user typing something in the location bar, or clicking on a // bookmark), where the window's URI hasn't yet been set, and will be bogus. // It also covers situations where a subframe is navigated to someting that // is same-origin with all its ancestors. This is a bit of a nasty hack, but // we will hopefully flag these channels better later. nsLoadFlags flags; rv = aChannel->GetLoadFlags(&flags); NS_ENSURE_SUCCESS(rv, rv); if (flags & nsIChannel::LOAD_DOCUMENT_URI) { if (SameCOMIdentity(ourWin, parentWin)) { // We only need to compare aURI to the channel URI -- the window's will be // bogus. We already know the answer. *aResult = false; return NS_OK; } // Make sure to still compare to ourWin's ancestors ourWin = parentWin; } // Check the window hierarchy. This covers most cases for an ordinary page // load from the location bar. return IsThirdPartyWindow(ourWin, channelURI, aResult); }