FirefoxやThunderbirdには、古い集中管理の仕組みとしてMCD(Mission Control Desktop)という機能があります。 元々はシステム管理者が決めた設定値を各端末のソフトウェアに強制適用するための物でしたが、現在その役割はポリシー設定機能が担うようになってきており、この用途においてMCDは、ポリシー設定機能では制御できない部分を補うために使われる程度となっています。
このMCDの設定ファイルを使用している環境では、FirefoxやThunderbirdの更新後に、起動時に「設定ファイルを正常に読み込めませんでした。システム管理者に問い合わせてください。」というメッセージが表示されるようになることがあります。 最近も、Thunderbrird 136への更新でこの現象が起こるようになったとのご相談をお客様から頂きました。
詳しく調査したところ、Thunderbird 136において、確かに同様のトラブルが起こりやすくなるような変更があったことと、多くの場合はモジュールの読み込みを行っている箇所を修正するだけで問題を解消できることが分かりました。 本記事では、この問題の背景事情と回避方法をご紹介します。
結論:Cu.import()
があればChromeUtils.importESModule()
に書き換えてみる
先に結論から述べると、
const { ~ } = Components.utils.import('~.jsm', {});
あるいは
const { ~ } = Cu.import('~.jsm', {});
このようなモジュール読み込みの指定がMCD用設定ファイルに含まれているのであれば、
const { ~ } = ChromeUtils.importESModule('~.sys.mjs');
と書き換えてみてください。 それ以前は動いていたのにThunderbird 136に更新したら動かなくなった、というケースの大半は、この変更で解消されると考えられます。
問題が起こる背景1:高度なカスタマイズ
先に、MCDはポリシー設定を補完する物と述べましたが、もう一つの使い方として、Firefox 57およびThunderbird 78以降で廃止されたXUL拡張機能を代替する用法があります。
現在の拡張機能は、専用のサンドボックス内で実行される非特権コードがWebExtensionsというAPIを通じてFirefox/Thunderbirdを制御する物となっており、できることは大幅に制限されています。 しかし、かつてのXUL拡張機能はFirefox/Thunderbirdに動的に特権コードを組み込む物であったため、外部との通信やローカルファイルの読み書き、内部コンポーネントの置き換えによる動作の変更などを無制限に行えました。
MCDは設定ファイルがJavaScriptのプログラムの形式を取っており、実装の性質上、現行バージョンのFirefox/ThunderbirdにおいてXUL拡張機能と同等のことを行える一種の「抜け道」となっています。 そのため当社の法人向けサポートでは、お客様からの特殊なご要望にお応えするために、実行可能コードを含むMCD用設定ファイルをご提供している事例がいくつかあります。
この用法は正規の手段では行えない柔軟なカスタマイズが可能ですが、XUL拡張機能がそうだったように、Firefox/Thunderbirdの内部APIの変更の影響を直接的に受けるため、更新で内部APIに互換性がなくなると途端に動作しなくなります。 それまで問題無く動作していたものが、更新後に先述の「設定ファイルを正常に読み込めませんでした。システム管理者に問い合わせてください。」というメッセージが表示されるようになってしまった、という問題は一般的にはこのような背景で発生します。
問題が起こる背景2:モジュール形式の変更
もう1つの背景として、近年Firefox/Thunderbird内で進められてきた、JS Code ModulesからES Modulesへの変更があります。
Firefox/Thunderbirdでは、ES Modulesという仕様ができる以前から、Mozilla独自のモジュール形式であるJS Code Modulesという形式でJavaScriptのモジュール化を行っていました。 しかし、ES Modulesの仕様が標準化され普及した現在では、Mozilla独自のモジュール形式を使用することに特段のメリットはもうありません。 そのため近年では、JS Code ModulesのモジュールをES Modulesに移行する変更が数多く行われています。 その際、後方互換性のための仕組みによって、ES Modulesに書き換えられた後のモジュールをJS Code Modulesとしても読み込める状態が維持されていたのですが、Firefox 136/Thunderbird 136の時点で、この後方互換性のための仕組みが廃止されました。 このために、JS Code Modulesを使うよう書かれていたMCD用設定ファイルは、Firefox 136/Thunderbird 136で読み込むと実行時にエラーが発生するようになりました。 これが、この問題の第2の背景です。
トラブルとその対処の事例
例えば、以下はThunderbird 128でアドレス帳のUI上の「エクスポート」機能を無効化するMCD用設定ファイル(autoconfig.cfg)の例です。 このMCD用設定ファイルを使用している状態でThunderbirdをThunderbird 136(およびそれ以降)に更新すると、Thunderbird起動時にエラーメッセージが表示されるようになり、「アドレス帳のエクスポート操作の禁止」が行われない状態になります。
// 1行目はThunderbirdによって無視されるため必ずコメント行とする
{// アドレス帳のエクスポート操作を禁止
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
const { AddonManager } = Cu.import('resource://gre/modules/AddonManager.jsm', {});
// 開かれたウィンドウを処理するハンドラー
const handleWindow = async window => {
// アドレス帳以外のウィンドウを無視
if (window.location.href != 'chrome://messenger/content/addressbook/addressbook.xhtml' &&
window.location.href != 'about:addressbook')
return;
// エクスポート操作に関わるUIを無効化
const items = window.document.querySelectorAll(
'[oncommand*="AbExportSelection"], [id~="bookContextExport"]'
);
for (const item of items) {
item.disabled = true;
item.setAttribute('disabled', true); // failsafe
}
window.AbExportSelection = () => {};
};
// 起動時点で開かれているすべてのウィンドウを走査して処理する
const windows = Services.wm.getEnumerator(null);
while (windows.hasMoreElements()) {
handleWindow(windows.getNext().QueryInterface(Ci.nsIDOMWindow));
}
// ウィンドウが開かれたときのイベントを検知して、
// 新たに開かれたすべてのウィンドウを処理する
Services.ww.registerNotification({
observe(subject, topic, data) {
if (topic != 'domwindowopened' ||
subject
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell)
.QueryInterface(Ci.nsIDocShellTreeNode || Ci.nsIDocShellTreeItem)
.QueryInterface(Ci.nsIDocShellTreeItem)
.parent)
return;
subject.getInterface(Ci.nsIDOMWindow).addEventListener('DOMContentLoaded', event => {
handleWindow(event.target.defaultView);
event.target.defaultView.addEventListener('DOMContentLoaded', event => {
handleWindow(event.target.defaultView);
}, { capture: true });
}, { once: true });
}
});
}
エラーは、冒頭にあるモジュール読み込みのためのこの行で発生します。
const { AddonManager } = Cu.import('resource://gre/modules/AddonManager.jsm', {});
ここで読み込んでいるアドオンマネージャーのモジュールは、Firefox 115/Thunderbird 115の時点ですでにES Modulesに移行していましたものが、先述の後方互換性の仕組みによってJS Code Modulesとして読み込まれていました。 そのため、後方互換性のための仕組みが廃止されたThunderbird 136ではモジュールを読み込めなくなり、エラーが発生するようになっているわけです。
ES Modulesのモジュールは静的なimport
文かimport()
関数でインポートしますが、前者を使うにはファイル全体がES Modulesのモジュールである必要があり、後者を使うにはモジュールを非同期で読み込む必要があります。
MCD用設定ファイルはES Modulesとして読み込まれる物ではないためimport()
を使うしかないのですが、そのためにはモジュールを読み込んで使用している箇所を非同期処理に書き換えなくてはならず、やりたいことによっては、それだと目的を達成できない恐れがあります。
そこで使うのが、Firefox/Thunderbird内部で使うための物として用意された、ES Modulesのモジュールを同期読み込みするChromeUtils.importESModule()
です。
先の箇所を以下のように書き換えれば、モジュールを期待通りに読み込めるようになり、Thunderbird起動時のエラーが解消されます。
const { AddonManager } = ChromeUtils.importESModule('resource://gre/modules/AddonManager.sys.mjs');
まとめ
以上、MCDの設定ファイルが読み込めなくなる問題のうち、Thunderbird 136への更新で起こりやすい事例の背景と対処方法を紹介しました。
MCD用設定ファイル内でのエラーの詳細は、Firefox/Thunderbirdが起動した後にキーボードショートカット「Ctrl-Shift-J」でエラーコンソールを開くと確認でき、多くの場合はコンソールの最初の方にメッセージが出ています。
Cu.import()
(Components.utils.import()
)を実行している行でエラーになっているようであれば、本記事で紹介した対処で動作するようになる可能性がありますが、それでも駄目な場合は、モジュールが廃止されたりリネームされたりしている可能性があり、変更の経緯を追っての調査が必要になります。
当社では、そのような調査・対応も含めたThunderbirdの包括的なサポートサービスを法人のお客様向けに有償にてご提供しています。 Thunderbirdを企業で導入していて同様のトラブルでお困りのシステム管理者の方は、お問い合わせフォームよりご連絡ください。