Upstream version 8.37.180.0
[platform/framework/web/crosswalk.git] / src / remoting / webapp / identity.js
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 /**
6  * @fileoverview
7  * Wrapper class for Chrome's identity API.
8  */
9
10 'use strict';
11
12 /** @suppress {duplicate} */
13 var remoting = remoting || {};
14
15 /**
16  * TODO(jamiewalch): Remove remoting.OAuth2 from this type annotation when
17  * the Apps v2 work is complete.
18  *
19  * @type {remoting.Identity|remoting.OAuth2}
20  */
21 remoting.identity = null;
22
23 /**
24  * @param {function(function():void):void} consentCallback Callback invoked if
25  *     user consent is required. The callback is passed a continuation function
26  *     which must be called from an interactive event handler (e.g. "click").
27  * @constructor
28  */
29 remoting.Identity = function(consentCallback) {
30   /** @private */
31   this.consentCallback_ = consentCallback;
32   /** @type {?string} @private */
33   this.email_ = null;
34   /** @type {Array.<remoting.Identity.Callbacks>} */
35   this.pendingCallbacks_ = [];
36 };
37
38 /**
39  * Call a function with an access token.
40  *
41  * @param {function(string):void} onOk Function to invoke with access token if
42  *     an access token was successfully retrieved.
43  * @param {function(remoting.Error):void} onError Function to invoke with an
44  *     error code on failure.
45  * @return {void} Nothing.
46  */
47 remoting.Identity.prototype.callWithToken = function(onOk, onError) {
48   this.pendingCallbacks_.push(new remoting.Identity.Callbacks(onOk, onError));
49   if (this.pendingCallbacks_.length == 1) {
50     chrome.identity.getAuthToken(
51         { 'interactive': false },
52         this.onAuthComplete_.bind(this, false));
53   }
54 };
55
56 /**
57  * Remove the cached auth token, if any.
58  *
59  * @param {function():void} onDone Completion callback.
60  * @return {void} Nothing.
61  */
62 remoting.Identity.prototype.removeCachedAuthToken = function(onDone) {
63   /** @param {string} token */
64   var onToken = function(token) {
65     if (token) {
66       chrome.identity.removeCachedAuthToken({ 'token': token }, onDone);
67     } else {
68       onDone();
69     }
70   };
71   chrome.identity.getAuthToken({ 'interactive': false }, onToken);
72 };
73
74 /**
75  * Get the user's email address.
76  *
77  * @param {function(string):void} onOk Callback invoked when the email
78  *     address is available.
79  * @param {function(remoting.Error):void} onError Callback invoked if an
80  *     error occurs.
81  * @return {void} Nothing.
82  */
83 remoting.Identity.prototype.getEmail = function(onOk, onError) {
84   /** @type {remoting.Identity} */
85   var that = this;
86   /** @param {string} email */
87   var onResponse = function(email) {
88     that.email_ = email;
89     onOk(email);
90   };
91
92   this.callWithToken(
93       remoting.OAuth2Api.getEmail.bind(null, onResponse, onError), onError);
94 };
95
96 /**
97  * Get the user's email address, or null if no successful call to getEmail
98  * has been made.
99  *
100  * @return {?string} The cached email address, if available.
101  */
102 remoting.Identity.prototype.getCachedEmail = function() {
103   return this.email_;
104 };
105
106 /**
107  * Callback for the getAuthToken API.
108  *
109  * @param {boolean} interactive The value of the "interactive" parameter to
110  *     getAuthToken.
111  * @param {?string} token The auth token, or null if the request failed.
112  * @private
113  */
114 remoting.Identity.prototype.onAuthComplete_ = function(interactive, token) {
115   // Pass the token to the callback(s) if it was retrieved successfully.
116   if (token) {
117     while (this.pendingCallbacks_.length > 0) {
118       var callback = /** @type {remoting.Identity.Callbacks} */
119           this.pendingCallbacks_.shift();
120       callback.onOk(token);
121     }
122     return;
123   }
124
125   // If not, pass an error back to the callback(s) if we've already prompted the
126   // user for permission.
127   // TODO(jamiewalch): Figure out what to do with the error in this case.
128   if (interactive) {
129     console.error(chrome.runtime.lastError);
130     while (this.pendingCallbacks_.length > 0) {
131       var callback = /** @type {remoting.Identity.Callbacks} */
132           this.pendingCallbacks_.shift();
133       callback.onError(remoting.Error.UNEXPECTED);
134     }
135     return;
136   }
137
138   // If there's no token, but we haven't yet prompted for permission, do so
139   // now. The consent callback is responsible for continuing the auth flow.
140   this.consentCallback_(this.onAuthContinue_.bind(this));
141 };
142
143 /**
144  * Called in response to the user signing in to the web-app.
145  *
146  * @private
147  */
148 remoting.Identity.prototype.onAuthContinue_ = function() {
149   chrome.identity.getAuthToken(
150       { 'interactive': true },
151       this.onAuthComplete_.bind(this, true));
152 };
153
154 /**
155  * Internal representation for pair of callWithToken callbacks.
156  *
157  * @param {function(string):void} onOk
158  * @param {function(remoting.Error):void} onError
159  * @constructor
160  * @private
161  */
162 remoting.Identity.Callbacks = function(onOk, onError) {
163   /** @type {function(string):void} */
164   this.onOk = onOk;
165   /** @type {function(remoting.Error):void} */
166   this.onError = onError;
167 };
168
169 /**
170  * Returns whether the web app has authenticated with the Google services.
171  *
172  * @return {boolean}
173  */
174 remoting.Identity.prototype.isAuthenticated = function() {
175   return remoting.identity.email_ != null;
176 };