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 #include "chrome/browser/extensions/api/messaging/incognito_connectability.h" 6 7 #include "base/lazy_instance.h" 8 #include "base/logging.h" 9 #include "base/strings/string16.h" 10 #include "base/strings/utf_string_conversions.h" 11 #include "chrome/browser/ui/simple_message_box.h" 12 #include "content/public/browser/web_contents.h" 13 #include "content/public/browser/web_contents_view.h" 14 #include "extensions/common/extension.h" 15 #include "grit/generated_resources.h" 16 #include "ui/base/l10n/l10n_util.h" 17 18 namespace extensions { 19 20 namespace { 21 IncognitoConnectability::ScopedAlertTracker::Mode g_alert_mode = 22 IncognitoConnectability::ScopedAlertTracker::INTERACTIVE; 23 int g_alert_count = 0; 24 } 25 26 IncognitoConnectability::ScopedAlertTracker::ScopedAlertTracker(Mode mode) 27 : last_checked_invocation_count_(g_alert_count) { 28 DCHECK_EQ(INTERACTIVE, g_alert_mode); 29 DCHECK_NE(INTERACTIVE, mode); 30 g_alert_mode = mode; 31 } 32 33 IncognitoConnectability::ScopedAlertTracker::~ScopedAlertTracker() { 34 DCHECK_NE(INTERACTIVE, g_alert_mode); 35 g_alert_mode = INTERACTIVE; 36 } 37 38 int IncognitoConnectability::ScopedAlertTracker::GetAndResetAlertCount() { 39 int result = g_alert_count - last_checked_invocation_count_; 40 last_checked_invocation_count_ = g_alert_count; 41 return result; 42 } 43 44 IncognitoConnectability::IncognitoConnectability(Profile* profile) { 45 CHECK(profile->IsOffTheRecord()); 46 } 47 48 IncognitoConnectability::~IncognitoConnectability() { 49 } 50 51 // static 52 IncognitoConnectability* IncognitoConnectability::Get(Profile* profile) { 53 return ProfileKeyedAPIFactory<IncognitoConnectability>::GetForProfile( 54 profile); 55 } 56 57 bool IncognitoConnectability::Query(const Extension* extension, 58 content::WebContents* web_contents, 59 const GURL& url) { 60 GURL origin = url.GetOrigin(); 61 if (origin.is_empty()) 62 return false; 63 64 if (IsInMap(extension, origin, allowed_origins_)) 65 return true; 66 if (IsInMap(extension, origin, disallowed_origins_)) 67 return false; 68 69 // We need to ask the user. 70 ++g_alert_count; 71 chrome::MessageBoxResult result = chrome::MESSAGE_BOX_RESULT_NO; 72 73 switch (g_alert_mode) { 74 // Production code should always be using INTERACTIVE. 75 case ScopedAlertTracker::INTERACTIVE: { 76 int template_id = extension->is_app() ? 77 IDS_EXTENSION_PROMPT_APP_CONNECT_FROM_INCOGNITO : 78 IDS_EXTENSION_PROMPT_EXTENSION_CONNECT_FROM_INCOGNITO; 79 result = chrome::ShowMessageBox( 80 web_contents ? web_contents->GetView()->GetTopLevelNativeWindow() 81 : NULL, 82 base::string16(), // no title 83 l10n_util::GetStringFUTF16(template_id, 84 UTF8ToUTF16(origin.spec()), 85 UTF8ToUTF16(extension->name())), 86 chrome::MESSAGE_BOX_TYPE_QUESTION); 87 break; 88 } 89 90 // Testing code can override to always allow or deny. 91 case ScopedAlertTracker::ALWAYS_ALLOW: 92 result = chrome::MESSAGE_BOX_RESULT_YES; 93 break; 94 case ScopedAlertTracker::ALWAYS_DENY: 95 result = chrome::MESSAGE_BOX_RESULT_NO; 96 break; 97 } 98 99 if (result == chrome::MESSAGE_BOX_RESULT_NO) { 100 disallowed_origins_[extension->id()].insert(origin); 101 return false; 102 } 103 allowed_origins_[extension->id()].insert(origin); 104 return true; 105 } 106 107 bool IncognitoConnectability::IsInMap(const Extension* extension, 108 const GURL& origin, 109 const ExtensionToOriginsMap& map) { 110 DCHECK_EQ(origin, origin.GetOrigin()); 111 ExtensionToOriginsMap::const_iterator it = map.find(extension->id()); 112 return it != map.end() && it->second.count(origin) > 0; 113 } 114 115 static base::LazyInstance<ProfileKeyedAPIFactory<IncognitoConnectability> > 116 g_factory = LAZY_INSTANCE_INITIALIZER; 117 118 // static 119 ProfileKeyedAPIFactory<IncognitoConnectability>* 120 IncognitoConnectability::GetFactoryInstance() { 121 return &g_factory.Get(); 122 } 123 124 } // namespace extensions 125