1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/chromeos/extensions/echo_private_api.h" 6 7#include <string> 8 9#include "base/bind.h" 10#include "base/files/file_util.h" 11#include "base/location.h" 12#include "base/prefs/pref_registry_simple.h" 13#include "base/prefs/pref_service.h" 14#include "base/prefs/scoped_user_pref_update.h" 15#include "base/strings/stringprintf.h" 16#include "base/strings/utf_string_conversions.h" 17#include "base/time/time.h" 18#include "base/values.h" 19#include "chrome/browser/browser_process.h" 20#include "chrome/browser/chromeos/kiosk_mode/kiosk_mode_settings.h" 21#include "chrome/browser/chromeos/settings/cros_settings.h" 22#include "chrome/browser/chromeos/ui/echo_dialog_view.h" 23#include "chrome/browser/ui/browser.h" 24#include "chrome/browser/ui/browser_window.h" 25#include "chrome/common/extensions/api/echo_private.h" 26#include "chrome/common/pref_names.h" 27#include "chromeos/system/statistics_provider.h" 28#include "content/public/browser/browser_thread.h" 29#include "extensions/common/extension.h" 30 31namespace echo_api = extensions::api::echo_private; 32 33using content::BrowserThread; 34 35namespace { 36 37// URL of "More info" link shown in echo dialog in GetUserConsent function. 38const char kMoreInfoLink[] = 39 "chrome-extension://honijodknafkokifofgiaalefdiedpko/main.html?" 40 "answer=2677280"; 41 42} // namespace 43 44namespace chromeos { 45 46namespace echo_offer { 47 48void RegisterPrefs(PrefRegistrySimple* registry) { 49 registry->RegisterDictionaryPref(prefs::kEchoCheckedOffers); 50} 51 52} // namespace echo_offer 53 54} // namespace chromeos 55 56EchoPrivateGetRegistrationCodeFunction:: 57 EchoPrivateGetRegistrationCodeFunction() {} 58 59EchoPrivateGetRegistrationCodeFunction:: 60 ~EchoPrivateGetRegistrationCodeFunction() {} 61 62void EchoPrivateGetRegistrationCodeFunction::GetRegistrationCode( 63 const std::string& type) { 64 if (!chromeos::KioskModeSettings::Get()->is_initialized()) { 65 chromeos::KioskModeSettings::Get()->Initialize(base::Bind( 66 &EchoPrivateGetRegistrationCodeFunction::GetRegistrationCode, 67 this, type)); 68 return; 69 } 70 // Possible ECHO code type and corresponding key name in StatisticsProvider. 71 const std::string kCouponType = "COUPON_CODE"; 72 const std::string kGroupType = "GROUP_CODE"; 73 74 chromeos::system::StatisticsProvider* provider = 75 chromeos::system::StatisticsProvider::GetInstance(); 76 std::string result; 77 if (!chromeos::KioskModeSettings::Get()->IsKioskModeEnabled()) { 78 // In Kiosk mode, we effectively disable the registration API 79 // by always returning an empty code. 80 if (type == kCouponType) { 81 provider->GetMachineStatistic(chromeos::system::kOffersCouponCodeKey, 82 &result); 83 } else if (type == kGroupType) { 84 provider->GetMachineStatistic(chromeos::system::kOffersGroupCodeKey, 85 &result); 86 } 87 } 88 89 results_ = echo_api::GetRegistrationCode::Results::Create(result); 90 SendResponse(true); 91} 92 93bool EchoPrivateGetRegistrationCodeFunction::RunSync() { 94 scoped_ptr<echo_api::GetRegistrationCode::Params> params = 95 echo_api::GetRegistrationCode::Params::Create(*args_); 96 EXTENSION_FUNCTION_VALIDATE(params); 97 GetRegistrationCode(params->type); 98 return true; 99} 100 101EchoPrivateSetOfferInfoFunction::EchoPrivateSetOfferInfoFunction() {} 102 103EchoPrivateSetOfferInfoFunction::~EchoPrivateSetOfferInfoFunction() {} 104 105bool EchoPrivateSetOfferInfoFunction::RunSync() { 106 scoped_ptr<echo_api::SetOfferInfo::Params> params = 107 echo_api::SetOfferInfo::Params::Create(*args_); 108 EXTENSION_FUNCTION_VALIDATE(params); 109 110 const std::string& service_id = params->id; 111 base::DictionaryValue* dict = params->offer_info. 112 additional_properties.DeepCopyWithoutEmptyChildren(); 113 114 PrefService* local_state = g_browser_process->local_state(); 115 DictionaryPrefUpdate offer_update(local_state, prefs::kEchoCheckedOffers); 116 offer_update->SetWithoutPathExpansion("echo." + service_id, dict); 117 return true; 118} 119 120EchoPrivateGetOfferInfoFunction::EchoPrivateGetOfferInfoFunction() {} 121 122EchoPrivateGetOfferInfoFunction::~EchoPrivateGetOfferInfoFunction() {} 123 124bool EchoPrivateGetOfferInfoFunction::RunSync() { 125 scoped_ptr<echo_api::GetOfferInfo::Params> params = 126 echo_api::GetOfferInfo::Params::Create(*args_); 127 EXTENSION_FUNCTION_VALIDATE(params); 128 129 const std::string& service_id = params->id; 130 PrefService* local_state = g_browser_process->local_state(); 131 const base::DictionaryValue* offer_infos = local_state-> 132 GetDictionary(prefs::kEchoCheckedOffers); 133 134 const base::DictionaryValue* offer_info = NULL; 135 if (!offer_infos->GetDictionaryWithoutPathExpansion( 136 "echo." + service_id, &offer_info)) { 137 error_ = "Not found"; 138 return false; 139 } 140 141 echo_api::GetOfferInfo::Results::Result result; 142 result.additional_properties.MergeDictionary(offer_info); 143 results_ = echo_api::GetOfferInfo::Results::Create(result); 144 return true; 145} 146 147EchoPrivateGetOobeTimestampFunction::EchoPrivateGetOobeTimestampFunction() { 148} 149 150EchoPrivateGetOobeTimestampFunction::~EchoPrivateGetOobeTimestampFunction() { 151} 152 153bool EchoPrivateGetOobeTimestampFunction::RunAsync() { 154 BrowserThread::PostTaskAndReplyWithResult( 155 BrowserThread::FILE, FROM_HERE, 156 base::Bind( 157 &EchoPrivateGetOobeTimestampFunction::GetOobeTimestampOnFileThread, 158 this), 159 base::Bind( 160 &EchoPrivateGetOobeTimestampFunction::SendResponse, this)); 161 return true; 162} 163 164// Get the OOBE timestamp from file /home/chronos/.oobe_completed. 165// The timestamp is used to determine when the user first activates the device. 166// If we can get the timestamp info, return it as yyyy-mm-dd, otherwise, return 167// an empty string. 168bool EchoPrivateGetOobeTimestampFunction::GetOobeTimestampOnFileThread() { 169 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 170 171 const char kOobeTimestampFile[] = "/home/chronos/.oobe_completed"; 172 std::string timestamp = ""; 173 base::File::Info fileInfo; 174 if (base::GetFileInfo(base::FilePath(kOobeTimestampFile), &fileInfo)) { 175 base::Time::Exploded ctime; 176 fileInfo.creation_time.UTCExplode(&ctime); 177 timestamp += base::StringPrintf("%u-%u-%u", 178 ctime.year, 179 ctime.month, 180 ctime.day_of_month); 181 } 182 results_ = echo_api::GetOobeTimestamp::Results::Create(timestamp); 183 return true; 184} 185 186EchoPrivateGetUserConsentFunction::EchoPrivateGetUserConsentFunction() 187 : redeem_offers_allowed_(false) { 188} 189 190// static 191scoped_refptr<EchoPrivateGetUserConsentFunction> 192EchoPrivateGetUserConsentFunction::CreateForTest( 193 const DialogShownTestCallback& dialog_shown_callback) { 194 scoped_refptr<EchoPrivateGetUserConsentFunction> function( 195 new EchoPrivateGetUserConsentFunction()); 196 function->dialog_shown_callback_ = dialog_shown_callback; 197 return function; 198} 199 200EchoPrivateGetUserConsentFunction::~EchoPrivateGetUserConsentFunction() {} 201 202bool EchoPrivateGetUserConsentFunction::RunAsync() { 203 CheckRedeemOffersAllowed(); 204 return true; 205} 206 207void EchoPrivateGetUserConsentFunction::OnAccept() { 208 Finalize(true); 209} 210 211void EchoPrivateGetUserConsentFunction::OnCancel() { 212 Finalize(false); 213} 214 215void EchoPrivateGetUserConsentFunction::OnMoreInfoLinkClicked() { 216 chrome::NavigateParams params( 217 GetProfile(), GURL(kMoreInfoLink), ui::PAGE_TRANSITION_LINK); 218 // Open the link in a new window. The echo dialog is modal, so the current 219 // window is useless until the dialog is closed. 220 params.disposition = NEW_WINDOW; 221 chrome::Navigate(¶ms); 222} 223 224void EchoPrivateGetUserConsentFunction::CheckRedeemOffersAllowed() { 225 chromeos::CrosSettingsProvider::TrustedStatus status = 226 chromeos::CrosSettings::Get()->PrepareTrustedValues(base::Bind( 227 &EchoPrivateGetUserConsentFunction::CheckRedeemOffersAllowed, 228 this)); 229 if (status == chromeos::CrosSettingsProvider::TEMPORARILY_UNTRUSTED) 230 return; 231 232 bool allow = true; 233 chromeos::CrosSettings::Get()->GetBoolean( 234 chromeos::kAllowRedeemChromeOsRegistrationOffers, &allow); 235 236 OnRedeemOffersAllowedChecked(allow); 237} 238 239void EchoPrivateGetUserConsentFunction::OnRedeemOffersAllowedChecked( 240 bool is_allowed) { 241 redeem_offers_allowed_ = is_allowed; 242 243 scoped_ptr<echo_api::GetUserConsent::Params> params = 244 echo_api::GetUserConsent::Params::Create(*args_); 245 246 // Verify that the passed origin URL is valid. 247 GURL service_origin = GURL(params->consent_requester.origin); 248 if (!service_origin.is_valid()) { 249 error_ = "Invalid origin."; 250 SendResponse(false); 251 return; 252 } 253 254 // Add ref to ensure the function stays around until the dialog listener is 255 // called. The reference is release in |Finalize|. 256 AddRef(); 257 258 // Create and show the dialog. 259 chromeos::EchoDialogView* dialog = new chromeos::EchoDialogView(this); 260 if (redeem_offers_allowed_) { 261 dialog->InitForEnabledEcho( 262 base::UTF8ToUTF16(params->consent_requester.service_name), 263 base::UTF8ToUTF16(params->consent_requester.origin)); 264 } else { 265 dialog->InitForDisabledEcho(); 266 } 267 dialog->Show(GetCurrentBrowser()->window()->GetNativeWindow()); 268 269 // If there is a dialog_shown_callback_, invoke it with the created dialog. 270 if (!dialog_shown_callback_.is_null()) 271 dialog_shown_callback_.Run(dialog); 272} 273 274void EchoPrivateGetUserConsentFunction::Finalize(bool consent) { 275 // Consent should not be true if offers redeeming is disabled. 276 CHECK(redeem_offers_allowed_ || !consent); 277 results_ = echo_api::GetUserConsent::Results::Create(consent); 278 SendResponse(true); 279 280 // Release the reference added in |OnRedeemOffersAllowedChecked|, before 281 // showing the dialog. 282 Release(); 283} 284