Teaching an Old Dog New Tricks: Forgejo + XMPP

Marius

늙은 개에게 새 재주 가르치기: Forgejo + XMPP

늙은 개에게 새 재주 가르치기: Forgejo + XMPP

최근 Codeberg를 떠나 직접 Forgejo 인스턴스를 운영하기로 했습니다. 초기 설정을 마치고 나니 직접 호스팅하는 포지는 내가 원하는 대로 만들 수 있는 포지라는 걸 깨달았습니다. 더 이상 다른 사람이 합리적이라고 정해 둔 기능에 만족할 필요가 없게 된 것입니다. 이제는 진정으로 내 것으로 만들고, Git 호스트가 해주길 늘 바라던 기능들을 켤 수 있습니다.

그중 첫 번째는 가입 절차에 관한 것입니다. 지금 Forgejo는 거의 모든 다른 포지와 마찬가지로 이메일 주소를 요구하고 인증 링크를 보내는데, 클릭된 링크가 여전히 상대방에 사람이 있다는 증거로 여겨지기 때문인 듯합니다. 하지만 저는 사람들이 차라리 XMPP JID로 가입하도록 하고 싶습니다. 한편으로는 링크를 받을 수 있는 이메일 주소가 자동 스팸에게는 더 이상 실질적인 장애물이 되지 못한 지 오래라 이메일 인증의 효과가 사람들이 생각하는 것보다 적기 때문이고, 다른 한편으로는 XMPP가 더 우수한 프로토콜이라 애초에 이메일보다는 XMPP로 사용자들이 찾아오길 바라기 때문입니다.

안타깝게도 ForgejoXMPP를 네이티브로 지원하지 않습니다. 게다가 Goshared 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.tomlForgejo를 검증할 자격 증명, 제출 포트를 위한 인증서, 그리고 모든 메시지를 보낼 단일 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가 원래 이메일로 보내던 모든 메시지가 대신 사용자가 이메일 필드에 입력한 JIDXMPP를 통해 발송됩니다. Switchyard는 IDN도 처리합니다. 아시다시피, 그게 제 전문 분야니까요. :-)

SMTP는 항상 도메인을 punycode 형태로 전달하는 반면, XMPP는 네이티브 IDN을 사용하므로 전달 과정에서 수신자 도메인을 디코딩하고, Forgejo에서 [email protected]으로 가입한 사용자는 XMPP에서 user@マリウス.com으로 메시지를 받게 됩니다.

Forgejo를 넘어서

이 가벼운 서비스는 Forgejo 전용이 아닙니다. SwitchyardSMTP 서버를 가리킬 수 있는 어떤 소프트웨어와도 동작하며, 해당 소프트웨어가 아무것도 바뀌었다는 걸 모르는 채 XMPP를 말하게 만듭니다. 반대편에서 해줘야 할 유일한 조정은 HTML 템플릿에서 “Email address” 필드의 라벨을 “JID”로 바꾸는 것으로, 사람들이 무엇을 입력해야 하는지 알 수 있게 하는 것입니다. Forgejo의 경우 이는 직접 쉽게 유지보수할 수 있는 작은 템플릿 패치입니다. 업스트림에서 거의 확실히 받아주지 않을 전체 XMPP 구현을 유지하는 것과는 전혀 다른 부담입니다.

단점은 이메일이 (일단은!) 사라진다는 것입니다. ForgejoSwitchyard와 대화하게 되면 보내는 모든 것이 XMPP로 가고, 이메일 주소를 입력한 사용자는 아무것도 받지 못합니다. 이미 이 문제를 해결하는 중인데, Switchyard가 먼저 대상 호스트가 실제 XMPP 서버인지 확인하고, 아닐 경우 설정해 둔 일반 메일 서버로 메시지를 전달하도록 하는 방식입니다. 이렇게 하면 하나의 프로토콜(SMTP)이 들어와서, 가능하면 선호하는 프로토콜(XMPP)로 분배되고, 그렇지 않으면 대체 프로토콜(SMTP)로 전달됩니다. 아주 간단하죠.

이게 깔끔하고 우아한 엔지니어링이냐고요? 전혀 아닙니다. SMTP 서버를 XMPP 클라이언트에 (중간에 작업 큐를 두고) 연결해 둔 것에 불과하지만, 동작하고 제 할 일은 합니다. Switchyard 덕분에 업스트림에 있어야 마땅하지만 거의 확실히 들어가지 않을 기능을 얻을 수 있었고, 제게는 깔끔해서 아름다움 대회에서나 상을 받을지 몰라도 평생 패치로 남을 구현보다 이게 더 가치 있습니다. Forgejo 릴리스마다 계속 머지하고 유지보수해야 할 패치 말입니다.

참고: 아직 저의 Git 플랫폼인 tty.fail에서 이 구현을 철저히 테스트하는 중이며, 외부 가입을 아직 열어두지 않았습니다. 프로젝트에 기여하고 싶어 미리 이용하고 싶으신 분은 커뮤니티 채널에 참여해서 알려주세요!

원문은 Marius님이 에 게재했습니다.

이 글은 muse-spark-1.2-contributor 모델을 사용해 번역했습니다.