1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "SettingsChangeObserver.h"
8 #include "ContentBlockingUserInteraction.h"
9
10 #include "mozilla/Services.h"
11 #include "mozilla/Preferences.h"
12 #include "nsIObserverService.h"
13 #include "nsIPermission.h"
14 #include "nsTArray.h"
15
16 using namespace mozilla;
17
18 namespace {
19
20 UniquePtr<nsTArray<SettingsChangeObserver::AntiTrackingSettingsChangedCallback>>
21 gSettingsChangedCallbacks;
22
23 }
24
NS_IMPL_ISUPPORTS(SettingsChangeObserver,nsIObserver)25 NS_IMPL_ISUPPORTS(SettingsChangeObserver, nsIObserver)
26
27 NS_IMETHODIMP SettingsChangeObserver::Observe(nsISupports* aSubject,
28 const char* aTopic,
29 const char16_t* aData) {
30 if (!strcmp(aTopic, "xpcom-shutdown")) {
31 nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
32 if (obs) {
33 obs->RemoveObserver(this, "perm-added");
34 obs->RemoveObserver(this, "perm-changed");
35 obs->RemoveObserver(this, "perm-cleared");
36 obs->RemoveObserver(this, "perm-deleted");
37 obs->RemoveObserver(this, "xpcom-shutdown");
38
39 Preferences::UnregisterPrefixCallback(
40 SettingsChangeObserver::PrivacyPrefChanged,
41 "browser.contentblocking.");
42 Preferences::UnregisterPrefixCallback(
43 SettingsChangeObserver::PrivacyPrefChanged, "network.cookie.");
44 Preferences::UnregisterPrefixCallback(
45 SettingsChangeObserver::PrivacyPrefChanged, "privacy.");
46
47 gSettingsChangedCallbacks = nullptr;
48 }
49 } else {
50 nsCOMPtr<nsIPermission> perm = do_QueryInterface(aSubject);
51 if (perm) {
52 nsAutoCString type;
53 nsresult rv = perm->GetType(type);
54 if (NS_WARN_IF(NS_FAILED(rv)) || type.Equals(USER_INTERACTION_PERM)) {
55 // Ignore failures or notifications that have been sent because of
56 // user interactions.
57 return NS_OK;
58 }
59 }
60
61 RunAntiTrackingSettingsChangedCallbacks();
62 }
63
64 return NS_OK;
65 }
66
67 // static
PrivacyPrefChanged(const char * aPref,void * aClosure)68 void SettingsChangeObserver::PrivacyPrefChanged(const char* aPref,
69 void* aClosure) {
70 RunAntiTrackingSettingsChangedCallbacks();
71 }
72
73 // static
RunAntiTrackingSettingsChangedCallbacks()74 void SettingsChangeObserver::RunAntiTrackingSettingsChangedCallbacks() {
75 if (gSettingsChangedCallbacks) {
76 for (auto& callback : *gSettingsChangedCallbacks) {
77 callback();
78 }
79 }
80 }
81
82 // static
OnAntiTrackingSettingsChanged(const SettingsChangeObserver::AntiTrackingSettingsChangedCallback & aCallback)83 void SettingsChangeObserver::OnAntiTrackingSettingsChanged(
84 const SettingsChangeObserver::AntiTrackingSettingsChangedCallback&
85 aCallback) {
86 static bool initialized = false;
87 if (!initialized) {
88 // It is possible that while we have some data in our cache, something
89 // changes in our environment that causes the anti-tracking checks below to
90 // change their response. Therefore, we need to clear our cache when we
91 // detect a related change.
92 Preferences::RegisterPrefixCallback(
93 SettingsChangeObserver::PrivacyPrefChanged, "browser.contentblocking.");
94 Preferences::RegisterPrefixCallback(
95 SettingsChangeObserver::PrivacyPrefChanged, "network.cookie.");
96 Preferences::RegisterPrefixCallback(
97 SettingsChangeObserver::PrivacyPrefChanged, "privacy.");
98
99 nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
100 if (obs) {
101 RefPtr<SettingsChangeObserver> observer = new SettingsChangeObserver();
102 obs->AddObserver(observer, "perm-added", false);
103 obs->AddObserver(observer, "perm-changed", false);
104 obs->AddObserver(observer, "perm-cleared", false);
105 obs->AddObserver(observer, "perm-deleted", false);
106 obs->AddObserver(observer, "xpcom-shutdown", false);
107 }
108
109 gSettingsChangedCallbacks =
110 MakeUnique<nsTArray<AntiTrackingSettingsChangedCallback>>();
111
112 initialized = true;
113 }
114
115 gSettingsChangedCallbacks->AppendElement(aCallback);
116 }
117