Bug 1155491 - Support autoconfig and manual config of gmail IMAP OAuth2 authentication, r=jcranmer
This commit is contained in:
Родитель
05f8ea8aa3
Коммит
6423d3829a
|
@ -50,6 +50,8 @@ AccountConfig.prototype =
|
|||
*/
|
||||
incomingAlternatives : null,
|
||||
outgoingAlternatives : null,
|
||||
// OAuth2 configuration, if needed.
|
||||
oauthSettings : null,
|
||||
// just an internal string to refer to this. Do not show to user.
|
||||
id : null,
|
||||
// who created the config.
|
||||
|
|
|
@ -28,6 +28,11 @@ function createAccountInBackend(config)
|
|||
if (config.rememberPassword && config.incoming.password.length)
|
||||
rememberPassword(inServer, config.incoming.password);
|
||||
|
||||
if (inServer.authMethod == Ci.nsMsgAuthMethod.OAuth2) {
|
||||
inServer.setCharValue("oauth2.scope", config.oauthSettings.scope);
|
||||
inServer.setCharValue("oauth2.issuer", config.oauthSettings.issuer);
|
||||
}
|
||||
|
||||
// SSL
|
||||
if (config.incoming.socketType == 1) // plain
|
||||
inServer.socketType = Ci.nsMsgSocketType.plain;
|
||||
|
@ -102,6 +107,14 @@ function createAccountInBackend(config)
|
|||
rememberPassword(outServer, config.incoming.password);
|
||||
}
|
||||
|
||||
if (outServer.authMethod == Ci.nsMsgAuthMethod.OAuth2) {
|
||||
let pref = "mail.smtpserver." + outServer.key + ".";
|
||||
Services.prefs.setCharPref(pref + "oauth2.scope",
|
||||
config.oauthSettings.scope);
|
||||
Services.prefs.setCharPref(pref + "oauth2.issuer",
|
||||
config.oauthSettings.issuer);
|
||||
}
|
||||
|
||||
if (config.outgoing.socketType == 1) // no SSL
|
||||
outServer.socketType = Ci.nsMsgSocketType.plain;
|
||||
else if (config.outgoing.socketType == 2) // SSL / TLS
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
Components.utils.import("resource:///modules/mailServices.js");
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
Components.utils.import("resource:///modules/hostnameUtils.jsm");
|
||||
Components.utils.import("resource://gre/modules/OAuth2Providers.jsm");
|
||||
|
||||
/**
|
||||
* This is the dialog opened by menu File | New account | Mail... .
|
||||
|
@ -34,8 +35,10 @@ Components.utils.import("resource:///modules/hostnameUtils.jsm");
|
|||
// from http://xyfer.blogspot.com/2005/01/javascript-regexp-email-validator.html
|
||||
var emailRE = /^[-_a-z0-9\'+*$^&%=~!?{}]+(?:\.[-_a-z0-9\'+*$^&%=~!?{}]+)*@(?:[-a-z0-9.]+\.[a-z]{2,6}|\d{1,3}(?:\.\d{1,3}){3})(?::\d+)?$/i;
|
||||
|
||||
Cu.import("resource:///modules/gloda/log4moz.js");
|
||||
let gEmailWizardLogger = Log4Moz.getConfiguredLogger("mail.wizard");
|
||||
if (typeof gEmailWizardLogger == "undefined") {
|
||||
Cu.import("resource:///modules/gloda/log4moz.js");
|
||||
var gEmailWizardLogger = Log4Moz.getConfiguredLogger("mail.wizard");
|
||||
}
|
||||
|
||||
var gStringsBundle;
|
||||
var gMessengerBundle;
|
||||
|
@ -181,6 +184,7 @@ EmailConfigWizard.prototype =
|
|||
"authPasswordEncrypted");
|
||||
setLabelFromStringBundle("in-authMethod-kerberos", "authKerberos");
|
||||
setLabelFromStringBundle("in-authMethod-ntlm", "authNTLM");
|
||||
setLabelFromStringBundle("in-authMethod-oauth2", "authOAuth2");
|
||||
setLabelFromStringBundle("out-authMethod-no", "authNo");
|
||||
setLabelFromStringBundle("out-authMethod-password-cleartext",
|
||||
"authPasswordCleartextViaSSL"); // will warn about insecure later
|
||||
|
@ -188,6 +192,7 @@ EmailConfigWizard.prototype =
|
|||
"authPasswordEncrypted");
|
||||
setLabelFromStringBundle("out-authMethod-kerberos", "authKerberos");
|
||||
setLabelFromStringBundle("out-authMethod-ntlm", "authNTLM");
|
||||
setLabelFromStringBundle("out-authMethod-oauth2", "authOAuth2");
|
||||
|
||||
e("incoming_port").value = gStringsBundle.getString("port_auto");
|
||||
this.fillPortDropdown("smtp");
|
||||
|
@ -665,7 +670,7 @@ EmailConfigWizard.prototype =
|
|||
assert(config instanceof AccountConfig,
|
||||
"BUG: Arg 'config' needs to be an AccountConfig object");
|
||||
|
||||
this._haveValidConfigForDomain = this._email.split("@")[1];;
|
||||
this._haveValidConfigForDomain = this._email.split("@")[1];
|
||||
|
||||
if (!this._realname || !this._email) {
|
||||
return;
|
||||
|
@ -792,6 +797,7 @@ EmailConfigWizard.prototype =
|
|||
unknownString);
|
||||
let certStatus = gStringsBundle.getString(server.badCert ?
|
||||
"resultSSLCertWeak" : "resultSSLCertOK");
|
||||
// TODO: we should really also display authentication method here.
|
||||
return gStringsBundle.getFormattedString(stringName,
|
||||
[ type, host, ssl, certStatus ]);
|
||||
};
|
||||
|
@ -1008,7 +1014,7 @@ EmailConfigWizard.prototype =
|
|||
e("incoming_ssl").value = sanitize.enum(config.incoming.socketType,
|
||||
[ 0, 1, 2, 3 ], 0);
|
||||
e("incoming_authMethod").value = sanitize.enum(config.incoming.auth,
|
||||
[ 0, 3, 4, 5, 6 ], 0);
|
||||
[ 0, 3, 4, 5, 6, 10 ], 0);
|
||||
e("incoming_username").value = config.incoming.username;
|
||||
if (config.incoming.port) {
|
||||
e("incoming_port").value = config.incoming.port;
|
||||
|
@ -1017,6 +1023,19 @@ EmailConfigWizard.prototype =
|
|||
}
|
||||
this.fillPortDropdown(config.incoming.type);
|
||||
|
||||
// If the hostname supports OAuth2 and imap is enabled, enable OAuth2.
|
||||
let iDetails = OAuth2Providers.getHostnameDetails(config.incoming.hostname);
|
||||
gEmailWizardLogger.info("OAuth2 details for incoming hostname " +
|
||||
config.incoming.hostname + " is " + iDetails);
|
||||
e("in-authMethod-oauth2").hidden = !(iDetails && e("incoming_protocol").value == 1);
|
||||
if (!e("in-authMethod-oauth2").hidden) {
|
||||
config.oauthSettings = {};
|
||||
[config.oauthSettings.issuer, config.oauthSettings.scope] = iDetails;
|
||||
// oauthsettings are not stored nor changable in the user interface, so just
|
||||
// store them in the base configuration.
|
||||
this._currentConfig.oauthSettings = config.oauthSettings;
|
||||
}
|
||||
|
||||
// outgoing server
|
||||
e("outgoing_hostname").value = config.outgoing.hostname;
|
||||
e("outgoing_username").value = config.outgoing.username;
|
||||
|
@ -1026,14 +1045,27 @@ EmailConfigWizard.prototype =
|
|||
e("outgoing_ssl").value = sanitize.enum(config.outgoing.socketType,
|
||||
[ 0, 1, 2, 3 ], 0);
|
||||
e("outgoing_authMethod").value = sanitize.enum(config.outgoing.auth,
|
||||
[ 0, 1, 3, 4, 5, 6 ], 0);
|
||||
[ 0, 1, 3, 4, 5, 6, 10 ], 0);
|
||||
if (config.outgoing.port) {
|
||||
e("outgoing_port").value = config.outgoing.port;
|
||||
} else {
|
||||
this.adjustOutgoingPortToSSLAndProtocol(config);
|
||||
}
|
||||
// populate fields even if existingServerKey, in case user changes back
|
||||
|
||||
// If the hostname supports OAuth2 and imap is enabled, enable OAuth2.
|
||||
let oDetails = OAuth2Providers.getHostnameDetails(config.outgoing.hostname);
|
||||
gEmailWizardLogger.info("OAuth2 details for outgoing hostname " +
|
||||
config.outgoing.hostname + " is " + oDetails);
|
||||
e("out-authMethod-oauth2").hidden = !oDetails;
|
||||
if (!e("out-authMethod-oauth2").hidden) {
|
||||
config.oauthSettings = {};
|
||||
[config.oauthSettings.issuer, config.oauthSettings.scope] = oDetails;
|
||||
// oauthsettings are not stored nor changable in the user interface, so just
|
||||
// store them in the base configuration.
|
||||
this._currentConfig.oauthSettings = config.oauthSettings;
|
||||
}
|
||||
|
||||
// populate fields even if existingServerKey, in case user changes back
|
||||
if (config.outgoing.existingServerKey) {
|
||||
let menulist = e("outgoing_hostname");
|
||||
// We can't use menulist.value = config.outgoing.existingServerKey
|
||||
|
@ -1581,6 +1613,12 @@ EmailConfigWizard.prototype =
|
|||
self._currentConfig.outgoing.auth = successfulConfig.outgoing.auth;
|
||||
self._currentConfig.incoming.username = successfulConfig.incoming.username;
|
||||
self._currentConfig.outgoing.username = successfulConfig.outgoing.username;
|
||||
|
||||
// We loaded dynamic client registration, fill this data back in to the
|
||||
// config set.
|
||||
if (successfulConfig.oauthSettings)
|
||||
self._currentConfig.oauthSettings = successfulConfig.oauthSettings;
|
||||
|
||||
self.finish();
|
||||
},
|
||||
function(e) // failed
|
||||
|
|
|
@ -307,6 +307,7 @@
|
|||
<menuitem id="in-authMethod-password-encrypted" value="4"/>
|
||||
<menuitem id="in-authMethod-kerberos" value="5"/>
|
||||
<menuitem id="in-authMethod-ntlm" value="6"/>
|
||||
<menuitem id="in-authMethod-oauth2" value="10" hidden="true"/>
|
||||
</menupopup>
|
||||
</menulist>
|
||||
</row>
|
||||
|
@ -356,6 +357,7 @@
|
|||
<menuitem id="out-authMethod-password-encrypted" value="4"/>
|
||||
<menuitem id="out-authMethod-kerberos" value="5"/>
|
||||
<menuitem id="out-authMethod-ntlm" value="6"/>
|
||||
<menuitem id="out-authMethod-oauth2" value="10" hidden="true"/>
|
||||
</menupopup>
|
||||
</menulist>
|
||||
</row>
|
||||
|
|
|
@ -59,6 +59,13 @@ function guessConfig(domain, progressCallback, successCallback, errorCallback,
|
|||
assert(typeof(progressCallback) == "function", "need progressCallback");
|
||||
assert(typeof(successCallback) == "function", "need successCallback");
|
||||
assert(typeof(errorCallback) == "function", "need errorCallback");
|
||||
|
||||
// Servers that we know enough that they support OAuth2 do not need guessing.
|
||||
if (resultConfig.incoming.auth == Ci.nsMsgAuthMethod.OAuth2) {
|
||||
successCallback(resultConfig);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!resultConfig)
|
||||
resultConfig = new AccountConfig();
|
||||
resultConfig.source = AccountConfig.kSourceGuess;
|
||||
|
|
|
@ -54,6 +54,16 @@ function readFromXML(clientConfigXML)
|
|||
throw exception ? exception : "need proper <domain> in XML";
|
||||
exception = null;
|
||||
|
||||
let oauthSettings = null;
|
||||
if ("oauth2Settings" in clientConfigXML.clientConfig) {
|
||||
oauthSettings = {};
|
||||
oauthSettings.scope = sanitize.nonemptystring(
|
||||
clientConfigXML.clientConfig.oauth2Settings.scope);
|
||||
if (!oauthSettings.scope)
|
||||
throw new Error("Malformed oauth2Settings in configuration XML");
|
||||
d.oauthSettings = oauthSettings;
|
||||
}
|
||||
|
||||
// incoming server
|
||||
for (let iX of array_or_undef(xml.$incomingServer)) // input (XML)
|
||||
{
|
||||
|
@ -94,7 +104,13 @@ function readFromXML(clientConfigXML)
|
|||
// @deprecated TODO remove
|
||||
"secure" : Ci.nsMsgAuthMethod.passwordEncrypted,
|
||||
"GSSAPI" : Ci.nsMsgAuthMethod.GSSAPI,
|
||||
"NTLM" : Ci.nsMsgAuthMethod.NTLM });
|
||||
"NTLM" : Ci.nsMsgAuthMethod.NTLM,
|
||||
"OAuth2" : Ci.nsMsgAuthMethod.OAuth2 });
|
||||
|
||||
// If we're using OAuth2, but don't have working settings, bail.
|
||||
if (iO.auth == Ci.nsMsgAuthMethod.OAuth2 && !oauthSettings)
|
||||
continue;
|
||||
|
||||
break; // take first that we support
|
||||
} catch (e) { exception = e; }
|
||||
}
|
||||
|
@ -175,7 +191,13 @@ function readFromXML(clientConfigXML)
|
|||
"secure" : Ci.nsMsgAuthMethod.passwordEncrypted,
|
||||
"GSSAPI" : Ci.nsMsgAuthMethod.GSSAPI,
|
||||
"NTLM" : Ci.nsMsgAuthMethod.NTLM,
|
||||
"OAuth2" : Ci.nsMsgAuthMethod.OAuth2,
|
||||
});
|
||||
|
||||
// If we're using OAuth2, but don't have working settings, bail.
|
||||
if (oO.auth == Ci.nsMsgAuthMethod.OAuth2 && !oauthSettings)
|
||||
continue;
|
||||
|
||||
break; // take first that we support
|
||||
} catch (e) { exception = e; }
|
||||
}
|
||||
|
|
|
@ -118,7 +118,7 @@ var sanitize =
|
|||
|
||||
var uri;
|
||||
try {
|
||||
uri = ioService().newURI(str, null, null);
|
||||
uri = Services.io.newURI(str, null, null);
|
||||
uri = uri.QueryInterface(Ci.nsIURL);
|
||||
} catch (e) {
|
||||
throw new MalformedException("url_parsing.error", unchecked);
|
||||
|
|
|
@ -248,11 +248,13 @@ function deepCopy(org)
|
|||
return result;
|
||||
}
|
||||
|
||||
let kDebug = false;
|
||||
if (typeof gEmailWizardLogger == "undefined") {
|
||||
Cu.import("resource:///modules/gloda/log4moz.js");
|
||||
var gEmailWizardLogger = Log4Moz.getConfiguredLogger("mail.wizard");
|
||||
}
|
||||
function ddump(text)
|
||||
{
|
||||
if (kDebug)
|
||||
dump(text + "\n");
|
||||
gEmailWizardLogger.info(text);
|
||||
}
|
||||
|
||||
function debugObject(obj, name, maxDepth, curDepth)
|
||||
|
|
|
@ -30,6 +30,12 @@
|
|||
*/
|
||||
|
||||
Components.utils.import("resource:///modules/mailServices.js");
|
||||
Components.utils.import("resource://gre/modules/OAuth2Providers.jsm");
|
||||
|
||||
if (typeof gEmailWizardLogger == "undefined") {
|
||||
Cu.import("resource:///modules/gloda/log4moz.js");
|
||||
var gEmailWizardLogger = Log4Moz.getConfiguredLogger("mail.wizard");
|
||||
}
|
||||
|
||||
function verifyConfig(config, alter, msgWindow, successCallback, errorCallback)
|
||||
{
|
||||
|
@ -63,10 +69,35 @@ function verifyConfig(config, alter, msgWindow, successCallback, errorCallback)
|
|||
inServer.socketType = Ci.nsMsgSocketType.SSL;
|
||||
else if (config.incoming.socketType == 3) // STARTTLS
|
||||
inServer.socketType = Ci.nsMsgSocketType.alwaysSTARTTLS;
|
||||
|
||||
gEmailWizardLogger.info("Setting incoming server authMethod to " +
|
||||
config.incoming.auth);
|
||||
inServer.authMethod = config.incoming.auth;
|
||||
|
||||
try {
|
||||
if (inServer.password)
|
||||
// Lookup issuer if needed.
|
||||
if (config.incoming.auth == Ci.nsMsgAuthMethod.OAuth2 ||
|
||||
config.outgoing.auth == Ci.nsMsgAuthMethod.OAuth2) {
|
||||
if (!config.oauthSettings.issuer || !config.oauthSettings.scope) {
|
||||
// lookup issuer or scope from hostname
|
||||
let hostname = (config.incoming.auth == Ci.nsMsgAuthMethod.OAuth2) ?
|
||||
config.incoming.hostname : config.outgoing.hostname;
|
||||
let hostDetails = OAuth2Providers.getHostnameDetails(hostname);
|
||||
if (hostDetails)
|
||||
[config.oauthSettings.issuer, config.oauthSettings.scope] = hostDetails;
|
||||
if (!config.oauthSettings.issuer || !config.oauthSettings.scope)
|
||||
throw "Could not get issuer for oauth2 authentication";
|
||||
}
|
||||
gEmailWizardLogger.info("Saving oauth parameters for issuer " +
|
||||
config.oauthSettings.issuer);
|
||||
inServer.setCharValue("oauth2.scope", config.oauthSettings.scope);
|
||||
inServer.setCharValue("oauth2.issuer", config.oauthSettings.issuer);
|
||||
gEmailWizardLogger.info("OAuth2 issuer, scope is " +
|
||||
config.oauthSettings.issuer + ", " + config.oauthSettings.scope);
|
||||
}
|
||||
|
||||
if (inServer.password ||
|
||||
inServer.authMethod == Ci.nsMsgAuthMethod.OAuth2)
|
||||
verifyLogon(config, inServer, alter, msgWindow,
|
||||
successCallback, errorCallback);
|
||||
else {
|
||||
|
@ -74,16 +105,20 @@ function verifyConfig(config, alter, msgWindow, successCallback, errorCallback)
|
|||
MailServices.accounts.removeIncomingServer(inServer, true);
|
||||
successCallback(config);
|
||||
}
|
||||
} catch (e) {
|
||||
ddump("ERROR: verify logon shouldn't have failed");
|
||||
errorCallback(e);
|
||||
throw(e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
catch (e) {
|
||||
gEmailWizardLogger.error("ERROR: verify logon shouldn't have failed");
|
||||
}
|
||||
// Avoid pref pollution, clear out server prefs.
|
||||
MailServices.accounts.removeIncomingServer(inServer, true);
|
||||
errorCallback(e);
|
||||
}
|
||||
|
||||
function verifyLogon(config, inServer, alter, msgWindow, successCallback,
|
||||
errorCallback)
|
||||
{
|
||||
gEmailWizardLogger.info("verifyLogon for server at " + inServer.hostName);
|
||||
// hack - save away the old callbacks.
|
||||
let saveCallbacks = msgWindow.notificationCallbacks;
|
||||
// set our own callbacks - this works because verifyLogon will
|
||||
|
@ -99,6 +134,7 @@ function verifyLogon(config, inServer, alter, msgWindow, successCallback,
|
|||
// clear msgWindow so url won't prompt for passwords.
|
||||
uri.QueryInterface(Ci.nsIMsgMailNewsUrl).msgWindow = null;
|
||||
}
|
||||
catch (e) { gEmailWizardLogger.error("verifyLogon failed: " + e); throw e;}
|
||||
finally {
|
||||
// restore them
|
||||
msgWindow.notificationCallbacks = saveCallbacks;
|
||||
|
|
|
@ -9,6 +9,7 @@ const Ci = Components.interfaces;
|
|||
const Cr = Components.results;
|
||||
|
||||
Components.utils.import("resource://gre/modules/OAuth2.jsm");
|
||||
Components.utils.import("resource://gre/modules/OAuth2Providers.jsm");
|
||||
Components.utils.import("resource://gre/modules/Preferences.jsm");
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
@ -22,19 +23,11 @@ OAuth2Module.prototype = {
|
|||
classID: Components.ID("{b63d8e4c-bf60-439b-be0e-7c9f67291042}"),
|
||||
|
||||
_loadOAuthClientDetails(aIssuer) {
|
||||
if (aIssuer == "accounts.google.com") {
|
||||
// For the moment, these details are hard-coded, since Google does not
|
||||
// provide dynamic client registration. Don't copy these values for your
|
||||
// own application--register it yourself. This code (and possibly even the
|
||||
// registration itself) will disappear when this is switched to dynamic
|
||||
// client registration.
|
||||
this._appKey = '406964657835-aq8lmia8j95dhl1a2bvharmfk3t1hgqj.apps.googleusercontent.com';
|
||||
this._appSecret = 'kSmqreRr0qwBWJgbf5Y-PjSU';
|
||||
this._authURI = "https://accounts.google.com/o/oauth2/auth";
|
||||
this._tokenURI = "https://www.googleapis.com/oauth2/v3/token";
|
||||
} else {
|
||||
let details = OAuth2Providers.getIssuerDetails(aIssuer);
|
||||
if (details)
|
||||
[this._appKey, this._appSecret, this._authURI, this._tokenURI] = details;
|
||||
else
|
||||
throw Cr.NS_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
},
|
||||
initFromSmtp(aServer) {
|
||||
return this._initPrefs("mail.smtpserver." + aServer.key + ".",
|
||||
|
@ -53,10 +46,10 @@ OAuth2Module.prototype = {
|
|||
// have them, we don't support OAuth2.
|
||||
if (!issuer || !scope) {
|
||||
// Since we currently only support gmail, init values if server matches.
|
||||
if (aHostname == "imap.googlemail.com" || aHostname == "smtp.googlemail.com")
|
||||
let details = OAuth2Providers.getHostnameDetails(aHostname);
|
||||
if (details)
|
||||
{
|
||||
issuer = "accounts.google.com";
|
||||
scope = "http://mail.google.com/";
|
||||
[issuer, scope] = details;
|
||||
Preferences.set(root + "oauth2.issuer", issuer);
|
||||
Preferences.set(root + "oauth2.scope", scope);
|
||||
}
|
||||
|
|
|
@ -56,10 +56,6 @@ OAuth2.prototype = {
|
|||
tokenExpires: 0,
|
||||
|
||||
connect: function connect(aSuccess, aFailure, aWithUI, aRefresh) {
|
||||
if (gConnecting[this.authURI]) {
|
||||
aFailure("Window already open");
|
||||
return;
|
||||
}
|
||||
|
||||
this.connectSuccessCallback = aSuccess;
|
||||
this.connectFailureCallback = aFailure;
|
||||
|
@ -67,14 +63,16 @@ OAuth2.prototype = {
|
|||
if (!aRefresh && this.accessToken) {
|
||||
aSuccess();
|
||||
} else if (this.refreshToken) {
|
||||
gConnecting[this.authURI] = true;
|
||||
this.requestAccessToken(this.refreshToken, OAuth2.CODE_REFRESH);
|
||||
} else {
|
||||
if (!aWithUI) {
|
||||
aFailure('{ "error": "auth_noui" }');
|
||||
return;
|
||||
}
|
||||
gConnecting[this.authURI] = true;
|
||||
if (gConnecting[this.authURI]) {
|
||||
aFailure("Window already open");
|
||||
return;
|
||||
}
|
||||
this.requestAuthorization();
|
||||
}
|
||||
},
|
||||
|
@ -156,9 +154,11 @@ OAuth2.prototype = {
|
|||
};
|
||||
|
||||
this.wrappedJSObject = this._browserRequest;
|
||||
gConnecting[this.authURI] = true;
|
||||
Services.ww.openWindow(null, this.requestWindowURI, null, this.requestWindowFeatures, this);
|
||||
},
|
||||
finishAuthorizationRequest: function() {
|
||||
gConnecting[this.authURI] = false;
|
||||
if (!("_browserRequest" in this)) {
|
||||
return;
|
||||
}
|
||||
|
@ -183,7 +183,6 @@ OAuth2.prototype = {
|
|||
},
|
||||
|
||||
onAuthorizationFailed: function(aError, aData) {
|
||||
gConnecting[this.authURI] = false;
|
||||
this.connectFailureCallback(aData);
|
||||
},
|
||||
|
||||
|
@ -210,7 +209,6 @@ OAuth2.prototype = {
|
|||
},
|
||||
|
||||
onAccessTokenFailed: function onAccessTokenFailed(aError, aData) {
|
||||
gConnecting[this.authURI] = false;
|
||||
if (aError != "offline") {
|
||||
this.refreshToken = null;
|
||||
}
|
||||
|
@ -218,7 +216,6 @@ OAuth2.prototype = {
|
|||
},
|
||||
|
||||
onAccessTokenReceived: function onRequestTokenReceived(aData) {
|
||||
gConnecting[this.authURI] = false;
|
||||
let result = JSON.parse(aData);
|
||||
|
||||
this.accessToken = result.access_token;
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* Details of supported OAuth2 Providers.
|
||||
*/
|
||||
var EXPORTED_SYMBOLS = ["OAuth2Providers"];
|
||||
|
||||
const {classes: Cc, interfaces: Ci, results: Cr, utils: Cu} = Components;
|
||||
|
||||
// map of hostnames to [issuer, scope]
|
||||
const kHostnames = new Map([
|
||||
["imap.googlemail.com", ["accounts.google.com", "http://mail.google.com/"]],
|
||||
["smtp.googlemail.com", ["accounts.google.com", "http://mail.google.com/"]],
|
||||
]);
|
||||
|
||||
// map of issuers to appKey, appSecret, authURI, tokenURI
|
||||
|
||||
// For the moment, these details are hard-coded, since Google does not
|
||||
// provide dynamic client registration. Don't copy these values for your
|
||||
// own application--register it yourself. This code (and possibly even the
|
||||
// registration itself) will disappear when this is switched to dynamic
|
||||
// client registration.
|
||||
const kIssuers = new Map ([
|
||||
["accounts.google.com", [
|
||||
'406964657835-aq8lmia8j95dhl1a2bvharmfk3t1hgqj.apps.googleusercontent.com',
|
||||
'kSmqreRr0qwBWJgbf5Y-PjSU',
|
||||
'https://accounts.google.com/o/oauth2/auth',
|
||||
'https://www.googleapis.com/oauth2/v3/token'
|
||||
]],
|
||||
]);
|
||||
|
||||
/**
|
||||
* OAuth2Providers: Methods to lookup OAuth2 parameters for supported
|
||||
* email providers.
|
||||
*/
|
||||
var OAuth2Providers = {
|
||||
|
||||
/**
|
||||
* Map a hostname to the relevant issuer and scope.
|
||||
*
|
||||
* @param aHostname String representing the url for an imap or smtp
|
||||
* server (example "imap.googlemail.com").
|
||||
*
|
||||
* @returns Array with [issuer, scope] for the hostname if found,
|
||||
* else undefined. issuer is a string representing the
|
||||
* organization, scope is an oauth parameter describing\
|
||||
* the required access level.
|
||||
*/
|
||||
getHostnameDetails: function (aHostname) { return kHostnames.get(aHostname);},
|
||||
|
||||
/**
|
||||
* Map an issuer to OAuth2 account details.
|
||||
*
|
||||
* @param aIssuer The organization issuing oauth2 parameters, example
|
||||
* "accounts.google.com".
|
||||
*
|
||||
* @return Array containing [appKey, appSecret, authURI, tokenURI]
|
||||
* where appKey and appDetails are strings representing the
|
||||
* account registered for Thunderbird with the organization,
|
||||
* authURI and tokenURI are url strings representing
|
||||
* endpoints to access OAuth2 authentication.
|
||||
*/
|
||||
getIssuerDetails: function (aIssuer) { return kIssuers.get(aIssuer);}
|
||||
}
|
|
@ -60,6 +60,7 @@ EXTRA_JS_MODULES += [
|
|||
'mailServices.js',
|
||||
'msgDBCacheManager.js',
|
||||
'OAuth2.jsm',
|
||||
'OAuth2Providers.jsm',
|
||||
'StringBundle.js',
|
||||
'templateUtils.js',
|
||||
'traceHelper.js',
|
||||
|
|
Загрузка…
Ссылка в новой задаче