[Pkg-mozext-commits] [gcontactsync] 15/31: Issue #2: Implement OAuth, additional cleanup
David Prévot
taffit at moszumanska.debian.org
Sun Feb 22 21:34:34 UTC 2015
This is an automated email from the git hooks/post-receive script.
taffit pushed a commit to branch master
in repository gcontactsync.
commit 28f97220810b23b042a817d6f0cb1e09a8010265
Author: Josh Geenen <joshgeenen at gmail.com>
Date: Mon Dec 22 12:43:38 2014 -0600
Issue #2: Implement OAuth, additional cleanup
---
src/chrome.manifest | 1 +
src/content/AccountSetupWizard.js | 64 +++-----------------
src/content/AccountSetupWizard.xul | 2 +
src/content/Accounts.js | 2 +
src/content/NewRefreshToken.xul | 49 +++++++++++++++
src/content/OAuth2.js | 113 +++++++++++++++++++++++++++++++++++
src/content/Overlay.xul | 2 +
src/content/Sync.js | 70 ++++------------------
src/content/gdata.js | 40 ++++++++-----
src/locale/en-US/NewRefreshToken.dtd | 1 +
10 files changed, 215 insertions(+), 129 deletions(-)
diff --git a/src/chrome.manifest b/src/chrome.manifest
index 27859b3..255613a 100644
--- a/src/chrome.manifest
+++ b/src/chrome.manifest
@@ -12,5 +12,6 @@ overlay chrome://messenger/content/addressbook/abNewCardDialog.xul chrome://g
style chrome://gcontactsync/content/ABOverlay.xul chrome://gcontactsync/skin/overlay.css
style chrome://gcontactsync/content/AccountSetupWizard.xul chrome://gcontactsync/skin/overlay.css
style chrome://gcontactsync/content/MessengerOverlay.xul chrome://gcontactsync/skin/overlay.css
+style chrome://gcontactsync/content/NewRefreshToken.xul chrome://gcontactsync/skin/overlay.css
style chrome://global/content/customizeToolbar.xul chrome://gcontactsync/skin/overlay.css
style chrome://messenger/content/addressbook/addressbook.xul chrome://gcontactsync/skin/overlay.css
diff --git a/src/content/AccountSetupWizard.js b/src/content/AccountSetupWizard.js
index 196149a..d78d9cc 100644
--- a/src/content/AccountSetupWizard.js
+++ b/src/content/AccountSetupWizard.js
@@ -15,7 +15,7 @@
*
* The Initial Developer of the Original Code is
* Josh Geenen <gcontactsync at pirules.org>.
- * Portions created by the Initial Developer are Copyright (C) 2013
+ * Portions created by the Initial Developer are Copyright (C) 2013-2014
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
@@ -34,8 +34,6 @@
*
* ***** END LICENSE BLOCK ***** */
-Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
-
if (!com) {var com = {};} // A generic wrapper variable
// A wrapper for all GCS functions and variables
if (!com.gContactSync) {com.gContactSync = {};}
@@ -128,71 +126,23 @@ com.gContactSync.AccountSetupWizard = {
loadOAuthPage: function AccountSetupWizard_loadOAuthPage() {
var wizard = document.getElementById("newAccountWizard");
-
- var url = com.gContactSync.gdata.OAUTH_URL +
- "?response_type=" + com.gContactSync.gdata.RESPONSE_TYPE +
- "&client_id=" + com.gContactSync.gdata.CLIENT_ID +
- "&redirect_uri=" + com.gContactSync.gdata.REDIRECT_URI +
- "&scope=" + com.gContactSync.gdata.SCOPE +
- "&login_hint=" + this.mEmailAddress;
-
var browser = document.getElementById("browser");
- browser.setAttribute("src", url);
- browser.addProgressListener(com.gContactSync.AccountSetupWizard.listener);
+ browser.setAttribute("src", com.gContactSync.gdata.getOAuthURL(this.mEmailAddress));
+ com.gContactSync.OAuth2.init(browser, com.gContactSync.gdata.REDIRECT_URI, this.onSuccessfulAuthentication);
wizard.canAdvance = false;
},
-
/**
- * Notify that an authorization code was received. Sends a token request using the code.
+ * Callback for OAuth2. Adds the refresh token to the login manager and advances the wizard.
*
- * @param aCode {string} The authorization code.
+ * @param aResponse {object} The parsed JSON object.
*/
- onCodeReceived: function AccountSetupWizard_onCodeReceived(aCode) {
- com.gContactSync.LOGGER.LOG("Received an authorization code");
- var browser = document.getElementById("browser");
- browser.removeProgressListener(com.gContactSync.AccountSetupWizard.listener);
- browser.setAttribute("src", "");
- var request = new com.gContactSync.GHttpRequest("TOKEN_REQUEST", aCode);
- request.mOnSuccess = com.gContactSync.AccountSetupWizard.onTokenReceived;
- request.mOnError = function onTokenError(aHttpReq) {
- com.gContactSync.alertError(aHttpReq.responseText);
- };
- request.send();
- },
- /**
- * Notify that an access token was received. Saves the refresh token and advances the wizard.
- *
- * @param aHttpReq {XmlHttpRequest} The HTTP request.
- */
- onTokenReceived: function AccountSetupWizard_onTokenReceived(aHttpReq) {
- com.gContactSync.LOGGER.LOG("Received an access token");
- var response = JSON.parse(aHttpReq.responseText);
- com.gContactSync.LoginManager.addAuthToken(com.gContactSync.AccountSetupWizard.mEmailAddress, response.refresh_token);
+ onSuccessfulAuthentication: function AccountSetupWizard_onSuccessfulAuthentication(aResponse) {
+ com.gContactSync.LoginManager.addAuthToken(com.gContactSync.AccountSetupWizard.mEmailAddress, aResponse.refresh_token);
var wizard = document.getElementById("newAccountWizard");
wizard.canAdvance = true;
wizard.advance();
},
/**
- * A nsIWebProgressListener that listens for a location change to the redirect URI.
- * Notifies the AccountSetupWizard.
- */
- listener: {
-
- QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsIWebProgressListener,
- Components.interfaces.nsISupportsWeakReference]),
-
- onLocationChange: function (aWebProgress, aRequest, aLocation) {
- if (aLocation.spec.indexOf(com.gContactSync.gdata.REDIRECT_URI) === 0) {
- var code = com.gContactSync.parseURLParameters(aLocation.spec)["code"];
- com.gContactSync.AccountSetupWizard.onCodeReceived(code);
- }
- },
- onStateChange: function () {},
- onProgressChange: function () {},
- onStatusChange: function () {},
- onSecurityChange: function () {},
- },
- /**
* Gets an auth token for the selected username if necessary (and possible), then returns whether the page may
* advance now. If this function must get an auth token it will advance the page upon successful completion
* of the HTTP request.
diff --git a/src/content/AccountSetupWizard.xul b/src/content/AccountSetupWizard.xul
index f6a9dd9..1658d88 100644
--- a/src/content/AccountSetupWizard.xul
+++ b/src/content/AccountSetupWizard.xul
@@ -89,6 +89,8 @@
<script type="application/x-javascript"
src="chrome://gcontactsync/content/Accounts.js"/>
<script type="application/x-javascript"
+ src="chrome://gcontactsync/content/OAuth2.js"/>
+ <script type="application/x-javascript"
src="chrome://gcontactsync/content/AccountSetupWizard.js"/>
<stringbundleset id="stringbundleset">
<stringbundle id="gContactSyncStringBundle"
diff --git a/src/content/Accounts.js b/src/content/Accounts.js
index 14fd12d..7657413 100644
--- a/src/content/Accounts.js
+++ b/src/content/Accounts.js
@@ -90,6 +90,7 @@ com.gContactSync.Accounts = {
* @returns {boolean} True if an authentication HTTP request was sent.
*/
newUsername: function Accounts_newUsername() {
+ /*
var prompt = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
.getService(Components.interfaces.nsIPromptService)
.promptUsernameAndPassword,
@@ -140,6 +141,7 @@ com.gContactSync.Accounts = {
com.gContactSync.LOGGER.LOG_ERROR(com.gContactSync.StringBundle.getStr('offlineErr'));
};
httpReq.send();
+ */
return true;
},
/**
diff --git a/src/content/NewRefreshToken.xul b/src/content/NewRefreshToken.xul
new file mode 100644
index 0000000..cb281eb
--- /dev/null
+++ b/src/content/NewRefreshToken.xul
@@ -0,0 +1,49 @@
+<?xml version="1.0"?>
+<!-- ***** BEGIN LICENSE BLOCK *****
+ - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ -
+ - The contents of this file are subject to the Mozilla Public License Version
+ - 1.1 (the "License"); you may not use this file except in compliance with
+ - the License. You may obtain a copy of the License at
+ - http://www.mozilla.org/MPL/
+ -
+ - Software distributed under the License is distributed on an "AS IS" basis,
+ - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ - for the specific language governing rights and limitations under the
+ - License.
+ -
+ - The Original Code is gContactSync.
+ -
+ - The Initial Developer of the Original Code is
+ - Josh Geenen <gcontactsync at pirules.org>.
+ - Portions created by the Initial Developer are Copyright (C) 2013-2014
+ - the Initial Developer. All Rights Reserved.
+ -
+ - Contributor(s):
+ -
+ - Alternatively, the contents of this file may be used under the terms of
+ - either the GNU General Public License Version 2 or later (the "GPL"), or
+ - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ - in which case the provisions of the GPL or the LGPL are applicable instead
+ - of those above. If you wish to allow use of your version of this file only
+ - under the terms of either the GPL or the LGPL, and not to allow others to
+ - use your version of this file under the terms of the MPL, indicate your
+ - decision by deleting the provisions above and replace them with the notice
+ - and other provisions required by the LGPL or the GPL. If you do not delete
+ - the provisions above, a recipient may use your version of this file under
+ - the terms of any one of the MPL, the GPL or the LGPL.
+ -
+ - ***** END LICENSE BLOCK ***** -->
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<?xml-stylesheet href="chrome://gcontactsync/skin/Accounts.css" type="text/css"?>
+
+<!DOCTYPE window SYSTEM "chrome://gContactSync/locale/NewRefreshToken.dtd">
+
+<window id="newAccountWizard" title="&NewRefreshToken.title;"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ height="740px"
+ width="700px">
+ <hbox flex="1">
+ <browser id="browser" src="" flex="1"/>
+ </hbox>
+</window>
diff --git a/src/content/OAuth2.js b/src/content/OAuth2.js
new file mode 100644
index 0000000..43c04a4
--- /dev/null
+++ b/src/content/OAuth2.js
@@ -0,0 +1,113 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is gContactSync.
+ *
+ * The Initial Developer of the Original Code is
+ * Josh Geenen <gcontactsync at pirules.org>.
+ * Portions created by the Initial Developer are Copyright (C) 2014
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+if (!com) {var com = {};} // A generic wrapper variable
+// A wrapper for all GCS functions and variables
+if (!com.gContactSync) {com.gContactSync = {};}
+
+/**
+ * A simple class to assist with OAuth2 authentication.
+ * Calls the given callback when the browser passed to init has its source changed to the redirect URI.
+ * Assumes the browser element's source is already pointed to the initial OAuth page.
+ * @class
+ */
+com.gContactSync.OAuth2 = {
+ /**
+ * Initializes this class.
+ * @param aBrowserElem {browser} Browser element.
+ * @param aRedirectURI {string} The redirect URI to watch for.
+ * @param aCallback {function} The function to call when the browser's source changes to the redirect URI.
+ */
+ init: function OAuth2_init(aBrowserElem, aRedirectURI, aCallback) {
+ this.mBrowserElem = aBrowserElem;
+ this.mRedirectURI = aRedirectURI;
+ this.mCallback = aCallback;
+ this.mBrowserElem.addProgressListener(this.mListener);
+ },
+ /**
+ * Notify that an authorization code was received. Sends a token request using the code.
+ *
+ * @param aCode {string} The authorization code.
+ */
+ onCodeReceived: function OAuth2_onCodeReceived(aCode) {
+ com.gContactSync.LOGGER.LOG("Received an authorization code");
+ this.mBrowserElem.removeProgressListener(com.gContactSync.OAuth2.mListener);
+ this.mBrowserElem.setAttribute("src", "");
+ var request = new com.gContactSync.GHttpRequest("TOKEN_REQUEST", aCode);
+ request.mOnSuccess = com.gContactSync.OAuth2.onTokenReceived;
+ request.mOnError = function onTokenError(aHttpReq) {
+ com.gContactSync.alertError(aHttpReq.responseText);
+ };
+ request.send();
+ },
+ /**
+ * Notify that an access token was received. Saves the refresh token and advances the wizard.
+ *
+ * @param aHttpReq {XmlHttpRequest} The HTTP request.
+ */
+ onTokenReceived: function OAuth2_onTokenReceived(aHttpReq) {
+ com.gContactSync.LOGGER.LOG("Received an access token");
+ com.gContactSync.OAuth2.mCallback(JSON.parse(aHttpReq.responseText));
+ },
+ /**
+ * A nsIWebProgressListener that listens for a location change to the redirect URI.
+ * Notifies OAuth2.
+ */
+ mListener: {
+ /** Implements nsIWebProgressListener, nsISupportsWeakRefrence */
+ QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsIWebProgressListener,
+ Components.interfaces.nsISupportsWeakReference]),
+ /**
+ * Watches for a location change to the redirect URI.
+ *
+ * @param aWebProgress The progress.
+ * @param aRequest The request.
+ * @param aLocation The location.
+ */
+ onLocationChange: function (aWebProgress, aRequest, aLocation) {
+ if (aLocation.spec.indexOf(com.gContactSync.OAuth2.mRedirectURI) === 0) {
+ var code = com.gContactSync.parseURLParameters(aLocation.spec).code;
+ com.gContactSync.OAuth2.onCodeReceived(code);
+ }
+ },
+ onStateChange: function () {},
+ onProgressChange: function () {},
+ onStatusChange: function () {},
+ onSecurityChange: function () {},
+ }
+};
diff --git a/src/content/Overlay.xul b/src/content/Overlay.xul
index 8d34392..c6cccdb 100644
--- a/src/content/Overlay.xul
+++ b/src/content/Overlay.xul
@@ -99,6 +99,8 @@
src="chrome://gcontactsync/content/LoginManager.js"/>
<script type="application/x-javascript"
src="chrome://gcontactsync/content/Import.js"/>
+ <script type="application/x-javascript"
+ src="chrome://gcontactsync/content/OAuth2.js"/>
<stringbundleset id="stringbundleset">
<stringbundle id="gContactSyncStringBundle"
diff --git a/src/content/Sync.js b/src/content/Sync.js
index 16e2a4e..109363b 100644
--- a/src/content/Sync.js
+++ b/src/content/Sync.js
@@ -110,10 +110,6 @@ com.gContactSync.Sync = {
* @param aManualSync {boolean} Set this to true if the sync was run manually.
*/
begin: function Sync_begin(aManualSync, aAddressBooks) {
- if (!com.gContactSync.gdata.isAuthValid()) {
- com.gContactSync.alert(com.gContactSync.StringBundle.getStr("pleaseAuth"));
- return;
- }
// quit if still syncing.
if (com.gContactSync.Preferences.mSyncPrefs.synchronizing.value) {
return;
@@ -147,6 +143,12 @@ com.gContactSync.Sync = {
}
com.gContactSync.Overlay.updateVersion();
+
+ if (com.gContactSync.Sync.mAddressBooks.length === 0) {
+ com.gContactSync.alert(com.gContactSync.StringBundle.getStr("pleaseAuth"));
+ return;
+ }
+
com.gContactSync.Sync.syncNextUser();
},
/**
@@ -156,7 +158,7 @@ com.gContactSync.Sync = {
syncNextUser: function Sync_syncNextUser() {
// If the sync was successful, set the previous address book's last sync date (if it exists)
- if (com.gContactSync.Sync.mPrevErrorCount == com.gContactSync.LOGGER.mErrorCount &&
+ if (com.gContactSync.Sync.mPrevErrorCount === com.gContactSync.LOGGER.mErrorCount &&
com.gContactSync.Sync.mCurrentAb &&
com.gContactSync.Sync.mCurrentAb.setLastSyncDate) {
com.gContactSync.Sync.mCurrentAb.setLastSyncDate((new Date()).getTime());
@@ -208,68 +210,20 @@ com.gContactSync.Sync = {
// If an authentication token cannot be found for this username then
// offer to let the user login with that account
if (!refreshToken) {
- // TODO FIXME
com.gContactSync.LOGGER.LOG_WARNING("Unable to find the auth token for: " +
com.gContactSync.Sync.mCurrentUsername);
- /*
if (com.gContactSync.confirm(com.gContactSync.StringBundle.getStr("noTokenFound") +
": " + com.gContactSync.Sync.mCurrentUsername +
"\n" + com.gContactSync.StringBundle.getStr("ab") +
": " + com.gContactSync.Sync.mCurrentAb.getName())) {
- // Now let the user login
- var prompt = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
- .getService(Components.interfaces.nsIPromptService)
- .promptUsernameAndPassword,
- username = {value: com.gContactSync.Sync.mCurrentUsername},
- password = {},
- // opens a username/password prompt
- ok = prompt(window, com.gContactSync.StringBundle.getStr("loginTitle"),
- com.gContactSync.StringBundle.getStr("loginText"), username, password, null,
- {value: false});
- if (!ok) {
- com.gContactSync.Sync.syncNextUser();
- return;
- }
- // Decrement the index so Sync.syncNextUser runs on this AB again
com.gContactSync.Sync.mIndex--;
- // This is a primitive way of validating an e-mail address, but Google takes
- // care of the rest. It seems to allow getting an auth token w/ only the
- // username, but returns an error when trying to do anything w/ that token
- // so this makes sure it is a full e-mail address.
- if (username.value.indexOf("@") < 1) {
- com.gContactSync.alertError(com.gContactSync.StringBundle.getStr("invalidEmail"));
- com.gContactSync.Sync.syncNextUser();
- return;
- }
- // fix the username before authenticating
- username.value = com.gContactSync.fixUsername(username.value);
- var body = com.gContactSync.gdata.makeAuthBody(username.value, password.value);
- var httpReq = new com.gContactSync.GHttpRequest("authenticate", null, null, body);
- // if it succeeds and Google returns the auth token, store it and then start
- // a new sync
- httpReq.mOnSuccess = function reauth_onSuccess(httpReq) {
- com.gContactSync.LoginManager.addAuthToken(username.value,
- 'GoogleLogin' +
- httpReq.responseText.split("\n")[2]);
- com.gContactSync.Sync.syncNextUser();
- };
- // if it fails, alert the user and prompt them to try again
- httpReq.mOnError = function reauth_onError(httpReq) {
- com.gContactSync.alertError(com.gContactSync.StringBundle.getStr('authErr'));
- com.gContactSync.LOGGER.LOG_ERROR('Authentication Error - ' +
- httpReq.status,
- httpReq.responseText);
+ com.gContactSync.gdata.requestNewRefreshToken(com.gContactSync.Sync.mCurrentUsername, function newRefreshToken(aResponse) {
+ com.gContactSync.LoginManager.addAuthToken(com.gContactSync.Sync.mCurrentUsername, aResponse.refresh_token);
com.gContactSync.Sync.syncNextUser();
- };
- // if the user is offline, alert them and quit
- httpReq.mOnOffline = com.gContactSync.Sync.mOfflineFunction;
- httpReq.mOn503 = com.gContactSync.Sync.m503Function;
- httpReq.send();
- }
- else
+ });
+ } else {
com.gContactSync.Sync.syncNextUser();
- */
- com.gContactSync.Sync.syncNextUser();
+ }
return;
}
var lastBackup = parseInt(obj.ab.mPrefs.lastBackup, 10),
diff --git a/src/content/gdata.js b/src/content/gdata.js
index a515d3a..77179e4 100644
--- a/src/content/gdata.js
+++ b/src/content/gdata.js
@@ -71,20 +71,18 @@ com.gContactSync.gdata = {
AUTH_SUB_REVOKE_URL: "https://www.google.com/accounts/AuthSubRevokeToken",
AUTH_SUB_REVOKE_TYPE: "GET",
/**
- * Sets up the body for an authentication request given the e-mail address
- * and password.
- * @param aEmail {string} The user's e-mail address
- * @param aPassword {string} The user's password
- * @returns {string} The body for an authentication request.
+ * Returns an OAuth URL for the given e-mail addres.
+ *
+ * @param aEmail {string} The e-mail address.
+ * @return {string} The OAuth URL.
*/
- makeAuthBody: function gdata_makeAuthBody(aEmail, aPassword) {
- // NOTE: leave accountType as HOSTED_OR_GOOGLE or Google Apps for your
- // domain accounts won't work
- // fix the username (remove whitespace)
- aEmail = com.gContactSync.fixUsername(aEmail);
- return "accountType=HOSTED_OR_GOOGLE&Email=" + encodeURIComponent(aEmail) +
- "&Passwd=" + encodeURIComponent(aPassword) +
- "&service=cp&source=Josh-gContactSync-0-3";
+ getOAuthURL: function gdata_getOAuthURL(aEmail) {
+ return com.gContactSync.gdata.OAUTH_URL +
+ "?response_type=" + com.gContactSync.gdata.RESPONSE_TYPE +
+ "&client_id=" + com.gContactSync.gdata.CLIENT_ID +
+ "&redirect_uri=" + com.gContactSync.gdata.REDIRECT_URI +
+ "&scope=" + com.gContactSync.gdata.SCOPE +
+ "&login_hint=" + aEmail;
},
/**
* Returns the email address of the given ID.
@@ -457,5 +455,19 @@ com.gContactSync.gdata = {
com.gContactSync.LOGGER.LOG("Beginning a backup of the Google Account:\n" +
aAccount + "\nto:\n" + destFile.path);
return com.gContactSync.FileIO.writeToFile(destFile, aFeed);
- }
+ },
+ requestNewRefreshToken: function gdata_requestNewRefreshToken(aEmail, aCallback) {
+ var wizard = window.open("chrome://gcontactsync/content/NewRefreshToken.xul",
+ "NewRefreshTokenWindow",
+ "chrome,resizable=yes,scrollbars=no,status=no");
+ // when the setup window loads, set its onunload property to begin a sync
+ wizard.onload = function onloadListener() {
+ var browser = wizard.document.getElementById("browser");
+ com.gContactSync.OAuth2.init(browser, com.gContactSync.gdata.REDIRECT_URI, function callback(aResponse) {
+ wizard.close();
+ aCallback(aResponse);
+ });
+ browser.setAttribute("src", com.gContactSync.gdata.getOAuthURL(aEmail));
+ };
+ },
};
diff --git a/src/locale/en-US/NewRefreshToken.dtd b/src/locale/en-US/NewRefreshToken.dtd
new file mode 100644
index 0000000..5b099f2
--- /dev/null
+++ b/src/locale/en-US/NewRefreshToken.dtd
@@ -0,0 +1 @@
+<!ENTITY NewRefreshToken.title "Refresh Token">
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-mozext/gcontactsync.git
More information about the Pkg-mozext-commits
mailing list