| Index: chrome/common/extensions/docs/examples/extensions/gdocs/chrome_ex_oauth.js
|
| ===================================================================
|
| --- chrome/common/extensions/docs/examples/extensions/gdocs/chrome_ex_oauth.js (revision 56269)
|
| +++ chrome/common/extensions/docs/examples/extensions/gdocs/chrome_ex_oauth.js (working copy)
|
| @@ -32,6 +32,14 @@
|
| this.key_token_secret = "oauth_token_secret";
|
| this.callback_page = opt_args && opt_args['callback_page'] ||
|
| "chrome_ex_oauth.html";
|
| + this.auth_params = {};
|
| + if (opt_args && opt_args['auth_params']) {
|
| + for (key in opt_args['auth_params']) {
|
| + if (opt_args['auth_params'].hasOwnProperty(key)) {
|
| + this.auth_params[key] = opt_args['auth_params'][key];
|
| + }
|
| + }
|
| + }
|
| };
|
|
|
| /*******************************************************************************
|
| @@ -51,20 +59,26 @@
|
| * "consumer_secret" {String} OAuth consumer secret.
|
| * "scope" {String} OAuth access scope.
|
| * "app_name" {String} Application name.
|
| + * "auth_params" {Object} Additional parameters to pass to the
|
| + * Authorization token URL. For an example, 'hd', 'hl', 'btmpl':
|
| + * http://code.google.com/apis/accounts/docs/OAuth_ref.html#GetAuth
|
| * @return {ChromeExOAuth} An initialized ChromeExOAuth object.
|
| */
|
| ChromeExOAuth.initBackgroundPage = function(oauth_config) {
|
| window.chromeExOAuthConfig = oauth_config;
|
| window.chromeExOAuth = ChromeExOAuth.fromConfig(oauth_config);
|
| window.chromeExOAuthRedirectStarted = false;
|
| + window.chromeExOAuthRequestingAccess = false;
|
|
|
| var url_match = chrome.extension.getURL(window.chromeExOAuth.callback_page);
|
| + var tabs = {};
|
| chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
|
| if (changeInfo.url &&
|
| changeInfo.url.substr(0, url_match.length) === url_match &&
|
| - !window.chromeExOAuthRedirectStarted) {
|
| - window.chromeExOAuthRedirectStarted = true;
|
| - chrome.tabs.create({ 'url' : changeInfo.url }, function() {
|
| + changeInfo.url != tabs[tabId] &&
|
| + window.chromeExOAuthRequestingAccess == false) {
|
| + chrome.tabs.create({ 'url' : changeInfo.url }, function(tab) {
|
| + tabs[tab.id] = tab.url;
|
| chrome.tabs.remove(tabId);
|
| });
|
| }
|
| @@ -131,8 +145,8 @@
|
| ChromeExOAuth.prototype.sendSignedRequest = function(url, callback,
|
| opt_params) {
|
| var method = opt_params && opt_params['method'] || 'GET';
|
| + var body = opt_params && opt_params['body'] || null;
|
| var params = opt_params && opt_params['parameters'] || {};
|
| - var body = opt_params && opt_params['body'] || null;
|
| var headers = opt_params && opt_params['headers'] || {};
|
|
|
| var signedUrl = this.signURL(url, method, params);
|
| @@ -148,7 +162,7 @@
|
| * Adds the required OAuth parameters to the given url and returns the
|
| * result. Useful if you need a signed url but don't want to make an XHR
|
| * request.
|
| - * @param {String} method The HTTP method to use.
|
| + * @param {String} method The http method to use.
|
| * @param {String} url The base url of the resource you are querying.
|
| * @param {Object} opt_params Query parameters to include in the request.
|
| * @return {String} The base url plus any query params plus any OAuth params.
|
| @@ -163,7 +177,7 @@
|
| var params = opt_params || {};
|
|
|
| var result = OAuthSimple().sign({
|
| - action: method,
|
| + action : method,
|
| path : url,
|
| parameters : params,
|
| signatures: {
|
| @@ -222,6 +236,9 @@
|
| * "consumer_secret" {String} OAuth consumer secret.
|
| * "scope" {String} OAuth access scope.
|
| * "app_name" {String} Application name.
|
| + * "auth_params" {Object} Additional parameters to pass to the
|
| + * Authorization token URL. For an example, 'hd', 'hl', 'btmpl':
|
| + * http://code.google.com/apis/accounts/docs/OAuth_ref.html#GetAuth
|
| * @return {ChromeExOAuth} An initialized ChromeExOAuth object.
|
| */
|
| ChromeExOAuth.fromConfig = function(oauth_config) {
|
| @@ -233,7 +250,8 @@
|
| oauth_config['consumer_secret'],
|
| oauth_config['scope'],
|
| {
|
| - 'app_name' : oauth_config['app_name']
|
| + 'app_name' : oauth_config['app_name'],
|
| + 'auth_params' : oauth_config['auth_params']
|
| }
|
| );
|
| };
|
| @@ -244,13 +262,16 @@
|
| * chrome_ex_oauth.html.
|
| */
|
| ChromeExOAuth.initCallbackPage = function() {
|
| - var oauth_config = chrome.extension.getBackgroundPage().chromeExOAuthConfig;
|
| + var background_page = chrome.extension.getBackgroundPage();
|
| + var oauth_config = background_page.chromeExOAuthConfig;
|
| var oauth = ChromeExOAuth.fromConfig(oauth_config);
|
| + background_page.chromeExOAuthRedirectStarted = true;
|
| oauth.initOAuthFlow(function (token, secret) {
|
| - var background_page = chrome.extension.getBackgroundPage();
|
| background_page.chromeExOAuthOnAuthorize(token, secret);
|
| background_page.chromeExOAuthRedirectStarted = false;
|
| - window.close();
|
| + chrome.tabs.getSelected(null, function (tab) {
|
| + chrome.tabs.remove(tab.id);
|
| + });
|
| });
|
| };
|
|
|
| @@ -292,7 +313,9 @@
|
| for (var i = 0, param; param = params[i]; i++) {
|
| var keyval = param.split("=");
|
| if (keyval.length == 2) {
|
| - decoded[decodeURIComponent(keyval[0])] = decodeURIComponent(keyval[1]);
|
| + var key = ChromeExOAuth.fromRfc3986(keyval[0]);
|
| + var val = ChromeExOAuth.fromRfc3986(keyval[1]);
|
| + decoded[key] = val;
|
| }
|
| }
|
| return decoded;
|
| @@ -329,6 +352,33 @@
|
| };
|
|
|
| /**
|
| + * Encodes a value according to the RFC3986 specification.
|
| + * @param {String} val The string to encode.
|
| + */
|
| +ChromeExOAuth.toRfc3986 = function(val){
|
| + return encodeURIComponent(val)
|
| + .replace(/\!/g, "%21")
|
| + .replace(/\*/g, "%2A")
|
| + .replace(/'/g, "%27")
|
| + .replace(/\(/g, "%28")
|
| + .replace(/\)/g, "%29");
|
| +};
|
| +
|
| +/**
|
| + * Decodes a string that has been encoded according to RFC3986.
|
| + * @param {String} val The string to decode.
|
| + */
|
| +ChromeExOAuth.fromRfc3986 = function(val){
|
| + var tmp = val
|
| + .replace(/%21/g, "!")
|
| + .replace(/%2A/g, "*")
|
| + .replace(/%27/g, "'")
|
| + .replace(/%28/g, "(")
|
| + .replace(/%29/g, ")");
|
| + return decodeURIComponent(tmp);
|
| +};
|
| +
|
| +/**
|
| * Adds a key/value parameter to the supplied URL.
|
| * @param {String} url An URL which may or may not contain querystring values.
|
| * @param {String} key A key
|
| @@ -338,7 +388,8 @@
|
| */
|
| ChromeExOAuth.addURLParam = function(url, key, value) {
|
| var sep = (url.indexOf('?') >= 0) ? "&" : "?";
|
| - return url + sep + encodeURIComponent(key) + "=" + encodeURIComponent(value);
|
| + return url + sep +
|
| + ChromeExOAuth.toRfc3986(key) + "=" + ChromeExOAuth.toRfc3986(value);
|
| };
|
|
|
| /**
|
| @@ -465,6 +516,11 @@
|
| this.setTokenSecret(params['oauth_token_secret']);
|
| var url = ChromeExOAuth.addURLParam(this.url_auth_token,
|
| "oauth_token", token);
|
| + for (var key in this.auth_params) {
|
| + if (this.auth_params.hasOwnProperty(key)) {
|
| + url = ChromeExOAuth.addURLParam(url, key, this.auth_params[key]);
|
| + }
|
| + }
|
| callback(url);
|
| } else {
|
| throw new Error("Fetching request token failed. Status " + xhr.status);
|
| @@ -486,21 +542,26 @@
|
| if (typeof callback !== "function") {
|
| throw new Error("Specified callback must be a function.");
|
| }
|
| - var result = OAuthSimple().sign({
|
| - path : this.url_access_token,
|
| - parameters: {
|
| - "oauth_token" : oauth_token,
|
| - "oauth_verifier" : oauth_verifier
|
| - },
|
| - signatures: {
|
| - consumer_key : this.consumer_key,
|
| - shared_secret : this.consumer_secret,
|
| - oauth_secret : this.getTokenSecret(this.oauth_scope)
|
| - }
|
| - });
|
| + var bg = chrome.extension.getBackgroundPage();
|
| + if (bg.chromeExOAuthRequestingAccess == false) {
|
| + bg.chromeExOAuthRequestingAccess = true;
|
|
|
| - var onToken = ChromeExOAuth.bind(this.onAccessToken, this, callback)
|
| - ChromeExOAuth.sendRequest("GET", result.signed_url, null, null, onToken);
|
| + var result = OAuthSimple().sign({
|
| + path : this.url_access_token,
|
| + parameters: {
|
| + "oauth_token" : oauth_token,
|
| + "oauth_verifier" : oauth_verifier
|
| + },
|
| + signatures: {
|
| + consumer_key : this.consumer_key,
|
| + shared_secret : this.consumer_secret,
|
| + oauth_secret : this.getTokenSecret(this.oauth_scope)
|
| + }
|
| + });
|
| +
|
| + var onToken = ChromeExOAuth.bind(this.onAccessToken, this, callback);
|
| + ChromeExOAuth.sendRequest("GET", result.signed_url, null, null, onToken);
|
| + }
|
| };
|
|
|
| /**
|
| @@ -515,14 +576,17 @@
|
| */
|
| ChromeExOAuth.prototype.onAccessToken = function(callback, xhr) {
|
| if (xhr.readyState == 4) {
|
| + var bg = chrome.extension.getBackgroundPage();
|
| if (xhr.status == 200) {
|
| var params = ChromeExOAuth.formDecode(xhr.responseText);
|
| var token = params["oauth_token"];
|
| var secret = params["oauth_token_secret"];
|
| this.setToken(token);
|
| this.setTokenSecret(secret);
|
| + bg.chromeExOAuthRequestingAccess = false;
|
| callback(token, secret);
|
| } else {
|
| + bg.chromeExOAuthRequestingAccess = false;
|
| throw new Error("Fetching access token failed with status " + xhr.status);
|
| }
|
| }
|
|
|