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 kVerifiedSiteKey
[] = "verified_site";
16 const char kVerifiedSitesKey
[] = "verified_sites";
17 const char kInlineInstallNotSupportedKey
[] = "inline_install_not_supported";
18 const char kRedirectUrlKey
[] = "redirect_url";
20 const char kInvalidWebstoreResponseError
[] = "Invalid Chrome Web Store reponse";
21 const char kNoVerifiedSitesError
[] =
22 "Inline installs can only be initiated for Chrome Web Store items that "
23 "have one or more verified sites";
24 const char kNotFromVerifiedSitesError
[] =
25 "Installs can only be initiated by one of the Chrome Web Store item's "
27 const char kInlineInstallSupportedError
[] =
28 "Inline installation is not supported for this item. The user will be "
29 "redirected to the Chrome Web Store.";
31 WebstoreInlineInstaller::WebstoreInlineInstaller(
32 content::WebContents
* web_contents
,
33 const std::string
& webstore_item_id
,
34 const GURL
& requestor_url
,
35 const Callback
& callback
)
36 : WebstoreStandaloneInstaller(
38 Profile::FromBrowserContext(web_contents
->GetBrowserContext()),
40 content::WebContentsObserver(web_contents
),
41 requestor_url_(requestor_url
) {
44 WebstoreInlineInstaller::~WebstoreInlineInstaller() {}
46 bool WebstoreInlineInstaller::CheckRequestorAlive() const {
47 // The tab may have gone away - cancel installation in that case.
48 return web_contents() != NULL
;
51 const GURL
& WebstoreInlineInstaller::GetRequestorURL() const {
52 return requestor_url_
;
55 scoped_ptr
<ExtensionInstallPrompt::Prompt
>
56 WebstoreInlineInstaller::CreateInstallPrompt() const {
57 scoped_ptr
<ExtensionInstallPrompt::Prompt
> prompt(
58 new ExtensionInstallPrompt::Prompt(
59 ExtensionInstallPrompt::INLINE_INSTALL_PROMPT
));
61 // crbug.com/260742: Don't display the user count if it's zero. The reason
62 // it's zero is very often that the number isn't actually being counted
63 // (intentionally), which means that it's unlikely to be correct.
64 prompt
->SetInlineInstallWebstoreData(localized_user_count(),
71 bool WebstoreInlineInstaller::ShouldShowPostInstallUI() const {
75 bool WebstoreInlineInstaller::ShouldShowAppInstalledBubble() const {
79 WebContents
* WebstoreInlineInstaller::GetWebContents() const {
80 return web_contents();
83 bool WebstoreInlineInstaller::CheckInlineInstallPermitted(
84 const base::DictionaryValue
& webstore_data
,
85 std::string
* error
) const {
86 // The store may not support inline installs for this item, in which case
87 // we open the store-provided redirect URL in a new tab and abort the
88 // installation process.
89 bool inline_install_not_supported
= false;
90 if (webstore_data
.HasKey(kInlineInstallNotSupportedKey
)
91 && !webstore_data
.GetBoolean(kInlineInstallNotSupportedKey
,
92 &inline_install_not_supported
)) {
93 *error
= kInvalidWebstoreResponseError
;
96 if (inline_install_not_supported
) {
97 std::string redirect_url
;
98 if (!webstore_data
.GetString(kRedirectUrlKey
, &redirect_url
)) {
99 *error
= kInvalidWebstoreResponseError
;
102 web_contents()->OpenURL(
103 content::OpenURLParams(
105 content::Referrer(web_contents()->GetURL(),
106 blink::WebReferrerPolicyDefault
),
107 NEW_FOREGROUND_TAB
, content::PAGE_TRANSITION_AUTO_BOOKMARK
, false));
108 *error
= kInlineInstallSupportedError
;
116 bool WebstoreInlineInstaller::CheckRequestorPermitted(
117 const base::DictionaryValue
& webstore_data
,
118 std::string
* error
) const {
119 // Ensure that there is at least one verified site present.
120 const bool data_has_single_site
= webstore_data
.HasKey(kVerifiedSiteKey
);
121 const bool data_has_site_list
= webstore_data
.HasKey(kVerifiedSitesKey
);
122 if (!data_has_single_site
&& !data_has_site_list
) {
123 *error
= kNoVerifiedSitesError
;
126 bool requestor_is_ok
= false;
127 // Handle the deprecated single-site case.
128 if (!data_has_site_list
) {
129 std::string verified_site
;
130 if (!webstore_data
.GetString(kVerifiedSiteKey
, &verified_site
)) {
131 *error
= kInvalidWebstoreResponseError
;
134 requestor_is_ok
= IsRequestorURLInVerifiedSite(requestor_url_
,
137 const base::ListValue
* verified_sites
= NULL
;
138 if (!webstore_data
.GetList(kVerifiedSitesKey
, &verified_sites
)) {
139 *error
= kInvalidWebstoreResponseError
;
142 for (base::ListValue::const_iterator it
= verified_sites
->begin();
143 it
!= verified_sites
->end() && !requestor_is_ok
; ++it
) {
144 std::string verified_site
;
145 if (!(*it
)->GetAsString(&verified_site
)) {
146 *error
= kInvalidWebstoreResponseError
;
149 if (IsRequestorURLInVerifiedSite(requestor_url_
, verified_site
)) {
150 requestor_is_ok
= true;
154 if (!requestor_is_ok
) {
155 *error
= kNotFromVerifiedSitesError
;
163 // Private implementation.
166 void WebstoreInlineInstaller::WebContentsDestroyed(
167 content::WebContents
* web_contents
) {
172 bool WebstoreInlineInstaller::IsRequestorURLInVerifiedSite(
173 const GURL
& requestor_url
,
174 const std::string
& verified_site
) {
175 // Turn the verified site into a URL that can be parsed by URLPattern.
176 // |verified_site| must follow the format:
178 // [scheme://]host[:port][/path/specifier]
180 // If scheme is omitted, URLPattern will match against either an
181 // HTTP or HTTPS requestor. If scheme is specified, it must be either HTTP
182 // or HTTPS, and URLPattern will only match the scheme specified.
183 GURL
verified_site_url(verified_site
);
184 int valid_schemes
= URLPattern::SCHEME_HTTP
| URLPattern::SCHEME_HTTPS
;
185 if (!verified_site_url
.is_valid() || !verified_site_url
.IsStandard())
186 // If no scheme is specified, GURL will fail to parse the string correctly.
187 // It will either determine that the URL is invalid, or parse a
188 // host:port/path as scheme:host/path.
189 verified_site_url
= GURL("http://" + verified_site
);
190 else if (verified_site_url
.SchemeIs("http"))
191 valid_schemes
= URLPattern::SCHEME_HTTP
;
192 else if (verified_site_url
.SchemeIs("https"))
193 valid_schemes
= URLPattern::SCHEME_HTTPS
;
197 std::string port_spec
=
198 verified_site_url
.has_port() ? ":" + verified_site_url
.port() : "";
199 std::string path_spec
= verified_site_url
.path() + "*";
200 std::string verified_site_pattern_spec
=
203 verified_site_url
.scheme().c_str(),
204 verified_site_url
.host().c_str(),
208 URLPattern
verified_site_pattern(valid_schemes
);
209 URLPattern::ParseResult parse_result
=
210 verified_site_pattern
.Parse(verified_site_pattern_spec
);
211 if (parse_result
!= URLPattern::PARSE_SUCCESS
) {
212 DLOG(WARNING
) << "Could not parse " << verified_site_pattern_spec
<<
213 " as URL pattern " << parse_result
;
216 verified_site_pattern
.SetScheme("*");
218 return verified_site_pattern
.MatchesURL(requestor_url
);
221 } // namespace extensions