push_messaging_api.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/api/push_messaging/push_messaging_api.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <set>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/lazy_instance.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/api/push_messaging/push_messaging_invalidation_handler.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/event_names.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/event_router.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_service.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_system.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/extension_system_factory.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/token_cache/token_cache_service.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/token_cache/token_cache_service_factory.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/signin/token_service.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/signin/token_service_factory.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/sync/profile_sync_service.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/sync/profile_sync_service_factory.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_notification_types.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/api/push_messaging.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/extension.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/extension_set.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/permissions/api_permission.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_details.h"
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_source.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "google_apis/gaia/gaia_constants.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "googleurl/src/gurl.h"
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kChannelIdSeparator[] = "/";
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kUserNotSignedIn[] = "The user is not signed in.";
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kTokenServiceNotAvailable[] = "Failed to get token service.";
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kObfuscatedGaiaIdTimeoutInDays = 30;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace extensions {
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace glue = api::push_messaging;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PushMessagingEventRouter::PushMessagingEventRouter(Profile* profile)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : profile_(profile) {
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PushMessagingEventRouter::~PushMessagingEventRouter() {}
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PushMessagingEventRouter::TriggerMessageForTest(
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& extension_id,
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int subchannel,
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& payload) {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OnMessage(extension_id, subchannel, payload);
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PushMessagingEventRouter::OnMessage(const std::string& extension_id,
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         int subchannel,
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         const std::string& payload) {
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glue::Message message;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  message.subchannel_id = subchannel;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  message.payload = payload;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DVLOG(2) << "PushMessagingEventRouter::OnMessage"
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           << " payload = '" << payload
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           << "' subchannel = '" << subchannel
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           << "' extension = '" << extension_id << "'";
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<base::ListValue> args(glue::OnMessage::Create(message));
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<extensions::Event> event(new extensions::Event(
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      event_names::kOnPushMessage, args.Pass()));
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  event->restrict_to_profile = profile_;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ExtensionSystem::Get(profile_)->event_router()->DispatchEventToExtension(
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      extension_id, event.Pass());
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// GetChannelId class functions
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PushMessagingGetChannelIdFunction::PushMessagingGetChannelIdFunction()
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : interactive_(false) {}
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PushMessagingGetChannelIdFunction::~PushMessagingGetChannelIdFunction() {}
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PushMessagingGetChannelIdFunction::RunImpl() {
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Fetch the function arguments.
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<glue::GetChannelId::Params> params(
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      glue::GetChannelId::Params::Create(*args_));
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_FUNCTION_VALIDATE(params.get());
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (params && params->interactive) {
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    interactive_ = *params->interactive;
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Balanced in ReportResult()
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddRef();
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!IsUserLoggedIn()) {
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (interactive_) {
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LoginUIService* login_ui_service =
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          LoginUIServiceFactory::GetForProfile(profile());
109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      TokenService* token_service = TokenServiceFactory::GetForProfile(
110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          profile());
111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // Register for token available so we can tell when the logon is done.
112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // Observe() will be called if token is issued.
113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      registrar_.Add(this,
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                     chrome::NOTIFICATION_TOKEN_AVAILABLE,
115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                     content::Source<TokenService>(token_service));
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      login_ui_service->ShowLoginPopup();
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      error_ = kUserNotSignedIn;
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ReportResult(std::string(), error_);
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return StartGaiaIdFetch();
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// If we are in an interactive login and it succeeds, start token fetch.
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void PushMessagingGetChannelIdFunction::Observe(
130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int type,
131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const content::NotificationSource& source,
132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const content::NotificationDetails& details) {
133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK_EQ(chrome::NOTIFICATION_TOKEN_AVAILABLE, type);
134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  TokenService::TokenAvailableDetails* token_details =
136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      content::Details<TokenService::TokenAvailableDetails>(details).ptr();
137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (token_details->service() == GaiaConstants::kGaiaOAuth2LoginRefreshToken) {
138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    TokenService* token_service = TokenServiceFactory::GetForProfile(profile());
139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    registrar_.Remove(this,
140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                      chrome::NOTIFICATION_TOKEN_AVAILABLE,
141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                      content::Source<TokenService>(token_service));
142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // If we got a token, the logon succeeded, continue fetching Obfuscated
143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Gaia Id.
144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!StartGaiaIdFetch())
145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      SendResponse(false);
146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PushMessagingGetChannelIdFunction::StartGaiaIdFetch() {
150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Start the async fetch of the Gaia Id.
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net::URLRequestContextGetter* context = profile()->GetRequestContext();
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TokenService* token_service = TokenServiceFactory::GetForProfile(profile());
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!token_service) {
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ReportResult(std::string(), std::string(kTokenServiceNotAvailable));
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::string& refresh_token =
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      token_service->GetOAuth2LoginRefreshToken();
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fetcher_.reset(new ObfuscatedGaiaIdFetcher(context, this, refresh_token));
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Get the token cache and see if we have already cached a Gaia Id.
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  TokenCacheService* token_cache =
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      TokenCacheServiceFactory::GetForProfile(profile());
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Check the cache, if we already have a Gaia ID, use it instead of
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // fetching the ID over the network.
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::string& gaia_id =
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      token_cache->RetrieveToken(GaiaConstants::kObfuscatedGaiaId);
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!gaia_id.empty()) {
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ReportResult(gaia_id, std::string());
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fetcher_->Start();
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Will finish asynchronously.
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Check if the user is logged in.
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PushMessagingGetChannelIdFunction::IsUserLoggedIn() const {
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TokenService* token_service = TokenServiceFactory::GetForProfile(profile());
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!token_service)
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return token_service->HasOAuthLoginToken();
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PushMessagingGetChannelIdFunction::ReportResult(
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& gaia_id, const std::string& error_string) {
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BuildAndSendResult(gaia_id, error_string);
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Cache the obfuscated ID locally. It never changes for this user,
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and if we call the web API too often, we get errors due to rate limiting.
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!gaia_id.empty()) {
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::TimeDelta timeout =
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::TimeDelta::FromDays(kObfuscatedGaiaIdTimeoutInDays);
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    TokenCacheService* token_cache =
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        TokenCacheServiceFactory::GetForProfile(profile());
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    token_cache->StoreToken(GaiaConstants::kObfuscatedGaiaId, gaia_id,
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            timeout);
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Balanced in RunImpl.
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Release();
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PushMessagingGetChannelIdFunction::BuildAndSendResult(
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& gaia_id, const std::string& error_message) {
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string channel_id;
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!gaia_id.empty()) {
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    channel_id = gaia_id;
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    channel_id += kChannelIdSeparator;
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    channel_id += extension_id();
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(petewil): It may be a good idea to further
220c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // obfuscate the channel ID to prevent the user's obfuscated Gaia Id
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // from being readily obtained.  Security review will tell us if we need to.
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create a ChannelId results object and set the fields.
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glue::ChannelIdResult result;
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result.channel_id = channel_id;
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetError(error_message);
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  results_ = glue::GetChannelId::Results::Create(result);
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = error_message.empty() && !gaia_id.empty();
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SendResponse(success);
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PushMessagingGetChannelIdFunction::OnObfuscatedGaiaIdFetchSuccess(
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& gaia_id) {
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReportResult(gaia_id, std::string());
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PushMessagingGetChannelIdFunction::OnObfuscatedGaiaIdFetchFailure(
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const GoogleServiceAuthError& error) {
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string error_text = error.error_message();
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the error message is blank, see if we can set it from the state.
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (error_text.empty() &&
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (0 != error.state())) {
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error_text = base::IntToString(error.state());
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DVLOG(1) << "GetChannelId status: '" << error_text << "'";
248c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
249c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // If we had bad credentials, try the logon again.
250c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  switch (error.state()) {
251c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS:
252c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case GoogleServiceAuthError::ACCOUNT_DELETED:
253c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case GoogleServiceAuthError::ACCOUNT_DISABLED: {
254c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (interactive_) {
255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        LoginUIService* login_ui_service =
256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            LoginUIServiceFactory::GetForProfile(profile());
257c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // content::NotificationObserver will be called if token is issued.
258c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        login_ui_service->ShowLoginPopup();
259c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      } else {
260c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        ReportResult(std::string(), error_text);
261c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
262c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return;
263c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
264c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    default:
265c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // Return error to caller.
266c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ReportResult(std::string(), error_text);
267c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return;
268c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)PushMessagingAPI::PushMessagingAPI(Profile* profile) : profile_(profile) {
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED,
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 content::Source<Profile>(profile_->GetOriginalProfile()));
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 content::Source<Profile>(profile_->GetOriginalProfile()));
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 content::Source<Profile>(profile_->GetOriginalProfile()));
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)PushMessagingAPI::~PushMessagingAPI() {
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)PushMessagingAPI* PushMessagingAPI::Get(Profile* profile) {
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return ProfileKeyedAPIFactory<PushMessagingAPI>::GetForProfile(profile);
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void PushMessagingAPI::Shutdown() {
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  event_router_.reset();
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  handler_.reset();
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static base::LazyInstance<ProfileKeyedAPIFactory<PushMessagingAPI> >
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)g_factory = LAZY_INSTANCE_INITIALIZER;
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ProfileKeyedAPIFactory<PushMessagingAPI>*
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)PushMessagingAPI::GetFactoryInstance() {
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return &g_factory.Get();
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void PushMessagingAPI::Observe(int type,
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               const content::NotificationSource& source,
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               const content::NotificationDetails& details) {
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ProfileSyncService* pss = ProfileSyncServiceFactory::GetForProfile(profile_);
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // This may be NULL; for example, for the ChromeOS guest user. In these cases,
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // just return without setting up anything, since it won't work anyway.
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!pss)
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!event_router_)
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    event_router_.reset(new PushMessagingEventRouter(profile_));
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!handler_) {
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    handler_.reset(new PushMessagingInvalidationHandler(
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        pss, event_router_.get()));
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  switch (type) {
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case chrome::NOTIFICATION_EXTENSION_INSTALLED: {
319c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      const Extension* extension =
320c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          content::Details<const InstalledExtensionInfo>(details)->extension;
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (extension->HasAPIPermission(APIPermission::kPushMessaging)) {
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        handler_->SuppressInitialInvalidationsForExtension(extension->id());
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case chrome::NOTIFICATION_EXTENSION_LOADED: {
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const Extension* extension = content::Details<Extension>(details).ptr();
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (extension->HasAPIPermission(APIPermission::kPushMessaging)) {
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        handler_->RegisterExtension(extension->id());
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case chrome::NOTIFICATION_EXTENSION_UNLOADED: {
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const Extension* extension =
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          content::Details<UnloadedExtensionInfo>(details)->extension;
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (extension->HasAPIPermission(APIPermission::kPushMessaging)) {
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        handler_->UnregisterExtension(extension->id());
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    default:
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      NOTREACHED();
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void PushMessagingAPI::SetMapperForTest(
3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<PushMessagingInvalidationMapper> mapper) {
3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  handler_ = mapper.Pass();
3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template <>
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ProfileKeyedAPIFactory<PushMessagingAPI>::DeclareFactoryDependencies() {
3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DependsOn(ExtensionSystemFactory::GetInstance());
3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DependsOn(ProfileSyncServiceFactory::GetInstance());
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace extensions
358