25
1
mirror of https://github.com/processone/ejabberd.git synced 2024-11-20 16:15:59 +01:00
xmpp.chapril.org-ejabberd/mix.exs
Holger Weiss 4723283896 ejabberd_c2s: Optionally allow unencrypted SASL2
XEP-0388 says: "SASL2 MUST only be used by Clients or offered by Servers
after TLS negotiation".  Therefore, we reject SASL2 negotiations over
unencrypted transports by default.  However, TLS might be terminated
outside of ejabberd.  Add the 'allow_unencrypted_sasl2' option to
support this use case.
2024-09-29 20:40:01 +02:00

450 lines
16 KiB
Elixir

defmodule Ejabberd.MixProject do
use Mix.Project
def project do
[app: :ejabberd,
source_url: "https://github.com/processone/ejabberd",
version: version(),
description: description(),
elixir: elixir_required_version(),
elixirc_paths: ["lib"],
compile_path: ".",
compilers: [:asn1, :yecc] ++ Mix.compilers(),
erlc_options: erlc_options(),
erlc_paths: ["asn1", "src"],
# Elixir tests are starting the part of ejabberd they need
aliases: [test: "test --no-start"],
start_permanent: Mix.env() == :prod,
language: :erlang,
dialyzer: dialyzer(),
releases: releases(),
package: package(),
docs: docs(),
deps: deps()]
end
def version do
case config(:vsn) do
:false -> "0.0.0" # ./configure wasn't run: vars.config not created
~c"0.0" -> "0.0.0" # the full git repository wasn't downloaded
~c"latest.0" -> "0.0.0" # running 'docker-ejabberd/ecs/build.sh latest'
[_, _, ?., _, _] = x ->
head = String.replace(:erlang.list_to_binary(x), ~r/\.0+([0-9])/, ".\\1")
"#{head}.0"
vsn -> String.replace(:erlang.list_to_binary(vsn), ~r/\.0+([0-9])/, ".\\1")
end
end
def description do
"""
Robust, Ubiquitous and Massively Scalable Messaging Platform (XMPP, MQTT, SIP Server)
"""
end
def application do
[mod: {:ejabberd_app, []},
extra_applications: [:inets, :kernel, :sasl, :ssl, :stdlib, :syntax_tools,
:logger, :mix]
++ cond_apps(),
included_applications: [:mnesia, :os_mon,
:cache_tab, :eimp, :mqtree, :p1_acme,
:p1_oauth2, :pkix]
++ cond_included_apps()]
end
defp dialyzer do
[
plt_add_apps: [
:mnesia, :odbc, :os_mon, :stdlib,
:eredis, :luerl,
:cache_tab, :eimp, :epam, :esip, :ezlib, :mqtree,
:p1_acme, :p1_mysql, :p1_oauth2, :p1_pgsql, :pkix,
:sqlite3, :stun, :xmpp],
]
end
defp if_version_above(ver, okResult) do
if :erlang.system_info(:otp_release) > ver do
okResult
else
[]
end
end
defp if_version_below(ver, okResult) do
if :erlang.system_info(:otp_release) < ver do
okResult
else
[]
end
end
defp if_type_exported(module, typeDef, okResult) do
try do
{:ok, concrete} = :dialyzer_utils.get_core_from_beam(:code.which(module))
{:ok, types} = :dialyzer_utils.get_record_and_type_info(concrete)
if Map.has_key?(types, typeDef) do
okResult
else
[]
end
rescue
_ -> []
end
end
defp erlc_options do
# Use our own includes + includes from all dependencies
includes = ["include", deps_include()]
result = [{:d, :ELIXIR_ENABLED}] ++
cond_options() ++
Enum.map(includes, fn (path) -> {:i, path} end) ++
if_version_above(~c"20", [{:d, :DEPRECATED_GET_STACKTRACE}]) ++
if_version_above(~c"20", [{:d, :HAVE_URI_STRING}]) ++
if_version_above(~c"20", [{:d, :HAVE_ERL_ERROR}]) ++
if_version_below(~c"21", [{:d, :USE_OLD_HTTP_URI}]) ++
if_version_below(~c"22", [{:d, :LAGER}]) ++
if_version_below(~c"21", [{:d, :NO_CUSTOMIZE_HOSTNAME_CHECK}]) ++
if_version_below(~c"23", [{:d, :USE_OLD_CRYPTO_HMAC}]) ++
if_version_below(~c"23", [{:d, :USE_OLD_PG2}]) ++
if_version_below(~c"24", [{:d, :COMPILER_REPORTS_ONLY_LINES}]) ++
if_version_below(~c"24", [{:d, :SYSTOOLS_APP_DEF_WITHOUT_OPTIONAL}]) ++
if_version_below(~c"24", [{:d, :OTP_BELOW_24}]) ++
if_version_below(~c"25", [{:d, :OTP_BELOW_25}]) ++
if_version_below(~c"26", [{:d, :OTP_BELOW_26}]) ++
if_version_below(~c"27", [{:d, :OTP_BELOW_27}]) ++
if_type_exported(:odbc, {:opaque, :connection_reference, 0}, [{:d, :ODBC_HAS_TYPES}])
defines = for {:d, value} <- result, do: {:d, value}
result ++ [{:d, :ALL_DEFS, defines}]
end
defp cond_options do
for {:true, option} <- [{config(:sip), {:d, :SIP}},
{config(:stun), {:d, :STUN}},
{config(:debug), :debug_info},
{not config(:debug), {:debug_info, false}},
{config(:roster_gateway_workaround), {:d, :ROSTER_GATEWAY_WORKAROUND}},
{config(:new_sql_schema), {:d, :NEW_SQL_SCHEMA}}
], do:
option
end
defp deps do
[{:cache_tab, "~> 1.0"},
{:dialyxir, "~> 1.2", only: [:test], runtime: false},
{:eimp, "~> 1.0"},
{:ex_doc, "~> 0.31", only: [:dev, :edoc], runtime: false},
{:fast_tls, git: "https://github.com/processone/fast_tls.git", ref: "75a08772f0ffddfed0441bfdc7e7f9a5adb3862f", override: true},
{:fast_xml, git: "https://github.com/processone/fast_xml.git", ref: "e7dc91310046831f436a03abf029587f0c2764f4", override: true},
{:fast_yaml, "~> 1.0"},
{:idna, "~> 6.0"},
{:mqtree, "~> 1.0"},
{:p1_acme, "~> 1.0"},
{:p1_oauth2, "~> 0.6"},
{:p1_utils, "~> 1.0"},
{:pkix, "~> 1.0"},
{:stringprep, ">= 1.0.26"},
{:xmpp, git: "https://github.com/processone/xmpp.git", ref: "ff0dd5390acc3c1ee8cd1c7e6dc60a0c3cb1d127", override: true},
{:yconf, "~> 1.0"}]
++ cond_deps()
end
defp deps_include() do
if Mix.Project.umbrella?() do
"../../deps"
else
case Mix.Project.deps_paths()[:ejabberd] do
nil -> "deps"
_ -> ".."
end
end
end
defp cond_deps do
for {:true, dep} <- [{config(:pam), {:epam, "~> 1.0"}},
{Mix.env() == :translations,
{:ejabberd_po, git: "https://github.com/processone/ejabberd-po.git"}},
{Mix.env() == :dev,
{:exsync, "~> 0.2", optional: true, runtime: false}},
{config(:redis), {:eredis, "~> 1.2.0"}},
{config(:sip), {:esip, "~> 1.0"}},
{config(:zlib), {:ezlib, "~> 1.0"}},
{if_version_above(~c"23", true), {:jose, "~> 1.11.10"}},
{if_version_below(~c"24", true), {:jose, "1.11.1", override: true}},
{if_version_below(~c"27", true), {:jiffy, "~> 1.1.1"}},
{if_version_below(~c"22", true), {:lager, "~> 3.9.1"}},
{config(:lua), {:luerl, "~> 1.2.0"}},
{config(:mysql), {:p1_mysql, ">= 1.0.24"}},
{config(:pgsql), {:p1_pgsql, ">= 1.1.26"}},
{config(:sqlite), {:sqlite3, "~> 1.1"}},
{config(:stun), {:stun, "~> 1.0"}}], do:
dep
end
defp cond_apps do
for {:true, app} <- [{config(:stun), :stun},
{if_version_below(~c"27", true), :jiffy},
{config(:tools), :observer}], do:
app
end
defp cond_included_apps do
for {:true, app} <- [{config(:pam), :epam},
{config(:lua), :luerl},
{config(:redis), :eredis},
{Mix.env() == :edoc, :ex_doc},
{Mix.env() == :test, :dialyxir},
{if_version_below(~c"22", true), :lager},
{config(:mysql), :p1_mysql},
{config(:sip), :esip},
{config(:odbc), :odbc},
{config(:pgsql), :p1_pgsql},
{config(:sqlite), :sqlite3}], do:
app
end
defp package do
[# These are the default files included in the package
files: ["include", "lib", "priv", "sql", "src",
"COPYING", "README.md",
"ejabberd.yml.example", "config/runtime.exs",
"mix.exs", "rebar.config", "rebar.config.script", "vars.config"],
maintainers: ["ProcessOne"],
licenses: ["GPL-2.0-or-later"],
links: %{"ejabberd.im" => "https://www.ejabberd.im",
"ejabberd Docs" => "http://docs.ejabberd.im",
"GitHub" => "https://github.com/processone/ejabberd",
"ProcessOne" => "http://www.process-one.net/"}]
end
defp vars do
filepath = case Application.fetch_env(:ejabberd, :vars_config_path) do
:error ->
"vars.config"
{:ok, path} ->
path
end
config2 = case :file.consult(filepath) do
{:ok,config} -> config
_ -> [stun: true, zlib: true]
end
case Mix.env() do
:dev -> List.keystore(config2, :tools, 0, {:tools, true})
_ -> config2
end
end
defp config(key) do
case vars()[key] do
nil -> false
value -> value
end
end
defp elixir_required_version do
case {Map.get(System.get_env(), "RELIVE", "false"),
MapSet.member?(MapSet.new(System.argv()), "release")}
do
{"true", _} ->
case Version.match?(System.version(), "~> 1.11") do
false ->
IO.puts("ERROR: To use 'make relive', Elixir 1.11.0 or higher is required.")
_ -> :ok
end
"~> 1.11"
{_, true} ->
case Version.match?(System.version(), "~> 1.10") do
false ->
IO.puts("ERROR: To build releases, Elixir 1.10.0 or higher is required.")
_ -> :ok
end
case Version.match?(System.version(), "< 1.11.4")
and :erlang.system_info(:otp_release) > ~c"23" do
true ->
IO.puts("ERROR: To build releases with Elixir lower than 1.11.4, Erlang/OTP lower than 24 is required.")
_ -> :ok
end
"~> 1.10"
_ ->
"~> 1.4"
end
end
defp releases do
maybe_tar = case Mix.env() do
:prod -> [:tar]
_ -> []
end
[
ejabberd: [
include_executables_for: [:unix],
# applications: [runtime_tools: :permanent]
steps: [&copy_extra_files/1, :assemble | maybe_tar]
]
]
end
defp copy_extra_files(release) do
assigns = [
version: version(),
rootdir: config(:rootdir),
installuser: config(:installuser),
libdir: config(:libdir),
sysconfdir: config(:sysconfdir),
localstatedir: config(:localstatedir),
config_dir: config(:config_dir),
logs_dir: config(:logs_dir),
spool_dir: config(:spool_dir),
vsn: version(),
iexpath: config(:iexpath),
erl: config(:erl),
epmd: config(:epmd),
bindir: Path.join([config(:release_dir), "releases", version()]),
release_dir: config(:release_dir),
erts_dir: config(:erts_dir),
erts_vsn: "erts-#{release.erts_version}"
]
ro = "rel/overlays"
File.rm_rf(ro)
# Elixir lower than 1.12.0 don't have System.shell
execute = fn(command) ->
case function_exported?(System, :shell, 1) do
true ->
System.shell(command, into: IO.stream())
false ->
:os.cmd(to_charlist(command))
end
end
# Mix/Elixir lower than 1.11.0 use config/releases.exs instead of runtime.exs
case Version.match?(System.version(), "~> 1.11") do
true ->
:ok
false ->
execute.("cp config/runtime.exs config/releases.exs")
end
execute.("sed -e 's|{{\\(\[_a-z\]*\\)}}|<%= @\\1 %>|g' ejabberdctl.template > ejabberdctl.example1")
Mix.Generator.copy_template("ejabberdctl.example1", "ejabberdctl.example2", assigns)
execute.("sed -e 's|{{\\(\[_a-z\]*\\)}}|<%= @\\1 %>|g' ejabberdctl.example2> ejabberdctl.example2a")
Mix.Generator.copy_template("ejabberdctl.example2a", "ejabberdctl.example2b", assigns)
execute.("sed -e 's|{{\\(\[_a-z\]*\\)}}|<%= @\\1 %>|g' ejabberdctl.example2b > ejabberdctl.example4")
execute.("sed -e 's|^ERLANG_OPTS=\"|ERLANG_OPTS=\"-boot ../releases/#{release.version}/start_clean -boot_var RELEASE_LIB ../lib |' ejabberdctl.example4 > ejabberdctl.example5")
execute.("sed -e 's|^INSTALLUSER=|ERL_OPTIONS=\"-setcookie \\$\\(cat \"\\${SCRIPT_DIR%/*}/releases/COOKIE\")\"\\nINSTALLUSER=|g' ejabberdctl.example5 > ejabberdctl.example6")
Mix.Generator.copy_template("ejabberdctl.example6", "#{ro}/bin/ejabberdctl", assigns)
File.chmod("#{ro}/bin/ejabberdctl", 0o755)
File.rm("ejabberdctl.example1")
File.rm("ejabberdctl.example2")
File.rm("ejabberdctl.example2a")
File.rm("ejabberdctl.example2b")
File.rm("ejabberdctl.example3")
File.rm("ejabberdctl.example4")
File.rm("ejabberdctl.example5")
File.rm("ejabberdctl.example6")
suffix = case Mix.env() do
:dev ->
Mix.Generator.copy_file("test/ejabberd_SUITE_data/ca.pem", "#{ro}/conf/ca.pem")
Mix.Generator.copy_file("test/ejabberd_SUITE_data/cert.pem", "#{ro}/conf/cert.pem")
".example"
_ -> ""
end
Mix.Generator.copy_file("ejabberd.yml.example", "#{ro}/conf/ejabberd.yml#{suffix}")
Mix.Generator.copy_file("ejabberdctl.cfg.example", "#{ro}/conf/ejabberdctl.cfg#{suffix}")
Mix.Generator.copy_file("inetrc", "#{ro}/conf/inetrc")
Enum.each(File.ls!("sql"),
fn x ->
Mix.Generator.copy_file("sql/#{x}", "#{ro}/lib/ejabberd-#{release.version}/priv/sql/#{x}")
end)
File.cp_r!("include", "#{ro}/lib/ejabberd-#{release.version}/include")
for {name, details} <- Map.to_list(release.applications) do
{_, is_otp_app} = List.keyfind(details, :otp_app?, 0)
{_, vsn} = List.keyfind(details, :vsn, 0)
{_, path} = List.keyfind(details, :path, 0)
source_dir = case is_otp_app do
:true -> "#{path}/include"
:false -> "deps/#{name}/include"
end
target_dir = "#{ro}/lib/#{name}-#{vsn}/include"
File.exists?(source_dir)
&& File.mkdir_p(target_dir)
&& File.cp_r!(source_dir, target_dir)
end
case Mix.env() do
:dev -> execute.("REL_DIR_TEMP=$PWD/rel/overlays/ rel/setup-dev.sh mix")
_ -> :ok
end
release
end
defp docs do
[
main: "readme",
logo: "_build/edoc/logo.png",
source_ref: "master",
extra_section: "", # No need for Pages section name, it's the only one
api_reference: false, # API section has just Elixir, hide it
filter_modules: "aaaaa", # Module section has just Elixir modules, hide them
extras: [
"README.md": [title: "Readme"],
"COMPILE.md": [title: "Compile and Install"],
"CONTAINER.md": [title: "Container Image"],
"CONTRIBUTING.md": [title: "Contributing"],
"CONTRIBUTORS.md": [title: "Contributors"],
"CODE_OF_CONDUCT.md": [title: "Code of Conduct"],
"CHANGELOG.md": [title: "ChangeLog"],
"COPYING": [title: "Copying License"],
"_build/edoc/docs.md": [title: "&xrArr; ejabberd Docs"]
],
groups_for_extras: [
"": Path.wildcard("*.md") ++ ["COPYING"],
"For more documentation": "_build/edoc/docs.md"
]
]
end
end
defmodule Mix.Tasks.Compile.Asn1 do
use Mix.Task
alias Mix.Compilers.Erlang
@recursive true
@manifest ".compile.asn1"
def run(args) do
{opts, _, _} = OptionParser.parse(args, switches: [force: :boolean])
project = Mix.Project.config()
source_paths = project[:asn1_paths] || ["asn1"]
dest_paths = project[:asn1_target] || ["src"]
mappings = Enum.zip(source_paths, dest_paths)
options = project[:asn1_options] || []
force = case opts[:force] do
:true -> [force: true]
_ -> [force: false]
end
Erlang.compile(manifest(), mappings, :asn1, :erl, force, fn
input, output ->
options = options ++ [:noobj, outdir: Erlang.to_erl_file(Path.dirname(output))]
case :asn1ct.compile(Erlang.to_erl_file(input), options) do
:ok -> {:ok, :done}
error -> error
end
end)
end
def manifests, do: [manifest()]
defp manifest, do: Path.join(Mix.Project.manifest_path(), @manifest)
def clean, do: Erlang.clean(manifest())
end