1 // Copyright 2013 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_EXTENSIONS_API_MESSAGING_INCOGNITO_CONNECTABILITY_H_
6 #define CHROME_BROWSER_EXTENSIONS_API_MESSAGING_INCOGNITO_CONNECTABILITY_H_
7 
8 #include <set>
9 
10 #include "base/memory/weak_ptr.h"
11 #include "extensions/browser/browser_context_keyed_api_factory.h"
12 #include "url/gurl.h"
13 
14 class InfoBarService;
15 
16 namespace content {
17 class BrowserContext;
18 class WebContents;
19 }
20 
21 namespace infobars {
22 class InfoBar;
23 }
24 
25 namespace extensions {
26 class Extension;
27 
28 // Tracks the web connectability of domains to extensions in incognito mode.
29 //
30 // The most important functionality is prompting the user to allow or disallow
31 // connections from incognito tabs to extensions or apps. Users are not prompted
32 // for extensions which can be enabled in incognito mode. However for apps, it's
33 // essential we have this functionality because there is no way for them to be
34 // enabled in incognito.
35 class IncognitoConnectability : public BrowserContextKeyedAPI {
36  public:
37   // While in scope, immediately either accepts or denies the alerts that show
38   // up, and counts the number of times it was invoked.
39   class ScopedAlertTracker {
40    public:
41     enum Mode {
42       INTERACTIVE,
43       ALWAYS_ALLOW,
44       ALWAYS_DENY,
45     };
46 
47     explicit ScopedAlertTracker(Mode mode);
48 
49     ~ScopedAlertTracker();
50 
51     // Returns the number of times the alert has been shown since
52     // GetAndResetAlertCount was last called.
53     int GetAndResetAlertCount();
54 
55    private:
56     int last_checked_invocation_count_;
57   };
58 
59   // Returns the IncognitoConnectability object for |context|. |context| must
60   // be off-the-record.
61   static IncognitoConnectability* Get(content::BrowserContext* context);
62 
63   // Passes true to the provided callback if |url| is allowed to connect from
64   // this profile, false otherwise. If unknown, the user will be prompted before
65   // an answer is returned.
66   void Query(const Extension* extension,
67              content::WebContents* web_contents,
68              const GURL& url,
69              const base::Callback<void(bool)>& callback);
70 
71  private:
72   struct TabContext {
73     TabContext();
74     TabContext(const TabContext& other);
75     ~TabContext();
76 
77     // The infobar being shown in a given tab. The InfoBarService maintains
78     // ownership of this object. This struct must always be destroyed before the
79     // infobar it tracks.
80     infobars::InfoBar* infobar;
81     // Connectability queries outstanding on this infobar.
82     std::vector<base::Callback<void(bool)>> callbacks;
83   };
84 
85   friend class BrowserContextKeyedAPIFactory<IncognitoConnectability>;
86 
87   explicit IncognitoConnectability(content::BrowserContext* context);
88   ~IncognitoConnectability() override;
89 
90   typedef std::map<std::string, std::set<GURL> > ExtensionToOriginsMap;
91   typedef std::pair<std::string, GURL> ExtensionOriginPair;
92   typedef std::map<InfoBarService*, TabContext> PendingOrigin;
93   typedef std::map<ExtensionOriginPair, PendingOrigin> PendingOriginMap;
94 
95   // Called with the user's selection from the infobar.
96   // |response == INTERACTIVE| indicates that the user closed the infobar
97   // without selecting allow or deny.
98   void OnInteractiveResponse(const std::string& extension_id,
99                              const GURL& origin,
100                              InfoBarService* infobar_service,
101                              ScopedAlertTracker::Mode response);
102 
103   // Returns true if the (|extension|, |origin|) pair appears in the map.
104   bool IsInMap(const Extension* extension,
105                const GURL& origin,
106                const ExtensionToOriginsMap& map);
107 
108   // BrowserContextKeyedAPI implementation.
109   static BrowserContextKeyedAPIFactory<IncognitoConnectability>*
110       GetFactoryInstance();
service_name()111   static const char* service_name() {
112     return "Messaging.IncognitoConnectability";
113   }
114   static const bool kServiceHasOwnInstanceInIncognito = true;
115   static const bool kServiceIsCreatedWithBrowserContext = false;
116 
117   // The origins that have been prompted for and either allowed or disallowed.
118   // These are deliberately stored in-memory so that they're reset when the
119   // profile is destroyed (i.e. when the last incognito window is closed).
120   ExtensionToOriginsMap allowed_origins_;
121   ExtensionToOriginsMap disallowed_origins_;
122 
123   // This maps extension/origin pairs to the tabs with an infobar prompting for
124   // incognito connectability on them. This also stores a reference to the
125   // infobar and the set of callbacks (passed to Query) that will be called when
126   // the query is resolved.
127   PendingOriginMap pending_origins_;
128 
129   base::WeakPtrFactory<IncognitoConnectability> weak_factory_{this};
130 };
131 
132 }  // namespace extensions
133 
134 #endif  // CHROME_BROWSER_EXTENSIONS_API_MESSAGING_INCOGNITO_CONNECTABILITY_H_
135