nsresult
CompareNetwork::Initialize(nsIPrincipal* aPrincipal, const nsAString& aURL, nsILoadGroup* aLoadGroup)
{
    MOZ_ASSERT(aPrincipal);
    AssertIsOnMainThread();

    nsCOMPtr<nsIURI> uri;
    nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL, nullptr, nullptr);
    if (NS_WARN_IF(NS_FAILED(rv))) {
        return rv;
    }

    nsCOMPtr<nsILoadGroup> loadGroup;
    rv = NS_NewLoadGroup(getter_AddRefs(loadGroup), aPrincipal);
    if (NS_WARN_IF(NS_FAILED(rv))) {
        return rv;
    }

    nsLoadFlags flags = nsIChannel::LOAD_BYPASS_SERVICE_WORKER;
    RefPtr<ServiceWorkerRegistrationInfo> registration =
        mManager->GetRegistration();
    if (registration->IsLastUpdateCheckTimeOverOneDay()) {
        flags |= nsIRequest::LOAD_BYPASS_CACHE;
    }

    // Note that because there is no "serviceworker" RequestContext type, we can
    // use the TYPE_INTERNAL_SCRIPT content policy types when loading a service
    // worker.
    rv = NS_NewChannel(getter_AddRefs(mChannel),
                       uri, aPrincipal,
                       nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED,
                       nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER,
                       loadGroup,
                       nullptr, // aCallbacks
                       flags);
    if (NS_WARN_IF(NS_FAILED(rv))) {
        return rv;
    }

    nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(mChannel);
    if (httpChannel) {
        // Spec says no redirects allowed for SW scripts.
        httpChannel->SetRedirectionLimit(0);

        httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Service-Worker"),
                                      NS_LITERAL_CSTRING("script"),
                                      /* merge */ false);
    }

    nsCOMPtr<nsIStreamLoader> loader;
    rv = NS_NewStreamLoader(getter_AddRefs(loader), this, this);
    if (NS_WARN_IF(NS_FAILED(rv))) {
        return rv;
    }

    rv = mChannel->AsyncOpen2(loader);
    if (NS_WARN_IF(NS_FAILED(rv))) {
        return rv;
    }

    return NS_OK;
}
Beispiel #2
0
nsresult
PendingLookup::SendRemoteQueryInternal()
{
  // If we aren't supposed to do remote lookups, bail.
  if (!Preferences::GetBool(PREF_SB_DOWNLOADS_REMOTE_ENABLED, false)) {
    LOG(("Remote lookups are disabled [this = %p]", this));
    return NS_ERROR_NOT_AVAILABLE;
  }
  // If the remote lookup URL is empty or absent, bail.
  nsCString serviceUrl;
  NS_ENSURE_SUCCESS(Preferences::GetCString(PREF_SB_APP_REP_URL, &serviceUrl),
                    NS_ERROR_NOT_AVAILABLE);
  if (serviceUrl.IsEmpty()) {
    LOG(("Remote lookup URL is empty [this = %p]", this));
    return NS_ERROR_NOT_AVAILABLE;
  }

  // If the blocklist or allowlist is empty (so we couldn't do local lookups),
  // bail
  {
    nsAutoCString table;
    NS_ENSURE_SUCCESS(Preferences::GetCString(PREF_DOWNLOAD_BLOCK_TABLE,
                                              &table),
                      NS_ERROR_NOT_AVAILABLE);
    if (table.IsEmpty()) {
      LOG(("Blocklist is empty [this = %p]", this));
      return NS_ERROR_NOT_AVAILABLE;
    }
  }
#ifdef XP_WIN
  // The allowlist is only needed to do signature verification on Windows
  {
    nsAutoCString table;
    NS_ENSURE_SUCCESS(Preferences::GetCString(PREF_DOWNLOAD_ALLOW_TABLE,
                                              &table),
                      NS_ERROR_NOT_AVAILABLE);
    if (table.IsEmpty()) {
      LOG(("Allowlist is empty [this = %p]", this));
      return NS_ERROR_NOT_AVAILABLE;
    }
  }
#endif

  LOG(("Sending remote query for application reputation [this = %p]",
       this));
  // We did not find a local result, so fire off the query to the
  // application reputation service.
  nsCOMPtr<nsIURI> uri;
  nsresult rv;
  rv = mQuery->GetSourceURI(getter_AddRefs(uri));
  NS_ENSURE_SUCCESS(rv, rv);
  nsCString spec;
  rv = GetStrippedSpec(uri, spec);
  NS_ENSURE_SUCCESS(rv, rv);
  mRequest.set_url(spec.get());

  uint32_t fileSize;
  rv = mQuery->GetFileSize(&fileSize);
  NS_ENSURE_SUCCESS(rv, rv);
  mRequest.set_length(fileSize);
  // We have no way of knowing whether or not a user initiated the
  // download. Set it to true to lessen the chance of false positives.
  mRequest.set_user_initiated(true);

  nsCString locale;
  NS_ENSURE_SUCCESS(Preferences::GetCString(PREF_GENERAL_LOCALE, &locale),
                    NS_ERROR_NOT_AVAILABLE);
  mRequest.set_locale(locale.get());
  nsCString sha256Hash;
  rv = mQuery->GetSha256Hash(sha256Hash);
  NS_ENSURE_SUCCESS(rv, rv);
  mRequest.mutable_digests()->set_sha256(sha256Hash.Data());
  nsString fileName;
  rv = mQuery->GetSuggestedFileName(fileName);
  NS_ENSURE_SUCCESS(rv, rv);
  mRequest.set_file_basename(NS_ConvertUTF16toUTF8(fileName).get());
  mRequest.set_download_type(GetDownloadType(fileName));

  if (mRequest.signature().trusted()) {
    LOG(("Got signed binary for remote application reputation check "
         "[this = %p]", this));
  } else {
    LOG(("Got unsigned binary for remote application reputation check "
         "[this = %p]", this));
  }

  // Serialize the protocol buffer to a string. This can only fail if we are
  // out of memory, or if the protocol buffer req is missing required fields
  // (only the URL for now).
  std::string serialized;
  if (!mRequest.SerializeToString(&serialized)) {
    return NS_ERROR_UNEXPECTED;
  }
  LOG(("Serialized protocol buffer [this = %p]: (length=%d) %s", this,
       serialized.length(), serialized.c_str()));

  // Set the input stream to the serialized protocol buffer
  nsCOMPtr<nsIStringInputStream> sstream =
    do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv);
  NS_ENSURE_SUCCESS(rv, rv);

  rv = sstream->SetData(serialized.c_str(), serialized.length());
  NS_ENSURE_SUCCESS(rv, rv);

  // Set up the channel to transmit the request to the service.
  nsCOMPtr<nsIIOService> ios = do_GetService(NS_IOSERVICE_CONTRACTID, &rv);
  rv = ios->NewChannel2(serviceUrl,
                        nullptr,
                        nullptr,
                        nullptr, // aLoadingNode
                        nsContentUtils::GetSystemPrincipal(),
                        nullptr, // aTriggeringPrincipal
                        nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
                        nsIContentPolicy::TYPE_OTHER,
                        getter_AddRefs(mChannel));
  NS_ENSURE_SUCCESS(rv, rv);

  nsCOMPtr<nsILoadInfo> loadInfo = mChannel->GetLoadInfo();
  if (loadInfo) {
    loadInfo->SetOriginAttributes(
      mozilla::NeckoOriginAttributes(NECKO_SAFEBROWSING_APP_ID, false));
  }

  nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(mChannel, &rv));
  NS_ENSURE_SUCCESS(rv, rv);
  mozilla::Unused << httpChannel;

  // Upload the protobuf to the application reputation service.
  nsCOMPtr<nsIUploadChannel2> uploadChannel = do_QueryInterface(mChannel, &rv);
  NS_ENSURE_SUCCESS(rv, rv);

  rv = uploadChannel->ExplicitSetUploadStream(sstream,
    NS_LITERAL_CSTRING("application/octet-stream"), serialized.size(),
    NS_LITERAL_CSTRING("POST"), false);
  NS_ENSURE_SUCCESS(rv, rv);

  // Set the Safebrowsing cookie jar, so that the regular Google cookie is not
  // sent with this request. See bug 897516.
  DocShellOriginAttributes attrs;
  attrs.mAppId = NECKO_SAFEBROWSING_APP_ID;
  nsCOMPtr<nsIInterfaceRequestor> loadContext = new mozilla::LoadContext(attrs);
  rv = mChannel->SetNotificationCallbacks(loadContext);
  NS_ENSURE_SUCCESS(rv, rv);

  uint32_t timeoutMs = Preferences::GetUint(PREF_SB_DOWNLOADS_REMOTE_TIMEOUT, 10000);
  mTimeoutTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
  mTimeoutTimer->InitWithCallback(this, timeoutMs, nsITimer::TYPE_ONE_SHOT);

  rv = mChannel->AsyncOpen2(this);
  NS_ENSURE_SUCCESS(rv, rv);

  return NS_OK;
}