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/extensions/api/push_messaging/obfuscated_gaia_id_fetcher.h"
6
7 #include <vector>
8
9 #include "base/json/json_reader.h"
10 #include "base/values.h"
11 #include "google_apis/gaia/google_service_auth_error.h"
12 #include "net/url_request/url_fetcher.h"
13 #include "net/url_request/url_request_status.h"
14
15 using net::URLFetcher;
16 using net::URLRequestContextGetter;
17 using net::URLRequestStatus;
18
19 namespace {
20
21 // URL of the service to get obfuscated Gaia ID (here misnamed channel ID).
22 static const char kCWSChannelServiceURL[] =
23 "https://www.googleapis.com/gcm_for_chrome/v1/channels/id";
24
CreateAuthError(const URLFetcher * source)25 GoogleServiceAuthError CreateAuthError(const URLFetcher* source) {
26 if (source->GetStatus().status() == URLRequestStatus::CANCELED) {
27 return GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED);
28 } else {
29 // TODO(munjal): Improve error handling. Currently we return connection
30 // error for even application level errors. We need to either expand the
31 // GoogleServiceAuthError enum or create a new one to report better
32 // errors.
33 if (source->GetStatus().is_success()) {
34 DLOG(WARNING) << "Remote server returned " << source->GetResponseCode();
35 return GoogleServiceAuthError::FromConnectionError(
36 source->GetResponseCode());
37 } else {
38 DLOG(WARNING) << "URLFetcher failed: " << source->GetStatus().error();
39 return GoogleServiceAuthError::FromConnectionError(
40 source->GetStatus().error());
41 }
42 }
43 }
44
45 } // namespace
46
47 namespace extensions {
48
ObfuscatedGaiaIdFetcher(URLRequestContextGetter * context,Delegate * delegate,const std::string & access_token)49 ObfuscatedGaiaIdFetcher::ObfuscatedGaiaIdFetcher(
50 URLRequestContextGetter* context,
51 Delegate* delegate,
52 const std::string& access_token)
53 : OAuth2ApiCallFlow(context, std::string(), access_token, GetScopes()),
54 delegate_(delegate) {
55 DCHECK(delegate);
56 }
57
~ObfuscatedGaiaIdFetcher()58 ObfuscatedGaiaIdFetcher::~ObfuscatedGaiaIdFetcher() { }
59
60 // Returns a vector of scopes needed to call the API to get obfuscated Gaia ID.
GetScopes()61 std::vector<std::string> ObfuscatedGaiaIdFetcher::GetScopes() {
62 std::vector<std::string> scopes;
63 scopes.push_back("https://www.googleapis.com/auth/gcm_for_chrome.readonly");
64 return scopes;
65 }
66
ReportSuccess(const std::string & obfuscated_id)67 void ObfuscatedGaiaIdFetcher::ReportSuccess(const std::string& obfuscated_id) {
68 if (delegate_)
69 delegate_->OnObfuscatedGaiaIdFetchSuccess(obfuscated_id);
70 }
71
ReportFailure(const GoogleServiceAuthError & error)72 void ObfuscatedGaiaIdFetcher::ReportFailure(
73 const GoogleServiceAuthError& error) {
74 if (delegate_)
75 delegate_->OnObfuscatedGaiaIdFetchFailure(error);
76 }
77
CreateApiCallUrl()78 GURL ObfuscatedGaiaIdFetcher::CreateApiCallUrl() {
79 return GURL(kCWSChannelServiceURL);
80 }
81
CreateApiCallBody()82 std::string ObfuscatedGaiaIdFetcher::CreateApiCallBody() {
83 // Nothing to do here, we don't need a body for this request, the URL
84 // encodes all the proper arguments.
85 return std::string();
86 }
87
ProcessApiCallSuccess(const net::URLFetcher * source)88 void ObfuscatedGaiaIdFetcher::ProcessApiCallSuccess(
89 const net::URLFetcher* source) {
90 // TODO(munjal): Change error code paths in this method to report an
91 // internal error.
92 std::string response_body;
93 CHECK(source->GetResponseAsString(&response_body));
94
95 std::string obfuscated_id;
96 if (ParseResponse(response_body, &obfuscated_id))
97 ReportSuccess(obfuscated_id);
98 else
99 // we picked 101 arbitrarily to help us correlate the error with this code.
100 ReportFailure(GoogleServiceAuthError::FromConnectionError(101));
101 }
102
ProcessApiCallFailure(const net::URLFetcher * source)103 void ObfuscatedGaiaIdFetcher::ProcessApiCallFailure(
104 const net::URLFetcher* source) {
105 ReportFailure(CreateAuthError(source));
106 }
107
ProcessNewAccessToken(const std::string & obfuscated_id)108 void ObfuscatedGaiaIdFetcher::ProcessNewAccessToken(
109 const std::string& obfuscated_id) {
110 // We generate a new access token every time instead of storing the access
111 // token since access tokens expire every hour and we expect to get
112 // obfuscated Gaia ID very infrequently.
113 }
114
ProcessMintAccessTokenFailure(const GoogleServiceAuthError & error)115 void ObfuscatedGaiaIdFetcher::ProcessMintAccessTokenFailure(
116 const GoogleServiceAuthError& error) {
117 // We failed to generate the token needed to call the API to get
118 // the obfuscated Gaia ID, so report failure to the caller.
119 ReportFailure(error);
120 }
121
122 // static
ParseResponse(const std::string & data,std::string * result)123 bool ObfuscatedGaiaIdFetcher::ParseResponse(
124 const std::string& data, std::string* result) {
125 scoped_ptr<base::Value> value(base::JSONReader::Read(data));
126
127 if (!value.get())
128 return false;
129
130 base::DictionaryValue* dict = NULL;
131 if (!value->GetAsDictionary(&dict))
132 return false;
133
134 return dict->GetString("id", result);
135 }
136
137 } // namespace extensions
138