diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a04993d2a..815780cf6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,7 +25,7 @@ jobs: strategy: fail-fast: false matrix: - otp: ['20.0', '25.3', '26.1'] + otp: ['20.0', '25', '26', '27.0-rc1'] runs-on: ubuntu-20.04 services: redis: @@ -38,7 +38,7 @@ jobs: - uses: actions/checkout@v4 - name: Test shell scripts - if: matrix.otp == '25.3' + if: matrix.otp == '26' run: | shellcheck test/ejabberd_SUITE_data/gencerts.sh shellcheck tools/captcha.sh @@ -46,13 +46,12 @@ jobs: shellcheck -x ejabberdctl.template - name: Get specific Erlang/OTP - if: matrix.otp != '25.3' uses: erlef/setup-beam@v1 with: otp-version: ${{ matrix.otp }} - name: Get a compatible Rebar3 - if: matrix.otp <= '21.3' + if: matrix.otp < 24 run: | rm rebar3 wget https://github.com/processone/ejabberd/raw/21.12/rebar3 @@ -111,7 +110,7 @@ jobs: key: ${{matrix.otp}}-${{hashFiles('rebar.config')}} - name: Download test logs - if: matrix.otp == '25.3' && github.repository == 'processone/ejabberd' + if: matrix.otp == '26' && github.repository == 'processone/ejabberd' continue-on-error: true run: | mkdir -p _build/test @@ -191,7 +190,7 @@ jobs: find logs/ -name exunit.log -exec cat '{}' ';' - name: Send to coveralls - if: matrix.otp == '25.3' + if: matrix.otp == '26' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | @@ -301,7 +300,7 @@ jobs: - name: Upload CT logs if: failure() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: ejabberd-ct-logs-${{matrix.otp}} # diff --git a/.github/workflows/container.yml b/.github/workflows/container.yml index b9c655ffa..d9810d370 100644 --- a/.github/workflows/container.yml +++ b/.github/workflows/container.yml @@ -36,7 +36,7 @@ jobs: - name: Get erlang/OTP version for bootstrapping run: | - echo "OTP_VSN=$(awk '/^otp_vsn=/ {{gsub(/[^0-9.]/, ""); print}}' tools/make-binaries)" >> $GITHUB_ENV + echo "OTP_VSN=$(awk '/^otp_vsn=/ {{gsub(/[^0-9.rc-]/, ""); print}}' tools/make-binaries)" >> $GITHUB_ENV echo "ELIXIR_VSN=$(awk '/^elixir_vsn=/ {{gsub(/[^0-9.]/, ""); print}}' tools/make-binaries)" >> $GITHUB_ENV - name: Install prerequisites diff --git a/.github/workflows/runtime.yml b/.github/workflows/runtime.yml index 98d81564d..5835fc3a7 100644 --- a/.github/workflows/runtime.yml +++ b/.github/workflows/runtime.yml @@ -31,7 +31,7 @@ jobs: strategy: fail-fast: false matrix: - otp: ['20.3', '25.3', '26'] + otp: ['20', '25', '26', '27'] rebar: ['rebar', 'rebar3'] runs-on: ubuntu-22.04 container: @@ -42,7 +42,7 @@ jobs: - uses: actions/checkout@v4 - name: Get compatible Rebar binaries - if: matrix.otp < 23 + if: matrix.otp < 24 run: | rm rebar rm rebar3 @@ -54,14 +54,14 @@ jobs: - name: Prepare libraries run: | apt-get -qq update - apt-get purge -y libgd3 + apt-get purge -y libgd3 nginx apt-get -qq install libexpat1-dev libgd-dev libpam0g-dev \ libsqlite3-dev libwebp-dev libyaml-dev - name: Compile run: | ./autogen.sh - ./configure --with-rebar=${{ matrix.rebar }} \ + ./configure --with-rebar=./${{ matrix.rebar }} \ --prefix=/tmp/ejabberd \ --enable-all \ --disable-elixir \ @@ -149,7 +149,7 @@ jobs: strategy: fail-fast: false matrix: - otp: ['23.0', '25.3', '26'] + otp: ['23.0', '25', '26', '27.0-rc1'] elixir: ['1.13.4', '1.15.7', '1.16'] exclude: - otp: '23.0' @@ -158,6 +158,8 @@ jobs: elixir: '1.16' - otp: '26' elixir: '1.13.4' + - otp: '27.0-rc1' + elixir: '1.13.4' runs-on: ubuntu-20.04 steps: @@ -170,6 +172,16 @@ jobs: otp-version: ${{matrix.otp}} elixir-version: ${{matrix.elixir}} + - name: Get compatible Rebar binaries + if: matrix.otp < 24 + run: | + rm rebar + rm rebar3 + wget https://github.com/processone/ejabberd/raw/21.12/rebar + wget https://github.com/processone/ejabberd/raw/21.12/rebar3 + chmod +x rebar + chmod +x rebar3 + - name: Prepare libraries run: | sudo apt-get -qq update @@ -187,7 +199,7 @@ jobs: - name: Compile run: | ./autogen.sh - ./configure --with-rebar=rebar3 \ + ./configure --with-rebar=./rebar3 \ --prefix=/tmp/ejabberd \ --enable-all \ --disable-odbc @@ -272,7 +284,7 @@ jobs: strategy: fail-fast: false matrix: - otp: ['23.0', '25.3', '26'] + otp: ['23.0', '25', '26', '27.0-rc1'] elixir: ['1.13.4', '1.15.7', '1.16'] exclude: - otp: '23.0' @@ -281,6 +293,8 @@ jobs: elixir: '1.16' - otp: '26' elixir: '1.13.4' + - otp: '27.0-rc1' + elixir: '1.13.4' runs-on: ubuntu-20.04 steps: diff --git a/Makefile.in b/Makefile.in index c287cbbd9..acad927fd 100644 --- a/Makefile.in +++ b/Makefile.in @@ -2,13 +2,21 @@ #' definitions # -REBAR = @ESCRIPT@ @rebar@ +ESCRIPT = @ESCRIPT@ +REBAR = @rebar@ MIX = @rebar@ AWK = @AWK@ INSTALL = @INSTALL@ MKDIR_P = @MKDIR_P@ SED = @SED@ ERL = @ERL@ +EPMD = @EPMD@ +IEX = @IEX@ + +INSTALLUSER=@INSTALLUSER@ +INSTALLGROUP=@INSTALLGROUP@ + +REBAR_ENABLE_ELIXIR = @elixir@ prefix = @prefix@ exec_prefix = @exec_prefix@ @@ -81,7 +89,6 @@ LOGDIR = @localstatedir@/log/ejabberd #' install user # -INSTALLUSER=@INSTALLUSER@ # if no user was enabled, don't set privileges or ownership ifeq ($(INSTALLUSER),) O_USER= @@ -96,8 +103,8 @@ else CHOWN_OUTPUT=&1 INIT_USER=$(INSTALLUSER) endif + # if no group was enabled, don't set privileges or ownership -INSTALLGROUP=@INSTALLGROUP@ ifneq ($(INSTALLGROUP),) G_USER=-g $(INSTALLGROUP) endif @@ -114,8 +121,6 @@ REBAR_VER:=$(shell $(REBAR) --version | $(AWK) -F '[ .]' '/rebar / {print $$2}') REBAR_VER_318:=$(shell $(REBAR) --version | $(AWK) -F '[ .]' '/rebar / {print ($$2 == 3 && $$3 >= 18 ? 1 : 0)}') endif -REBAR_ENABLE_ELIXIR = @elixir@ - ifeq "$(REBAR_VER)" "6" REBAR=$(MIX) SKIPDEPS= @@ -133,9 +138,11 @@ ifeq "$(REBAR_VER)" "6" ELIXIR_LIBDIR=":$(ELIXIR_LIBDIR_RAW)" REBARREL=MIX_ENV=prod $(REBAR) release --overwrite REBARDEV=MIX_ENV=dev $(REBAR) release --overwrite - RELIVECMD=escript rel/relive.escript && MIX_ENV=dev RELIVE=true iex --name ejabberd@localhost -S mix run + RELIVECMD=$(ESCRIPT) rel/relive.escript && MIX_ENV=dev RELIVE=true $(IEX) --name ejabberd@localhost -S mix run REL_LIB_DIR = _build/dev/rel/ejabberd/lib COPY_REL_TARGET = dev + GET_DEPS_TRANSLATIONS=MIX_ENV=translations $(REBAR) $(GET_DEPS) + DEPSDIR_TRANSLATIONS=deps else ifeq ($(REBAR_ENABLE_ELIXIR),true) ELIXIR_LIBDIR_RAW=$(shell elixir -e "IO.puts(:filename.dirname(:code.lib_dir(:elixir)))" -e ":erlang.halt") @@ -160,10 +167,12 @@ endif XREFOPTIONS= CLEANARG=--all REBARREL=$(REBAR) as prod tar - REBARDEV=REBAR_PROFILE=dev $(REBAR) release + REBARDEV=$(REBAR) as dev release RELIVECMD=$(REBAR) relive REL_LIB_DIR = _build/dev/rel/ejabberd/lib COPY_REL_TARGET = dev + GET_DEPS_TRANSLATIONS=$(REBAR) as translations $(GET_DEPS) + DEPSDIR_TRANSLATIONS=_build/translations/lib else SKIPDEPS=skip_deps=true LISTDEPS=-q list-deps @@ -179,7 +188,7 @@ else REBARREL=$(REBAR) generate REBARDEV= RELIVECMD=@echo "Rebar2 detected... relive not supported.\ - \nTry: ./configure --with-rebar=./rebar3 ; make relive" + \nTry: ./configure --with-rebar=rebar3 ; make relive" REL_LIB_DIR = rel/ejabberd/lib COPY_REL_TARGET = rel endif @@ -223,7 +232,8 @@ options: all tools/opt_types.sh ejabberd_option $(EBINDIR) translations: - tools/prepare-tr.sh $(DEPSDIR) + $(GET_DEPS_TRANSLATIONS) + tools/prepare-tr.sh $(DEPSDIR_TRANSLATIONS) doap: tools/generate-doap.sh @@ -362,15 +372,15 @@ LOGS_DIR = ${relivedir}/logs # ejabberdctl.relive: - $(SED) -e "s*{{installuser}}*@INSTALLUSER@*g" \ + $(SED) -e "s*{{installuser}}*${INSTALLUSER}*g" \ -e "s*{{config_dir}}*${CONFIG_DIR}*g" \ -e "s*{{logs_dir}}*${LOGS_DIR}*g" \ -e "s*{{spool_dir}}*${SPOOL_DIR}*g" \ - -e "s*{{bindir}}*@bindir@*g" \ + -e "s*{{bindir}}*${BINDIR}*g" \ -e "s*{{libdir}}*${relivelibdir}${ELIXIR_LIBDIR}*g" \ - -e "s*{{iexpath}}*@IEX@*g" \ - -e "s*{{erl}}*@ERL@*g" \ - -e "s*{{epmd}}*@EPMD@*g" ejabberdctl.template \ + -e "s*{{iexpath}}*${IEX}*g" \ + -e "s*{{erl}}*${ERL}*g" \ + -e "s*{{epmd}}*${EPMD}*g" ejabberdctl.template \ > ejabberdctl.relive ejabberd.init: @@ -386,15 +396,15 @@ ejabberd.service: chmod 644 ejabberd.service ejabberdctl.example: vars.config - $(SED) -e "s*{{installuser}}*@INSTALLUSER@*g" \ + $(SED) -e "s*{{installuser}}*${INSTALLUSER}*g" \ -e "s*{{config_dir}}*${ETCDIR}*g" \ -e "s*{{logs_dir}}*${LOGDIR}*g" \ -e "s*{{spool_dir}}*${SPOOLDIR}*g" \ - -e "s*{{bindir}}*@bindir@*g" \ - -e "s*{{libdir}}*@libdir@${ELIXIR_LIBDIR}*g" \ - -e "s*{{iexpath}}*@IEX@*g" \ - -e "s*{{erl}}*@ERL@*g" \ - -e "s*{{epmd}}*@EPMD@*g" ejabberdctl.template \ + -e "s*{{bindir}}*${BINDIR}*g" \ + -e "s*{{libdir}}*${LIBDIR}${ELIXIR_LIBDIR}*g" \ + -e "s*{{iexpath}}*${IEX}*g" \ + -e "s*{{erl}}*${ERL}*g" \ + -e "s*{{epmd}}*${EPMD}*g" ejabberdctl.template \ > ejabberdctl.example scripts: ejabberd.init ejabberd.service ejabberdctl.example @@ -430,12 +440,12 @@ install-main: # # Spool directory $(INSTALL) -d -m 750 $(O_USER) $(DESTDIR)$(SPOOLDIR) - $(CHOWN_COMMAND) -R @INSTALLUSER@ $(DESTDIR)$(SPOOLDIR) >$(CHOWN_OUTPUT) + $(CHOWN_COMMAND) -R $(INSTALLUSER) $(DESTDIR)$(SPOOLDIR) >$(CHOWN_OUTPUT) chmod -R 750 $(DESTDIR)$(SPOOLDIR) # # Log directory $(INSTALL) -d -m 750 $(O_USER) $(DESTDIR)$(LOGDIR) - $(CHOWN_COMMAND) -R @INSTALLUSER@ $(DESTDIR)$(LOGDIR) >$(CHOWN_OUTPUT) + $(CHOWN_COMMAND) -R $(INSTALLUSER) $(DESTDIR)$(LOGDIR) >$(CHOWN_OUTPUT) chmod -R 750 $(DESTDIR)$(LOGDIR) # # Documentation @@ -642,7 +652,7 @@ help: @echo " doap Generate DOAP file" @echo " edoc Generate edoc documentation (unused)" @echo " options Generate ejabberd_option.erl" - @echo " translations Extract translation files (requires --enable-tools)" + @echo " translations Extract translation files" @echo " TAGS Generate tags file for text editors" @echo "" @echo " dialyzer Run Dialyzer static analyzer" diff --git a/configure.ac b/configure.ac index 065047cb9..f4c1a48ca 100644 --- a/configure.ac +++ b/configure.ac @@ -42,6 +42,7 @@ AC_PATH_TOOL(ERL, erl, , [${extra_erl_path}$PATH]) AC_PATH_TOOL(ERLC, erlc, , [${extra_erl_path}$PATH]) AC_PATH_TOOL(EPMD, epmd, , [${extra_erl_path}$PATH]) +AC_PATH_TOOL(REBAR, rebar, , [${extra_erl_path}$PATH]) AC_PATH_TOOL(REBAR3, rebar3, , [${extra_erl_path}$PATH]) AC_PATH_TOOL(ELIXIR, elixir, , [${extra_erl_path}$PATH]) AC_PATH_TOOL(IEX, iex, , [${extra_erl_path}$PATH]) @@ -58,6 +59,12 @@ if test "$rebar" = unconfigured; then rebar=$MIX fi fi +if test "x$rebar" = "xrebar" -a "x$REBAR" = "x" ; then + rebar="./rebar" +fi +if test "x$rebar" = "xrebar3" -a "x$REBAR3" = "x" ; then + rebar="./rebar3" +fi AC_ERLANG_NEED_ERL AC_ERLANG_NEED_ERLC @@ -256,7 +263,7 @@ AC_ARG_ENABLE(system_deps, esac],[if test "x$system_deps" = "x"; then system_deps=false; fi]) AC_ARG_ENABLE(tools, -[AS_HELP_STRING([--enable-tools],[build development tools: ejabberd-po, etop (default: no)])], +[AS_HELP_STRING([--enable-tools],[include debugging/development tools (default: no)])], [case "${enableval}" in yes) tools=true ;; no) tools=false ;; diff --git a/mix.exs b/mix.exs index f7e252533..28fa171e8 100644 --- a/mix.exs +++ b/mix.exs @@ -81,7 +81,9 @@ defmodule Ejabberd.MixProject do 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, :SYSTOOLS_APP_DEF_WITHOUT_OPTIONAL}]) ++ + if_version_below(~c"24", [{:d, :OTP_BELOW_24}]) ++ + if_version_below(~c"25", [{:d, :OTP_BELOW_25}]) defines = for {:d, value} <- result, do: {:d, value} result ++ [{:d, :ALL_DEFS, defines}] end @@ -132,11 +134,16 @@ defmodule Ejabberd.MixProject do 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"}}, {config(:redis), {:eredis, "~> 1.2.0"}}, {config(:sip), {:esip, "~> 1.0"}}, {config(:zlib), {:ezlib, "~> 1.0"}}, {if_version_below(~c"22", true), {:lager, "~> 3.9.1"}}, - {config(:lua), {:luerl, "~> 1.0"}}, + {config(:lua) and if_version_below(~c"27", true), + {:luerl, "~> 1.1.1"}}, + {config(:lua) and if_version_above(~c"26", true), + {:luerl, git: "https://github.com/processone/luerl", branch: "otp27"}}, {config(:mysql), {:p1_mysql, ">= 1.0.23" }}, {config(:pgsql), {:p1_pgsql, "~> 1.1"}}, {config(:sqlite), {:sqlite3, "~> 1.1"}}, @@ -146,8 +153,7 @@ defmodule Ejabberd.MixProject do defp cond_apps do for {:true, app} <- [{config(:stun), :stun}, - {config(:tools), :observer}, - {config(:tools), :runtime_tools}], do: + {config(:tools), :observer}], do: app end @@ -184,10 +190,14 @@ defmodule Ejabberd.MixProject do {:ok, path} -> path end - case :file.consult(filepath) do + 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 diff --git a/rebar b/rebar index 0b6871e70..d0f5766d6 100755 Binary files a/rebar and b/rebar differ diff --git a/rebar.config b/rebar.config index 4242f5d0b..de4ebf951 100644 --- a/rebar.config +++ b/rebar.config @@ -25,8 +25,6 @@ {deps, [{base64url, ".*", {git, "https://github.com/dvv/base64url", {tag, "1.0.1"}}}, {cache_tab, ".*", {git, "https://github.com/processone/cache_tab", {tag, "1.0.30"}}}, {eimp, ".*", {git, "https://github.com/processone/eimp", {tag, "1.0.22"}}}, - {if_var_true, tools, - {ejabberd_po, ".*", {git, "https://github.com/processone/ejabberd-po", {branch, "main"}}}}, {if_var_true, pam, {epam, ".*", {git, "https://github.com/processone/epam", {tag, "1.0.14"}}}}, {if_var_true, redis, @@ -50,14 +48,28 @@ {if_version_below, "22", {lager, ".*", {git, "https://github.com/erlang-lager/lager", {tag, "3.9.1"}}} }, + %% Lua, rebar, OTP 20: 1.0 git tag {if_var_true, lua, {if_not_rebar3, - {luerl, ".*", {git, "https://github.com/rvirding/luerl", {tag, "1.0"}}} - }}, + {if_version_below, "21", + {luerl, ".*", {git, "https://github.com/rvirding/luerl", {tag, "1.0"}}} + }}}, + %% Lua, rebar3, OTP 20: 1.0.0 hex package {if_var_true, lua, {if_rebar3, - {luerl, ".*", {git, "https://github.com/rvirding/luerl", {tag, "1.0.0"}}} - }}, + {if_version_below, "21", + {luerl, ".*", {git, "https://github.com/rvirding/luerl", {tag, "1.0.0"}}} + }}}, + %% Lua, any rebar, OTP 21-26: 1.1.1 git tag / 1.1.1 hex package + {if_var_true, lua, + {if_version_above, "20", {if_version_below, "27", + {luerl, ".*", {git, "https://github.com/rvirding/luerl", {tag, "1.1.1"}}} + }}}, + %% Lua, any rebar, OTP 27: temporary otp27 branch from fork + {if_var_true, lua, + {if_version_above, "26", + {luerl, ".*", {git, "https://github.com/processone/luerl", {branch, "otp27"}}} + }}, {mqtree, ".*", {git, "https://github.com/processone/mqtree", {tag, "1.0.15"}}}, {p1_acme, ".*", {git, "https://github.com/processone/p1_acme", {tag, "1.0.22"}}}, {if_var_true, mysql, @@ -131,6 +143,7 @@ {if_version_below, "23", {d, 'USE_OLD_PG2'}}, {if_version_below, "24", {d, 'COMPILER_REPORTS_ONLY_LINES'}}, {if_version_below, "24", {d, 'SYSTOOLS_APP_DEF_WITHOUT_OPTIONAL'}}, + {if_version_below, "24", {d, 'OTP_BELOW_24'}}, {if_version_below, "25", {d, 'OTP_BELOW_25'}}, {if_var_false, debug, no_debug_info}, {if_var_true, debug, debug_info}, @@ -196,7 +209,8 @@ {if_var_false, sqlite, "(\"sqlite3\":_/_)"}, {if_var_false, zlib, "(\"ezlib\":_/_)"}]}. -{xref_ignores, [{eldap_filter_yecc, return_error, 2} ]}. +{xref_ignores, [{eldap_filter_yecc, return_error, 2}, + {http_uri, encode, 1}]}. {eunit_compile_opts, [{i, "tools"}, {i, "include"}]}. @@ -283,6 +297,7 @@ {copy, "ejabberd.yml.example", "conf/ejabberd.yml.example"}, {copy, "test/ejabberd_SUITE_data/ca.pem", "conf/"}, {copy, "test/ejabberd_SUITE_data/cert.pem", "conf/"}]}]}]}, + {translations, [{deps, [{ejabberd_po, ".*", {git, "https://github.com/processone/ejabberd-po", {branch, "main"}}}]}]}, {test, [{erl_opts, [nowarn_export_all]}]}]}. {alias, [{relive, [{shell, "--apps ejabberd \ diff --git a/rebar.config.script b/rebar.config.script index 0304bf37c..bc1e060db 100644 --- a/rebar.config.script +++ b/rebar.config.script @@ -353,15 +353,11 @@ VarsApps = case file:consult(filename:join([filename:dirname(SCRIPT),"vars.confi ProcessRelx = fun(Relx, Deps) -> {value, {release, NameVersion, DefaultApps}, RelxTail} = lists:keytake(release, 1, Relx), - ProfileApps = case os:getenv("REBAR_PROFILE") of - "dev" -> [observer, runtime_tools, wx, debugger]; - _ -> [] - end, DepApps = lists:map(fun({DepName, _, _}) -> DepName; ({DepName, _}) -> DepName; (DepName) -> DepName end, Deps), - [{release, NameVersion, DefaultApps ++ VarsApps ++ ProfileApps ++ DepApps} | RelxTail] + [{release, NameVersion, DefaultApps ++ VarsApps ++ DepApps} | RelxTail] end, GithubConfig = case {os:getenv("GITHUB_ACTIONS"), os:getenv("GITHUB_TOKEN")} of diff --git a/rebar3 b/rebar3 index e903655b8..ab1c1369d 100755 Binary files a/rebar3 and b/rebar3 differ diff --git a/src/ejabberd.app.src.script b/src/ejabberd.app.src.script index 83a639095..089295804 100644 --- a/src/ejabberd.app.src.script +++ b/src/ejabberd.app.src.script @@ -6,10 +6,22 @@ {elixir, true} -> [elixir, iex, logger, mix]; _ -> [] end, - Tools = case lists:keyfind(tools, 1, Terms) of - {tools, true} -> [observer, runtime_tools]; % for `ejabberdctl etop` + + ProfileEnvironmentVariable = os:getenv("REBAR_PROFILE"), + AsProfiles = case lists:dropwhile(fun("as") -> false; (_) -> true end, + init:get_plain_arguments()) of + ["as", Profiles | _] -> string:split(Profiles, ","); + _ -> [] + end, + Terms2 = case lists:member("dev", [ProfileEnvironmentVariable | AsProfiles]) of + true -> lists:keystore(tools, 1, Terms, {tools, true}); + false -> Terms + end, + Tools = case lists:keyfind(tools, 1, Terms2) of + {tools, true} -> [observer]; _ -> [] end, + {[lists:keyfind(description, 1, Terms), lists:keyfind(vsn, 1, Terms), {env, [{enabled_backends, EBs}]} diff --git a/src/ejabberd_auth.erl b/src/ejabberd_auth.erl index 0034e6a92..594fc1bd7 100644 --- a/src/ejabberd_auth.erl +++ b/src/ejabberd_auth.erl @@ -425,7 +425,7 @@ user_exists(User, Server) -> false end. --spec user_exists_in_other_modules(atom(), binary(), binary()) -> boolean() | maybe. +-spec user_exists_in_other_modules(atom(), binary(), binary()) -> boolean() | maybe_exists. user_exists_in_other_modules(Module, User, Server) -> user_exists_in_other_modules_loop( auth_modules(Server) -- [Module], User, Server). @@ -439,7 +439,7 @@ user_exists_in_other_modules_loop([AuthModule | AuthModules], User, Server) -> {false, _} -> user_exists_in_other_modules_loop(AuthModules, User, Server); {{error, _}, _} -> - maybe + maybe_exists end. -spec which_users_exists(list({binary(), binary()})) -> list({binary(), binary()}). diff --git a/src/ejabberd_auth_anonymous.erl b/src/ejabberd_auth_anonymous.erl index 17289e6fb..9fb67047c 100644 --- a/src/ejabberd_auth_anonymous.erl +++ b/src/ejabberd_auth_anonymous.erl @@ -153,7 +153,7 @@ check_password(User, _AuthzId, Server, _Password) -> %% If user exists in other module, reject anonnymous authentication true -> false; %% If we are not sure whether the user exists in other module, reject anon auth - maybe -> false; + maybe_exists -> false; false -> login(User, Server) end}. diff --git a/src/ejabberd_sql.erl b/src/ejabberd_sql.erl index 8c192a784..58580c182 100644 --- a/src/ejabberd_sql.erl +++ b/src/ejabberd_sql.erl @@ -67,12 +67,22 @@ -export([connecting/2, connecting/3, session_established/2, session_established/3]). +-ifdef(OTP_RELEASE). + -if(?OTP_RELEASE >= 27). + -type(odbc_connection_reference() :: odbc:connection_reference()). + -else. + -type(odbc_connection_reference() :: pid()). + -endif. +-else. + -type(odbc_connection_reference() :: pid()). +-endif. + -include("logger.hrl"). -include("ejabberd_sql_pt.hrl"). -include("ejabberd_stacktrace.hrl"). -record(state, - {db_ref :: undefined | pid(), + {db_ref :: undefined | pid() | odbc_connection_reference(), db_type = odbc :: pgsql | mysql | sqlite | odbc | mssql, db_version :: undefined | non_neg_integer() | {non_neg_integer(), atom(), non_neg_integer()}, reconnect_count = 0 :: non_neg_integer(), @@ -1122,14 +1132,18 @@ mysql_to_odbc(ok) -> mysql_item_to_odbc(Columns, Recs) -> {selected, [element(2, Column) || Column <- Columns], Recs}. -to_odbc({selected, Columns, Recs}) -> - Rows = [lists:map( - fun(I) when is_integer(I) -> - integer_to_binary(I); - (B) -> - B - end, Row) || Row <- Recs], - {selected, [list_to_binary(C) || C <- Columns], Rows}; +to_odbc({selected, Columns, Rows}) -> + Rows2 = lists:map( + fun(Row) -> + Row2 = if is_tuple(Row) -> tuple_to_list(Row); + is_list(Row) -> Row + end, + lists:map( + fun(I) when is_integer(I) -> integer_to_binary(I); + (B) -> B + end, Row2) + end, Rows), + {selected, [list_to_binary(C) || C <- Columns], Rows2}; to_odbc({error, Reason}) when is_list(Reason) -> {error, list_to_binary(Reason)}; to_odbc(Res) -> diff --git a/src/misc.erl b/src/misc.erl index 6d3491a90..52a2fb15f 100644 --- a/src/misc.erl +++ b/src/misc.erl @@ -41,7 +41,7 @@ intersection/2, format_val/1, cancel_timer/1, unique_timestamp/0, is_mucsub_message/1, best_match/2, pmap/2, peach/2, format_exception/4, get_my_ipv4_address/0, get_my_ipv6_address/0, parse_ip_mask/1, - crypto_hmac/3, crypto_hmac/4, uri_parse/1, uri_parse/2, + crypto_hmac/3, crypto_hmac/4, uri_parse/1, uri_parse/2, uri_quote/1, match_ip_mask/3, format_hosts_list/1, format_cycle/1, delete_dir/1, semver_to_xxyy/1, logical_processors/0, get_mucsub_event_type/1]). @@ -97,6 +97,19 @@ uri_parse(URL, Protocols) -> end. -endif. +-ifdef(OTP_BELOW_25). +-ifdef(OTP_BELOW_24). +uri_quote(Data) -> + Data. +-else. +uri_quote(Data) -> + http_uri:encode(Data). +-endif. +-else. +uri_quote(Data) -> + uri_string:quote(Data). +-endif. + -ifdef(USE_OLD_CRYPTO_HMAC). crypto_hmac(Type, Key, Data) -> crypto:hmac(Type, Key, Data). crypto_hmac(Type, Key, Data, MacL) -> crypto:hmac(Type, Key, Data, MacL). diff --git a/src/mod_matrix_gw.erl b/src/mod_matrix_gw.erl index 6e5a3a94a..f44ed0317 100644 --- a/src/mod_matrix_gw.erl +++ b/src/mod_matrix_gw.erl @@ -5,7 +5,7 @@ %%% Created : 23 Apr 2022 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2022 ProcessOne +%%% ejabberd, Copyright (C) 2002-2024 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -24,7 +24,7 @@ %%%---------------------------------------------------------------------- -module(mod_matrix_gw). --if(?OTP_RELEASE >= 24). +-ifndef(OTP_BELOW_24). -author('alexey@process-one.net'). @@ -362,16 +362,6 @@ process([<<"federation">>, <<"v2">>, <<"send_join">>, RoomID, EventID], case get_id_domain_exn(Sender) of Origin -> case mod_matrix_gw_room:send_join(Host, Origin, RoomID, EventID, JSON) of - {error, room_not_found} -> - Res = #{<<"errcode">> => <<"M_NOT_FOUND">>, - <<"error">> => <<"Unknown room">>}, - {404, [{<<"Content-Type">>, <<"application/json;charset=UTF-8">>}], - jiffy:encode(Res)}; - {error, not_invited} -> - Res = #{<<"errcode">> => <<"M_FORBIDDEN">>, - <<"error">> => <<"You are not invited to this room">>}, - {403, [{<<"Content-Type">>, <<"application/json;charset=UTF-8">>}], - jiffy:encode(Res)}; {error, Error} when is_binary(Error) -> Res = #{<<"errcode">> => <<"M_BAD_REQUEST">>, <<"error">> => Error}, @@ -733,17 +723,27 @@ sign_json(Host, JSON) -> Msg = encode_canonical_json(JSON2), SignatureName = mod_matrix_gw_opt:matrix_domain(Host), KeyName = mod_matrix_gw_opt:key_name(Host), - {PubKey, PrivKey} = mod_matrix_gw_opt:key(Host), + {_PubKey, PrivKey} = mod_matrix_gw_opt:key(Host), KeyID = <<"ed25519:", KeyName/binary>>, - Sig = public_key:sign(Msg, ignored, {ed_pri, ed25519, PubKey, PrivKey}), + Sig = crypto:sign(eddsa, none, Msg, [PrivKey, ed25519]), Sig64 = base64_encode(Sig), Signatures2 = Signatures#{SignatureName => #{KeyID => Sig64}}, JSON#{<<"signatures">> => Signatures2}. +-spec send_request( + binary(), + get | post | put, + binary(), + [binary()], + [{binary(), binary()}], + none | #{atom() | binary() => jiffy:json_value()}, + [any()], + [any()]) -> {ok, any()} | {error, any()}. + send_request(Host, Method, MatrixServer, Path, Query, JSON, HTTPOptions, Options) -> URI1 = iolist_to_binary( - lists:map(fun(P) -> [$/, http_uri:encode(P)] end, Path)), + lists:map(fun(P) -> [$/, misc:uri_quote(P)] end, Path)), URI = case Query of [] -> URI1; @@ -751,13 +751,13 @@ send_request(Host, Method, MatrixServer, Path, Query, JSON, URI2 = str:join( lists:map( fun({K, V}) -> - [http_uri:encode(K), $=, http_uri:encode(V)] + iolist_to_binary( + [misc:uri_quote(K), $=, + misc:uri_quote(V)]) end, Query), $&), <> end, - % TODO {MHost, MPort} = mod_matrix_gw_s2s:get_matrix_host_port(Host, MatrixServer), - %{MHost, MPort} = {MatrixServer, 8008}, URL = <<"https://", MHost/binary, ":", (integer_to_binary(MPort))/binary, URI/binary>>, diff --git a/src/mod_matrix_gw_room.erl b/src/mod_matrix_gw_room.erl index a56c2496b..18be85b15 100644 --- a/src/mod_matrix_gw_room.erl +++ b/src/mod_matrix_gw_room.erl @@ -5,7 +5,7 @@ %%% Created : 1 May 2022 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2022 ProcessOne +%%% ejabberd, Copyright (C) 2002-2024 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -24,7 +24,7 @@ %%%------------------------------------------------------------------- -module(mod_matrix_gw_room). --if(?OTP_RELEASE >= 24). +-ifndef(OTP_BELOW_24). -behaviour(gen_statem). %% API @@ -67,12 +67,12 @@ sender :: binary(), prev_events :: [binary()], origin_server_ts :: integer(), - json :: jiffy:json_object(), + json :: #{atom() | binary() => jiffy:json_value()}, state_map}). -record(data, {host :: binary(), - local_user :: jid(), + local_user :: jid() | undefined, remote_user :: binary() | undefined, remote_servers = #{}, room_id :: binary(), @@ -347,14 +347,7 @@ send_join(Host, Origin, RoomID, EventID, JSON) -> %% process to initialize. %% @end %%-------------------------------------------------------------------- --spec init(Args :: term()) -> - {gen_statem:callback_mode(), - State :: term(), Data :: term()} | - {gen_statem:callback_mode(), - State :: term(), Data :: term(), - [gen_statem:action()] | gen_statem:action()} | - ignore | - {stop, Reason :: term()}. +-spec init(Args :: term()) -> gen_statem:init_result(term()). init([Host, RoomID]) -> mnesia:dirty_write( #matrix_room{room_id = RoomID, @@ -2038,12 +2031,12 @@ get_sender_power_level(EventID, Data) -> case {RoomVersion#room_version.implicit_room_creator, E} of {false, #event{type = ?ROOM_CREATE, state_key = <<"">>, - json = #event{json = #{<<"content">> := - #{<<"creator">> := Sender}}}}} -> + json = #{<<"content">> := + #{<<"creator">> := Sender}}}} -> 100; {true, #event{type = ?ROOM_CREATE, state_key = <<"">>, - json = #event{sender = Sender}}} -> + sender = Sender}} -> 100; _ -> Acc diff --git a/src/mod_matrix_gw_s2s.erl b/src/mod_matrix_gw_s2s.erl index b2479c7b8..fea528eef 100644 --- a/src/mod_matrix_gw_s2s.erl +++ b/src/mod_matrix_gw_s2s.erl @@ -5,7 +5,7 @@ %%% Created : 1 May 2022 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2022 ProcessOne +%%% ejabberd, Copyright (C) 2002-2024 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -23,7 +23,7 @@ %%% %%%------------------------------------------------------------------- -module(mod_matrix_gw_s2s). --if(?OTP_RELEASE >= 24). +-ifndef(OTP_BELOW_24). -behaviour(gen_statem). %% API @@ -216,14 +216,7 @@ check_signature(Host, JSON) -> %% process to initialize. %% @end %%-------------------------------------------------------------------- --spec init(Args :: term()) -> - {gen_statem:callback_mode(), - State :: term(), Data :: term()} | - {gen_statem:callback_mode(), - State :: term(), Data :: term(), - [gen_statem:action()] | gen_statem:action()} | - ignore | - {stop, Reason :: term()}. +-spec init(Args :: term()) -> gen_statem:init_result(term()). init([Host, MatrixServer]) -> mnesia:dirty_write( #matrix_s2s{to = MatrixServer, @@ -476,8 +469,9 @@ do_get_matrix_host_port(Data) -> "_matrix._tcp." ++ binary_to_list(MatrixServer), case inet_res:getbyname(SRVName, srv, 5000) of {ok, HostEntry} -> - case h_addr_list_to_host_ports( - HostEntry#hostent.h_addr_list) of + {hostent, _Name, _Aliases, _AddrType, _Len, + HAddrList} = HostEntry, + case h_addr_list_to_host_ports(HAddrList) of {ok, [{Host, Port} | _]} -> {list_to_binary(Host), Port}; _ -> @@ -531,7 +525,7 @@ check_signature(JSON, SignatureName, KeyID, VerifyKey) -> Signature = mod_matrix_gw:base64_decode(SSignature), JSON2 = maps:without([<<"signatures">>, <<"unsigned">>], JSON), Msg = mod_matrix_gw:encode_canonical_json(JSON2), - public_key:verify(Msg, ignored, Signature, {ed_pub, ed25519, VerifyKey}) + crypto:verify(eddsa, none, Msg, Signature, [VerifyKey, ed25519]) catch _:_ -> false diff --git a/src/mod_matrix_gw_sup.erl b/src/mod_matrix_gw_sup.erl index f29ea8b0c..b0c757a5c 100644 --- a/src/mod_matrix_gw_sup.erl +++ b/src/mod_matrix_gw_sup.erl @@ -2,7 +2,7 @@ %%% Created : 1 May 2022 by Alexey Shchepin %%% %%% -%%% ejabberd, Copyright (C) 2002-2022 ProcessOne +%%% ejabberd, Copyright (C) 2002-2024 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as @@ -20,7 +20,7 @@ %%% %%%---------------------------------------------------------------------- -module(mod_matrix_gw_sup). --if(?OTP_RELEASE >= 24). +-ifndef(OTP_BELOW_24). -behaviour(supervisor). %% API diff --git a/tools/make-binaries b/tools/make-binaries index c32771d28..d91cd8610 100755 --- a/tools/make-binaries +++ b/tools/make-binaries @@ -67,19 +67,19 @@ rel_vsn=$(git describe --tags | sed -e 's/-g.*//' -e 's/-/./' | tr -d '[:space:] mix_vsn=$(mix_version "$rel_vsn") crosstool_vsn='1.26.0' termcap_vsn='1.3.1' -expat_vsn='2.5.0' -zlib_vsn='1.3' +expat_vsn='2.6.0' +zlib_vsn='1.3.1' yaml_vsn='0.2.5' ssl_vsn='3.2.1' otp_vsn='26.2.2' elixir_vsn='1.16.1' pam_vsn='1.5.2' -png_vsn='1.6.40' -jpeg_vsn='9e' +png_vsn='1.6.42' +jpeg_vsn='9f' webp_vsn='1.3.2' gd_vsn='2.3.3' odbc_vsn='2.3.12' -sqlite_vsn='3430100' +sqlite_vsn='3450100' root_dir="${BUILD_DIR:-$HOME/build}" bootstrap_dir="$root_dir/bootstrap" ct_prefix_dir="$root_dir/x-tools" diff --git a/vars.config.in b/vars.config.in index 8bd4c9361..69e51f07a 100644 --- a/vars.config.in +++ b/vars.config.in @@ -24,7 +24,6 @@ {debug, @debug@}. {new_sql_schema, @new_sql_schema@}. -%% Ad-hoc directories with source files {tools, @tools@}. %% Dependencies