Merge branch 'fix/emudhra-ca-trust' (#77) into release/2.11

This commit is contained in:
Lain Soykaf 2026-10-22 11:27:15 +04:00
commit fc91131892
No known key found for this signature in database
6 changed files with 100 additions and 4 deletions

View file

@ -1 +1 @@
Hackney and Finch now trust only the CAStore certificate bundle, which rejects the compromised eMudhra intermediate CAs Hackney, Finch, Mua and the Swoosh HTTP mail adapters now trust only the CAStore certificate bundle, which rejects the compromised eMudhra intermediate CAs

View file

@ -68,6 +68,21 @@ defmodule Pleroma.Emails.Mailer do
end end
defp parse_config(config) do defp parse_config(config) do
Swoosh.Mailer.parse_config(@otp_app, __MODULE__, @mailer_config, config) @otp_app
|> Swoosh.Mailer.parse_config(__MODULE__, @mailer_config, config)
|> put_mua_cacertfile()
end
@doc false
# Mua otherwise trusts the OS CA store. Keep a CA that the admin set.
def put_mua_cacertfile(config) do
ssl = Keyword.get(config, :ssl, [])
if config[:adapter] == Swoosh.Adapters.Mua and
not Keyword.has_key?(ssl, :cacertfile) and not Keyword.has_key?(ssl, :cacerts) do
Keyword.put(config, :ssl, [{:cacertfile, CAStore.file_path()} | ssl])
else
config
end
end end
end end

View file

@ -46,6 +46,24 @@ defmodule Pleroma.HTTP.AdapterHelper do
|> adapter_helper().options(uri) |> adapter_helper().options(uri)
end end
@doc """
The configured Tesla adapter with TLS options, for clients that do not go
through `Pleroma.HTTP`.
"""
@spec tesla_adapter() :: module() | {module(), keyword()}
def tesla_adapter do
case adapter() do
Tesla.Adapter.Hackney ->
{Tesla.Adapter.Hackney, Pleroma.HTTP.TLS.put_hackney_ssl_options([])}
Tesla.Adapter.Gun ->
{Tesla.Adapter.Gun, certificates_verification: true}
adapter ->
adapter
end
end
defp adapter, do: Application.get_env(:tesla, :adapter) defp adapter, do: Application.get_env(:tesla, :adapter)
defp adapter_helper do defp adapter_helper do

View file

@ -160,7 +160,7 @@ defmodule Pleroma.Search.QdrantSearch.OpenAIClient do
end end
defp client do defp client do
Tesla.client(middleware()) Tesla.client(middleware(), Pleroma.HTTP.AdapterHelper.tesla_adapter())
end end
defp middleware do defp middleware do
@ -191,7 +191,7 @@ defmodule Pleroma.Search.QdrantSearch.QdrantClient do
end end
defp client do defp client do
Tesla.client(middleware()) Tesla.client(middleware(), Pleroma.HTTP.AdapterHelper.tesla_adapter())
end end
defp middleware do defp middleware do

View file

@ -61,4 +61,33 @@ defmodule Pleroma.Emails.MailerTest do
assert hackney_options[:ssl_options] == assert hackney_options[:ssl_options] ==
Pleroma.HTTP.TLS.ssl_options() Pleroma.HTTP.TLS.ssl_options()
end end
describe "put_mua_cacertfile/1" do
test "makes Mua trust the CAStore bundle" do
config = Mailer.put_mua_cacertfile(adapter: Swoosh.Adapters.Mua, relay: "mail.example.com")
assert config[:ssl] == [cacertfile: CAStore.file_path()]
assert config[:relay] == "mail.example.com"
end
test "keeps other ssl options" do
config = Mailer.put_mua_cacertfile(adapter: Swoosh.Adapters.Mua, ssl: [depth: 3])
assert config[:ssl] == [cacertfile: CAStore.file_path(), depth: 3]
end
test "keeps a CA that the admin set" do
config = [adapter: Swoosh.Adapters.Mua, ssl: [cacertfile: "/etc/ssl/smtp.pem"]]
assert Mailer.put_mua_cacertfile(config) == config
config = [adapter: Swoosh.Adapters.Mua, ssl: [cacerts: []]]
assert Mailer.put_mua_cacertfile(config) == config
end
test "leaves other adapters alone" do
config = [adapter: Swoosh.Adapters.SMTP, relay: "mail.example.com"]
assert Mailer.put_mua_cacertfile(config) == config
end
end
end end

View file

@ -0,0 +1,34 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.HTTP.AdapterHelper.TeslaAdapterTest do
use ExUnit.Case, async: false
alias Pleroma.HTTP.AdapterHelper
alias Pleroma.HTTP.TLS
setup do
adapter = Application.get_env(:tesla, :adapter)
on_exit(fn -> Application.put_env(:tesla, :adapter, adapter) end)
end
test "adds the TLS options to Hackney" do
Application.put_env(:tesla, :adapter, Tesla.Adapter.Hackney)
assert AdapterHelper.tesla_adapter() ==
{Tesla.Adapter.Hackney, ssl_options: TLS.ssl_options()}
end
test "turns on certificate checks for Gun" do
Application.put_env(:tesla, :adapter, Tesla.Adapter.Gun)
assert AdapterHelper.tesla_adapter() == {Tesla.Adapter.Gun, certificates_verification: true}
end
test "keeps other adapters" do
Application.put_env(:tesla, :adapter, {Tesla.Adapter.Finch, name: MyFinch})
assert AdapterHelper.tesla_adapter() == {Tesla.Adapter.Finch, name: MyFinch}
end
end