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