Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / extensions / webstore_inline_installer.cc
blob045d996465d3616d7cded6e997339c801ebfa203
1 // Copyright (c) 2012 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.
5 #include "chrome/browser/extensions/webstore_inline_installer.h"
7 #include "base/strings/stringprintf.h"
8 #include "chrome/browser/profiles/profile.h"
9 #include "chrome/browser/ui/browser_finder.h"
10 #include "content/public/browser/web_contents.h"
12 using content::WebContents;
14 namespace extensions {
16 const char kInvalidWebstoreResponseError[] =
17 "Invalid Chrome Web Store response.";
18 const char kNoVerifiedSitesError[] =
19 "Inline installs can only be initiated for Chrome Web Store items that "
20 "have one or more verified sites.";
21 const char kNotFromVerifiedSitesError[] =
22 "Installs can only be initiated by one of the Chrome Web Store item's "
23 "verified sites.";
24 const char kInlineInstallSupportedError[] =
25 "Inline installation is not supported for this item. The user will be "
26 "redirected to the Chrome Web Store.";
27 const char kInitiatedFromPopupError[] =
28 "Inline installs can not be initiated from pop-up windows.";
30 WebstoreInlineInstaller::WebstoreInlineInstaller(
31 content::WebContents* web_contents,
32 const std::string& webstore_item_id,
33 const GURL& requestor_url,
34 const Callback& callback)
35 : WebstoreStandaloneInstaller(
36 webstore_item_id,
37 Profile::FromBrowserContext(web_contents->GetBrowserContext()),
38 callback),
39 content::WebContentsObserver(web_contents),
40 requestor_url_(requestor_url) {
43 WebstoreInlineInstaller::~WebstoreInlineInstaller() {}
45 // static
46 bool WebstoreInlineInstaller::IsRequestorPermitted(
47 const base::DictionaryValue& webstore_data,
48 const GURL& requestor_url,
49 std::string* error) {
50 // Ensure that there is at least one verified site present.
51 const bool data_has_single_site = webstore_data.HasKey(kVerifiedSiteKey);
52 const bool data_has_site_list = webstore_data.HasKey(kVerifiedSitesKey);
53 if (!data_has_single_site && !data_has_site_list) {
54 *error = kNoVerifiedSitesError;
55 return false;
57 bool requestor_is_ok = false;
58 // Handle the deprecated single-site case.
59 if (!data_has_site_list) {
60 std::string verified_site;
61 if (!webstore_data.GetString(kVerifiedSiteKey, &verified_site)) {
62 *error = kInvalidWebstoreResponseError;
63 return false;
65 requestor_is_ok = IsRequestorURLInVerifiedSite(requestor_url,
66 verified_site);
67 } else {
68 const base::ListValue* verified_sites = NULL;
69 if (!webstore_data.GetList(kVerifiedSitesKey, &verified_sites)) {
70 *error = kInvalidWebstoreResponseError;
71 return false;
73 for (base::ListValue::const_iterator it = verified_sites->begin();
74 it != verified_sites->end() && !requestor_is_ok; ++it) {
75 std::string verified_site;
76 if (!(*it)->GetAsString(&verified_site)) {
77 *error = kInvalidWebstoreResponseError;
78 return false;
80 if (IsRequestorURLInVerifiedSite(requestor_url, verified_site)) {
81 requestor_is_ok = true;
85 if (!requestor_is_ok) {
86 *error = kNotFromVerifiedSitesError;
87 return false;
89 *error = "";
90 return true;
93 bool WebstoreInlineInstaller::CheckRequestorAlive() const {
94 // The tab may have gone away - cancel installation in that case.
95 return web_contents() != NULL;
98 const GURL& WebstoreInlineInstaller::GetRequestorURL() const {
99 return requestor_url_;
102 scoped_refptr<ExtensionInstallPrompt::Prompt>
103 WebstoreInlineInstaller::CreateInstallPrompt() const {
104 scoped_refptr<ExtensionInstallPrompt::Prompt> prompt(
105 new ExtensionInstallPrompt::Prompt(
106 ExtensionInstallPrompt::INLINE_INSTALL_PROMPT));
108 // crbug.com/260742: Don't display the user count if it's zero. The reason
109 // it's zero is very often that the number isn't actually being counted
110 // (intentionally), which means that it's unlikely to be correct.
111 prompt->SetWebstoreData(localized_user_count(),
112 show_user_count(),
113 average_rating(),
114 rating_count());
115 return prompt;
118 bool WebstoreInlineInstaller::ShouldShowPostInstallUI() const {
119 return true;
122 bool WebstoreInlineInstaller::ShouldShowAppInstalledBubble() const {
123 return true;
126 WebContents* WebstoreInlineInstaller::GetWebContents() const {
127 return web_contents();
130 bool WebstoreInlineInstaller::CheckInlineInstallPermitted(
131 const base::DictionaryValue& webstore_data,
132 std::string* error) const {
133 Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
134 DCHECK(browser);
135 if (browser->is_type_popup()) {
136 *error = kInitiatedFromPopupError;
137 return false;
139 // The store may not support inline installs for this item, in which case
140 // we open the store-provided redirect URL in a new tab and abort the
141 // installation process.
142 bool inline_install_not_supported = false;
143 if (webstore_data.HasKey(kInlineInstallNotSupportedKey)
144 && !webstore_data.GetBoolean(kInlineInstallNotSupportedKey,
145 &inline_install_not_supported)) {
146 *error = kInvalidWebstoreResponseError;
147 return false;
149 if (inline_install_not_supported) {
150 std::string redirect_url;
151 if (!webstore_data.GetString(kRedirectUrlKey, &redirect_url)) {
152 *error = kInvalidWebstoreResponseError;
153 return false;
155 web_contents()->OpenURL(content::OpenURLParams(
156 GURL(redirect_url),
157 content::Referrer::SanitizeForRequest(
158 GURL(redirect_url),
159 content::Referrer(web_contents()->GetURL(),
160 blink::WebReferrerPolicyDefault)),
161 NEW_FOREGROUND_TAB, ui::PAGE_TRANSITION_AUTO_BOOKMARK, false));
162 *error = kInlineInstallSupportedError;
163 return false;
165 *error = "";
166 return true;
169 bool WebstoreInlineInstaller::CheckRequestorPermitted(
170 const base::DictionaryValue& webstore_data,
171 std::string* error) const {
172 return IsRequestorPermitted(webstore_data, requestor_url_, error);
176 // Private implementation.
179 void WebstoreInlineInstaller::WebContentsDestroyed() {
180 AbortInstall();
183 // static
184 bool WebstoreInlineInstaller::IsRequestorURLInVerifiedSite(
185 const GURL& requestor_url,
186 const std::string& verified_site) {
187 // Turn the verified site into a URL that can be parsed by URLPattern.
188 // |verified_site| must follow the format:
190 // [scheme://]host[:port][/path/specifier]
192 // If scheme is omitted, URLPattern will match against either an
193 // HTTP or HTTPS requestor. If scheme is specified, it must be either HTTP
194 // or HTTPS, and URLPattern will only match the scheme specified.
195 GURL verified_site_url(verified_site);
196 int valid_schemes = URLPattern::SCHEME_HTTP | URLPattern::SCHEME_HTTPS;
197 if (!verified_site_url.is_valid() || !verified_site_url.IsStandard())
198 // If no scheme is specified, GURL will fail to parse the string correctly.
199 // It will either determine that the URL is invalid, or parse a
200 // host:port/path as scheme:host/path.
201 verified_site_url = GURL("http://" + verified_site);
202 else if (verified_site_url.SchemeIs("http"))
203 valid_schemes = URLPattern::SCHEME_HTTP;
204 else if (verified_site_url.SchemeIs("https"))
205 valid_schemes = URLPattern::SCHEME_HTTPS;
206 else
207 return false;
209 std::string port_spec =
210 verified_site_url.has_port() ? ":" + verified_site_url.port() : "";
211 std::string path_spec = verified_site_url.path() + "*";
212 std::string verified_site_pattern_spec =
213 base::StringPrintf(
214 "%s://*.%s%s%s",
215 verified_site_url.scheme().c_str(),
216 verified_site_url.host().c_str(),
217 port_spec.c_str(),
218 path_spec.c_str());
220 URLPattern verified_site_pattern(valid_schemes);
221 URLPattern::ParseResult parse_result =
222 verified_site_pattern.Parse(verified_site_pattern_spec);
223 if (parse_result != URLPattern::PARSE_SUCCESS) {
224 DLOG(WARNING) << "Could not parse " << verified_site_pattern_spec <<
225 " as URL pattern " << parse_result;
226 return false;
228 verified_site_pattern.SetScheme("*");
230 return verified_site_pattern.MatchesURL(requestor_url);
233 } // namespace extensions