1 // Copyright (c) 2011 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/ui/webui/new_tab_page_sync_handler.h" 6 7 #include <vector> 8 9 #include "base/callback.h" 10 #include "base/string_split.h" 11 #include "base/string_util.h" 12 #include "base/utf_string_conversions.h" 13 #include "base/values.h" 14 #include "chrome/browser/net/chrome_url_request_context.h" 15 #include "chrome/browser/profiles/profile.h" 16 #include "content/browser/renderer_host/render_view_host.h" 17 #include "grit/generated_resources.h" 18 #include "net/base/cookie_monster.h" 19 #include "net/url_request/url_request_context.h" 20 #include "ui/base/l10n/l10n_util.h" 21 22 // Default URL for the sync web interface. 23 // 24 // TODO(idana): when we figure out how we are going to allow third parties to 25 // plug in their own sync engine, we should allow this value to be 26 // configurable. 27 static const char kSyncDefaultViewOnlineUrl[] = "http://docs.google.com"; 28 29 // TODO(idana): the following code was originally copied from 30 // toolbar_importer.h/cc and it needs to be moved to a common Google Accounts 31 // utility. 32 33 // A simple pair of fields that identify a set of Google cookies, used to 34 // filter from a larger set. 35 struct GoogleCookieFilter { 36 // The generalized, fully qualified URL of pages where 37 // cookies with id |cookie_id| are obtained / accessed. 38 const char* url; 39 // The id of the cookie this filter is selecting, 40 // with name/value delimiter (i.e '='). 41 const char* cookie_id; 42 }; 43 44 // Filters to select Google GAIA cookies. 45 static const GoogleCookieFilter kGAIACookieFilters[] = { 46 { "http://.google.com/", "SID=" }, // Gmail. 47 // Add filters here for other interesting cookies that should result in 48 // showing the promotions (e.g ASIDAS for dasher accounts). 49 }; 50 51 bool IsGoogleGAIACookieInstalled() { 52 for (size_t i = 0; i < arraysize(kGAIACookieFilters); ++i) { 53 // Since we are running on the UI thread don't call GetURLRequestContext(). 54 net::CookieStore* store = 55 Profile::GetDefaultRequestContext()->DONTUSEME_GetCookieStore(); 56 GURL url(kGAIACookieFilters[i].url); 57 net::CookieOptions options; 58 options.set_include_httponly(); // The SID cookie might be httponly. 59 std::string cookies = store->GetCookiesWithOptions(url, options); 60 std::vector<std::string> cookie_list; 61 base::SplitString(cookies, ';', &cookie_list); 62 for (std::vector<std::string>::iterator current = cookie_list.begin(); 63 current != cookie_list.end(); 64 ++current) { 65 size_t position = 66 current->find(kGAIACookieFilters[i].cookie_id); 67 if (0 == position) 68 return true; 69 } 70 } 71 return false; 72 } 73 74 NewTabPageSyncHandler::NewTabPageSyncHandler() : sync_service_(NULL), 75 waiting_for_initial_page_load_(true) { 76 } 77 78 NewTabPageSyncHandler::~NewTabPageSyncHandler() { 79 if (sync_service_) 80 sync_service_->RemoveObserver(this); 81 } 82 83 // static 84 NewTabPageSyncHandler::MessageType 85 NewTabPageSyncHandler::FromSyncStatusMessageType( 86 sync_ui_util::MessageType type) { 87 switch (type) { 88 case sync_ui_util::SYNC_ERROR: 89 return SYNC_ERROR; 90 case sync_ui_util::SYNC_PROMO: 91 return SYNC_PROMO; 92 case sync_ui_util::PRE_SYNCED: 93 case sync_ui_util::SYNCED: 94 default: 95 return HIDE; 96 } 97 } 98 99 WebUIMessageHandler* NewTabPageSyncHandler::Attach(WebUI* web_ui) { 100 sync_service_ = web_ui->GetProfile()->GetProfileSyncService(); 101 DCHECK(sync_service_); // This shouldn't get called by an incognito NTP. 102 DCHECK(!sync_service_->IsManaged()); // And neither if sync is managed. 103 sync_service_->AddObserver(this); 104 return WebUIMessageHandler::Attach(web_ui); 105 } 106 107 void NewTabPageSyncHandler::RegisterMessages() { 108 web_ui_->RegisterMessageCallback("GetSyncMessage", 109 NewCallback(this, &NewTabPageSyncHandler::HandleGetSyncMessage)); 110 web_ui_->RegisterMessageCallback("SyncLinkClicked", 111 NewCallback(this, &NewTabPageSyncHandler::HandleSyncLinkClicked)); 112 } 113 114 void NewTabPageSyncHandler::HandleGetSyncMessage(const ListValue* args) { 115 waiting_for_initial_page_load_ = false; 116 BuildAndSendSyncStatus(); 117 } 118 119 void NewTabPageSyncHandler::HideSyncStatusSection() { 120 SendSyncMessageToPage(HIDE, std::string(), std::string()); 121 } 122 123 void NewTabPageSyncHandler::BuildAndSendSyncStatus() { 124 DCHECK(!waiting_for_initial_page_load_); 125 126 // Hide the sync status section if sync is managed or disabled entirely. 127 if (!sync_service_ || sync_service_->IsManaged()) { 128 HideSyncStatusSection(); 129 return; 130 } 131 132 // Don't show sync status if setup is not complete. 133 if (!sync_service_->HasSyncSetupCompleted()) { 134 return; 135 } 136 137 // Once sync has been enabled, the supported "sync statuses" for the NNTP 138 // from the user's perspective are: 139 // 140 // "Sync error", when we can't authenticate or establish a connection with 141 // the sync server (appropriate information appended to 142 // message). 143 string16 status_msg; 144 string16 link_text; 145 sync_ui_util::MessageType type = 146 sync_ui_util::GetStatusLabelsForNewTabPage(sync_service_, 147 &status_msg, 148 &link_text); 149 SendSyncMessageToPage(FromSyncStatusMessageType(type), 150 UTF16ToUTF8(status_msg), UTF16ToUTF8(link_text)); 151 } 152 153 void NewTabPageSyncHandler::HandleSyncLinkClicked(const ListValue* args) { 154 DCHECK(!waiting_for_initial_page_load_); 155 DCHECK(sync_service_); 156 if (!sync_service_->IsSyncEnabled()) 157 return; 158 if (sync_service_->HasSyncSetupCompleted()) { 159 sync_service_->ShowErrorUI(NULL); 160 DictionaryValue value; 161 value.SetString("syncEnabledMessage", 162 l10n_util::GetStringFUTF16(IDS_SYNC_NTP_SYNCED_TO, 163 sync_service_->GetAuthenticatedUsername())); 164 web_ui_->CallJavascriptFunction("syncAlreadyEnabled", value); 165 } else { 166 // User clicked the 'Start now' link to begin syncing. 167 ProfileSyncService::SyncEvent(ProfileSyncService::START_FROM_NTP); 168 sync_service_->ShowLoginDialog(NULL); 169 } 170 } 171 172 void NewTabPageSyncHandler::OnStateChanged() { 173 // Don't do anything if the page has not yet loaded. 174 if (waiting_for_initial_page_load_) 175 return; 176 BuildAndSendSyncStatus(); 177 } 178 179 void NewTabPageSyncHandler::SendSyncMessageToPage( 180 MessageType type, std::string msg, 181 std::string linktext) { 182 DictionaryValue value; 183 std::string user; 184 std::string title; 185 std::string linkurl; 186 187 // If there is nothing to show, we should hide the sync section altogether. 188 if (type == HIDE || (msg.empty() && linktext.empty())) { 189 value.SetBoolean("syncsectionisvisible", false); 190 } else { 191 if (type == SYNC_ERROR) 192 title = l10n_util::GetStringUTF8(IDS_SYNC_NTP_SYNC_SECTION_ERROR_TITLE); 193 else if (type == SYNC_PROMO) 194 title = l10n_util::GetStringUTF8(IDS_SYNC_NTP_SYNC_SECTION_PROMO_TITLE); 195 else 196 NOTREACHED(); 197 198 value.SetBoolean("syncsectionisvisible", true); 199 value.SetString("msg", msg); 200 value.SetString("title", title); 201 if (linktext.empty()) { 202 value.SetBoolean("linkisvisible", false); 203 } else { 204 value.SetBoolean("linkisvisible", true); 205 value.SetString("linktext", linktext); 206 207 // The only time we set the URL is when the user is synced and we need to 208 // show a link to a web interface (e.g. http://docs.google.com). When we 209 // set that URL, HandleSyncLinkClicked won't be called when the user 210 // clicks on the link. 211 if (linkurl.empty()) { 212 value.SetBoolean("linkurlisset", false); 213 } else { 214 value.SetBoolean("linkurlisset", true); 215 value.SetString("linkurl", linkurl); 216 } 217 } 218 } 219 web_ui_->CallJavascriptFunction("syncMessageChanged", value); 220 } 221