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