1// Copyright 2014 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/ui/toolbar/origin_chip_info.h"
6
7#include "base/prefs/pref_service.h"
8#include "base/strings/string_util.h"
9#include "base/strings/utf_string_conversions.h"
10#include "chrome/browser/extensions/extension_service.h"
11#include "chrome/browser/extensions/extension_util.h"
12#include "chrome/browser/profiles/profile.h"
13#include "chrome/browser/safe_browsing/client_side_detection_host.h"
14#include "chrome/browser/safe_browsing/safe_browsing_tab_observer.h"
15#include "chrome/browser/ui/toolbar/toolbar_model.h"
16#include "chrome/common/extensions/extension_constants.h"
17#include "chrome/common/pref_names.h"
18#include "chrome/common/url_constants.h"
19#include "content/public/browser/web_contents.h"
20#include "extensions/browser/extension_icon_image.h"
21#include "extensions/browser/extension_system.h"
22#include "extensions/common/constants.h"
23#include "extensions/common/manifest_handlers/icons_handler.h"
24#include "grit/chromium_strings.h"
25#include "grit/components_strings.h"
26#include "grit/generated_resources.h"
27#include "grit/theme_resources.h"
28#include "net/base/net_util.h"
29#include "ui/base/l10n/l10n_util.h"
30#include "url/gurl.h"
31
32namespace {
33
34// For selected kChromeUIScheme and url::kAboutScheme, return the string
35// resource
36// number for the title of the page. If we don't have a specialized title,
37// returns -1.
38int StringForChromeHost(const GURL& url) {
39  DCHECK(url.is_empty() || url.SchemeIs(content::kChromeUIScheme));
40
41  if (url.is_empty())
42    return IDS_NEW_TAB_TITLE;
43
44  // TODO(gbillock): Just get the page title and special case exceptions?
45  std::string host = url.host();
46  if (host == chrome::kChromeUIAppLauncherPageHost)
47    return IDS_APP_DEFAULT_PAGE_NAME;
48  if (host == chrome::kChromeUIBookmarksHost)
49    return IDS_BOOKMARK_MANAGER_TITLE;
50  if (host == chrome::kChromeUIComponentsHost)
51    return IDS_COMPONENTS_TITLE;
52  if (host == chrome::kChromeUICrashesHost)
53    return IDS_CRASHES_TITLE;
54#if defined(ENABLE_SERVICE_DISCOVERY)
55  if (host == chrome::kChromeUIDevicesHost)
56    return IDS_LOCAL_DISCOVERY_DEVICES_PAGE_TITLE;
57#endif  // ENABLE_SERVICE_DISCOVERY
58  if (host == chrome::kChromeUIDownloadsHost)
59    return IDS_DOWNLOAD_TITLE;
60  if (host == chrome::kChromeUIExtensionsHost)
61    return IDS_MANAGE_EXTENSIONS_SETTING_WINDOWS_TITLE;
62  if (host == chrome::kChromeUIHelpHost)
63    return IDS_ABOUT_TITLE;
64  if (host == chrome::kChromeUIHistoryHost)
65    return IDS_HISTORY_TITLE;
66  if (host == chrome::kChromeUINewTabHost)
67    return IDS_NEW_TAB_TITLE;
68  if (host == chrome::kChromeUIPluginsHost)
69    return IDS_PLUGINS_TITLE;
70  if (host == chrome::kChromeUIPolicyHost)
71    return IDS_POLICY_TITLE;
72  if (host == chrome::kChromeUIPrintHost)
73    return IDS_PRINT_PREVIEW_TITLE;
74  if (host == chrome::kChromeUISettingsHost)
75    return IDS_SETTINGS_TITLE;
76  if (host == chrome::kChromeUIVersionHost)
77    return IDS_ABOUT_VERSION_TITLE;
78
79  return -1;
80}
81
82}  // namespace
83
84OriginChipInfo::OriginChipInfo(
85    extensions::IconImage::Observer* owner,
86    Profile* profile)
87    : owner_(owner),
88      profile_(profile) {}
89
90OriginChipInfo::~OriginChipInfo() {}
91
92bool OriginChipInfo::Update(const content::WebContents* web_contents,
93                            const ToolbarModel* toolbar_model) {
94  GURL displayed_url = toolbar_model->GetURL();
95  ToolbarModel::SecurityLevel security_level =
96      toolbar_model->GetSecurityLevel(true);
97  bool is_url_malware = OriginChip::IsMalware(displayed_url, web_contents);
98
99  if ((displayed_url_ == displayed_url) &&
100      (security_level_ == security_level) &&
101      (is_url_malware_ == is_url_malware))
102    return false;
103
104  displayed_url_ = displayed_url;
105  security_level_ = security_level;
106  is_url_malware_ = is_url_malware;
107
108  label_ = OriginChip::LabelFromURLForProfile(displayed_url, profile_);
109  if (security_level_ == ToolbarModel::EV_SECURE) {
110    label_ = l10n_util::GetStringFUTF16(IDS_SITE_CHIP_EV_SSL_LABEL,
111                                        toolbar_model->GetEVCertName(),
112                                        label_);
113  }
114
115
116  if (displayed_url_.SchemeIs(extensions::kExtensionScheme)) {
117    const extensions::Extension* extension =
118        extensions::ExtensionSystem::Get(profile_)->extension_service()->
119            extensions()->GetExtensionOrAppByURL(displayed_url_);
120
121    if (extension) {
122      icon_ = IDR_EXTENSIONS_FAVICON;
123      extension_icon_image_.reset(
124          new extensions::IconImage(profile_,
125                                    extension,
126                                    extensions::IconsInfo::GetIcons(extension),
127                                    extension_misc::EXTENSION_ICON_BITTY,
128                                    extensions::util::GetDefaultAppIcon(),
129                                    owner_));
130
131      // Forces load of the image.
132      extension_icon_image_->image_skia().GetRepresentation(1.0f);
133      if (!extension_icon_image_->image_skia().image_reps().empty())
134        owner_->OnExtensionIconImageChanged(extension_icon_image_.get());
135
136      return true;
137    }
138  }
139
140  if (extension_icon_image_) {
141    extension_icon_image_.reset();
142    owner_->OnExtensionIconImageChanged(NULL);
143  }
144
145  icon_ = (displayed_url_.is_empty() ||
146           displayed_url_.SchemeIs(content::kChromeUIScheme)) ?
147      IDR_PRODUCT_LOGO_16 :
148      toolbar_model->GetIconForSecurityLevel(security_level_);
149
150  return true;
151}
152
153base::string16 OriginChipInfo::Tooltip() const {
154  return base::UTF8ToUTF16(displayed_url_.spec());
155}
156
157// static
158bool OriginChip::IsMalware(const GURL& url, const content::WebContents* tab) {
159  DCHECK(tab);
160
161  if (tab->GetURL() != url)
162    return false;
163
164  const safe_browsing::SafeBrowsingTabObserver* sb_observer =
165      safe_browsing::SafeBrowsingTabObserver::FromWebContents(tab);
166  return sb_observer && sb_observer->detection_host() &&
167      sb_observer->detection_host()->DidPageReceiveSafeBrowsingMatch();
168}
169
170// static
171base::string16 OriginChip::LabelFromURLForProfile(const GURL& provided_url,
172                                                  Profile* profile) {
173  // First, strip view-source: if it appears.  Note that GetContent removes
174  // "view-source:" but leaves the original scheme (http, https, ftp, etc).
175  GURL url(provided_url);
176  if (url.SchemeIs(content::kViewSourceScheme))
177    url = GURL(url.GetContent());
178
179  // About scheme pages. Currently all about: URLs other than about:blank
180  // redirect to chrome: URLs, so this only affects about:blank.
181  if (url.SchemeIs(url::kAboutScheme))
182    return base::UTF8ToUTF16(url.spec());
183
184  // Chrome built-in pages.
185  if (url.is_empty() || url.SchemeIs(content::kChromeUIScheme)) {
186    int string_ref = StringForChromeHost(url);
187    return l10n_util::GetStringUTF16(
188        (string_ref == -1) ? IDS_SHORT_PRODUCT_NAME : string_ref);
189  }
190
191  // For chrome-extension URLs, return the extension name.
192  if (url.SchemeIs(extensions::kExtensionScheme)) {
193    ExtensionService* service =
194        extensions::ExtensionSystem::Get(profile)->extension_service();
195    const extensions::Extension* extension =
196        service->extensions()->GetExtensionOrAppByURL(url);
197    return extension ?
198        base::UTF8ToUTF16(extension->name()) : base::UTF8ToUTF16(url.host());
199  }
200
201  if (url.SchemeIsHTTPOrHTTPS() || url.SchemeIs(url::kFtpScheme)) {
202    // See ToolbarModelImpl::GetText(). Does not pay attention to any user
203    // edits, and uses GetURL/net::FormatUrl -- We don't really care about
204    // length or the autocomplete parser.
205    // TODO(gbillock): This uses an algorithm very similar to GetText, which
206    // is probably too conservative. Try out just using a simpler mechanism of
207    // StripWWW() and IDNToUnicode().
208    std::string languages;
209    if (profile)
210      languages = profile->GetPrefs()->GetString(prefs::kAcceptLanguages);
211
212    // TODO(macourteau): Extract the bits we care about from FormatUrl to
213    // format |url.host()| instead of this.
214    base::string16 formatted = net::FormatUrl(url.GetOrigin(), languages,
215        net::kFormatUrlOmitAll, net::UnescapeRule::NORMAL, NULL, NULL, NULL);
216    // Remove scheme, "www.", and trailing "/".
217    if (StartsWith(formatted, base::ASCIIToUTF16("http://"), false))
218      formatted = formatted.substr(7);
219    else if (StartsWith(formatted, base::ASCIIToUTF16("https://"), false))
220      formatted = formatted.substr(8);
221    else if (StartsWith(formatted, base::ASCIIToUTF16("ftp://"), false))
222      formatted = formatted.substr(6);
223    if (StartsWith(formatted, base::ASCIIToUTF16("www."), false))
224      formatted = formatted.substr(4);
225    if (EndsWith(formatted, base::ASCIIToUTF16("/"), false))
226      formatted = formatted.substr(0, formatted.size() - 1);
227    return formatted;
228  }
229
230  // These internal-ish debugging-style schemes we don't expect users
231  // to see. In these cases, the site chip will display the first
232  // part of the full URL.
233  if (url.SchemeIs(chrome::kChromeNativeScheme) ||
234      url.SchemeIs(url::kBlobScheme) ||
235      url.SchemeIs(content::kChromeDevToolsScheme) ||
236      url.SchemeIs(url::kDataScheme) ||
237      url.SchemeIs(url::kFileScheme) ||
238      url.SchemeIs(url::kFileSystemScheme) ||
239      url.SchemeIs(content::kGuestScheme) ||
240      url.SchemeIs(url::kJavaScriptScheme) ||
241      url.SchemeIs(url::kMailToScheme) ||
242      url.SchemeIs(content::kMetadataScheme) ||
243      url.SchemeIs(content::kSwappedOutScheme)) {
244    std::string truncated_url;
245    base::TruncateUTF8ToByteSize(url.spec(), 1000, &truncated_url);
246    return base::UTF8ToUTF16(truncated_url);
247  }
248
249#if defined(OS_CHROMEOS)
250  if (url.SchemeIs(chrome::kCrosScheme) ||
251      url.SchemeIs(chrome::kDriveScheme))
252    return base::UTF8ToUTF16(url.spec());
253#endif
254
255  // If all else fails, return the hostname.
256  return base::UTF8ToUTF16(url.host());
257}
258