push_messaging_api.cc revision effb81e5f8246d0db0270817048dc992db66e9fb
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"
147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/api/push_messaging/push_messaging_invalidation_handler.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_service.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/token_cache/token_cache_service.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/token_cache/token_cache_service_factory.h"
1923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "chrome/browser/invalidation/invalidation_auth_provider.h"
20eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/invalidation/invalidation_service.h"
21eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/invalidation/invalidation_service_factory.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/signin/signin_manager.h"
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/signin/signin_manager_factory.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/api/push_messaging.h"
27effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "components/signin/core/browser/profile_oauth2_token_service.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_details.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_source.h"
31f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/browser/event_router.h"
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_system.h"
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_system_provider.h"
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extensions_browser_client.h"
35f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/extension.h"
364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "extensions/common/permissions/api_permission.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "google_apis/gaia/gaia_constants.h"
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kChannelIdSeparator[] = "/";
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kUserNotSignedIn[] = "The user is not signed in.";
437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochconst char kUserAccessTokenFailure[] =
447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    "Cannot obtain access token for the user.";
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kObfuscatedGaiaIdTimeoutInDays = 30;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace extensions {
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace glue = api::push_messaging;
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PushMessagingEventRouter::PushMessagingEventRouter(Profile* profile)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : profile_(profile) {
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PushMessagingEventRouter::~PushMessagingEventRouter() {}
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PushMessagingEventRouter::TriggerMessageForTest(
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& extension_id,
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int subchannel,
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& payload) {
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OnMessage(extension_id, subchannel, payload);
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PushMessagingEventRouter::OnMessage(const std::string& extension_id,
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         int subchannel,
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         const std::string& payload) {
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glue::Message message;
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  message.subchannel_id = subchannel;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  message.payload = payload;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DVLOG(2) << "PushMessagingEventRouter::OnMessage"
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           << " payload = '" << payload
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           << "' subchannel = '" << subchannel
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           << "' extension = '" << extension_id << "'";
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<base::ListValue> args(glue::OnMessage::Create(message));
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<extensions::Event> event(new extensions::Event(
783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      glue::OnMessage::kEventName, args.Pass()));
79f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  event->restrict_to_browser_context = profile_;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ExtensionSystem::Get(profile_)->event_router()->DispatchEventToExtension(
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      extension_id, event.Pass());
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// GetChannelId class functions
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PushMessagingGetChannelIdFunction::PushMessagingGetChannelIdFunction()
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : OAuth2TokenService::Consumer("push_messaging"),
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (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()) {
10623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    invalidation::InvalidationAuthProvider* auth_provider =
10723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        GetInvalidationAuthProvider();
10823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    if (interactive_ && auth_provider->ShowLoginUI()) {
10923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      auth_provider->GetTokenService()->AddObserver(this);
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      error_ = kUserNotSignedIn;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ReportResult(std::string(), error_);
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  DVLOG(2) << "Logged in profile name: " << GetProfile()->GetProfileName();
1193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  StartAccessTokenFetch();
1217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return true;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid PushMessagingGetChannelIdFunction::StartAccessTokenFetch() {
1257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  std::vector<std::string> scope_vector =
1267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      extensions::ObfuscatedGaiaIdFetcher::GetScopes();
1277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  OAuth2TokenService::ScopeSet scopes(scope_vector.begin(), scope_vector.end());
12823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  invalidation::InvalidationAuthProvider* auth_provider =
12923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      GetInvalidationAuthProvider();
13023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  fetcher_access_token_request_ =
13123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      auth_provider->GetTokenService()->StartRequest(
13223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          auth_provider->GetAccountId(), scopes, this);
1337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
1347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid PushMessagingGetChannelIdFunction::OnRefreshTokenAvailable(
1367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const std::string& account_id) {
13723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  GetInvalidationAuthProvider()->GetTokenService()->RemoveObserver(this);
1381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  DVLOG(2) << "Newly logged in: " << GetProfile()->GetProfileName();
1397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  StartAccessTokenFetch();
1407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
1417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid PushMessagingGetChannelIdFunction::OnGetTokenSuccess(
1437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const OAuth2TokenService::Request* request,
1447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const std::string& access_token,
1457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const base::Time& expiration_time) {
1467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK_EQ(fetcher_access_token_request_.get(), request);
1477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  fetcher_access_token_request_.reset();
1487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  StartGaiaIdFetch(access_token);
1507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
1517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid PushMessagingGetChannelIdFunction::OnGetTokenFailure(
1537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const OAuth2TokenService::Request* request,
1547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const GoogleServiceAuthError& error) {
1557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK_EQ(fetcher_access_token_request_.get(), request);
1567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  fetcher_access_token_request_.reset();
1577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // TODO(fgorski): We are currently ignoring the error passed in upon failure.
1597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // It should be revisited when we are working on improving general error
1607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // handling for the identity related code.
1613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DVLOG(1) << "Cannot obtain access token for this user "
1623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)           << error.error_message() << " " << error.state();
1637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  error_ = kUserAccessTokenFailure;
1647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ReportResult(std::string(), error_);
165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid PushMessagingGetChannelIdFunction::StartGaiaIdFetch(
1687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const std::string& access_token) {
169c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Start the async fetch of the Gaia Id.
170effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::UI);
1711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  net::URLRequestContextGetter* context = GetProfile()->GetRequestContext();
1727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  fetcher_.reset(new ObfuscatedGaiaIdFetcher(context, this, access_token));
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Get the token cache and see if we have already cached a Gaia Id.
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  TokenCacheService* token_cache =
1761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      TokenCacheServiceFactory::GetForProfile(GetProfile());
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Check the cache, if we already have a Gaia ID, use it instead of
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // fetching the ID over the network.
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::string& gaia_id =
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      token_cache->RetrieveToken(GaiaConstants::kObfuscatedGaiaId);
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!gaia_id.empty()) {
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ReportResult(gaia_id, std::string());
1847dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fetcher_->Start();
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Check if the user is logged in.
19123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)bool PushMessagingGetChannelIdFunction::IsUserLoggedIn() {
19223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  invalidation::InvalidationAuthProvider* auth_provider =
19323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      GetInvalidationAuthProvider();
19423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  return auth_provider->GetTokenService()->RefreshTokenIsAvailable(
19523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      auth_provider->GetAccountId());
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PushMessagingGetChannelIdFunction::ReportResult(
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& gaia_id, const std::string& error_string) {
200effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::UI);
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BuildAndSendResult(gaia_id, error_string);
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Cache the obfuscated ID locally. It never changes for this user,
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and if we call the web API too often, we get errors due to rate limiting.
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!gaia_id.empty()) {
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::TimeDelta timeout =
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::TimeDelta::FromDays(kObfuscatedGaiaIdTimeoutInDays);
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    TokenCacheService* token_cache =
2101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        TokenCacheServiceFactory::GetForProfile(GetProfile());
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    token_cache->StoreToken(GaiaConstants::kObfuscatedGaiaId, gaia_id,
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            timeout);
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Balanced in RunImpl.
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Release();
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PushMessagingGetChannelIdFunction::BuildAndSendResult(
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& gaia_id, const std::string& error_message) {
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string channel_id;
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!gaia_id.empty()) {
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    channel_id = gaia_id;
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    channel_id += kChannelIdSeparator;
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    channel_id += extension_id();
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(petewil): It may be a good idea to further
229c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // obfuscate the channel ID to prevent the user's obfuscated Gaia Id
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // from being readily obtained.  Security review will tell us if we need to.
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create a ChannelId results object and set the fields.
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glue::ChannelIdResult result;
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result.channel_id = channel_id;
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetError(error_message);
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  results_ = glue::GetChannelId::Results::Create(result);
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = error_message.empty() && !gaia_id.empty();
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SendResponse(success);
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PushMessagingGetChannelIdFunction::OnObfuscatedGaiaIdFetchSuccess(
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& gaia_id) {
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReportResult(gaia_id, std::string());
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PushMessagingGetChannelIdFunction::OnObfuscatedGaiaIdFetchFailure(
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const GoogleServiceAuthError& error) {
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string error_text = error.error_message();
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the error message is blank, see if we can set it from the state.
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (error_text.empty() &&
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (0 != error.state())) {
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error_text = base::IntToString(error.state());
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DVLOG(1) << "GetChannelId status: '" << error_text << "'";
257c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
258c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // If we had bad credentials, try the logon again.
259c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  switch (error.state()) {
260c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS:
261c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case GoogleServiceAuthError::ACCOUNT_DELETED:
262c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case GoogleServiceAuthError::ACCOUNT_DISABLED: {
26323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      if (!interactive_ || !GetInvalidationAuthProvider()->ShowLoginUI()) {
264c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        ReportResult(std::string(), error_text);
265c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
266c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return;
267c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
268c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    default:
269c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // Return error to caller.
270c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ReportResult(std::string(), error_text);
271c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return;
272c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
27523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)invalidation::InvalidationAuthProvider*
27623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)PushMessagingGetChannelIdFunction::GetInvalidationAuthProvider() {
27723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  return invalidation::InvalidationServiceFactory::GetForProfile(GetProfile())
27823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      ->GetInvalidationAuthProvider();
27923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}
28023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
281a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)PushMessagingAPI::PushMessagingAPI(content::BrowserContext* context)
282a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    : profile_(Profile::FromBrowserContext(context)) {
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED,
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 content::Source<Profile>(profile_->GetOriginalProfile()));
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 content::Source<Profile>(profile_->GetOriginalProfile()));
28723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED,
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 content::Source<Profile>(profile_->GetOriginalProfile()));
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)PushMessagingAPI::~PushMessagingAPI() {
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
295a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)PushMessagingAPI* PushMessagingAPI::Get(content::BrowserContext* context) {
296a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return BrowserContextKeyedAPIFactory<PushMessagingAPI>::Get(context);
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void PushMessagingAPI::Shutdown() {
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  event_router_.reset();
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  handler_.reset();
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
304a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)static base::LazyInstance<BrowserContextKeyedAPIFactory<PushMessagingAPI> >
305a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    g_factory = LAZY_INSTANCE_INITIALIZER;
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
308a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)BrowserContextKeyedAPIFactory<PushMessagingAPI>*
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)PushMessagingAPI::GetFactoryInstance() {
3105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return g_factory.Pointer();
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void PushMessagingAPI::Observe(int type,
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               const content::NotificationSource& source,
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               const content::NotificationDetails& details) {
316eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  invalidation::InvalidationService* invalidation_service =
317eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      invalidation::InvalidationServiceFactory::GetForProfile(profile_);
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // This may be NULL; for example, for the ChromeOS guest user. In these cases,
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // just return without setting up anything, since it won't work anyway.
320eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!invalidation_service)
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!event_router_)
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    event_router_.reset(new PushMessagingEventRouter(profile_));
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!handler_) {
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    handler_.reset(new PushMessagingInvalidationHandler(
327eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        invalidation_service, event_router_.get()));
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  switch (type) {
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case chrome::NOTIFICATION_EXTENSION_INSTALLED: {
331c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      const Extension* extension =
332c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          content::Details<const InstalledExtensionInfo>(details)->extension;
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (extension->HasAPIPermission(APIPermission::kPushMessaging)) {
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        handler_->SuppressInitialInvalidationsForExtension(extension->id());
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case chrome::NOTIFICATION_EXTENSION_LOADED: {
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const Extension* extension = content::Details<Extension>(details).ptr();
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (extension->HasAPIPermission(APIPermission::kPushMessaging)) {
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        handler_->RegisterExtension(extension->id());
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
34523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    case chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED: {
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const Extension* extension =
3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          content::Details<UnloadedExtensionInfo>(details)->extension;
3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (extension->HasAPIPermission(APIPermission::kPushMessaging)) {
3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        handler_->UnregisterExtension(extension->id());
3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    default:
3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      NOTREACHED();
3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void PushMessagingAPI::SetMapperForTest(
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<PushMessagingInvalidationMapper> mapper) {
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  handler_ = mapper.Pass();
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template <>
364a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void
365a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)BrowserContextKeyedAPIFactory<PushMessagingAPI>::DeclareFactoryDependencies() {
3665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
367eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DependsOn(invalidation::InvalidationServiceFactory::GetInstance());
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace extensions
371