blob: 9f13c3cc5cec2d5c44d4bbbb24af36f67584554e [file] [log] [blame]
[email protected]bdb74a22012-01-25 20:33:331// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]8915f342011-08-29 22:14:372// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]734bcec2012-10-08 20:29:055#include "chrome/browser/extensions/webstore_standalone_installer.h"
[email protected]8915f342011-08-29 22:14:376
[email protected]8915f342011-08-29 22:14:377#include "base/values.h"
[email protected]8915f342011-08-29 22:14:378#include "chrome/browser/extensions/crx_installer.h"
[email protected]d44ec7b2013-03-15 04:34:349#include "chrome/browser/extensions/extension_install_prompt.h"
[email protected]00b38242012-07-18 18:43:2210#include "chrome/browser/extensions/extension_install_ui.h"
[email protected]655b2b1a2011-10-13 17:13:0611#include "chrome/browser/extensions/extension_service.h"
[email protected]7b3941052013-02-13 01:21:5912#include "chrome/browser/extensions/webstore_data_fetcher.h"
[email protected]8915f342011-08-29 22:14:3713#include "chrome/browser/profiles/profile.h"
[email protected]8915f342011-08-29 22:14:3714#include "chrome/common/extensions/extension.h"
[email protected]10c2d692012-05-11 05:32:2315#include "content/public/browser/web_contents.h"
[email protected]a6483d22013-07-03 22:11:0016#include "url/gurl.h"
[email protected]8915f342011-08-29 22:14:3717
[email protected]26b5e322011-12-23 01:36:4718using content::WebContents;
[email protected]631bb742011-11-02 11:29:3919
[email protected]3d61a7f2012-07-12 19:11:2520namespace extensions {
21
[email protected]8915f342011-08-29 22:14:3722const char kManifestKey[] = "manifest";
23const char kIconUrlKey[] = "icon_url";
24const char kLocalizedNameKey[] = "localized_name";
[email protected]5fdbd6f2011-09-01 17:33:0425const char kLocalizedDescriptionKey[] = "localized_description";
26const char kUsersKey[] = "users";
[email protected]dcde34b32013-07-31 02:28:4527const char kShowUserCountKey[] = "show_user_count";
[email protected]5fdbd6f2011-09-01 17:33:0428const char kAverageRatingKey[] = "average_rating";
29const char kRatingCountKey[] = "rating_count";
[email protected]8915f342011-08-29 22:14:3730
[email protected]a221ef092011-09-07 01:34:1031const char kInvalidWebstoreItemId[] = "Invalid Chrome Web Store item ID";
32const char kWebstoreRequestError[] =
33 "Could not fetch data from the Chrome Web Store";
34const char kInvalidWebstoreResponseError[] = "Invalid Chrome Web Store reponse";
[email protected]8915f342011-08-29 22:14:3735const char kInvalidManifestError[] = "Invalid manifest";
36const char kUserCancelledError[] = "User cancelled install";
[email protected]d44ec7b2013-03-15 04:34:3437
[email protected]8915f342011-08-29 22:14:3738
[email protected]734bcec2012-10-08 20:29:0539WebstoreStandaloneInstaller::WebstoreStandaloneInstaller(
[email protected]d44ec7b2013-03-15 04:34:3440 const std::string& webstore_item_id,
[email protected]c1b2d042013-02-23 00:31:0441 Profile* profile,
[email protected]c1b2d042013-02-23 00:31:0442 const Callback& callback)
[email protected]d44ec7b2013-03-15 04:34:3443 : id_(webstore_item_id),
[email protected]d2a639e2012-09-17 07:41:2144 callback_(callback),
[email protected]d44ec7b2013-03-15 04:34:3445 profile_(profile),
[email protected]084e35482013-09-25 02:46:1946 install_source_(WebstoreInstaller::INSTALL_SOURCE_INLINE),
[email protected]dcde34b32013-07-31 02:28:4547 show_user_count_(true),
[email protected]c7bf7452011-09-12 21:31:5048 average_rating_(0.0),
[email protected]5f2a4752012-04-27 22:18:5849 rating_count_(0) {
[email protected]c1b2d042013-02-23 00:31:0450 CHECK(!callback_.is_null());
51}
52
[email protected]d44ec7b2013-03-15 04:34:3453WebstoreStandaloneInstaller::~WebstoreStandaloneInstaller() {}
54
55//
56// Private interface implementation.
57//
[email protected]8915f342011-08-29 22:14:3758
[email protected]734bcec2012-10-08 20:29:0559void WebstoreStandaloneInstaller::BeginInstall() {
[email protected]3d6d676522013-10-14 20:44:5560 // Add a ref to keep this alive for WebstoreDataFetcher.
61 // All code paths from here eventually lead to either CompleteInstall or
62 // AbortInstall, which both release this ref.
63 AddRef();
[email protected]8915f342011-08-29 22:14:3764
[email protected]3d61a7f2012-07-12 19:11:2565 if (!Extension::IdIsValid(id_)) {
[email protected]8915f342011-08-29 22:14:3766 CompleteInstall(kInvalidWebstoreItemId);
67 return;
68 }
69
[email protected]b4574c02011-11-17 06:19:1370 // Use the requesting page as the referrer both since that is more correct
71 // (it is the page that caused this request to happen) and so that we can
72 // track top sites that trigger inline install requests.
[email protected]7b3941052013-02-13 01:21:5973 webstore_data_fetcher_.reset(new WebstoreDataFetcher(
74 this,
[email protected]c1b2d042013-02-23 00:31:0475 profile_->GetRequestContext(),
[email protected]d44ec7b2013-03-15 04:34:3476 GetRequestorURL(),
[email protected]7b3941052013-02-13 01:21:5977 id_));
78 webstore_data_fetcher_->Start();
[email protected]8915f342011-08-29 22:14:3779}
80
[email protected]f8b23b42013-06-27 20:12:1481scoped_ptr<ExtensionInstallPrompt>
82WebstoreStandaloneInstaller::CreateInstallUI() {
83 return make_scoped_ptr(new ExtensionInstallPrompt(GetWebContents()));
84}
85
[email protected]7b3941052013-02-13 01:21:5986void WebstoreStandaloneInstaller::OnWebstoreRequestFailure() {
87 CompleteInstall(kWebstoreRequestError);
[email protected]8915f342011-08-29 22:14:3788}
89
[email protected]734bcec2012-10-08 20:29:0590void WebstoreStandaloneInstaller::OnWebstoreResponseParseSuccess(
[email protected]b3188ec2013-11-06 10:26:1391 scoped_ptr<DictionaryValue> webstore_data) {
[email protected]d44ec7b2013-03-15 04:34:3492 if (!CheckRequestorAlive()) {
[email protected]007b3f82013-04-09 08:46:4593 CompleteInstall(std::string());
[email protected]4693243e2011-09-09 23:52:3794 return;
95 }
96
[email protected]d44ec7b2013-03-15 04:34:3497 std::string error;
[email protected]8915f342011-08-29 22:14:3798
[email protected]d44ec7b2013-03-15 04:34:3499 if (!CheckInlineInstallPermitted(*webstore_data, &error)) {
100 CompleteInstall(error);
[email protected]8915f342011-08-29 22:14:37101 return;
102 }
103
[email protected]d44ec7b2013-03-15 04:34:34104 if (!CheckRequestorPermitted(*webstore_data, &error)) {
105 CompleteInstall(error);
[email protected]dd5161a2011-09-14 17:40:17106 return;
107 }
108
109 // Manifest, number of users, average rating and rating count are required.
110 std::string manifest;
111 if (!webstore_data->GetString(kManifestKey, &manifest) ||
112 !webstore_data->GetString(kUsersKey, &localized_user_count_) ||
[email protected]5fdbd6f2011-09-01 17:33:04113 !webstore_data->GetDouble(kAverageRatingKey, &average_rating_) ||
114 !webstore_data->GetInteger(kRatingCountKey, &rating_count_)) {
115 CompleteInstall(kInvalidWebstoreResponseError);
116 return;
117 }
118
[email protected]dcde34b32013-07-31 02:28:45119 // Optional.
120 show_user_count_ = true;
121 webstore_data->GetBoolean(kShowUserCountKey, &show_user_count_);
122
[email protected]c82da8c42012-06-08 19:49:11123 if (average_rating_ < ExtensionInstallPrompt::kMinExtensionRating ||
124 average_rating_ > ExtensionInstallPrompt::kMaxExtensionRating) {
[email protected]5fdbd6f2011-09-01 17:33:04125 CompleteInstall(kInvalidWebstoreResponseError);
126 return;
127 }
128
129 // Localized name and description are optional.
130 if ((webstore_data->HasKey(kLocalizedNameKey) &&
131 !webstore_data->GetString(kLocalizedNameKey, &localized_name_)) ||
132 (webstore_data->HasKey(kLocalizedDescriptionKey) &&
133 !webstore_data->GetString(
134 kLocalizedDescriptionKey, &localized_description_))) {
[email protected]8915f342011-08-29 22:14:37135 CompleteInstall(kInvalidWebstoreResponseError);
136 return;
137 }
138
139 // Icon URL is optional.
140 GURL icon_url;
141 if (webstore_data->HasKey(kIconUrlKey)) {
142 std::string icon_url_string;
143 if (!webstore_data->GetString(kIconUrlKey, &icon_url_string)) {
144 CompleteInstall(kInvalidWebstoreResponseError);
145 return;
146 }
147 icon_url = GURL(extension_urls::GetWebstoreLaunchURL()).Resolve(
148 icon_url_string);
149 if (!icon_url.is_valid()) {
150 CompleteInstall(kInvalidWebstoreResponseError);
151 return;
152 }
153 }
154
[email protected]d44ec7b2013-03-15 04:34:34155 // Assume ownership of webstore_data.
[email protected]b3188ec2013-11-06 10:26:13156 webstore_data_ = webstore_data.Pass();
[email protected]a221ef092011-09-07 01:34:10157
[email protected]007b3f82013-04-09 08:46:45158 scoped_refptr<WebstoreInstallHelper> helper =
159 new WebstoreInstallHelper(this,
160 id_,
161 manifest,
162 std::string(), // We don't have any icon data.
163 icon_url,
164 profile_->GetRequestContext());
[email protected]8915f342011-08-29 22:14:37165 // The helper will call us back via OnWebstoreParseSucces or
166 // OnWebstoreParseFailure.
167 helper->Start();
168}
169
[email protected]734bcec2012-10-08 20:29:05170void WebstoreStandaloneInstaller::OnWebstoreResponseParseFailure(
[email protected]8915f342011-08-29 22:14:37171 const std::string& error) {
172 CompleteInstall(error);
173}
174
[email protected]734bcec2012-10-08 20:29:05175void WebstoreStandaloneInstaller::OnWebstoreParseSuccess(
[email protected]98e4e522011-10-25 13:00:16176 const std::string& id,
[email protected]8915f342011-08-29 22:14:37177 const SkBitmap& icon,
178 base::DictionaryValue* manifest) {
[email protected]d44ec7b2013-03-15 04:34:34179 CHECK_EQ(id_, id);
180
181 if (!CheckRequestorAlive()) {
[email protected]007b3f82013-04-09 08:46:45182 CompleteInstall(std::string());
[email protected]2fd920fb2011-09-08 23:33:00183 return;
184 }
185
[email protected]8915f342011-08-29 22:14:37186 manifest_.reset(manifest);
187 icon_ = icon;
188
[email protected]d44ec7b2013-03-15 04:34:34189 install_prompt_ = CreateInstallPrompt();
190 if (install_prompt_) {
[email protected]f8b23b42013-06-27 20:12:14191 ShowInstallUI();
[email protected]d44ec7b2013-03-15 04:34:34192 // Control flow finishes up in InstallUIProceed or InstallUIAbort.
193 } else {
[email protected]3d6d676522013-10-14 20:44:55194 // Balanced in InstallUIAbort or indirectly in InstallUIProceed via
195 // OnExtensionInstallSuccess or OnExtensionInstallFailure.
196 AddRef();
[email protected]77e9261d2013-02-04 22:01:47197 InstallUIProceed();
[email protected]77e9261d2013-02-04 22:01:47198 }
[email protected]8915f342011-08-29 22:14:37199}
200
[email protected]734bcec2012-10-08 20:29:05201void WebstoreStandaloneInstaller::OnWebstoreParseFailure(
[email protected]98e4e522011-10-25 13:00:16202 const std::string& id,
[email protected]8915f342011-08-29 22:14:37203 InstallHelperResultCode result_code,
204 const std::string& error_message) {
205 CompleteInstall(error_message);
206}
207
[email protected]734bcec2012-10-08 20:29:05208void WebstoreStandaloneInstaller::InstallUIProceed() {
[email protected]d44ec7b2013-03-15 04:34:34209 if (!CheckRequestorAlive()) {
[email protected]007b3f82013-04-09 08:46:45210 CompleteInstall(std::string());
[email protected]2fd920fb2011-09-08 23:33:00211 return;
212 }
213
[email protected]21a5ad62012-04-03 04:48:45214 scoped_ptr<WebstoreInstaller::Approval> approval(
[email protected]89019d62012-05-17 18:47:09215 WebstoreInstaller::Approval::CreateWithNoInstallPrompt(
[email protected]c1b2d042013-02-23 00:31:04216 profile_,
[email protected]89019d62012-05-17 18:47:09217 id_,
[email protected]85290822013-08-23 20:27:38218 scoped_ptr<base::DictionaryValue>(manifest_.get()->DeepCopy()),
219 true));
[email protected]d44ec7b2013-03-15 04:34:34220 approval->skip_post_install_ui = !ShouldShowPostInstallUI();
221 approval->use_app_installed_bubble = ShouldShowAppInstalledBubble();
[email protected]28e910e2013-08-23 04:18:33222 approval->installing_icon = gfx::ImageSkia::CreateFrom1xBitmap(icon_);
[email protected]21a5ad62012-04-03 04:48:45223
[email protected]98e4e522011-10-25 13:00:16224 scoped_refptr<WebstoreInstaller> installer = new WebstoreInstaller(
[email protected]d44ec7b2013-03-15 04:34:34225 profile_,
226 this,
227 &(GetWebContents()->GetController()),
228 id_,
229 approval.Pass(),
[email protected]084e35482013-09-25 02:46:19230 install_source_);
[email protected]98e4e522011-10-25 13:00:16231 installer->Start();
[email protected]8915f342011-08-29 22:14:37232}
233
[email protected]734bcec2012-10-08 20:29:05234void WebstoreStandaloneInstaller::InstallUIAbort(bool user_initiated) {
[email protected]8915f342011-08-29 22:14:37235 CompleteInstall(kUserCancelledError);
[email protected]3d6d676522013-10-14 20:44:55236 Release(); // Balanced in ShowInstallUI.
[email protected]8915f342011-08-29 22:14:37237}
238
[email protected]734bcec2012-10-08 20:29:05239void WebstoreStandaloneInstaller::OnExtensionInstallSuccess(
240 const std::string& id) {
[email protected]cb08ba22011-10-19 21:41:40241 CHECK_EQ(id_, id);
[email protected]007b3f82013-04-09 08:46:45242 CompleteInstall(std::string());
[email protected]3d6d676522013-10-14 20:44:55243 Release(); // Balanced in ShowInstallUI.
[email protected]cb08ba22011-10-19 21:41:40244}
245
[email protected]734bcec2012-10-08 20:29:05246void WebstoreStandaloneInstaller::OnExtensionInstallFailure(
[email protected]bcd1eaf72012-10-03 05:42:29247 const std::string& id,
248 const std::string& error,
249 WebstoreInstaller::FailureReason cancelled) {
[email protected]cb08ba22011-10-19 21:41:40250 CHECK_EQ(id_, id);
251 CompleteInstall(error);
[email protected]3d6d676522013-10-14 20:44:55252 Release(); // Balanced in ShowInstallUI.
[email protected]cb08ba22011-10-19 21:41:40253}
254
[email protected]d44ec7b2013-03-15 04:34:34255void WebstoreStandaloneInstaller::AbortInstall() {
256 callback_.Reset();
257 // Abort any in-progress fetches.
[email protected]3eeddd892013-04-17 17:00:11258 if (webstore_data_fetcher_) {
[email protected]d44ec7b2013-03-15 04:34:34259 webstore_data_fetcher_.reset();
260 Release(); // Matches the AddRef in BeginInstall.
261 }
262}
263
[email protected]734bcec2012-10-08 20:29:05264void WebstoreStandaloneInstaller::CompleteInstall(const std::string& error) {
[email protected]d2a639e2012-09-17 07:41:21265 if (!callback_.is_null())
266 callback_.Run(error.empty(), error);
[email protected]5db2e882012-12-20 10:17:26267 Release(); // Matches the AddRef in BeginInstall.
[email protected]8915f342011-08-29 22:14:37268}
[email protected]5f2a4752012-04-27 22:18:58269
[email protected]d44ec7b2013-03-15 04:34:34270void
[email protected]f8b23b42013-06-27 20:12:14271WebstoreStandaloneInstaller::ShowInstallUI() {
[email protected]d44ec7b2013-03-15 04:34:34272 std::string error;
273 localized_extension_for_display_ =
274 ExtensionInstallPrompt::GetLocalizedExtensionForDisplay(
275 manifest_.get(),
276 Extension::REQUIRE_KEY | Extension::FROM_WEBSTORE,
277 id_,
278 localized_name_,
279 localized_description_,
280 &error);
[email protected]dc24976f2013-06-02 21:15:09281 if (!localized_extension_for_display_.get()) {
[email protected]d44ec7b2013-03-15 04:34:34282 CompleteInstall(kInvalidManifestError);
283 return;
[email protected]5f2a4752012-04-27 22:18:58284 }
[email protected]5f2a4752012-04-27 22:18:58285
[email protected]3d6d676522013-10-14 20:44:55286 // Keep this alive as long as the install prompt lives.
287 // Balanced in InstallUIAbort or indirectly in InstallUIProceed via
288 // OnExtensionInstallSuccess or OnExtensionInstallFailure.
289 AddRef();
290
[email protected]f8b23b42013-06-27 20:12:14291 install_ui_ = CreateInstallUI();
[email protected]dc24976f2013-06-02 21:15:09292 install_ui_->ConfirmStandaloneInstall(
293 this, localized_extension_for_display_.get(), &icon_, *install_prompt_);
[email protected]5f2a4752012-04-27 22:18:58294}
[email protected]3d61a7f2012-07-12 19:11:25295
296} // namespace extensions