1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef CHROME_BROWSER_ANDROID_SEARCH_PERMISSIONS_SEARCH_PERMISSIONS_SERVICE_H_
6 #define CHROME_BROWSER_ANDROID_SEARCH_PERMISSIONS_SEARCH_PERMISSIONS_SERVICE_H_
7 
8 #include "base/callback_forward.h"
9 #include "base/memory/singleton.h"
10 #include "base/strings/string16.h"
11 #include "components/content_settings/core/common/content_settings.h"
12 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
13 #include "components/keyed_service/core/keyed_service.h"
14 #include "url/origin.h"
15 
16 namespace content {
17 class BrowserContext;
18 }
19 
20 namespace user_prefs {
21 class PrefRegistrySyncable;
22 }
23 
24 class HostContentSettingsMap;
25 class PrefService;
26 class Profile;
27 
28 // Helper class to manage DSE permissions. It keeps the setting valid by
29 // watching change to the CCTLD and DSE.
30 // Glossary:
31 //     DSE: Default Search Engine
32 //     CCTLD: Country Code Top Level Domain (e.g. google.com.au)
33 class SearchPermissionsService : public KeyedService {
34  public:
35   // Delegate for search engine related functionality. Can be overridden for
36   // testing.
37   class SearchEngineDelegate {
38    public:
~SearchEngineDelegate()39     virtual ~SearchEngineDelegate() {}
40 
41     // Returns the name of the current DSE.
42     virtual base::string16 GetDSEName() = 0;
43 
44     // Returns the origin of the DSE. If the current DSE is Google this will
45     // return the current CCTLD.
46     virtual url::Origin GetDSEOrigin() = 0;
47 
48     // Set a callback that will be called if the DSE or CCTLD changes for any
49     // reason.
50     virtual void SetDSEChangedCallback(base::RepeatingClosure callback) = 0;
51   };
52 
53   // Factory implementation will not create a service in incognito.
54   class Factory : public BrowserContextKeyedServiceFactory {
55    public:
56     static SearchPermissionsService* GetForBrowserContext(
57         content::BrowserContext* context);
58 
59     static Factory* GetInstance();
60 
61    private:
62     friend struct base::DefaultSingletonTraits<Factory>;
63 
64     Factory();
65     ~Factory() override;
66 
67     // BrowserContextKeyedServiceFactory
68     bool ServiceIsCreatedWithBrowserContext() const override;
69     KeyedService* BuildServiceInstanceFor(
70         content::BrowserContext* profile) const override;
71     void RegisterProfilePrefs(
72         user_prefs::PrefRegistrySyncable* registry) override;
73   };
74 
75   explicit SearchPermissionsService(Profile* profile);
76 
77   // Returns whether the given permission is being configured for the DSE for
78   // the given origin.
79   bool IsPermissionControlledByDSE(ContentSettingsType type,
80                                    const url::Origin& requesting_origin);
81 
82   // Resets the DSE permission for a single ContentSettingsType.
83   void ResetDSEPermission(ContentSettingsType type);
84 
85   // Reset all supported DSE permissions.
86   void ResetDSEPermissions();
87 
88   // KeyedService:
89   void Shutdown() override;
90 
91  private:
92   friend class ChromeBrowsingDataRemoverDelegateTest;
93   friend class SearchPermissionsServiceTest;
94   FRIEND_TEST_ALL_PREFIXES(GeolocationPermissionContextDelegateTests,
95                            SearchGeolocationInIncognito);
96   struct PrefValue;
97 
98   ~SearchPermissionsService() override;
99 
100   // When the DSE CCTLD changes (either by changing their DSE or by changing
101   // their CCTLD) we carry over the geolocation/notification permissions from
102   // the last DSE CCTLD. Before carrying them over, we store the old value
103   // of the permissions in a pref so the user's settings can be restored if
104   // they change DSE in the future.
105   // We resolve conflicts in the following way:
106   // * If the DSE CCTLD origin permission is BLOCK, but the old DSE's permission
107   //   is ALLOW, change the DSE permission setting to BLOCK.
108   // * If the DSE CCTLD origin permission is ALLOW, but the old DSE's permission
109   //   is BLOCK, change the DSE permission setting to BLOCK but restore it to
110   //   ASK later.
111   // * If the user changes the DSE CCTLD origin permission, we restore it back
112   //   to ASK when they change DSE.
113   // Also, if the DSE changes and geolocation is enabled, we reset the
114   // geolocation disclosure so that it will be shown again.
115   void OnDSEChanged();
116 
117   // Restore the setting for an origin before it became the DSE. Returns the
118   // setting that the origin was set to before restoring the old value.
119   ContentSetting RestoreOldSettingAndReturnPrevious(
120       const GURL& dse_origin,
121       ContentSettingsType type,
122       ContentSetting setting_to_restore);
123 
124   // Helper function for OnDSEChanged which transitions the DSE setting for a
125   // specific permission. It returns the content setting to be restored later
126   // for |new_dse_origin|.
127   ContentSetting UpdatePermissionAndReturnPrevious(ContentSettingsType type,
128                                                    const GURL& old_dse_origin,
129                                                    const GURL& new_dse_origin,
130                                                    ContentSetting old_setting,
131                                                    bool dse_name_changed);
132 
133   // Initialize the DSE permission settings if they haven't already been
134   // initialized. Also, if they haven't been initialized, reset whether the DSE
135   // geolocation disclosure has been shown to ensure user who may have seen it
136   // on earlier versions (due to Finch experiments) see it again.
137   void InitializeSettingsIfNeeded();
138 
139   PrefValue GetDSEPref();
140   void SetDSEPref(const PrefValue& pref);
141 
142   // Retrieve the content setting for the given permission/origin.
143   ContentSetting GetContentSetting(const GURL& origin,
144                                    ContentSettingsType type);
145   // Set the content setting for the given permission/origin.
146   void SetContentSetting(const GURL& origin,
147                          ContentSettingsType type,
148                          ContentSetting setting);
149 
150   void SetSearchEngineDelegateForTest(
151       std::unique_ptr<SearchEngineDelegate> delegate);
152 
153   Profile* profile_;
154   PrefService* pref_service_;
155   HostContentSettingsMap* host_content_settings_map_;
156   std::unique_ptr<SearchEngineDelegate> delegate_;
157 };
158 
159 #endif  // CHROME_BROWSER_ANDROID_SEARCH_PERMISSIONS_SEARCH_PERMISSIONS_SERVICE_H_
160