18ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 28ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Copyright (c) 2010 The Chromium Authors. All rights reserved. Use of this 38ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * source code is governed by a BSD-style license that can be found in the 48ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * LICENSE file. 58ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 68ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 78ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 88ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Constructor - no need to invoke directly, call initBackgroundPage instead. 98ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @constructor 108ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} url_request_token The OAuth request token URL. 118ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} url_auth_token The OAuth authorize token URL. 128ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} url_access_token The OAuth access token URL. 138ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} consumer_key The OAuth consumer key. 148ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} consumer_secret The OAuth consumer secret. 158ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} oauth_scope The OAuth scope parameter. 168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Object} opt_args Optional arguments. Recognized parameters: 178ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * "app_name" {String} Name of the current application 188ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * "callback_page" {String} If you renamed chrome_ex_oauth.html, the name 198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * this file was renamed to. 208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 218ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenfunction ChromeExOAuth(url_request_token, url_auth_token, url_access_token, 228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen consumer_key, consumer_secret, oauth_scope, opt_args) { 238ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen this.url_request_token = url_request_token; 248ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen this.url_auth_token = url_auth_token; 258ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen this.url_access_token = url_access_token; 268ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen this.consumer_key = consumer_key; 278ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen this.consumer_secret = consumer_secret; 288ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen this.oauth_scope = oauth_scope; 298ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen this.app_name = opt_args && opt_args['app_name'] || 308ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen "ChromeExOAuth Library"; 318ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen this.key_token = "oauth_token"; 328ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen this.key_token_secret = "oauth_token_secret"; 338ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen this.callback_page = opt_args && opt_args['callback_page'] || 348ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen "chrome_ex_oauth.html"; 358ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen this.auth_params = {}; 368ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (opt_args && opt_args['auth_params']) { 378ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen for (key in opt_args['auth_params']) { 388ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (opt_args['auth_params'].hasOwnProperty(key)) { 398ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen this.auth_params[key] = opt_args['auth_params'][key]; 408ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 418ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 428ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 438ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}; 448ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 458ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/******************************************************************************* 468ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * PUBLIC API METHODS 478ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Call these from your background page. 488ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen ******************************************************************************/ 498ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 508ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 518ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Initializes the OAuth helper from the background page. You must call this 528ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * before attempting to make any OAuth calls. 538ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Object} oauth_config Configuration parameters in a JavaScript object. 548ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * The following parameters are recognized: 558ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * "request_url" {String} OAuth request token URL. 568ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * "authorize_url" {String} OAuth authorize token URL. 578ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * "access_url" {String} OAuth access token URL. 588ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * "consumer_key" {String} OAuth consumer key. 598ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * "consumer_secret" {String} OAuth consumer secret. 608ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * "scope" {String} OAuth access scope. 618ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * "app_name" {String} Application name. 628ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * "auth_params" {Object} Additional parameters to pass to the 638ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Authorization token URL. For an example, 'hd', 'hl', 'btmpl': 648ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * http://code.google.com/apis/accounts/docs/OAuth_ref.html#GetAuth 658ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {ChromeExOAuth} An initialized ChromeExOAuth object. 668ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 678ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenChromeExOAuth.initBackgroundPage = function(oauth_config) { 688ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen window.chromeExOAuthConfig = oauth_config; 698ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen window.chromeExOAuth = ChromeExOAuth.fromConfig(oauth_config); 708ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen window.chromeExOAuthRedirectStarted = false; 718ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen window.chromeExOAuthRequestingAccess = false; 728ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 738ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var url_match = chrome.extension.getURL(window.chromeExOAuth.callback_page); 748ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var tabs = {}; 758ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) { 768ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (changeInfo.url && 778ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen changeInfo.url.substr(0, url_match.length) === url_match && 788ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen changeInfo.url != tabs[tabId] && 798ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen window.chromeExOAuthRequestingAccess == false) { 808ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen chrome.tabs.create({ 'url' : changeInfo.url }, function(tab) { 818ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen tabs[tab.id] = tab.url; 828ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen chrome.tabs.remove(tabId); 838ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen }); 848ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 858ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen }); 868ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 878ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return window.chromeExOAuth; 888ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}; 898ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 908ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 918ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Authorizes the current user with the configued API. You must call this 928ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * before calling sendSignedRequest. 938ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Function} callback A function to call once an access token has 948ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * been obtained. This callback will be passed the following arguments: 958ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * token {String} The OAuth access token. 968ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * secret {String} The OAuth access token secret. 978ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 988ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenChromeExOAuth.prototype.authorize = function(callback) { 998ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (this.hasToken()) { 1008ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen callback(this.getToken(), this.getTokenSecret()); 1018ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } else { 1028ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen window.chromeExOAuthOnAuthorize = function(token, secret) { 1038ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen callback(token, secret); 1048ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen }; 1058ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen chrome.tabs.create({ 'url' :chrome.extension.getURL(this.callback_page) }); 1068ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 1078ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}; 1088ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1098ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 1108ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Clears any OAuth tokens stored for this configuration. Effectively a 1118ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * "logout" of the configured OAuth API. 1128ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 1138ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenChromeExOAuth.prototype.clearTokens = function() { 1148ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen delete localStorage[this.key_token + encodeURI(this.oauth_scope)]; 1158ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen delete localStorage[this.key_token_secret + encodeURI(this.oauth_scope)]; 1168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}; 1178ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1188ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 1198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Returns whether a token is currently stored for this configuration. 1208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Effectively a check to see whether the current user is "logged in" to 1218ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * the configured OAuth API. 1228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Boolean} True if an access token exists. 1238ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 1248ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenChromeExOAuth.prototype.hasToken = function() { 1258ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return !!this.getToken(); 1268ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}; 1278ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1288ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 1298ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Makes an OAuth-signed HTTP request with the currently authorized tokens. 1308ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} url The URL to send the request to. Querystring parameters 1318ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * should be omitted. 1328ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Function} callback A function to be called once the request is 1338ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * completed. This callback will be passed the following arguments: 1348ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * responseText {String} The text response. 1358ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * xhr {XMLHttpRequest} The XMLHttpRequest object which was used to 1368ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * send the request. Useful if you need to check response status 1378ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * code, etc. 1388ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Object} opt_params Additional parameters to configure the request. 1398ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * The following parameters are accepted: 1408ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * "method" {String} The HTTP method to use. Defaults to "GET". 1418ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * "body" {String} A request body to send. Defaults to null. 1428ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * "parameters" {Object} Query parameters to include in the request. 1438ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * "headers" {Object} Additional headers to include in the request. 1448ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 1458ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenChromeExOAuth.prototype.sendSignedRequest = function(url, callback, 1468ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen opt_params) { 1478ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var method = opt_params && opt_params['method'] || 'GET'; 1488ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var body = opt_params && opt_params['body'] || null; 1498ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var params = opt_params && opt_params['parameters'] || {}; 1508ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var headers = opt_params && opt_params['headers'] || {}; 1518ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1528ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var signedUrl = this.signURL(url, method, params); 1538ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1548ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen ChromeExOAuth.sendRequest(method, signedUrl, headers, body, function (xhr) { 1558ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (xhr.readyState == 4) { 1568ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen callback(xhr.responseText, xhr); 1578ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 1588ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen }); 1598ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}; 1608ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1618ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 1628ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Adds the required OAuth parameters to the given url and returns the 1638ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * result. Useful if you need a signed url but don't want to make an XHR 1648ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * request. 1658ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} method The http method to use. 1668ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} url The base url of the resource you are querying. 1678ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Object} opt_params Query parameters to include in the request. 1688ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {String} The base url plus any query params plus any OAuth params. 1698ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 1708ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenChromeExOAuth.prototype.signURL = function(url, method, opt_params) { 1718ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var token = this.getToken(); 1728ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var secret = this.getTokenSecret(); 1738ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (!token || !secret) { 1748ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen throw new Error("No oauth token or token secret"); 1758ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 1768ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1778ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var params = opt_params || {}; 1788ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1798ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var result = OAuthSimple().sign({ 1808ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen action : method, 1818ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen path : url, 1828ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen parameters : params, 1838ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen signatures: { 1848ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen consumer_key : this.consumer_key, 1858ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen shared_secret : this.consumer_secret, 1868ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen oauth_secret : secret, 1878ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen oauth_token: token 1888ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 1898ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen }); 1908ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1918ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return result.signed_url; 1928ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}; 1938ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 1948ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 1958ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Generates the Authorization header based on the oauth parameters. 1968ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} url The base url of the resource you are querying. 1978ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Object} opt_params Query parameters to include in the request. 1988ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {String} An Authorization header containing the oauth_* params. 1998ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 2008ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenChromeExOAuth.prototype.getAuthorizationHeader = function(url, method, 2018ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen opt_params) { 2028ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var token = this.getToken(); 2038ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var secret = this.getTokenSecret(); 2048ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (!token || !secret) { 2058ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen throw new Error("No oauth token or token secret"); 2068ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 2078ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 2088ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var params = opt_params || {}; 2098ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 2108ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return OAuthSimple().getHeaderString({ 2118ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen action: method, 2128ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen path : url, 2138ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen parameters : params, 2148ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen signatures: { 2158ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen consumer_key : this.consumer_key, 2168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen shared_secret : this.consumer_secret, 2178ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen oauth_secret : secret, 2188ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen oauth_token: token 2198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 2208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen }); 2218ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}; 2228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 2238ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/******************************************************************************* 2248ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * PRIVATE API METHODS 2258ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Used by the library. There should be no need to call these methods directly. 2268ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen ******************************************************************************/ 2278ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 2288ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 2298ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Creates a new ChromeExOAuth object from the supplied configuration object. 2308ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Object} oauth_config Configuration parameters in a JavaScript object. 2318ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * The following parameters are recognized: 2328ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * "request_url" {String} OAuth request token URL. 2338ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * "authorize_url" {String} OAuth authorize token URL. 2348ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * "access_url" {String} OAuth access token URL. 2358ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * "consumer_key" {String} OAuth consumer key. 2368ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * "consumer_secret" {String} OAuth consumer secret. 2378ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * "scope" {String} OAuth access scope. 2388ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * "app_name" {String} Application name. 2398ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * "auth_params" {Object} Additional parameters to pass to the 2408ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Authorization token URL. For an example, 'hd', 'hl', 'btmpl': 2418ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * http://code.google.com/apis/accounts/docs/OAuth_ref.html#GetAuth 2428ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {ChromeExOAuth} An initialized ChromeExOAuth object. 2438ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 2448ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenChromeExOAuth.fromConfig = function(oauth_config) { 2458ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return new ChromeExOAuth( 2468ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen oauth_config['request_url'], 2478ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen oauth_config['authorize_url'], 2488ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen oauth_config['access_url'], 2498ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen oauth_config['consumer_key'], 2508ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen oauth_config['consumer_secret'], 2518ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen oauth_config['scope'], 2528ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen { 2538ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 'app_name' : oauth_config['app_name'], 2548ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 'auth_params' : oauth_config['auth_params'] 2558ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 2568ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen ); 2578ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}; 2588ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 2598ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 2608ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Initializes chrome_ex_oauth.html and redirects the page if needed to start 2618ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * the OAuth flow. Once an access token is obtained, this function closes 2628ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * chrome_ex_oauth.html. 2638ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 2648ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenChromeExOAuth.initCallbackPage = function() { 2658ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var background_page = chrome.extension.getBackgroundPage(); 2668ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var oauth_config = background_page.chromeExOAuthConfig; 2678ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var oauth = ChromeExOAuth.fromConfig(oauth_config); 2688ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen background_page.chromeExOAuthRedirectStarted = true; 2698ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen oauth.initOAuthFlow(function (token, secret) { 2708ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen background_page.chromeExOAuthOnAuthorize(token, secret); 2718ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen background_page.chromeExOAuthRedirectStarted = false; 2728ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen chrome.tabs.getSelected(null, function (tab) { 2738ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen chrome.tabs.remove(tab.id); 2748ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen }); 2758ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen }); 2768ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}; 2778ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 2788ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 2798ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Sends an HTTP request. Convenience wrapper for XMLHttpRequest calls. 2808ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} method The HTTP method to use. 2818ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} url The URL to send the request to. 2828ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Object} headers Optional request headers in key/value format. 2838ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} body Optional body content. 2848ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Function} callback Function to call when the XMLHttpRequest's 2858ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * ready state changes. See documentation for XMLHttpRequest's 2868ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * onreadystatechange handler for more information. 2878ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 2888ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenChromeExOAuth.sendRequest = function(method, url, headers, body, callback) { 2898ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var xhr = new XMLHttpRequest(); 2908ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen xhr.onreadystatechange = function(data) { 2918ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen callback(xhr, data); 2928ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 2938ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen xhr.open(method, url, true); 2948ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (headers) { 2958ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen for (var header in headers) { 2968ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (headers.hasOwnProperty(header)) { 2978ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen xhr.setRequestHeader(header, headers[header]); 2988ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 2998ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 3008ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 3018ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen xhr.send(body); 3028ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}; 3038ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 3048ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 3058ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Decodes a URL-encoded string into key/value pairs. 3068ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} encoded An URL-encoded string. 3078ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Object} An object representing the decoded key/value pairs found 3088ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * in the encoded string. 3098ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 3108ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenChromeExOAuth.formDecode = function(encoded) { 3118ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var params = encoded.split("&"); 3128ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var decoded = {}; 3138ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen for (var i = 0, param; param = params[i]; i++) { 3148ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var keyval = param.split("="); 3158ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (keyval.length == 2) { 3168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var key = ChromeExOAuth.fromRfc3986(keyval[0]); 3178ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var val = ChromeExOAuth.fromRfc3986(keyval[1]); 3188ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen decoded[key] = val; 3198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 3208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 3218ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return decoded; 3228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}; 3238ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 3248ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 3258ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Returns the current window's querystring decoded into key/value pairs. 3268ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Object} A object representing any key/value pairs found in the 3278ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * current window's querystring. 3288ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 3298ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenChromeExOAuth.getQueryStringParams = function() { 3308ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var urlparts = window.location.href.split("?"); 3318ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (urlparts.length >= 2) { 3328ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var querystring = urlparts.slice(1).join("?"); 3338ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return ChromeExOAuth.formDecode(querystring); 3348ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 3358ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return {}; 3368ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}; 3378ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 3388ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 3398ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Binds a function call to a specific object. This function will also take 3408ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * a variable number of additional arguments which will be prepended to the 3418ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * arguments passed to the bound function when it is called. 3428ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Function} func The function to bind. 3438ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Object} obj The object to bind to the function's "this". 3448ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {Function} A closure that will call the bound function. 3458ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 3468ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenChromeExOAuth.bind = function(func, obj) { 3478ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var newargs = Array.prototype.slice.call(arguments).slice(2); 3488ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return function() { 3498ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var combinedargs = newargs.concat(Array.prototype.slice.call(arguments)); 3508ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen func.apply(obj, combinedargs); 3518ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen }; 3528ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}; 3538ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 3548ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 3558ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Encodes a value according to the RFC3986 specification. 3568ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} val The string to encode. 3578ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 3588ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenChromeExOAuth.toRfc3986 = function(val){ 3598ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return encodeURIComponent(val) 3608ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen .replace(/\!/g, "%21") 3618ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen .replace(/\*/g, "%2A") 3628ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen .replace(/'/g, "%27") 3638ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen .replace(/\(/g, "%28") 3648ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen .replace(/\)/g, "%29"); 3658ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}; 3668ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 3678ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 3688ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Decodes a string that has been encoded according to RFC3986. 3698ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} val The string to decode. 3708ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 3718ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenChromeExOAuth.fromRfc3986 = function(val){ 3728ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var tmp = val 3738ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen .replace(/%21/g, "!") 3748ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen .replace(/%2A/g, "*") 3758ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen .replace(/%27/g, "'") 3768ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen .replace(/%28/g, "(") 3778ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen .replace(/%29/g, ")"); 3788ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return decodeURIComponent(tmp); 3798ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}; 3808ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 3818ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 3828ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Adds a key/value parameter to the supplied URL. 3838ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} url An URL which may or may not contain querystring values. 3848ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} key A key 3858ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} value A value 3868ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {String} The URL with URL-encoded versions of the key and value 3878ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * appended, prefixing them with "&" or "?" as needed. 3888ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 3898ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenChromeExOAuth.addURLParam = function(url, key, value) { 3908ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var sep = (url.indexOf('?') >= 0) ? "&" : "?"; 3918ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return url + sep + 3928ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen ChromeExOAuth.toRfc3986(key) + "=" + ChromeExOAuth.toRfc3986(value); 3938ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}; 3948ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 3958ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 3968ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Stores an OAuth token for the configured scope. 3978ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} token The token to store. 3988ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 3998ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenChromeExOAuth.prototype.setToken = function(token) { 4008ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen localStorage[this.key_token + encodeURI(this.oauth_scope)] = token; 4018ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}; 4028ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4038ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 4048ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Retrieves any stored token for the configured scope. 4058ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {String} The stored token. 4068ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 4078ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenChromeExOAuth.prototype.getToken = function() { 4088ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return localStorage[this.key_token + encodeURI(this.oauth_scope)]; 4098ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}; 4108ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4118ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 4128ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Stores an OAuth token secret for the configured scope. 4138ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} secret The secret to store. 4148ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 4158ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenChromeExOAuth.prototype.setTokenSecret = function(secret) { 4168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen localStorage[this.key_token_secret + encodeURI(this.oauth_scope)] = secret; 4178ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}; 4188ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 4208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Retrieves any stored secret for the configured scope. 4218ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @return {String} The stored secret. 4228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 4238ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenChromeExOAuth.prototype.getTokenSecret = function() { 4248ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen return localStorage[this.key_token_secret + encodeURI(this.oauth_scope)]; 4258ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}; 4268ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4278ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 4288ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Starts an OAuth authorization flow for the current page. If a token exists, 4298ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * no redirect is needed and the supplied callback is called immediately. 4308ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * If this method detects that a redirect has finished, it grabs the 4318ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * appropriate OAuth parameters from the URL and attempts to retrieve an 4328ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * access token. If no token exists and no redirect has happened, then 4338ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * an access token is requested and the page is ultimately redirected. 4348ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Function} callback The function to call once the flow has finished. 4358ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * This callback will be passed the following arguments: 4368ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * token {String} The OAuth access token. 4378ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * secret {String} The OAuth access token secret. 4388ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 4398ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenChromeExOAuth.prototype.initOAuthFlow = function(callback) { 4408ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (!this.hasToken()) { 4418ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var params = ChromeExOAuth.getQueryStringParams(); 4428ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (params['chromeexoauthcallback'] == 'true') { 4438ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var oauth_token = params['oauth_token']; 4448ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var oauth_verifier = params['oauth_verifier'] 4458ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen this.getAccessToken(oauth_token, oauth_verifier, callback); 4468ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } else { 4478ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var request_params = { 4488ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 'url_callback_param' : 'chromeexoauthcallback' 4498ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 4508ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen this.getRequestToken(function(url) { 4518ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen window.location.href = url; 4528ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen }, request_params); 4538ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 4548ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } else { 4558ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen callback(this.getToken(), this.getTokenSecret()); 4568ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 4578ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}; 4588ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4598ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 4608ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Requests an OAuth request token. 4618ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Function} callback Function to call once the authorize URL is 4628ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * calculated. This callback will be passed the following arguments: 4638ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * url {String} The URL the user must be redirected to in order to 4648ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * approve the token. 4658ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Object} opt_args Optional arguments. The following parameters 4668ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * are accepted: 4678ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * "url_callback" {String} The URL the OAuth provider will redirect to. 4688ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * "url_callback_param" {String} A parameter to include in the callback 4698ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * URL in order to indicate to this library that a redirect has 4708ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * taken place. 4718ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 4728ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenChromeExOAuth.prototype.getRequestToken = function(callback, opt_args) { 4738ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (typeof callback !== "function") { 4748ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen throw new Error("Specified callback must be a function."); 4758ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 4768ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var url = opt_args && opt_args['url_callback'] || 4778ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen window && window.top && window.top.location && 4788ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen window.top.location.href; 4798ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4808ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var url_param = opt_args && opt_args['url_callback_param'] || 4818ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen "chromeexoauthcallback"; 4828ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var url_callback = ChromeExOAuth.addURLParam(url, url_param, "true"); 4838ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 4848ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var result = OAuthSimple().sign({ 4858ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen path : this.url_request_token, 4868ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen parameters: { 4878ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen "xoauth_displayname" : this.app_name, 4888ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen "scope" : this.oauth_scope, 4898ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen "oauth_callback" : url_callback 4908ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen }, 4918ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen signatures: { 4928ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen consumer_key : this.consumer_key, 4938ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen shared_secret : this.consumer_secret 4948ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 4958ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen }); 4968ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var onToken = ChromeExOAuth.bind(this.onRequestToken, this, callback); 4978ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen ChromeExOAuth.sendRequest("GET", result.signed_url, null, null, onToken); 4988ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}; 4998ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 5008ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 5018ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Called when a request token has been returned. Stores the request token 5028ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * secret for later use and sends the authorization url to the supplied 5038ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * callback (for redirecting the user). 5048ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Function} callback Function to call once the authorize URL is 5058ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * calculated. This callback will be passed the following arguments: 5068ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * url {String} The URL the user must be redirected to in order to 5078ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * approve the token. 5088ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {XMLHttpRequest} xhr The XMLHttpRequest object used to fetch the 5098ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * request token. 5108ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 5118ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenChromeExOAuth.prototype.onRequestToken = function(callback, xhr) { 5128ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (xhr.readyState == 4) { 5138ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (xhr.status == 200) { 5148ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var params = ChromeExOAuth.formDecode(xhr.responseText); 5158ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var token = params['oauth_token']; 5168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen this.setTokenSecret(params['oauth_token_secret']); 5178ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var url = ChromeExOAuth.addURLParam(this.url_auth_token, 5188ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen "oauth_token", token); 5198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen for (var key in this.auth_params) { 5208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (this.auth_params.hasOwnProperty(key)) { 5218ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen url = ChromeExOAuth.addURLParam(url, key, this.auth_params[key]); 5228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 5238ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 5248ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen callback(url); 5258ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } else { 5268ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen throw new Error("Fetching request token failed. Status " + xhr.status); 5278ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 5288ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 5298ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}; 5308ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 5318ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 5328ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Requests an OAuth access token. 5338ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} oauth_token The OAuth request token. 5348ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {String} oauth_verifier The OAuth token verifier. 5358ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Function} callback The function to call once the token is obtained. 5368ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * This callback will be passed the following arguments: 5378ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * token {String} The OAuth access token. 5388ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * secret {String} The OAuth access token secret. 5398ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 5408ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenChromeExOAuth.prototype.getAccessToken = function(oauth_token, oauth_verifier, 5418ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen callback) { 5428ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (typeof callback !== "function") { 5438ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen throw new Error("Specified callback must be a function."); 5448ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 5458ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var bg = chrome.extension.getBackgroundPage(); 5468ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (bg.chromeExOAuthRequestingAccess == false) { 5478ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen bg.chromeExOAuthRequestingAccess = true; 5488ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 5498ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var result = OAuthSimple().sign({ 5508ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen path : this.url_access_token, 5518ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen parameters: { 5528ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen "oauth_token" : oauth_token, 5538ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen "oauth_verifier" : oauth_verifier 5548ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen }, 5558ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen signatures: { 5568ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen consumer_key : this.consumer_key, 5578ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen shared_secret : this.consumer_secret, 5588ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen oauth_secret : this.getTokenSecret(this.oauth_scope) 5598ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 5608ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen }); 5618ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 5628ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var onToken = ChromeExOAuth.bind(this.onAccessToken, this, callback); 5638ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen ChromeExOAuth.sendRequest("GET", result.signed_url, null, null, onToken); 5648ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 5658ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}; 5668ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 5678ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen/** 5688ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * Called when an access token has been returned. Stores the access token and 5698ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * access token secret for later use and sends them to the supplied callback. 5708ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {Function} callback The function to call once the token is obtained. 5718ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * This callback will be passed the following arguments: 5728ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * token {String} The OAuth access token. 5738ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * secret {String} The OAuth access token secret. 5748ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * @param {XMLHttpRequest} xhr The XMLHttpRequest object used to fetch the 5758ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen * access token. 5768ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen */ 5778ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenChromeExOAuth.prototype.onAccessToken = function(callback, xhr) { 5788ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (xhr.readyState == 4) { 5798ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var bg = chrome.extension.getBackgroundPage(); 5808ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen if (xhr.status == 200) { 5818ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var params = ChromeExOAuth.formDecode(xhr.responseText); 5828ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var token = params["oauth_token"]; 5838ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen var secret = params["oauth_token_secret"]; 5848ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen this.setToken(token); 5858ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen this.setTokenSecret(secret); 5868ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen bg.chromeExOAuthRequestingAccess = false; 5878ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen callback(token, secret); 5888ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } else { 5898ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen bg.chromeExOAuthRequestingAccess = false; 5908ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen throw new Error("Fetching access token failed with status " + xhr.status); 5918ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 5928ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen } 5938ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}; 5948ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen 595