1 // Copyright 2023 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/media_device_salt/media_device_salt_service.h"
7 #include "base/containers/contains.h"
8 #include "base/files/file_path.h"
9 #include "base/run_loop.h"
10 #include "base/system/system_monitor.h"
11 #include "base/test/bind.h"
12 #include "base/test/mock_devices_changed_observer.h"
13 #include "base/test/scoped_feature_list.h"
14 #include "base/test/test_future.h"
15 #include "base/time/time.h"
16 #include "components/keyed_service/content/browser_context_dependency_manager.h"
17 #include "components/media_device_salt/media_device_id_salt.h"
18 #include "components/sync_preferences/testing_pref_service_syncable.h"
19 #include "components/user_prefs/user_prefs.h"
20 #include "content/public/test/browser_task_environment.h"
21 #include "content/public/test/test_browser_context.h"
22 #include "testing/gmock/include/gmock/gmock.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24 #include "third_party/blink/public/common/storage_key/storage_key.h"
26 namespace media_device_salt {
30 using ::testing::IsEmpty;
31 using ::testing::UnorderedElementsAre;
32 using StorageKeyMatcher =
33 ::content::StoragePartition::StorageKeyMatcherFunction;
35 blink::StorageKey StorageKey1() {
36 return blink::StorageKey::CreateFromStringForTesting("https://example1.com");
39 blink::StorageKey StorageKey2() {
40 return blink::StorageKey::CreateFromStringForTesting("https://example2.com");
43 blink::StorageKey StorageKey3() {
44 return blink::StorageKey::CreateFromStringForTesting("https://example3.com");
49 class MediaDeviceSaltServiceTest : public testing::TestWithParam<bool> {
51 void SetUp() override {
52 if (UsePerStorageKeySalts()) {
53 feature_list_.InitWithFeatures(
54 {kMediaDeviceIdPartitioning, kMediaDeviceIdRandomSaltsPerStorageKey},
57 feature_list_.InitWithFeatures({kMediaDeviceIdPartitioning},
58 {kMediaDeviceIdRandomSaltsPerStorageKey});
60 BrowserContextDependencyManager::GetInstance()->MarkBrowserContextLive(
63 user_prefs::UserPrefs::Set(&browser_context_, &pref_service_);
64 ASSERT_FALSE(pref_service_.FindPreference(
65 media_device_salt::prefs::kMediaDeviceIdSalt));
67 MediaDeviceIDSalt::RegisterProfilePrefs(pref_service_.registry());
68 ASSERT_TRUE(pref_service_.FindPreference(
69 media_device_salt::prefs::kMediaDeviceIdSalt));
71 service_ = std::make_unique<MediaDeviceSaltService>(&pref_service_,
75 void TearDown() override {
76 BrowserContextDependencyManager::GetInstance()
77 ->DestroyBrowserContextServices(&browser_context_);
81 content::BrowserTaskEnvironment& task_environment() {
82 return task_environment_;
84 base::test::ScopedFeatureList& feature_list() { return feature_list_; }
85 const sync_preferences::TestingPrefServiceSyncable& pref_service() const {
88 MediaDeviceSaltService* service() const { return service_.get(); }
90 bool UsePerStorageKeySalts() const { return GetParam(); }
92 std::string GetSalt(const blink::StorageKey& storage_key) const {
93 base::test::TestFuture<const std::string&> future;
94 service_->GetSalt(storage_key, future.GetCallback());
98 void DeleteSaltUsingMatcher(const blink::StorageKey& storage_key) const {
99 base::test::TestFuture<void> future;
100 auto matcher = base::BindLambdaForTesting(
101 [&storage_key](const blink::StorageKey& candidate_key) {
102 return candidate_key == storage_key;
104 service_->DeleteSalts(base::Time::Min(), base::Time::Max(), matcher,
105 future.GetCallback());
106 CHECK(future.Wait());
109 void DeleteSalts(const std::vector<blink::StorageKey>& keys) {
110 base::test::TestFuture<void> future;
111 auto matcher = base::BindLambdaForTesting(
112 [&keys](const blink::StorageKey& candidate_key) {
113 return base::Contains(keys, candidate_key);
115 service_->DeleteSalts(base::Time::Min(), base::Time::Max(), matcher,
116 future.GetCallback());
117 CHECK(future.Wait());
120 void DeleteSaltsInTimeRange(base::Time delete_begin, base::Time delete_end) {
121 base::test::TestFuture<void> future;
122 service_->DeleteSalts(delete_begin, delete_end, StorageKeyMatcher(),
123 future.GetCallback());
124 CHECK(future.Wait());
127 void DeleteSingleSalt(const blink::StorageKey& storage_key) {
128 base::test::TestFuture<void> future;
129 service_->DeleteSalt(storage_key, future.GetCallback());
130 CHECK(future.Wait());
133 std::vector<blink::StorageKey> GetAllStorageKeys() {
134 base::test::TestFuture<std::vector<blink::StorageKey>> future;
135 service_->GetAllStorageKeys(future.GetCallback());
140 content::BrowserTaskEnvironment task_environment_;
141 base::test::ScopedFeatureList feature_list_;
142 content::TestBrowserContext browser_context_;
143 sync_preferences::TestingPrefServiceSyncable pref_service_;
144 std::unique_ptr<MediaDeviceSaltService> service_;
147 TEST_P(MediaDeviceSaltServiceTest, ResetGlobalSaltFiresDeviceChange) {
148 feature_list().Reset();
149 feature_list().InitAndDisableFeature(kMediaDeviceIdPartitioning);
150 base::SystemMonitor monitor;
151 ASSERT_EQ(base::SystemMonitor::Get(), &monitor);
152 testing::StrictMock<base::MockDevicesChangedObserver> observer;
153 monitor.AddDevicesChangedObserver(&observer);
155 EXPECT_CALL(observer, OnDevicesChanged(base::SystemMonitor::DEVTYPE_AUDIO));
156 EXPECT_CALL(observer,
157 OnDevicesChanged(base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE));
158 service()->DeleteSalts(base::Time::Min(), base::Time::Max(),
159 StorageKeyMatcher(), base::DoNothing());
160 task_environment().RunUntilIdle();
162 monitor.RemoveDevicesChangedObserver(&observer);
165 TEST_P(MediaDeviceSaltServiceTest, DeleteSingleSaltUsingMatcher) {
166 // Deletion of individual salts is not supported when using the global salt.
167 std::string salt1 = GetSalt(StorageKey1());
168 std::string salt2 = GetSalt(StorageKey2());
169 EXPECT_FALSE(salt1.empty());
170 EXPECT_EQ(salt1 != salt2, UsePerStorageKeySalts());
172 DeleteSaltUsingMatcher(StorageKey1());
173 std::string salt1b = GetSalt(StorageKey1());
174 std::string salt2b = GetSalt(StorageKey2());
175 EXPECT_FALSE(salt1b.empty());
176 EXPECT_EQ(salt1 != salt1b, UsePerStorageKeySalts());
177 EXPECT_EQ(salt2b, salt2);
179 DeleteSaltUsingMatcher(StorageKey2());
180 std::string salt1c = GetSalt(StorageKey1());
181 std::string salt2c = GetSalt(StorageKey2());
182 EXPECT_EQ(salt1c, salt1b);
183 EXPECT_EQ(salt2c != salt2b, UsePerStorageKeySalts());
184 EXPECT_EQ(salt2c != salt1c, UsePerStorageKeySalts());
187 TEST_P(MediaDeviceSaltServiceTest, DeleteMultipleSaltsUsingMatcher) {
188 // Deletion of individual salts is not supported when using the global salt.
189 std::string salt1 = GetSalt(StorageKey1());
190 std::string salt2 = GetSalt(StorageKey2());
191 std::string salt3 = GetSalt(StorageKey3());
193 DeleteSalts({StorageKey1(), StorageKey2()});
194 std::string salt1b = GetSalt(StorageKey1());
195 std::string salt2b = GetSalt(StorageKey2());
196 std::string salt3b = GetSalt(StorageKey3());
198 EXPECT_EQ(salt1 != salt1b, UsePerStorageKeySalts());
199 EXPECT_EQ(salt2 != salt2b, UsePerStorageKeySalts());
200 EXPECT_EQ(salt3, salt3b);
203 TEST_P(MediaDeviceSaltServiceTest, DeleteSingleSalt) {
204 // Deletion of individual salts is not supported when using the global salt.
205 std::string salt1 = GetSalt(StorageKey1());
206 std::string salt2 = GetSalt(StorageKey2());
207 EXPECT_FALSE(salt1.empty());
208 EXPECT_EQ(salt1 != salt2, UsePerStorageKeySalts());
210 DeleteSingleSalt(StorageKey1());
211 std::string salt1b = GetSalt(StorageKey1());
212 std::string salt2b = GetSalt(StorageKey2());
213 EXPECT_FALSE(salt1b.empty());
214 EXPECT_EQ(salt1 != salt1b, UsePerStorageKeySalts());
215 EXPECT_EQ(salt2b, salt2);
217 DeleteSingleSalt(StorageKey2());
218 std::string salt1c = GetSalt(StorageKey1());
219 std::string salt2c = GetSalt(StorageKey2());
220 EXPECT_EQ(salt1c, salt1b);
221 EXPECT_EQ(salt2c != salt2b, UsePerStorageKeySalts());
222 EXPECT_EQ(salt2c != salt1c, UsePerStorageKeySalts());
225 TEST_P(MediaDeviceSaltServiceTest, DeleteSaltsInTimeRange) {
226 // Deletion of salts by time range is supported with both the global and
227 // per-storage-key salts.
228 base::Time time1 = base::Time::Now();
229 std::string salt1 = GetSalt(StorageKey1());
230 std::string salt2 = GetSalt(StorageKey2());
231 base::Time time3 = base::Time::Now();
232 std::string salt3 = GetSalt(StorageKey3());
233 base::Time time4 = base::Time::Now();
236 DeleteSaltsInTimeRange(time4, base::Time::Max());
237 std::string salt1b = GetSalt(StorageKey1());
238 std::string salt2b = GetSalt(StorageKey2());
239 std::string salt3b = GetSalt(StorageKey3());
240 EXPECT_EQ(salt1b, salt1);
241 EXPECT_EQ(salt2b, salt2);
242 EXPECT_EQ(salt3b, salt3);
244 // Only salt for StorageKey3 deleted
245 DeleteSaltsInTimeRange(time3, base::Time::Max());
246 std::string salt1c = GetSalt(StorageKey1());
247 std::string salt2c = GetSalt(StorageKey2());
248 std::string salt3c = GetSalt(StorageKey3());
249 EXPECT_EQ(salt1c, salt1b);
250 EXPECT_EQ(salt2c, salt2b);
251 EXPECT_NE(salt3c, salt3b);
253 // Salts for StorageKey1 and StorageKey2 deleted
254 DeleteSaltsInTimeRange(time1, time3);
255 std::string salt1d = GetSalt(StorageKey1());
256 std::string salt2d = GetSalt(StorageKey2());
257 std::string salt3d = GetSalt(StorageKey3());
258 EXPECT_NE(salt1d, salt1c);
259 EXPECT_NE(salt2d, salt2c);
260 EXPECT_EQ(salt3d, salt3c);
263 DeleteSaltsInTimeRange(base::Time::Min(), base::Time::Max());
264 std::string salt1e = GetSalt(StorageKey1());
265 std::string salt2e = GetSalt(StorageKey2());
266 std::string salt3e = GetSalt(StorageKey3());
267 EXPECT_NE(salt1e, salt1d);
268 EXPECT_NE(salt2e, salt2d);
269 EXPECT_NE(salt3e, salt3d);
272 TEST_P(MediaDeviceSaltServiceTest, GetAllStorageKeys) {
273 // Deletion of individual salts is not supported when using the global salt.
274 std::string salt1 = GetSalt(StorageKey1());
275 std::string salt2 = GetSalt(StorageKey2());
276 std::string salt3 = GetSalt(StorageKey3());
279 UnorderedElementsAre(StorageKey1(), StorageKey2(), StorageKey3()));
281 DeleteSingleSalt(StorageKey2());
282 EXPECT_THAT(GetAllStorageKeys(),
283 UnorderedElementsAre(StorageKey1(), StorageKey3()));
285 DeleteSaltsInTimeRange(base::Time::Min(), base::Time::Max());
286 EXPECT_THAT(GetAllStorageKeys(), IsEmpty());
289 TEST_P(MediaDeviceSaltServiceTest, OpaqueKey) {
290 // Storage keys with opaque origin use an ephemeral global salt.
291 std::string salt1 = GetSalt(blink::StorageKey());
293 // The fallback salt is reset when all salts are deleted.
294 DeleteSaltsInTimeRange(base::Time::Min(), base::Time::Max());
295 std::string salt2 = GetSalt(blink::StorageKey());
296 EXPECT_NE(salt1, salt2);
298 // The fallback salt is not deleted in a matching deletion.
299 DeleteSaltUsingMatcher(blink::StorageKey());
300 std::string salt3 = GetSalt(blink::StorageKey());
301 EXPECT_EQ(salt2, salt3);
304 TEST_P(MediaDeviceSaltServiceTest, ManyGetSalts) {
305 const size_t n = 100;
306 std::vector<std::string> salts;
307 base::RunLoop run_loop;
308 for (size_t i = 0; i < n; i++) {
309 service()->GetSalt(StorageKey1(),
310 base::BindLambdaForTesting([&](const std::string& salt) {
311 salts.push_back(salt);
312 if (salts.size() == n) {
318 ASSERT_EQ(salts.size(), n);
319 EXPECT_FALSE(salts[0].empty());
320 for (size_t i = 1; i < n; i++) {
321 EXPECT_EQ(salts[i], salts[0]);
325 TEST_P(MediaDeviceSaltServiceTest, DeviceChangeEvent) {
326 base::SystemMonitor monitor;
327 ASSERT_EQ(base::SystemMonitor::Get(), &monitor);
328 testing::StrictMock<base::MockDevicesChangedObserver> observer;
329 monitor.AddDevicesChangedObserver(&observer);
330 GetSalt(StorageKey1());
331 GetSalt(StorageKey2());
333 EXPECT_CALL(observer, OnDevicesChanged(base::SystemMonitor::DEVTYPE_AUDIO));
334 EXPECT_CALL(observer,
335 OnDevicesChanged(base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE));
336 DeleteSaltUsingMatcher(StorageKey1());
337 task_environment().RunUntilIdle();
339 EXPECT_CALL(observer, OnDevicesChanged(base::SystemMonitor::DEVTYPE_AUDIO));
340 EXPECT_CALL(observer,
341 OnDevicesChanged(base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE));
342 DeleteSaltsInTimeRange(base::Time::Min(), base::Time::Max());
343 task_environment().RunUntilIdle();
345 monitor.RemoveDevicesChangedObserver(&observer);
348 INSTANTIATE_TEST_SUITE_P(All, MediaDeviceSaltServiceTest, testing::Bool());
349 } // namespace media_device_salt