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 "
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(
37 Profile::FromBrowserContext(web_contents
->GetBrowserContext()),
39 content::WebContentsObserver(web_contents
),
40 requestor_url_(requestor_url
) {
43 WebstoreInlineInstaller::~WebstoreInlineInstaller() {}
46 bool WebstoreInlineInstaller::IsRequestorPermitted(
47 const base::DictionaryValue
& webstore_data
,
48 const GURL
& requestor_url
,
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
;
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
;
65 requestor_is_ok
= IsRequestorURLInVerifiedSite(requestor_url
,
68 const base::ListValue
* verified_sites
= NULL
;
69 if (!webstore_data
.GetList(kVerifiedSitesKey
, &verified_sites
)) {
70 *error
= kInvalidWebstoreResponseError
;
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
;
80 if (IsRequestorURLInVerifiedSite(requestor_url
, verified_site
)) {
81 requestor_is_ok
= true;
85 if (!requestor_is_ok
) {
86 *error
= kNotFromVerifiedSitesError
;
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(),
118 bool WebstoreInlineInstaller::ShouldShowPostInstallUI() const {
122 bool WebstoreInlineInstaller::ShouldShowAppInstalledBubble() const {
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());
135 if (browser
->is_type_popup()) {
136 *error
= kInitiatedFromPopupError
;
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
;
149 if (inline_install_not_supported
) {
150 std::string redirect_url
;
151 if (!webstore_data
.GetString(kRedirectUrlKey
, &redirect_url
)) {
152 *error
= kInvalidWebstoreResponseError
;
155 web_contents()->OpenURL(content::OpenURLParams(
157 content::Referrer::SanitizeForRequest(
159 content::Referrer(web_contents()->GetURL(),
160 blink::WebReferrerPolicyDefault
)),
161 NEW_FOREGROUND_TAB
, ui::PAGE_TRANSITION_AUTO_BOOKMARK
, false));
162 *error
= kInlineInstallSupportedError
;
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() {
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
;
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
=
215 verified_site_url
.scheme().c_str(),
216 verified_site_url
.host().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
;
228 verified_site_pattern
.SetScheme("*");
230 return verified_site_pattern
.MatchesURL(requestor_url
);
233 } // namespace extensions