Commit c7142ef9 authored by Milica Selakovic's avatar Milica Selakovic Committed by Commit Bot

[PasswordScriptsFetcher] Support min Chrome version in PasswordScriptsFetcher

Scripts should not be offered on Chrome clients with version less than
min_version provided in scripts.

Bug: 1132942
Change-Id: Iec209027b6f7c2fff0f637adbb0badeef66aa9d9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2435352
Commit-Queue: Milica Selakovic <selakovic@google.com>
Reviewed-by: default avatarMaxim Kolosovskiy  <kolos@chromium.org>
Reviewed-by: default avatarIoana Pandele <ioanap@chromium.org>
Cr-Commit-Position: refs/heads/master@{#812150}
parent 90f6db1a
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "components/strings/grit/components_strings.h" #include "components/strings/grit/components_strings.h"
#include "components/sync/driver/profile_sync_service.h" #include "components/sync/driver/profile_sync_service.h"
#include "components/url_formatter/url_formatter.h" #include "components/url_formatter/url_formatter.h"
#include "components/version_info/version_info.h"
#include "ui/base/l10n/l10n_util.h" #include "ui/base/l10n/l10n_util.h"
namespace { namespace {
...@@ -228,7 +229,8 @@ CompromisedCredentialForUI PasswordCheckManager::MakeUICredential( ...@@ -228,7 +229,8 @@ CompromisedCredentialForUI PasswordCheckManager::MakeUICredential(
ui_credential.has_startable_script = ui_credential.has_startable_script =
!credential.username.empty() && ShouldFetchPasswordScripts() && !credential.username.empty() && ShouldFetchPasswordScripts() &&
password_script_fetcher_->IsScriptAvailable( password_script_fetcher_->IsScriptAvailable(
url::Origin::Create(credential.url.GetOrigin())); url::Origin::Create(credential.url.GetOrigin()),
version_info::GetVersion());
ui_credential.has_auto_change_button = ui_credential.has_auto_change_button =
ui_credential.has_startable_script && ui_credential.has_startable_script &&
base::FeatureList::IsEnabled( base::FeatureList::IsEnabled(
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "base/test/bind_test_util.h" #include "base/test/bind_test_util.h"
#include "base/test/scoped_feature_list.h" #include "base/test/scoped_feature_list.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "base/version.h"
#include "chrome/browser/password_check/android/password_check_ui_status.h" #include "chrome/browser/password_check/android/password_check_ui_status.h"
#include "chrome/browser/password_manager/bulk_leak_check_service_factory.h" #include "chrome/browser/password_manager/bulk_leak_check_service_factory.h"
#include "chrome/browser/password_manager/password_manager_test_util.h" #include "chrome/browser/password_manager/password_manager_test_util.h"
...@@ -91,10 +92,15 @@ class MockPasswordScriptsFetcher ...@@ -91,10 +92,15 @@ class MockPasswordScriptsFetcher
MOCK_METHOD(void, MOCK_METHOD(void,
FetchScriptAvailability, FetchScriptAvailability,
(const url::Origin&, base::OnceCallback<void(bool)>), (const url::Origin&,
const base::Version&,
base::OnceCallback<void(bool)>),
(override)); (override));
MOCK_METHOD(bool, IsScriptAvailable, (const url::Origin&), (const override)); MOCK_METHOD(bool,
IsScriptAvailable,
(const url::Origin&, const base::Version&),
(const override));
}; };
BulkLeakCheckService* CreateAndUseBulkLeakCheckService( BulkLeakCheckService* CreateAndUseBulkLeakCheckService(
......
...@@ -12,6 +12,10 @@ namespace url { ...@@ -12,6 +12,10 @@ namespace url {
class Origin; class Origin;
} }
namespace base {
class Version;
}
namespace password_manager { namespace password_manager {
// Abstract interface to fetch the list of password scripts. // Abstract interface to fetch the list of password scripts.
...@@ -29,20 +33,23 @@ class PasswordScriptsFetcher : public KeyedService { ...@@ -29,20 +33,23 @@ class PasswordScriptsFetcher : public KeyedService {
// another. // another.
virtual void RefreshScriptsIfNecessary( virtual void RefreshScriptsIfNecessary(
base::OnceClosure fetch_finished_callback) = 0; base::OnceClosure fetch_finished_callback) = 0;
// Returns whether there is a password change script for |origin| via // Returns whether there is a password change script for |origin| and
// |callback|. If the cache was never set or is stale, it triggers a re-fetch. // Chrome's |version| via |callback|. If the cache was never set or is stale,
// In case of a network error, the verdict will default to no script being // it triggers a re-fetch. In case of a network error, the verdict will
// available. // default to no script being available.
virtual void FetchScriptAvailability(const url::Origin& origin, virtual void FetchScriptAvailability(const url::Origin& origin,
const base::Version& version,
ResponseCallback callback) = 0; ResponseCallback callback) = 0;
// Immediately returns whether there is a password change script for |origin|. // Immediately returns whether there is a password change script for |origin|
// The method does NOT trigger any network requests if the cache is not ready // and Chrome's |version|. The method does NOT trigger any network requests if
// or stale but reads the current state of the cache. In case of a network // the cache is not ready or stale but reads the current state of the cache.
// error while fetching the scripts, the result will always be false. // In case of a network error while fetching the scripts, the result will
// always be false.
// TODO(crbug.com/1086114): It is better to deprecate this method and always // TODO(crbug.com/1086114): It is better to deprecate this method and always
// use |FetchScriptAvailability| instead because |IsScriptAvailable| may // use |FetchScriptAvailability| instead because |IsScriptAvailable| may
// return stale data. // return stale data.
virtual bool IsScriptAvailable(const url::Origin& origin) const = 0; virtual bool IsScriptAvailable(const url::Origin& origin,
const base::Version& version) const = 0;
}; };
} // namespace password_manager } // namespace password_manager
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "base/metrics/field_trial_params.h" #include "base/metrics/field_trial_params.h"
#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_functions.h"
#include "base/no_destructor.h" #include "base/no_destructor.h"
#include "base/version.h"
#include "components/password_manager/core/common/password_manager_features.h" #include "components/password_manager/core/common/password_manager_features.h"
#include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/network/public/cpp/shared_url_loader_factory.h"
#include "url/gurl.h" #include "url/gurl.h"
...@@ -25,14 +26,15 @@ constexpr int kMaxDownloadSizeInBytes = 10 * 1024; ...@@ -25,14 +26,15 @@ constexpr int kMaxDownloadSizeInBytes = 10 * 1024;
using ParsingResult = using ParsingResult =
password_manager::PasswordScriptsFetcherImpl::ParsingResult; password_manager::PasswordScriptsFetcherImpl::ParsingResult;
// Extracts the domains for which password changes are supported and adds them // Extracts the domains and min Chrome's version for which password changes are
// to |supported_domains|. // supported and adds them to |supported_domains|.
// |script_config| is the dictionary passed for a domain, representig the // |script_config| is the dictionary passed for a domain, representig the
// configuration data of one password change script. // configuration data of one password change script. For example, the fetched
// For example, the fetched JSON might look like this: // JSON might look like this:
// { // {
// 'example.com': { // 'example.com': {
// 'domains': [ 'https://www.example.com', 'https://m.example.com' ] // 'domains': [ 'https://www.example.com', 'https://m.example.com' ],
// 'min_version': '86'
// } // }
// } // }
// In this case |script_config| would represent the dictionary value // In this case |script_config| would represent the dictionary value
...@@ -41,9 +43,9 @@ using ParsingResult = ...@@ -41,9 +43,9 @@ using ParsingResult =
// The function tries to be lax about errors and prefers to skip them // The function tries to be lax about errors and prefers to skip them
// with warnings rather than bail the parsing. This is for forward // with warnings rather than bail the parsing. This is for forward
// compatibility. // compatibility.
base::flat_set<ParsingResult> ExtractPasswordDomains( base::flat_set<ParsingResult> ParseDomainSpecificParamaters(
const base::Value& script_config, const base::Value& script_config,
base::flat_set<url::Origin>& supported_domains) { base::flat_map<url::Origin, base::Version>& supported_domains) {
if (!script_config.is_dict()) if (!script_config.is_dict())
return {ParsingResult::kInvalidJson}; return {ParsingResult::kInvalidJson};
...@@ -53,6 +55,21 @@ base::flat_set<ParsingResult> ExtractPasswordDomains( ...@@ -53,6 +55,21 @@ base::flat_set<ParsingResult> ExtractPasswordDomains(
return {ParsingResult::kInvalidJson}; return {ParsingResult::kInvalidJson};
base::flat_set<ParsingResult> warnings; base::flat_set<ParsingResult> warnings;
const std::string* min_version = script_config.FindStringKey("min_version");
base::Version version;
if (!min_version) {
warnings.insert(ParsingResult::kInvalidJson);
// TODO(crbug.com/1132942): remove this when server side change is in place
// and return error.
version = base::Version("0");
} else {
version = base::Version(*min_version);
if (!version.IsValid()) {
return {ParsingResult::kInvalidJson};
}
}
for (const base::Value& domain : supported_domains_list->GetList()) { for (const base::Value& domain : supported_domains_list->GetList()) {
if (!domain.is_string()) { if (!domain.is_string()) {
warnings.insert(ParsingResult::kInvalidJson); warnings.insert(ParsingResult::kInvalidJson);
...@@ -64,7 +81,7 @@ base::flat_set<ParsingResult> ExtractPasswordDomains( ...@@ -64,7 +81,7 @@ base::flat_set<ParsingResult> ExtractPasswordDomains(
warnings.insert(ParsingResult::kInvalidUrl); warnings.insert(ParsingResult::kInvalidUrl);
continue; continue;
} }
supported_domains.insert(url::Origin::Create(url)); supported_domains.insert(std::make_pair(url::Origin::Create(url), version));
} }
return warnings; return warnings;
...@@ -128,21 +145,26 @@ void PasswordScriptsFetcherImpl::RefreshScriptsIfNecessary( ...@@ -128,21 +145,26 @@ void PasswordScriptsFetcherImpl::RefreshScriptsIfNecessary(
void PasswordScriptsFetcherImpl::FetchScriptAvailability( void PasswordScriptsFetcherImpl::FetchScriptAvailability(
const url::Origin& origin, const url::Origin& origin,
const base::Version& version,
ResponseCallback callback) { ResponseCallback callback) {
if (IsCacheStale()) { if (IsCacheStale()) {
pending_callbacks_.emplace_back( pending_callbacks_.emplace_back(
std::make_pair(origin, std::move(callback))); std::make_pair(std::make_pair(origin, version), std::move(callback)));
StartFetch(); StartFetch();
return; return;
} }
RunResponseCallback(origin, std::move(callback)); RunResponseCallback(origin, version, std::move(callback));
} }
bool PasswordScriptsFetcherImpl::IsScriptAvailable( bool PasswordScriptsFetcherImpl::IsScriptAvailable(
const url::Origin& origin) const { const url::Origin& origin,
return password_change_domains_.find(origin) != const base::Version& version) const {
password_change_domains_.end(); const auto& it = password_change_domains_.find(origin);
if (it == password_change_domains_.end()) {
return false;
}
return version >= it->second;
} }
void PasswordScriptsFetcherImpl::StartFetch() { void PasswordScriptsFetcherImpl::StartFetch() {
...@@ -213,7 +235,9 @@ void PasswordScriptsFetcherImpl::OnFetchComplete( ...@@ -213,7 +235,9 @@ void PasswordScriptsFetcherImpl::OnFetchComplete(
for (auto& callback : std::exchange(fetch_finished_callbacks_, {})) for (auto& callback : std::exchange(fetch_finished_callbacks_, {}))
std::move(callback).Run(); std::move(callback).Run();
for (auto& callback : std::exchange(pending_callbacks_, {})) for (auto& callback : std::exchange(pending_callbacks_, {}))
RunResponseCallback(std::move(callback.first), std::move(callback.second)); RunResponseCallback(std::move(callback.first.first),
std::move(callback.first.second),
std::move(callback.second));
} }
base::flat_set<ParsingResult> PasswordScriptsFetcherImpl::ParseResponse( base::flat_set<ParsingResult> PasswordScriptsFetcherImpl::ParseResponse(
...@@ -235,10 +259,12 @@ base::flat_set<ParsingResult> PasswordScriptsFetcherImpl::ParseResponse( ...@@ -235,10 +259,12 @@ base::flat_set<ParsingResult> PasswordScriptsFetcherImpl::ParseResponse(
base::flat_set<ParsingResult> warnings; base::flat_set<ParsingResult> warnings;
for (const auto& script_it : data.value->DictItems()) { for (const auto& script_it : data.value->DictItems()) {
// |script_it.first| is an identifier that we don't care about. // |script_it.first| is an identifier (normally, a domain name, e.g.
// |script_it.second| provides domain-sepcific parameters. // example.com) that we don't care about.
// |script_it.second| provides domain-specific parameters.
base::flat_set<ParsingResult> warnings_for_script = base::flat_set<ParsingResult> warnings_for_script =
ExtractPasswordDomains(script_it.second, password_change_domains_); ParseDomainSpecificParamaters(script_it.second,
password_change_domains_);
warnings.insert(warnings_for_script.begin(), warnings_for_script.end()); warnings.insert(warnings_for_script.begin(), warnings_for_script.end());
} }
return warnings; return warnings;
...@@ -253,11 +279,11 @@ bool PasswordScriptsFetcherImpl::IsCacheStale() const { ...@@ -253,11 +279,11 @@ bool PasswordScriptsFetcherImpl::IsCacheStale() const {
void PasswordScriptsFetcherImpl::RunResponseCallback( void PasswordScriptsFetcherImpl::RunResponseCallback(
url::Origin origin, url::Origin origin,
base::Version version,
ResponseCallback callback) { ResponseCallback callback) {
DCHECK(!url_loader_); // Fetching is not running. DCHECK(!url_loader_); // Fetching is not running.
DCHECK(!IsCacheStale()); // Cache is ready. DCHECK(!IsCacheStale()); // Cache is ready.
bool has_script = bool has_script = IsScriptAvailable(origin, version);
password_change_domains_.find(origin) != password_change_domains_.end();
std::move(callback).Run(has_script); std::move(callback).Run(has_script);
} }
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <vector> #include <vector>
#include "base/callback_forward.h" #include "base/callback_forward.h"
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h" #include "base/containers/flat_set.h"
#include "base/memory/scoped_refptr.h" #include "base/memory/scoped_refptr.h"
#include "base/time/time.h" #include "base/time/time.h"
...@@ -25,6 +26,10 @@ namespace network { ...@@ -25,6 +26,10 @@ namespace network {
class SharedURLLoaderFactory; class SharedURLLoaderFactory;
} }
namespace base {
class Version;
}
namespace password_manager { namespace password_manager {
extern const char kDefaultChangePasswordScriptsListUrl[]; extern const char kDefaultChangePasswordScriptsListUrl[];
...@@ -73,8 +78,10 @@ class PasswordScriptsFetcherImpl ...@@ -73,8 +78,10 @@ class PasswordScriptsFetcherImpl
void RefreshScriptsIfNecessary( void RefreshScriptsIfNecessary(
base::OnceClosure fetch_finished_callback) override; base::OnceClosure fetch_finished_callback) override;
void FetchScriptAvailability(const url::Origin& origin, void FetchScriptAvailability(const url::Origin& origin,
const base::Version& version,
ResponseCallback callback) override; ResponseCallback callback) override;
bool IsScriptAvailable(const url::Origin& origin) const override; bool IsScriptAvailable(const url::Origin& origin,
const base::Version& version) const override;
#if defined(UNIT_TEST) #if defined(UNIT_TEST)
void make_cache_stale_for_testing() { void make_cache_stale_for_testing() {
...@@ -99,19 +106,23 @@ class PasswordScriptsFetcherImpl ...@@ -99,19 +106,23 @@ class PasswordScriptsFetcherImpl
// Returns whether a re-fetch is needed. // Returns whether a re-fetch is needed.
bool IsCacheStale() const; bool IsCacheStale() const;
// Runs |callback| immediately with the script availability for |origin|. // Runs |callback| immediately with the script availability for |origin|.
void RunResponseCallback(url::Origin origin, ResponseCallback callback); void RunResponseCallback(url::Origin origin,
base::Version version,
ResponseCallback callback);
// URL to fetch a list of scripts from. // URL to fetch a list of scripts from.
const std::string scripts_list_url_; const std::string scripts_list_url_;
// Parsed set of domains from gstatic. // Parsed set of domains from gstatic.
base::flat_set<url::Origin> password_change_domains_; base::flat_map<url::Origin, base::Version> password_change_domains_;
// Timestamp of the last finished request. // Timestamp of the last finished request.
base::TimeTicks last_fetch_timestamp_; base::TimeTicks last_fetch_timestamp_;
// Stores the callbacks that are waiting for the request to finish. // Stores the callbacks that are waiting for the request to finish.
std::vector<base::OnceClosure> fetch_finished_callbacks_; std::vector<base::OnceClosure> fetch_finished_callbacks_;
// Stores the per-origin callbacks that are waiting for the request to finish. // Stores the per-origin callbacks that are waiting for the request to finish.
std::vector<std::pair<url::Origin, ResponseCallback>> pending_callbacks_; std::vector<
std::pair<std::pair<url::Origin, base::Version>, ResponseCallback>>
pending_callbacks_;
// URL loader object for the gstatic request. If |url_loader_| is not null, a // URL loader object for the gstatic request. If |url_loader_| is not null, a
// request is currently in flight. // request is currently in flight.
std::unique_ptr<network::SimpleURLLoader> url_loader_; std::unique_ptr<network::SimpleURLLoader> url_loader_;
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "base/test/metrics/histogram_tester.h" #include "base/test/metrics/histogram_tester.h"
#include "base/test/task_environment.h" #include "base/test/task_environment.h"
#include "base/version.h"
#include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
#include "services/network/test/test_url_loader_factory.h" #include "services/network/test/test_url_loader_factory.h"
...@@ -21,6 +22,7 @@ constexpr char kOriginWithScript1[] = "https://example.com"; ...@@ -21,6 +22,7 @@ constexpr char kOriginWithScript1[] = "https://example.com";
constexpr char kOriginWithScript2[] = "https://mobile.example.com"; constexpr char kOriginWithScript2[] = "https://mobile.example.com";
constexpr char kOriginWithScript3[] = "https://test.com"; constexpr char kOriginWithScript3[] = "https://test.com";
constexpr char kOriginWithoutScript[] = "https://no-script.com"; constexpr char kOriginWithoutScript[] = "https://no-script.com";
constexpr char kVersion[] = "87";
constexpr char kTestResponseContent[] = constexpr char kTestResponseContent[] =
R"json( R"json(
...@@ -29,10 +31,12 @@ constexpr char kTestResponseContent[] = ...@@ -29,10 +31,12 @@ constexpr char kTestResponseContent[] =
"domains": [ "domains": [
"https://example.com", "https://example.com",
"https://mobile.example.com" "https://mobile.example.com"
] ],
"min_version": "86"
}, },
"test.com": { "test.com": {
"domains": ["https://test.com"] "domains": ["https://test.com"],
"min_version": "87"
} }
} }
)json"; )json";
...@@ -52,6 +56,11 @@ url::Origin GetOriginWithScript3() { ...@@ -52,6 +56,11 @@ url::Origin GetOriginWithScript3() {
url::Origin GetOriginWithoutScript() { url::Origin GetOriginWithoutScript() {
return url::Origin::Create(GURL(kOriginWithoutScript)); return url::Origin::Create(GURL(kOriginWithoutScript));
} }
base::Version GetVersion() {
return base::Version(kVersion);
}
} // namespace } // namespace
namespace password_manager { namespace password_manager {
...@@ -109,7 +118,8 @@ class PasswordScriptsFetcherImplTest : public ::testing::Test { ...@@ -109,7 +118,8 @@ class PasswordScriptsFetcherImplTest : public ::testing::Test {
private: private:
void RequestSingleScriptAvailability(const url::Origin& origin) { void RequestSingleScriptAvailability(const url::Origin& origin) {
fetcher_->FetchScriptAvailability(origin, GenerateResponseCallback(origin)); fetcher_->FetchScriptAvailability(origin, GetVersion(),
GenerateResponseCallback(origin));
} }
void RecordResponse(url::Origin origin, bool has_script) { void RecordResponse(url::Origin origin, bool has_script) {
...@@ -235,8 +245,10 @@ TEST_F(PasswordScriptsFetcherImplTest, InvalidResponseBody) { ...@@ -235,8 +245,10 @@ TEST_F(PasswordScriptsFetcherImplTest, InvalidResponseBody) {
PasswordScriptsFetcherImpl::ParsingResult::kInvalidJson}, PasswordScriptsFetcherImpl::ParsingResult::kInvalidJson},
{R"({"no-domains-attribute.com" : {}})", {R"({"no-domains-attribute.com" : {}})",
PasswordScriptsFetcherImpl::ParsingResult::kInvalidJson}, PasswordScriptsFetcherImpl::ParsingResult::kInvalidJson},
{R"({"not-url.com" : {"domains": ["scheme-forgotten.com"]}})", {R"({"not-url.com" : {"domains": ["scheme-forgotten.com"], "min_version": "2"}})",
PasswordScriptsFetcherImpl::ParsingResult::kInvalidUrl}}; PasswordScriptsFetcherImpl::ParsingResult::kInvalidUrl},
{R"({"not-url.com" : {"domains": ["https://no-min-version.com"]}})",
PasswordScriptsFetcherImpl::ParsingResult::kInvalidJson}};
for (const auto& test_case : kTestCases) { for (const auto& test_case : kTestCases) {
SCOPED_TRACE(testing::Message() << "test_case=" << test_case.response); SCOPED_TRACE(testing::Message() << "test_case=" << test_case.response);
base::HistogramTester histogram_tester; base::HistogramTester histogram_tester;
...@@ -283,10 +295,14 @@ TEST_F(PasswordScriptsFetcherImplTest, ServerError) { ...@@ -283,10 +295,14 @@ TEST_F(PasswordScriptsFetcherImplTest, ServerError) {
TEST_F(PasswordScriptsFetcherImplTest, IsScriptAvailable) { TEST_F(PasswordScriptsFetcherImplTest, IsScriptAvailable) {
// |IsScriptAvailable| does not trigger any network requests and returns the // |IsScriptAvailable| does not trigger any network requests and returns the
// default value (false). // default value (false).
EXPECT_FALSE(fetcher()->IsScriptAvailable(GetOriginWithScript1())); EXPECT_FALSE(
EXPECT_FALSE(fetcher()->IsScriptAvailable(GetOriginWithScript2())); fetcher()->IsScriptAvailable(GetOriginWithScript1(), GetVersion()));
EXPECT_FALSE(fetcher()->IsScriptAvailable(GetOriginWithScript3())); EXPECT_FALSE(
EXPECT_FALSE(fetcher()->IsScriptAvailable(GetOriginWithoutScript())); fetcher()->IsScriptAvailable(GetOriginWithScript2(), GetVersion()));
EXPECT_FALSE(
fetcher()->IsScriptAvailable(GetOriginWithScript3(), GetVersion()));
EXPECT_FALSE(
fetcher()->IsScriptAvailable(GetOriginWithoutScript(), GetVersion()));
EXPECT_EQ(0, GetNumberOfPendingRequests()); EXPECT_EQ(0, GetNumberOfPendingRequests());
StartBulkCheck(); StartBulkCheck();
...@@ -298,17 +314,25 @@ TEST_F(PasswordScriptsFetcherImplTest, IsScriptAvailable) { ...@@ -298,17 +314,25 @@ TEST_F(PasswordScriptsFetcherImplTest, IsScriptAvailable) {
SimulateResponse(); SimulateResponse();
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
// Cache is ready. // Cache is ready.
EXPECT_TRUE(fetcher()->IsScriptAvailable(GetOriginWithScript1())); EXPECT_TRUE(
EXPECT_TRUE(fetcher()->IsScriptAvailable(GetOriginWithScript2())); fetcher()->IsScriptAvailable(GetOriginWithScript1(), GetVersion()));
EXPECT_TRUE(fetcher()->IsScriptAvailable(GetOriginWithScript3())); EXPECT_TRUE(
EXPECT_FALSE(fetcher()->IsScriptAvailable(GetOriginWithoutScript())); fetcher()->IsScriptAvailable(GetOriginWithScript2(), GetVersion()));
EXPECT_TRUE(
fetcher()->IsScriptAvailable(GetOriginWithScript3(), GetVersion()));
EXPECT_FALSE(
fetcher()->IsScriptAvailable(GetOriginWithoutScript(), GetVersion()));
// |IsScriptAvailable| does not trigger refetching and returns stale values. // |IsScriptAvailable| does not trigger refetching and returns stale values.
fetcher()->make_cache_stale_for_testing(); fetcher()->make_cache_stale_for_testing();
EXPECT_TRUE(fetcher()->IsScriptAvailable(GetOriginWithScript1())); EXPECT_TRUE(
EXPECT_TRUE(fetcher()->IsScriptAvailable(GetOriginWithScript2())); fetcher()->IsScriptAvailable(GetOriginWithScript1(), GetVersion()));
EXPECT_TRUE(fetcher()->IsScriptAvailable(GetOriginWithScript3())); EXPECT_TRUE(
EXPECT_FALSE(fetcher()->IsScriptAvailable(GetOriginWithoutScript())); fetcher()->IsScriptAvailable(GetOriginWithScript2(), GetVersion()));
EXPECT_TRUE(
fetcher()->IsScriptAvailable(GetOriginWithScript3(), GetVersion()));
EXPECT_FALSE(
fetcher()->IsScriptAvailable(GetOriginWithoutScript(), GetVersion()));
EXPECT_EQ(0, GetNumberOfPendingRequests()); EXPECT_EQ(0, GetNumberOfPendingRequests());
} }
...@@ -328,7 +352,8 @@ TEST_F(PasswordScriptsFetcherImplTest, AnotherScriptsListUrl) { ...@@ -328,7 +352,8 @@ TEST_F(PasswordScriptsFetcherImplTest, AnotherScriptsListUrl) {
R"json( R"json(
{ {
"experiment.com": { "experiment.com": {
"domains": ["https://experiment.com"] "domains": ["https://experiment.com"],
"min_version" : "86"
} }
} }
)json"; )json";
...@@ -339,8 +364,21 @@ TEST_F(PasswordScriptsFetcherImplTest, AnotherScriptsListUrl) { ...@@ -339,8 +364,21 @@ TEST_F(PasswordScriptsFetcherImplTest, AnotherScriptsListUrl) {
// Use |IsScriptAvailable(origin)| instead of |FetchScriptAvailability(origin, // Use |IsScriptAvailable(origin)| instead of |FetchScriptAvailability(origin,
// callback)| to simplify the test. // callback)| to simplify the test.
EXPECT_TRUE(fetcher.IsScriptAvailable( EXPECT_TRUE(fetcher.IsScriptAvailable(
url::Origin::Create(GURL(kExperimentalDomain)))); url::Origin::Create(GURL(kExperimentalDomain)), GetVersion()));
EXPECT_FALSE(fetcher.IsScriptAvailable(GetOriginWithScript3())); EXPECT_FALSE(fetcher.IsScriptAvailable(GetOriginWithScript3(), GetVersion()));
}
TEST_F(PasswordScriptsFetcherImplTest, DifferentVersions) {
StartBulkCheck();
EXPECT_EQ(1, GetNumberOfPendingRequests());
SimulateResponse();
base::RunLoop().RunUntilIdle();
const char kOlderVersion[] = "86";
EXPECT_FALSE(fetcher()->IsScriptAvailable(GetOriginWithScript3(),
base::Version(kOlderVersion)));
EXPECT_TRUE(
fetcher()->IsScriptAvailable(GetOriginWithScript3(), GetVersion()));
} }
} // namespace password_manager } // namespace password_manager
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment