Rewrite AndroidSyncSettings to be significantly simpler.
[chromium-blink-merge.git] / remoting / webapp / crd / js / oauth2_api_impl.js
blob18a71ce03d8e478d412e4430a63939eab7f468dc
1 // Copyright 2013 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.
5 /**
6  * @fileoverview
7  * OAuth2 API flow implementations.
8  */
10 'use strict';
12 /** @suppress {duplicate} */
13 var remoting = remoting || {};
15 /**
16  * @constructor
17  * @implements {remoting.OAuth2Api}
18  */
19 remoting.OAuth2ApiImpl = function() {
22 /** @private
23  *  @return {string} OAuth2 token URL.
24  */
25 remoting.OAuth2ApiImpl.prototype.getOAuth2TokenEndpoint_ = function() {
26   return remoting.settings.OAUTH2_BASE_URL + '/token';
29 /** @private
30  *  @return {string} OAuth2 userinfo API URL.
31  */
32 remoting.OAuth2ApiImpl.prototype.getOAuth2ApiUserInfoEndpoint_ = function() {
33   return remoting.settings.OAUTH2_API_BASE_URL + '/v1/userinfo';
37 /**
38  * Interprets HTTP error responses in authentication XMLHttpRequests.
39  *
40  * @private
41  * @param {number} xhrStatus Status (HTTP response code) of the XMLHttpRequest.
42  * @return {remoting.Error} An error code to be raised.
43  */
44 remoting.OAuth2ApiImpl.prototype.interpretXhrStatus_ =
45     function(xhrStatus) {
46   // Return AUTHENTICATION_FAILED by default, so that the user can try to
47   // recover from an unexpected failure by signing in again.
48   /** @type {remoting.Error} */
49   var error = remoting.Error.AUTHENTICATION_FAILED;
50   if (xhrStatus == 400 || xhrStatus == 401 || xhrStatus == 403) {
51     error = remoting.Error.AUTHENTICATION_FAILED;
52   } else if (xhrStatus == 502 || xhrStatus == 503) {
53     error = remoting.Error.SERVICE_UNAVAILABLE;
54   } else if (xhrStatus == 0) {
55     error = remoting.Error.NETWORK_FAILURE;
56   } else {
57     console.warn('Unexpected authentication response code: ' + xhrStatus);
58   }
59   return error;
62 /**
63  * Asynchronously retrieves a new access token from the server.
64  *
65  * @param {function(string, number): void} onDone Callback to invoke when
66  *     the access token and expiration time are successfully fetched.
67  * @param {function(remoting.Error):void} onError Callback invoked if an
68  *     error occurs.
69  * @param {string} clientId OAuth2 client ID.
70  * @param {string} clientSecret OAuth2 client secret.
71  * @param {string} refreshToken OAuth2 refresh token to be redeemed.
72  * @return {void} Nothing.
73  */
74 remoting.OAuth2ApiImpl.prototype.refreshAccessToken = function(
75     onDone, onError, clientId, clientSecret, refreshToken) {
76   /** @param {XMLHttpRequest} xhr */
77   var onResponse = function(xhr) {
78     if (xhr.status == 200) {
79       try {
80         // Don't use base.jsonParseSafe here unless you also include base.js,
81         // otherwise this won't work from the OAuth trampoline.
82         // TODO(jamiewalch): Fix this once we're no longer using the trampoline.
83         var tokens = JSON.parse(xhr.responseText);
84         onDone(tokens['access_token'], tokens['expires_in']);
85       } catch (/** @type {Error} */ err) {
86         console.error('Invalid "token" response from server:', err);
87         onError(remoting.Error.UNEXPECTED);
88       }
89     } else {
90       console.error('Failed to refresh token. Status: ' + xhr.status +
91                     ' response: ' + xhr.responseText);
92       onError(remoting.Error.fromHttpStatus(xhr.status));
93     }
94   };
96   remoting.xhr.start({
97     method: 'POST',
98     url: this.getOAuth2TokenEndpoint_(),
99     onDone: onResponse,
100     formContent: {
101       'client_id': clientId,
102       'client_secret': clientSecret,
103       'refresh_token': refreshToken,
104       'grant_type': 'refresh_token'
105     }
106   });
110  * Asynchronously exchanges an authorization code for access and refresh tokens.
112  * @param {function(string, string, number): void} onDone Callback to
113  *     invoke when the refresh token, access token and access token expiration
114  *     time are successfully fetched.
115  * @param {function(remoting.Error):void} onError Callback invoked if an
116  *     error occurs.
117  * @param {string} clientId OAuth2 client ID.
118  * @param {string} clientSecret OAuth2 client secret.
119  * @param {string} code OAuth2 authorization code.
120  * @param {string} redirectUri Redirect URI used to obtain this code.
121  * @return {void} Nothing.
122  */
123 remoting.OAuth2ApiImpl.prototype.exchangeCodeForTokens = function(
124     onDone, onError, clientId, clientSecret, code, redirectUri) {
125   /** @param {XMLHttpRequest} xhr */
126   var onResponse = function(xhr) {
127     if (xhr.status == 200) {
128       try {
129         // Don't use base.jsonParseSafe here unless you also include base.js,
130         // otherwise this won't work from the OAuth trampoline.
131         // TODO(jamiewalch): Fix this once we're no longer using the trampoline.
132         var tokens = JSON.parse(xhr.responseText);
133         onDone(tokens['refresh_token'],
134                tokens['access_token'], tokens['expires_in']);
135       } catch (/** @type {Error} */ err) {
136         console.error('Invalid "token" response from server:', err);
137         onError(remoting.Error.UNEXPECTED);
138       }
139     } else {
140       console.error('Failed to exchange code for token. Status: ' + xhr.status +
141                     ' response: ' + xhr.responseText);
142       onError(remoting.Error.fromHttpStatus(xhr.status));
143     }
144   };
146   remoting.xhr.start({
147     method: 'POST',
148     url: this.getOAuth2TokenEndpoint_(),
149     onDone: onResponse,
150     formContent: {
151       'client_id': clientId,
152       'client_secret': clientSecret,
153       'redirect_uri': redirectUri,
154       'code': code,
155       'grant_type': 'authorization_code'
156     }
157   });
161  * Get the user's email address.
163  * @param {function(string):void} onDone Callback invoked when the email
164  *     address is available.
165  * @param {function(remoting.Error):void} onError Callback invoked if an
166  *     error occurs.
167  * @param {string} token Access token.
168  * @return {void} Nothing.
169  */
170 remoting.OAuth2ApiImpl.prototype.getEmail = function(onDone, onError, token) {
171   /** @param {XMLHttpRequest} xhr */
172   var onResponse = function(xhr) {
173     if (xhr.status == 200) {
174       try {
175         var result = JSON.parse(xhr.responseText);
176         onDone(result['email']);
177       } catch (/** @type {Error} */ err) {
178         console.error('Invalid "userinfo" response from server:', err);
179         onError(remoting.Error.UNEXPECTED);
180       }
181     } else {
182       console.error('Failed to get email. Status: ' + xhr.status +
183                     ' response: ' + xhr.responseText);
184       onError(remoting.Error.fromHttpStatus(xhr.status));
185     }
186   };
187   remoting.xhr.start({
188     method: 'GET',
189     url: this.getOAuth2ApiUserInfoEndpoint_(),
190     onDone: onResponse,
191     oauthToken: token
192   });
196  * Get the user's email address and full name.
198  * @param {function(string, string):void} onDone Callback invoked when the email
199  *     address and full name are available.
200  * @param {function(remoting.Error):void} onError Callback invoked if an
201  *     error occurs.
202  * @param {string} token Access token.
203  * @return {void} Nothing.
204  */
205 remoting.OAuth2ApiImpl.prototype.getUserInfo =
206     function(onDone, onError, token) {
207   /** @param {XMLHttpRequest} xhr */
208   var onResponse = function(xhr) {
209     if (xhr.status == 200) {
210       try {
211         var result = JSON.parse(xhr.responseText);
212         onDone(result['email'], result['name']);
213       } catch (/** @type {Error} */ err) {
214         console.error('Invalid "userinfo" response from server:', err);
215         onError(remoting.Error.UNEXPECTED);
216       }
217     } else {
218       console.error('Failed to get user info. Status: ' + xhr.status +
219                     ' response: ' + xhr.responseText);
220       onError(remoting.Error.fromHttpStatus(xhr.status));
221     }
222   };
223   remoting.xhr.start({
224     method: 'GET',
225     url: this.getOAuth2ApiUserInfoEndpoint_(),
226     onDone: onResponse,
227     oauthToken: token
228   });
231 /** @type {remoting.OAuth2Api} */
232 remoting.oauth2Api = new remoting.OAuth2ApiImpl();