Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / webstore_standalone_installer.cc
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.
4
5 #include "chrome/browser/extensions/webstore_standalone_installer.h"
6
7 #include "base/values.h"
8 #include "chrome/browser/extensions/crx_installer.h"
9 #include "chrome/browser/extensions/extension_install_prompt.h"
10 #include "chrome/browser/extensions/extension_install_ui.h"
11 #include "chrome/browser/extensions/extension_service.h"
12 #include "chrome/browser/extensions/webstore_data_fetcher.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "content/public/browser/web_contents.h"
15 #include "extensions/browser/extension_prefs.h"
16 #include "extensions/browser/extension_system.h"
17 #include "extensions/common/extension.h"
18 #include "url/gurl.h"
19
20 using content::WebContents;
21
22 namespace extensions {
23
24 const char kInvalidWebstoreItemId[] = "Invalid Chrome Web Store item ID";
25 const char kWebstoreRequestError[] =
26     "Could not fetch data from the Chrome Web Store";
27 const char kInvalidWebstoreResponseError[] = "Invalid Chrome Web Store reponse";
28 const char kInvalidManifestError[] = "Invalid manifest";
29 const char kUserCancelledError[] = "User cancelled install";
30 const char kExtensionIsBlacklisted[] = "Extension is blacklisted";
31
32 WebstoreStandaloneInstaller::WebstoreStandaloneInstaller(
33     const std::string& webstore_item_id,
34     Profile* profile,
35     const Callback& callback)
36     : id_(webstore_item_id),
37       callback_(callback),
38       profile_(profile),
39       install_source_(WebstoreInstaller::INSTALL_SOURCE_INLINE),
40       show_user_count_(true),
41       average_rating_(0.0),
42       rating_count_(0) {
43 }
44
45 WebstoreStandaloneInstaller::~WebstoreStandaloneInstaller() {}
46
47 //
48 // Private interface implementation.
49 //
50
51 void WebstoreStandaloneInstaller::BeginInstall() {
52   // Add a ref to keep this alive for WebstoreDataFetcher.
53   // All code paths from here eventually lead to either CompleteInstall or
54   // AbortInstall, which both release this ref.
55   AddRef();
56
57   if (!Extension::IdIsValid(id_)) {
58     CompleteInstall(kInvalidWebstoreItemId);
59     return;
60   }
61
62   // Use the requesting page as the referrer both since that is more correct
63   // (it is the page that caused this request to happen) and so that we can
64   // track top sites that trigger inline install requests.
65   webstore_data_fetcher_.reset(new WebstoreDataFetcher(
66       this,
67       profile_->GetRequestContext(),
68       GetRequestorURL(),
69       id_));
70   webstore_data_fetcher_->Start();
71 }
72
73 bool WebstoreStandaloneInstaller::CheckInstallValid(
74     const base::DictionaryValue& manifest,
75     std::string* error) {
76   return true;
77 }
78
79 scoped_ptr<ExtensionInstallPrompt>
80 WebstoreStandaloneInstaller::CreateInstallUI() {
81   return make_scoped_ptr(new ExtensionInstallPrompt(GetWebContents()));
82 }
83
84 scoped_ptr<WebstoreInstaller::Approval>
85 WebstoreStandaloneInstaller::CreateApproval() const {
86   scoped_ptr<WebstoreInstaller::Approval> approval(
87       WebstoreInstaller::Approval::CreateWithNoInstallPrompt(
88           profile_,
89           id_,
90           scoped_ptr<base::DictionaryValue>(manifest_.get()->DeepCopy()),
91           true));
92   approval->skip_post_install_ui = !ShouldShowPostInstallUI();
93   approval->use_app_installed_bubble = ShouldShowAppInstalledBubble();
94   approval->installing_icon = gfx::ImageSkia::CreateFrom1xBitmap(icon_);
95   return approval.Pass();
96 }
97
98 void WebstoreStandaloneInstaller::OnWebstoreRequestFailure() {
99   CompleteInstall(kWebstoreRequestError);
100 }
101
102 void WebstoreStandaloneInstaller::OnWebstoreResponseParseSuccess(
103     scoped_ptr<base::DictionaryValue> webstore_data) {
104   if (!CheckRequestorAlive()) {
105     CompleteInstall(std::string());
106     return;
107   }
108
109   std::string error;
110
111   if (!CheckInlineInstallPermitted(*webstore_data, &error)) {
112     CompleteInstall(error);
113     return;
114   }
115
116   if (!CheckRequestorPermitted(*webstore_data, &error)) {
117     CompleteInstall(error);
118     return;
119   }
120
121   // Manifest, number of users, average rating and rating count are required.
122   std::string manifest;
123   if (!webstore_data->GetString(kManifestKey, &manifest) ||
124       !webstore_data->GetString(kUsersKey, &localized_user_count_) ||
125       !webstore_data->GetDouble(kAverageRatingKey, &average_rating_) ||
126       !webstore_data->GetInteger(kRatingCountKey, &rating_count_)) {
127     CompleteInstall(kInvalidWebstoreResponseError);
128     return;
129   }
130
131   // Optional.
132   show_user_count_ = true;
133   webstore_data->GetBoolean(kShowUserCountKey, &show_user_count_);
134
135   if (average_rating_ < ExtensionInstallPrompt::kMinExtensionRating ||
136       average_rating_ > ExtensionInstallPrompt::kMaxExtensionRating) {
137     CompleteInstall(kInvalidWebstoreResponseError);
138     return;
139   }
140
141   // Localized name and description are optional.
142   if ((webstore_data->HasKey(kLocalizedNameKey) &&
143       !webstore_data->GetString(kLocalizedNameKey, &localized_name_)) ||
144       (webstore_data->HasKey(kLocalizedDescriptionKey) &&
145       !webstore_data->GetString(
146           kLocalizedDescriptionKey, &localized_description_))) {
147     CompleteInstall(kInvalidWebstoreResponseError);
148     return;
149   }
150
151   // Icon URL is optional.
152   GURL icon_url;
153   if (webstore_data->HasKey(kIconUrlKey)) {
154     std::string icon_url_string;
155     if (!webstore_data->GetString(kIconUrlKey, &icon_url_string)) {
156       CompleteInstall(kInvalidWebstoreResponseError);
157       return;
158     }
159     icon_url = GURL(extension_urls::GetWebstoreLaunchURL()).Resolve(
160         icon_url_string);
161     if (!icon_url.is_valid()) {
162       CompleteInstall(kInvalidWebstoreResponseError);
163       return;
164     }
165   }
166
167   // Assume ownership of webstore_data.
168   webstore_data_ = webstore_data.Pass();
169
170   scoped_refptr<WebstoreInstallHelper> helper =
171       new WebstoreInstallHelper(this,
172                                 id_,
173                                 manifest,
174                                 std::string(),  // We don't have any icon data.
175                                 icon_url,
176                                 profile_->GetRequestContext());
177   // The helper will call us back via OnWebstoreParseSucces or
178   // OnWebstoreParseFailure.
179   helper->Start();
180 }
181
182 void WebstoreStandaloneInstaller::OnWebstoreResponseParseFailure(
183     const std::string& error) {
184   CompleteInstall(error);
185 }
186
187 void WebstoreStandaloneInstaller::OnWebstoreParseSuccess(
188     const std::string& id,
189     const SkBitmap& icon,
190     base::DictionaryValue* manifest) {
191   CHECK_EQ(id_, id);
192
193   if (!CheckRequestorAlive()) {
194     CompleteInstall(std::string());
195     return;
196   }
197
198   manifest_.reset(manifest);
199   icon_ = icon;
200
201   std::string error;
202   if (!CheckInstallValid(*manifest, &error)) {
203     DCHECK(!error.empty());
204     CompleteInstall(error);
205     return;
206   }
207
208   install_prompt_ = CreateInstallPrompt();
209   if (install_prompt_) {
210     ShowInstallUI();
211     // Control flow finishes up in InstallUIProceed or InstallUIAbort.
212   } else {
213     // Balanced in InstallUIAbort or indirectly in InstallUIProceed via
214     // OnExtensionInstallSuccess or OnExtensionInstallFailure.
215     AddRef();
216     InstallUIProceed();
217   }
218 }
219
220 void WebstoreStandaloneInstaller::OnWebstoreParseFailure(
221     const std::string& id,
222     InstallHelperResultCode result_code,
223     const std::string& error_message) {
224   CompleteInstall(error_message);
225 }
226
227 void WebstoreStandaloneInstaller::InstallUIProceed() {
228   if (!CheckRequestorAlive()) {
229     CompleteInstall(std::string());
230     return;
231   }
232
233   ExtensionService* extension_service =
234       ExtensionSystem::Get(profile_)->extension_service();
235   const Extension* extension =
236       extension_service->GetExtensionById(id_, true /* include disabled */);
237   if (extension) {
238     std::string install_result;  // Empty string for install success.
239     if (!extension_service->IsExtensionEnabled(id_)) {
240       if (!ExtensionPrefs::Get(profile_)->IsExtensionBlacklisted(id_)) {
241         // If the extension is installed but disabled, and not blacklisted,
242         // enable it.
243         extension_service->EnableExtension(id_);
244       } else {  // Don't install a blacklisted extension.
245         install_result = kExtensionIsBlacklisted;
246       }
247     }  // else extension is installed and enabled; no work to be done.
248     CompleteInstall(install_result);
249     return;
250   }
251
252   scoped_ptr<WebstoreInstaller::Approval> approval = CreateApproval();
253
254   scoped_refptr<WebstoreInstaller> installer = new WebstoreInstaller(
255       profile_,
256       this,
257       GetWebContents(),
258       id_,
259       approval.Pass(),
260       install_source_);
261   installer->Start();
262 }
263
264 void WebstoreStandaloneInstaller::InstallUIAbort(bool user_initiated) {
265   CompleteInstall(kUserCancelledError);
266   Release();  // Balanced in ShowInstallUI.
267 }
268
269 void WebstoreStandaloneInstaller::OnExtensionInstallSuccess(
270     const std::string& id) {
271   CHECK_EQ(id_, id);
272   CompleteInstall(std::string());
273   Release();  // Balanced in ShowInstallUI.
274 }
275
276 void WebstoreStandaloneInstaller::OnExtensionInstallFailure(
277     const std::string& id,
278     const std::string& error,
279     WebstoreInstaller::FailureReason cancelled) {
280   CHECK_EQ(id_, id);
281   CompleteInstall(error);
282   Release();  // Balanced in ShowInstallUI.
283 }
284
285 void WebstoreStandaloneInstaller::AbortInstall() {
286   callback_.Reset();
287   // Abort any in-progress fetches.
288   if (webstore_data_fetcher_) {
289     webstore_data_fetcher_.reset();
290     Release();  // Matches the AddRef in BeginInstall.
291   }
292 }
293
294 void WebstoreStandaloneInstaller::InvokeCallback(const std::string& error) {
295   if (!callback_.is_null())
296     callback_.Run(error.empty(), error);
297 }
298
299 void WebstoreStandaloneInstaller::CompleteInstall(const std::string& error) {
300   InvokeCallback(error);
301   Release();  // Matches the AddRef in BeginInstall.
302 }
303
304 void
305 WebstoreStandaloneInstaller::ShowInstallUI() {
306   std::string error;
307   localized_extension_for_display_ =
308       ExtensionInstallPrompt::GetLocalizedExtensionForDisplay(
309           manifest_.get(),
310           Extension::REQUIRE_KEY | Extension::FROM_WEBSTORE,
311           id_,
312           localized_name_,
313           localized_description_,
314           &error);
315   if (!localized_extension_for_display_.get()) {
316     CompleteInstall(kInvalidManifestError);
317     return;
318   }
319
320   // Keep this alive as long as the install prompt lives.
321   // Balanced in InstallUIAbort or indirectly in InstallUIProceed via
322   // OnExtensionInstallSuccess or OnExtensionInstallFailure.
323   AddRef();
324
325   install_ui_ = CreateInstallUI();
326   install_ui_->ConfirmStandaloneInstall(
327       this, localized_extension_for_display_.get(), &icon_, *install_prompt_);
328 }
329
330 }  // namespace extensions