Revision control
Copy as Markdown
Other Tools
/* 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,
'use strict';
/**
* AccountHub Experiment API
*
* Listens for new incoming-server registrations from Thunderbird's Accounts Hub.
* When a Thundermail account is added, retrieves its OIDC/OAuth2 refresh token
* and fires the onAccountAdded event so the add-on can log the user in automatically.
*/
(function (exports) {
var { MailServices } = ChromeUtils.importESModule(
);
var { OAuth2Module } = ChromeUtils.importESModule(
);
/** Matches both production (mail.thundermail.com) and staging (mail.stage-thundermail.com) hosts. */
const THUNDERMAIL_HOST_PATTERN = /thundermail\.com$/i;
class AccountHub extends ExtensionCommon.ExtensionAPI {
getAPI(context) {
return {
AccountHub: {
onAccountAdded: new ExtensionCommon.EventManager({
context,
name: 'AccountHub.onAccountAdded',
register(fire) {
const serverListener = {
QueryInterface: ChromeUtils.generateQI([
'nsIIncomingServerListener',
]),
async onServerLoaded(server) {
try {
const hostname = server.hostname;
if (!THUNDERMAIL_HOST_PATTERN.test(hostname)) {
return;
}
const email = server.username;
const oauth2Module = new OAuth2Module();
if (!oauth2Module.initFromMail(server)) {
console.warn(
`[AccountHub] Failed to initialize OAuth2Module for ${hostname}`
);
return;
}
// getRefreshToken() asynchronously reads the stored token
// from the Thunderbird login manager (password manager).
// The token is guaranteed to be stored already because
// verifyConfig() (which runs OAuth2 auth) completes before
// createAccountInBackend() fires NotifyServerLoaded.
const token = await oauth2Module.getRefreshToken();
if (!token) {
console.warn(
`[AccountHub] No OIDC token available for ${email} — skipping auto-login`
);
return;
}
// Retrieve the display name from the account's default identity.
const account =
MailServices.accounts.findAccountForServer(server);
const name = account?.defaultIdentity?.fullName ?? '';
fire.async({ token, email, name });
} catch (e) {
console.error(
'[AccountHub] Error in onServerLoaded handler:',
e
);
}
},
// Required by nsIMsgIncomingServerListener but not used here.
onServerUnloaded(_server) { },
onServerChanged(_server) { },
};
MailServices.accounts.addIncomingServerListener(serverListener);
// Return cleanup function — called when the listener is removed.
return () => {
MailServices.accounts.removeIncomingServerListener(
serverListener
);
};
},
}).api(),
},
};
}
}
exports.AccountHub = AccountHub;
})(this);