1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen// Use of this source code is governed by a BSD-style license that can be
3bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen// found in the LICENSE file.
4bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
5bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "chrome/browser/extensions/extension_webstore_private_api.h"
6bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
7731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include <string>
8731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include <vector>
9731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
10ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/scoped_temp_dir.h"
11bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "base/string_util.h"
12bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "base/values.h"
13bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "chrome/browser/browser_process.h"
14bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "chrome/browser/extensions/crx_installer.h"
15ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/extensions/extension_install_dialog.h"
16bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "chrome/browser/extensions/extension_prefs.h"
1721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/extensions/extension_service.h"
18513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "chrome/browser/net/gaia/token_service.h"
1921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile_manager.h"
20bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "chrome/browser/sync/profile_sync_service.h"
214a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "chrome/common/chrome_switches.h"
22bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "chrome/common/extensions/extension_constants.h"
234a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "chrome/common/extensions/extension_error_utils.h"
24513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "chrome/common/net/gaia/gaia_constants.h"
25dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/tab_contents/tab_contents.h"
26ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_details.h"
27ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_source.h"
28ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_type.h"
29513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "grit/chromium_strings.h"
30513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "grit/generated_resources.h"
31bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen#include "net/base/escape.h"
3272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/l10n/l10n_util.h"
33bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
34bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsennamespace {
35bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
36731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickconst char kLoginKey[] = "login";
37731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickconst char kTokenKey[] = "token";
38ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenconst char kImageDecodeError[] = "Image decode failed";
394a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochconst char kInvalidIdError[] = "Invalid id";
40ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenconst char kInvalidManifestError[] = "Invalid manifest";
414a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochconst char kNoPreviousBeginInstallError[] =
424a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    "* does not match a previous call to beginInstall";
43ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenconst char kUserCancelledError[] = "User cancelled install";
444a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochconst char kUserGestureRequiredError[] =
454a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    "This function must be called during a user gesture";
46731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
47731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickProfileSyncService* test_sync_service = NULL;
48513209b27ff55e2841eac0e4120199c23acce758Ben MurdochBrowserSignin* test_signin = NULL;
494a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochbool ignore_user_gesture_for_tests = false;
50731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
51731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// Returns either the test sync service, or the real one from |profile|.
52731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickProfileSyncService* GetSyncService(Profile* profile) {
53731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (test_sync_service)
54731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return test_sync_service;
55731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  else
56731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return profile->GetProfileSyncService();
57731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
58bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
59513209b27ff55e2841eac0e4120199c23acce758Ben MurdochBrowserSignin* GetBrowserSignin(Profile* profile) {
60513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (test_signin)
61513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return test_signin;
62513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  else
63513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return profile->GetBrowserSignin();
64513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
65513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
66731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool IsWebStoreURL(Profile* profile, const GURL& url) {
6721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  ExtensionService* service = profile->GetExtensionService();
68513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  const Extension* store = service->GetWebStoreApp();
694a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (!store) {
704a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    NOTREACHED();
714a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    return false;
724a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  }
73731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return (service->GetExtensionByWebExtent(url) == store);
74bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}
75bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
76513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// Helper to create a dictionary with login and token properties set from
77513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// the appropriate values in the passed-in |profile|.
78513209b27ff55e2841eac0e4120199c23acce758Ben MurdochDictionaryValue* CreateLoginResult(Profile* profile) {
79513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DictionaryValue* dictionary = new DictionaryValue();
80513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  std::string username = GetBrowserSignin(profile)->GetSignedInUsername();
81513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  dictionary->SetString(kLoginKey, username);
82513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!username.empty()) {
834a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    CommandLine* cmdline = CommandLine::ForCurrentProcess();
84513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    TokenService* token_service = profile->GetTokenService();
854a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    if (cmdline->HasSwitch(switches::kAppsGalleryReturnTokens) &&
864a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch        token_service->HasTokenForService(GaiaConstants::kGaiaService)) {
87513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      dictionary->SetString(kTokenKey,
88513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                            token_service->GetTokenForService(
89513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                GaiaConstants::kGaiaService));
90513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    }
91513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
92513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return dictionary;
93513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
94513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
95ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// If |profile| is not incognito, returns it. Otherwise returns the real
96ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// (not incognito) default profile.
97513209b27ff55e2841eac0e4120199c23acce758Ben MurdochProfile* GetDefaultProfile(Profile* profile) {
98513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!profile->IsOffTheRecord())
99513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return profile;
100513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  else
101513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return g_browser_process->profile_manager()->GetDefaultProfile();
102513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
103513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
104731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}  // namespace
105bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
106731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// static
107731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid WebstorePrivateApi::SetTestingProfileSyncService(
108731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    ProfileSyncService* service) {
109731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  test_sync_service = service;
110bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}
111bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
112bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen// static
113513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid WebstorePrivateApi::SetTestingBrowserSignin(BrowserSignin* signin) {
114513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  test_signin = signin;
115513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
116513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
117513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// static
1184a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochvoid BeginInstallFunction::SetIgnoreUserGestureForTests(bool ignore) {
1194a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  ignore_user_gesture_for_tests = ignore;
1204a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch}
1214a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
1224a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochbool BeginInstallFunction::RunImpl() {
1234a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (!IsWebStoreURL(profile_, source_url()))
1244a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    return false;
1254a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
1264a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  std::string id;
1274a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &id));
1284a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (!Extension::IdIsValid(id)) {
1294a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    error_ = kInvalidIdError;
1304a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    return false;
1314a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  }
1324a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
1334a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (!user_gesture() && !ignore_user_gesture_for_tests) {
1344a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    error_ = kUserGestureRequiredError;
1354a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    return false;
1364a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  }
1374a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
1384a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // This gets cleared in CrxInstaller::ConfirmInstall(). TODO(asargent) - in
1394a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // the future we may also want to add time-based expiration, where a whitelist
1404a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  // entry is only valid for some number of minutes.
1414a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  CrxInstaller::SetWhitelistedInstallId(id);
1424a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  return true;
1434a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch}
1444a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
145ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// This is a class to help BeginInstallWithManifestFunction manage sending
146ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// JSON manifests and base64-encoded icon data to the utility process for
147ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// parsing.
148ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenclass SafeBeginInstallHelper : public UtilityProcessHost::Client {
149ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen public:
150ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SafeBeginInstallHelper(BeginInstallWithManifestFunction* client,
151ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                         const std::string& icon_data,
152ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                         const std::string& manifest)
153ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      : client_(client),
154ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        icon_data_(icon_data),
155ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        manifest_(manifest),
156ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        utility_host_(NULL),
157ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        icon_decode_complete_(false),
158ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        manifest_parse_complete_(false),
159ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        parse_error_(BeginInstallWithManifestFunction::UNKNOWN_ERROR) {}
160ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
161ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  void Start() {
162ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
163ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    BrowserThread::PostTask(
164ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        BrowserThread::IO,
165ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        FROM_HERE,
166ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        NewRunnableMethod(this,
167ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                          &SafeBeginInstallHelper::StartWorkOnIOThread));
168ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
169ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
170ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  void StartWorkOnIOThread() {
171ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
172ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    utility_host_ = new UtilityProcessHost(this, BrowserThread::IO);
173ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    utility_host_->StartBatchMode();
174ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (icon_data_.empty())
175ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      icon_decode_complete_ = true;
176ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    else
177ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      utility_host_->StartImageDecodingBase64(icon_data_);
178ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    utility_host_->StartJSONParsing(manifest_);
179ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
180ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
181ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Implementing pieces of the UtilityProcessHost::Client interface.
182ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  virtual void OnDecodeImageSucceeded(const SkBitmap& decoded_image) {
183ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
184ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    icon_ = decoded_image;
185ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    icon_decode_complete_ = true;
186ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    ReportResultsIfComplete();
187ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
188ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  virtual void OnDecodeImageFailed() {
189ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
190ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    icon_decode_complete_ = true;
191ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    error_ = std::string(kImageDecodeError);
192ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    parse_error_ = BeginInstallWithManifestFunction::ICON_ERROR;
193ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    ReportResultsIfComplete();
194ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
195ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  virtual void OnJSONParseSucceeded(const ListValue& wrapper) {
196ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
197ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    manifest_parse_complete_ = true;
198ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    Value* value = NULL;
199ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    CHECK(wrapper.Get(0, &value));
200ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (value->IsType(Value::TYPE_DICTIONARY)) {
201ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      parsed_manifest_.reset(
202ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          static_cast<DictionaryValue*>(value)->DeepCopy());
203ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    } else {
204ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      parse_error_ = BeginInstallWithManifestFunction::MANIFEST_ERROR;
205ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
206ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    ReportResultsIfComplete();
207ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
208ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
209ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  virtual void OnJSONParseFailed(const std::string& error_message) {
210ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
211ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    manifest_parse_complete_ = true;
212ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    error_ = error_message;
213ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    parse_error_ = BeginInstallWithManifestFunction::MANIFEST_ERROR;
214ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    ReportResultsIfComplete();
215ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
216ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
217ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  void ReportResultsIfComplete() {
218ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
219ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
220ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (!icon_decode_complete_ || !manifest_parse_complete_)
221ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return;
222ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
223ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // The utility_host_ will take care of deleting itself after this call.
224ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    utility_host_->EndBatchMode();
225ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    utility_host_ = NULL;
226ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
227ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    BrowserThread::PostTask(
228ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        BrowserThread::UI,
229ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        FROM_HERE,
230ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        NewRunnableMethod(this,
231ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                          &SafeBeginInstallHelper::ReportResultFromUIThread));
232ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
233ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
234ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  void ReportResultFromUIThread() {
235ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
236ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (error_.empty() && parsed_manifest_.get())
237ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      client_->OnParseSuccess(icon_, parsed_manifest_.release());
238ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    else
239ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      client_->OnParseFailure(parse_error_, error_);
240ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
241ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
242ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen private:
243ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ~SafeBeginInstallHelper() {}
244ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
245ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // The client who we'll report results back to.
246ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  BeginInstallWithManifestFunction* client_;
247ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
248ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // The data to parse.
249ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::string icon_data_;
250ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::string manifest_;
251ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
252ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  UtilityProcessHost* utility_host_;
253ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
254ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Flags for whether we're done doing icon decoding and manifest parsing.
255ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  bool icon_decode_complete_;
256ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  bool manifest_parse_complete_;
257ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
258ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // The results of succesful decoding/parsing.
259ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SkBitmap icon_;
260ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  scoped_ptr<DictionaryValue> parsed_manifest_;
261ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
262ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // A details string for keeping track of any errors.
263ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::string error_;
264ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
265ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // A code to distinguish between an error with the icon, and an error with the
266ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // manifest.
267ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  BeginInstallWithManifestFunction::ResultCode parse_error_;
268ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen};
269ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
270ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenBeginInstallWithManifestFunction::BeginInstallWithManifestFunction() {}
271ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
272ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenBeginInstallWithManifestFunction::~BeginInstallWithManifestFunction() {}
273ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
274ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool BeginInstallWithManifestFunction::RunImpl() {
275ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!IsWebStoreURL(profile_, source_url())) {
276ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    SetResult(PERMISSION_DENIED);
277ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return false;
278ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
279ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
280ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!user_gesture() && !ignore_user_gesture_for_tests) {
281ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    SetResult(NO_GESTURE);
282ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    error_ = kUserGestureRequiredError;
283ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return false;
284ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
285ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
286ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &id_));
287ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!Extension::IdIsValid(id_)) {
288ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    SetResult(INVALID_ID);
289ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    error_ = kInvalidIdError;
290ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return false;
291ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
292ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
293ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &icon_data_));
294ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  EXTENSION_FUNCTION_VALIDATE(args_->GetString(2, &manifest_));
295ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
296ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  scoped_refptr<SafeBeginInstallHelper> helper =
297ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      new SafeBeginInstallHelper(this, icon_data_, manifest_);
298ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // The helper will call us back via OnParseSucces or OnParseFailure.
299ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  helper->Start();
300ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
301ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Matched with a Release in OnSuccess/OnFailure.
302ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  AddRef();
303ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
304ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // The response is sent asynchronously in OnSuccess/OnFailure.
305ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return true;
306ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
307ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
308ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
309ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid BeginInstallWithManifestFunction::SetResult(ResultCode code) {
310ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  switch (code) {
311ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case ERROR_NONE:
312ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      result_.reset(Value::CreateStringValue(""));
313ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      break;
314ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case UNKNOWN_ERROR:
315ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      result_.reset(Value::CreateStringValue("unknown_error"));
316ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      break;
317ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case USER_CANCELLED:
318ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      result_.reset(Value::CreateStringValue("user_cancelled"));
319ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      break;
320ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case MANIFEST_ERROR:
321ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      result_.reset(Value::CreateStringValue("manifest_error"));
322ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      break;
323ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case ICON_ERROR:
324ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      result_.reset(Value::CreateStringValue("icon_error"));
325ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      break;
326ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case INVALID_ID:
327ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      result_.reset(Value::CreateStringValue("invalid_id"));
328ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      break;
329ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case PERMISSION_DENIED:
330ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      result_.reset(Value::CreateStringValue("permission_denied"));
331ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      break;
332ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    case NO_GESTURE:
333ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      result_.reset(Value::CreateStringValue("no_gesture"));
334ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      break;
335ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    default:
336ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      CHECK(false);
337ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
338ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
339ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
340ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
341ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid BeginInstallWithManifestFunction::OnParseSuccess(
342ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const SkBitmap& icon, DictionaryValue* parsed_manifest) {
343ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  CHECK(parsed_manifest);
344ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  icon_ = icon;
345ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  parsed_manifest_.reset(parsed_manifest);
346ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
347ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Create a dummy extension and show the extension install confirmation
348ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // dialog.
349ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::string init_errors;
350ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  dummy_extension_ = Extension::Create(
351ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      FilePath(),
352ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      Extension::INTERNAL,
353ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      *static_cast<DictionaryValue*>(parsed_manifest_.get()),
354ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      Extension::NO_FLAGS,
355ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      &init_errors);
356ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!dummy_extension_.get()) {
357ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    OnParseFailure(MANIFEST_ERROR, std::string(kInvalidManifestError));
358ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
359ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
360ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (icon_.empty())
361ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    icon_ = Extension::GetDefaultIcon(dummy_extension_->is_app());
362ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
363ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ShowExtensionInstallDialog(profile(),
364ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                             this,
365ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                             dummy_extension_.get(),
366ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                             &icon_,
367ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                             dummy_extension_->GetPermissionMessageStrings(),
368ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                             ExtensionInstallUI::INSTALL_PROMPT);
369ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
370ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Control flow finishes up in InstallUIProceed or InstallUIAbort.
371ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
372ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
373ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid BeginInstallWithManifestFunction::OnParseFailure(
374ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    ResultCode result_code, const std::string& error_message) {
375ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SetResult(result_code);
376ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  error_ = error_message;
377ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SendResponse(false);
378ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
379ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Matches the AddRef in RunImpl().
380ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  Release();
381ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
382ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
383ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid BeginInstallWithManifestFunction::InstallUIProceed() {
384ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  CrxInstaller::SetWhitelistedManifest(id_, parsed_manifest_.release());
385ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SetResult(ERROR_NONE);
386ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SendResponse(true);
387ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
388ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Matches the AddRef in RunImpl().
389ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  Release();
390ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
391ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
392ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid BeginInstallWithManifestFunction::InstallUIAbort() {
393ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  error_ = std::string(kUserCancelledError);
394ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SetResult(USER_CANCELLED);
395ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SendResponse(false);
396ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
397ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Matches the AddRef in RunImpl().
398ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  Release();
399ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
400ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
4014a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochbool CompleteInstallFunction::RunImpl() {
402731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (!IsWebStoreURL(profile_, source_url()))
403bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    return false;
404bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
405bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  std::string id;
406bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &id));
4074a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (!Extension::IdIsValid(id)) {
4084a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    error_ = kInvalidIdError;
4094a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    return false;
4104a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  }
4114a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
412ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!CrxInstaller::IsIdWhitelisted(id) &&
413ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      !CrxInstaller::GetWhitelistedManifest(id)) {
4144a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    error_ = ExtensionErrorUtils::FormatErrorMessage(
4154a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch        kNoPreviousBeginInstallError, id);
4164a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    return false;
4174a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  }
418bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
419bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  std::vector<std::string> params;
420bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  params.push_back("id=" + id);
421bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  params.push_back("lang=" + g_browser_process->GetApplicationLocale());
422bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  params.push_back("uc");
423201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  std::string url_string = Extension::GalleryUpdateUrl(true).spec();
424bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
425bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  GURL url(url_string + "?response=redirect&x=" +
426bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      EscapeQueryParamValue(JoinString(params, '&'), true));
427bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  DCHECK(url.is_valid());
428bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
429bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  // The download url for the given |id| is now contained in |url|. We
430bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  // navigate the current (calling) tab to this url which will result in a
431bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  // download starting. Once completed it will go through the normal extension
432bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  // install flow. The above call to SetWhitelistedInstallId will bypass the
433bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  // normal permissions install dialog.
434bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  NavigationController& controller =
435bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen      dispatcher()->delegate()->associated_tab_contents()->controller();
436bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  controller.LoadURL(url, source_url(), PageTransition::LINK);
437bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
438bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  return true;
439bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}
440bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
441731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool GetBrowserLoginFunction::RunImpl() {
442731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (!IsWebStoreURL(profile_, source_url()))
443bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    return false;
444513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  result_.reset(CreateLoginResult(GetDefaultProfile(profile_)));
445bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  return true;
446bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}
447bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
448bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsenbool GetStoreLoginFunction::RunImpl() {
449731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (!IsWebStoreURL(profile_, source_url()))
450bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    return false;
45121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  ExtensionService* service = profile_->GetExtensionService();
452bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  ExtensionPrefs* prefs = service->extension_prefs();
453bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  std::string login;
454bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  if (prefs->GetWebStoreLogin(&login)) {
455bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    result_.reset(Value::CreateStringValue(login));
456bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  } else {
457bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    result_.reset(Value::CreateStringValue(std::string()));
458bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  }
459bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  return true;
460bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}
461bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen
462bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsenbool SetStoreLoginFunction::RunImpl() {
463731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (!IsWebStoreURL(profile_, source_url()))
464bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen    return false;
465bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  std::string login;
466bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &login));
46721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  ExtensionService* service = profile_->GetExtensionService();
468bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  ExtensionPrefs* prefs = service->extension_prefs();
469bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  prefs->SetWebStoreLogin(login);
470bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen  return true;
471bda42a81ee5f9b20d2bebedcf0bbef1e30e5b293Kristian Monsen}
472731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
473513209b27ff55e2841eac0e4120199c23acce758Ben MurdochPromptBrowserLoginFunction::PromptBrowserLoginFunction()
474513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    : waiting_for_token_(false) {}
475513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
476513209b27ff55e2841eac0e4120199c23acce758Ben MurdochPromptBrowserLoginFunction::~PromptBrowserLoginFunction() {
477513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
478731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
479731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool PromptBrowserLoginFunction::RunImpl() {
480731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (!IsWebStoreURL(profile_, source_url()))
481731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return false;
482731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
483731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  std::string preferred_email;
484731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (args_->GetSize() > 0) {
485731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &preferred_email));
486731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
487731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
488513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  Profile* profile = GetDefaultProfile(profile_);
489513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
490513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Login can currently only be invoked tab-modal.  Since this is
491513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // coming from the webstore, we should always have a tab, but check
492513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // just in case.
493513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  TabContents* tab = dispatcher()->delegate()->associated_tab_contents();
494513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!tab)
495513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return false;
496513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
497731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // We return the result asynchronously, so we addref to keep ourself alive.
498513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Matched with a Release in OnLoginSuccess() and OnLoginFailure().
499731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  AddRef();
500731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
501513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Start listening for notifications about the token.
502513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  TokenService* token_service = profile->GetTokenService();
503513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  registrar_.Add(this,
504513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                 NotificationType::TOKEN_AVAILABLE,
505513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                 Source<TokenService>(token_service));
506513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  registrar_.Add(this,
507513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                 NotificationType::TOKEN_REQUEST_FAILED,
508513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                 Source<TokenService>(token_service));
509513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
510513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  GetBrowserSignin(profile)->RequestSignin(tab,
511513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                           ASCIIToUTF16(preferred_email),
512513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                           GetLoginMessage(),
513513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                           this);
514513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
515513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // The response will be sent asynchronously in OnLoginSuccess/OnLoginFailure.
516731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return true;
517731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
518731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
519513209b27ff55e2841eac0e4120199c23acce758Ben Murdochstring16 PromptBrowserLoginFunction::GetLoginMessage() {
520513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  using l10n_util::GetStringUTF16;
521513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  using l10n_util::GetStringFUTF16;
522513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
523513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // TODO(johnnyg): This would be cleaner as an HTML template.
524513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // http://crbug.com/60216
525513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  string16 message;
526513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  message = ASCIIToUTF16("<p>")
527513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      + GetStringUTF16(IDS_WEB_STORE_LOGIN_INTRODUCTION_1)
528513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      + ASCIIToUTF16("</p>");
529513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  message = message + ASCIIToUTF16("<p>")
530513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      + GetStringFUTF16(IDS_WEB_STORE_LOGIN_INTRODUCTION_2,
531513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                        GetStringUTF16(IDS_PRODUCT_NAME))
532513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      + ASCIIToUTF16("</p>");
533513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return message;
534513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
535731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
536513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid PromptBrowserLoginFunction::OnLoginSuccess() {
537513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Ensure that apps are synced.
538513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // - If the user has already setup sync, we add Apps to the current types.
539513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // - If not, we create a new set which is just Apps.
540513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  ProfileSyncService* service = GetSyncService(GetDefaultProfile(profile_));
541513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  syncable::ModelTypeSet types;
542513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (service->HasSyncSetupCompleted())
543513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    service->GetPreferredDataTypes(&types);
544513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  types.insert(syncable::APPS);
545513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  service->ChangePreferredDataTypes(types);
546513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  service->SetSyncSetupCompleted();
547513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
548513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // We'll finish up in Observe() when the token is ready.
549513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  waiting_for_token_ = true;
550513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
551513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
552513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid PromptBrowserLoginFunction::OnLoginFailure(
553513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    const GoogleServiceAuthError& error) {
554513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  SendResponse(false);
555513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Matches the AddRef in RunImpl().
556513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  Release();
557513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
558731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
559513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid PromptBrowserLoginFunction::Observe(NotificationType type,
560513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                         const NotificationSource& source,
561513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                         const NotificationDetails& details) {
562513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Make sure this notification is for the service we are interested in.
563513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  std::string service;
564513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (type == NotificationType::TOKEN_AVAILABLE) {
565513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    TokenService::TokenAvailableDetails* available =
566513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        Details<TokenService::TokenAvailableDetails>(details).ptr();
567513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    service = available->service();
568513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  } else if (type == NotificationType::TOKEN_REQUEST_FAILED) {
569513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    TokenService::TokenRequestFailedDetails* failed =
570513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        Details<TokenService::TokenRequestFailedDetails>(details).ptr();
571513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    service = failed->service();
572513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  } else {
573513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    NOTREACHED();
574513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
575731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
576513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (service != GaiaConstants::kGaiaService) {
577513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return;
578731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
579513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
580513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK(waiting_for_token_);
581513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
582513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  result_.reset(CreateLoginResult(GetDefaultProfile(profile_)));
583513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  SendResponse(true);
584513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
585513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Matches the AddRef in RunImpl().
586513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  Release();
587731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
588