From fc07d4b34dd4d9aa0c31eb7dad59dfa2afa5c379 Mon Sep 17 00:00:00 2001 From: badlop Date: Tue, 14 Feb 2023 14:58:34 +0100 Subject: [PATCH 01/12] Codacy: Add Codacy Security Scan --- .github/workflows/codacy.yml | 61 ++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 .github/workflows/codacy.yml diff --git a/.github/workflows/codacy.yml b/.github/workflows/codacy.yml new file mode 100644 index 00000000000..af390e38398 --- /dev/null +++ b/.github/workflows/codacy.yml @@ -0,0 +1,61 @@ +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +# This workflow checks out code, performs a Codacy security scan +# and integrates the results with the +# GitHub Advanced Security code scanning feature. For more information on +# the Codacy security scan action usage and parameters, see +# https://github.com/codacy/codacy-analysis-cli-action. +# For more information on Codacy Analysis CLI in general, see +# https://github.com/codacy/codacy-analysis-cli. + +name: Codacy Security Scan + +on: + push: + branches: [ "dependabot" ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ "dependabot" ] + schedule: + - cron: '45 13 * * 6' + +permissions: + contents: read + +jobs: + codacy-security-scan: + permissions: + contents: read # for actions/checkout to fetch code + security-events: write # for github/codeql-action/upload-sarif to upload SARIF results + actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status + name: Codacy Security Scan + runs-on: ubuntu-latest + steps: + # Checkout the repository to the GitHub Actions runner + - name: Checkout code + uses: actions/checkout@v3 + + # Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis + - name: Run Codacy Analysis CLI + uses: codacy/codacy-analysis-cli-action@5cc54a75f9ad88159bb54046196d920e40e367a5 + with: + # Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository + # You can also omit the token and run the tools that support default configurations + project-token: ${{ secrets.CODACY_PROJECT_TOKEN }} + verbose: true + output: results.sarif + format: sarif + # Adjust severity of non-security issues + gh-code-scanning-compat: true + # Force 0 exit code to allow SARIF file generation + # This will handover control about PR rejection to the GitHub side + max-allowed-issues: 2147483647 + + # Upload the SARIF file generated in the previous step + - name: Upload SARIF results file + uses: github/codeql-action/upload-sarif@v2 + with: + sarif_file: results.sarif From 6ea94e3057e9d646ea9d32387f31d3c526be8eb7 Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 14 Feb 2023 19:10:12 +0100 Subject: [PATCH 02/12] Codacy: Disable many checks in several tools for now --- .github/workflows/codacy.yml | 46 ++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/.github/workflows/codacy.yml b/.github/workflows/codacy.yml index af390e38398..4eececa09b9 100644 --- a/.github/workflows/codacy.yml +++ b/.github/workflows/codacy.yml @@ -38,6 +38,52 @@ jobs: - name: Checkout code uses: actions/checkout@v3 + - name: Setup Checkov + run: | + sed -i '/PASSWORD/i #checkov:skip=CKV_SECRET_6:' .github/workflows/ci.yml + sed -i '/PASSWORD/i #checkov:skip=CKV_SECRET_6:' test/docker/docker-compose.yml + + - name: Setup CSSlint + run: | + echo "{\"exclude-list\": [\"priv/css/\"]}" > .csslintrc + + - name: Setup Markdownlint + run: | + sed -i '1i\' .github/ISSUE_TEMPLATE/bug_report.md + sed -i '1i\' .github/ISSUE_TEMPLATE/feature_request.md + sed -i '1i\' CODE_OF_CONDUCT.md + sed -i '1i\' CHANGELOG.md + sed -i '1i\' README.md + sed -i '1i\' test/docker/README.md + sed -i '1i\' CONTAINER.md + sed -i '1i\' COMPILE.md + sed -i '1i\' CONTRIBUTING.md + sed -i '1i\' CONTRIBUTORS.md + + - name: Setup Shellcheck + run: | + sed -i '1a\# shellcheck disable=all' tools/captcha-ng.sh + sed -i '1a\# shellcheck disable=SC2013,SC3014,SC3060' tools/check_xep_versions.sh + + - name: Setup Stylelint + run: | + sed -i '1i\/* stylelint-disable */' priv/css/admin.css + sed -i '1i\/* stylelint-disable */' priv/css/bosh.css + sed -i '1i\/* stylelint-disable */' priv/css/muc.css + sed -i '1i\/* stylelint-disable */' priv/css/oauth.css + sed -i '1i\/* stylelint-disable */' priv/css/register.css + + - name: Setup TSQLlint + run: | + sed -i '1i\-- tsqllint-disable' sql/*.sql + sed -i '1s\disable\disable data-compression set-transaction-isolation-level\' sql/mssql*.sql + + - name: Remove escript files which are not shell scripts + run: | + rm tools/extract-tr.sh + rm tools/hook_deps.sh + rm tools/opt_types.sh + # Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis - name: Run Codacy Analysis CLI uses: codacy/codacy-analysis-cli-action@5cc54a75f9ad88159bb54046196d920e40e367a5 From 78559d5f46f64357966331bb0c7e91fa08458f83 Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 11 Sep 2023 12:01:44 +0200 Subject: [PATCH 03/12] Codacy: Use actions main version, to help solve the problem uploading SARIF file --- .github/workflows/codacy.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codacy.yml b/.github/workflows/codacy.yml index 4eececa09b9..780aef2019e 100644 --- a/.github/workflows/codacy.yml +++ b/.github/workflows/codacy.yml @@ -36,7 +36,7 @@ jobs: steps: # Checkout the repository to the GitHub Actions runner - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@main - name: Setup Checkov run: | @@ -86,7 +86,7 @@ jobs: # Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis - name: Run Codacy Analysis CLI - uses: codacy/codacy-analysis-cli-action@5cc54a75f9ad88159bb54046196d920e40e367a5 + uses: codacy/codacy-analysis-cli-action@master with: # Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository # You can also omit the token and run the tools that support default configurations @@ -102,6 +102,6 @@ jobs: # Upload the SARIF file generated in the previous step - name: Upload SARIF results file - uses: github/codeql-action/upload-sarif@v2 + uses: github/codeql-action/upload-sarif@main with: sarif_file: results.sarif From 97199729b79a8838b13b711dad4dc968328953eb Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 7 Feb 2024 19:44:26 +0100 Subject: [PATCH 04/12] Codacy: Update config, trying to solve problem when uploading SARIF file Copied example confioguration from: https://github.com/marketplace/actions/codacy-analysis-cli#integration-with-github-code-scanning --- .github/workflows/codacy.yml | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/.github/workflows/codacy.yml b/.github/workflows/codacy.yml index 780aef2019e..31aee649d32 100644 --- a/.github/workflows/codacy.yml +++ b/.github/workflows/codacy.yml @@ -1,16 +1,3 @@ -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. - -# This workflow checks out code, performs a Codacy security scan -# and integrates the results with the -# GitHub Advanced Security code scanning feature. For more information on -# the Codacy security scan action usage and parameters, see -# https://github.com/codacy/codacy-analysis-cli-action. -# For more information on Codacy Analysis CLI in general, see -# https://github.com/codacy/codacy-analysis-cli. - name: Codacy Security Scan on: @@ -22,19 +9,12 @@ on: schedule: - cron: '45 13 * * 6' -permissions: - contents: read jobs: codacy-security-scan: - permissions: - contents: read # for actions/checkout to fetch code - security-events: write # for github/codeql-action/upload-sarif to upload SARIF results - actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status name: Codacy Security Scan runs-on: ubuntu-latest steps: - # Checkout the repository to the GitHub Actions runner - name: Checkout code uses: actions/checkout@main @@ -84,20 +64,15 @@ jobs: rm tools/hook_deps.sh rm tools/opt_types.sh - # Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis - name: Run Codacy Analysis CLI uses: codacy/codacy-analysis-cli-action@master with: - # Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository - # You can also omit the token and run the tools that support default configurations - project-token: ${{ secrets.CODACY_PROJECT_TOKEN }} - verbose: true output: results.sarif format: sarif # Adjust severity of non-security issues gh-code-scanning-compat: true # Force 0 exit code to allow SARIF file generation - # This will handover control about PR rejection to the GitHub side + # This will hand over control about PR rejection to the GitHub side max-allowed-issues: 2147483647 # Upload the SARIF file generated in the previous step From 5738de0156ecf3ff62cbc203b06db49d0148e8bf Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 7 Feb 2024 20:51:31 +0100 Subject: [PATCH 05/12] Codacy: Apply workaround for SARIF problem As seen in codacy / codacy-analysis-cli-action/issues/95 --- .github/workflows/codacy.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/codacy.yml b/.github/workflows/codacy.yml index 31aee649d32..eba4d3b5170 100644 --- a/.github/workflows/codacy.yml +++ b/.github/workflows/codacy.yml @@ -75,8 +75,12 @@ jobs: # This will hand over control about PR rejection to the GitHub side max-allowed-issues: 2147483647 + - name: Clean duplicates + run: + jq '.runs |= unique_by({tool, invocations, results})' codacy.sarif + # Upload the SARIF file generated in the previous step - name: Upload SARIF results file uses: github/codeql-action/upload-sarif@main with: - sarif_file: results.sarif + sarif_file: codacy.sarif From d44d7ab9ae9964a9c92e5a82b5f04abafcb65dd5 Mon Sep 17 00:00:00 2001 From: Badlop Date: Sat, 30 Apr 2022 21:52:15 +0200 Subject: [PATCH 06/12] Dependabot: Detect updates in docker, actions and mix --- .github/dependabot.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000000..c65905e2096 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,18 @@ +version: 2 + +updates: + + - package-ecosystem: "docker" + directory: "/.github/container/" + schedule: + interval: "weekly" + + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + + - package-ecosystem: "mix" + directory: "/" + schedule: + interval: "weekly" From 0921d8c7c5d5dd73413f169b76856d6840588908 Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 14 Oct 2024 13:08:12 +0200 Subject: [PATCH 07/12] mod_mam: Advertise XEP-0424 feature in server disco info (3340) --- src/mod_mam.erl | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/mod_mam.erl b/src/mod_mam.erl index 9b4fa83f9e4..5dec822e583 100644 --- a/src/mod_mam.erl +++ b/src/mod_mam.erl @@ -38,6 +38,7 @@ -export([sm_receive_packet/1, user_receive_packet/1, user_send_packet/1, user_send_packet_strip_tag/1, process_iq_v0_2/1, process_iq_v0_3/1, + disco_local_features/5, disco_sm_features/5, remove_user/2, remove_room/3, mod_opt_type/1, muc_process_iq/2, muc_filter_message/3, message_is_archived/3, delete_old_messages/2, get_commands_spec/0, msg_to_el/4, @@ -147,6 +148,8 @@ start(Host, Opts) -> muc_filter_message, 50), ejabberd_hooks:add(muc_process_iq, Host, ?MODULE, muc_process_iq, 50), + ejabberd_hooks:add(disco_local_features, Host, ?MODULE, + disco_local_features, 50), ejabberd_hooks:add(disco_sm_features, Host, ?MODULE, disco_sm_features, 50), ejabberd_hooks:add(remove_user, Host, ?MODULE, @@ -226,6 +229,8 @@ stop(Host) -> muc_filter_message, 50), ejabberd_hooks:delete(muc_process_iq, Host, ?MODULE, muc_process_iq, 50), + ejabberd_hooks:delete(disco_local_features, Host, ?MODULE, + disco_local_features, 50), ejabberd_hooks:delete(disco_sm_features, Host, ?MODULE, disco_sm_features, 50), ejabberd_hooks:delete(remove_user, Host, ?MODULE, @@ -612,6 +617,20 @@ parse_query(#mam_query{xdata = #xdata{}} = Query, Lang) -> parse_query(#mam_query{}, _Lang) -> {ok, []}. +disco_local_features({error, _Error} = Acc, _From, _To, _Node, _Lang) -> + Acc; +disco_local_features(Acc, _From, _To, <<"">>, _Lang) -> + Features = case Acc of + {result, Fs} -> Fs; + empty -> [] + end, + {result, [?NS_MESSAGE_RETRACT | Features]}; +disco_local_features(empty, _From, _To, _Node, Lang) -> + Txt = ?T("No features available"), + {error, xmpp:err_item_not_found(Txt, Lang)}; +disco_local_features(Acc, _From, _To, _Node, _Lang) -> + Acc. + disco_sm_features(empty, From, To, Node, Lang) -> disco_sm_features({result, []}, From, To, Node, Lang); disco_sm_features({result, OtherFeatures}, From 100fa44f140b39717708fe89c3fb77700cebfd7a Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 26 Sep 2024 12:07:52 +0200 Subject: [PATCH 08/12] Preliminary support for "IQ permission" from XEP-0356 0.4.1 (3889) --- src/ejabberd_router.erl | 21 ++++- src/mod_privilege.erl | 191 ++++++++++++++++++++++++++++++++++++-- src/mod_privilege_opt.erl | 7 ++ 3 files changed, 210 insertions(+), 9 deletions(-) diff --git a/src/ejabberd_router.erl b/src/ejabberd_router.erl index 94f25f80d15..8f877dfaf95 100644 --- a/src/ejabberd_router.erl +++ b/src/ejabberd_router.erl @@ -380,8 +380,9 @@ code_change(_OldVsn, State, _Extra) -> %%% Internal functions %%-------------------------------------------------------------------- -spec do_route(stanza()) -> ok. -do_route(OrigPacket) -> - ?DEBUG("Route:~n~ts", [xmpp:pp(OrigPacket)]), +do_route(OrigPacket1) -> + ?DEBUG("Route:~n~ts", [xmpp:pp(OrigPacket1)]), + OrigPacket = process_privilege_iq(OrigPacket1), case ejabberd_hooks:run_fold(filter_packet, OrigPacket, []) of drop -> ok; @@ -405,6 +406,22 @@ do_route(OrigPacket) -> end end. +%% @format-begin +process_privilege_iq(Packet) -> + To = xmpp:get_to(Packet), + case xmpp:get_meta(Packet, privilege_iq, none) of + {OriginalId, OriginalHost, ReplacedJid} when ReplacedJid == To -> + Privilege = #privilege{forwarded = #forwarded{sub_els = [Packet]}}, + #iq{type = xmpp:get_type(Packet), + id = OriginalId, + to = jid:make(OriginalHost), + from = ReplacedJid, + sub_els = [Privilege]}; + _ -> + Packet + end. +%% @format-end + -spec do_route(stanza(), #route{}) -> any(). do_route(Pkt, #route{local_hint = LocalHint, pid = Pid}) when is_pid(Pid) -> diff --git a/src/mod_privilege.erl b/src/mod_privilege.erl index b873fe13f72..9808a4158f0 100644 --- a/src/mod_privilege.erl +++ b/src/mod_privilege.erl @@ -25,7 +25,7 @@ -author('amuhar3@gmail.com'). --protocol({xep, 356, '0.2.1', '16.09', "", ""}). +-protocol({xep, 356, '0.4.1', '24.xx', "", ""}). -behaviour(gen_server). -behaviour(gen_mod). @@ -37,6 +37,7 @@ -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). -export([component_connected/1, component_disconnected/2, + component_send_packet/1, roster_access/2, process_message/1, process_presence_out/1, process_presence_in/1]). @@ -45,14 +46,17 @@ -include("translate.hrl"). -type roster_permission() :: both | get | set. +-type iq_permission() :: both | get | set. -type presence_permission() :: managed_entity | roster. -type message_permission() :: outgoing. -type roster_permissions() :: [{roster_permission(), acl:acl()}]. +-type iq_permissions() :: [{iq_permission(), acl:acl()}]. -type presence_permissions() :: [{presence_permission(), acl:acl()}]. -type message_permissions() :: [{message_permission(), acl:acl()}]. --type access() :: [{roster, roster_permissions()} | - {presence, presence_permissions()} | - {message, message_permissions()}]. +-type access() :: [{roster, roster_permission()} | + {iq, [privilege_namespace()]} | + {presence, presence_permission()} | + {message, message_permission()}]. -type permissions() :: #{binary() => access()}. -record(state, {server_host = <<"">> :: binary()}). @@ -71,6 +75,10 @@ reload(_Host, _NewOpts, _OldOpts) -> mod_opt_type(roster) -> econf:options( #{both => econf:acl(), get => econf:acl(), set => econf:acl()}); +mod_opt_type(iq) -> + econf:map( + econf:binary(), + econf:options(#{both => econf:acl(), get => econf:acl(), set => econf:acl()})); mod_opt_type(message) -> econf:options( #{outgoing => econf:acl()}); @@ -80,6 +88,7 @@ mod_opt_type(presence) -> mod_options(_) -> [{roster, [{both, none}, {get, none}, {set, none}]}, + {iq, []}, {presence, [{managed_entity, none}, {roster, none}]}, {message, [{outgoing,none}]}]. @@ -130,6 +139,27 @@ mod_doc() -> desc => ?T("Sets write access to a user's roster. " "The default value is 'none'.")}}]}, + {iq, + #{value => "{Namespace: Options}", + desc => + ?T("This option defines namespaces and their IQ permissions. " + "By default no permissions are given. " + "The 'Options' are:")}, + [{both, + #{value => ?T("AccessName"), + desc => + ?T("Allows sending IQ stanzas of type 'get' and 'set'. " + "The default value is 'none'.")}}, + {get, + #{value => ?T("AccessName"), + desc => + ?T("Allows sending IQ stanzas of type 'get'. " + "The default value is 'none'.")}}, + {set, + #{value => ?T("AccessName"), + desc => + ?T("Allows sending IQ stanzas of type 'set'. " + "The default value is 'none'.")}}]}, {message, #{value => ?T("Options"), desc => @@ -164,6 +194,9 @@ mod_doc() -> example => ["modules:", " mod_privilege:", + " iq:", + " http://jabber.org/protocol/pubsub:", + " get: all", " roster:", " get: all", " presence:", @@ -190,6 +223,10 @@ component_disconnected(Host, _Reason) -> gen_server:cast(Proc, {component_disconnected, Host}) end, ejabberd_option:hosts()). +%% +%% Message processing +%% + -spec process_message(stanza()) -> stop | ok. process_message(#message{from = #jid{luser = <<"">>, lresource = <<"">>} = From, to = #jid{lresource = <<"">>} = To, @@ -212,9 +249,73 @@ process_message(#message{from = #jid{luser = <<"">>, lresource = <<"">>} = From, %% Component is disconnected ok end; + process_message(_Stanza) -> ok. +%% +%% IQ processing +%% + +%% @format-begin + +component_send_packet({#iq{from = From, + to = #jid{lresource = <<"">>} = To, + id = Id, + type = Type} = + IQ, + State}) + when Type /= error -> + Host = From#jid.lserver, + ServerHost = To#jid.lserver, + Permissions = get_permissions(ServerHost), + Result = + case {maps:find(Host, Permissions), get_iq_encapsulated_details(IQ)} of + {{ok, Access}, {ok, EncapType, EncapNs, EncapFrom, EncIq}} + when (EncapType == Type) and ((EncapFrom == undefined) or (EncapFrom == To)) -> + NsPermissions = proplists:get_value(iq, Access, none), + Permission = + case lists:keyfind(EncapNs, 2, NsPermissions) of + #privilege_namespace{type = AllowedType} -> + AllowedType; + _ -> + none + end, + case Permission == both + orelse Permission == get andalso Type == get + orelse Permission == set andalso Type == set + of + true -> + forward_iq(Host, To, Id, EncIq); + false -> + ?INFO_MSG("IQ not forwarded: Permission not granted to ns=~s with type=~p", + [EncapNs, Type]), + drop + end; + {error, _} -> + %% Component is disconnected + ?INFO_MSG("IQ not forwarded: Component seems disconnected", []), + drop; + {_, {ok, E, _, _, _}} when E /= Type -> + ?INFO_MSG("IQ not forwarded: The encapsulated IQ stanza type=~p " + "does not match the top-level IQ stanza type=~p", + [E, Type]), + drop; + {_, {ok, _, _, EF, _}} when (EF /= undefined) and (EF /= To) -> + ?INFO_MSG("IQ not forwarded: The FROM attribute in the encapsulated " + "IQ stanza and the TO in top-level IQ stanza do not match", + []), + drop + end, + {Result, State}; +component_send_packet(Acc) -> + Acc. +%% @format-end + +%% +%% Roster processing +%% + -spec roster_access({true, iq()} | false, iq()) -> {true, iq()} | false. roster_access({true, _IQ} = Acc, _) -> Acc; @@ -309,6 +410,8 @@ init([Host|_]) -> process_presence_out, 50), ejabberd_hooks:add(user_receive_packet, Host, ?MODULE, process_presence_in, 50), + ejabberd_hooks:add(component_send_packet, ?MODULE, + component_send_packet, 50), {ok, #state{server_host = Host}}. handle_call(Request, From, State) -> @@ -320,22 +423,26 @@ handle_cast({component_connected, Host}, State) -> From = jid:make(ServerHost), To = jid:make(Host), RosterPerm = get_roster_permission(ServerHost, Host), + IqNamespaces = get_iq_namespaces(ServerHost, Host), PresencePerm = get_presence_permission(ServerHost, Host), MessagePerm = get_message_permission(ServerHost, Host), - if RosterPerm /= none; PresencePerm /= none; MessagePerm /= none -> + if RosterPerm /= none; IqNamespaces /= []; PresencePerm /= none; MessagePerm /= none -> Priv = #privilege{perms = [#privilege_perm{access = message, type = MessagePerm}, #privilege_perm{access = roster, type = RosterPerm}, + #privilege_perm{access = iq, + namespaces = IqNamespaces}, #privilege_perm{access = presence, type = PresencePerm}]}, ?INFO_MSG("Granting permissions to external " "component '~ts': roster = ~ts, presence = ~ts, " - "message = ~ts", - [Host, RosterPerm, PresencePerm, MessagePerm]), + "message = ~ts,~n iq = ~p", + [Host, RosterPerm, PresencePerm, MessagePerm, IqNamespaces]), Msg = #message{from = From, to = To, sub_els = [Priv]}, ejabberd_router:route(Msg), Permissions = maps:put(Host, [{roster, RosterPerm}, + {iq, IqNamespaces}, {presence, PresencePerm}, {message, MessagePerm}], get_permissions(ServerHost)), @@ -366,6 +473,8 @@ terminate(_Reason, State) -> Host = State#state.server_host, case gen_mod:is_loaded_elsewhere(Host, ?MODULE) of false -> + ejabberd_hooks:delete(component_send_packet, ?MODULE, + component_send_packet, 50), ejabberd_hooks:delete(component_connected, ?MODULE, component_connected, 50), ejabberd_hooks:delete(component_disconnected, ?MODULE, @@ -396,6 +505,10 @@ get_permissions(ServerHost) -> [{_, Permissions}] -> Permissions end. +%% +%% Message +%% + -spec forward_message(message()) -> ok. forward_message(#message{to = To} = Msg) -> ServerHost = To#jid.lserver, @@ -436,6 +549,45 @@ forward_message(#message{to = To} = Msg) -> ejabberd_router:route_error(Msg, Err) end. +%% +%% IQ +%% + +%% @format-begin + +-spec get_iq_encapsulated_details(iq()) -> + {ok, set | get, binary(), jid(), iq()} | + {error, Why :: atom(), any(), iq()}. +get_iq_encapsulated_details(#iq{sub_els = [IqSub]} = Msg) -> + Lang = xmpp:get_lang(Msg), + try xmpp:try_subtag(Msg, #privileged_iq{}) of + #privileged_iq{iq = #iq{type = EncapsulatedType, from = From} = EncIq} -> + [IqSubSub] = xmpp:get_els(IqSub), + [Element] = xmpp:get_els(IqSubSub), + Ns = xmpp:get_ns(Element), + {ok, EncapsulatedType, Ns, From, EncIq}; + _ -> + Txt = ?T("No element found"), + Err = xmpp:err_bad_request(Txt, Lang), + {error, no_privileged_iq, Err} + catch + _:{xmpp_codec, Why} -> + Txt = xmpp:io_format_error(Why), + Err = xmpp:err_bad_request(Txt, Lang), + {error, codec_error, Err} + end. + +-spec forward_iq(binary(), jid(), binary(), iq()) -> iq(). +forward_iq(Host, ToplevelTo, Id, Iq) -> + FromJID = ToplevelTo, + NewIq0 = Iq#iq{from = FromJID}, + xmpp:put_meta(NewIq0, privilege_iq, {Id, Host, FromJID}). +%% @format-end + +%% +%% Permissions +%% + -spec get_roster_permission(binary(), binary()) -> roster_permission() | none. get_roster_permission(ServerHost, Host) -> Perms = mod_privilege_opt:roster(ServerHost), @@ -452,6 +604,26 @@ get_roster_permission(ServerHost, Host) -> end end. +-spec get_iq_namespaces(binary(), binary()) -> [privilege_namespace()]. +get_iq_namespaces(ServerHost, Host) -> + NsPerms = mod_privilege_opt:iq(ServerHost), + [#privilege_namespace{ns = Ns, type = get_iq_permission(ServerHost, Host, Perms)} || {Ns, Perms} <- NsPerms]. + +-spec get_iq_permission(binary(), binary(), [iq_permission()]) -> iq_permission() | none. +get_iq_permission(ServerHost, Host, Perms) -> + case match_rule(ServerHost, Host, Perms, both) of + allow -> + both; + deny -> + Get = match_rule(ServerHost, Host, Perms, get), + Set = match_rule(ServerHost, Host, Perms, set), + if Get == allow, Set == allow -> both; + Get == allow -> get; + Set == allow -> set; + true -> none + end + end. + -spec get_message_permission(binary(), binary()) -> message_permission() | none. get_message_permission(ServerHost, Host) -> Perms = mod_privilege_opt:message(ServerHost), @@ -473,7 +645,12 @@ get_presence_permission(ServerHost, Host) -> end end. +-ifdef(OTP_BELOW_26). +-dialyzer({no_contracts, match_rule/4}). +-endif. + -spec match_rule(binary(), binary(), roster_permissions(), roster_permission()) -> allow | deny; + (binary(), binary(), iq_permissions(), iq_permission()) -> allow | deny; (binary(), binary(), presence_permissions(), presence_permission()) -> allow | deny; (binary(), binary(), message_permissions(), message_permission()) -> allow | deny. match_rule(ServerHost, Host, Perms, Type) -> diff --git a/src/mod_privilege_opt.erl b/src/mod_privilege_opt.erl index 64198b387e5..36bf54efa56 100644 --- a/src/mod_privilege_opt.erl +++ b/src/mod_privilege_opt.erl @@ -3,10 +3,17 @@ -module(mod_privilege_opt). +-export([iq/1]). -export([message/1]). -export([presence/1]). -export([roster/1]). +-spec iq(gen_mod:opts() | global | binary()) -> [{binary(),[{'both',acl:acl()} | {'get',acl:acl()} | {'set',acl:acl()}]}]. +iq(Opts) when is_map(Opts) -> + gen_mod:get_opt(iq, Opts); +iq(Host) -> + gen_mod:get_module_opt(Host, mod_privilege, iq). + -spec message(gen_mod:opts() | global | binary()) -> [{'outgoing','none' | acl:acl()}]. message(Opts) when is_map(Opts) -> gen_mod:get_opt(message, Opts); From 53acf05bacf88a4fcc3dd8c54124c607824a2a8c Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 27 Aug 2024 11:57:28 +0200 Subject: [PATCH 09/12] Add feature announcement to disco-info (4039) --- src/mod_block_strangers.erl | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/mod_block_strangers.erl b/src/mod_block_strangers.erl index c7a436c249b..26b8e73d0e3 100644 --- a/src/mod_block_strangers.erl +++ b/src/mod_block_strangers.erl @@ -32,7 +32,8 @@ -export([start/2, stop/1, reload/3, mod_doc/0, depends/2, mod_opt_type/1, mod_options/1]). --export([filter_packet/1, filter_offline_msg/1, filter_subscription/2]). +-export([filter_packet/1, filter_offline_msg/1, filter_subscription/2, + get_sm_features/5]). -include_lib("xmpp/include/xmpp.hrl"). -include("logger.hrl"). @@ -40,13 +41,17 @@ -define(SETS, gb_sets). +-define(NS_BLOCK_STRANGERS, <<"urn:ejabberd:block-strangers">>). + -type c2s_state() :: ejabberd_c2s:state(). %%%=================================================================== %%% Callbacks and hooks %%%=================================================================== start(_Host, _Opts) -> - {ok, [{hook, user_receive_packet, filter_packet, 25}, + {ok, [{hook, disco_local_features, get_sm_features, 50}, + {hook, disco_sm_features, get_sm_features, 50}, + {hook, user_receive_packet, filter_packet, 25}, {hook, roster_in_subscription, filter_subscription, 25}, {hook, offline_message_hook, filter_offline_msg, 25}]}. @@ -56,6 +61,16 @@ stop(_Host) -> reload(_Host, _NewOpts, _OldOpts) -> ok. +get_sm_features(Acc, _From, _To, <<"">>, _Lang) -> + Features = case Acc of + {result, I} -> I; + _ -> [] + end, + {result, [?NS_BLOCK_STRANGERS | Features]}; + +get_sm_features(Acc, _From, _To, _Node, _Lang) -> + Acc. + -spec filter_packet({stanza(), c2s_state()}) -> {stanza(), c2s_state()} | {stop, {drop, c2s_state()}}. filter_packet({#message{from = From} = Msg, State} = Acc) -> From c97321d8cab70aa5b58115450664ef2e4108d835 Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 21 Oct 2024 16:36:52 +0200 Subject: [PATCH 10/12] Update XMPP library --- mix.exs | 2 +- rebar.config | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mix.exs b/mix.exs index 69ca7928ca9..86048f57b26 100644 --- a/mix.exs +++ b/mix.exs @@ -144,7 +144,7 @@ defmodule Ejabberd.MixProject do {:p1_utils, "~> 1.0"}, {:pkix, "~> 1.0"}, {:stringprep, ">= 1.0.26"}, - {:xmpp, git: "https://github.com/processone/xmpp.git", ref: "422c107a882b6967e615ea69b33fac4897048fbb", override: true}, + {:xmpp, git: "https://github.com/processone/xmpp.git", ref: "c045d4d8555e251f2212743db8af90255da2ab57", override: true}, {:yconf, "~> 1.0"}] ++ cond_deps() end diff --git a/rebar.config b/rebar.config index 868b16d905a..e0ab33b35e2 100644 --- a/rebar.config +++ b/rebar.config @@ -69,7 +69,7 @@ {stringprep, "~> 1.0.29", {git, "https://github.com/processone/stringprep", {tag, "1.0.30"}}}, {if_var_true, stun, {stun, "~> 1.2.12", {git, "https://github.com/processone/stun", {tag, "1.2.14"}}}}, - {xmpp, "~> 1.8.3", {git, "https://github.com/processone/xmpp", "422c107a882b6967e615ea69b33fac4897048fbb"}}, + {xmpp, "~> 1.8.3", {git, "https://github.com/processone/xmpp", "c045d4d8555e251f2212743db8af90255da2ab57"}}, {yconf, "~> 1.0.15", {git, "https://github.com/processone/yconf", {tag, "1.0.16"}}} ]}. From ec03852476c3dfe689ecc4fa209f028aeaa4702b Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 21 Oct 2024 16:52:14 +0200 Subject: [PATCH 11/12] Update xmpp dependency --- mix.lock | 2 +- rebar.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mix.lock b/mix.lock index 0e034aae34c..283fd0aab7b 100644 --- a/mix.lock +++ b/mix.lock @@ -32,6 +32,6 @@ "stringprep": {:hex, :stringprep, "1.0.30", "46cf0ff631b3e7328f61f20b454d59428d87738f25d709798b5dcbb9b83c23f1", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "f6fc9b3384a03877830f89b2f38580caf3f4a27448a4a333d6a8c3975c220b9a"}, "stun": {:hex, :stun, "1.2.14", "6f538ac80c842131dbd149055570d116bfabc9b5ebff4bd6af2e7888958c660c", [:rebar3], [{:fast_tls, "1.1.21", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "e134807b1b7a8dffd94e64eefee00e65c7b4042f3d14e16f8f43566d20371583"}, "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, - "xmpp": {:git, "https://github.com/processone/xmpp.git", "422c107a882b6967e615ea69b33fac4897048fbb", [ref: "422c107a882b6967e615ea69b33fac4897048fbb"]}, + "xmpp": {:git, "https://github.com/processone/xmpp.git", "c045d4d8555e251f2212743db8af90255da2ab57", [ref: "c045d4d8555e251f2212743db8af90255da2ab57"]}, "yconf": {:hex, :yconf, "1.0.16", "d59521d66ff89f219411b6e9277cd6feec7cc6fce11554e67de02a8d0a470479", [:rebar3], [{:fast_yaml, "1.0.37", [hex: :fast_yaml, repo: "hexpm", optional: false]}], "hexpm", "e947813273f38711c7b2e5a8e4acc9a51c7bbe854f744a345f60300b38586c89"}, } diff --git a/rebar.lock b/rebar.lock index 2e5892eb1da..6d844e27f02 100644 --- a/rebar.lock +++ b/rebar.lock @@ -32,7 +32,7 @@ {<<"unicode_util_compat">>,{pkg,<<"unicode_util_compat">>,<<"0.7.0">>},1}, {<<"xmpp">>, {git,"https://github.com/processone/xmpp", - {ref,"422c107a882b6967e615ea69b33fac4897048fbb"}}, + {ref,"c045d4d8555e251f2212743db8af90255da2ab57"}}, 0}, {<<"yconf">>,{pkg,<<"yconf">>,<<"1.0.16">>},0}]}. [ From 1d3be850bfb1fb66b1d1aa845bc30d16b2869d22 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 06:48:56 +0000 Subject: [PATCH 12/12] Bump stun from 1.2.14 to 1.2.15 Bumps [stun](https://github.com/processone/stun) from 1.2.14 to 1.2.15. - [Changelog](https://github.com/processone/stun/blob/master/CHANGELOG.md) - [Commits](https://github.com/processone/stun/compare/1.2.14...1.2.15) --- updated-dependencies: - dependency-name: stun dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- mix.lock | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index 283fd0aab7b..e9623114a8b 100644 --- a/mix.lock +++ b/mix.lock @@ -9,10 +9,12 @@ "erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"}, "esip": {:hex, :esip, "1.0.54", "dae8fb8278fd3b2c0d38c2e832c4b8d26700eb239b9a42c8ea574fee76f5e76a", [:rebar3], [{:fast_tls, "1.1.21", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}, {:stun, "1.2.14", [hex: :stun, repo: "hexpm", optional: false]}], "hexpm", "8187af819d7259cdaddaf69726c239ef604c9b0b0298a5f2d3e687bf5e2237ee"}, "ex_doc": {:hex, :ex_doc, "0.34.2", "13eedf3844ccdce25cfd837b99bea9ad92c4e511233199440488d217c92571e8", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "5ce5f16b41208a50106afed3de6a2ed34f4acfd65715b82a0b84b49d995f95c1"}, + "exsync": {:hex, :exsync, "0.4.1", "0a14fe4bfcb80a509d8a0856be3dd070fffe619b9ba90fec13c58b316c176594", [:mix], [{:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}], "hexpm", "cefb22aa805ec97ffc5b75a4e1dc54bcaf781e8b32564bf74abbe5803d1b5178"}, "ezlib": {:hex, :ezlib, "1.0.13", "3c7f62862850a241159c10b218ecf580bce54d0890601b65144dacc2633be2b0", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "9ee62ab3f8ed55a0fd11a9569fcb8e458683f95575417272192b069f092abfbb"}, "fast_tls": {:git, "https://github.com/processone/fast_tls.git", "75a08772f0ffddfed0441bfdc7e7f9a5adb3862f", [ref: "75a08772f0ffddfed0441bfdc7e7f9a5adb3862f"]}, "fast_xml": {:git, "https://github.com/processone/fast_xml.git", "e7dc91310046831f436a03abf029587f0c2764f4", [ref: "e7dc91310046831f436a03abf029587f0c2764f4"]}, "fast_yaml": {:hex, :fast_yaml, "1.0.37", "f71d472fbf787ccd161b914d1eb486116a0f4f2e835337a378fbd31b59d2e74b", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "8de868721bf7e2172414f7d3148ede0f3c922b496455cd625dd5c4429515a769"}, + "file_system": {:hex, :file_system, "1.0.1", "79e8ceaddb0416f8b8cd02a0127bdbababe7bf4a23d2a395b983c1f8b3f73edd", [:mix], [], "hexpm", "4414d1f38863ddf9120720cd976fce5bdde8e91d8283353f0e31850fa89feb9e"}, "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, "jiffy": {:hex, :jiffy, "1.1.2", "a9b6c9a7ec268e7cf493d028f0a4c9144f59ccb878b1afe42841597800840a1b", [:rebar3], [], "hexpm", "bb61bc42a720bbd33cb09a410e48bb79a61012c74cb8b3e75f26d988485cf381"}, "jose": {:hex, :jose, "1.11.10", "a903f5227417bd2a08c8a00a0cbcc458118be84480955e8d251297a425723f83", [:mix, :rebar3], [], "hexpm", "0d6cd36ff8ba174db29148fc112b5842186b68a90ce9fc2b3ec3afe76593e614"}, @@ -30,7 +32,7 @@ "pkix": {:hex, :pkix, "1.0.10", "d3bfadf7b7cfe2a3636f1b256c9cce5f646a07ce31e57ee527668502850765a0", [:rebar3], [], "hexpm", "e02164f83094cb124c41b1ab28988a615d54b9adc38575f00f19a597a3ac5d0e"}, "sqlite3": {:hex, :sqlite3, "1.1.15", "e819defd280145c328457d7af897d2e45e8e5270e18812ee30b607c99cdd21af", [:rebar3], [], "hexpm", "3c0ba4e13322c2ad49de4e2ddd28311366adde54beae8dba9d9e3888f69d2857"}, "stringprep": {:hex, :stringprep, "1.0.30", "46cf0ff631b3e7328f61f20b454d59428d87738f25d709798b5dcbb9b83c23f1", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "f6fc9b3384a03877830f89b2f38580caf3f4a27448a4a333d6a8c3975c220b9a"}, - "stun": {:hex, :stun, "1.2.14", "6f538ac80c842131dbd149055570d116bfabc9b5ebff4bd6af2e7888958c660c", [:rebar3], [{:fast_tls, "1.1.21", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "e134807b1b7a8dffd94e64eefee00e65c7b4042f3d14e16f8f43566d20371583"}, + "stun": {:hex, :stun, "1.2.15", "eec510af6509201ff97f1f2c87b7977c833bf29c04e985383370ec21f04e4ccf", [:rebar3], [{:fast_tls, "1.1.22", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "f6d8a541a29fd13f2ce658b676c0cc661262b96e045b52def1644b75ebc0edef"}, "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, "xmpp": {:git, "https://github.com/processone/xmpp.git", "c045d4d8555e251f2212743db8af90255da2ab57", [ref: "c045d4d8555e251f2212743db8af90255da2ab57"]}, "yconf": {:hex, :yconf, "1.0.16", "d59521d66ff89f219411b6e9277cd6feec7cc6fce11554e67de02a8d0a470479", [:rebar3], [{:fast_yaml, "1.0.37", [hex: :fast_yaml, repo: "hexpm", optional: false]}], "hexpm", "e947813273f38711c7b2e5a8e4acc9a51c7bbe854f744a345f60300b38586c89"},