老犬に新しい芸を ― ForgejoとXMPP

最近、Codebergを離れることにしました。代わりに自分でForgejoのインスタンスを運用することにしたのです。初期セットアップを終えて気づいたのは、自分でホストするforgeは自分で形を作れるforgeだということです。誰かが「妥当」と考えた機能セットで我慢する必要はもうありません。本当に自分のものにできますし、Gitホストにずっと求めてきたことをようやく実現できるのです。
まず取り組みたいのがユーザー登録の仕組みです。今のForgejoは、他のほとんどのforgeと同じようにメールアドレスを求め、そこに確認リンクを送ります。リンクをクリックすれば向こう側に人間がいると証明したことになる、という考えのようです。しかし私は、むしろXMPPのJIDで登録できるようにしたいと考えています。理由は二つあります。一つは、リンクを受信できるメールアドレスが、自動スパムにとって障壁にならなくなって久しく、メール認証の効果は思われているほど高くないことです。もう一つは、XMPPの方が優れたプロトコルであり、最初からメールではなくXMPP経由でユーザーに来てほしいからです。
残念ながらForgejoにはネイティブなXMPPサポートがありません。加えて、Goのshared objectsも使われていません。これがあれば拡張機能をコアからほぼ独立して構築できるはずで、この規模のモノリスであればなおさら理にかなっているのですが。コア自体に手を入れずにプロトコルを追加できるきれいな場所は存在しないのです。
ただ、私はForgejoの中に本物のJID登録や認証を実装しようとは思いませんでした。それは風車に立ち向かうようなものだからです。これは経験から言っています。これまでもっと軽微な変更でさえ、設計に関する議論やユースケースの収集といった官僚的な要件で潰されてきましたし、どこかで通行証A38まで求められたことでしょう。そこで、まともでありながら少し常軌を逸した人なら誰でもそうするように、Forgejoの既存のメール連携をXMPPにブリッジすることにしたのです。
Switchyardの紹介
Switchyardは、片側でSMTPを、もう片側でXMPPを話す小さなデーモンです。メールとXMPPは偶然にも同じアドレス形式[email protected]を共有しているため、宛先はそのまま対応します。[email protected]宛てのメッセージは、JIDの[email protected]へのチャットとして送信されるのです。サービスからSMTP経由で送られたメールを受け取り、それぞれをキュー上のジョブに変換し、ワーカーが常時接続のXMPPコネクション経由で配信します。このコネクションはサーバー側で切断されても自動的に再接続されます。
通常のメールサーバーと同じようにSMTPを待ち受けるため、Forgejo側にパッチを当てる必要はありません。実際のメールサーバーを指定するときと同じブロックで、mailerエンドポイントとして設定するだけです。
[mailer]
ENABLED = true
FROM = [email protected]
PROTOCOL = smtp
SMTP_ADDR = 127.0.0.1
SMTP_PORT = 587
USER = forgejo
PASSWD = `change-me`反対側では、短いswitchyard.tomlで、Forgejo側と照合する認証情報、サブミッションポート用の証明書、そしてすべての送信に使う単一のXMPPアカウントを指定します。
[redis]
addrs = ["127.0.0.1:6379"]
[smtp]
allowed_ips = ["127.0.0.1/32"]
username = "forgejo"
password = "change-me"
[smtp.tls]
enable = true
cert = "/etc/switchyard/tls/cert.pem"
key = "/etc/switchyard/tls/key.pem"
[xmpp]
server = "xmpp.myhost.tld:5222"
username = "[email protected]"
password = "change-me"これで、Forgejoが本来メールで送るはずのあらゆるメッセージ――登録確認やパスワードリセット、新しいissueの通知など――が、ユーザーがメール欄に入力したJID宛てにXMPP経由で届くようになります。SwitchyardはIDNにも対応しています。まあ、これが私の得意分野ですからね。:-)
SMTPではドメインは常にpunycode形式で運ばれますが、XMPPではネイティブなIDNが使われます。そのためSwitchyardは通過時に受信者のドメインをデコードし、Forgejoで[email protected]として登録したユーザーには、XMPP上でuser@マリウス.comとして届くのです。
Forgejoを超えて
この軽量なサービスはForgejo専用ではありません。SwitchyardはSMTPサーバーを指定できるものなら何にでも使え、ソフトウェア自体に何も変わったことを気づかせることなく、XMPPを話せるようにします。相手側で唯一調整すべきなのは、HTMLテンプレートの「Email address」フィールドを「JID」にラベル変更することです。これでユーザーは何を入力すべきか分かるようになります。Forgejoの場合は小さなテンプレートパッチで済み、自分で簡単に維持できます。上流がまず受け入れることのない完全なXMPP実装を維持し続けるのとは、負担がまったく違うのです。
欠点は、これでメールが使えなくなることです(今のところは!)。ForgejoがSwitchyardと話すようになると、送信されるものはすべてXMPPに流れ、メールアドレスを入力したユーザーには何も届かなくなります。この点はすでに修正に取り組んでおり、Switchyardがまず宛先ホストが実際にXMPPサーバーかどうかを確認し、そうでなければ設定しておいた通常のメールサーバーへフォールバックして転送するようにする予定です。こうすれば一つのプロトコル(SMTP)で入ってきたものを、利用可能なら優先するプロトコル(XMPP)へ振り分け、そうでなければフォールバック(SMTP)へ転送できます。簡単な話です。
これがクリーンでエレガントなエンジニアリングかといえば、もちろん違います。SMTPサーバーにXMPPクライアントを配線したもの(間にジョブキューを挟んでいます)で、動きますし、仕事は果たします。Switchyardによって、本来は上流にあるべきなのにほぼ確実に実現しない機能を手に入れられます。私にとっては、美しさで賞を取れるかもしれないけれど一生パッチのまま残り、Forgejoのリリースごとにマージとメンテナンスを強いられるクリーンな実装よりも、こちらの方がずっと価値があるのです。
注記: この実装は現在、私自身のGitプラットフォームであるtty.failで徹底的にテスト中であり、まだ一般の登録は開放していません。いずれかのプロジェクトに貢献したく、そのために早期アクセスを希望される場合は、コミュニティチャンネルに参加してお知らせください!
記事をランダムに読む