1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
|
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_EXTENSIONS_APP_NOTIFY_CHANNEL_SETUP_H_
#define CHROME_BROWSER_EXTENSIONS_APP_NOTIFY_CHANNEL_SETUP_H_
#include <string>
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/extensions/app_notify_channel_ui.h"
#include "chrome/common/net/gaia/oauth2_access_token_consumer.h"
#include "chrome/common/net/gaia/oauth2_access_token_fetcher.h"
#include "googleurl/src/gurl.h"
#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_fetcher_delegate.h"
class AppNotifyChannelSetupTest;
class Profile;
// This class uses the browser login credentials to setup app notifications
// for a given app.
//
// Performs the following steps when Start() is called:
// 1. If the user is not logged in, prompt the user to login.
// 2. OAuth2: Record a notifications grant for the user and the given app.
// 3. Get notifications channel id for the current user.
// 4. Call the delegate passed in to the constructor with the results of
// the above steps.
class AppNotifyChannelSetup
: public net::URLFetcherDelegate,
public AppNotifyChannelUI::Delegate,
public OAuth2AccessTokenConsumer,
public base::RefCountedThreadSafe<AppNotifyChannelSetup> {
public:
// These are the various error conditions, made public for use by the test
// interceptor.
enum SetupError {
NONE,
AUTH_ERROR,
INTERNAL_ERROR,
USER_CANCELLED,
// This is used for histograms, and should always be the last value.
SETUP_ERROR_BOUNDARY
};
class Delegate {
public:
// If successful, |channel_id| will be non-empty. On failure, |channel_id|
// will be empty and |error| will contain an error to report to the JS
// callback.
virtual void AppNotifyChannelSetupComplete(
const std::string& channel_id,
const std::string& error,
const AppNotifyChannelSetup* setup) = 0;
};
// For tests, we allow intercepting the request to setup the channel and
// forcing the return of a certain result to the delegate.
class InterceptorForTests {
public:
virtual void DoIntercept(
const AppNotifyChannelSetup* setup,
std::string* result_channel_id,
AppNotifyChannelSetup::SetupError* result_error) = 0;
};
static void SetInterceptorForTests(InterceptorForTests* interceptor);
// Ownership of |ui| is transferred to this object.
AppNotifyChannelSetup(Profile* profile,
const std::string& extension_id,
const std::string& client_id,
const GURL& requestor_url,
int return_route_id,
int callback_id,
AppNotifyChannelUI* ui,
base::WeakPtr<Delegate> delegate);
AppNotifyChannelUI* ui() { return ui_.get(); }
// This begins the process of fetching the channel id using the browser login
// credentials (or using |ui_| to prompt for login if needed).
void Start();
// OAuth2AccessTokenConsumer implementation.
virtual void OnGetTokenSuccess(const std::string& access_token,
const base::Time& expiration_time) OVERRIDE;
virtual void OnGetTokenFailure(const GoogleServiceAuthError& error) OVERRIDE;
// Getters for various members.
const std::string& extension_id() const { return extension_id_; }
const std::string& client_id() const { return client_id_; }
int return_route_id() const { return return_route_id_; }
int callback_id() const { return callback_id_; }
protected:
// net::URLFetcherDelegate.
virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
// AppNotifyChannelUI::Delegate.
virtual void OnSyncSetupResult(bool enabled) OVERRIDE;
private:
enum State {
INITIAL,
LOGIN_STARTED,
LOGIN_DONE,
FETCH_ACCESS_TOKEN_STARTED,
FETCH_ACCESS_TOKEN_DONE,
RECORD_GRANT_STARTED,
RECORD_GRANT_DONE,
CHANNEL_ID_SETUP_STARTED,
CHANNEL_ID_SETUP_DONE,
ERROR_STATE
};
friend class base::RefCountedThreadSafe<AppNotifyChannelSetup>;
friend class AppNotifyChannelSetupTest;
virtual ~AppNotifyChannelSetup();
// Creates an instance of URLFetcher that does not send or save cookies.
// The URLFether's method will be GET if body is empty, POST otherwise.
// Caller owns the returned instance.
net::URLFetcher* CreateURLFetcher(
const GURL& url, const std::string& body, const std::string& auth_token);
void BeginLogin();
void EndLogin(bool success);
void BeginGetAccessToken();
void EndGetAccessToken(bool success);
void BeginRecordGrant();
void EndRecordGrant(const net::URLFetcher* source);
void BeginGetChannelId();
void EndGetChannelId(const net::URLFetcher* source);
void ReportResult(const std::string& channel_id, SetupError error);
static std::string GetErrorString(SetupError error);
static GURL GetCWSChannelServiceURL();
static GURL GetOAuth2IssueTokenURL();
static std::string MakeOAuth2IssueTokenBody(
const std::string& oauth_client_id, const std::string& extension_id);
static std::string MakeAuthorizationHeader(const std::string& auth_token);
static bool ParseCWSChannelServiceResponse(
const std::string& data, std::string* result);
// Checks if the user needs to be prompted for login.
bool ShouldPromptForLogin() const;
void RegisterForTokenServiceNotifications();
void UnregisterForTokenServiceNotifications();
Profile* profile_;
std::string extension_id_;
std::string client_id_;
GURL requestor_url_;
int return_route_id_;
int callback_id_;
base::WeakPtr<Delegate> delegate_;
scoped_ptr<net::URLFetcher> url_fetcher_;
scoped_ptr<OAuth2AccessTokenFetcher> oauth2_fetcher_;
scoped_ptr<AppNotifyChannelUI> ui_;
State state_;
std::string oauth2_access_token_;
// Keeps track of whether we have encountered failure in OAuth2 access
// token generation already. We use this to prevent us from doing an
// infinite loop of trying to generate access token, if that fails, try
// to login the user and generate access token, etc.
bool oauth2_access_token_failure_;
DISALLOW_COPY_AND_ASSIGN(AppNotifyChannelSetup);
};
#endif // CHROME_BROWSER_EXTENSIONS_APP_NOTIFY_CHANNEL_SETUP_H_
|