summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--remoting/webapp/jscompiler_hacks.js2
-rw-r--r--remoting/webapp/oauth2.js24
-rw-r--r--remoting/webapp/oauth2_callback.js10
3 files changed, 30 insertions, 6 deletions
diff --git a/remoting/webapp/jscompiler_hacks.js b/remoting/webapp/jscompiler_hacks.js
index 28551e2..a28ee59 100644
--- a/remoting/webapp/jscompiler_hacks.js
+++ b/remoting/webapp/jscompiler_hacks.js
@@ -31,7 +31,7 @@ Element.ALLOW_KEYBOARD_INPUT;
/** @return {void} Nothing. */
Element.prototype.webkitRequestFullScreen = function(flags) {};
-/** @type {{getRandomValues: function(Uint16Array):void}} */
+/** @type {{getRandomValues: function((Uint16Array|Uint8Array)):void}} */
Window.prototype.crypto;
/** @constructor
diff --git a/remoting/webapp/oauth2.js b/remoting/webapp/oauth2.js
index 9956f5a..d67c1ec 100644
--- a/remoting/webapp/oauth2.js
+++ b/remoting/webapp/oauth2.js
@@ -33,6 +33,8 @@ remoting.OAuth2.prototype.KEY_REFRESH_TOKEN_REVOKABLE_ =
/** @private */
remoting.OAuth2.prototype.KEY_ACCESS_TOKEN_ = 'oauth2-access-token';
/** @private */
+remoting.OAuth2.prototype.KEY_XSRF_TOKEN_ = 'oauth2-xsrf-token';
+/** @private */
remoting.OAuth2.prototype.KEY_EMAIL_ = 'remoting-email';
// Constants for parameters used in retrieving the OAuth2 credentials.
@@ -262,16 +264,29 @@ remoting.OAuth2.prototype.refreshAccessToken_ = function(onDone) {
};
/**
+ * @private
+ * @return {string} A URL-Safe Base64-encoded 128-bit random value. */
+remoting.OAuth2.prototype.generateXsrfToken_ = function() {
+ var random = new Uint8Array(16);
+ window.crypto.getRandomValues(random);
+ var base64Token = window.btoa(String.fromCharCode.apply(null, random));
+ return base64Token.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
+};
+
+/**
* Redirect page to get a new OAuth2 Refresh Token.
*
* @return {void} Nothing.
*/
remoting.OAuth2.prototype.doAuthRedirect = function() {
+ var xsrf_token = this.generateXsrfToken_();
+ window.localStorage.setItem(this.KEY_XSRF_TOKEN_, xsrf_token);
var GET_CODE_URL = 'https://accounts.google.com/o/oauth2/auth?' +
remoting.xhr.urlencodeParamHash({
'client_id': this.CLIENT_ID_,
'redirect_uri': this.REDIRECT_URI_,
'scope': this.SCOPE_,
+ 'state': xsrf_token,
'response_type': 'code',
'access_type': 'offline',
'approval_prompt': 'force'
@@ -283,11 +298,18 @@ remoting.OAuth2.prototype.doAuthRedirect = function() {
* Asynchronously exchanges an authorization code for a refresh token.
*
* @param {string} code The new refresh token.
+ * @param {string} state The state parameter received from the OAuth redirect.
* @param {function(XMLHttpRequest):void} onDone Callback to invoke on
* completion.
* @return {void} Nothing.
*/
-remoting.OAuth2.prototype.exchangeCodeForToken = function(code, onDone) {
+remoting.OAuth2.prototype.exchangeCodeForToken = function(code, state, onDone) {
+ var xsrf_token = window.localStorage.getItem(this.KEY_XSRF_TOKEN_);
+ window.localStorage.removeItem(this.KEY_XSRF_TOKEN_);
+ if (xsrf_token == undefined || state != xsrf_token) {
+ // Invalid XSRF token, or unexpected OAuth2 redirect. Abort.
+ onDone(null);
+ }
var parameters = {
'client_id': this.CLIENT_ID_,
'client_secret': this.CLIENT_SECRET_,
diff --git a/remoting/webapp/oauth2_callback.js b/remoting/webapp/oauth2_callback.js
index b5c0558..6d94dca 100644
--- a/remoting/webapp/oauth2_callback.js
+++ b/remoting/webapp/oauth2_callback.js
@@ -21,11 +21,13 @@ function retrieveRefreshToken() {
var pair = parts[i].split('=');
queryArgs[pair[0]] = pair[1];
}
- if ('code' in queryArgs) {
+
+ if ('code' in queryArgs && 'state' in queryArgs) {
var oauth2 = new remoting.OAuth2();
- oauth2.exchangeCodeForToken(queryArgs['code'], function() {
- window.location.replace(chrome.extension.getURL('main.html'));
- });
+ oauth2.exchangeCodeForToken(queryArgs['code'], queryArgs['state'],
+ function() {
+ window.location.replace(chrome.extension.getURL('main.html'));
+ });
} else {
window.location.replace(chrome.extension.getURL('main.html'));
}