Compare commits

...

18 Commits

Author SHA1 Message Date
Badlop cea1423efe Fix PIEFXIS export of user when password is scrammed (#2721) 2018-12-21 10:44:15 +01:00
Badlop 19e483f555 Search also for _jid when importing room from prosody (#2723) 2018-12-21 10:44:11 +01:00
Badlop 3edef215ff Parse persistent and archiving room options importing from prosody (#2720) 2018-12-21 10:44:06 +01:00
Christophe Romain 4fcfb38f2a Add hook on api call 2018-12-13 14:42:20 +01:00
Christophe Romain 3c390b0aed Update version for mix 2018-12-13 13:35:32 +01:00
Paweł Chmielowski 1803fb71a4 Update changelog 2018-12-13 12:06:44 +01:00
Paweł Chmielowski 7e328196f2 Add code for handling deprecations of get_stacktrace() 2018-12-13 11:50:34 +01:00
Evgeny Khramtsov ebf04fa40f Add HTTP listener on port 5280 for admin web interface 2018-12-13 11:49:52 +01:00
Holger Weiss 173d364fb7 mod_roster: Don't set version to "not_found"
Don't include a "ver" attribute with roster pushes if no roster version
is available.
2018-12-13 11:49:21 +01:00
Badlop c1c0d2ba12 When unknown roster version, return an acceptable version ID binary (#2709) 2018-12-13 11:49:17 +01:00
Evgeny Khramtsov 599f112244 Fix (un)setting of priority 2018-12-13 11:48:58 +01:00
Evgeny Khramtsov 44dfc108ca Don't lose carbons on presence change or session resumption 2018-12-13 11:48:48 +01:00
Paweł Chmielowski 52784e7dcf Add CHANGELOG.md file 2018-12-13 11:48:29 +01:00
Paweł Chmielowski 3e99749dbd Normalize hostname when processing host_config 2018-12-13 11:48:22 +01:00
Paweł Chmielowski 65b2f48ba9 Bump version of xmpp in mix.lock 2018-12-13 11:48:16 +01:00
Paweł Chmielowski 5d001743ab Start fast_tls before pkix 2018-12-13 11:48:12 +01:00
Paweł Chmielowski 0aa4e8358e Bump xmpp dep 2018-12-13 11:48:07 +01:00
Holger Weiss 693b8af611 configure.ac: Bump required Erlang/OTP version 2018-12-13 11:48:02 +01:00
30 changed files with 310 additions and 209 deletions

18
CHANGELOG.md Normal file
View File

@ -0,0 +1,18 @@
# Version NEXT
*
# Version 18.12.1
* Fix compilation with rebar3 by updating xmpp dependency
* Fix issue with ordering of pkix and fast_tls startup
* Fix loosing info about enabling carbons after resuming old session
* Re-enable port 5280 in default config
* Don't add ver attribute to roster result when roster versioning is not enabled
# Version 18.12
* MAM data store compression
* Proxy protocol support (http://www.haproxy.org/download/1.8/doc/proxy-protocol.txt)
* MUC Self-Ping optimization (XEP-0410)
* Bookmarks conversion (XEP-0411)

View File

@ -3,7 +3,7 @@
AC_PREREQ(2.53)
AC_INIT(ejabberd, m4_esyscmd([echo `git describe --tags 2>/dev/null || echo 0.0` | sed 's/-g.*//;s/-/./' | tr -d '\012']), [ejabberd@process-one.net], [ejabberd])
REQUIRE_ERLANG_MIN="6.4 (Erlang/OTP 17.5)"
REQUIRE_ERLANG_MIN="8.0 (Erlang/OTP 19.0)"
REQUIRE_ERLANG_MAX="100.0.0 (No Max)"
AC_CONFIG_MACRO_DIR([m4])

View File

@ -65,6 +65,11 @@ listen:
web_admin: true
captcha: true
tls: true
-
port: 5280
ip: "::"
module: ejabberd_http
web_admin: true
s2s_use_starttls: optional

View File

@ -0,0 +1,27 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2018 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
%%% published by the Free Software Foundation; either version 2 of the
%%% License, or (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License along
%%% with this program; if not, write to the Free Software Foundation, Inc.,
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
%%%
%%%----------------------------------------------------------------------
-ifdef(DEPRECATED_GET_STACKTRACE).
-define(EX_RULE(Class, Reason, Stack), Class:Reason:Stack).
-define(EX_STACK(Stack), Stack).
-else.
-define(EX_RULE(Class, Reason, _), Class:Reason).
-define(EX_STACK(_), erlang:get_stacktrace()).
-endif.

11
mix.exs
View File

@ -3,7 +3,7 @@ defmodule Ejabberd.Mixfile do
def project do
[app: :ejabberd,
version: "18.12.0",
version: "18.12.1",
description: description(),
elixir: "~> 1.4",
elixirc_paths: ["lib"],
@ -42,10 +42,19 @@ defmodule Ejabberd.Mixfile do
end
end
defp if_version_above(ver, okResult) do
if :erlang.system_info(:otp_release) > ver do
okResult
else
[]
end
end
defp erlc_options do
# Use our own includes + includes from all dependencies
includes = ["include"] ++ deps_include(["fast_xml", "xmpp", "p1_utils"])
[:debug_info, {:d, :ELIXIR_ENABLED}] ++ cond_options() ++ Enum.map(includes, fn(path) -> {:i, path} end) ++
if_version_above('20', [{:d, :DEPRECATED_GET_STACKTRACE}]) ++
if_function_exported(:crypto, :strong_rand_bytes, 1, [{:d, :STRONG_RAND_BYTES}]) ++
if_function_exported(:rand, :uniform, 1, [{:d, :RAND_UNIFORM}]) ++
if_function_exported(:gb_sets, :iterator_from, 2, [{:d, :GB_SETS_ITERATOR_FROM}]) ++

View File

@ -35,5 +35,5 @@
"sqlite3": {:hex, :sqlite3, "1.1.6", "4ea71af0b45908b5f02c9b09e4c87177039ef404f20accb35049cd8924cc417c", [:rebar3], [], "hexpm"},
"stringprep": {:hex, :stringprep, "1.0.14", "230a2d1c576bba168749d653fd6681166d02431ef07161a918444f3edb478ad0", [:rebar3], [{:p1_utils, "1.0.13", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
"stun": {:hex, :stun, "1.0.26", "87b05229d0519f0db5c6b67b5c25ed3b79766beb96eba83d29bde4cae9e702e4", [:rebar3], [{:fast_tls, "1.0.26", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.13", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
"xmpp": {:hex, :xmpp, "1.2.7", "79bbe73f4172c8a4ea3cf8ae81c85f395cc651aed446b4d2646f7e9f55e12d74", [:rebar3], [{:ezlib, "1.0.4", [hex: :ezlib, repo: "hexpm", optional: false]}, {:fast_tls, "1.0.26", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:fast_xml, "1.1.34", [hex: :fast_xml, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.13", [hex: :p1_utils, repo: "hexpm", optional: false]}, {:stringprep, "1.0.14", [hex: :stringprep, repo: "hexpm", optional: false]}], "hexpm"},
"xmpp": {:hex, :xmpp, "1.2.8", "c506ea4c7e4b8d042654d54b080f4b6b4135c93658d7e156968a073c5b5f99a1", [:rebar3], [{:ezlib, "1.0.4", [hex: :ezlib, repo: "hexpm", optional: false]}, {:fast_tls, "1.0.26", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:fast_xml, "1.1.34", [hex: :fast_xml, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.13", [hex: :p1_utils, repo: "hexpm", optional: false]}, {:stringprep, "1.0.14", [hex: :stringprep, repo: "hexpm", optional: false]}], "hexpm"},
}

View File

@ -24,7 +24,7 @@
{fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.0.26"}}},
{stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.14"}}},
{fast_xml, ".*", {git, "https://github.com/processone/fast_xml", {tag, "1.1.34"}}},
{xmpp, ".*", {git, "https://github.com/processone/xmpp", {tag, "1.2.7"}}},
{xmpp, ".*", {git, "https://github.com/processone/xmpp", {tag, "1.2.8"}}},
{fast_yaml, ".*", {git, "https://github.com/processone/fast_yaml", {tag, "1.0.17"}}},
{jiffy, ".*", {git, "https://github.com/davisp/jiffy", {tag, "0.14.8"}}},
{p1_oauth2, ".*", {git, "https://github.com/processone/p1_oauth2", {tag, "0.6.3"}}},
@ -92,6 +92,7 @@
{if_var_true, debug, debug_info},
{if_var_true, sip, {d, 'SIP'}},
{if_var_true, stun, {d, 'STUN'}},
{if_version_above, "20", {d, 'DEPRECATED_GET_STACKTRACE'}},
{if_var_true, roster_gateway_workaround, {d, 'ROSTER_GATWAY_WORKAROUND'}},
{if_var_match, db_type, mssql, {d, 'mssql'}},
{if_var_true, elixir, {d, 'ELIXIR_ENABLED'}},

View File

@ -25,6 +25,7 @@
-include("ejabberd_commands.hrl").
-include("ejabberd_acme.hrl").
-include_lib("public_key/include/public_key.hrl").
-include("ejabberd_stacktrace.hrl").
-define(DEFAULT_CONFIG_CONTACT, <<"mailto:example-admin@example.com">>).
-define(DEFAULT_CONFIG_CA_URL, "https://acme-v01.api.letsencrypt.org").
@ -100,10 +101,10 @@ is_valid_domain_opt(DomainString) ->
end.
-spec is_valid_revoke_cert(string()) -> boolean().
is_valid_revoke_cert(DomainOrFile) ->
is_valid_revoke_cert(DomainOrFile) ->
lists:prefix("file:", DomainOrFile) orelse
lists:prefix("domain:", DomainOrFile).
%% Commands
get_commands_spec() ->
[#ejabberd_commands{name = get_certificates, tags = [acme],
@ -142,7 +143,7 @@ get_commands_spec() ->
%%
-spec get_certificates(domains_opt()) -> string() | {'error', _}.
get_certificates(Domains) ->
case is_valid_domain_opt(Domains) of
case is_valid_domain_opt(Domains) of
true ->
try
CAUrl = get_config_ca_url(),
@ -150,9 +151,8 @@ get_certificates(Domains) ->
catch
throw:Throw ->
Throw;
E:R ->
St = erlang:get_stacktrace(),
?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, St]),
?EX_RULE(E, R, St) ->
?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, ?EX_STACK(St)]),
{error, get_certificates}
end;
false ->
@ -171,7 +171,7 @@ retrieve_or_create_account(CAUrl) ->
case read_account_persistent() of
none ->
create_save_new_account(CAUrl);
{ok, AccId, CAUrl, PrivateKey} ->
{ok, AccId, PrivateKey};
{ok, _AccId, _, _PrivateKey} ->
@ -199,7 +199,7 @@ get_certificates2(CAUrl, PrivateKey, Hosts) ->
%% Format the result to send back to ejabberdctl
format_get_certificates_result(SavedCerts).
-spec format_get_certificates_result([{'ok', bitstring(), _} |
-spec format_get_certificates_result([{'ok', bitstring(), _} |
{'error', bitstring(), _}]) ->
string().
format_get_certificates_result(Certs) ->
@ -211,26 +211,26 @@ format_get_certificates_result(Certs) ->
case Cond of
true ->
Result = io_lib:format("Success:~n~s", [FormattedCerts]),
lists:flatten(Result);
lists:flatten(Result);
_ ->
Result = io_lib:format("Error with one or more certificates~n~s", [FormattedCerts]),
lists:flatten(Result)
end.
-spec format_get_certificate({'ok', bitstring(), _} |
-spec format_get_certificate({'ok', bitstring(), _} |
{'error', bitstring(), _}) ->
string().
format_get_certificate({ok, Domain, saved}) ->
format_get_certificate({ok, Domain, saved}) ->
io_lib:format(" Certificate for domain: \"~s\" acquired and saved", [Domain]);
format_get_certificate({ok, Domain, not_found}) ->
format_get_certificate({ok, Domain, not_found}) ->
io_lib:format(" Certificate for domain: \"~s\" not found, so it was not renewed", [Domain]);
format_get_certificate({ok, Domain, no_expire}) ->
io_lib:format(" Certificate for domain: \"~s\" is not close to expiring", [Domain]);
format_get_certificate({error, Domain, Reason}) ->
io_lib:format(" Error for domain: \"~s\", with reason: \'~s\'", [Domain, Reason]).
-spec get_certificate(url(), bitstring(), jose_jwk:key()) ->
{'ok', bitstring(), pem()} |
-spec get_certificate(url(), bitstring(), jose_jwk:key()) ->
{'ok', bitstring(), pem()} |
{'error', bitstring(), _}.
get_certificate(CAUrl, DomainName, PrivateKey) ->
try
@ -243,9 +243,8 @@ get_certificate(CAUrl, DomainName, PrivateKey) ->
catch
throw:Throw ->
Throw;
E:R ->
St = erlang:get_stacktrace(),
?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, St]),
?EX_RULE(E, R, St) ->
?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, ?EX_STACK(St)]),
{error, DomainName, get_certificate}
end.
@ -267,23 +266,23 @@ create_save_new_account(CAUrl) ->
%% TODO:
%% Find a way to ask the user if he accepts the TOS
-spec create_new_account(url(), bitstring(), jose_jwk:key()) -> {'ok', string()} |
-spec create_new_account(url(), bitstring(), jose_jwk:key()) -> {'ok', string()} |
no_return().
create_new_account(CAUrl, Contact, PrivateKey) ->
try
{ok, Dirs, Nonce0} = ejabberd_acme_comm:directory(CAUrl),
Req0 = [{ <<"contact">>, [Contact]}],
{ok, {TOS, Account}, Nonce1} =
{ok, {TOS, Account}, Nonce1} =
ejabberd_acme_comm:new_account(Dirs, PrivateKey, Req0, Nonce0),
{<<"id">>, AccIdInt} = lists:keyfind(<<"id">>, 1, Account),
AccId = integer_to_list(AccIdInt),
Req1 = [{ <<"agreement">>, list_to_bitstring(TOS)}],
{ok, _Account2, _Nonce2} =
{ok, _Account2, _Nonce2} =
ejabberd_acme_comm:update_account({CAUrl, AccId}, PrivateKey, Req1, Nonce1),
{ok, AccId}
catch
E:R ->
?ERROR_MSG("Error: ~p creating an account for contact: ~p",
?ERROR_MSG("Error: ~p creating an account for contact: ~p",
[{E,R}, Contact]),
throw({error,create_new_account})
end.
@ -298,7 +297,7 @@ create_new_authorization(CAUrl, DomainName, PrivateKey) ->
{[{<<"type">>, <<"dns">>},
{<<"value">>, DomainName}]}},
{<<"existing">>, <<"accept">>}],
{ok, {AuthzUrl, Authz}, Nonce1} =
{ok, {AuthzUrl, Authz}, Nonce1} =
ejabberd_acme_comm:new_authz(Dirs, PrivateKey, Req0, Nonce0),
{ok, AuthzId} = location_to_id(AuthzUrl),
@ -321,7 +320,7 @@ create_new_authorization(CAUrl, DomainName, PrivateKey) ->
acme_challenge:unregister_hooks(DomainName)
end.
-spec create_new_certificate(url(), {bitstring(), [bitstring()]}, jose_jwk:key()) ->
-spec create_new_certificate(url(), {bitstring(), [bitstring()]}, jose_jwk:key()) ->
{ok, bitstring(), pem()}.
create_new_certificate(CAUrl, {DomainName, AllSubDomains}, PrivateKey) ->
try
@ -338,7 +337,7 @@ create_new_certificate(CAUrl, {DomainName, AllSubDomains}, PrivateKey) ->
{ok, {IssuerCertLink, Certificate}, _Nonce1} =
ejabberd_acme_comm:new_cert(Dirs, PrivateKey, Req, Nonce0),
DecodedCert = public_key:pkix_decode_cert(list_to_binary(Certificate), plain),
DecodedCert = public_key:pkix_decode_cert(list_to_binary(Certificate), plain),
PemEntryCert = public_key:pem_entry_encode('Certificate', DecodedCert),
{ok, IssuerCert, _Nonce2} = ejabberd_acme_comm:get_issuer_cert(IssuerCertLink),
@ -351,7 +350,7 @@ create_new_certificate(CAUrl, {DomainName, AllSubDomains}, PrivateKey) ->
PemCertKey = public_key:pem_encode([PemEntryKey, PemEntryCert, PemEntryIssuerCert]),
{ok, DomainName, PemCertKey}
catch
catch
E:R ->
?ERROR_MSG("Error: ~p getting an authorization for domain: ~p~n",
[{E,R}, DomainName]),
@ -383,9 +382,8 @@ renew_certificates() ->
catch
throw:Throw ->
Throw;
E:R ->
St = erlang:get_stacktrace(),
?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, St]),
?EX_RULE(E, R, St) ->
?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, ?EX_STACK(St)]),
{error, get_certificates}
end.
@ -406,8 +404,8 @@ renew_certificates0(CAUrl) ->
%% Format the result to send back to ejabberdctl
format_get_certificates_result(SavedCerts).
-spec renew_certificate(url(), {bitstring(), data_cert()}, jose_jwk:key()) ->
{'ok', bitstring(), _} |
-spec renew_certificate(url(), {bitstring(), data_cert()}, jose_jwk:key()) ->
{'ok', bitstring(), _} |
{'error', bitstring(), _}.
renew_certificate(CAUrl, {DomainName, _} = Cert, PrivateKey) ->
case cert_to_expire(Cert) of
@ -449,9 +447,8 @@ list_certificates(Verbose) ->
catch
throw:Throw ->
Throw;
E:R ->
St = erlang:get_stacktrace(),
?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, St]),
?EX_RULE(E, R, St) ->
?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, ?EX_STACK(St)]),
{error, list_certificates}
end;
false ->
@ -492,34 +489,33 @@ format_certificate(DataCert, Verbose) ->
format_certificate_verbose(DomainName, SANs, NotAfter, PemCert)
end
catch
E:R ->
St = erlang:get_stacktrace(),
?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, St]),
?EX_RULE(E, R, St) ->
?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, ?EX_STACK(St)]),
fail_format_certificate(DomainName)
end.
-spec format_certificate_plain(bitstring(), [string()], {expired | ok, string()}, string())
-spec format_certificate_plain(bitstring(), [string()], {expired | ok, string()}, string())
-> string().
format_certificate_plain(DomainName, SANs, NotAfter, Path) ->
Result = lists:flatten(io_lib:format(
" Domain: ~s~n"
" Domain: ~s~n"
"~s"
" ~s~n"
" Path: ~s",
" ~s~n"
" Path: ~s",
[DomainName,
lists:flatten([io_lib:format(" SAN: ~s~n", [SAN]) || SAN <- SANs]),
format_validity(NotAfter), Path])),
Result.
-spec format_certificate_verbose(bitstring(), [string()], {expired | ok, string()}, bitstring())
-spec format_certificate_verbose(bitstring(), [string()], {expired | ok, string()}, bitstring())
-> string().
format_certificate_verbose(DomainName, SANs, NotAfter, PemCert) ->
Result = lists:flatten(io_lib:format(
" Domain: ~s~n"
"~s"
" ~s~n"
" Certificate In PEM format: ~n~s",
[DomainName,
"~s"
" ~s~n"
" Certificate In PEM format: ~n~s",
[DomainName,
lists:flatten([io_lib:format(" SAN: ~s~n", [SAN]) || SAN <- SANs]),
format_validity(NotAfter), PemCert])),
Result.
@ -533,8 +529,8 @@ format_validity({ok, NotAfter}) ->
-spec fail_format_certificate(bitstring()) -> string().
fail_format_certificate(DomainName) ->
Result = lists:flatten(io_lib:format(
" Domain: ~s~n"
" Failed to format Certificate",
" Domain: ~s~n"
" Failed to format Certificate",
[DomainName])),
Result.
@ -542,7 +538,7 @@ fail_format_certificate(DomainName) ->
get_commonName(#'Certificate'{tbsCertificate = TbsCertificate}) ->
#'TBSCertificate'{
subject = {rdnSequence, SubjectList}
} = TbsCertificate,
} = TbsCertificate,
%% TODO: Not the best way to find the commonName
ShallowSubjectList = [Attribute || [Attribute] <- SubjectList],
@ -560,9 +556,9 @@ get_notAfter(Certificate) ->
true -> "19" ++ [Y1,Y2];
_ -> "20" ++ [Y1,Y2]
end,
NotAfter = lists:flatten(io_lib:format("~s-~s-~s ~s:~s:~s",
NotAfter = lists:flatten(io_lib:format("~s-~s-~s ~s:~s:~s",
[YEAR, [MO1,MO2], [D1,D2],
[H1,H2], [MI1,MI2], [S1,S2]])),
[H1,H2], [MI1,MI2], [S1,S2]])),
case close_to_expire(UtcTime, 0) of
true ->
@ -577,7 +573,7 @@ get_subjectAltNames(#'Certificate'{tbsCertificate = TbsCertificate}) ->
extensions = Exts
} = TbsCertificate,
EncodedSANs = [Val || #'Extension'{extnID = Oid, extnValue = Val} <- Exts,
EncodedSANs = [Val || #'Extension'{extnID = Oid, extnValue = Val} <- Exts,
Oid =:= attribute_oid(subjectAltName)],
lists:flatmap(
@ -586,7 +582,7 @@ get_subjectAltNames(#'Certificate'{tbsCertificate = TbsCertificate}) ->
[Name || {dNSName, Name} <- SANs0]
end, EncodedSANs).
-spec get_utc_validity(#'Certificate'{}) -> string().
get_utc_validity(#'Certificate'{tbsCertificate = TbsCertificate}) ->
@ -618,18 +614,17 @@ revoke_certificates(DomainOrFile) ->
catch
throw:Throw ->
Throw;
E:R ->
St = erlang:get_stacktrace(),
?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, St]),
?EX_RULE(E, R, St) ->
?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, ?EX_STACK(St)]),
{error, revoke_certificate}
end.
end.
-spec revoke_certificate0(url(), string()) -> {ok, deleted}.
revoke_certificate0(CAUrl, DomainOrFile) ->
ParsedCert = parse_revoke_cert_argument(DomainOrFile),
revoke_certificate1(CAUrl, ParsedCert).
-spec revoke_certificate1(url(), {domain, bitstring()} | {file, file:filename()}) ->
-spec revoke_certificate1(url(), {domain, bitstring()} | {file, file:filename()}) ->
{ok, deleted}.
revoke_certificate1(CAUrl, {domain, Domain}) ->
case domain_certificate_exists(Domain) of
@ -650,7 +645,7 @@ revoke_certificate1(CAUrl, {file, File}) ->
?ERROR_MSG("Error: ~p reading pem certificate-key file: ~p", [Reason, File]),
throw({error, Reason})
end.
-spec revoke_certificate2(url(), pem()) -> ok.
revoke_certificate2(CAUrl, PemEncodedCert) ->
@ -676,10 +671,10 @@ prepare_certificate_revoke(PemEncodedCert) ->
DerCert = public_key:der_encode('Certificate', PemCert),
Base64Cert = base64url:encode(DerCert),
{ok, Key} = find_private_key_in_pem(PemEncodedCert),
{ok, Key} = find_private_key_in_pem(PemEncodedCert),
{Base64Cert, Key}.
-spec domain_certificate_exists(bitstring()) -> {bitstring(), data_cert()} | false.
-spec domain_certificate_exists(bitstring()) -> {bitstring(), data_cert()} | false.
domain_certificate_exists(Domain) ->
Certs = read_certificates_persistent(),
lists:keyfind(Domain, 1, Certs).
@ -693,7 +688,7 @@ domain_certificate_exists(Domain) ->
%% For now we accept only generating a key of
%% specific type for signing the csr
-spec make_csr(proplist(), [{dNSName, bitstring()}])
-spec make_csr(proplist(), [{dNSName, bitstring()}])
-> {binary(), jose_jwk:key()}.
make_csr(Attributes, SANs) ->
Key = generate_key(),
@ -749,9 +744,9 @@ extension(SANs) ->
extension_request(SANs) ->
#'AttributePKCS-10'{
type = ?'pkcs-9-at-extensionRequest',
values = [{'asn1_OPENTYPE',
values = [{'asn1_OPENTYPE',
public_key:der_encode(
'ExtensionRequest',
'ExtensionRequest',
[extension(SANs)])}]
}.
@ -918,7 +913,7 @@ find_private_key_in_pem(Pem) ->
JoseKey = jose_jwk:from_key(Key),
{ok, JoseKey}
end.
-spec find_private_key_in_pem1([public_key:pki_asn1_type()],
[public_key:pem_entry()]) ->
@ -948,10 +943,10 @@ private_key_types() ->
find_all_sub_domains(DomainName) ->
AllRoutes = ejabberd_router:get_all_routes(),
DomainLen = size(DomainName),
[Route || Route <- AllRoutes,
binary:longest_common_suffix([DomainName, Route])
[Route || Route <- AllRoutes,
binary:longest_common_suffix([DomainName, Route])
=:= DomainLen].
-spec is_error(_) -> boolean().
is_error({error, _}) -> true;
@ -981,13 +976,13 @@ data_get_account(Data) ->
end.
-spec data_set_account(acme_data(), {list(), url(), jose_jwk:key()}) -> acme_data().
data_set_account(Data, {AccId, CAUrl, PrivateKey}) ->
data_set_account(Data, {AccId, CAUrl, PrivateKey}) ->
NewAcc = {account, #data_acc{id = AccId, ca_url = CAUrl, key = PrivateKey}},
lists:keystore(account, 1, Data, NewAcc).
%%
%% Certificates
%%
%%
-spec data_get_certificates(acme_data()) -> data_certs().
data_get_certificates(Data) ->
@ -999,7 +994,7 @@ data_get_certificates(Data) ->
end.
-spec data_set_certificates(acme_data(), data_certs()) -> acme_data().
data_set_certificates(Data, NewCerts) ->
data_set_certificates(Data, NewCerts) ->
lists:keystore(certs, 1, Data, {certs, NewCerts}).
%% ATM we preserve one certificate for each domain
@ -1053,7 +1048,7 @@ write_persistent(Data) ->
{error, Reason} ->
?ERROR_MSG("Error: ~p writing acme data file", [Reason]),
throw({error, Reason})
end.
end.
-spec create_persistent() -> ok | no_return().
create_persistent() ->
@ -1069,7 +1064,7 @@ create_persistent() ->
{error, Reason} ->
?ERROR_MSG("Error: ~p creating acme data file", [Reason]),
throw({error, Reason})
end.
end.
-spec write_account_persistent({list(), url(), jose_jwk:key()}) -> ok | no_return().
write_account_persistent({AccId, CAUrl, PrivateKey}) ->
@ -1099,7 +1094,7 @@ remove_certificate_persistent(DataCert) ->
NewData = data_remove_certificate(Data, DataCert),
ok = write_persistent(NewData).
-spec save_certificate({ok, bitstring(), binary()} | {error, _, _}) ->
-spec save_certificate({ok, bitstring(), binary()} | {error, _, _}) ->
{ok, bitstring(), saved} | {error, bitstring(), _}.
save_certificate({error, _, _} = Error) ->
Error;
@ -1123,13 +1118,12 @@ save_certificate({ok, DomainName, Cert}) ->
catch
throw:Throw ->
Throw;
E:R ->
St = erlang:get_stacktrace(),
?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, St]),
?EX_RULE(E, R, St) ->
?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, ?EX_STACK(St)]),
{error, DomainName, saving}
end.
-spec save_renewed_certificate({ok, bitstring(), _} | {error, _, _}) ->
-spec save_renewed_certificate({ok, bitstring(), _} | {error, _, _}) ->
{ok, bitstring(), _} | {error, bitstring(), _}.
save_renewed_certificate({error, _, _} = Error) ->
Error;

View File

@ -152,10 +152,10 @@ start_apps() ->
crypto:start(),
ejabberd:start_app(sasl),
ejabberd:start_app(ssl),
ejabberd:start_app(pkix),
ejabberd:start_app(p1_utils),
ejabberd:start_app(fast_yaml),
ejabberd:start_app(fast_tls),
ejabberd:start_app(pkix),
ejabberd:start_app(xmpp),
ejabberd:start_app(cache_tab),
ejabberd:start_app(eimp).

View File

@ -708,13 +708,11 @@ process_presence_out(#{lserver := LServer, jid := JID,
end.
-spec process_self_presence(state(), presence()) -> state().
process_self_presence(#{ip := IP, conn := Conn, lserver := LServer,
auth_module := AuthMod, sid := SID,
process_self_presence(#{lserver := LServer, sid := SID,
user := U, server := S, resource := R} = State,
#presence{type = unavailable} = Pres) ->
Status = xmpp:get_text(Pres#presence.status),
Info = [{ip, IP}, {conn, Conn}, {auth_module, AuthMod}],
ejabberd_sm:unset_presence(SID, U, S, R, Status, Info),
ejabberd_sm:unset_presence(SID, U, S, R, Status),
{Pres1, State1} = ejabberd_hooks:run_fold(
c2s_self_presence, LServer, {Pres, State}, []),
State2 = broadcast_presence_unavailable(State1, Pres1),
@ -732,13 +730,11 @@ process_self_presence(#{lserver := LServer} = State,
process_self_presence(State, _Pres) ->
State.
-spec update_priority(state(), presence()) -> ok.
update_priority(#{ip := IP, conn := Conn, auth_module := AuthMod,
sid := SID, user := U, server := S, resource := R},
-spec update_priority(state(), presence()) -> ok | {error, notfound}.
update_priority(#{sid := SID, user := U, server := S, resource := R},
Pres) ->
Priority = get_priority_from_presence(Pres),
Info = [{ip, IP}, {conn, Conn}, {auth_module, AuthMod}],
ejabberd_sm:set_presence(SID, U, S, R, Priority, Pres, Info).
ejabberd_sm:set_presence(SID, U, S, R, Priority, Pres).
-spec broadcast_presence_unavailable(state(), presence()) -> state().
broadcast_presence_unavailable(#{jid := JID, pres_a := PresA} = State, Pres) ->

View File

@ -492,6 +492,7 @@ do_execute_command(Command, Arguments) ->
Module = Command#ejabberd_commands.module,
Function = Command#ejabberd_commands.function,
?DEBUG("Executing command ~p:~p with Args=~p", [Module, Function, Arguments]),
ejabberd_hooks:run(api_call, [Module, Function, Arguments]),
apply(Module, Function, Arguments).
-spec get_tags_commands() -> [{string(), [string()]}].

View File

@ -500,7 +500,8 @@ get_config_option_key(Name, Val) ->
maps_to_lists(IMap) ->
maps:fold(fun(Name, Map, Res) when Name == host_config orelse Name == append_host_config ->
[{Name, [{Host, maps_to_lists(SMap)} || {Host,SMap} <- maps:values(Map)]} | Res];
[{Name, [{jid:nameprep(Host), maps_to_lists(SMap)} ||
{Host,SMap} <- maps:values(Map)]} | Res];
(Name, Map, Res) when is_map(Map) ->
[{Name, maps:values(Map)} | Res];
(Name, Val, Res) ->
@ -513,8 +514,9 @@ merge_configs(Terms, ResMap) ->
New = lists:foldl(fun(SVal, OMap) ->
NVal = if Name == host_config orelse Name == append_host_config ->
{Host, Opts} = SVal,
{_, SubMap} = maps:get(Host, OMap, {Host, #{}}),
{Host, merge_configs(Opts, SubMap)};
HostNP = jid:nameprep(Host),
{_, SubMap} = maps:get(HostNP, OMap, {HostNP, #{}}),
{HostNP, merge_configs(Opts, SubMap)};
true ->
SVal
end,

View File

@ -59,6 +59,7 @@
-include("ejabberd_ctl.hrl").
-include("ejabberd_commands.hrl").
-include("logger.hrl").
-include("ejabberd_stacktrace.hrl").
-define(DEFAULT_VERSION, 1000000).
@ -327,9 +328,9 @@ try_call_command(Args, Auth, AccessCommands, Version) ->
catch
throw:Error ->
{io_lib:format("~p", [Error]), ?STATUS_ERROR};
A:Why ->
Stack = erlang:get_stacktrace(),
{io_lib:format("Problem '~p ~p' occurred executing the command.~nStacktrace: ~p", [A, Why, Stack]), ?STATUS_ERROR}
?EX_RULE(A, Why, Stack) ->
{io_lib:format("Problem '~p ~p' occurred executing the command.~nStacktrace: ~p",
[A, Why, ?EX_STACK(Stack)]), ?STATUS_ERROR}
end.
%% @spec (Args::[string()], Auth, AccessCommands) -> string() | integer() | {string(), integer()} | {error, ErrorType}

View File

@ -57,6 +57,7 @@
terminate/2]).
-include("logger.hrl").
-include("ejabberd_stacktrace.hrl").
-record(state, {}).
-type local_hook() :: { Seq :: integer(), Module :: atom(), Function :: atom()}.
@ -129,14 +130,14 @@ delete_dist(Hook, Node, Module, Function, Seq) ->
delete_dist(Hook, Host, Node, Module, Function, Seq) ->
gen_server:call(ejabberd_hooks, {delete, Hook, Host, Node, Module, Function, Seq}).
-spec delete_all_hooks() -> true.
-spec delete_all_hooks() -> true.
%% @doc Primarily for testing / instrumentation
delete_all_hooks() ->
gen_server:call(ejabberd_hooks, {delete_all}).
-spec get_handlers(atom(), binary() | global) -> [local_hook() | distributed_hook()].
%% @doc Returns currently set handler for hook name
%% @doc Returns currently set handler for hook name
get_handlers(Hookname, Host) ->
gen_server:call(ejabberd_hooks, {get_handlers, Hookname, Host}).
@ -264,7 +265,7 @@ handle_delete(Hook, Host, El) ->
ok;
[] ->
ok
end.
end.
%%----------------------------------------------------------------------
%% Func: handle_cast/2
@ -379,15 +380,11 @@ safe_apply(Hook, Module, Function, Args) ->
true ->
apply(Module, Function, Args)
end
catch E:R when E /= exit; R /= normal ->
St = get_stacktrace(),
catch ?EX_RULE(E, R, St) when E /= exit; R /= normal ->
?ERROR_MSG("Hook ~p crashed when running ~p:~p/~p:~n"
"** Reason = ~p~n"
"** Arguments = ~p",
[Hook, Module, Function, length(Args),
{E, R, St}, Args]),
{E, R, ?EX_STACK(St)}, Args]),
'EXIT'
end.
get_stacktrace() ->
[{Mod, Fun, Loc, Args} || {Mod, Fun, Args, Loc} <- erlang:get_stacktrace()].

View File

@ -48,6 +48,7 @@
-include("logger.hrl").
-include_lib("stdlib/include/ms_transform.hrl").
-include("xmpp.hrl").
-include("ejabberd_stacktrace.hrl").
-record(state, {}).
@ -70,10 +71,9 @@ start_link() ->
-spec route(stanza()) -> any().
route(Packet) ->
try do_route(Packet)
catch E:R ->
St = erlang:get_stacktrace(),
catch ?EX_RULE(E, R, St) ->
?ERROR_MSG("failed to route packet:~n~s~nReason = ~p",
[xmpp:pp(Packet), {E, {R, St}}])
[xmpp:pp(Packet), {E, {R, ?EX_STACK(St)}}])
end.
-spec route_iq(iq(), function()) -> ok.

View File

@ -43,6 +43,7 @@
-define(NEED_RESET, [local_content, type]).
-include("logger.hrl").
-include("ejabberd_stacktrace.hrl").
-record(state, {tables = #{} :: map(),
schema = [] :: [{atom(), [{atom(), any()}]}]}).
@ -385,8 +386,8 @@ do_transform(OldAttrs, Attrs, Old) ->
transform_fun(Module, Name) ->
fun(Obj) ->
try Module:transform(Obj)
catch E:R ->
StackTrace = erlang:get_stacktrace(),
catch ?EX_RULE(E, R, St) ->
StackTrace = ?EX_STACK(St),
?ERROR_MSG("Failed to transform Mnesia table ~s:~n"
"** Record: ~p~n"
"** Reason: ~p~n"

View File

@ -166,15 +166,10 @@ export_users([], _Server, _Fd) ->
export_user(User, Server, Fd) ->
Password = ejabberd_auth:get_password_s(User, Server),
LServer = jid:nameprep(Server),
PasswordFormat = ejabberd_auth:password_format(LServer),
Pass = case Password of
{_,_,_,_} ->
case PasswordFormat of
scram -> format_scram_password(Password);
_ -> <<"">>
end;
_ -> Password
end,
Pass = case ejabberd_auth:password_format(LServer) of
scram -> format_scram_password(Password);
_ -> Password
end,
Els = get_offline(User, Server) ++
get_vcard(User, Server) ++
get_privacy(User, Server) ++
@ -186,7 +181,8 @@ export_user(User, Server, Fd) ->
{<<"password">>, Pass}],
children = Els})).
format_scram_password({StoredKey, ServerKey, Salt, IterationCount}) ->
format_scram_password(#scram{storedkey = StoredKey, serverkey = ServerKey,
salt = Salt, iterationcount = IterationCount}) ->
StoredKeyB64 = base64:encode(StoredKey),
ServerKeyB64 = base64:encode(ServerKey),
SaltB64 = base64:encode(Salt),

View File

@ -50,6 +50,7 @@
-define(CALL_TIMEOUT, 60*1000). %% 60 seconds
-include("logger.hrl").
-include("ejabberd_stacktrace.hrl").
-record(state, {connection :: pid() | undefined,
num :: pos_integer(),
@ -106,9 +107,9 @@ multi(F) ->
{error, _} = Err -> Err;
Result -> get_result(Result)
end
catch E:R ->
catch ?EX_RULE(E, R, St) ->
erlang:erase(?TR_STACK),
erlang:raise(E, R, erlang:get_stacktrace())
erlang:raise(E, R, ?EX_STACK(St))
end;
_ ->
erlang:error(nested_transaction)

View File

@ -71,6 +71,7 @@
-include("logger.hrl").
-include("ejabberd_router.hrl").
-include("xmpp.hrl").
-include("ejabberd_stacktrace.hrl").
-callback init() -> any().
-callback register_route(binary(), binary(), local_hint(),
@ -90,10 +91,9 @@ start_link() ->
-spec route(stanza()) -> ok.
route(Packet) ->
try do_route(Packet)
catch E:R ->
St = erlang:get_stacktrace(),
catch ?EX_RULE(E, R, St) ->
?ERROR_MSG("failed to route packet:~n~s~nReason = ~p",
[xmpp:pp(Packet), {E, {R, St}}])
[xmpp:pp(Packet), {E, {R, ?EX_STACK(St)}}])
end.
-spec route(jid(), jid(), xmlel() | stanza()) -> ok.

View File

@ -32,6 +32,7 @@
-include("logger.hrl").
-include("ejabberd_sql_pt.hrl").
-include("ejabberd_router.hrl").
-include("ejabberd_stacktrace.hrl").
%%%===================================================================
%%% API
@ -121,12 +122,11 @@ row_to_route(Domain, {ServerHost, NodeS, PidS, LocalHintS} = Row) ->
local_hint = dec_local_hint(LocalHintS)}]
catch _:{bad_node, _} ->
[];
E:R ->
St = erlang:get_stacktrace(),
?EX_RULE(E, R, St) ->
?ERROR_MSG("failed to decode row from 'route' table:~n"
"Row = ~p~n"
"Domain = ~s~n"
"Reason = ~p",
[Row, Domain, {E, {R, St}}]),
[Row, Domain, {E, {R, ?EX_STACK(St)}}]),
[]
end.

View File

@ -55,12 +55,10 @@
transform_options/1, opt_type/1]).
-include("logger.hrl").
-include("xmpp.hrl").
-include("ejabberd_commands.hrl").
-include_lib("public_key/include/public_key.hrl").
-include("ejabberd_stacktrace.hrl").
-define(PKIXEXPLICIT, 'OTP-PUB-KEY').
@ -94,10 +92,9 @@ start_link() ->
route(Packet) ->
try do_route(Packet)
catch E:R ->
St = erlang:get_stacktrace(),
catch ?EX_RULE(E, R, St) ->
?ERROR_MSG("failed to route packet:~n~s~nReason = ~p",
[xmpp:pp(Packet), {E, {R, St}}])
[xmpp:pp(Packet), {E, {R, ?EX_STACK(St)}}])
end.
clean_temporarily_blocked_table() ->

View File

@ -47,8 +47,8 @@
disconnect_removed_user/2,
get_user_resources/2,
get_user_present_resources/2,
set_presence/7,
unset_presence/6,
set_presence/6,
unset_presence/5,
close_session_unset_presence/5,
dirty_get_sessions_list/0,
dirty_get_my_sessions_list/0,
@ -90,6 +90,7 @@
-include("ejabberd_commands.hrl").
-include("ejabberd_sm.hrl").
-include("ejabberd_stacktrace.hrl").
-callback init() -> ok | {error, any()}.
-callback set_session(#session{}) -> ok | {error, any()}.
@ -140,11 +141,10 @@ route(Packet) ->
?DEBUG("hook dropped stanza:~n~s", [xmpp:pp(Packet)]);
Packet1 ->
try do_route(Packet1), ok
catch E:R ->
St = erlang:get_stacktrace(),
catch ?EX_RULE(E, R, St) ->
?ERROR_MSG("failed to route packet:~n~s~nReason = ~p",
[xmpp:pp(Packet1),
{E, {R, St}}])
{E, {R, ?EX_STACK(St)}}])
end
end.
@ -307,26 +307,48 @@ del_user_info(User, Server, Resource, Key) ->
end.
-spec set_presence(sid(), binary(), binary(), binary(),
prio(), presence(), info()) -> ok.
prio(), presence()) -> ok | {error, notfound}.
set_presence(SID, User, Server, Resource, Priority,
Presence, Info) ->
set_session(SID, User, Server, Resource, Priority,
Info),
ejabberd_hooks:run(set_presence_hook,
jid:nameprep(Server),
[User, Server, Resource, Presence]).
set_presence(SID, User, Server, Resource, Priority, Presence) ->
LUser = jid:nodeprep(User),
LServer = jid:nameprep(Server),
LResource = jid:resourceprep(Resource),
Mod = get_sm_backend(LServer),
case get_sessions(Mod, LUser, LServer, LResource) of
[] -> {error, notfound};
Ss ->
case lists:keyfind(SID, #session.sid, Ss) of
#session{info = Info} ->
set_session(SID, User, Server, Resource, Priority, Info),
ejabberd_hooks:run(set_presence_hook,
LServer,
[User, Server, Resource, Presence]);
false ->
{error, notfound}
end
end.
-spec unset_presence(sid(), binary(), binary(),
binary(), binary(), info()) -> ok.
binary(), binary()) -> ok | {error, notfound}.
unset_presence(SID, User, Server, Resource, Status,
Info) ->
set_session(SID, User, Server, Resource, undefined,
Info),
ejabberd_hooks:run(unset_presence_hook,
jid:nameprep(Server),
[User, Server, Resource, Status]).
unset_presence(SID, User, Server, Resource, Status) ->
LUser = jid:nodeprep(User),
LServer = jid:nameprep(Server),
LResource = jid:resourceprep(Resource),
Mod = get_sm_backend(LServer),
case get_sessions(Mod, LUser, LServer, LResource) of
[] -> {error, notfound};
Ss ->
case lists:keyfind(SID, #session.sid, Ss) of
#session{info = Info} ->
set_session(SID, User, Server, Resource, undefined, Info),
ejabberd_hooks:run(unset_presence_hook,
LServer,
[User, Server, Resource, Status]);
false ->
{error, notfound}
end
end.
-spec close_session_unset_presence(sid(), binary(), binary(),
binary(), binary()) -> ok.

View File

@ -69,6 +69,7 @@
-include("logger.hrl").
-include("ejabberd_sql_pt.hrl").
-include("ejabberd_stacktrace.hrl").
-record(state,
{db_ref = self() :: pid(),
@ -516,24 +517,26 @@ outer_transaction(F, NRestarts, _Reason) ->
end,
sql_query_internal([<<"begin;">>]),
put(?NESTING_KEY, PreviousNestingLevel + 1),
Result = (catch F()),
put(?NESTING_KEY, PreviousNestingLevel),
case Result of
{aborted, Reason} when NRestarts > 0 ->
sql_query_internal([<<"rollback;">>]),
outer_transaction(F, NRestarts - 1, Reason);
{aborted, Reason} when NRestarts =:= 0 ->
?ERROR_MSG("SQL transaction restarts exceeded~n** "
"Restarts: ~p~n** Last abort reason: "
"~p~n** Stacktrace: ~p~n** When State "
"== ~p",
[?MAX_TRANSACTION_RESTARTS, Reason,
erlang:get_stacktrace(), get(?STATE_KEY)]),
sql_query_internal([<<"rollback;">>]),
{aborted, Reason};
{'EXIT', Reason} ->
sql_query_internal([<<"rollback;">>]), {aborted, Reason};
Res -> sql_query_internal([<<"commit;">>]), {atomic, Res}
try F() of
Res ->
sql_query_internal([<<"commit;">>]),
{atomic, Res}
catch
?EX_RULE(throw, {aborted, Reason}, _) when NRestarts > 0 ->
sql_query_internal([<<"rollback;">>]),
outer_transaction(F, NRestarts - 1, Reason);
?EX_RULE(throw, {aborted, Reason}, Stack) when NRestarts =:= 0 ->
?ERROR_MSG("SQL transaction restarts exceeded~n** "
"Restarts: ~p~n** Last abort reason: "
"~p~n** Stacktrace: ~p~n** When State "
"== ~p",
[?MAX_TRANSACTION_RESTARTS, Reason,
?EX_STACK(Stack), get(?STATE_KEY)]),
sql_query_internal([<<"rollback;">>]),
{aborted, Reason};
?EX_RULE(exit, Reason, _) ->
sql_query_internal([<<"rollback;">>]),
{aborted, Reason}
end.
execute_bloc(F) ->
@ -599,10 +602,9 @@ sql_query_internal(#sql_query{} = Query) ->
{error, <<"killed">>};
exit:{normal, _} ->
{error, <<"terminated unexpectedly">>};
Class:Reason ->
ST = erlang:get_stacktrace(),
?EX_RULE(Class, Reason, Stack) ->
?ERROR_MSG("Internal error while processing SQL query: ~p",
[{Class, Reason, ST}]),
[{Class, Reason, ?EX_STACK(Stack)}]),
{error, <<"internal error">>}
end,
check_error(Res, Query);
@ -737,12 +739,11 @@ sql_query_format_res({selected, _, Rows}, SQLQuery) ->
try
[(SQLQuery#sql_query.format_res)(Row)]
catch
Class:Reason ->
ST = erlang:get_stacktrace(),
?EX_RULE(Class, Reason, Stack) ->
?ERROR_MSG("Error while processing "
"SQL query result: ~p~n"
"row: ~p",
[{Class, Reason, ST}, Row]),
[{Class, Reason, ?EX_STACK(Stack)}, Row]),
[]
end
end, Rows),

View File

@ -40,6 +40,7 @@
-include("logger.hrl").
-include("xmpp.hrl").
-include("translate.hrl").
-include("ejabberd_stacktrace.hrl").
-type component() :: ejabberd_sm | ejabberd_local.
@ -113,10 +114,9 @@ process_iq(_Host, Module, Function, IQ) ->
ejabberd_router:route(ResIQ);
ignore ->
ok
catch E:R ->
St = erlang:get_stacktrace(),
catch ?EX_RULE(E, R, St) ->
?ERROR_MSG("failed to process iq:~n~s~nReason = ~p",
[xmpp:pp(IQ), {E, {R, St}}]),
[xmpp:pp(IQ), {E, {R, ?EX_STACK(St)}}]),
Txt = <<"Module failed to handle the query">>,
Err = xmpp:err_internal_server_error(Txt, IQ#iq.lang),
ejabberd_router:route_error(IQ, Err)

View File

@ -58,6 +58,7 @@
-include("logger.hrl").
-include_lib("stdlib/include/ms_transform.hrl").
-include("ejabberd_stacktrace.hrl").
-record(ejabberd_module,
{module_host = {undefined, <<"">>} :: {atom(), binary()},
@ -217,8 +218,8 @@ start_module(Host, Module, Opts0, Order, NeedValidation) ->
{ok, Pid} when is_pid(Pid) -> {ok, Pid};
Err -> erlang:error({bad_return, Module, Err})
end
catch Class:Reason ->
StackTrace = erlang:get_stacktrace(),
catch ?EX_RULE(Class, Reason, Stack) ->
StackTrace = ?EX_STACK(Stack),
ets:delete(ejabberd_modules, {Module, Host}),
ErrorText = format_module_error(
Module, start, 2,
@ -282,8 +283,8 @@ reload_module(Host, Module, NewOpts, OldOpts, Order) ->
{ok, Pid} when is_pid(Pid) -> {ok, Pid};
Err -> erlang:error({bad_return, Module, Err})
end
catch Class:Reason ->
StackTrace = erlang:get_stacktrace(),
catch ?EX_RULE(Class, Reason, Stack) ->
StackTrace = ?EX_STACK(Stack),
ErrorText = format_module_error(
Module, reload, 3,
NewOpts, Class, Reason,

View File

@ -38,6 +38,7 @@
iq_handler/1, disco_features/5,
is_carbon_copy/1, mod_opt_type/1, depends/2,
mod_options/1]).
-export([c2s_copy_session/2, c2s_session_opened/1, c2s_session_resumed/1]).
%% For debugging purposes
-export([list/2]).
@ -45,6 +46,7 @@
-include("xmpp.hrl").
-type direction() :: sent | received.
-type c2s_state() :: ejabberd_c2s:state().
-spec is_carbon_copy(stanza()) -> boolean().
is_carbon_copy(#message{meta = #{carbon_copy := true}}) ->
@ -57,6 +59,9 @@ start(Host, _Opts) ->
%% why priority 89: to define clearly that we must run BEFORE mod_logdb hook (90)
ejabberd_hooks:add(user_send_packet,Host, ?MODULE, user_send_packet, 89),
ejabberd_hooks:add(user_receive_packet,Host, ?MODULE, user_receive_packet, 89),
ejabberd_hooks:add(c2s_copy_session, Host, ?MODULE, c2s_copy_session, 50),
ejabberd_hooks:add(c2s_session_resumed, Host, ?MODULE, c2s_session_resumed, 50),
ejabberd_hooks:add(c2s_session_opened, Host, ?MODULE, c2s_session_opened, 50),
gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_CARBONS_2, ?MODULE, iq_handler).
stop(Host) ->
@ -64,7 +69,10 @@ stop(Host) ->
ejabberd_hooks:delete(disco_local_features, Host, ?MODULE, disco_features, 50),
%% why priority 89: to define clearly that we must run BEFORE mod_logdb hook (90)
ejabberd_hooks:delete(user_send_packet,Host, ?MODULE, user_send_packet, 89),
ejabberd_hooks:delete(user_receive_packet,Host, ?MODULE, user_receive_packet, 89).
ejabberd_hooks:delete(user_receive_packet,Host, ?MODULE, user_receive_packet, 89),
ejabberd_hooks:delete(c2s_copy_session, Host, ?MODULE, c2s_copy_session, 50),
ejabberd_hooks:delete(c2s_session_resumed, Host, ?MODULE, c2s_session_resumed, 50),
ejabberd_hooks:delete(c2s_session_opened, Host, ?MODULE, c2s_session_opened, 50).
reload(_Host, _NewOpts, _OldOpts) ->
ok.
@ -123,6 +131,29 @@ user_receive_packet({Packet, #{jid := JID} = C2SState}) ->
Pkt -> {Pkt, C2SState}
end.
-spec c2s_copy_session(c2s_state(), c2s_state()) -> c2s_state().
c2s_copy_session(State, #{user := U, server := S, resource := R}) ->
case ejabberd_sm:get_user_info(U, S, R) of
offline -> State;
Info ->
case lists:keyfind(carboncopy, 1, Info) of
{_, CC} -> State#{carboncopy => CC};
false -> State
end
end.
-spec c2s_session_resumed(c2s_state()) -> c2s_state().
c2s_session_resumed(#{user := U, server := S, resource := R,
carboncopy := CC} = State) ->
ejabberd_sm:set_user_info(U, S, R, carboncopy, CC),
maps:remove(carboncopy, State);
c2s_session_resumed(State) ->
State.
-spec c2s_session_opened(c2s_state()) -> c2s_state().
c2s_session_opened(State) ->
maps:remove(carboncopy, State).
% Modified from original version:
% - registered to the user_send_packet hook, to be called only once even for multicast
% - do not support "private" message mode, and do not modify the original packet in any way

View File

@ -80,6 +80,7 @@
-include("xmpp.hrl").
-include("logger.hrl").
-include("ejabberd_http.hrl").
-include("ejabberd_stacktrace.hrl").
-define(DEFAULT_API_VERSION, 0).
@ -192,9 +193,8 @@ process([Call], #request{method = 'POST', data = Data, ip = IPPort} = Req) ->
_:{error,{_,invalid_json}} = _Err ->
?DEBUG("Bad Request: ~p", [_Err]),
badrequest_response(<<"Invalid JSON input">>);
_:_Error ->
St = erlang:get_stacktrace(),
?DEBUG("Bad Request: ~p ~p", [_Error, St]),
?EX_RULE(_Class, _Error, Stack) ->
?DEBUG("Bad Request: ~p ~p", [_Error, ?EX_STACK(Stack)]),
badrequest_response()
end;
process([Call], #request{method = 'GET', q = Data, ip = {IP, _}} = Req) ->
@ -210,9 +210,8 @@ process([Call], #request{method = 'GET', q = Data, ip = {IP, _}} = Req) ->
%% TODO We need to refactor to remove redundant error return formatting
throw:{error, unknown_command} ->
json_format({404, 44, <<"Command not found.">>});
_:_Error ->
St = erlang:get_stacktrace(),
?DEBUG("Bad Request: ~p ~p", [_Error, St]),
?EX_RULE(_, _Error, Stack) ->
?DEBUG("Bad Request: ~p ~p", [_Error, ?EX_STACK(Stack)]),
badrequest_response()
end;
process([_Call], #request{method = 'OPTIONS', data = <<>>}) ->
@ -302,9 +301,8 @@ handle(Call, Auth, Args, Version) when is_atom(Call), is_list(Args) ->
{400, misc:atom_to_binary(Error)};
throw:Msg when is_list(Msg); is_binary(Msg) ->
{400, iolist_to_binary(Msg)};
_Error ->
St = erlang:get_stacktrace(),
?ERROR_MSG("REST API Error: ~p ~p", [_Error, St]),
?EX_RULE(Class, Error, Stack) ->
?ERROR_MSG("REST API Error: ~p:~p ~p", [Class, Error, ?EX_STACK(Stack)]),
{500, <<"internal_error">>}
end;
{error, Msg} ->

View File

@ -54,6 +54,7 @@
-include("xmpp.hrl").
-include("translate.hrl").
-include("mod_muc_room.hrl").
-include("ejabberd_stacktrace.hrl").
-define(MAX_USERS_DEFAULT_LIST,
[5, 10, 20, 30, 50, 100, 200, 500, 1000, 2000, 5000]).
@ -2765,7 +2766,7 @@ process_item_change(Item, SD, UJID) ->
maybe_send_affiliation(JID, A, SD1),
SD1
end
catch E:R ->
catch ?EX_RULE(E, R, St) ->
FromSuffix = case UJID of
#jid{} ->
JidString = jid:encode(UJID),
@ -2773,9 +2774,8 @@ process_item_change(Item, SD, UJID) ->
undefined ->
<<"">>
end,
St = erlang:get_stacktrace(),
?ERROR_MSG("failed to set item ~p~s: ~p",
[Item, FromSuffix, {E, {R, St}}]),
[Item, FromSuffix, {E, {R, ?EX_STACK(St)}}]),
{error, xmpp:err_internal_server_error()}
end.

View File

@ -53,14 +53,11 @@
depends/2]).
-include("logger.hrl").
-include("xmpp.hrl").
-include("mod_roster.hrl").
-include("ejabberd_http.hrl").
-include("ejabberd_web_admin.hrl").
-include("ejabberd_stacktrace.hrl").
-define(ROSTER_CACHE, roster_cache).
-define(ROSTER_ITEM_CACHE, roster_item_cache).
@ -231,7 +228,7 @@ roster_version(LServer, LUser) ->
case roster_version_on_db(LServer) of
true ->
case read_roster_version(LUser, LServer) of
error -> not_found;
error -> undefined;
{ok, V} -> V
end;
false ->
@ -320,10 +317,9 @@ process_iq_get(#iq{to = To, lang = Lang,
#roster_query{items = Items,
ver = Version}
end)
catch E:R ->
St = erlang:get_stacktrace(),
catch ?EX_RULE(E, R, St) ->
?ERROR_MSG("failed to process roster get for ~s: ~p",
[jid:encode(To), {E, {R, St}}]),
[jid:encode(To), {E, {R, ?EX_STACK(St)}}]),
Txt = <<"Roster module has failed">>,
xmpp:make_error(IQ, xmpp:err_internal_server_error(Txt, Lang))
end.

View File

@ -189,7 +189,11 @@ convert_data(Host, "vcard", User, [Data]) ->
ok
end;
convert_data(_Host, "config", _User, [Data]) ->
RoomJID = jid:decode(proplists:get_value(<<"jid">>, Data, <<"">>)),
RoomJID1 = case proplists:get_value(<<"jid">>, Data, not_found) of
not_found -> proplists:get_value(<<"_jid">>, Data, room_jid_not_found);
A when is_binary(A) -> A
end,
RoomJID = jid:decode(RoomJID1),
Config = proplists:get_value(<<"_data">>, Data, []),
RoomCfg = convert_room_config(Data),
case proplists:get_bool(<<"persistent">>, Config) of
@ -358,9 +362,11 @@ convert_room_config(Data) ->
end,
[{affiliations, convert_room_affiliations(Data)},
{allow_change_subj, proplists:get_bool(<<"changesubject">>, Config)},
{mam, proplists:get_bool(<<"archiving">>, Config)},
{description, proplists:get_value(<<"description">>, Config, <<"">>)},
{members_only, proplists:get_bool(<<"members_only">>, Config)},
{moderated, proplists:get_bool(<<"moderated">>, Config)},
{persistent, proplists:get_bool(<<"persistent">>, Config)},
{anonymous, Anonymous}] ++ Pass ++ Subj.
convert_privacy_item({_, Item}) ->