| // Copyright 2020 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/metrics/entropy_state.h" |
| |
| #include <string> |
| |
| #include "base/command_line.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/string_util.h" |
| #include "components/metrics/metrics_pref_names.h" |
| #include "components/metrics/metrics_service.h" |
| #include "components/metrics/metrics_switches.h" |
| #include "components/prefs/testing_pref_service.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace metrics { |
| |
| class EntropyStateTest : public testing::Test { |
| public: |
| EntropyStateTest() { MetricsService::RegisterPrefs(prefs_.registry()); } |
| |
| EntropyStateTest(const EntropyStateTest&) = delete; |
| EntropyStateTest& operator=(const EntropyStateTest&) = delete; |
| |
| protected: |
| TestingPrefServiceSimple prefs_; |
| }; |
| |
| TEST_F(EntropyStateTest, LowEntropySourceNotReset) { |
| EntropyState entropy_state(&prefs_); |
| // Get the low entropy source once, to initialize it. |
| entropy_state.GetLowEntropySource(); |
| |
| // Now, set it to 0 and ensure it doesn't get reset. |
| entropy_state.low_entropy_source_ = 0; |
| EXPECT_EQ(0, entropy_state.GetLowEntropySource()); |
| // Call it another time, just to make sure. |
| EXPECT_EQ(0, entropy_state.GetLowEntropySource()); |
| } |
| |
| TEST_F(EntropyStateTest, PseudoLowEntropySourceNotReset) { |
| EntropyState entropy_state(&prefs_); |
| // Get the pseudo low entropy source once, to initialize it. |
| entropy_state.GetPseudoLowEntropySource(); |
| |
| // Now, set it to 0 and ensure it doesn't get reset. |
| entropy_state.pseudo_low_entropy_source_ = 0; |
| EXPECT_EQ(0, entropy_state.GetPseudoLowEntropySource()); |
| // Call it another time, just to make sure. |
| EXPECT_EQ(0, entropy_state.GetPseudoLowEntropySource()); |
| } |
| |
| TEST_F(EntropyStateTest, HaveNoLowEntropySource) { |
| EntropyState entropy_state(&prefs_); |
| // If we have none of the new, old, or pseudo low entropy sources stored in |
| // prefs, then the new source should be created... |
| int new_low_source = entropy_state.GetLowEntropySource(); |
| EXPECT_TRUE(EntropyState::IsValidLowEntropySource(new_low_source)) |
| << new_low_source; |
| int pseudo_low_source = entropy_state.GetPseudoLowEntropySource(); |
| EXPECT_TRUE(EntropyState::IsValidLowEntropySource(pseudo_low_source)) |
| << pseudo_low_source; |
| // ...but the old source should not... |
| EXPECT_EQ(EntropyState::kLowEntropySourceNotSet, |
| entropy_state.GetOldLowEntropySource()); |
| // ...and the high entropy source should include the *new* low entropy source. |
| std::string high_source = entropy_state.GetHighEntropySource( |
| "AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEF"); |
| EXPECT_TRUE(base::EndsWith(high_source, base::NumberToString(new_low_source), |
| base::CompareCase::SENSITIVE)) |
| << high_source; |
| } |
| |
| TEST_F(EntropyStateTest, HaveOnlyNewLowEntropySource) { |
| // If we have the new low entropy sources stored in prefs, but not the old |
| // one... |
| const int new_low_source = 1234; |
| prefs_.SetInteger(prefs::kMetricsLowEntropySource, new_low_source); |
| |
| EntropyState entropy_state(&prefs_); |
| // ...then the new source should be loaded... |
| EXPECT_EQ(new_low_source, entropy_state.GetLowEntropySource()); |
| // ...but the old source should not be created... |
| EXPECT_EQ(EntropyState::kLowEntropySourceNotSet, |
| entropy_state.GetOldLowEntropySource()); |
| // ...and the high entropy source should include the *new* low entropy source. |
| std::string high_source = entropy_state.GetHighEntropySource( |
| "AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEF"); |
| EXPECT_TRUE(base::EndsWith(high_source, base::NumberToString(new_low_source), |
| base::CompareCase::SENSITIVE)) |
| << high_source; |
| } |
| |
| TEST_F(EntropyStateTest, HaveOnlyOldLowEntropySource) { |
| // If we have the old low entropy sources stored in prefs, but not the new |
| // one... |
| const int old_low_source = 5678; |
| prefs_.SetInteger(prefs::kMetricsOldLowEntropySource, old_low_source); |
| |
| // ...then the new source should be created... |
| EntropyState entropy_state(&prefs_); |
| |
| int new_low_source = entropy_state.GetLowEntropySource(); |
| EXPECT_TRUE(EntropyState::IsValidLowEntropySource(new_low_source)) |
| << new_low_source; |
| // ...and the old source should be loaded... |
| EXPECT_EQ(old_low_source, entropy_state.GetOldLowEntropySource()); |
| // ...and the high entropy source should include the *old* low entropy source. |
| std::string high_source = entropy_state.GetHighEntropySource( |
| "AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEF"); |
| EXPECT_TRUE(base::EndsWith(high_source, base::NumberToString(old_low_source), |
| base::CompareCase::SENSITIVE)) |
| << high_source; |
| } |
| |
| TEST_F(EntropyStateTest, HaveAllLowEntropySources) { |
| // If we have all three of new, old, and pseudo low entropy sources in |
| // prefs... |
| const int new_low_source = 1234; |
| const int old_low_source = 5678; |
| const int pseudo_low_source = 4321; |
| prefs_.SetInteger(prefs::kMetricsLowEntropySource, new_low_source); |
| prefs_.SetInteger(prefs::kMetricsOldLowEntropySource, old_low_source); |
| prefs_.SetInteger(prefs::kMetricsPseudoLowEntropySource, pseudo_low_source); |
| |
| // ...then all three should be loaded... |
| EntropyState entropy_state(&prefs_); |
| |
| EXPECT_EQ(new_low_source, entropy_state.GetLowEntropySource()); |
| EXPECT_EQ(old_low_source, entropy_state.GetOldLowEntropySource()); |
| EXPECT_EQ(pseudo_low_source, entropy_state.GetPseudoLowEntropySource()); |
| // ...and the high entropy source should include the *old* low entropy source. |
| std::string high_source = entropy_state.GetHighEntropySource( |
| "AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEF"); |
| EXPECT_TRUE(base::EndsWith(high_source, base::NumberToString(old_low_source), |
| base::CompareCase::SENSITIVE)) |
| << high_source; |
| } |
| |
| TEST_F(EntropyStateTest, CorruptNewLowEntropySources) { |
| EntropyState entropy_state(&prefs_); |
| const int corrupt_sources[] = {-12345, -1, 8000, 12345}; |
| for (int corrupt_source : corrupt_sources) { |
| // If the new low entropy source has been corrupted... |
| EXPECT_FALSE(EntropyState::IsValidLowEntropySource(corrupt_source)) |
| << corrupt_source; |
| prefs_.SetInteger(prefs::kMetricsLowEntropySource, corrupt_source); |
| // ...then a new source should be created. |
| int loaded_source = entropy_state.GetLowEntropySource(); |
| EXPECT_TRUE(EntropyState::IsValidLowEntropySource(loaded_source)) |
| << loaded_source; |
| } |
| } |
| |
| TEST_F(EntropyStateTest, CorruptOldLowEntropySources) { |
| EntropyState entropy_state(&prefs_); |
| const int corrupt_sources[] = {-12345, -1, 8000, 12345}; |
| for (int corrupt_source : corrupt_sources) { |
| // If the old low entropy source has been corrupted... |
| EXPECT_FALSE(EntropyState::IsValidLowEntropySource(corrupt_source)) |
| << corrupt_source; |
| prefs_.SetInteger(prefs::kMetricsOldLowEntropySource, corrupt_source); |
| // ...then it should be ignored. |
| EXPECT_EQ(EntropyState::kLowEntropySourceNotSet, |
| entropy_state.GetOldLowEntropySource()); |
| } |
| } |
| |
| #if BUILDFLAG(IS_CHROMEOS_LACROS) |
| TEST_F(EntropyStateTest, ClearPrefs) { |
| // On Lacros we expect that there will be no clearing of prefs. |
| prefs_.SetInteger(prefs::kMetricsLowEntropySource, 1234); |
| prefs_.SetInteger(prefs::kMetricsOldLowEntropySource, 5678); |
| prefs_.SetInteger(prefs::kMetricsPseudoLowEntropySource, 4321); |
| prefs_.SetString(prefs::kMetricsLimitedEntropyRandomizationSource, |
| "00000000000000000000000000000001"); |
| |
| EntropyState::ClearPrefs(&prefs_); |
| |
| EXPECT_TRUE(prefs_.HasPrefPath(prefs::kMetricsLowEntropySource)); |
| EXPECT_TRUE(prefs_.HasPrefPath(prefs::kMetricsOldLowEntropySource)); |
| EXPECT_TRUE(prefs_.HasPrefPath(prefs::kMetricsPseudoLowEntropySource)); |
| EXPECT_TRUE( |
| prefs_.HasPrefPath(prefs::kMetricsLimitedEntropyRandomizationSource)); |
| } |
| |
| TEST_F(EntropyStateTest, SetExternalPrefs) { |
| prefs_.ClearPref(prefs::kMetricsLowEntropySource); |
| prefs_.ClearPref(prefs::kMetricsOldLowEntropySource); |
| prefs_.ClearPref(prefs::kMetricsPseudoLowEntropySource); |
| prefs_.ClearPref(prefs::kMetricsLimitedEntropyRandomizationSource); |
| |
| std::string limited_entropy_randomization_source = |
| "00000000000000000000000000000001"; |
| EntropyState::SetExternalPrefs(&prefs_, 1234, 4567, 3456, |
| limited_entropy_randomization_source); |
| |
| EXPECT_EQ(prefs_.GetInteger(prefs::kMetricsLowEntropySource), 1234); |
| EXPECT_EQ(prefs_.GetInteger(prefs::kMetricsOldLowEntropySource), 4567); |
| EXPECT_EQ(prefs_.GetInteger(prefs::kMetricsPseudoLowEntropySource), 3456); |
| EXPECT_EQ(prefs_.GetString(prefs::kMetricsLimitedEntropyRandomizationSource), |
| limited_entropy_randomization_source); |
| } |
| |
| TEST_F(EntropyStateTest, SetEmptyStringToLimitedEntropyRandomizationSource) { |
| prefs_.ClearPref(prefs::kMetricsLimitedEntropyRandomizationSource); |
| |
| EntropyState::SetExternalPrefs(&prefs_, 1234, 4567, 3456, std::string_view()); |
| |
| EXPECT_FALSE( |
| prefs_.HasPrefPath(prefs::kMetricsLimitedEntropyRandomizationSource)); |
| } |
| |
| #else |
| |
| TEST_F(EntropyStateTest, ClearPrefs) { |
| prefs_.SetInteger(prefs::kMetricsLowEntropySource, 1234); |
| prefs_.SetInteger(prefs::kMetricsOldLowEntropySource, 5678); |
| prefs_.SetInteger(prefs::kMetricsPseudoLowEntropySource, 4321); |
| prefs_.SetString(prefs::kMetricsLimitedEntropyRandomizationSource, |
| "00000000000000000000000000000001"); |
| |
| EntropyState::ClearPrefs(&prefs_); |
| |
| EXPECT_FALSE(prefs_.HasPrefPath(prefs::kMetricsLowEntropySource)); |
| EXPECT_FALSE(prefs_.HasPrefPath(prefs::kMetricsOldLowEntropySource)); |
| EXPECT_FALSE(prefs_.HasPrefPath(prefs::kMetricsPseudoLowEntropySource)); |
| EXPECT_FALSE( |
| prefs_.HasPrefPath(prefs::kMetricsLimitedEntropyRandomizationSource)); |
| } |
| #endif |
| |
| TEST_F(EntropyStateTest, ClearingPrefWillNotResetValuesDuringSession) { |
| // Setting test values in prefs; |
| prefs_.SetInteger(prefs::kMetricsLowEntropySource, 1234); |
| prefs_.SetInteger(prefs::kMetricsOldLowEntropySource, 5678); |
| prefs_.SetInteger(prefs::kMetricsPseudoLowEntropySource, 4321); |
| prefs_.SetString(prefs::kMetricsLimitedEntropyRandomizationSource, |
| "00000000000000000000000000000001"); |
| EntropyState entropy_state(&prefs_); |
| |
| // Generates all managed values. This should load the values from prefs. |
| auto low = entropy_state.GetLowEntropySource(); |
| auto old_low = entropy_state.GetOldLowEntropySource(); |
| auto pseudo_low = entropy_state.GetPseudoLowEntropySource(); |
| auto high = entropy_state.GetHighEntropySource( |
| "AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEF"); |
| auto limited = entropy_state.GetLimitedEntropyRandomizationSource(); |
| |
| EntropyState::ClearPrefs(&prefs_); |
| |
| // Clearing values in prefs should not result in returning different values. |
| EXPECT_EQ(low, entropy_state.GetLowEntropySource()); |
| EXPECT_EQ(old_low, entropy_state.GetOldLowEntropySource()); |
| EXPECT_EQ(pseudo_low, entropy_state.GetPseudoLowEntropySource()); |
| EXPECT_EQ(high, entropy_state.GetHighEntropySource( |
| "AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEF")); |
| EXPECT_EQ(limited, entropy_state.GetLimitedEntropyRandomizationSource()); |
| } |
| |
| TEST_F(EntropyStateTest, |
| GenerateLimitedEntropyRandomizationSourceWhenNotAvailable) { |
| // Pref for limited entropy randomization source is unset. |
| EXPECT_FALSE( |
| prefs_.HasPrefPath(prefs::kMetricsLimitedEntropyRandomizationSource)); |
| |
| // Generate a new limited entropy randomization source. |
| EntropyState entropy_state(&prefs_); |
| entropy_state.GetLimitedEntropyRandomizationSource(); |
| |
| // There should be a generated value and it should be stored in prefs. |
| auto getter_value = entropy_state.GetLimitedEntropyRandomizationSource(); |
| auto pref_value = |
| prefs_.GetString(prefs::kMetricsLimitedEntropyRandomizationSource); |
| EXPECT_NE("", getter_value); |
| EXPECT_EQ(getter_value, pref_value); |
| } |
| |
| TEST_F(EntropyStateTest, LoadLimitedEntropyRandomizationSourceFromPref) { |
| // There is a previously generated limited entropy randomization source stored |
| // in prefs. |
| auto* test_value = "00000000000000000000000000000001"; |
| prefs_.SetString(prefs::kMetricsLimitedEntropyRandomizationSource, |
| test_value); |
| |
| // This should load the previous value from prefs. |
| EntropyState entropy_state(&prefs_); |
| entropy_state.GetLimitedEntropyRandomizationSource(); |
| |
| // Verify that the previous value was returned. |
| EXPECT_EQ(test_value, entropy_state.GetLimitedEntropyRandomizationSource()); |
| // Verify that the value stored in prefs is not altered. |
| EXPECT_EQ(test_value, |
| prefs_.GetString(prefs::kMetricsLimitedEntropyRandomizationSource)); |
| } |
| |
| TEST_F(EntropyStateTest, LimitedEntropyRandomizationSourceNotReset) { |
| EntropyState entropy_state(&prefs_); |
| |
| // Attempts to generate the limited entropy randomization source twice. |
| auto first_call_value = entropy_state.GetLimitedEntropyRandomizationSource(); |
| auto second_call_value = entropy_state.GetLimitedEntropyRandomizationSource(); |
| |
| // The generated value should not be empty. |
| EXPECT_NE("", first_call_value); |
| // The values returned from the two calls should be identical. |
| EXPECT_EQ(first_call_value, second_call_value); |
| } |
| |
| TEST_F(EntropyStateTest, ResetLimitedEntropyRandomizationSourceThroughCmdLine) { |
| // Setup a command line flag to reset the variations state. |
| base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); |
| command_line->AppendSwitch(switches::kResetVariationState); |
| // ...and store a previously generated limited entropy randomization source |
| // value in prefs. |
| auto* test_value = "00000000000000000000000000000001"; |
| prefs_.SetString(prefs::kMetricsLimitedEntropyRandomizationSource, |
| test_value); |
| |
| // Attempts to generate a limited entropy randomization source value. |
| EntropyState entropy_state(&prefs_); |
| entropy_state.GetLimitedEntropyRandomizationSource(); |
| |
| // The generated value should not be the one in prefs initially. |
| EXPECT_NE(test_value, entropy_state.GetLimitedEntropyRandomizationSource()); |
| // There should be a new value, and the new value should overwrite the one in |
| // prefs initially. |
| EXPECT_EQ(entropy_state.GetLimitedEntropyRandomizationSource(), |
| prefs_.GetString(prefs::kMetricsLimitedEntropyRandomizationSource)); |
| } |
| |
| TEST_F(EntropyStateTest, ValidLimitedEntropyRandomizationSource) { |
| const char* test_values[] = { |
| "00000000000000000000000000000001", |
| "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", |
| "0123456789ABCDEF0123456789ABCDEF", |
| }; |
| for (auto* test_value : test_values) { |
| EXPECT_TRUE( |
| EntropyState::IsValidLimitedEntropyRandomizationSource(test_value)) |
| << "Expect EntropyState::IsValidLimitedEntropyRandomizationSource(" |
| << test_value << ") to be true."; |
| } |
| } |
| |
| TEST_F(EntropyStateTest, InvalidLimitedEntropyRandomizationSource) { |
| const char* test_values[] = { |
| // The empty string is not a valid limited entropy randomization source. |
| "", |
| // A value with all zero is a not a valid `base::UnguessableToken`. |
| "00000000000000000000000000000000", |
| // Not a hex string representing 128 bits. |
| "1234", |
| // A string with valid length of 128 bits but 'X' is not a hex value. |
| "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", |
| // A invalid hex string because of the lower case letters. |
| "0123456789abcdef0123456789abcdef", |
| }; |
| for (auto* test_value : test_values) { |
| EXPECT_FALSE( |
| EntropyState::IsValidLimitedEntropyRandomizationSource(test_value)) |
| << "Expect EntropyState::IsValidLimitedEntropyRandomizationSource(" |
| << test_value << ") to be false."; |
| } |
| } |
| |
| } // namespace metrics |