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 "content/public/browser/web_contents.h"
11 using content::WebContents
;
13 namespace extensions
{
15 const char kInvalidWebstoreResponseError
[] = "Invalid Chrome Web Store reponse";
16 const char kNoVerifiedSitesError
[] =
17 "Inline installs can only be initiated for Chrome Web Store items that "
18 "have one or more verified sites";
19 const char kNotFromVerifiedSitesError
[] =
20 "Installs can only be initiated by one of the Chrome Web Store item's "
22 const char kInlineInstallSupportedError
[] =
23 "Inline installation is not supported for this item. The user will be "
24 "redirected to the Chrome Web Store.";
26 WebstoreInlineInstaller::WebstoreInlineInstaller(
27 content::WebContents
* web_contents
,
28 const std::string
& webstore_item_id
,
29 const GURL
& requestor_url
,
30 const Callback
& callback
)
31 : WebstoreStandaloneInstaller(
33 Profile::FromBrowserContext(web_contents
->GetBrowserContext()),
35 content::WebContentsObserver(web_contents
),
36 requestor_url_(requestor_url
) {
39 WebstoreInlineInstaller::~WebstoreInlineInstaller() {}
42 bool WebstoreInlineInstaller::IsRequestorPermitted(
43 const base::DictionaryValue
& webstore_data
,
44 const GURL
& requestor_url
,
46 // Ensure that there is at least one verified site present.
47 const bool data_has_single_site
= webstore_data
.HasKey(kVerifiedSiteKey
);
48 const bool data_has_site_list
= webstore_data
.HasKey(kVerifiedSitesKey
);
49 if (!data_has_single_site
&& !data_has_site_list
) {
50 *error
= kNoVerifiedSitesError
;
53 bool requestor_is_ok
= false;
54 // Handle the deprecated single-site case.
55 if (!data_has_site_list
) {
56 std::string verified_site
;
57 if (!webstore_data
.GetString(kVerifiedSiteKey
, &verified_site
)) {
58 *error
= kInvalidWebstoreResponseError
;
61 requestor_is_ok
= IsRequestorURLInVerifiedSite(requestor_url
,
64 const base::ListValue
* verified_sites
= NULL
;
65 if (!webstore_data
.GetList(kVerifiedSitesKey
, &verified_sites
)) {
66 *error
= kInvalidWebstoreResponseError
;
69 for (base::ListValue::const_iterator it
= verified_sites
->begin();
70 it
!= verified_sites
->end() && !requestor_is_ok
; ++it
) {
71 std::string verified_site
;
72 if (!(*it
)->GetAsString(&verified_site
)) {
73 *error
= kInvalidWebstoreResponseError
;
76 if (IsRequestorURLInVerifiedSite(requestor_url
, verified_site
)) {
77 requestor_is_ok
= true;
81 if (!requestor_is_ok
) {
82 *error
= kNotFromVerifiedSitesError
;
89 bool WebstoreInlineInstaller::CheckRequestorAlive() const {
90 // The tab may have gone away - cancel installation in that case.
91 return web_contents() != NULL
;
94 const GURL
& WebstoreInlineInstaller::GetRequestorURL() const {
95 return requestor_url_
;
98 scoped_refptr
<ExtensionInstallPrompt::Prompt
>
99 WebstoreInlineInstaller::CreateInstallPrompt() const {
100 scoped_refptr
<ExtensionInstallPrompt::Prompt
> prompt(
101 new ExtensionInstallPrompt::Prompt(
102 ExtensionInstallPrompt::INLINE_INSTALL_PROMPT
));
104 // crbug.com/260742: Don't display the user count if it's zero. The reason
105 // it's zero is very often that the number isn't actually being counted
106 // (intentionally), which means that it's unlikely to be correct.
107 prompt
->SetWebstoreData(localized_user_count(),
114 bool WebstoreInlineInstaller::ShouldShowPostInstallUI() const {
118 bool WebstoreInlineInstaller::ShouldShowAppInstalledBubble() const {
122 WebContents
* WebstoreInlineInstaller::GetWebContents() const {
123 return web_contents();
126 bool WebstoreInlineInstaller::CheckInlineInstallPermitted(
127 const base::DictionaryValue
& webstore_data
,
128 std::string
* error
) const {
129 // The store may not support inline installs for this item, in which case
130 // we open the store-provided redirect URL in a new tab and abort the
131 // installation process.
132 bool inline_install_not_supported
= false;
133 if (webstore_data
.HasKey(kInlineInstallNotSupportedKey
)
134 && !webstore_data
.GetBoolean(kInlineInstallNotSupportedKey
,
135 &inline_install_not_supported
)) {
136 *error
= kInvalidWebstoreResponseError
;
139 if (inline_install_not_supported
) {
140 std::string redirect_url
;
141 if (!webstore_data
.GetString(kRedirectUrlKey
, &redirect_url
)) {
142 *error
= kInvalidWebstoreResponseError
;
145 web_contents()->OpenURL(content::OpenURLParams(
147 content::Referrer::SanitizeForRequest(
149 content::Referrer(web_contents()->GetURL(),
150 blink::WebReferrerPolicyDefault
)),
151 NEW_FOREGROUND_TAB
, ui::PAGE_TRANSITION_AUTO_BOOKMARK
, false));
152 *error
= kInlineInstallSupportedError
;
160 bool WebstoreInlineInstaller::CheckRequestorPermitted(
161 const base::DictionaryValue
& webstore_data
,
162 std::string
* error
) const {
163 return IsRequestorPermitted(webstore_data
, requestor_url_
, error
);
167 // Private implementation.
170 void WebstoreInlineInstaller::WebContentsDestroyed() {
175 bool WebstoreInlineInstaller::IsRequestorURLInVerifiedSite(
176 const GURL
& requestor_url
,
177 const std::string
& verified_site
) {
178 // Turn the verified site into a URL that can be parsed by URLPattern.
179 // |verified_site| must follow the format:
181 // [scheme://]host[:port][/path/specifier]
183 // If scheme is omitted, URLPattern will match against either an
184 // HTTP or HTTPS requestor. If scheme is specified, it must be either HTTP
185 // or HTTPS, and URLPattern will only match the scheme specified.
186 GURL
verified_site_url(verified_site
);
187 int valid_schemes
= URLPattern::SCHEME_HTTP
| URLPattern::SCHEME_HTTPS
;
188 if (!verified_site_url
.is_valid() || !verified_site_url
.IsStandard())
189 // If no scheme is specified, GURL will fail to parse the string correctly.
190 // It will either determine that the URL is invalid, or parse a
191 // host:port/path as scheme:host/path.
192 verified_site_url
= GURL("http://" + verified_site
);
193 else if (verified_site_url
.SchemeIs("http"))
194 valid_schemes
= URLPattern::SCHEME_HTTP
;
195 else if (verified_site_url
.SchemeIs("https"))
196 valid_schemes
= URLPattern::SCHEME_HTTPS
;
200 std::string port_spec
=
201 verified_site_url
.has_port() ? ":" + verified_site_url
.port() : "";
202 std::string path_spec
= verified_site_url
.path() + "*";
203 std::string verified_site_pattern_spec
=
206 verified_site_url
.scheme().c_str(),
207 verified_site_url
.host().c_str(),
211 URLPattern
verified_site_pattern(valid_schemes
);
212 URLPattern::ParseResult parse_result
=
213 verified_site_pattern
.Parse(verified_site_pattern_spec
);
214 if (parse_result
!= URLPattern::PARSE_SUCCESS
) {
215 DLOG(WARNING
) << "Could not parse " << verified_site_pattern_spec
<<
216 " as URL pattern " << parse_result
;
219 verified_site_pattern
.SetScheme("*");
221 return verified_site_pattern
.MatchesURL(requestor_url
);
224 } // namespace extensions