Compare commits

...

99 Commits

Author SHA1 Message Date
Badlop 601fcba4cb Set version to 24.10
Container / Container (push) Failing after 55s
Installers / Binaries (push) Failing after 49s
Runtime / Rebars (20, rebar) (push) Failing after 4s
Runtime / Rebars (20, rebar3) (push) Failing after 5s
Runtime / Rebars (25, rebar) (push) Failing after 4s
Runtime / Rebars (25, rebar3) (push) Failing after 4s
Runtime / Rebars (26, rebar) (push) Failing after 4s
Runtime / Rebars (26, rebar3) (push) Failing after 4s
Runtime / Rebars (27, rebar3) (push) Failing after 4s
Installers / Release (push) Has been skipped
CI / Tests (20.0) (push) Has been cancelled
CI / Tests (25) (push) Has been cancelled
CI / Tests (26) (push) Has been cancelled
CI / Tests (27) (push) Has been cancelled
Runtime / Rebar3+Elixir (1.13, 23.0) (push) Has been cancelled
Runtime / Rebar3+Elixir (1.13, 25) (push) Has been cancelled
Runtime / Rebar3+Elixir (1.15, 25) (push) Has been cancelled
Runtime / Rebar3+Elixir (1.15, 26) (push) Has been cancelled
Runtime / Rebar3+Elixir (1.16, 25) (push) Has been cancelled
Runtime / Rebar3+Elixir (1.16, 26) (push) Has been cancelled
Runtime / Rebar3+Elixir (1.17, 25) (push) Has been cancelled
Runtime / Rebar3+Elixir (1.17, 26) (push) Has been cancelled
Runtime / Rebar3+Elixir (1.17, 27) (push) Has been cancelled
Runtime / Mix (1.13, 23.0) (push) Has been cancelled
Runtime / Mix (1.13, 25) (push) Has been cancelled
Runtime / Mix (1.15, 25) (push) Has been cancelled
Runtime / Mix (1.15, 26) (push) Has been cancelled
Runtime / Mix (1.16, 25) (push) Has been cancelled
Runtime / Mix (1.16, 26) (push) Has been cancelled
Runtime / Mix (1.17, 25) (push) Has been cancelled
Runtime / Mix (1.17, 26) (push) Has been cancelled
Runtime / Mix (1.17, 27) (push) Has been cancelled
2024-10-28 17:02:10 +01:00
Badlop cc3a9f7722 Update Changelog to 24.10 2024-10-28 16:34:25 +01:00
Badlop 296ef8287f Remove mod_tombstone from man, it's in ejabberd-contrib (thanks to Licaon_Kter) 2024-10-28 16:34:22 +01:00
Paweł Chmielowski b5dab24679 Update dependencies 2024-10-28 16:21:44 +01:00
Badlop 319414b985 Update man page to 24.10 2024-10-28 13:50:02 +01:00
Badlop 6b0058c89c Add two more version notes 2024-10-28 13:50:02 +01:00
Badlop 855c828d1f Update Spanish and Catalan translations 2024-10-28 13:35:49 +01:00
Badlop c72ef537ee Update Chinese (Simplified) translation (thanks to Sketch6580) 2024-10-28 13:35:47 +01:00
Badlop 11e86811a0 Update Portuguese (Brazil) translation (thanks to Wellington Uemura) 2024-10-28 13:35:46 +01:00
Badlop 2183f60917 Update Italian translation (thanks to Ermete Melchiorre) 2024-10-28 13:35:45 +01:00
Badlop 05f0fbf195 Update Bulgarian translation (thanks to MrEddX) 2024-10-28 13:35:43 +01:00
Badlop 853da159de ejabberd.yml.example: Enable mod_s2s_bidi in default configuration 2024-10-28 12:06:56 +01:00
Badlop 643ae7e5f9 Result of running "make doap options" 2024-10-28 12:06:55 +01:00
Badlop 322e25d18e CI: Get again continue-on-error for XMPP Interop Tests
See explanations following the comment
https://github.com/processone/ejabberd/pull/4285#issuecomment-2397047355

This partially reverts commit 94c2a115d5.
2024-10-28 12:06:53 +01:00
Badlop bdd8ba115e Document ejabberd version of the new modules 2024-10-28 12:06:51 +01:00
Badlop 71ad7c368d Minor improvements to support mod_tombstones
New check_register_user hook in ejabberd_auth.erl
to allow blocking account registration when a tombstone exists.

Modified room_destroyed hook in mod_muc_room.erl
Until now the hook passed as arguments: LServer, Room, Host.
Now it passes: LServer, Room, Host, Persistent
That new Persistent argument passes the room persistent option,
required by mod_tombstones because only persistent rooms should generate
a tombstone, temporary ones should not.
And the persistent option should not be completely overwritten, as we must
still known its real value even when room is being destroyed.

mod_tombstones is available in experimental mode in ejabberd-contrib git.

Initial feature request: #2546
2024-10-28 12:06:48 +01:00
Paweł Chmielowski 8be0f8a0b0 Revert some unrelated changes 2024-10-28 09:44:05 +01:00
Paweł Chmielowski e9e678a994 Add support for scram upgrade tasks 2024-10-28 09:26:04 +01:00
Paweł Chmielowski a89152a3d7 Add support for s2s bidi 2024-10-28 09:25:56 +01:00
Badlop 46d5ab369f Update xmpp dependency 2024-10-21 17:23:59 +02:00
Badlop 81906b74ed Support "IQ permission" from XEP-0356 0.4.1 (#3889) 2024-10-21 17:23:59 +02:00
Badlop 74b0f64645 mod_block_strangers: Add feature announcement to disco-info (#4039) 2024-10-21 17:23:59 +02:00
Badlop 50948d1619 mod_mam: Advertise XEP-0424 feature in server disco-info (#3340) 2024-10-21 17:23:49 +02:00
Holger Weiss 38f1132192 ejabberd_stun: Omit 'auth_realm' log message
These days, TURN authentication is usually performed using ephemeral
credentials handed out by mod_stun_disco.  In that case, the TURN realm
is irrelevant.  Therefore, omit the misleading log message that warned
about a missing realm configuration.

(Commit 6eb2f07274 reduced the log level
of that message already.)
2024-10-15 22:50:30 +02:00
Badlop 50ef49d190 mod_vcard: Return explicit error stanza when user attempts to modify other's vcard 2024-10-11 11:54:18 +02:00
Badlop 3669ac8aed ejabberd_app: At server start, log Erlang and Elixir versions 2024-10-11 11:54:16 +02:00
Badlop 7f8519c0af ejabberdctl: If ERLANG_NODE lacks host, add hostname (#4288) 2024-10-11 11:49:34 +02:00
dependabot[bot] 859ba3e0c2 Bump dialyxir from 1.4.3 to 1.4.4
Bumps [dialyxir](https://github.com/jeremyjh/dialyxir) from 1.4.3 to 1.4.4.
- [Release notes](https://github.com/jeremyjh/dialyxir/releases)
- [Changelog](https://github.com/jeremyjh/dialyxir/blob/master/CHANGELOG.md)
- [Commits](https://github.com/jeremyjh/dialyxir/compare/1.4.3...1.4.4)

---
updated-dependencies:
- dependency-name: dialyxir
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-11 11:49:30 +02:00
Badlop 94c2a115d5 CI: Disable XMPP Interop specifications that are known to fail 2024-10-11 11:49:28 +02:00
badlop 634b646711 Merge pull request #4285 from guusdk/xmpp-interop-testing
CI: Add XMPP Interop tests
2024-10-11 11:03:26 +02:00
Holger Weiss 2a9dc2c7b2 make-binaries: Bump Erlang/OTP version to 26.2.5.4 2024-10-09 15:37:47 +02:00
Holger Weiss ef93a5359b Bump 'xmpp' dependency tag
This fixes announcing SASL2 over non-TLS connections if
'allow_unencrypted_sasl2' is configured.
2024-10-08 17:38:11 +02:00
Badlop efb1fc9b3f mod_register: Document behavior when access is set to none (#4078) 2024-10-01 15:57:19 +02:00
Badlop aa5faf1f36 mod_privilege: Replace try...catch with a clean alternative 2024-10-01 15:57:15 +02:00
Holger Weiss 4723283896 ejabberd_c2s: Optionally allow unencrypted SASL2
XEP-0388 says: "SASL2 MUST only be used by Clients or offered by Servers
after TLS negotiation".  Therefore, we reject SASL2 negotiations over
unencrypted transports by default.  However, TLS might be terminated
outside of ejabberd.  Add the 'allow_unencrypted_sasl2' option to
support this use case.
2024-09-29 20:40:01 +02:00
Holger Weiss 36187e07d0 mod_pubsub: Fall back to default plugin options
If the plugin handling a node creation request isn't enabled, fall back
to applying the default plugin (currently node_flat) options.
2024-09-28 17:58:07 +02:00
Holger Weiss a9583b43c3 mod_pubsub: Fix choice of node config defaults
Ignore node plugin defaults if the plugin handling the request isn't
enabled, rather than ignoring 'default_node_config' options and
applying plugin defaults in that case.
2024-09-28 17:51:28 +02:00
Holger Weiss ca54f81f58 mod_pubsub: Fix merging of default node options
Use any option specified via 'default_node_config' by default, and take
the remaining defaults from the node plugin handling the request.  This
is the documented behavior.

Before this change, the code applied the plugin defaults only if no
'default_node_config' existed at all.  And even this logic didn't work
as intended, since 'default_node_config' yielded an empty list in case
it wasn't configured, which resulted in plugin defaults never being
applied.
2024-09-28 16:56:46 +02:00
Holger Weiss b4399291ef mod_pubsub: Fix default node config parsing
Don't merge 'default_node_config' settings with the default options of
the first configured node plugin.  Otherwise, the latter might later
override those of the plugin that should handle a node creation request.
For example, the following configuration would lead to the 'flat'
options being used by default for 'pep' nodes as well:

  mod_pubsub:
    plugins:
      - flat
      - pep
2024-09-28 16:45:59 +02:00
Guus der Kinderen a8df58f056 CI: Limit execution of XMPP Interop tests
Run the XMPP Interop tests on only one build of the CI-matrix. This prevents redundant testing, as well as logs overwriting each-other.
2024-09-27 09:55:18 +02:00
Guus der Kinderen 54a89b39fb CI: Add XMPP Interop tests
Modifies the CI build to integrate the GitHub Action-based test runner from the [XMPP Interop Testing project](https://xmpp-interop-testing.github.io). This executes additional integration tests that help verify ejabberd's compliance with XMPP specifications.

In this commit, none of the tests are excluded, which likely results in false positives. Therefor, the 'continue-on-error' flag is set. This should ideally be removed in a later commit.
2024-09-26 21:45:51 +02:00
Badlop 4a931b42ab hooks_deps: Hide false-positive warnings about gen_mod 2024-09-24 12:37:06 +02:00
Badlop 15d73b9d20 Support to block IPs in a vhost using append_host_config (#4038) 2024-09-24 12:20:16 +02:00
Badlop c2d4f73893 Move some modules webadmin pages to their modules 2024-09-16 17:50:47 +02:00
Badlop 31b85351f2 Add new "MAM Archive" page to webadmin 2024-09-16 17:50:46 +02:00
Badlop c900f0ad83 WebAdmin: Improve pages to handle disabled modules 2024-09-16 17:50:44 +02:00
Badlop b2e6749fd2 Fix dialyzer: captcha_cmd is a binary for sure 2024-09-16 17:50:43 +02:00
Badlop 2437dc4e06 New command get_mam_count to get number of archived messages for an account 2024-09-16 17:50:42 +02:00
Badlop 115e7d08aa Add links in user page to offline and roster pages 2024-09-16 17:50:40 +02:00
Badlop d9ddbe0212 Add mam and offline tags to the related purge commands 2024-09-16 17:50:39 +02:00
Badlop 512285e48d Result of running "make options" 2024-09-16 17:50:38 +02:00
Badlop 642e7ecc29 mod_matrix_gw: Remove useless option "persist" 2024-09-16 17:50:37 +02:00
Badlop ce5a8acaf7 Define the types of options that opt_type.sh cannot derive automatically 2024-09-16 17:50:33 +02:00
Holger Weiss 3d9a5a1635 Fix 'update' command output
So far, ejabberd_update:update/0 returned the return value of
release_handler_1:eval_script/1.  That function returns the list of
updated but unpurged modules, i.e., modules where one or more processes
are still running an old version of the code.  Since commit
5a34020d23, the ejabberd 'update' command
assumes that value to be the list of updated modules instead.  As
that seems more useful, modify ejabberd_update:update/0 accordingly.
This fixes the 'update' command output.
2024-09-14 21:54:01 +02:00
Holger Weiss 3469a51f58 mod_pubsub: Don't blindly echo PEP notification
Since commit 514c25caef, whenever a PEP
item was published, a notification was blindly sent back to the owner.
However, this should only be done subject to +notify filtering, as per
XEP-0163:

| the PEP service shall send notifications to all of the account owner's
| available resources (subject to notification filtering).

The motivation for the mentioned commit was that +notify subscriptions
initially didn't work for PEP node owners (#2108).  However, that issue
was fixed by commit 5968bc9318 (#2112).
As a result, the owner's client was actually notified twice if the
client was subscribed to the node (e.g., via +notify).

Therefore, just omit the additional, blind notification.

Thanks to W. Martin Borgert and Daniel Gultsch for reporting the issue.
2024-09-13 20:50:00 +02:00
Paweł Chmielowski d4b30957a3 Skip non-delivery errors for local pubsub generated notifications
Those are ignored by pubsub service anyway, so we can skip those, and
reduce number of messages processed by pubsub process.
2024-09-11 13:20:53 +02:00
Badlop cc377bbebf Update lock files 2024-09-11 11:39:39 +02:00
Badlop eec836239f Improve documentation of ldap_servers and ldap_backups options (#3977) 2024-09-11 11:39:34 +02:00
Badlop 941d51a6e7 Handle call by gen_event:swap_handler (#4233) 2024-09-11 11:39:30 +02:00
Holger Weiss e3243fa35b make-binaries: Update OpenSSL URLs 2024-09-06 19:18:32 +02:00
Holger Weiss 70512c7116 make-binaries: Bump dependency versions 2024-09-06 19:05:12 +02:00
Paweł Chmielowski 3c896d1c6a Better handling of malformed jids in send_direct_invitation command 2024-09-02 12:49:39 +02:00
Paweł Chmielowski b455d93c69 Fix dialyzer warnings 2024-09-02 12:42:55 +02:00
Paweł Chmielowski 017b2feac1 Make set_presence command return error when session not found
Should fix issue #4274
2024-09-02 12:01:56 +02:00
Paweł Chmielowski 5f47860ee1 Remove support for old websocket connection protocol
This removes handling of pre-rfc7395 encapsulation of xmpp in websocket
(where data send in websocket was using just raw data as send in regular
socket). This didn't work correctly for last 5 years, and as we didn't
see complains about this, we can assume it's not used anymore.
2024-09-02 11:55:46 +02:00
Badlop 795498fa45 Runtime: Cache hex.pm archive from rebar3 and mix 2024-08-26 15:50:25 +02:00
Badlop aa1717ee77 CI: Add Elvis tests 2024-08-26 15:50:25 +02:00
Badlop db6d3e63f2 Fix Elvis report: Fix dollar space syntax
https://github.com/inaka/elvis_core/blob/main/doc_rules/elvis_style/no_dollar_space.md
2024-08-26 15:50:25 +02:00
Badlop 0304428d95 Fix Elvis report: Remove spaces in weird places
https://github.com/inaka/elvis_core/blob/main/doc_rules/elvis_style/no_space.md
2024-08-26 15:50:25 +02:00
Badlop 74b80bfe08 Fix Elvis report: Don't use ignored variables
https://github.com/inaka/elvis_core/blob/main/doc_rules/elvis_style/used_ignored_variable.md
2024-08-26 15:48:32 +02:00
Badlop 90ce65e4dc Fix Elvis report: Remove trailing whitespace characters
https://github.com/inaka/elvis_core/blob/main/doc_rules/elvis_text_style/no_trailing_whitespace.md
2024-08-26 15:48:32 +02:00
Badlop d4d9771a71 Makefile: Add support for "make elvis" when using rebar3 2024-08-26 15:48:32 +02:00
Badlop 70ee294079 elvis.config: Fix file syntax, set vim mode, disable many tests
Let's disable the tests that would require major changes in existing
ejabberd source code, and fixing them would produce a curtain of changes
that would difficult using git blame and git log, but provide minimal
benefits.

Don't check erlang header files by now.

Don't check rebar.config because it has customizations that must be
parsed by rebar.config.script to have suitable syntax.
2024-08-26 15:48:32 +02:00
Badlop 5f4d17621f Fix Erlang LS warning about unused macro definitions
Macro name + commit when it was added - commit when usage was removed:

* BATCH_SIZE + f6db8428 - 71c44bff8
* INVALID_SETTING_MSG - 6b126171d - 381065397
* POLICY_ACCESS + 7c1e7e5b - 56d273477
* PROCNAME + 068db1a2 - 6876a37e6
* SALT_LENGTH + e575c87e - 633b68db1
* SERVER + 068db1a2 - but was never used!
* SERVER + f44e23b8c - but was never used!
* STORAGE_TYPES + 92db9ff1 - 9a93acc62
* TCP_SEND_TIMEOUT + f0af10e6 - 6e900d6a8
* TDTD + c3280e9 - 5a34020
* TVFIELD + dcc05ac8 - da310a517
2024-08-26 15:48:32 +02:00
Badlop 8f4179050b erlang_ls.config: Let it find paths, update to Erlang 26, enable crossref 2024-08-26 15:48:32 +02:00
Badlop fddacd51a4 .vscode/launch.json: Experimental support for debugging with Neovim 2024-08-26 15:48:32 +02:00
Badlop e726ba9a8b .vscode/relive.sh: Update to benefit from ejabberd 24.02 behaviour 2024-08-26 15:48:32 +02:00
Badlop da1673e264 mix.lock: Don't mention Relive deps, otherwise they are always downloaded 2024-08-26 15:48:32 +02:00
Badlop 7cd34d3709 CONTAINER.md: Use same general badges in both container images readme files 2024-08-26 15:48:32 +02:00
Paweł Chmielowski ec7fd05987 Update xmpp once more 2024-08-24 15:27:58 +02:00
Paweł Chmielowski 34a58863e3 Update xmpp dep 2024-08-24 13:16:03 +02:00
Paweł Chmielowski 3237a955e5 Fix dep spec for rebar2 2024-08-23 20:56:52 +02:00
Paweł Chmielowski 8e7489c2be Remove duplicate dep from mix.exs 2024-08-23 20:52:36 +02:00
Paweł Chmielowski df5202a2f0 Update deps to bring improved s2s fallback for invalid direct tls connections
This allows connections to server that have both xmpps-server and xmpp-server
srv entries, for which xmpps version doesn't work correctly. Before this
change we would stop on non-working xmpps server, now we will also attempt
to connect further servers on list.
2024-08-23 20:48:53 +02:00
Badlop db3a5d8915 Start ExSync manually to ensure it's started if (and only if) Relive 2024-08-21 10:51:59 +02:00
Badlop 6110f213de Return error stanza when storage doesn't support vcard update (#4266) 2024-08-21 10:51:56 +02:00
Badlop e99fe98db4 Remove from extra_applications the apps already defined in deps (#4265) 2024-08-21 10:51:53 +02:00
Michael Slezak b07e28be2c Fix 'mix release' error: logger being regular and included application (#4265) 2024-08-21 10:51:51 +02:00
Badlop 937d5fe495 Document which SQL servers can really use update_sql_schema 2024-08-21 10:51:49 +02:00
Badlop 01141e5f69 Relax password complexity in test database
This password is not strong enough in MSSQL 2022, relax this restriction
  https://learn.microsoft.com/en-us/sql/relational-databases/security/password-policy?view=sql-server-ver16
  https://learn.microsoft.com/en-us/sql/t-sql/statements/create-login-transact-sql?view=sql-server-ver16#check_policy---on--off-
2024-08-21 10:51:46 +02:00
Badlop 15569d0b13 Add links in top-level options documentation to their Docs website sections 2024-08-12 16:25:42 +02:00
Badlop 918806006c Update fast_xml to use use_maps and remove obsolete elixir files 2024-08-09 12:31:37 +02:00
Badlop d5e030a638 CI: Tell sqlcmd to trust server self-signed certificate
As explained in
https://techcommunity.microsoft.com/t5/sql-server-blog/odbc-driver-18-0-for-sql-server-released/ba-p/3169228

Version 18.0 of the Microsoft ODBC Driver 18 for SQL Server has been released.
BREAKING CHANGE - Default Encrypt to Yes/Mandatory.
2024-08-09 12:31:35 +02:00
Badlop 47f1beca0c CI: Update path to sqlcmd command in the mssql container
As mentioned in
https://learn.microsoft.com/en-us/sql/linux/quickstart-install-connect-docker

Starting with SQL Server 2022 (16.x) CU 14 and SQL Server 2019 (15.x)
CU 28, the container images include the new mssql-tools18 package.
The previous directory /opt/mssql-tools/bin is being phased out.
The new directory for Microsoft ODBC 18 tools is /opt/mssql-tools18/bin,
aligning with the latest tools offering.
2024-08-09 12:31:34 +02:00
Badlop a565b0e4c1 ext_mod: Handle info message when contrib module transfers table ownership 2024-08-09 12:31:29 +02:00
Badlop 10d1704899 mod_muc_rtbl: Fix call to gen_server:stop (#4260) 2024-07-22 13:28:47 +02:00
Badlop bc7c8e3952 Handle case when elixir support is enabled but not available
This happens when:
./configure --with-rebar=rebar3 --enable-elixir
make
rebar3 ct
2024-07-19 18:08:02 +02:00
Paweł Chmielowski 4e35515a8c Also change mysql.new.sql in similar way 2024-07-18 17:55:37 +02:00
Paweł Chmielowski d2a3fe3ed2 Fix column type in comment with schema update 2024-07-18 17:13:45 +02:00
98 changed files with 1804 additions and 635 deletions
+28 -8
View File
@@ -68,8 +68,8 @@ jobs:
- name: Prepare databases
run: |
docker exec ejabberd-mssql /opt/mssql-tools/bin/sqlcmd -U SA -P ejabberd_Test1 -S localhost -i /initdb_mssql.sql
docker exec ejabberd-mssql /opt/mssql-tools/bin/sqlcmd -U SA -P ejabberd_Test1 -S localhost -d ejabberd_test -i /mssql.sql
docker exec ejabberd-mssql /opt/mssql-tools18/bin/sqlcmd -C -U SA -P ejabberd_Test1 -S localhost -i /initdb_mssql.sql
docker exec ejabberd-mssql /opt/mssql-tools18/bin/sqlcmd -C -U SA -P ejabberd_Test1 -S localhost -d ejabberd_test -i /mssql.sql
sudo systemctl start mysql.service
sudo systemctl start postgresql.service
mysql -u root -proot -e "CREATE DATABASE ejabberd_test;"
@@ -100,7 +100,7 @@ jobs:
- name: Remove syntax_tools from release
run: sed -i 's|, syntax_tools||g' src/ejabberd.app.src.script
- name: Cache rebar
- name: Cache Hex.pm
uses: actions/cache@v4
with:
path: |
@@ -133,6 +133,8 @@ jobs:
- run: make xref
- run: make dialyzer
- run: make test-eunit
- run: make elvis
if: matrix.otp >= 23
- name: Check Production Release
run: |
@@ -145,12 +147,30 @@ jobs:
cat $RE/logs/ejabberd.log
grep -q "is stopped in" $RE/logs/ejabberd.log
- name: Check Development Release
- name: Start Development Release
run: |
make dev
RE=_build/dev/rel/ejabberd
sed -i 's/starttls_required: true/starttls_required: false/g' $RE/conf/ejabberd.yml
$RE/bin/ejabberdctl start
$RE/bin/ejabberdctl started
$RE/bin/ejabberdctl register admin localhost admin
grep -q "is started in" $RE/logs/ejabberd.log
- name: Run XMPP Interoperability Tests against CI server.
if: matrix.otp == '26'
continue-on-error: true
uses: XMPP-Interop-Testing/xmpp-interop-tests-action@v1.4.0
with:
domain: 'localhost'
adminAccountUsername: 'admin'
adminAccountPassword: 'admin'
disabledSpecifications: RFC6121,XEP-0030,XEP-0045,XEP-0054,XEP-0060,XEP-0080,XEP-0115,XEP-0118,XEP-0215,XEP-0347,XEP-0363,XEP-0384
- name: Stop Development Release
if: always()
run: |
RE=_build/dev/rel/ejabberd
$RE/bin/ejabberdctl stop
$RE/bin/ejabberdctl stopped
cat $RE/logs/ejabberd.log
@@ -256,12 +276,12 @@ jobs:
run: |
[[ -d logs ]] && rm -rf logs
[[ -d _build/test/logs ]] && rm -rf _build/test/logs || true
docker exec ejabberd-mssql /opt/mssql-tools/bin/sqlcmd -U SA -P ejabberd_Test1 -S localhost -Q "drop database [ejabberd_test];"
docker exec ejabberd-mssql /opt/mssql-tools/bin/sqlcmd -U SA -P ejabberd_Test1 -S localhost -Q "drop login [ejabberd_test];"
docker exec ejabberd-mssql /opt/mssql-tools18/bin/sqlcmd -C -U SA -P ejabberd_Test1 -S localhost -Q "drop database [ejabberd_test];"
docker exec ejabberd-mssql /opt/mssql-tools18/bin/sqlcmd -C -U SA -P ejabberd_Test1 -S localhost -Q "drop login [ejabberd_test];"
mysql -u root -proot -e "DROP DATABASE ejabberd_test;"
sudo -u postgres psql -c "DROP DATABASE ejabberd_test;"
docker exec ejabberd-mssql /opt/mssql-tools/bin/sqlcmd -U SA -P ejabberd_Test1 -S localhost -i /initdb_mssql.sql
docker exec ejabberd-mssql /opt/mssql-tools/bin/sqlcmd -U SA -P ejabberd_Test1 -S localhost -d ejabberd_test -i /mssql.new.sql
docker exec ejabberd-mssql /opt/mssql-tools18/bin/sqlcmd -C -U SA -P ejabberd_Test1 -S localhost -i /initdb_mssql.sql
docker exec ejabberd-mssql /opt/mssql-tools18/bin/sqlcmd -C -U SA -P ejabberd_Test1 -S localhost -d ejabberd_test -i /mssql.new.sql
mysql -u root -proot -e "CREATE DATABASE ejabberd_test;"
mysql -u root -proot -e "GRANT ALL ON ejabberd_test.*
TO 'ejabberd_test'@'localhost';"
+21
View File
@@ -61,6 +61,13 @@ jobs:
apt-get -qq install libexpat1-dev libgd-dev libpam0g-dev \
libsqlite3-dev libwebp-dev libyaml-dev
- name: Cache Hex.pm
uses: actions/cache@v4
with:
path: |
~/.cache/rebar3/
key: ${{matrix.otp}}-${{hashFiles('rebar.config')}}
- name: Compile
run: |
./autogen.sh
@@ -204,6 +211,13 @@ jobs:
sed -i 's|^{deps, \[\(.*\)|{deps, [{decimal, ".*", {git, "https://github.com/ericmj/decimal", {branch, "main"}}},\n \1|g' rebar.config
cat rebar.config
- name: Cache Hex.pm
uses: actions/cache@v4
with:
path: |
~/.cache/rebar3/
key: ${{matrix.otp}}-${{hashFiles('rebar.config')}}
- name: Compile
run: |
./autogen.sh
@@ -347,6 +361,13 @@ jobs:
run: |
mix deps.unlock jose
- name: Cache Hex.pm
uses: actions/cache@v4
with:
path: |
~/.hex/
key: ${{matrix.otp}}-${{hashFiles('mix.exs')}}
- name: Compile
run: |
./autogen.sh
+17
View File
@@ -1,6 +1,23 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Relive (Vim)",
"type": "erlang",
"request": "launch",
"runinterminal": [
"./rebar3", "shell",
"--apps", "ejabberd",
"--config", "rel/relive.config",
"--script", "rel/relive.escript",
"--name", "ejabberd@localhost",
"--setcookie", "COOKIE"
],
"projectnode": "ejabberd@localhost",
"cookie": "COOKIE",
"timeout": 900,
"cwd": "."
},
{
"name": "Relive",
"type": "erlang",
+1 -1
View File
@@ -1,6 +1,6 @@
[ ! -f Makefile ] \
&& ./autogen.sh \
&& ./configure --with-rebar=./rebar3 \
&& ./configure --with-rebar=rebar3 \
&& make deps
make relive
+80
View File
@@ -1,3 +1,83 @@
## Version 24.10
#### Miscelanea
- `ejabberd_c2s`: Optionally allow unencrypted SASL2
- `ejabberd_system_monitor`: Handle call by `gen_event:swap_handler` ([#4233](https://github.com/processone/ejabberd/issues/4233))
- `ejabberd_http_ws`: Remove support for old websocket connection protocol
- `ejabberd_stun`: Omit `auth_realm` log message
- `ext_mod`: Handle `info` message when contrib module transfers table ownership
- `mod_block_strangers`: Add feature announcement to disco-info ([#4039](https://github.com/processone/ejabberd/issues/4039))
- `mod_mam`: Advertise XEP-0424 feature in server disco-info ([#3340](https://github.com/processone/ejabberd/issues/3340))
- `mod_muc_admin`: Better handling of malformed jids in `send_direct_invitation` command
- `mod_muc_rtbl`: Fix call to `gen_server:stop` ([#4260](https://github.com/processone/ejabberd/issues/4260))
- `mod_privilege`: Support "IQ permission" from XEP-0356 0.4.1 ([#3889](https://github.com/processone/ejabberd/issues/3889))
- `mod_pubsub`: Don't blindly echo PEP notification
- `mod_pubsub`: Skip non-delivery errors for local pubsub generated notifications
- `mod_pubsub`: Fall back to default plugin options
- `mod_pubsub`: Fix choice of node config defaults
- `mod_pubsub`: Fix merging of default node options
- `mod_pubsub`: Fix default node config parsing
- `mod_register`: Support to block IPs in a vhost using `append_host_config` ([#4038](https://github.com/processone/ejabberd/issues/4038))
- `mod_s2s_bidi`: Add support for S2S Bidirectional
- `mod_scram_upgrade`: Add support for SCRAM upgrade tasks
- `mod_vcard`: Return error stanza when storage doesn't support vcard update ([#4266](https://github.com/processone/ejabberd/issues/4266))
- `mod_vcard`: Return explicit error stanza when user attempts to modify other's vcard
- Minor improvements to support `mod_tombstones` (#2456)
- Update `fast_xml` to use `use_maps` and remove obsolete elixir files
- Update `fast_tls` and `xmpp` to improve s2s fallback for invalid direct tls connections
- `make-binaries`: Bump dependency versions: Elixir 1.17.2, OpenSSL 3.3.2, ...
#### Administration
- `ejabberdctl`: If `ERLANG_NODE` lacks host, add hostname ([#4288](https://github.com/processone/ejabberd/issues/4288))
- `ejabberd_app`: At server start, log Erlang and Elixir versions
- MySQL: Fix column type in the schema update of `archive` table in schema update
#### Commands API
- `get_mam_count`: New command to get number of archived messages for an account
- `set_presence`: Return error when session not found
- `update`: Fix command output
- Add `mam` and `offline` tags to the related purge commands
#### Code Quality
- Fix warnings about unused macro definitions reported by Erlang LS
- Fix Elvis report: Fix dollar space syntax
- Fix Elvis report: Remove spaces in weird places
- Fix Elvis report: Don't use ignored variables
- Fix Elvis report: Remove trailing whitespace characters
- Define the types of options that `opt_type.sh` cannot derive automatically
- `ejabberd_http_ws`: Fix dialyzer warnings
- `mod_matrix_gw`: Remove useless option `persist`
- `mod_privilege`: Replace `try...catch` with a clean alternative
#### Development Help
- `elvis.config`: Fix file syntax, set vim mode, disable many tests
- `erlang_ls.config`: Let it find paths, update to Erlang 26, enable crossref
- `hooks_deps`: Hide false-positive warnings about `gen_mod`
- `Makefile`: Add support for `make elvis` when using rebar3
- `.vscode/launch.json`: Experimental support for debugging with Neovim
- CI: Add Elvis tests
- CI: Add XMPP Interop tests
- Runtime: Cache hex.pm archive from rebar3 and mix
#### Documentation
- Add links in top-level options documentation to their Docs website sections
- Document which SQL servers can really use `update_sql_schema`
- Improve documentation of `ldap_servers` and `ldap_backups` options ([#3977](https://github.com/processone/ejabberd/issues/3977))
- `mod_register`: Document behavior when `access` is set to `none` ([#4078](https://github.com/processone/ejabberd/issues/4078))
#### Elixir
- Handle case when elixir support is enabled but not available
- Start ExSync manually to ensure it's started if (and only if) Relive
- `mix.exs`: Fix `mix release` error: `logger` being regular and included application ([#4265](https://github.com/processone/ejabberd/issues/4265))
- `mix.exs`: Remove from `extra_applications` the apps already defined in `deps` ([#4265](https://github.com/processone/ejabberd/issues/4265))
#### WebAdmin
- Add links in user page to offline and roster pages
- Add new "MAM Archive" page to webadmin
- Improve many pages to handle when modules are disabled
- `mod_admin_extra`: Move some webadmin pages to their modules
## Version 24.07
#### Core
+2 -2
View File
@@ -1,7 +1,7 @@
[![GitHub tag (latest SemVer)](https://img.shields.io/github/v/tag/processone/ejabberd?sort=semver&logo=embarcadero&label=&color=49c0c4)](https://github.com/processone/ejabberd/tags)
[![GitHub Container](https://img.shields.io/github/v/tag/processone/ejabberd?label=ejabberd&sort=semver&logo=docker)](https://github.com/processone/ejabberd/pkgs/container/ejabberd)
[![ejabberd Container on GitHub](https://img.shields.io/github/v/tag/processone/ejabberd?label=ejabberd&sort=semver&logo=docker)](https://github.com/processone/ejabberd/pkgs/container/ejabberd)
[![ecs Container on Docker](https://img.shields.io/docker/v/ejabberd/ecs?label=ecs&sort=semver&logo=docker)](https://hub.docker.com/r/ejabberd/ecs/)
`ejabberd` Container Image
==========================
+8
View File
@@ -642,6 +642,13 @@ dialyzer: erlang_plt deps_plt ejabberd_plt
endif
endif
#.
#' elvis
#
elvis:
$(REBAR) lint
#.
#' test
#
@@ -699,6 +706,7 @@ help:
@echo " indent Indent source code using erlang-mode [emacs]"
@echo ""
@echo " dialyzer Run Dialyzer static analyzer"
@echo " elvis Run Elvis source code style reviewer [rebar3]"
@echo " hooks Run hooks validator"
@echo " test Run Common Tests suite [rebar3]"
@echo " test-eunit Run EUnit suite [rebar3]"
+1 -1
View File
@@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.59)
AC_INIT(ejabberd, m4_esyscmd([echo `git describe --tags 2>/dev/null || echo 24.07` | sed 's/-g.*//;s/-/./' | tr -d '\012']), [ejabberd@process-one.net], [ejabberd])
AC_INIT(ejabberd, m4_esyscmd([echo `git describe --tags 2>/dev/null || echo 24.10` | sed 's/-g.*//;s/-/./' | tr -d '\012']), [ejabberd@process-one.net], [ejabberd])
REQUIRE_ERLANG_MIN="9.0.5 (Erlang/OTP 20.0)"
REQUIRE_ERLANG_MAX="100.0.0 (No Max)"
+20 -2
View File
@@ -566,6 +566,15 @@
<xmpp:note>mod_carboncopy</xmpp:note>
</xmpp:SupportedXep>
</implements>
<implements>
<xmpp:SupportedXep>
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0288.html"/>
<xmpp:version>1.0.1</xmpp:version>
<xmpp:since>24.10</xmpp:since>
<xmpp:status>complete</xmpp:status>
<xmpp:note>mod_s2s_bidi</xmpp:note>
</xmpp:SupportedXep>
</implements>
<implements>
<xmpp:SupportedXep>
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0313.html"/>
@@ -623,8 +632,8 @@
<implements>
<xmpp:SupportedXep>
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0356.html"/>
<xmpp:version>0.2.1</xmpp:version>
<xmpp:since>16.09</xmpp:since>
<xmpp:version>0.4.1</xmpp:version>
<xmpp:since>24.10</xmpp:since>
<xmpp:status></xmpp:status>
<xmpp:note>mod_privilege</xmpp:note>
</xmpp:SupportedXep>
@@ -791,6 +800,15 @@
<xmpp:note></xmpp:note>
</xmpp:SupportedXep>
</implements>
<implements>
<xmpp:SupportedXep>
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0480.html"/>
<xmpp:version>0.1</xmpp:version>
<xmpp:since>24.10</xmpp:since>
<xmpp:status>complete</xmpp:status>
<xmpp:note>mod_scram_upgrade</xmpp:note>
</xmpp:SupportedXep>
</implements>
<implements>
<xmpp:SupportedXep>
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0485.html"/>
+1
View File
@@ -227,6 +227,7 @@ modules:
ip_access: trusted_network
mod_roster:
versioning: true
mod_s2s_bidi: {}
mod_s2s_dialback: {}
mod_shared_roster: {}
mod_stream_mgmt:
+1
View File
@@ -66,6 +66,7 @@ done
# shellcheck source=ejabberdctl.cfg.example
[ -f "$EJABBERDCTL_CONFIG_PATH" ] && . "$EJABBERDCTL_CONFIG_PATH"
[ -n "$ERLANG_NODE_ARG" ] && ERLANG_NODE="$ERLANG_NODE_ARG"
[ "$ERLANG_NODE" = "${ERLANG_NODE%@*}" ] && ERLANG_NODE="$ERLANG_NODE@$(hostname -s)"
[ "$ERLANG_NODE" = "${ERLANG_NODE%.*}" ] && S="-s"
: "${SPOOL_DIR:="{{spool_dir}}"}"
: "${EJABBERD_LOG_PATH:="$LOGS_DIR/ejabberd.log"}"
+37 -21
View File
@@ -5,38 +5,54 @@
{config,
[#{dirs => ["src"],
filter => "*.erl",
ignore => ['ELDAPv3', eldap_filter_yecc],
ruleset => erl_files,
rules => [{elvis_style, line_length, #{limit => 100,
skip_comments => false}},
rules => [{elvis_text_style, line_length, #{limit => 1000, skip_comments => false}},
{elvis_text_style, no_tabs, disable},
{elvis_style, no_debug_call, disable},
{elvis_style, operator_spaces, disable},
{elvis_style, atom_naming_convention, disable},
{elvis_style, consistent_variable_casing, disable},
{elvis_style, dont_repeat_yourself, #{min_complexity => 70}},
{elvis_style, export_used_types, disable},
{elvis_style, function_naming_convention, disable},
{elvis_style, god_modules, #{limit => 300}},
{elvis_style, invalid_dynamic_call, disable},
{elvis_style, variable_naming_convention, #{ regex => ".*" }},
{elvis_style, dont_repeat_yourself, #{min_complexity => 20}}
]
{elvis_style, macro_module_names, disable},
{elvis_style, macro_names, disable},
{elvis_style, max_function_arity, disable}, % #{max_arity => 15}},
{elvis_style, nesting_level, disable},
{elvis_style, no_author, disable},
{elvis_style, no_catch_expressions, disable},
{elvis_style, no_debug_call, disable},
{elvis_style, no_if_expression, disable},
{elvis_style, no_import, disable},
{elvis_style, no_match_in_condition, disable},
{elvis_style, no_nested_try_catch, disable},
{elvis_style, no_single_clause_case, disable},
{elvis_style, no_spec_with_records, disable},
{elvis_style, no_throw, disable},
{elvis_style, operator_spaces, disable},
{elvis_style, param_pattern_matching, disable},
{elvis_style, private_data_types, disable},
{elvis_style, variable_naming_convention, disable}
]
},
%#{dirs => ["include"],
% filter => "*.hrl",
% ruleset => hrl_files},
#{dirs => ["."],
filter => "Makefile.in",
ruleset => makefiles,
rules => [{elvis_style, line_length, #{limit => 100,
rules => [{elvis_text_style, line_length, #{limit => 400,
skip_comments => false}},
{elvis_style, no_tabs, disable},
{elvis_style, dont_repeat_yourself, #{min_complexity => 20}}
]
},
#{dirs => ["."],
filter => "rebar.config",
ruleset => rebar_config,
rules => [{elvis_style, line_length, #{limit => 100,
skip_comments => false}},
{elvis_style, no_tabs, disable},
{elvis_style, dont_repeat_yourself, #{min_complexity => 20}}
]
{elvis_style, dont_repeat_yourself, #{min_complexity => 20}}
]
}
}
]
}
]
}
].
%% vim: set filetype=erlang tabstop=8:
+5 -5
View File
@@ -1,5 +1,5 @@
otp_path: "/usr/lib/erlang"
plt_path: "_build/default/rebar3_24.3.3_plt"
#otp_path: "/usr/lib/erlang"
#plt_path: "_build/default/rebar3_24.3.3_plt"
#code_reload:
# node: ejabberd@localhost
apps_dirs:
@@ -14,12 +14,12 @@ macros:
- name: DEPRECATED_GET_STACKTRACE
- name: HAVE_ERL_ERROR
- name: HAVE_URI_STRING
- name: OTP_BELOW_25
- name: OTP_BELOW_27
- name: SIP
- name: STUN
diagnostics:
# enabled:
# - crossref
enabled:
- crossref
disabled:
# - dialyzer
- unused_includes # Otherwise it complains about unused logger.hrl
+1 -1
View File
@@ -44,7 +44,7 @@
allow_visitor_nickchange = true :: boolean(),
public = true :: boolean(),
public_list = true :: boolean(),
persistent = false :: boolean(),
persistent = false :: boolean() | {destroying, boolean()},
moderated = true :: boolean(),
captcha_protected = false :: boolean(),
members_by_default = true :: boolean(),
+206 -59
View File
@@ -2,12 +2,12 @@
.\" Title: ejabberd.yml
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
.\" Date: 07/18/2024
.\" Date: 10/28/2024
.\" Manual: \ \&
.\" Source: \ \&
.\" Language: English
.\"
.TH "EJABBERD\&.YML" "5" "07/18/2024" "\ \&" "\ \&"
.TH "EJABBERD\&.YML" "5" "10/28/2024" "\ \&" "\ \&"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -82,12 +82,12 @@ All options can be changed in runtime by running \fIejabberdctl reload\-config\f
.sp
Some options can be specified for particular virtual host(s) only using \fIhost_config\fR or \fIappend_host_config\fR options\&. Such options are called \fIlocal\fR\&. Examples are \fImodules\fR, \fIauth_method\fR and \fIdefault_db\fR\&. The options that cannot be defined per virtual host are called \fIglobal\fR\&. Examples are \fIloglevel\fR, \fIcertfiles\fR and \fIlisten\fR\&. It is a configuration mistake to put \fIglobal\fR options under \fIhost_config\fR or \fIappend_host_config\fR section \- ejabberd will refuse to load such configuration\&.
.sp
It is not recommended to write ejabberd\&.yml from scratch\&. Instead it is better to start from "default" configuration file available at https://github\&.com/processone/ejabberd/blob/24\&.07/ejabberd\&.yml\&.example\&. Once you get ejabberd running you can start changing configuration options to meet your requirements\&.
It is not recommended to write ejabberd\&.yml from scratch\&. Instead it is better to start from "default" configuration file available at https://github\&.com/processone/ejabberd/blob/24\&.10/ejabberd\&.yml\&.example\&. Once you get ejabberd running you can start changing configuration options to meet your requirements\&.
.sp
Note that this document is intended to provide comprehensive description of all configuration options that can be consulted to understand the meaning of a particular option, its format and possible values\&. It will be quite hard to understand how to configure ejabberd by reading this document only \- for this purpose the reader is recommended to read online Configuration Guide available at https://docs\&.ejabberd\&.im/admin/configuration\&.
.SH "TOP LEVEL OPTIONS"
.sp
This section describes top level options of ejabberd 24\&.07\&. The options that changed in this version are marked with 🟤\&.
This section describes top level options of ejabberd 24\&.10\&. The options that changed in this version are marked with 🟤\&.
.PP
\fBaccess_rules\fR: \fI{AccessName: {allow|deny: ACLRules|ACLName}}\fR
.RS 4
@@ -138,7 +138,8 @@ access_rules:
.PP
\fBacl\fR: \fI{ACLName: {ACLType: ACLValue}}\fR
.RS 4
The option defines access control lists: named sets of rules which are used to match against different targets (such as a JID or an IP address)\&. Every set of rules has name
This option defines
\fI\&.\&./configuration/basic\&.md#acl|access control lists\fR: named sets of rules which are used to match against different targets (such as a JID or an IP address)\&. Every set of rules has name
\fIACLName\fR: it can be any string except
\fIall\fR
or
@@ -319,7 +320,9 @@ means that the same username can be taken multiple times in anonymous login mode
.PP
\fBanonymous_protocol\fR: \fIlogin_anon | sasl_anon | both\fR
.RS 4
Define what anonymous protocol will be used:
Define what
\fIauthentication\&.md#anonymous\-login\-and\-sasl\-anonymous|anonymous\fR
protocol will be used:
.sp
.RS 4
.ie n \{\
@@ -368,11 +371,8 @@ Define the permissions for API access\&. Please consult the ejabberd Docs web
.PP
\fBappend_host_config\fR: \fI{Host: Options}\fR
.RS 4
To define specific ejabberd modules in a virtual host, you can define the global
\fImodules\fR
option with the common modules, and later add specific modules to certain virtual hosts\&. To accomplish that,
\fIappend_host_config\fR
option can be used\&.
Add a few specific options to a certain
\fI\&.\&./configuration/basic\&.md#virtual\-hosting|virtual host\fR\&.
.RE
.PP
\fBauth_cache_life_time\fR: \fItimeout()\fR
@@ -412,7 +412,9 @@ and certificate based authentication)\&. This helps with processing offline mess
.PP
\fBauth_method\fR: \fI[mnesia | sql | anonymous | external | jwt | ldap | pam, \&.\&.\&.]\fR
.RS 4
A list of authentication methods to use\&. If several methods are defined, authentication is considered successful as long as authentication of at least one of the methods succeeds\&. The default value is
A list of
\fIauthentication\&.md|authentication\fR
methods to use\&. If several methods are defined, authentication is considered successful as long as authentication of at least one of the methods succeeds\&. The default value is
\fI[mnesia]\fR\&.
.RE
.PP
@@ -682,7 +684,8 @@ A list of Erlang nodes to connect on ejabberd startup\&. This option is mostly i
.PP
\fBdefault_db\fR: \fImnesia | sql\fR
.RS 4
Default persistent storage for ejabberd\&. Modules and other components (e\&.g\&. authentication) may have its own value\&. The default value is
\fIdatabase\&.md#default\-database|Default database\fR
to store persistent data in ejabberd\&. Modules and other components (e\&.g\&. authentication) may have its own value\&. The default value is
\fImnesia\fR\&.
.RE
.PP
@@ -694,7 +697,8 @@ Default volatile (in\-memory) storage for ejabberd\&. Modules and other componen
.PP
\fBdefine_macro\fR: \fI{MacroName: MacroValue}\fR
.RS 4
Defines a macro\&. The value can be any valid arbitrary YAML value\&. For convenience, it\(cqs recommended to define a
Defines a
\fI\&.\&./configuration/file\-format\&.md#macros\-in\-configuration\-file|macro\fR\&. The value can be any valid arbitrary YAML value\&. For convenience, it\(cqs recommended to define a
\fIMacroName\fR
in capital letters\&. Duplicated macros are not allowed\&. Macros are processed after additional configuration files have been included, so it is possible to use macros that are defined in configuration files included before the usage\&. It is possible to use a
\fIMacroValue\fR
@@ -742,7 +746,9 @@ which enables this extension\&.
.PP
\fBdomain_balancing\fR: \fI{Domain: Options}\fR
.RS 4
An algorithm to load balance the components that are plugged on an ejabberd cluster\&. It means that you can plug one or several instances of the same component on each ejabberd node and that the traffic will be automatically distributed\&. The algorithm to deliver messages to the component(s) can be specified by this option\&. For any component connected as
An algorithm to
\fI\&.\&./guide/clustering\&.md#service\-load\-balancing|load\-balance\fR
the components that are plugged on an ejabberd cluster\&. It means that you can plug one or several instances of the same component on each ejabberd node and that the traffic will be automatically distributed\&. The algorithm to deliver messages to the component(s) can be specified by this option\&. For any component connected as
\fIDomain\fR, available
\fIOptions\fR
are:
@@ -821,18 +827,22 @@ Define the base URI when performing ReST requests\&. The default value is:
.PP
\fBextauth_pool_name\fR: \fIName\fR
.RS 4
Define the pool name appendix, so the full pool name will be
Define the pool name appendix in
\fIauthentication\&.md#external\-script|external auth\fR, so the full pool name will be
\fIextauth_pool_Name\fR\&. The default value is the hostname\&.
.RE
.PP
\fBextauth_pool_size\fR: \fISize\fR
.RS 4
The option defines the number of instances of the same external program to start for better load balancing\&. The default is the number of available CPU cores\&.
The option defines the number of instances of the same
\fIauthentication\&.md#external\-script|external auth\fR
program to start for better load balancing\&. The default is the number of available CPU cores\&.
.RE
.PP
\fBextauth_program\fR: \fIPath\fR
.RS 4
Indicate in this option the full path to the external authentication script\&. The script must be executable by ejabberd\&.
Indicate in this option the full path to the
\fIauthentication\&.md#external\-script|external authentication script\fR\&. The script must be executable by ejabberd\&.
.RE
.PP
\fBfqdn\fR: \fIDomain\fR
@@ -851,7 +861,8 @@ for backward compatibility\&.
.RS 4
The option is used to redefine
\fIOptions\fR
for virtual host
for
\fI\&.\&./configuration/basic\&.md#virtual\-hosting|virtual host\fR
\fIHost\fR\&. In the example below LDAP authentication method will be used on virtual host
\fIdomain\&.tld\fR
and SQL method will be used on virtual host
@@ -882,7 +893,9 @@ host_config:
.PP
\fBhosts\fR: \fI[Domain1, Domain2, \&.\&.\&.]\fR
.RS 4
The option defines a list containing one or more domains that
List of one or more
\fI\&.\&./configuration/basic\&.md#host\-names|host names\fR
(or domains) that
\fIejabberd\fR
will serve\&. This is a
\fBmandatory\fR
@@ -891,7 +904,9 @@ option\&.
.PP
\fBinclude_config_file\fR: \fI[Filename, \&.\&.\&.] | {Filename: Options}\fR
.RS 4
Read additional configuration from
Read and
\fI\&.\&./configuration/file\-format\&.md#include\-additional\-files|include additional file\fR
from
\fIFilename\fR\&. If the value is provided in
\fI{Filename: Options}\fR
format, the
@@ -922,7 +937,9 @@ at start time\&. The default value is an empty list of modules:
.PP
\fBjwt_auth_only_rule\fR: \fIAccessName\fR
.RS 4
This ACL rule defines accounts that can use only this auth method, even if others are also defined in the ejabberd configuration file\&. In other words: if there are several auth methods enabled for this host (JWT, SQL, \&...), users that match this rule can only use JWT\&. The default value is
This ACL rule defines accounts that can use only the
\fIauthentication\&.md#jwt\-authentication|JWT\fR
auth method, even if others are also defined in the ejabberd configuration file\&. In other words: if there are several auth methods enabled for this host (JWT, SQL, \&...), users that match this rule can only use JWT\&. The default value is
\fInone\fR\&.
.RE
.PP
@@ -930,18 +947,24 @@ This ACL rule defines accounts that can use only this auth method, even if other
.RS 4
By default, the JID is defined in the
\fI"jid"\fR
JWT field\&. In this option you can specify other JWT field name where the JID is defined\&.
JWT field\&. In this option you can specify other
\fIauthentication\&.md#jwt\-authentication|JWT\fR
field name where the JID is defined\&.
.RE
.PP
\fBjwt_key\fR: \fIFilePath\fR
.RS 4
Path to the file that contains the JWK Key\&. The default value is
Path to the file that contains the
\fIauthentication\&.md#jwt\-authentication|JWT\fR
key\&. The default value is
\fIundefined\fR\&.
.RE
.PP
\fBlanguage\fR: \fILanguage\fR
.RS 4
The option defines the default language of server strings that can be seen by XMPP clients\&. If an XMPP client does not possess
Define the
\fI\&.\&./configuration/basic\&.md#default\-language|default language\fR
of server strings that can be seen by XMPP clients\&. If an XMPP client does not possess
\fIxml:lang\fR
attribute, the specified language is used\&. The default value is
\fI"en"\fR\&.
@@ -949,9 +972,10 @@ attribute, the specified language is used\&. The default value is
.PP
\fBldap_backups\fR: \fI[Host, \&.\&.\&.]\fR
.RS 4
A list of IP addresses or DNS names of LDAP backup servers\&. When no servers listed in
A list of IP addresses or DNS names of LDAP backup servers (see
\fI\&.\&./configuration/ldap\&.md#ldap\-connection|LDAP connection\fR)\&. When no servers listed in
\fIldap_servers\fR
option are reachable, ejabberd will try to connect to these backup servers\&. The default is an empty list, i\&.e\&. no backup servers specified\&. WARNING: ejabberd doesn\(cqt try to reconnect back to the main servers when they become operational again, so the only way to restore these connections is to restart ejabberd\&. This limitation might be fixed in future releases\&.
option are reachable, ejabberd connects to these backup servers\&. The default is an empty list, i\&.e\&. no backup servers specified\&. Please notice that ejabberd only connects to the next server when the existing connection is lost; it doesn\(cqt detect when a previously\-attempted server becomes available again\&.
.RE
.PP
\fBldap_base\fR: \fIBase\fR
@@ -1022,7 +1046,8 @@ Bind Distinguished Name\&. The default value is an empty string, which means "an
.PP
\fBldap_servers\fR: \fI[Host, \&.\&.\&.]\fR
.RS 4
A list of IP addresses or DNS names of your LDAP servers\&. The default value is
A list of IP addresses or DNS names of your LDAP servers (see
\fI\&.\&./configuration/ldap\&.md#ldap\-connection|LDAP connection\fR)\&. ejabberd connects immediately to all of them, and reconnects infinitely if connection is lost\&. The default value is
\fI[localhost]\fR\&.
.RE
.PP
@@ -1114,7 +1139,8 @@ The size (in bytes) of a log file to trigger rotation\&. If set to
.PP
\fBloglevel\fR: \fInone | emergency | alert | critical | error | warning | notice | info | debug\fR
.RS 4
Verbosity of log files generated by ejabberd\&. The default value is
Verbosity of ejabberd
\fI\&.\&./configuration/basic\&.md#logging|logging\fR\&. The default value is
\fIinfo\fR\&. NOTE: previous versions of ejabberd had log levels defined in numeric format (\fI0\&.\&.5\fR)\&. The numeric values are still accepted for backward compatibility, but are not recommended\&.
.RE
.PP
@@ -1126,9 +1152,9 @@ This option specifies the maximum number of elements in the queue of the FSM (Fi
.PP
\fBmodules\fR: \fI{Module: Options}\fR
.RS 4
The option for modules configuration\&. See
\fImodules\&.md|Modules\fR
section for details\&.
Set all the
\fImodules\&.md|modules\fR
configuration options\&.
.RE
.PP
\fBnegotiation_timeout\fR: \fItimeout()\fR
@@ -1147,10 +1173,9 @@ This option can be used to tune tick time parameter of
.PP
\fBnew_sql_schema\fR: \fItrue | false\fR
.RS 4
Whether to use
\fInew\fR
SQL schema\&. All schemas are located at
https://github\&.com/processone/ejabberd/tree/24\&.07/sql\&. There are two schemas available\&. The default legacy schema stores one XMPP domain into one ejabberd database\&. The
Whether to use the
\fIdatabase\&.md#default\-and\-new\-schemas|new SQL schema\fR\&. All schemas are located at
https://github\&.com/processone/ejabberd/tree/24\&.10/sql\&. There are two schemas available\&. The default legacy schema stores one XMPP domain into one ejabberd database\&. The
\fInew\fR
schema can handle several XMPP domains in a single ejabberd database\&. Using this
\fInew\fR
@@ -1296,13 +1321,17 @@ seconds\&.
.PP
\fBpam_service\fR: \fIName\fR
.RS 4
This option defines the PAM service name\&. Refer to the PAM documentation of your operation system for more information\&. The default value is
This option defines the
\fIauthentication\&.md#pam\-authentication|PAM\fR
service name\&. Refer to the PAM documentation of your operation system for more information\&. The default value is
\fIejabberd\fR\&.
.RE
.PP
\fBpam_userinfotype\fR: \fIusername | jid\fR
.RS 4
This option defines what type of information about the user ejabberd provides to the PAM service: only the username, or the user\(cqs JID\&. Default is
This option defines what type of information about the user ejabberd provides to the
\fIauthentication\&.md#pam\-authentication|PAM\fR
service: only the username, or the user\(cqs JID\&. Default is
\fIusername\fR\&.
.RE
.PP
@@ -1336,36 +1365,47 @@ option where file queues will be placed\&. The default value is
.PP
\fBredis_connect_timeout\fR: \fItimeout()\fR
.RS 4
A timeout to wait for the connection to be re\-established to the Redis server\&. The default is
A timeout to wait for the connection to be re\-established to the
\fIdatabase\&.md#redis|Redis\fR
server\&. The default is
\fI1 second\fR\&.
.RE
.PP
\fBredis_db\fR: \fINumber\fR
.RS 4
Redis database number\&. The default is
\fIdatabase\&.md#redis|Redis\fR
database number\&. The default is
\fI0\fR\&.
.RE
.PP
\fBredis_password\fR: \fIPassword\fR
.RS 4
The password to the Redis server\&. The default is an empty string, i\&.e\&. no password\&.
The password to the
\fIdatabase\&.md#redis|Redis\fR
server\&. The default is an empty string, i\&.e\&. no password\&.
.RE
.PP
\fBredis_pool_size\fR: \fINumber\fR
.RS 4
The number of simultaneous connections to the Redis server\&. The default value is
The number of simultaneous connections to the
\fIdatabase\&.md#redis|Redis\fR
server\&. The default value is
\fI10\fR\&.
.RE
.PP
\fBredis_port\fR: \fI1\&.\&.65535\fR
.RS 4
The port where the Redis server is accepting connections\&. The default is
The port where the
\fIdatabase\&.md#redis|Redis\fR
server is accepting connections\&. The default is
\fI6379\fR\&.
.RE
.PP
\fBredis_queue_type\fR: \fIram | file\fR
.RS 4
The type of request queue for the Redis server\&. See description of
The type of request queue for the
\fIdatabase\&.md#redis|Redis\fR
server\&. See description of
\fIqueue_type\fR
option for the explanation\&. The default value is the value defined in
\fIqueue_type\fR
@@ -1376,7 +1416,9 @@ if the latter is not set\&.
.PP
\fBredis_server\fR: \fIHostname\fR
.RS 4
A hostname or an IP address of the Redis server\&. The default is
A hostname or an IP address of the
\fIdatabase\&.md#redis|Redis\fR
server\&.The default is
\fIlocalhost\fR\&.
.RE
.PP
@@ -1579,7 +1621,8 @@ XEP\-0138) or not\&. The default value is
.PP
\fBshaper\fR: \fI{ShaperName: Rate}\fR
.RS 4
The option defines a set of shapers\&. Every shaper is assigned a name
The option defines a set of
\fI\&.\&./configuration/basic\&.md#shapers|shapers\fR\&. Every shaper is assigned a name
\fIShaperName\fR
that can be used in other parts of the configuration file, such as
\fIshaper_rules\fR
@@ -1611,7 +1654,9 @@ shaper:
.PP
\fBshaper_rules\fR: \fI{ShaperRuleName: {Number|ShaperName: ACLRule|ACLName}}\fR
.RS 4
An entry allowing to declaring shaper to use for matching user/hosts\&. Semantics is similar to
This option defines
\fI\&.\&./configuration/basic\&.md#shaper\-rules|shaper rules\fR
to use for matching user/hosts\&. Semantics is similar to
\fIaccess_rules\fR
option, the only difference is that instead using
\fIallow\fR
@@ -1858,11 +1903,11 @@ header if you enable this option as, otherwise, the client can set it itself and
\fBupdate_sql_schema\fR: \fItrue | false\fR
.RS 4
\fINote\fR
about this option: updated in 24\&.06\&. Allow ejabberd to update SQL schema\&. This option was added in ejabberd 23\&.10, and enabled by default since 24\&.06\&. The default value is
about this option: updated in 24\&.06\&. Allow ejabberd to update SQL schema in MySQL, PostgreSQL and SQLite databases\&. This option was added in ejabberd 23\&.10, and enabled by default since 24\&.06\&. The default value is
\fItrue\fR\&.
.RE
.PP
\fBupdate_sql_schema_timeout 🟤\fR: \fItimeout()\fR
\fBupdate_sql_schema_timeout\fR: \fItimeout()\fR
.RS 4
\fINote\fR
about this option: added in 24\&.07\&. Time allocated to SQL schema update queries\&. The default value is set to 5 minutes\&.
@@ -1919,12 +1964,7 @@ seconds\&.
.RE
.SH "MODULES"
.sp
This section describes modules options of ejabberd 24\&.07\&. The modules that changed in this version are marked with 🟤\&.
.SS "Elixir\&.ModPresenceDemo"
.sp
This is just a demonstration\&.
.sp
The module has no options\&.
This section describes modules options of ejabberd 24\&.10\&. The modules that changed in this version are marked with 🟤\&.
.SS "mod_adhoc"
.sp
This module implements XEP\-0050: Ad\-Hoc Commands\&. It\(cqs an auxiliary module and is only needed by some of the other modules\&.
@@ -5367,6 +5407,8 @@ option, but applied to this module only\&.
.RE
.SS "mod_privilege"
.sp
\fINote\fR about this option: improved in 24\&.10\&.
.sp
This module is an implementation of XEP\-0356: Privileged Entity\&. This extension allows components to have privileged access to other entity data (send messages on behalf of the server or on behalf of a user, get/set user roster, access presence information, etc\&.)\&. This may be used to write powerful external components, for example implementing an external PEP or MAM service\&.
.sp
By default a component does not have any privileged access\&. It is worth noting that the permissions grant access to the component to a specific data type for all users of the virtual host on which \fImod_privilege\fR is loaded\&.
@@ -5413,6 +5455,36 @@ This module is complementary to \fImod_delegation\fR, but can also be used separ
\fBAvailable options:\fR
.RS 4
.PP
\fBiq\fR: \fI{Namespace: Options}\fR
.RS 4
This option defines namespaces and their IQ permissions\&. By default no permissions are given\&. The
\fIOptions\fR
are:
.PP
\fBboth\fR: \fIAccessName\fR
.RS 4
Allows sending IQ stanzas of type
\fIget\fR
and
\fIset\fR\&. The default value is
\fInone\fR\&.
.RE
.PP
\fBget\fR: \fIAccessName\fR
.RS 4
Allows sending IQ stanzas of type
\fIget\fR\&. The default value is
\fInone\fR\&.
.RE
.PP
\fBset\fR: \fIAccessName\fR
.RS 4
Allows sending IQ stanzas of type
\fIset\fR\&. The default value is
\fInone\fR\&.
.RE
.RE
.PP
\fBmessage\fR: \fIOptions\fR
.RS 4
This option defines permissions for messages\&. By default no permissions are given\&. The
@@ -5485,6 +5557,9 @@ Sets write access to a user\(cqs roster\&. The default value is
.nf
modules:
mod_privilege:
iq:
http://jabber\&.org/protocol/pubsub:
get: all
roster:
get: all
presence:
@@ -6120,7 +6195,10 @@ This module reads also the top\-level \fIregistration_timeout\fR option defined
.RS 4
Specify rules to restrict what usernames can be registered\&. If a rule returns
\fIdeny\fR
on the requested username, registration of that user name is denied\&. There are no restrictions by default\&.
on the requested username, registration of that user name is denied\&. There are no restrictions by default\&. If
\fIAccessName\fR
is
\fInone\fR, then registering new accounts using In\-Band Registration is disabled and the corresponding stream feature is not announced to clients\&.
.RE
.PP
\fBaccess_from\fR: \fIAccessName\fR
@@ -6376,6 +6454,33 @@ modules:
.RE
.\}
.RE
.SS "mod_s2s_bidi"
.sp
\fINote\fR about this option: added in 24\&.10\&.
.sp
The module adds support for XEP\-0288: Bidirectional Server\-to\-Server Connections that allows using single s2s connection to communicate in both directions\&.
.sp
The module has no options\&.
.sp
.it 1 an-trap
.nr an-no-space-flag 1
.nr an-break-flag 1
.br
.ps +1
\fBExample:\fR
.RS 4
.sp
.if n \{\
.RS 4
.\}
.nf
modules:
mod_s2s_bidi: {}
.fi
.if n \{\
.RE
.\}
.RE
.SS "mod_s2s_dialback"
.sp
The module adds support for XEP\-0220: Server Dialback to provide server identity verification based on DNS\&.
@@ -6435,6 +6540,48 @@ modules:
.RE
.\}
.RE
.SS "mod_scram_upgrade"
.sp
\fINote\fR about this option: added in 24\&.10\&.
.sp
The module adds support for XEP\-0480: SASL Upgrade Tasks that allows users to upgrade passwords to more secure representation\&.
.sp
.it 1 an-trap
.nr an-no-space-flag 1
.nr an-break-flag 1
.br
.ps +1
\fBAvailable options:\fR
.RS 4
.PP
\fBoffered_upgrades\fR: \fIlist(sha256, sha512)\fR
.RS 4
List with upgrade types that should be offered
.RE
.RE
.sp
.it 1 an-trap
.nr an-no-space-flag 1
.nr an-break-flag 1
.br
.ps +1
\fBExample:\fR
.RS 4
.sp
.if n \{\
.RS 4
.\}
.nf
modules:
mod_scram_upgrade:
offered_upgrades:
\- sha256
\- sha512
.fi
.if n \{\
.RE
.\}
.RE
.SS "mod_service_log"
.sp
This module forwards copies of all stanzas to remote XMPP servers or components\&. Every stanza is encapsulated into <forwarded/> element as described in XEP\-0297: Stanza Forwarding\&.
@@ -7833,7 +7980,7 @@ Should the operating system be revealed or not\&. The default value is
.RE
.SH "LISTENERS"
.sp
This section describes listeners options of ejabberd 24\&.07\&.
This section describes listeners options of ejabberd 24\&.10\&.
.sp
TODO
.SH "AUTHOR"
@@ -7841,13 +7988,13 @@ TODO
ProcessOne\&.
.SH "VERSION"
.sp
This document describes the configuration file of ejabberd 24\&.07\&. Configuration options of other ejabberd versions may differ significantly\&.
This document describes the configuration file of ejabberd 24\&.10\&. Configuration options of other ejabberd versions may differ significantly\&.
.SH "REPORTING BUGS"
.sp
Report bugs to https://github\&.com/processone/ejabberd/issues
.SH "SEE ALSO"
.sp
Default configuration file: https://github\&.com/processone/ejabberd/blob/24\&.07/ejabberd\&.yml\&.example
Default configuration file: https://github\&.com/processone/ejabberd/blob/24\&.10/ejabberd\&.yml\&.example
.sp
Main site: https://ejabberd\&.im
.sp
+7 -9
View File
@@ -43,11 +43,10 @@ defmodule Ejabberd.MixProject do
def application do
[mod: {:ejabberd_app, []},
applications: [:idna, :inets, :kernel, :sasl, :ssl, :stdlib, :mix,
:fast_tls, :fast_xml, :fast_yaml, :jose,
:p1_utils, :stringprep, :syntax_tools, :yconf, :xmpp]
extra_applications: [:inets, :kernel, :sasl, :ssl, :stdlib, :syntax_tools,
:logger, :mix]
++ cond_apps(),
included_applications: [:mnesia, :os_mon, :logger,
included_applications: [:mnesia, :os_mon,
:cache_tab, :eimp, :mqtree, :p1_acme,
:p1_oauth2, :pkix]
++ cond_included_apps()]
@@ -135,8 +134,8 @@ defmodule Ejabberd.MixProject do
{:dialyxir, "~> 1.2", only: [:test], runtime: false},
{:eimp, "~> 1.0"},
{:ex_doc, "~> 0.31", only: [:dev, :edoc], runtime: false},
{:fast_tls, ">= 1.1.18"},
{:fast_xml, ">= 1.1.51"},
{:fast_tls, "~> 1.1.22"},
{:fast_xml, "~> 1.1.53"},
{:fast_yaml, "~> 1.0"},
{:idna, "~> 6.0"},
{:mqtree, "~> 1.0"},
@@ -145,7 +144,7 @@ defmodule Ejabberd.MixProject do
{:p1_utils, "~> 1.0"},
{:pkix, "~> 1.0"},
{:stringprep, ">= 1.0.26"},
{:xmpp, ">= 1.8.3"},
{:xmpp, "~> 1.9"},
{:yconf, "~> 1.0"}]
++ cond_deps()
end
@@ -166,7 +165,7 @@ defmodule Ejabberd.MixProject do
{Mix.env() == :translations,
{:ejabberd_po, git: "https://github.com/processone/ejabberd-po.git"}},
{Mix.env() == :dev,
{:exsync, "~> 0.2"}},
{:exsync, "~> 0.2", optional: true, runtime: false}},
{config(:redis), {:eredis, "~> 1.2.0"}},
{config(:sip), {:esip, "~> 1.0"}},
{config(:zlib), {:ezlib, "~> 1.0"}},
@@ -184,7 +183,6 @@ defmodule Ejabberd.MixProject do
defp cond_apps do
for {:true, app} <- [{config(:stun), :stun},
{Map.has_key?(System.get_env(), "RELIVE"), :exsync},
{if_version_below(~c"27", true), :jiffy},
{config(:tools), :observer}], do:
app
+10 -13
View File
@@ -1,40 +1,37 @@
%{
"base64url": {:hex, :base64url, "1.0.1", "f8c7f2da04ca9a5d0f5f50258f055e1d699f0e8bf4cfdb30b750865368403cf6", [:rebar3], [], "hexpm", "f9b3add4731a02a9b0410398b475b33e7566a695365237a6bdee1bb447719f5c"},
"cache_tab": {:hex, :cache_tab, "1.0.31", "e4097b50a6f373ab1e0a5f01bab0bef6626771a4cd6c93404ed6d54810e11fbc", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "8582b60a4a09b247ef86355ba9e07fce9e11edc0345a775c9171f971c72b6351"},
"dialyxir": {:hex, :dialyxir, "1.4.3", "edd0124f358f0b9e95bfe53a9fcf806d615d8f838e2202a9f430d59566b6b53b", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "bf2cfb75cd5c5006bec30141b131663299c661a864ec7fbbc72dfa557487a986"},
"dialyxir": {:hex, :dialyxir, "1.4.4", "fb3ce8741edeaea59c9ae84d5cec75da00fa89fe401c72d6e047d11a61f65f70", [:mix], [{:erlex, ">= 0.2.7", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "cd6111e8017ccd563e65621a4d9a4a1c5cd333df30cebc7face8029cacb4eff6"},
"earmark_parser": {:hex, :earmark_parser, "1.4.41", "ab34711c9dc6212dda44fcd20ecb87ac3f3fce6f0ca2f28d4a00e4154f8cd599", [:mix], [], "hexpm", "a81a04c7e34b6617c2792e291b5a2e57ab316365c2644ddc553bb9ed863ebefa"},
"eimp": {:hex, :eimp, "1.0.23", "aaf32efab061143403dadbaa63e699ef8e81702fbfa96fd436d5e9be4d6a8d3a", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "907c780023cb2893e4fc4bdbe6a4f02c355913862ac67f0ecc26605e816b628a"},
"ejabberd_po": {:git, "https://github.com/processone/ejabberd-po.git", "6ef974cbc28e1a52d7a35fd4d9081d175d0ac10d", []},
"epam": {:hex, :epam, "1.0.14", "aa0b85d27f4ef3a756ae995179df952a0721237e83c6b79d644347b75016681a", [:rebar3], [], "hexpm", "2f3449e72885a72a6c2a843f561add0fc2f70d7a21f61456930a547473d4d989"},
"eredis": {:hex, :eredis, "1.2.0", "0b8e9cfc2c00fa1374cd107ea63b49be08d933df2cf175e6a89b73dd9c380de4", [:rebar3], [], "hexpm", "d9b5abef2c2c8aba8f32aa018203e0b3dc8b1157773b254ab1d4c2002317f1e1"},
"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"},
"esip": {:hex, :esip, "1.0.56", "63c0fdc667be751714e1e5c14621a9334f21b60ac1bb68be889454ca9ca021b7", [: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]}, {:stun, "1.2.15", [hex: :stun, repo: "hexpm", optional: false]}], "hexpm", "9ef3660cef93b623f7368dcd5c79f4e704358631909e6dd464e335378815da1f"},
"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": {:hex, :fast_tls, "1.1.21", "65d7d547a09eefb37a1c0d04d8601fac4f3e6e2c1ede859a7787081670f9648d", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "131542913937025e48cd80aa81f00359686d5501b75621e72026a87b5229505b"},
"fast_xml": {:hex, :fast_xml, "1.1.52", "0289daafbf1190b0e53b444d4885cccf41e4b05768d4b3acc76dd8d143668e10", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "795192390e06d2b65016a6990bbfa5727f4a26d2914808b1c3c9a32eedcd1bfd"},
"fast_tls": {:hex, :fast_tls, "1.1.22", "44356b256afad4399c2fc5059a3066669dafd8bd4e4e796c9c1cf8910ddd265e", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "e65779aefb7ab15c4755230fef8077e687d20cc5a3984a5974f9f657e8e2485b"},
"fast_xml": {:hex, :fast_xml, "1.1.53", "1ef4f6e5995bcfa94800a46b460c3400c19c0a533948b12200a2e2fb1a2be427", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "5064336d6f363eee5097aa5dc5ced9b67f05152f2e6b8520fd50d268c2ab839c"},
"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.0", "b689cc7dcee665f774de94b5a832e578bd7963c8e637ef940cd44327db7de2cd", [:mix], [], "hexpm", "6752092d66aec5a10e662aefeed8ddb9531d79db0bc145bb8c40325ca1d8536d"},
"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"},
"luerl": {:hex, :luerl, "1.2.0", "60f05f4240f0e7c148ddb79b67b8ff972734aad237aa74c83d0748b8214c8ef0", [:rebar3], [], "hexpm", "9cafd4f6094ff0f5a9d278fd81d60d3e026c820bdfb6cacd4b1bd909f21b525d"},
"makeup": {:hex, :makeup, "1.1.2", "9ba8837913bdf757787e71c1581c21f9d2455f4dd04cfca785c70bbfff1a76a3", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cce1566b81fbcbd21eca8ffe808f33b221f9eee2cbc7a1706fc3da9ff18e6cac"},
"makeup_elixir": {:hex, :makeup_elixir, "0.16.2", "627e84b8e8bf22e60a2579dad15067c755531fea049ae26ef1020cad58fe9578", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "41193978704763f6bbe6cc2758b84909e62984c7752b3784bd3c218bb341706b"},
"makeup_erlang": {:hex, :makeup_erlang, "1.0.0", "6f0eff9c9c489f26b69b61440bf1b238d95badae49adac77973cbacae87e3c2e", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "ea7a9307de9d1548d2a72d299058d1fd2339e3d398560a0e46c27dab4891e4d2"},
"makeup_erlang": {:hex, :makeup_erlang, "1.0.1", "c7f58c120b2b5aa5fd80d540a89fdf866ed42f1f3994e4fe189abebeab610839", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "8a89a1eeccc2d798d6ea15496a6e4870b75e014d1af514b1b71fa33134f57814"},
"mqtree": {:hex, :mqtree, "1.0.17", "82f54b8f2d22b4445db1d6cccb7fe9ead049d61410c29e32475f3ceb3ee62a89", [:rebar3], [{:p1_utils, "1.0.26", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "5fe8b7cf8fbc4783d0fceb94654ac2bbf3242a58cd0397d249ded8ae021be2a3"},
"nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"},
"p1_acme": {:hex, :p1_acme, "1.0.23", "791aef0f79dc7f768b228808250c349fa9ce585cd8779da50ca93106eb3394d0", [:rebar3], [{:base64url, "~> 1.0", [hex: :base64url, repo: "hexpm", optional: false]}, {:idna, "~> 6.0", [hex: :idna, repo: "hexpm", optional: false]}, {:jiffy, "~> 1.1.1", [hex: :jiffy, repo: "hexpm", optional: false]}, {:jose, "~> 1.11.10", [hex: :jose, repo: "hexpm", optional: false]}, {:yconf, "~> 1.0.15", [hex: :yconf, repo: "hexpm", optional: false]}], "hexpm", "8ce196f26e3d22ea10b7809122950465878c127f80767e325207aed7e8d0dd59"},
"p1_mysql": {:hex, :p1_mysql, "1.0.24", "0ed1e098c5a4525032448c65a2715f30980aae725615a4d255fd25f26bb22507", [:rebar3], [], "hexpm", "f058865f64257f507a2c6a5aff369b1375dbcb30b3d4258dad4f1b3eaffb655f"},
"p1_acme": {:hex, :p1_acme, "1.0.24", "e19876618eb0be22815aca99640cb88cd5c86e4239b8e8dc15b4e5d7854ef7e2", [:rebar3], [{:base64url, "~> 1.0", [hex: :base64url, repo: "hexpm", optional: false]}, {:idna, "~> 6.0", [hex: :idna, repo: "hexpm", optional: false]}, {:jiffy, "~> 1.1.1", [hex: :jiffy, repo: "hexpm", optional: false]}, {:jose, "~> 1.11.10", [hex: :jose, repo: "hexpm", optional: false]}, {:yconf, "~> 1.0.15", [hex: :yconf, repo: "hexpm", optional: false]}], "hexpm", "f1451d706595ef997ab1ca17162ddac58f874ac97e315a5fadbe3cfa26148002"},
"p1_mysql": {:hex, :p1_mysql, "1.0.25", "875d4cbdc7c9990270df3292cce2514e4c18a9fdfd19bef258cb4d0c45b4f243", [:rebar3], [], "hexpm", "e6187ffae95b726098e88f3ee6f2344ac259ce2c26e0ee403b05feef341ae434"},
"p1_oauth2": {:hex, :p1_oauth2, "0.6.14", "1c5f82535574de87e2059695ac4b91f8f9aebacbc1c80287dae6f02552d47aea", [:rebar3], [], "hexpm", "1fd3ac474e43722d9d5a87c6df8d36f698ed87af7bb81cbbb66361451d99ae8f"},
"p1_pgsql": {:hex, :p1_pgsql, "1.1.27", "883e335d82ac062de0bde7981f8250a2e632258bb7a47df839a4cbdcb3e971e6", [:rebar3], [{:xmpp, "~> 1.8.0", [hex: :xmpp, repo: "hexpm", optional: false]}], "hexpm", "8e4d1a7602cb68780e55d89dc5a9b2e1aaca3f4f1ee3d1a25f2f8c3d2364ffb9"},
"p1_pgsql": {:hex, :p1_pgsql, "1.1.28", "08eca7d2afc81ba6d757b572f4a57ef3a2383b0c7b785fde38184bc368376d54", [:rebar3], [{:xmpp, "~> 1.9.0", [hex: :xmpp, repo: "hexpm", optional: false]}], "hexpm", "655bb75df036ace55ddce17ca741143c42e0667c6206ac27a4dcbc65f71ac9ef"},
"p1_utils": {:hex, :p1_utils, "1.0.26", "67b0c4ac9fa3ba3ef563b31aa111b0a004439a37fac85e027f1c3617e1c7ec6c", [:rebar3], [], "hexpm", "d0379e8c1156b98bd64f8129c1de022fcca4f2fdb7486ce73bf0ed2c3376b04c"},
"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": {:hex, :xmpp, "1.8.3", "acf39a8b70b066bb8f10b0862e031e8abcf92fe89d1c41d06c1e39ae5caf89c4", [:rebar3], [{:ezlib, "~> 1.0.12", [hex: :ezlib, repo: "hexpm", optional: false]}, {:fast_tls, "~> 1.1.19", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:fast_xml, "~> 1.1.51", [hex: :fast_xml, repo: "hexpm", optional: false]}, {:idna, "~> 6.0", [hex: :idna, repo: "hexpm", optional: false]}, {:p1_utils, "~> 1.0.25", [hex: :p1_utils, repo: "hexpm", optional: false]}, {:stringprep, "~> 1.0.29", [hex: :stringprep, repo: "hexpm", optional: false]}], "hexpm", "ed70065f9a89a818dcff43b74c080c9e7f4f1414e1051beddb7280db809af711"},
"xmpp": {:hex, :xmpp, "1.9.0", "d92446bf51d36adda02db63b963fe6d4a1ede33e59b38a43d9b90afd20c25b74", [:rebar3], [{:ezlib, "~> 1.0.12", [hex: :ezlib, repo: "hexpm", optional: false]}, {:fast_tls, "~> 1.1.19", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:fast_xml, "~> 1.1.51", [hex: :fast_xml, repo: "hexpm", optional: false]}, {:idna, "~> 6.0", [hex: :idna, repo: "hexpm", optional: false]}, {:p1_utils, "~> 1.0.25", [hex: :p1_utils, repo: "hexpm", optional: false]}, {:stringprep, "~> 1.0.29", [hex: :stringprep, repo: "hexpm", optional: false]}], "hexpm", "c1b91be74a9a9503afa6766f756477516920ffbfeea0c260c2fa171355f53c27"},
"yconf": {:hex, :yconf, "1.0.16", "d59521d66ff89f219411b6e9277cd6feec7cc6fce11554e67de02a8d0a470479", [:rebar3], [{:fast_yaml, "1.0.37", [hex: :fast_yaml, repo: "hexpm", optional: false]}], "hexpm", "e947813273f38711c7b2e5a8e4acc9a51c7bbe854f744a345f60300b38586c89"},
}
+23
View File
@@ -111,6 +111,11 @@
{"Dynamically specify a replyto of the item publisher","Динамично задаване на отговор към публикувалия елемента"}.
{"Edit Properties","Редактиране на свойства"}.
{"Either approve or decline the voice request.","Одобрете или отхвърлете заявката за гласова връзка."}.
{"ejabberd HTTP Upload service","ejabberd HTTP Upload услуга"}.
{"ejabberd MUC module","ejabberd MUC модул"}.
{"ejabberd Multicast service","ejabberd Multicast услуга"}.
{"ejabberd Publish-Subscribe module","ejabberd Publish-Subscribe модул"}.
{"ejabberd SOCKS5 Bytestreams module","ejabberd SOCKS5 Bytestreams модул"}.
{"ejabberd vCard module","ejabberd vCard модул"}.
{"ejabberd Web Admin","Уеб администрация на ejabberd"}.
{"ejabberd","ejabberd"}.
@@ -158,6 +163,12 @@
{"Get User Statistics","Покажи статистика за потребителя"}.
{"Given Name","Име"}.
{"Grant voice to this person?","Предоставяне на глас за потребителя?"}.
{"has been banned","е със забранен достъп"}.
{"has been kicked because of a system shutdown","е отстранен поради изключване на системата"}.
{"has been kicked because of an affiliation change","е отстранен поради промяна на принадлежността"}.
{"has been kicked because the room has been changed to members-only","е изгонен, защото стаята е променена и е само за членове"}.
{"has been kicked","е отстранен"}.
{"Hash of the vCard-temp avatar of this room","Хеш на временния vCard аватар на тази стая"}.
{"Hat title","Заглавие на шапката"}.
{"Hat URI","URI адрес за шапка"}.
{"Hats limit exceeded","Превишен е лимитът за шапка"}.
@@ -190,6 +201,7 @@
{"Invalid 'previd' value","Невалидна стойност на 'previd'"}.
{"Invitations are not allowed in this conference","Поканите не са разрешени в тази конференция"}.
{"IP addresses","IP адреси"}.
{"is now known as","е известен като"}.
{"It is not allowed to send error messages to the room. The participant (~s) has sent an error message (~s) and got kicked from the room","Не е позволено да изпращате съобщения за грешки в стаята. Участникът (~s) е изпратил съобщение за грешка (~s) и е бил отстранен от стаята"}.
{"It is not allowed to send private messages of type \"groupchat\"","Изпращането на лични съобщения от тип \"групов чат\" не е разрешено"}.
{"It is not allowed to send private messages to the conference","Изпращането на лични съобщения до конференцията не е разрешено"}.
@@ -199,6 +211,7 @@
{"JID normalization failed","Нормализирането на JID е неуспешно"}.
{"Joined MIX channels of ~ts","Свързани MIX канали на ~ts"}.
{"Joined MIX channels:","Свързани MIX канали:"}.
{"joins the room","се присъединява към стаята"}.
{"July","Юли"}.
{"June","Юни"}.
{"Just created","Току що създаден"}.
@@ -208,8 +221,10 @@
{"Last month","Миналия месец"}.
{"Last year","Миналата година"}.
{"Least significant bits of SHA-256 hash of text should equal hexadecimal label","Най-малко значимите битове SHA-256 хеш на текст трябва да са равни на шестнайсетичния етикет"}.
{"leaves the room","напуска стаята"}.
{"List of users with hats","Списък на потребителите с шапки"}.
{"List users with hats","Избройте потребителите с шапки"}.
{"Logged Out","Излязъл"}.
{"Logging","Регистриране на събития"}.
{"Make participants list public","Направи списъка с участниците публичен"}.
{"Make room CAPTCHA protected","Защити стаята с CAPTCHA"}.
@@ -360,6 +375,7 @@
{"Previous session PID has exited","Предишният PID на сесията е излязъл"}.
{"Previous session PID is dead","PID от предишната сесия не съществува"}.
{"Previous session timed out","Времето на предишната сесия изтече"}.
{"private, ","частна, "}.
{"Public","Публичен"}.
{"Publish model","Модел за публикуване"}.
{"Publish-Subscribe","Публикуване-Абониране"}.
@@ -423,6 +439,7 @@
{"Set message of the day on all hosts and send to online users","Задавай съобщение на деня на всички хостове и изпрати на онлайн потребителите"}.
{"Shared Roster Groups","Споделени групи от списъци с контакти"}.
{"Show Integral Table","Покажи интегрална таблица"}.
{"Show Occupants Join/Leave","Покажи участници Влязъл/Напускнал"}.
{"Show Ordinary Table","Покажи обикновена таблица"}.
{"Shut Down Service","Изключи услугата"}.
{"SOCKS5 Bytestreams","SOCKS5 байтови потоци"}.
@@ -482,6 +499,7 @@
{"The number of unread or undelivered messages","Броят непрочетени или недоставени съобщения"}.
{"The password contains unacceptable characters","Паролата съдържа недопустими символи"}.
{"The password is too weak","Паролата е твърде слаба"}.
{"the password is","паролата е"}.
{"The password of your XMPP account was successfully changed.","Паролата на вашия XMPP профил беше успешно променена."}.
{"The password was not changed","Паролата не е променена"}.
{"The passwords are different","Паролите са различни"}.
@@ -555,6 +573,7 @@
{"Value of '~s' should be datetime string","Стойността на '~s' трябва да бъде низ за дата и час"}.
{"Value of '~s' should be integer","Стойността на '~s' трябва да бъде цяло число"}.
{"Value 'set' of 'type' attribute is not allowed","Стойността 'set' на атрибут 'type' не е разрешена"}.
{"vCard User Search","vCard търсене на потребител"}.
{"View joined MIX channels","Вижте присъединените MIX канали"}.
{"Virtual Hosts","Виртуални хостове"}.
{"Visitors are not allowed to change their nicknames in this room","Посетителите нямат право да променят псевдонимите си в тази стая"}.
@@ -584,6 +603,7 @@
{"XMPP Show Value of Chat","XMPP покажи стойност на Чат"}.
{"XMPP Show Value of DND (Do Not Disturb)","XMPP покажи стойност на DND (Не ме безпокой)"}.
{"XMPP Show Value of XA (Extended Away)","XMPP покажи стойност на Продължително отсъствие"}.
{"XMPP URI of Associated Publish-Subscribe Node","XMPP URI на асоцииран Publish-Subscribe нод"}.
{"You are being removed from the room because of a system shutdown","Премахнати сте от стаята поради изключване на системата"}.
{"You are not allowed to send private messages","Нямате право да изпращате лични съобщения"}.
{"You are not joined to the channel","Не сте присъединени към канала"}.
@@ -594,6 +614,9 @@
{"You need a client that supports x:data and CAPTCHA to register","За да се регистрирате Ви е нужен клиент, който поддържа x:data и CAPTCHA"}.
{"You need a client that supports x:data to register the nickname","За да регистрирате псевдонима, Ви е необходим клиент, който поддържа x:data"}.
{"You need an x:data capable client to search","За да търсите, Ви е нужен клиент, който поддържа x:data"}.
{"Your active privacy list has denied the routing of this stanza.","Вашият активен списък за поверителност отказа маршрутизирането на тази строфа."}.
{"Your contact offline message queue is full. The message has been discarded.","Достигнат е максималният брой офлайн съобщения за вашия контакт. Съобщението е отхвърлено."}.
{"Your subscription request and/or messages to ~s have been blocked. To unblock your subscription request, visit ~s","Вашата заявка за абонамент и/или съобщения до ~s са блокирани. За да отблокирате заявката си за абонамент, посетете ~s"}.
{"Your XMPP account was successfully registered.","Вашият XMPP акаунт, беше регистриран успешно."}.
{"Your XMPP account was successfully unregistered.","Вашият XMPP акаунт, беше успешно дерегистриран."}.
{"You're not allowed to create nodes","Нямате право да създавате нодове"}.
+1
View File
@@ -168,6 +168,7 @@
{"has been kicked because of an affiliation change","ha sigut expulsat a causa d'un canvi d'afiliació"}.
{"has been kicked because the room has been changed to members-only","ha sigut expulsat perquè la sala ara és només per a membres"}.
{"has been kicked","ha sigut expulsat"}.
{"Hash of the vCard-temp avatar of this room","Hash del avatar a vCard-temp d'esta sala"}.
{"Hat title","Títol del barret"}.
{"Hat URI","URI del barret"}.
{"Hats limit exceeded","El límit de tràfic ha sigut sobrepassat"}.
+1
View File
@@ -168,6 +168,7 @@
{"has been kicked because of an affiliation change","ha sido expulsado por un cambio de su afiliación"}.
{"has been kicked because the room has been changed to members-only","ha sido expulsado porque la sala es ahora solo para miembros"}.
{"has been kicked","ha sido expulsado"}.
{"Hash of the vCard-temp avatar of this room","Hash del avatar vCard-temp de esta sala"}.
{"Hat title","Título del sombrero"}.
{"Hat URI","Dirección del sombrero"}.
{"Hats limit exceeded","Se ha excedido el límite de sombreros"}.
+4 -4
View File
@@ -9,19 +9,19 @@
{"A description of the node","Una descrizione del nodo"}.
{"A friendly name for the node","Un nome comodo per il nodo"}.
{"A password is required to enter this room","Per entrare in questa stanza è necessaria una password"}.
{"A Web Page","Un Pagina Web"}.
{"A Web Page","Una pagina web"}.
{"Accept","Accettare"}.
{"Access denied by service policy","Accesso impedito dalle politiche del servizio"}.
{"Access denied by service policy","Accesso negato dalle politiche del servizio"}.
{"Access model","Modello di accesso"}.
{"Account doesn't exist","L'account non esiste"}.
{"Action on user","Azione sull'utente"}.
{"Add a hat to a user","Aggiungere un cappello a un utente"}.
{"Add User","Aggiungere un Utente"}.
{"Add User","Aggiungere un utente"}.
{"Administration of ","Amministrazione di "}.
{"Administration","Amministrazione"}.
{"Administrator privileges required","Sono richiesti privilegi di amministratore"}.
{"All activity","Tutta l'attività"}.
{"All Users","Tutti gli Utenti"}.
{"All Users","Tutti gli utenti"}.
{"Allow subscription","Consenti iscrizione"}.
{"Allow this Jabber ID to subscribe to this pubsub node?","Consentire a questo ID Jabber di iscriversi a questo nodo pubsub?"}.
{"Allow this person to register with the room?","Permettere a questa persona di registrarsi con la stanza?"}.
+1
View File
@@ -168,6 +168,7 @@
{"has been kicked because of an affiliation change","foi desconectado porque por afiliação inválida"}.
{"has been kicked because the room has been changed to members-only","foi desconectado porque a política da sala mudou, só membros são permitidos"}.
{"has been kicked","foi removido"}.
{"Hash of the vCard-temp avatar of this room","Hash do avatar do vCard-temp desta sala"}.
{"Hat title","Título do chapéu"}.
{"Hat URI","URI do chapéu"}.
{"Hats limit exceeded","O limite dos chapéus foi excedido"}.
+7 -6
View File
@@ -168,6 +168,7 @@
{"has been kicked because of an affiliation change","由于从属关系的更改而被踢出"}.
{"has been kicked because the room has been changed to members-only","被踢出,因为群聊已更改为仅成员进入"}.
{"has been kicked","已被踢出"}.
{"Hash of the vCard-temp avatar of this room","此群聊 vCard-temp 头像的散列值"}.
{"Hat title","头衔标题"}.
{"Hat URI","头衔 URI"}.
{"Hats limit exceeded","已超过头衔限制"}.
@@ -226,12 +227,12 @@
{"Logged Out","已登出"}.
{"Logging","日志记录"}.
{"Make participants list public","公开参与者列表"}.
{"Make room CAPTCHA protected","群聊验证码保护"}.
{"Make room members-only","让群聊仅成员进入"}.
{"Make room CAPTCHA protected","开启群聊验证码保护"}.
{"Make room members-only","仅成员进入的群聊"}.
{"Make room moderated","开启群聊发言审核"}.
{"Make room password protected","群聊密码保护"}.
{"Make room persistent","让群聊持续存在"}.
{"Make room public searchable","让群聊可公开搜索"}.
{"Make room password protected","开启群聊密码保护"}.
{"Make room persistent","持续存在的群聊"}.
{"Make room public searchable","可公开搜索的群聊"}.
{"Malformed username","用户名格式不正确"}.
{"MAM preference modification denied by service policy","服务策略拒绝修改 MAM 首选项"}.
{"March","三月"}.
@@ -607,7 +608,7 @@
{"You are not allowed to send private messages","不允许您发送私信"}.
{"You are not joined to the channel","您未加入频道"}.
{"You can later change your password using an XMPP client.","您之后可以使用 XMPP 客户端更改密码。"}.
{"You have been banned from this room","您已被此群聊封禁"}.
{"You have been banned from this room","禁止您进入此群聊"}.
{"You have joined too many conferences","您加入了太多群聊"}.
{"You must fill in field \"Nickname\" in the form","您必须在表单中填写“昵称”字段"}.
{"You need a client that supports x:data and CAPTCHA to register","您需要支持 x:data 和验证码的客户端来注册"}.
+10 -9
View File
@@ -33,11 +33,11 @@
{if_var_true, redis,
{eredis, "~> 1.2.0", {git, "https://github.com/wooga/eredis", {tag, "v1.2.0"}}}},
{if_var_true, sip,
{esip, "~> 1.0.52", {git, "https://github.com/processone/esip", {tag, "1.0.54"}}}},
{esip, "~> 1.0.52", {git, "https://github.com/processone/esip", {tag, "1.0.56"}}}},
{if_var_true, zlib,
{ezlib, "~> 1.0.12", {git, "https://github.com/processone/ezlib", {tag, "1.0.13"}}}},
{fast_tls, "~> 1.1.19", {git, "https://github.com/processone/fast_tls", {tag, "1.1.21"}}},
{fast_xml, "~> 1.1.51", {git, "https://github.com/processone/fast_xml", {tag, "1.1.52"}}},
{fast_tls, "~> 1.1.19", {git, "https://github.com/processone/fast_tls", {tag, "1.1.22"}}},
{fast_xml, ".*", {git, "https://github.com/processone/fast_xml", {tag, "1.1.53"}}},
{fast_yaml, "~> 1.0.36", {git, "https://github.com/processone/fast_yaml", {tag, "1.0.37"}}},
{idna, "~> 6.0", {git, "https://github.com/benoitc/erlang-idna", {tag, "6.0.0"}}},
{if_version_below, "27",
@@ -56,20 +56,20 @@
{luerl, "~> 1.2.0", {git, "https://github.com/rvirding/luerl", {tag, "1.2"}}}
}},
{mqtree, "~> 1.0.16", {git, "https://github.com/processone/mqtree", {tag, "1.0.17"}}},
{p1_acme, "~> 1.0.23", {git, "https://github.com/processone/p1_acme", {tag, "1.0.23"}}},
{p1_acme, "~> 1.0.23", {git, "https://github.com/processone/p1_acme", {tag, "1.0.24"}}},
{if_var_true, mysql,
{p1_mysql, "~> 1.0.24", {git, "https://github.com/processone/p1_mysql", {tag, "1.0.24"}}}},
{p1_mysql, "~> 1.0.24", {git, "https://github.com/processone/p1_mysql", {tag, "1.0.25"}}}},
{p1_oauth2, "~> 0.6.14", {git, "https://github.com/processone/p1_oauth2", {tag, "0.6.14"}}},
{if_var_true, pgsql,
{p1_pgsql, "~> 1.1.26", {git, "https://github.com/processone/p1_pgsql", {tag, "1.1.27"}}}},
{p1_pgsql, "~> 1.1.26", {git, "https://github.com/processone/p1_pgsql", {tag, "1.1.28"}}}},
{p1_utils, "~> 1.0.25", {git, "https://github.com/processone/p1_utils", {tag, "1.0.26"}}},
{pkix, "~> 1.0.10", {git, "https://github.com/processone/pkix", {tag, "1.0.10"}}},
{if_var_true, sqlite,
{sqlite3, "~> 1.1.14", {git, "https://github.com/processone/erlang-sqlite3", {tag, "1.1.15"}}}},
{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", {tag, "1.8.3"}}},
{stun, "~> 1.2.12", {git, "https://github.com/processone/stun", {tag, "1.2.15"}}}},
{xmpp, "~> 1.9.0", {git, "https://github.com/processone/xmpp", {tag, "1.9.0"}}},
{yconf, "~> 1.0.15", {git, "https://github.com/processone/yconf", {tag, "1.0.16"}}}
]}.
@@ -156,7 +156,8 @@
{branch, "consolidation_fix"}}}
}]}}.
{if_rebar3, {project_plugins, [configure_deps,
{if_var_true, tools, rebar3_format}
{if_var_true, tools, rebar3_format},
{if_var_true, tools, rebar3_lint}
]}}.
{if_not_rebar3, {plugins, [
deps_erl_opts, override_deps_versions2, override_opts, configure_deps
+24 -24
View File
@@ -4,27 +4,27 @@
{<<"eimp">>,{pkg,<<"eimp">>,<<"1.0.23">>},0},
{<<"epam">>,{pkg,<<"epam">>,<<"1.0.14">>},0},
{<<"eredis">>,{pkg,<<"eredis">>,<<"1.2.0">>},0},
{<<"esip">>,{pkg,<<"esip">>,<<"1.0.54">>},0},
{<<"esip">>,{pkg,<<"esip">>,<<"1.0.56">>},0},
{<<"ezlib">>,{pkg,<<"ezlib">>,<<"1.0.13">>},0},
{<<"fast_tls">>,{pkg,<<"fast_tls">>,<<"1.1.21">>},0},
{<<"fast_xml">>,{pkg,<<"fast_xml">>,<<"1.1.52">>},0},
{<<"fast_tls">>,{pkg,<<"fast_tls">>,<<"1.1.22">>},0},
{<<"fast_xml">>,{pkg,<<"fast_xml">>,<<"1.1.53">>},0},
{<<"fast_yaml">>,{pkg,<<"fast_yaml">>,<<"1.0.37">>},0},
{<<"idna">>,{pkg,<<"idna">>,<<"6.1.1">>},0},
{<<"jiffy">>,{pkg,<<"jiffy">>,<<"1.1.2">>},1},
{<<"jose">>,{pkg,<<"jose">>,<<"1.11.10">>},0},
{<<"luerl">>,{pkg,<<"luerl">>,<<"1.2.0">>},0},
{<<"mqtree">>,{pkg,<<"mqtree">>,<<"1.0.17">>},0},
{<<"p1_acme">>,{pkg,<<"p1_acme">>,<<"1.0.23">>},0},
{<<"p1_mysql">>,{pkg,<<"p1_mysql">>,<<"1.0.24">>},0},
{<<"p1_acme">>,{pkg,<<"p1_acme">>,<<"1.0.24">>},0},
{<<"p1_mysql">>,{pkg,<<"p1_mysql">>,<<"1.0.25">>},0},
{<<"p1_oauth2">>,{pkg,<<"p1_oauth2">>,<<"0.6.14">>},0},
{<<"p1_pgsql">>,{pkg,<<"p1_pgsql">>,<<"1.1.27">>},0},
{<<"p1_pgsql">>,{pkg,<<"p1_pgsql">>,<<"1.1.28">>},0},
{<<"p1_utils">>,{pkg,<<"p1_utils">>,<<"1.0.26">>},0},
{<<"pkix">>,{pkg,<<"pkix">>,<<"1.0.10">>},0},
{<<"sqlite3">>,{pkg,<<"sqlite3">>,<<"1.1.15">>},0},
{<<"stringprep">>,{pkg,<<"stringprep">>,<<"1.0.30">>},0},
{<<"stun">>,{pkg,<<"stun">>,<<"1.2.14">>},0},
{<<"stun">>,{pkg,<<"stun">>,<<"1.2.15">>},0},
{<<"unicode_util_compat">>,{pkg,<<"unicode_util_compat">>,<<"0.7.0">>},1},
{<<"xmpp">>,{pkg,<<"xmpp">>,<<"1.8.3">>},0},
{<<"xmpp">>,{pkg,<<"xmpp">>,<<"1.9.0">>},0},
{<<"yconf">>,{pkg,<<"yconf">>,<<"1.0.16">>},0}]}.
[
{pkg_hash,[
@@ -33,27 +33,27 @@
{<<"eimp">>, <<"AAF32EFAB061143403DADBAA63E699EF8E81702FBFA96FD436D5E9BE4D6A8D3A">>},
{<<"epam">>, <<"AA0B85D27F4EF3A756AE995179DF952A0721237E83C6B79D644347B75016681A">>},
{<<"eredis">>, <<"0B8E9CFC2C00FA1374CD107EA63B49BE08D933DF2CF175E6A89B73DD9C380DE4">>},
{<<"esip">>, <<"DAE8FB8278FD3B2C0D38C2E832C4B8D26700EB239B9A42C8EA574FEE76F5E76A">>},
{<<"esip">>, <<"63C0FDC667BE751714E1E5C14621A9334F21B60AC1BB68BE889454CA9CA021B7">>},
{<<"ezlib">>, <<"3C7F62862850A241159C10B218ECF580BCE54D0890601B65144DACC2633BE2B0">>},
{<<"fast_tls">>, <<"65D7D547A09EEFB37A1C0D04D8601FAC4F3E6E2C1EDE859A7787081670F9648D">>},
{<<"fast_xml">>, <<"0289DAAFBF1190B0E53B444D4885CCCF41E4B05768D4B3ACC76DD8D143668E10">>},
{<<"fast_tls">>, <<"44356B256AFAD4399C2FC5059A3066669DAFD8BD4E4E796C9C1CF8910DDD265E">>},
{<<"fast_xml">>, <<"1EF4F6E5995BCFA94800A46B460C3400C19C0A533948B12200A2E2FB1A2BE427">>},
{<<"fast_yaml">>, <<"F71D472FBF787CCD161B914D1EB486116A0F4F2E835337A378FBD31B59D2E74B">>},
{<<"idna">>, <<"8A63070E9F7D0C62EB9D9FCB360A7DE382448200FBBD1B106CC96D3D8099DF8D">>},
{<<"jiffy">>, <<"A9B6C9A7EC268E7CF493D028F0A4C9144F59CCB878B1AFE42841597800840A1B">>},
{<<"jose">>, <<"A903F5227417BD2A08C8A00A0CBCC458118BE84480955E8D251297A425723F83">>},
{<<"luerl">>, <<"60F05F4240F0E7C148DDB79B67B8FF972734AAD237AA74C83D0748B8214C8EF0">>},
{<<"mqtree">>, <<"82F54B8F2D22B4445DB1D6CCCB7FE9EAD049D61410C29E32475F3CEB3EE62A89">>},
{<<"p1_acme">>, <<"791AEF0F79DC7F768B228808250C349FA9CE585CD8779DA50CA93106EB3394D0">>},
{<<"p1_mysql">>, <<"0ED1E098C5A4525032448C65A2715F30980AAE725615A4D255FD25F26BB22507">>},
{<<"p1_acme">>, <<"E19876618EB0BE22815ACA99640CB88CD5C86E4239B8E8DC15B4E5D7854EF7E2">>},
{<<"p1_mysql">>, <<"875D4CBDC7C9990270DF3292CCE2514E4C18A9FDFD19BEF258CB4D0C45B4F243">>},
{<<"p1_oauth2">>, <<"1C5F82535574DE87E2059695AC4B91F8F9AEBACBC1C80287DAE6F02552D47AEA">>},
{<<"p1_pgsql">>, <<"883E335D82AC062DE0BDE7981F8250A2E632258BB7A47DF839A4CBDCB3E971E6">>},
{<<"p1_pgsql">>, <<"08ECA7D2AFC81BA6D757B572F4A57EF3A2383B0C7B785FDE38184BC368376D54">>},
{<<"p1_utils">>, <<"67B0C4AC9FA3BA3EF563B31AA111B0A004439A37FAC85E027F1C3617E1C7EC6C">>},
{<<"pkix">>, <<"D3BFADF7B7CFE2A3636F1B256C9CCE5F646A07CE31E57EE527668502850765A0">>},
{<<"sqlite3">>, <<"E819DEFD280145C328457D7AF897D2E45E8E5270E18812EE30B607C99CDD21AF">>},
{<<"stringprep">>, <<"46CF0FF631B3E7328F61F20B454D59428D87738F25D709798B5DCBB9B83C23F1">>},
{<<"stun">>, <<"6F538AC80C842131DBD149055570D116BFABC9B5EBFF4BD6AF2E7888958C660C">>},
{<<"stun">>, <<"EEC510AF6509201FF97F1F2C87B7977C833BF29C04E985383370EC21F04E4CCF">>},
{<<"unicode_util_compat">>, <<"BC84380C9AB48177092F43AC89E4DFA2C6D62B40B8BD132B1059ECC7232F9A78">>},
{<<"xmpp">>, <<"ACF39A8B70B066BB8F10B0862E031E8ABCF92FE89D1C41D06C1E39AE5CAF89C4">>},
{<<"xmpp">>, <<"D92446BF51D36ADDA02DB63B963FE6D4A1EDE33E59B38A43D9B90AFD20C25B74">>},
{<<"yconf">>, <<"D59521D66FF89F219411B6E9277CD6FEEC7CC6FCE11554E67DE02A8D0A470479">>}]},
{pkg_hash_ext,[
{<<"base64url">>, <<"F9B3ADD4731A02A9B0410398B475B33E7566A695365237A6BDEE1BB447719F5C">>},
@@ -61,26 +61,26 @@
{<<"eimp">>, <<"907C780023CB2893E4FC4BDBE6A4F02C355913862AC67F0ECC26605E816B628A">>},
{<<"epam">>, <<"2F3449E72885A72A6C2A843F561ADD0FC2F70D7A21F61456930A547473D4D989">>},
{<<"eredis">>, <<"D9B5ABEF2C2C8ABA8F32AA018203E0B3DC8B1157773B254AB1D4C2002317F1E1">>},
{<<"esip">>, <<"8187AF819D7259CDADDAF69726C239EF604C9B0B0298A5F2D3E687BF5E2237EE">>},
{<<"esip">>, <<"9EF3660CEF93B623F7368DCD5C79F4E704358631909E6DD464E335378815DA1F">>},
{<<"ezlib">>, <<"9EE62AB3F8ED55A0FD11A9569FCB8E458683F95575417272192B069F092ABFBB">>},
{<<"fast_tls">>, <<"131542913937025E48CD80AA81F00359686D5501B75621E72026A87B5229505B">>},
{<<"fast_xml">>, <<"795192390E06D2B65016A6990BBFA5727F4A26D2914808B1C3C9A32EEDCD1BFD">>},
{<<"fast_tls">>, <<"E65779AEFB7AB15C4755230FEF8077E687D20CC5A3984A5974F9F657E8E2485B">>},
{<<"fast_xml">>, <<"5064336D6F363EEE5097AA5DC5CED9B67F05152F2E6B8520FD50D268C2AB839C">>},
{<<"fast_yaml">>, <<"8DE868721BF7E2172414F7D3148EDE0F3C922B496455CD625DD5C4429515A769">>},
{<<"idna">>, <<"92376EB7894412ED19AC475E4A86F7B413C1B9FBB5BD16DCCD57934157944CEA">>},
{<<"jiffy">>, <<"BB61BC42A720BBD33CB09A410E48BB79A61012C74CB8B3E75F26D988485CF381">>},
{<<"jose">>, <<"0D6CD36FF8BA174DB29148FC112B5842186B68A90CE9FC2B3EC3AFE76593E614">>},
{<<"luerl">>, <<"9CAFD4F6094FF0F5A9D278FD81D60D3E026C820BDFB6CACD4B1BD909F21B525D">>},
{<<"mqtree">>, <<"5FE8B7CF8FBC4783D0FCEB94654AC2BBF3242A58CD0397D249DED8AE021BE2A3">>},
{<<"p1_acme">>, <<"8CE196F26E3D22EA10B7809122950465878C127F80767E325207AED7E8D0DD59">>},
{<<"p1_mysql">>, <<"F058865F64257F507A2C6A5AFF369B1375DBCB30B3D4258DAD4F1B3EAFFB655F">>},
{<<"p1_acme">>, <<"F1451D706595EF997AB1CA17162DDAC58F874AC97E315A5FADBE3CFA26148002">>},
{<<"p1_mysql">>, <<"E6187FFAE95B726098E88F3EE6F2344AC259CE2C26E0EE403B05FEEF341AE434">>},
{<<"p1_oauth2">>, <<"1FD3AC474E43722D9D5A87C6DF8D36F698ED87AF7BB81CBBB66361451D99AE8F">>},
{<<"p1_pgsql">>, <<"8E4D1A7602CB68780E55D89DC5A9B2E1AACA3F4F1EE3D1A25F2F8C3D2364FFB9">>},
{<<"p1_pgsql">>, <<"655BB75DF036ACE55DDCE17CA741143C42E0667C6206AC27A4DCBC65F71AC9EF">>},
{<<"p1_utils">>, <<"D0379E8C1156B98BD64F8129C1DE022FCCA4F2FDB7486CE73BF0ED2C3376B04C">>},
{<<"pkix">>, <<"E02164F83094CB124C41B1AB28988A615D54B9ADC38575F00F19A597A3AC5D0E">>},
{<<"sqlite3">>, <<"3C0BA4E13322C2AD49DE4E2DDD28311366ADDE54BEAE8DBA9D9E3888F69D2857">>},
{<<"stringprep">>, <<"F6FC9B3384A03877830F89B2F38580CAF3F4A27448A4A333D6A8C3975C220B9A">>},
{<<"stun">>, <<"E134807B1B7A8DFFD94E64EEFEE00E65C7B4042F3D14E16F8F43566D20371583">>},
{<<"stun">>, <<"F6D8A541A29FD13F2CE658B676C0CC661262B96E045B52DEF1644B75EBC0EDEF">>},
{<<"unicode_util_compat">>, <<"25EEE6D67DF61960CF6A794239566599B09E17E668D3700247BC498638152521">>},
{<<"xmpp">>, <<"ED70065F9A89A818DCFF43B74C080C9E7F4F1414E1051BEDDB7280DB809AF711">>},
{<<"xmpp">>, <<"C1B91BE74A9A9503AFA6766F756477516920FFBFEEA0C260C2FA171355F53C27">>},
{<<"yconf">>, <<"E947813273F38711C7B2E5A8E4ACC9A51C7BBE854F744A345F60300B38586C89">>}]}
].
+1 -1
View File
@@ -122,7 +122,7 @@ CREATE INDEX i_archive_sh_timestamp USING BTREE ON archive(server_host(191), tim
CREATE INDEX i_archive_sh_username_origin_id USING BTREE ON archive(server_host(191), username(191), origin_id(191));
-- To update 'archive' from ejabberd <= 23.10:
-- ALTER TABLE archive ADD COLUMN origin_id text NOT NULL DEFAULT '';
-- ALTER TABLE archive ADD COLUMN origin_id varchar(191) NOT NULL DEFAULT '';
-- ALTER TABLE archive ALTER COLUMN origin_id DROP DEFAULT;
-- CREATE INDEX i_archive_sh_username_origin_id USING BTREE ON archive(server_host(191), username(191), origin_id(191));
+1 -1
View File
@@ -110,7 +110,7 @@ CREATE INDEX i_timestamp USING BTREE ON archive(timestamp);
CREATE INDEX i_archive_username_origin_id USING BTREE ON archive(username(191), origin_id(191));
-- To update 'archive' from ejabberd <= 23.10:
-- ALTER TABLE archive ADD COLUMN origin_id origin_id(191) NOT NULL DEFAULT '';
-- ALTER TABLE archive ADD COLUMN origin_id varchar(191) NOT NULL DEFAULT '';
-- ALTER TABLE archive ALTER COLUMN origin_id DROP DEFAULT;
-- CREATE INDEX i_archive_username_origin_id USING BTREE ON archive(username(191), origin_id(191));
+8 -7
View File
@@ -203,6 +203,7 @@ get_commands_spec() ->
#ejabberd_commands{name = update, tags = [server],
desc = "Update the given module",
longdesc = "To update all the possible modules, use `all`.",
note = "improved in 24.10",
module = ?MODULE, function = update,
args_example = ["all"],
args = [{module, string}],
@@ -370,17 +371,17 @@ get_commands_spec() ->
args = [{out, string}],
result = {res, rescode}},
#ejabberd_commands{name = delete_expired_messages, tags = [purge],
#ejabberd_commands{name = delete_expired_messages, tags = [offline, purge],
desc = "Delete expired offline messages from database",
module = ?MODULE, function = delete_expired_messages,
args = [], result = {res, rescode}},
#ejabberd_commands{name = delete_old_messages, tags = [purge],
#ejabberd_commands{name = delete_old_messages, tags = [offline, purge],
desc = "Delete offline messages older than DAYS",
module = ?MODULE, function = delete_old_messages,
args_desc = ["Number of days"],
args_example = [31],
args = [{days, integer}], result = {res, rescode}},
#ejabberd_commands{name = delete_old_messages_batch, tags = [purge],
#ejabberd_commands{name = delete_old_messages_batch, tags = [offline, purge],
desc = "Delete offline messages older than DAYS",
note = "added in 22.05",
module = ?MODULE, function = delete_old_messages_batch,
@@ -393,7 +394,7 @@ get_commands_spec() ->
result = {res, restuple},
result_desc = "Result tuple",
result_example = {ok, <<"Removal of 5000 messages in progress">>}},
#ejabberd_commands{name = delete_old_messages_status, tags = [purge],
#ejabberd_commands{name = delete_old_messages_status, tags = [offline, purge],
desc = "Status of delete old offline messages operation",
note = "added in 22.05",
module = ?MODULE, function = delete_old_messages_status,
@@ -403,7 +404,7 @@ get_commands_spec() ->
result = {status, string},
result_desc = "Status test",
result_example = "Operation in progress, delete 5000 messages"},
#ejabberd_commands{name = abort_delete_old_messages, tags = [purge],
#ejabberd_commands{name = abort_delete_old_messages, tags = [offline, purge],
desc = "Abort currently running delete old offline messages operation",
note = "added in 22.05",
module = ?MODULE, function = delete_old_messages_abort,
@@ -528,7 +529,7 @@ get_commands_spec() ->
module = ejabberd_doc, function = man,
args = [], result = {res, restuple}},
#ejabberd_commands{name = webadmin_host_user_queue, tags = [internal],
#ejabberd_commands{name = webadmin_host_user_queue, tags = [offline, internal],
desc = "Generate WebAdmin offline queue HTML",
module = mod_offline, function = webadmin_host_user_queue,
args = [{user, binary}, {host, binary}, {query, any}, {lang, binary}],
@@ -746,7 +747,7 @@ update_module(ModuleNameString) ->
case ejabberd_update:update([ModuleName]) of
{ok, []} ->
{ok, "Not updated: "++ModuleNameString};
{ok, [{ModuleName, _}]} ->
{ok, [ModuleName]} ->
{ok, "Updated: "++ModuleNameString};
{error, Reason} -> {error, Reason}
end.
+20 -1
View File
@@ -59,10 +59,14 @@ start(normal, _Args) ->
ejabberd_hooks:run(ejabberd_started, []),
ejabberd:check_apps(),
ejabberd_systemd:ready(),
maybe_start_exsync(),
{T2, _} = statistics(wall_clock),
?INFO_MSG("ejabberd ~ts is started in the node ~p in ~.2fs",
[ejabberd_option:version(),
node(), (T2-T1)/1000]),
maybe_print_elixir_version(),
?INFO_MSG("~ts",
[erlang:system_info(system_version)]),
{ok, SupPid};
Err ->
?CRITICAL_MSG("Failed to start ejabberd application: ~p", [Err]),
@@ -175,7 +179,11 @@ file_queue_init() ->
-ifdef(ELIXIR_ENABLED).
is_using_elixir_config() ->
Config = ejabberd_config:path(),
'Elixir.Ejabberd.ConfigUtil':is_elixir_config(Config).
try 'Elixir.Ejabberd.ConfigUtil':is_elixir_config(Config) of
B when is_boolean(B) -> B
catch
_:_ -> false
end.
setup_if_elixir_conf_used() ->
case is_using_elixir_config() of
@@ -194,8 +202,19 @@ start_elixir_application() ->
ok -> ok;
{error, _Msg} -> ?ERROR_MSG("Elixir application not started.", [])
end.
maybe_start_exsync() ->
case os:getenv("RELIVE") of
"true" -> rpc:call(node(), 'Elixir.ExSync.Application', start, []);
_ -> ok
end.
maybe_print_elixir_version() ->
?INFO_MSG("Elixir ~ts", [maps:get(build, 'Elixir.System':build_info())]).
-else.
setup_if_elixir_conf_used() -> ok.
register_elixir_config_hooks() -> ok.
start_elixir_application() -> ok.
maybe_start_exsync() -> ok.
maybe_print_elixir_version() -> ok.
-endif.
+5
View File
@@ -293,6 +293,8 @@ try_register(User, Server, Password) ->
false ->
case ejabberd_router:is_my_host(LServer) of
true ->
case ejabberd_hooks:run_fold(check_register_user, LServer, true, [User, Server, Password]) of
true ->
case lists:foldl(
fun(_, ok) ->
ok;
@@ -307,6 +309,9 @@ try_register(User, Server, Password) ->
{error, _} = Err ->
Err
end;
false ->
{error, not_allowed}
end;
false ->
{error, not_allowed}
end
+3 -3
View File
@@ -44,9 +44,9 @@
%%%----------------------------------------------------------------------
start(Host) ->
%% We add our default JWT verifier with hook priority 100.
%% So if you need to check or verify your custom JWT before the
%% default verifier, It's better to use this hook with priority
%% little than 100 and return bool() or {stop, bool()} in your own
%% So if you need to check or verify your custom JWT before the
%% default verifier, It's better to use this hook with priority
%% little than 100 and return bool() or {stop, bool()} in your own
%% callback function.
ejabberd_hooks:add(check_decoded_jwt, Host, ?MODULE, check_decoded_jwt, 100),
case ejabberd_option:jwt_key(Host) of
-4
View File
@@ -41,8 +41,6 @@
-include("ejabberd_sql_pt.hrl").
-include("ejabberd_auth.hrl").
-define(SALT_LENGTH, 16).
%%%----------------------------------------------------------------------
%%% API
%%%----------------------------------------------------------------------
@@ -161,8 +159,6 @@ remove_user(User, Server) ->
{error, db_failure}
end.
-define(BATCH_SIZE, 1000).
scram_hash_encode(Hash, StoreKey) ->
case Hash of
sha -> StoreKey;
+14 -14
View File
@@ -308,9 +308,9 @@ init([#body{attrs = Attrs}, IP, SID]) ->
ignore
end.
wait_for_session(_Event, State) ->
wait_for_session(Event, State) ->
?ERROR_MSG("Unexpected event in 'wait_for_session': ~p",
[_Event]),
[Event]),
{next_state, wait_for_session, State}.
wait_for_session(#body{attrs = Attrs} = Req, From,
@@ -367,16 +367,16 @@ wait_for_session(#body{attrs = Attrs} = Req, From,
reply_next_state(State4, Resp#body{els = RespEls}, RID,
From)
end;
wait_for_session(_Event, _From, State) ->
wait_for_session(Event, _From, State) ->
?ERROR_MSG("Unexpected sync event in 'wait_for_session': ~p",
[_Event]),
[Event]),
{reply, {error, badarg}, wait_for_session, State}.
active({#body{} = Body, From}, State) ->
active1(Body, From, State);
active(_Event, State) ->
active(Event, State) ->
?ERROR_MSG("Unexpected event in 'active': ~p",
[_Event]),
[Event]),
{next_state, active, State}.
active(#body{attrs = Attrs, size = Size} = Req, From,
@@ -408,9 +408,9 @@ active(#body{attrs = Attrs, size = Size} = Req, From,
end;
true -> active1(Req, From, State1)
end;
active(_Event, _From, State) ->
active(Event, _From, State) ->
?ERROR_MSG("Unexpected sync event in 'active': ~p",
[_Event]),
[Event]),
{reply, {error, badarg}, active, State}.
active1(#body{attrs = Attrs} = Req, From, State) ->
@@ -517,9 +517,9 @@ handle_event({activate, C2SPid}, StateName,
handle_event({change_shaper, Shaper}, StateName,
State) ->
{next_state, StateName, State#state{shaper_state = Shaper}};
handle_event(_Event, StateName, State) ->
handle_event(Event, StateName, State) ->
?ERROR_MSG("Unexpected event in '~ts': ~p",
[StateName, _Event]),
[StateName, Event]),
{next_state, StateName, State}.
handle_sync_event({send_xml,
@@ -557,9 +557,9 @@ handle_sync_event(deactivate_socket, _From, StateName,
StateData) ->
{reply, ok, StateName,
StateData#state{c2s_pid = undefined}};
handle_sync_event(_Event, _From, StateName, State) ->
handle_sync_event(Event, _From, StateName, State) ->
?ERROR_MSG("Unexpected sync event in '~ts': ~p",
[StateName, _Event]),
[StateName, Event]),
{reply, {error, badarg}, StateName, State}.
handle_info({timeout, TRef, wait_timeout}, StateName,
@@ -583,9 +583,9 @@ handle_info({timeout, TRef, shaper_timeout}, StateName,
{stop, normal, State};
_ -> {next_state, StateName, State}
end;
handle_info(_Info, StateName, State) ->
handle_info(Info, StateName, State) ->
?ERROR_MSG("Unexpected info:~n** Msg: ~p~n** StateName: ~p",
[_Info, StateName]),
[Info, StateName]),
{next_state, StateName, State}.
terminate(_Reason, _StateName, State) ->
+29 -12
View File
@@ -35,16 +35,17 @@
-export([init/1, handle_call/3, handle_cast/2,
handle_info/2, terminate/2, code_change/3]).
-export([tls_options/1, tls_required/1, tls_enabled/1,
compress_methods/1, bind/2, sasl_mechanisms/2,
get_password_fun/2, check_password_fun/2, check_password_digest_fun/2,
unauthenticated_stream_features/1, authenticated_stream_features/1,
handle_stream_start/2, handle_stream_end/2,
handle_unauthenticated_packet/2, handle_authenticated_packet/2,
handle_auth_success/4, handle_auth_failure/4, handle_send/3,
handle_recv/3, handle_cdata/2, handle_unbinded_packet/2,
inline_stream_features/1, handle_sasl2_inline/2,
handle_sasl2_inline_post/3, handle_bind2_inline/2,
handle_bind2_inline_post/3, sasl_options/1]).
allow_unencrypted_sasl2/1, compress_methods/1, bind/2,
sasl_mechanisms/2, get_password_fun/2, check_password_fun/2,
check_password_digest_fun/2, unauthenticated_stream_features/1,
authenticated_stream_features/1, handle_stream_start/2,
handle_stream_end/2, handle_unauthenticated_packet/2,
handle_authenticated_packet/2, handle_auth_success/4,
handle_auth_failure/4, handle_send/3, handle_recv/3, handle_cdata/2,
handle_unbinded_packet/2, inline_stream_features/1,
handle_sasl2_inline/2, handle_sasl2_inline_post/3,
handle_bind2_inline/2, handle_bind2_inline_post/3, sasl_options/1,
handle_sasl2_task_next/4, handle_sasl2_task_data/3]).
%% Hooks
-export([handle_unexpected_cast/2, handle_unexpected_call/3,
process_auth_result/3, reject_unauthenticated_packet/2,
@@ -392,6 +393,9 @@ tls_enabled(#{tls_enabled := TLSEnabled,
tls_verify := TLSVerify}) ->
TLSEnabled or TLSRequired or TLSVerify.
allow_unencrypted_sasl2(#{allow_unencrypted_sasl2 := AllowUnencryptedSasl2}) ->
AllowUnencryptedSasl2.
compress_methods(#{zlib := true}) ->
[<<"zlib">>];
compress_methods(_) ->
@@ -404,7 +408,7 @@ authenticated_stream_features(#{lserver := LServer}) ->
ejabberd_hooks:run_fold(c2s_post_auth_features, LServer, [], [LServer]).
inline_stream_features(#{lserver := LServer}) ->
ejabberd_hooks:run_fold(c2s_inline_features, LServer, {[], []}, [LServer]).
ejabberd_hooks:run_fold(c2s_inline_features, LServer, {[], [], []}, [LServer]).
sasl_mechanisms(Mechs, #{lserver := LServer, stream_encrypted := Encrypted} = State) ->
Type = ejabberd_auth:store_type(LServer),
@@ -580,6 +584,14 @@ handle_bind2_inline_post(Els, Results, #{lserver := LServer} = State) ->
ejabberd_hooks:run_fold(c2s_handle_bind2_inline_post, LServer,
State, [Els, Results]).
handle_sasl2_task_next(Task, Els, InlineEls, #{lserver := LServer} = State) ->
ejabberd_hooks:run_fold(c2s_handle_sasl2_task_next, LServer,
{abort, State}, [Task, Els, InlineEls]).
handle_sasl2_task_data(Els, InlineEls, #{lserver := LServer} = State) ->
ejabberd_hooks:run_fold(c2s_handle_sasl2_task_data, LServer,
{abort, State}, [Els, InlineEls]).
handle_recv(El, Pkt, #{lserver := LServer} = State) ->
ejabberd_hooks:run_fold(c2s_handle_recv, LServer, State, [El, Pkt]).
@@ -604,12 +616,14 @@ init([State, Opts]) ->
TLSEnabled = proplists:get_bool(starttls, Opts),
TLSRequired = proplists:get_bool(starttls_required, Opts),
TLSVerify = proplists:get_bool(tls_verify, Opts),
AllowUnencryptedSasl2 = proplists:get_bool(allow_unencrypted_sasl2, Opts),
Zlib = proplists:get_bool(zlib, Opts),
Timeout = ejabberd_option:negotiation_timeout(),
State1 = State#{tls_options => TLSOpts2,
tls_required => TLSRequired,
tls_enabled => TLSEnabled,
tls_verify => TLSVerify,
allow_unencrypted_sasl2 => AllowUnencryptedSasl2,
pres_a => ?SETS:new(),
zlib => Zlib,
lang => ejabberd_option:language(),
@@ -1002,7 +1016,7 @@ get_conn_type(State) ->
websocket -> websocket
end.
-spec fix_from_to(xmpp_element(), state()) -> stanza().
-spec fix_from_to(xmpp_element(), state()) -> stanza() | xmpp_element().
fix_from_to(Pkt, #{jid := JID}) when ?is_stanza(Pkt) ->
#jid{luser = U, lserver = S, lresource = R} = JID,
case xmpp:get_from(Pkt) of
@@ -1047,6 +1061,8 @@ listen_opt_type(starttls) ->
econf:bool();
listen_opt_type(starttls_required) ->
econf:bool();
listen_opt_type(allow_unencrypted_sasl2) ->
econf:bool();
listen_opt_type(tls_verify) ->
econf:bool();
listen_opt_type(zlib) ->
@@ -1069,6 +1085,7 @@ listen_options() ->
{tls_compression, false},
{starttls, false},
{starttls_required, false},
{allow_unencrypted_sasl2, false},
{tls_verify, false},
{zlib, false},
{max_stanza_size, infinity},
+1 -2
View File
@@ -616,8 +616,7 @@ return(Port, TRef, Result) ->
is_feature_available() ->
case get_prog_name() of
Prog when is_binary(Prog) -> true;
MF when is_list(MF) -> true;
PathOrModule when is_binary(PathOrModule) -> true;
false -> false
end.
-2
View File
@@ -56,8 +56,6 @@
-include("logger.hrl").
-include_lib("stdlib/include/ms_transform.hrl").
-define(POLICY_ACCESS, '$policy').
-type auth() :: {binary(), binary(), binary() | {oauth, binary()}, boolean()} | map().
-record(state, {}).
+1 -1
View File
@@ -80,7 +80,7 @@ start_link() ->
add(Hook, Function, Seq) when is_function(Function) ->
add(Hook, global, undefined, Function, Seq).
-spec add(atom(), HostOrModule :: binary() | atom(), fun() | atom() , integer()) -> ok.
-spec add(atom(), HostOrModule :: binary() | atom(), fun() | atom(), integer()) -> ok.
add(Hook, Host, Function, Seq) when is_function(Function) ->
add(Hook, Host, undefined, Function, Seq);
+50 -100
View File
@@ -50,8 +50,7 @@
input = [] :: list(),
active = false :: boolean(),
c2s_pid :: pid(),
ws :: {#ws{}, pid()},
rfc_compliant = undefined :: boolean() | undefined}).
ws :: {#ws{}, pid()}}).
%-define(DBGFSM, true).
@@ -166,57 +165,38 @@ handle_event({new_shaper, Shaper}, StateName, #state{ws = {_, WsPid}} = StateDat
{next_state, StateName, StateData}.
handle_sync_event({send_xml, Packet}, _From, StateName,
#state{ws = {_, WsPid}, rfc_compliant = R} = StateData) ->
Packet2 = case {case R of undefined -> true; V -> V end, Packet} of
{true, {xmlstreamstart, _, Attrs}} ->
Attrs2 = [{<<"xmlns">>, <<"urn:ietf:params:xml:ns:xmpp-framing">>} |
lists:keydelete(<<"xmlns">>, 1, lists:keydelete(<<"xmlns:stream">>, 1, Attrs))],
{xmlstreamelement, #xmlel{name = <<"open">>, attrs = Attrs2}};
{true, {xmlstreamend, _}} ->
{xmlstreamelement, #xmlel{name = <<"close">>,
attrs = [{<<"xmlns">>, <<"urn:ietf:params:xml:ns:xmpp-framing">>}]}};
{true, {xmlstreamraw, <<"\r\n\r\n">>}} -> % cdata ping
skip;
{true, {xmlstreamelement, #xmlel{name=Name2} = El2}} ->
El3 = case Name2 of
<<"stream:", _/binary>> ->
fxml:replace_tag_attr(<<"xmlns:stream">>, ?NS_STREAM, El2);
_ ->
case fxml:get_tag_attr_s(<<"xmlns">>, El2) of
<<"">> ->
fxml:replace_tag_attr(<<"xmlns">>, <<"jabber:client">>, El2);
_ ->
El2
end
end,
{xmlstreamelement , El3};
_ ->
Packet
end,
case Packet2 of
{xmlstreamstart, Name, Attrs3} ->
B = fxml:element_to_binary(#xmlel{name = Name, attrs = Attrs3}),
route_text(WsPid, <<(binary:part(B, 0, byte_size(B)-2))/binary, ">">>);
{xmlstreamend, Name} ->
route_text(WsPid, <<"</", Name/binary, ">">>);
{xmlstreamelement, El} ->
route_text(WsPid, fxml:element_to_binary(El));
{xmlstreamraw, Bin} ->
route_text(WsPid, Bin);
{xmlstreamcdata, Bin2} ->
route_text(WsPid, Bin2);
skip ->
ok
end,
SN2 = case Packet2 of
{xmlstreamelement, #xmlel{name = <<"close">>}} ->
stream_end_sent;
_ ->
StateName
end,
#state{ws = {_, WsPid}} = StateData) ->
SN2 = case Packet of
{xmlstreamstart, _, Attrs} ->
Attrs2 = [{<<"xmlns">>, <<"urn:ietf:params:xml:ns:xmpp-framing">>} |
lists:keydelete(<<"xmlns">>, 1, lists:keydelete(<<"xmlns:stream">>, 1, Attrs))],
route_el(WsPid, #xmlel{name = <<"open">>, attrs = Attrs2}),
StateName;
{xmlstreamend, _} ->
route_el(WsPid, #xmlel{name = <<"close">>,
attrs = [{<<"xmlns">>, <<"urn:ietf:params:xml:ns:xmpp-framing">>}]}),
stream_end_sent;
{xmlstreamraw, <<"\r\n\r\n">>} ->
% cdata ping
StateName;
{xmlstreamelement, #xmlel{name = Name2} = El2} ->
El3 = case Name2 of
<<"stream:", _/binary>> ->
fxml:replace_tag_attr(<<"xmlns:stream">>, ?NS_STREAM, El2);
_ ->
case fxml:get_tag_attr_s(<<"xmlns">>, El2) of
<<"">> ->
fxml:replace_tag_attr(<<"xmlns">>, <<"jabber:client">>, El2);
_ ->
El2
end
end,
route_el(WsPid, El3),
StateName
end,
{reply, ok, SN2, StateData};
handle_sync_event(close, _From, StateName, #state{ws = {_, WsPid}, rfc_compliant = true} = StateData)
when StateName /= stream_end_sent ->
handle_sync_event(close, _From, StateName, #state{ws = {_, WsPid}} = StateData)
when StateName /= stream_end_sent ->
Close = #xmlel{name = <<"close">>,
attrs = [{<<"xmlns">>, <<"urn:ietf:params:xml:ns:xmpp-framing">>}]},
route_text(WsPid, fxml:element_to_binary(Close)),
@@ -230,7 +210,7 @@ handle_info({received, Packet}, StateName, StateDataI) ->
{StateData, Parsed} = parse(StateDataI, Packet),
SD = case StateData#state.active of
false ->
Input = StateData#state.input ++ if is_binary(Parsed) -> [Parsed]; true -> Parsed end,
Input = StateData#state.input ++ Parsed,
StateData#state{input = Input};
true ->
StateData#state.c2s_pid ! {tcp, StateData#state.socket, Parsed},
@@ -313,53 +293,19 @@ get_human_html_xmlel() ->
"client that supports it.">>}]}]}]}.
parse(#state{rfc_compliant = C} = State, Data) ->
case C of
undefined ->
P = fxml_stream:new(self()),
P2 = fxml_stream:parse(P, Data),
fxml_stream:close(P2),
case parsed_items([]) of
error ->
{State#state{rfc_compliant = true}, <<"parse error">>};
[] ->
{State#state{rfc_compliant = true}, <<"parse error">>};
[{xmlstreamstart, <<"open">>, _} | _] ->
parse(State#state{rfc_compliant = true}, Data);
_ ->
parse(State#state{rfc_compliant = false}, Data)
end;
true ->
El = fxml_stream:parse_element(Data),
case El of
#xmlel{name = <<"open">>, attrs = Attrs} ->
Attrs2 = [{<<"xmlns:stream">>, ?NS_STREAM}, {<<"xmlns">>, <<"jabber:client">>} |
lists:keydelete(<<"xmlns">>, 1, lists:keydelete(<<"xmlns:stream">>, 1, Attrs))],
{State, [{xmlstreamstart, <<"stream:stream">>, Attrs2}]};
#xmlel{name = <<"close">>} ->
{State, [{xmlstreamend, <<"stream:stream">>}]};
{error, _} ->
{State, <<"parse error">>};
_ ->
{State, [El]}
end;
false ->
{State, Data}
end.
parsed_items(List) ->
receive
{'$gen_event', El}
when element(1, El) == xmlel;
element(1, El) == xmlstreamstart;
element(1, El) == xmlstreamelement;
element(1, El) == xmlstreamcdata;
element(1, El) == xmlstreamend ->
parsed_items([El | List]);
{'$gen_event', {xmlstreamerror, _}} ->
error
after 0 ->
lists:reverse(List)
parse(State, Data) ->
El = fxml_stream:parse_element(Data),
case El of
#xmlel{name = <<"open">>, attrs = Attrs} ->
Attrs2 = [{<<"xmlns:stream">>, ?NS_STREAM}, {<<"xmlns">>, <<"jabber:client">>} |
lists:keydelete(<<"xmlns">>, 1, lists:keydelete(<<"xmlns:stream">>, 1, Attrs))],
{State, [{xmlstreamstart, <<"stream:stream">>, Attrs2}]};
#xmlel{name = <<"close">>} ->
{State, [{xmlstreamend, <<"stream:stream">>}]};
{error, _} ->
{State, [{xmlstreamerror, {4, <<"not well-formed">>}}]};
_ ->
{State, [El]}
end.
-spec route_text(pid(), binary()) -> ok.
@@ -369,3 +315,7 @@ route_text(Pid, Data) ->
{text_reply, Pid} ->
ok
end.
-spec route_el(pid(), xmlel() | cdata()) -> ok.
route_el(Pid, Data) ->
route_text(Pid, fxml:element_to_binary(Data)).
-2
View File
@@ -60,8 +60,6 @@
-optional_callbacks([listen_opt_type/1, tcp_init/2, udp_init/2]).
-define(TCP_SEND_TIMEOUT, 15000).
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
+1 -1
View File
@@ -283,7 +283,7 @@ start(Level) ->
burst_limit_window_time => LogBurstLimitWindowTime,
burst_limit_max_count => LogBurstLimitCount},
FmtConfig = #{legacy_header => false,
time_designator => $ ,
time_designator => $\s,
max_size => 100*1024,
single_line => false},
FileFmtConfig = FmtConfig#{template => file_template()},
-1
View File
@@ -39,7 +39,6 @@
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
-define(STORAGE_TYPES, [disc_copies, disc_only_copies, ram_copies]).
-define(NEED_RESET, [local_content, type]).
-include("logger.hrl").
+1 -1
View File
@@ -619,7 +619,7 @@ strings_to_binary(L) when is_list(L) ->
end;
strings_to_binary({A, B, C, D}) when
is_integer(A), is_integer(B), is_integer(C), is_integer(D) ->
{A, B, C ,D};
{A, B, C, D};
strings_to_binary(T) when is_tuple(T) ->
list_to_tuple(strings_to_binary1(tuple_to_list(T)));
strings_to_binary(X) ->
+1 -1
View File
@@ -330,7 +330,7 @@ cache_size() ->
cache_size(Host) ->
ejabberd_config:get_option({cache_size, Host}).
-spec captcha_cmd() -> any().
-spec captcha_cmd() -> 'undefined' | binary().
captcha_cmd() ->
ejabberd_config:get_option({captcha_cmd, global}).
+1
View File
@@ -491,6 +491,7 @@ opt_type(jwt_auth_only_rule) ->
{c2s_protocol_options, undefined | binary()} |
{s2s_ciphers, undefined | binary()} |
{c2s_ciphers, undefined | binary()} |
{captcha_cmd, undefined | binary()} |
{websocket_origin, [binary()]} |
{disable_sasl_mechanisms, [binary()]} |
{s2s_zlib, boolean()} |
+90 -48
View File
@@ -30,8 +30,9 @@ doc() ->
[{hosts,
#{value => ?T("[Domain1, Domain2, ...]"),
desc =>
?T("The option defines a list containing one or more "
"domains that 'ejabberd' will serve. This is a "
?T("List of one or more "
"_`../configuration/basic.md#host-names|host names`_ "
"(or domains) that 'ejabberd' will serve. This is a "
"**mandatory** option.")}},
{listen,
#{value => "[Options, ...]",
@@ -42,15 +43,15 @@ doc() ->
{modules,
#{value => "{Module: Options}",
desc =>
?T("The option for modules configuration. See "
"_`modules.md|Modules`_ section "
"for details.")}},
?T("Set all the "
"_`modules.md|modules`_ configuration options.")}},
{loglevel,
#{value =>
"none | emergency | alert | critical | "
"error | warning | notice | info | debug",
desc =>
?T("Verbosity of log files generated by ejabberd. "
?T("Verbosity of ejabberd "
"_`../configuration/basic.md#logging|logging`_. "
"The default value is 'info'. "
"NOTE: previous versions of ejabberd had log levels "
"defined in numeric format ('0..5'). The numeric values "
@@ -106,7 +107,8 @@ doc() ->
{default_db,
#{value => "mnesia | sql",
desc =>
?T("Default persistent storage for ejabberd. "
?T("_`database.md#default-database|Default database`_ "
"to store persistent data in ejabberd. "
"Modules and other components (e.g. authentication) "
"may have its own value. The default value is 'mnesia'.")}},
{default_ram_db,
@@ -135,7 +137,9 @@ doc() ->
{acl,
#{value => "{ACLName: {ACLType: ACLValue}}",
desc =>
?T("The option defines access control lists: named sets "
?T("This option defines "
"_`../configuration/basic.md#acl|access control lists`_: "
"named sets "
"of rules which are used to match against different targets "
"(such as a JID or an IP address). Every set of rules "
"has name 'ACLName': it can be any string except 'all' or 'none' "
@@ -317,7 +321,9 @@ doc() ->
{anonymous_protocol,
#{value => "login_anon | sasl_anon | both",
desc =>
[?T("Define what anonymous protocol will be used: "), "",
[?T("Define what "
"_`authentication.md#anonymous-login-and-sasl-anonymous|anonymous`_ "
"protocol will be used: "), "",
?T("* 'login_anon' means that the anonymous login method will be used. "), "",
?T("* 'sasl_anon' means that the SASL Anonymous method will be used. "), "",
?T("* 'both' means that SASL Anonymous and login anonymous are both "
@@ -332,10 +338,8 @@ doc() ->
{append_host_config,
#{value => "{Host: Options}",
desc =>
?T("To define specific ejabberd modules in a virtual host, "
"you can define the global 'modules' option with the common modules, "
"and later add specific modules to certain virtual hosts. "
"To accomplish that, 'append_host_config' option can be used.")}},
?T("Add a few specific options to a certain "
"_`../configuration/basic.md#virtual-hosting|virtual host`_.")}},
{auth_cache_life_time,
#{value => "timeout()",
desc =>
@@ -354,7 +358,7 @@ doc() ->
{auth_method,
#{value => "[mnesia | sql | anonymous | external | jwt | ldap | pam, ...]",
desc =>
?T("A list of authentication methods to use. "
?T("A list of _`authentication.md|authentication`_ methods to use. "
"If several methods are defined, authentication is "
"considered successful as long as authentication of "
"at least one of the methods succeeds. "
@@ -533,7 +537,9 @@ doc() ->
{define_macro,
#{value => "{MacroName: MacroValue}",
desc =>
?T("Defines a macro. The value can be any valid arbitrary "
?T("Defines a "
"_`../configuration/file-format.md#macros-in-configuration-file|macro`_. "
"The value can be any valid arbitrary "
"YAML value. For convenience, it's recommended to define "
"a 'MacroName' in capital letters. Duplicated macros are not allowed. "
"Macros are processed after additional configuration files have "
@@ -572,7 +578,9 @@ doc() ->
{domain_balancing,
#{value => "{Domain: Options}",
desc =>
?T("An algorithm to load balance the components that are plugged "
?T("An algorithm to "
"_`../guide/clustering.md#service-load-balancing|load-balance`_ "
"the components that are plugged "
"on an ejabberd cluster. It means that you can plug one or several "
"instances of the same component on each ejabberd node and that "
"the traffic will be automatically distributed. The algorithm "
@@ -605,19 +613,23 @@ doc() ->
{extauth_pool_name,
#{value => ?T("Name"),
desc =>
?T("Define the pool name appendix, so the full pool name will be "
?T("Define the pool name appendix in "
"_`authentication.md#external-script|external auth`_, "
"so the full pool name will be "
"'extauth_pool_Name'. The default value is the hostname.")}},
{extauth_pool_size,
#{value => ?T("Size"),
desc =>
?T("The option defines the number of instances of the same "
"external program to start for better load balancing. "
"_`authentication.md#external-script|external auth`_ "
"program to start for better load balancing. "
"The default is the number of available CPU cores.")}},
{extauth_program,
#{value => ?T("Path"),
desc =>
?T("Indicate in this option the full path to the external "
"authentication script. The script must be executable by ejabberd.")}},
?T("Indicate in this option the full path to the "
"_`authentication.md#external-script|external authentication script`_. "
"The script must be executable by ejabberd.")}},
{ext_api_headers,
#{value => "Headers",
desc =>
@@ -655,8 +667,10 @@ doc() ->
{host_config,
#{value => "{Host: Options}",
desc =>
?T("The option is used to redefine 'Options' for virtual host "
"'Host'. In the example below LDAP authentication method "
?T("The option is used to redefine 'Options' for "
"_`../configuration/basic.md#virtual-hosting|virtual host`_ "
"'Host'. "
"In the example below LDAP authentication method "
"will be used on virtual host 'domain.tld' and SQL method "
"will be used on virtual host 'example.org'."),
example =>
@@ -674,7 +688,9 @@ doc() ->
{include_config_file,
#{value => "[Filename, ...\\] | {Filename: Options}",
desc =>
?T("Read additional configuration from 'Filename'. If the "
?T("Read and "
"_`../configuration/file-format.md#include-additional-files|include additional file`_ "
"from 'Filename'. If the "
"value is provided in 'pass:[{Filename: Options}]' format, the "
"'Options' must be one of the following:")},
[{disallow,
@@ -701,7 +717,8 @@ doc() ->
{jwt_auth_only_rule,
#{value => ?T("AccessName"),
desc =>
?T("This ACL rule defines accounts that can use only this auth "
?T("This ACL rule defines accounts that can use only the "
"_`authentication.md#jwt-authentication|JWT`_ auth "
"method, even if others are also defined in the ejabberd "
"configuration file. In other words: if there are several auth "
"methods enabled for this host (JWT, SQL, ...), users that "
@@ -711,36 +728,44 @@ doc() ->
#{value => ?T("FieldName"),
desc =>
?T("By default, the JID is defined in the '\"jid\"' JWT field. "
"In this option you can specify other JWT field name "
"In this option you can specify other "
"_`authentication.md#jwt-authentication|JWT`_ "
"field name "
"where the JID is defined.")}},
{jwt_key,
#{value => ?T("FilePath"),
desc =>
?T("Path to the file that contains the JWK Key. "
?T("Path to the file that contains the "
"_`authentication.md#jwt-authentication|JWT`_ key. "
"The default value is 'undefined'.")}},
{language,
#{value => ?T("Language"),
desc =>
?T("The option defines the default language of server strings "
?T("Define the "
"_`../configuration/basic.md#default-language|default language`_ "
"of server strings "
"that can be seen by XMPP clients. If an XMPP client does not "
"possess 'xml:lang' attribute, the specified language is used. "
"The default value is '\"en\"'.")}},
"The default value is '\"en\"'. ")}},
{ldap_servers,
#{value => "[Host, ...]",
desc =>
?T("A list of IP addresses or DNS names of your LDAP servers. "
?T("A list of IP addresses or DNS names of your LDAP servers (see "
"_`../configuration/ldap.md#ldap-connection|LDAP connection`_). "
"ejabberd connects immediately to all of them, "
"and reconnects infinitely if connection is lost. "
"The default value is '[localhost]'.")}},
{ldap_backups,
#{value => "[Host, ...]",
desc =>
?T("A list of IP addresses or DNS names of LDAP backup servers. "
?T("A list of IP addresses or DNS names of LDAP backup servers (see "
"_`../configuration/ldap.md#ldap-connection|LDAP connection`_). "
"When no servers listed in _`ldap_servers`_ option are reachable, "
"ejabberd will try to connect to these backup servers. "
"ejabberd connects to these backup servers. "
"The default is an empty list, i.e. no backup servers specified. "
"WARNING: ejabberd doesn't try to reconnect back to the main "
"servers when they become operational again, so the only way "
"to restore these connections is to restart ejabberd. This "
"limitation might be fixed in future releases.")}},
"Please notice that ejabberd only connects to the next server "
"when the existing connection is lost; it doesn't detect when a "
"previously-attempted server becomes available again.")}},
{ldap_encrypt,
#{value => "tls | none",
desc =>
@@ -909,7 +934,9 @@ doc() ->
{new_sql_schema,
#{value => "true | false",
desc =>
{?T("Whether to use 'new' SQL schema. All schemas are located "
{?T("Whether to use the "
"_`database.md#default-and-new-schemas|new SQL schema`_. "
"All schemas are located "
"at <https://github.com/processone/ejabberd/tree/~s/sql>. "
"There are two schemas available. The default legacy schema "
"stores one XMPP domain into one ejabberd database. "
@@ -925,7 +952,8 @@ doc() ->
#{value => "true | false",
note => "updated in 24.06",
desc =>
?T("Allow ejabberd to update SQL schema. "
?T("Allow ejabberd to update SQL schema in "
"MySQL, PostgreSQL and SQLite databases. "
"This option was added in ejabberd 23.10, "
"and enabled by default since 24.06. "
"The default value is 'true'.")}},
@@ -1049,14 +1077,18 @@ doc() ->
{pam_service,
#{value => ?T("Name"),
desc =>
?T("This option defines the PAM service name. Refer to the PAM "
?T("This option defines the "
"_`authentication.md#pam-authentication|PAM`_ "
"service name. Refer to the PAM "
"documentation of your operation system for more information. "
"The default value is 'ejabberd'.")}},
{pam_userinfotype,
#{value => "username | jid",
desc =>
?T("This option defines what type of information about the "
"user ejabberd provides to the PAM service: only the username, "
"user ejabberd provides to the "
"_`authentication.md#pam-authentication|PAM`_ "
"service: only the username, "
"or the user's JID. Default is 'username'.")}},
{pgsql_users_number_estimate,
#{value => "true | false",
@@ -1073,36 +1105,42 @@ doc() ->
#{value => "timeout()",
desc =>
?T("A timeout to wait for the connection to be re-established "
"to the Redis server. The default is '1 second'.")}},
"to the _`database.md#redis|Redis`_ "
"server. The default is '1 second'.")}},
{redis_db,
#{value => ?T("Number"),
desc => ?T("Redis database number. The default is '0'.")}},
desc => ?T("_`database.md#redis|Redis`_ "
"database number. The default is '0'.")}},
{redis_password,
#{value => ?T("Password"),
desc =>
?T("The password to the Redis server. "
?T("The password to the _`database.md#redis|Redis`_ server. "
"The default is an empty string, i.e. no password.")}},
{redis_pool_size,
#{value => ?T("Number"),
desc =>
?T("The number of simultaneous connections to the Redis server. "
?T("The number of simultaneous connections to the "
"_`database.md#redis|Redis`_ server. "
"The default value is '10'.")}},
{redis_port,
#{value => "1..65535",
desc =>
?T("The port where the Redis server is accepting connections. "
?T("The port where the _`database.md#redis|Redis`_ "
" server is accepting connections. "
"The default is '6379'.")}},
{redis_queue_type,
#{value => "ram | file",
desc =>
?T("The type of request queue for the Redis server. "
?T("The type of request queue for the "
"_`database.md#redis|Redis`_ server. "
"See description of _`queue_type`_ option for the explanation. "
"The default value is the value defined in _`queue_type`_ "
"or 'ram' if the latter is not set.")}},
{redis_server,
#{value => ?T("Hostname"),
desc =>
?T("A hostname or an IP address of the Redis server. "
?T("A hostname or an IP address of the "
"_`database.md#redis|Redis`_ server."
"The default is 'localhost'.")}},
{registration_timeout,
#{value => "timeout()",
@@ -1257,7 +1295,9 @@ doc() ->
{shaper,
#{value => "{ShaperName: Rate}",
desc =>
?T("The option defines a set of shapers. Every shaper is assigned "
?T("The option defines a set of "
"_`../configuration/basic.md#shapers|shapers`_. "
"Every shaper is assigned "
"a name 'ShaperName' that can be used in other parts of the "
"configuration file, such as _`shaper_rules`_ option. The shaper "
"itself is defined by its 'Rate', where 'Rate' stands for the "
@@ -1274,7 +1314,9 @@ doc() ->
{shaper_rules,
#{value => "{ShaperRuleName: {Number|ShaperName: ACLRule|ACLName}}",
desc =>
?T("An entry allowing to declaring shaper to use for matching user/hosts. "
?T("This option defines "
"_`../configuration/basic.md#shaper-rules|shaper rules`_ "
"to use for matching user/hosts. "
"Semantics is similar to _`access_rules`_ option, the only difference is "
"that instead using 'allow' or 'deny', a name of a shaper (defined in "
"_`shaper`_ option) or a positive number should be used."),
-2
View File
@@ -42,8 +42,6 @@
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
-define(SERVER, ?MODULE).
-define(PROCNAME, 'ejabberd_redis_client').
-define(TR_STACK, redis_transaction_stack).
-define(DEFAULT_MAX_QUEUE, 10000).
-define(MAX_RETRIES, 1).
+19 -2
View File
@@ -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) ->
+21 -1
View File
@@ -43,7 +43,7 @@
external_host_overloaded/1, is_temporarly_blocked/1,
get_commands_spec/0, zlib_enabled/1, get_idle_timeout/1,
tls_required/1, tls_enabled/1, tls_options/3,
host_up/1, host_down/1, queue_type/1]).
host_up/1, host_down/1, queue_type/1, register_connection/1]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2,
@@ -130,6 +130,10 @@ get_connections_pids(FromTo) ->
[]
end.
-spec register_connection(FromTo :: {binary(), binary()}) -> ok.
register_connection(FromTo) ->
gen_server:call(ejabberd_s2s, {register_connection, FromTo, self()}).
-spec dirty_get_connections() -> [{binary(), binary()}].
dirty_get_connections() ->
mnesia:dirty_all_keys(s2s).
@@ -228,6 +232,8 @@ init([]) ->
handle_call({new_connection, Args}, _From, State) ->
{reply, erlang:apply(fun new_connection_int/7, Args), State};
handle_call({register_connection, FromTo, Pid}, _From, State) ->
{reply, register_connection_int(FromTo, Pid), State};
handle_call(Request, From, State) ->
?WARNING_MSG("Unexpected call from ~p: ~p", [From, Request]),
{noreply, State}.
@@ -478,6 +484,20 @@ new_connection_int(MyServer, Server, From, FromTo,
[]
end.
-spec register_connection_int(FromTo :: {binary(), binary()}, Pid :: pid()) -> ok.
register_connection_int(FromTo, Pid) ->
F = fun() ->
mnesia:write(#s2s{fromto = FromTo, pid = Pid})
end,
TRes = mnesia:transaction(F),
case TRes of
{atomic, _} ->
erlang:monitor(process, Pid),
ok;
_ ->
ok
end.
-spec max_s2s_connections_number({binary(), binary()}) -> pos_integer().
max_s2s_connections_number({From, To}) ->
case ejabberd_shaper:match(From, max_s2s_connections, jid:make(To)) of
+4 -1
View File
@@ -34,7 +34,7 @@
terminate/2, code_change/3]).
%% Hooks
-export([process_auth_result/2, process_closed/2, handle_unexpected_info/2,
handle_unexpected_cast/2, process_downgraded/2]).
handle_unexpected_cast/2, process_downgraded/2, handle_unauthenticated_features/2]).
%% API
-export([start/3, start_link/3, connect/1, close/1, close/2, stop_async/1, send/2,
route/2, establish/1, update_state/2, host_up/1, host_down/1]).
@@ -216,6 +216,9 @@ dns_retries(#{server_host := ServerHost}) ->
dns_timeout(#{server_host := ServerHost}) ->
ejabberd_option:s2s_dns_timeout(ServerHost).
handle_unauthenticated_features(Features, #{server_host := ServerHost} = State) ->
ejabberd_hooks:run_fold(s2s_out_unauthenticated_features, ServerHost, State, [Features]).
handle_auth_success(Mech, #{socket := Socket, ip := IP,
remote_server := RServer,
server_host := ServerHost,
+12
View File
@@ -206,6 +206,18 @@ bounce_offline_message(Acc) ->
Acc.
-spec bounce_sm_packet({bounce | term(), stanza()}) -> any().
bounce_sm_packet({bounce, #message{meta = #{ignore_sm_bounce := true}} = Packet} = Acc) ->
?DEBUG("Dropping packet to unavailable resource:~n~ts",
[xmpp:pp(Packet)]),
Acc;
bounce_sm_packet({bounce, #iq{meta = #{ignore_sm_bounce := true}} = Packet} = Acc) ->
?DEBUG("Dropping packet to unavailable resource:~n~ts",
[xmpp:pp(Packet)]),
Acc;
bounce_sm_packet({bounce, #presence{meta = #{ignore_sm_bounce := true}} = Packet} = Acc) ->
?DEBUG("Dropping packet to unavailable resource:~n~ts",
[xmpp:pp(Packet)]),
Acc;
bounce_sm_packet({bounce, Packet} = Acc) ->
Lang = xmpp:get_lang(Packet),
Txt = ?T("User session not found"),
+2 -2
View File
@@ -183,8 +183,8 @@ keep_alive(Host, Proc) ->
Timeout) of
{selected,_,[[<<"1">>]]} ->
ok;
_Err ->
?ERROR_MSG("Keep alive query failed, closing connection: ~p", [_Err]),
Err ->
?ERROR_MSG("Keep alive query failed, closing connection: ~p", [Err]),
sync_send_event(Proc, force_timeout, Timeout)
end.
+3 -13
View File
@@ -106,7 +106,6 @@ prepare_turn_opts(Opts) ->
prepare_turn_opts(Opts, _UseTurn = false) ->
set_certfile(Opts);
prepare_turn_opts(Opts, _UseTurn = true) ->
NumberOfMyHosts = length(ejabberd_option:hosts()),
TurnIP = case proplists:get_value(turn_ipv4_address, Opts) of
undefined ->
MyIP = misc:get_my_ipv4_address(),
@@ -129,18 +128,9 @@ prepare_turn_opts(Opts, _UseTurn = true) ->
AuthType = proplists:get_value(auth_type, Opts, user),
Realm = case proplists:get_value(auth_realm, Opts) of
undefined when AuthType == user ->
if NumberOfMyHosts > 1 ->
?INFO_MSG("You have several virtual hosts "
"configured, but option 'auth_realm' is "
"undefined and 'auth_type' is set to "
"'user', so the TURN relay might not be "
"working properly. Using ~ts as a "
"fallback",
[ejabberd_config:get_myname()]);
true ->
ok
end,
[{auth_realm, ejabberd_config:get_myname()}];
MyName = ejabberd_config:get_myname(),
?DEBUG("Using ~ts as TURN realm", [MyName]),
[{auth_realm, MyName}];
_ ->
[]
end,
+3 -1
View File
@@ -82,7 +82,9 @@ config_reloaded() ->
%%%===================================================================
%%% gen_event callbacks
%%%===================================================================
init([]) ->
init({[], _}) -> % Called by gen_event:swap_handler
{ok, #state{}};
init([]) -> % Called by gen_event:add_handler
ejabberd_hooks:add(config_reloaded, ?MODULE, config_reloaded, 50),
{ok, #state{}}.
+21 -13
View File
@@ -38,13 +38,17 @@
%% Update all the modified modules
update() ->
case update_info() of
{ok, Dir, _UpdatedBeams, _Script, LowLevelScript, _Check} ->
Eval =
eval_script(
LowLevelScript, [],
[{ejabberd, "", filename:join(Dir, "..")}]),
?DEBUG("Eval: ~p~n", [Eval]),
Eval;
{ok, Dir, UpdatedBeams, _Script, LowLevelScript, _Check} ->
case eval_script(
LowLevelScript, [],
[{ejabberd, "", filename:join(Dir, "..")}]) of
{ok, _} ->
?DEBUG("Updated: ~p~n", [UpdatedBeams]),
{ok, UpdatedBeams};
Eval ->
?DEBUG("Eval: ~p~n", [Eval]),
Eval
end;
{error, Reason} ->
{error, Reason}
end.
@@ -56,12 +60,16 @@ update(ModulesToUpdate) ->
UpdatedBeamsNow =
[A || A <- UpdatedBeamsAll, B <- ModulesToUpdate, A == B],
{_, LowLevelScript, _} = build_script(Dir, UpdatedBeamsNow),
Eval =
eval_script(
LowLevelScript, [],
[{ejabberd, "", filename:join(Dir, "..")}]),
?DEBUG("Eval: ~p~n", [Eval]),
Eval;
case eval_script(
LowLevelScript, [],
[{ejabberd, "", filename:join(Dir, "..")}]) of
{ok, _} ->
?DEBUG("Updated: ~p~n", [UpdatedBeamsNow]),
{ok, UpdatedBeamsNow};
Eval ->
?DEBUG("Eval: ~p~n", [Eval]),
Eval
end;
{error, Reason} ->
{error, Reason}
end.
-1
View File
@@ -1,7 +1,6 @@
%%%----------------------------------------------------------------------
%%% File : ejabberd_web.erl
%%% Author : Alexey Shchepin <alexey@process-one.net>
%%% Purpose :
%%% Purpose :
%%% Created : 28 Feb 2004 by Alexey Shchepin <alexey@process-one.net>
%%%
+107 -46
View File
@@ -747,46 +747,99 @@ list_users(Host, Level, PageSize, RPath, R, RegisterEl) ->
end.
list_users(Host, Level, PageSize, RPath, R, Usernames, RegisterEl) ->
IsOffline = gen_mod:is_loaded(Host, mod_offline),
IsMam = gen_mod:is_loaded(Host, mod_mam),
IsRoster = gen_mod:is_loaded(Host, mod_roster),
IsLast = gen_mod:is_loaded(Host, mod_last),
Columns =
[<<"user">>,
{<<"offline">>, right},
{<<"roster">>, right},
{<<"timestamp">>, left},
{<<"status">>, left}],
list_users_element(IsOffline, column, offline, {}),
list_users_element(IsMam, column, mam, {}),
list_users_element(IsRoster, column, roster, {}),
list_users_element(IsLast, column, timestamp, {}),
list_users_element(IsLast, column, status, {})],
Rows =
[{make_command(echo,
R,
[{<<"sentence">>,
jid:encode(
jid:make(Username, Host))}],
[{only, raw_and_value}, {result_links, [{sentence, user, Level, <<"">>}]}]),
make_command(get_offline_count,
R,
[{<<"user">>, Username}, {<<"host">>, Host}],
[{only, raw_and_value},
{result_links,
[{value, arg_host, Level, <<"user/", Username/binary, "/queue/">>}]}]),
make_command(get_roster_count,
R,
[{<<"user">>, Username}, {<<"host">>, Host}],
[{only, raw_and_value},
{result_links,
[{value, arg_host, Level, <<"user/", Username/binary, "/roster/">>}]}]),
?C(element(1,
make_command_raw_value(get_last,
R,
[{<<"user">>, Username}, {<<"host">>, Host}]))),
?C(element(2,
make_command_raw_value(get_last,
R,
[{<<"user">>, Username}, {<<"host">>, Host}])))}
[list_to_tuple(lists:flatten([make_command(echo,
R,
[{<<"sentence">>,
jid:encode(
jid:make(Username, Host))}],
[{only, raw_and_value},
{result_links,
[{sentence, user, Level, <<"">>}]}]),
list_users_element(IsOffline,
row,
offline,
{R, Username, Host, Level}),
list_users_element(IsMam,
row,
mam,
{R, Username, Host, Level}),
list_users_element(IsRoster,
row,
roster,
{R, Username, Host, Level}),
list_users_element(IsLast, row, last, {R, Username, Host})]))
|| Username <- Usernames],
[RegisterEl,
make_command(registered_users, R, [], [{only, presentation}]),
make_command(get_offline_count, R, [], [{only, presentation}]),
make_command(get_roster_count, R, [], [{only, presentation}]),
make_command(get_last, R, [], [{only, presentation}]),
make_table(PageSize, RPath, Columns, Rows)].
Table = make_table(PageSize, RPath, lists:flatten(Columns), Rows),
Result =
[RegisterEl,
make_command(registered_users, R, [], [{only, presentation}]),
list_users_element(IsOffline, presentation, offline, R),
list_users_element(IsMam, presentation, mam, R),
list_users_element(IsRoster, presentation, roster, R),
list_users_element(IsLast, presentation, last, R),
Table],
lists:flatten(Result).
list_users_element(false, _, _, _) ->
[];
list_users_element(_, column, offline, _) ->
{<<"offline">>, right};
list_users_element(_, column, mam, _) ->
{<<"mam">>, right};
list_users_element(_, column, roster, _) ->
{<<"roster">>, right};
list_users_element(_, column, timestamp, _) ->
{<<"timestamp">>, left};
list_users_element(_, column, status, _) ->
{<<"status">>, left};
list_users_element(_, row, offline, {R, Username, Host, Level}) ->
make_command(get_offline_count,
R,
[{<<"user">>, Username}, {<<"host">>, Host}],
[{only, raw_and_value},
{result_links,
[{value, arg_host, Level, <<"user/", Username/binary, "/queue/">>}]}]);
list_users_element(_, row, mam, {R, Username, Host, Level}) ->
make_command(get_mam_count,
R,
[{<<"user">>, Username}, {<<"host">>, Host}],
[{only, raw_and_value},
{result_links,
[{value, arg_host, Level, <<"user/", Username/binary, "/mam/">>}]}]);
list_users_element(_, row, roster, {R, Username, Host, Level}) ->
make_command(get_roster_count,
R,
[{<<"user">>, Username}, {<<"host">>, Host}],
[{only, raw_and_value},
{result_links,
[{value, arg_host, Level, <<"user/", Username/binary, "/roster/">>}]}]);
list_users_element(_, row, last, {R, Username, Host}) ->
[?C(element(1,
make_command_raw_value(get_last, R, [{<<"user">>, Username}, {<<"host">>, Host}]))),
?C(element(2,
make_command_raw_value(get_last,
R,
[{<<"user">>, Username}, {<<"host">>, Host}])))];
list_users_element(_, presentation, offline, R) ->
make_command(get_offline_count, R, [], [{only, presentation}]);
list_users_element(_, presentation, mam, R) ->
make_command(get_mam_count, R, [], [{only, presentation}]);
list_users_element(_, presentation, roster, R) ->
make_command(get_roster_count, R, [], [{only, presentation}]);
list_users_element(_, presentation, last, R) ->
make_command(get_last, R, [], [{only, presentation}]).
list_users_diapason(Host, R, Usernames, N, RegisterEl) ->
URLFunc = fun url_func/1,
@@ -952,6 +1005,17 @@ user_info(User, Server, #request{q = Query, lang = Lang} = R) ->
Res = user_parse_query(User, Server, Query),
UserItems = ejabberd_hooks:run_fold(webadmin_user,
LServer, [], [User, Server, R]),
Lasts = case gen_mod:is_loaded(Server, mod_last) of
true ->
[make_command(get_last, R,
[{<<"user">>, User}, {<<"host">>, Server}],
[]),
make_command(set_last, R,
[{<<"user">>, User}, {<<"host">>, Server}],
[])];
false ->
[]
end,
[?XC(<<"h1">>, (str:translate_and_format(Lang, ?T("User ~ts"),
[us_to_list(US)])))]
++
@@ -968,13 +1032,8 @@ user_info(User, Server, #request{q = Query, lang = Lang} = R) ->
[{result_links, [{node, node, 4, <<>>}]}]),
make_command(change_password, R,
[{<<"user">>, User}, {<<"host">>, Server}],
[{style, danger}]),
make_command(get_last, R,
[{<<"user">>, User}, {<<"host">>, Server}],
[]),
make_command(set_last, R,
[{<<"user">>, User}, {<<"host">>, Server}],
[])] ++
[{style, danger}])] ++
Lasts ++
UserItems ++
[?P,
make_command(unregister, R,
@@ -1180,7 +1239,7 @@ pretty_print_xml({xmlcdata, CData}, Prefix) ->
($\n) -> true;
($\t) -> true;
($\v) -> true;
($ ) -> true;
($\s) -> true;
(_) -> false
end, binary_to_list(CData)),
if IsBlankCData ->
@@ -1667,7 +1726,7 @@ make_command_raw_value(Name, Request, BaseArguments) ->
raw_value |
raw_and_value} |
{input_name_append, [binary()]} |
{force_execution, boolean()} |
{force_execution, boolean() | undefined} |
{table_options, {PageSize :: integer(), RemainingPath :: [binary()]}} |
{result_named, boolean()} |
{result_links,
@@ -1678,7 +1737,7 @@ make_command_raw_value(Name, Request, BaseArguments) ->
{style, normal | danger}.
make_command2(Name, Request, BaseArguments, Options) ->
Only = proplists:get_value(only, Options, all),
ForceExecution = proplists:get_value(force_execution, Options, false),
ForceExecution = proplists:get_value(force_execution, Options, undefined),
InputNameAppend = proplists:get_value(input_name_append, Options, []),
Resultnamed = proplists:get_value(result_named, Options, false),
ResultLinks = proplists:get_value(result_links, Options, []),
@@ -1732,6 +1791,8 @@ make_command2(Name,
case {ForceExecution, ResultFormatApi} of
{true, _} ->
auto;
{false, _} ->
manual;
{_, {_, rescode}} ->
manual;
{_, {_, restuple}} ->
+2 -2
View File
@@ -256,9 +256,9 @@ ws_loop(Codec, Socket, WsHandleLoopPid, SockMod, Shaper) ->
"with pid ~p",
[self()]),
websocket_close(Codec, Socket, WsHandleLoopPid, SockMod, 1001); % going away
_Ignored ->
Ignored ->
?WARNING_MSG("Received unexpected message, ignoring: ~p",
[_Ignored]),
[Ignored]),
ws_loop(Codec, Socket, WsHandleLoopPid,
SockMod, Shaper)
end.
+5
View File
@@ -79,6 +79,11 @@ handle_cast(Msg, State) ->
?WARNING_MSG("Unexpected cast: ~p", [Msg]),
{noreply, State}.
handle_info({'ETS-TRANSFER', Table, Process, Module}, State) ->
?DEBUG("ejabberd now controls ETS table ~p from process ~p for module ~p",
[Table, Process, Module]),
{noreply, State};
handle_info(Info, State) ->
?WARNING_MSG("Unexpected info: ~p", [Info]),
{noreply, State}.
+5 -70
View File
@@ -1425,8 +1425,10 @@ set_presence(User, Host, Resource, Type, Show, Status, Priority) ->
show = misc:binary_to_atom(Show),
priority = Priority,
sub_els = []},
Ref = ejabberd_sm:get_session_pid(User, Host, Resource),
ejabberd_c2s:set_presence(Ref, Pres).
case ejabberd_sm:get_session_pid(User, Host, Resource) of
none -> throw({error, "User session not found"});
Ref -> ejabberd_c2s:set_presence(Ref, Pres)
end.
user_sessions_info(User, Host) ->
lists:filtermap(fun(Resource) ->
@@ -2204,13 +2206,7 @@ web_page_host(Acc, _, _) ->
%%% HostUser
web_menu_hostuser(Acc, _Host, _Username, _Lang) ->
Acc
++ [{<<"auth">>, <<"Authentication">>},
{<<"mam">>, <<"MAM">>},
{<<"privacy">>, <<"Privacy Lists">>},
{<<"private">>, <<"Private XML Storage">>},
{<<"session">>, <<"Sessions">>},
{<<"vcard">>, <<"vCard">>}].
Acc ++ [{<<"auth">>, <<"Authentication">>}, {<<"session">>, <<"Sessions">>}].
web_page_hostuser(_, Host, User, #request{path = [<<"auth">>]} = R) ->
Ban = make_command(ban_account,
@@ -2240,26 +2236,6 @@ web_page_hostuser(_, Host, User, #request{path = [<<"auth">>]} = R) ->
[{<<"user">>, User}, {<<"host">>, Host}],
[{style, danger}])],
{stop, Res};
web_page_hostuser(_, Host, User, #request{path = [<<"mam">>]} = R) ->
Res = ?H1GL(<<"MAM">>, <<"modules/#mod_mam">>, <<"mod_mam">>)
++ [make_command(remove_mam_for_user,
R,
[{<<"user">>, User}, {<<"host">>, Host}],
[{style, danger}]),
make_command(remove_mam_for_user_with_peer,
R,
[{<<"user">>, User}, {<<"host">>, Host}],
[{style, danger}])],
{stop, Res};
web_page_hostuser(_, Host, User, #request{path = [<<"privacy">>]} = R) ->
Res = ?H1GL(<<"Privacy Lists">>, <<"modules/#mod_privacy">>, <<"mod_privacy">>)
++ [make_command(privacy_set, R, [{<<"user">>, User}, {<<"host">>, Host}], [])],
{stop, Res};
web_page_hostuser(_, Host, User, #request{path = [<<"private">>]} = R) ->
Res = ?H1GL(<<"Private XML Storage">>, <<"modules/#mod_private">>, <<"mod_private">>)
++ [make_command(private_set, R, [{<<"user">>, User}, {<<"host">>, Host}], []),
make_command(private_get, R, [{<<"user">>, User}, {<<"host">>, Host}], [])],
{stop, Res};
web_page_hostuser(_, Host, User, #request{path = [<<"session">>]} = R) ->
Head = [?XC(<<"h1">>, <<"Sessions">>), ?BR],
Set = [make_command(resource_num, R, [{<<"user">>, User}, {<<"host">>, Host}], []),
@@ -2278,47 +2254,6 @@ web_page_hostuser(_, Host, User, #request{path = [<<"session">>]} = R) ->
make_command(get_presence, R, [{<<"user">>, User}, {<<"host">>, Host}], []),
make_command(num_resources, R, [{<<"user">>, User}, {<<"host">>, Host}], [])],
{stop, Head ++ Get ++ Set};
web_page_hostuser(_, Host, User, #request{path = [<<"vcard">>]} = R) ->
Head = ?H1GL(<<"vCard">>, <<"modules/#mod_vcard">>, <<"mod_vcard">>),
Set = [make_command(set_nickname, R, [{<<"user">>, User}, {<<"host">>, Host}], []),
make_command(set_vcard, R, [{<<"user">>, User}, {<<"host">>, Host}], []),
make_command(set_vcard2, R, [{<<"user">>, User}, {<<"host">>, Host}], []),
make_command(set_vcard2_multi, R, [{<<"user">>, User}, {<<"host">>, Host}], [])],
timer:sleep(100), % setting vcard takes a while, let's delay the get commands
FieldNames = [<<"VERSION">>, <<"FN">>, <<"NICKNAME">>, <<"BDAY">>],
FieldNames2 =
[{<<"N">>, <<"FAMILY">>},
{<<"N">>, <<"GIVEN">>},
{<<"N">>, <<"MIDDLE">>},
{<<"ADR">>, <<"CTRY">>},
{<<"ADR">>, <<"LOCALITY">>},
{<<"EMAIL">>, <<"USERID">>}],
Get = [make_command(get_vcard, R, [{<<"user">>, User}, {<<"host">>, Host}], []),
?XE(<<"blockquote">>,
[make_table([<<"name">>, <<"value">>],
[{?C(FieldName),
make_command(get_vcard,
R,
[{<<"user">>, User},
{<<"host">>, Host},
{<<"name">>, FieldName}],
[{only, value}])}
|| FieldName <- FieldNames])]),
make_command(get_vcard2, R, [{<<"user">>, User}, {<<"host">>, Host}], []),
?XE(<<"blockquote">>,
[make_table([<<"name">>, <<"subname">>, <<"value">>],
[{?C(FieldName),
?C(FieldSubName),
make_command(get_vcard2,
R,
[{<<"user">>, User},
{<<"host">>, Host},
{<<"name">>, FieldName},
{<<"subname">>, FieldSubName}],
[{only, value}])}
|| {FieldName, FieldSubName} <- FieldNames2])]),
make_command(get_vcard2_multi, R, [{<<"user">>, User}, {<<"host">>, Host}], [])],
{stop, Head ++ Get ++ Set};
web_page_hostuser(Acc, _, _, _) ->
Acc.
-3
View File
@@ -494,9 +494,6 @@ announce_commands(From, To,
{error, xmpp:err_bad_request(Txt, Lang)}
end.
-define(TVFIELD(Type, Var, Val),
#xdata_field{type = Type, var = Var, values = vvaluel(Val)}).
vvaluel(Val) ->
case Val of
<<>> -> [];
+17 -2
View File
@@ -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) ->
+2 -2
View File
@@ -74,8 +74,8 @@ process([], #request{method = 'GET', data = <<>>}) ->
{200, ?HEADER(?CT_XML), get_human_html_xmlel()};
process([], #request{method = 'OPTIONS', data = <<>>}) ->
{200, ?OPTIONS_HEADER, []};
process(_Path, _Request) ->
?DEBUG("Bad Request: ~p", [_Request]),
process(_Path, Request) ->
?DEBUG("Bad Request: ~p", [Request]),
{400, ?HEADER(?CT_XML),
#xmlel{name = <<"h1">>, attrs = [],
children = [{xmlcdata, <<"400 Bad Request">>}]}}.
+1 -1
View File
@@ -1,7 +1,7 @@
%%%----------------------------------------------------------------------
%%% File : mod_bosh_sql.erl
%%% Author : Evgeny Khramtsov <ekhramtsov@process-one.net>
%%% Purpose :
%%% Purpose :
%%% Created : 28 Mar 2017 by Evgeny Khramtsov <ekhramtsov@process-one.net>
%%%
%%%
+2 -2
View File
@@ -145,10 +145,10 @@ c2s_session_resumed(State) ->
c2s_session_opened(State) ->
maps:remove(carboncopy, State).
c2s_inline_features({Sasl, Bind} = Acc, Host) ->
c2s_inline_features({Sasl, Bind, Extra} = Acc, Host) ->
case gen_mod:is_loaded(Host, ?MODULE) of
true ->
{Sasl, [#bind2_feature{var = ?NS_CARBONS_2} | Bind]};
{Sasl, [#bind2_feature{var = ?NS_CARBONS_2} | Bind], Extra};
false ->
Acc
end.
+4 -4
View File
@@ -139,8 +139,8 @@ handle_call(Request, From, State) ->
?WARNING_MSG("Unexpected call from ~p: ~p", [From, Request]),
{noreply, State}.
handle_cast(_Msg, State) ->
?WARNING_MSG("Unexpected cast = ~p", [_Msg]),
handle_cast(Msg, State) ->
?WARNING_MSG("Unexpected cast = ~p", [Msg]),
{noreply, State}.
handle_info(clean, State) ->
@@ -151,8 +151,8 @@ handle_info(clean, State) ->
ets:fun2ms(fun({_, _, UnbanTS, _}) -> UnbanTS =< Now end)),
erlang:send_after(?CLEAN_INTERVAL, self(), clean),
{noreply, State};
handle_info(_Info, State) ->
?WARNING_MSG("Unexpected info = ~p", [_Info]),
handle_info(Info, State) ->
?WARNING_MSG("Unexpected info = ~p", [Info]),
{noreply, State}.
terminate(_Reason, #state{host = Host}) ->
+1 -1
View File
@@ -542,7 +542,7 @@ log(Call, Args, IP) ->
?INFO_MSG("API call ~ts ~p (~p)", [Call, hide_sensitive_args(Args), IP]).
hide_sensitive_args(Args=[_H|_T]) ->
lists:map( fun({<<"password">>, Password}) -> {<<"password">>, ejabberd_config:may_hide_data(Password)};
lists:map(fun({<<"password">>, Password}) -> {<<"password">>, ejabberd_config:may_hide_data(Password)};
({<<"newpass">>,NewPassword}) -> {<<"newpass">>, ejabberd_config:may_hide_data(NewPassword)};
(E) -> E end,
Args);
+154 -4
View File
@@ -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,
@@ -45,13 +46,21 @@
mod_options/1, remove_mam_for_user_with_peer/3, remove_mam_for_user/2,
is_empty_for_user/2, is_empty_for_room/3, check_create_room/4,
process_iq/3, store_mam_message/7, make_id/0, wrap_as_mucsub/2, select/7,
get_mam_count/2,
webadmin_menu_hostuser/4,
webadmin_page_hostuser/4,
get_mam_messages/2, webadmin_user/4,
delete_old_messages_batch/5, delete_old_messages_status/1, delete_old_messages_abort/1,
remove_message_from_archive/3]).
-import(ejabberd_web_admin, [make_command/4, make_command/2]).
-include_lib("xmpp/include/xmpp.hrl").
-include("logger.hrl").
-include("mod_muc_room.hrl").
-include("ejabberd_commands.hrl").
-include("ejabberd_http.hrl").
-include("ejabberd_web_admin.hrl").
-include("mod_mam.hrl").
-include("translate.hrl").
@@ -139,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,
@@ -149,6 +160,12 @@ start(Host, Opts) ->
set_room_option, 50),
ejabberd_hooks:add(store_mam_message, Host, ?MODULE,
store_mam_message, 100),
ejabberd_hooks:add(webadmin_menu_hostuser, Host, ?MODULE,
webadmin_menu_hostuser, 50),
ejabberd_hooks:add(webadmin_page_hostuser, Host, ?MODULE,
webadmin_page_hostuser, 50),
ejabberd_hooks:add(webadmin_user, Host, ?MODULE,
webadmin_user, 50),
case mod_mam_opt:assume_mam_usage(Opts) of
true ->
ejabberd_hooks:add(message_is_archived, Host, ?MODULE,
@@ -212,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,
@@ -222,6 +241,12 @@ stop(Host) ->
set_room_option, 50),
ejabberd_hooks:delete(store_mam_message, Host, ?MODULE,
store_mam_message, 100),
ejabberd_hooks:delete(webadmin_menu_hostuser, Host, ?MODULE,
webadmin_menu_hostuser, 50),
ejabberd_hooks:delete(webadmin_page_hostuser, Host, ?MODULE,
webadmin_page_hostuser, 50),
ejabberd_hooks:delete(webadmin_user, Host, ?MODULE,
webadmin_user, 50),
case mod_mam_opt:assume_mam_usage(Host) of
true ->
ejabberd_hooks:delete(message_is_archived, Host, ?MODULE,
@@ -592,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},
@@ -614,6 +653,52 @@ message_is_archived(false, #{lserver := LServer}, Pkt) ->
false
end.
%%%
%%% Commands
%%%
%% @format-begin
get_mam_count(User, Host) ->
Jid = jid:make(User, Host),
{_, _, Count} = select(Host, Jid, Jid, [], #rsm_set{}, chat, only_count),
Count.
get_mam_messages(User, Host) ->
Jid = jid:make(User, Host),
{Messages, _, _} = select(Host, Jid, Jid, [], #rsm_set{}, chat, only_messages),
format_user_messages(Messages).
format_user_messages(Messages) ->
lists:map(fun({_ID, _IDInt, Fwd}) ->
El = hd(Fwd#forwarded.sub_els),
FPacket =
ejabberd_web_admin:pretty_print_xml(
xmpp:encode(El)),
SFrom = jid:encode(El#message.from),
STo = jid:encode(El#message.to),
Time = format_time(Fwd#forwarded.delay#delay.stamp),
{Time, SFrom, STo, FPacket}
end,
Messages).
format_time(Now) ->
{{Year, Month, Day}, {Hour, Minute, Second}} = calendar:now_to_local_time(Now),
str:format("~w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w",
[Year, Month, Day, Hour, Minute, Second]).
webadmin_user(Acc, User, Server, R) ->
Acc
++ [make_command(get_mam_count,
R,
[{<<"user">>, User}, {<<"host">>, Server}],
[{result_links, [{value, arg_host, 4, <<"user/", User/binary, "/mam/">>}]}])].
%% @format-end
%%%
%%% Commands: Purge
%%%
delete_old_messages_batch(Server, Type, Days, BatchSize, Rate) when Type == <<"chat">>;
Type == <<"groupchat">>;
Type == <<"all">> ->
@@ -1487,7 +1572,29 @@ get_jids(Js) ->
[jid:tolower(jid:remove_resource(J)) || J <- Js].
get_commands_spec() ->
[#ejabberd_commands{name = delete_old_mam_messages, tags = [purge],
[
#ejabberd_commands{name = get_mam_count, tags = [mam],
desc = "Get number of MAM messages in a local user archive",
module = ?MODULE, function = get_mam_count,
note = "added in 24.10",
policy = user,
args = [],
result_example = 5,
result_desc = "Number",
result = {value, integer}},
#ejabberd_commands{name = get_mam_messages,
tags = [internal, mam],
desc = "Get the mam messages",
policy = user,
module = mod_mam, function = get_mam_messages,
args = [],
result = {archive, {list, {messages, {tuple, [{time, string},
{from, string},
{to, string},
{packet, string}
]}}}}},
#ejabberd_commands{name = delete_old_mam_messages, tags = [mam, purge],
desc = "Delete MAM messages older than DAYS",
longdesc = "Valid message TYPEs: "
"`chat`, `groupchat`, `all`.",
@@ -1497,7 +1604,7 @@ get_commands_spec() ->
args_example = [<<"all">>, 31],
args = [{type, binary}, {days, integer}],
result = {res, rescode}},
#ejabberd_commands{name = delete_old_mam_messages_batch, tags = [purge],
#ejabberd_commands{name = delete_old_mam_messages_batch, tags = [mam, purge],
desc = "Delete MAM messages older than DAYS",
note = "added in 22.05",
longdesc = "Valid message TYPEs: "
@@ -1513,7 +1620,7 @@ get_commands_spec() ->
result = {res, restuple},
result_desc = "Result tuple",
result_example = {ok, <<"Removal of 5000 messages in progress">>}},
#ejabberd_commands{name = delete_old_mam_messages_status, tags = [purge],
#ejabberd_commands{name = delete_old_mam_messages_status, tags = [mam, purge],
desc = "Status of delete old MAM messages operation",
note = "added in 22.05",
module = ?MODULE, function = delete_old_messages_status,
@@ -1523,7 +1630,7 @@ get_commands_spec() ->
result = {status, string},
result_desc = "Status test",
result_example = "Operation in progress, delete 5000 messages"},
#ejabberd_commands{name = abort_delete_old_mam_messages, tags = [purge],
#ejabberd_commands{name = abort_delete_old_mam_messages, tags = [mam, purge],
desc = "Abort currently running delete old MAM messages operation",
note = "added in 22.05",
module = ?MODULE, function = delete_old_messages_abort,
@@ -1555,6 +1662,49 @@ get_commands_spec() ->
result_example = {ok, <<"MAM archive removed">>}}
].
%%%
%%% WebAdmin
%%%
webadmin_menu_hostuser(Acc, _Host, _Username, _Lang) ->
Acc ++ [{<<"mam">>, <<"MAM">>},
{<<"mam-archive">>, <<"MAM Archive">>}].
webadmin_page_hostuser(_, Host, U,
#request{us = _US, path = [<<"mam">>]} = R) ->
Res = ?H1GL(<<"MAM">>, <<"modules/#mod_mam">>, <<"mod_mam">>)
++ [make_command(get_mam_count,
R,
[{<<"user">>, U}, {<<"host">>, Host}],
[{result_links,
[{value, arg_host, 5, <<"user/", U/binary, "/mam-archive/">>}]}]),
make_command(remove_mam_for_user,
R,
[{<<"user">>, U}, {<<"host">>, Host}],
[{style, danger}]),
make_command(remove_mam_for_user_with_peer,
R,
[{<<"user">>, U}, {<<"host">>, Host}],
[{style, danger}])],
{stop, Res};
webadmin_page_hostuser(_, Host, U,
#request{us = _US, path = [<<"mam-archive">> | RPath],
lang = Lang} = R) ->
PageTitle =
str:translate_and_format(Lang, ?T("~ts's MAM Archive"), [jid:encode({U, Host, <<"">>})]),
Head = ?H1GL(PageTitle, <<"modules/#mod_mam">>, <<"mod_mam">>),
Res = make_command(get_mam_messages, R, [{<<"user">>, U},
{<<"host">>, Host}],
[{table_options, {10, RPath}},
{result_links, [{packet, paragraph, 1, <<"">>}]}]),
{stop, Head ++ [Res]};
webadmin_page_hostuser(Acc, _, _, _) -> Acc.
%%%
%%% Documentation
%%%
mod_opt_type(compress_xml) ->
econf:bool();
mod_opt_type(assume_mam_usage) ->
+6 -6
View File
@@ -386,8 +386,8 @@ process([<<"federation">>, <<"v2">>, <<"send_join">>, RoomID, EventID],
{result, HTTPResult} ->
HTTPResult
end;
process(_Path, _Request) ->
?DEBUG("matrix 404: ~p~n~p~n", [_Path, _Request]),
process(Path, Request) ->
?DEBUG("matrix 404: ~p~n~p~n", [Path, Request]),
ejabberd_web:error(not_found).
preprocess_federation_request(Request) ->
@@ -869,17 +869,17 @@ mod_opt_type(key) ->
crypto:generate_key(eddsa, ed25519, Key2)
end;
mod_opt_type(matrix_id_as_jid) ->
econf:bool();
mod_opt_type(persist) ->
econf:bool().
-spec mod_options(binary()) -> [{key, {binary(), binary()}} |
{atom(), any()}].
mod_options(Host) ->
[{matrix_domain, Host},
{host, <<"matrix.", Host/binary>>},
{key_name, <<"">>},
{key, {<<"">>, <<"">>}},
{matrix_id_as_jid, false},
{persist, false}].
{matrix_id_as_jid, false}].
mod_doc() ->
#{desc =>
+1 -8
View File
@@ -8,7 +8,6 @@
-export([key_name/1]).
-export([matrix_domain/1]).
-export([matrix_id_as_jid/1]).
-export([persist/1]).
-spec host(gen_mod:opts() | global | binary()) -> binary().
host(Opts) when is_map(Opts) ->
@@ -16,7 +15,7 @@ host(Opts) when is_map(Opts) ->
host(Host) ->
gen_mod:get_module_opt(Host, mod_matrix_gw, host).
-spec key(gen_mod:opts() | global | binary()) -> any().
-spec key(gen_mod:opts() | global | binary()) -> {binary(),binary()}.
key(Opts) when is_map(Opts) ->
gen_mod:get_opt(key, Opts);
key(Host) ->
@@ -40,9 +39,3 @@ matrix_id_as_jid(Opts) when is_map(Opts) ->
matrix_id_as_jid(Host) ->
gen_mod:get_module_opt(Host, mod_matrix_gw, matrix_id_as_jid).
-spec persist(gen_mod:opts() | global | binary()) -> boolean().
persist(Opts) when is_map(Opts) ->
gen_mod:get_opt(persist, Opts);
persist(Host) ->
gen_mod:get_module_opt(Host, mod_matrix_gw, persist).
-2
View File
@@ -41,8 +41,6 @@
-export([init/1, terminate/3, code_change/4, callback_mode/0]).
-export([handle_event/4]).
-define(SERVER, ?MODULE).
-include_lib("xmpp/include/xmpp.hrl").
-include("logger.hrl").
-include("ejabberd_http.hrl").
-2
View File
@@ -35,8 +35,6 @@
-export([init/1, terminate/3, code_change/4, callback_mode/0]).
-export([handle_event/4]).
-define(SERVER, ?MODULE).
-include("logger.hrl").
-include("ejabberd_http.hrl").
-include_lib("kernel/include/inet.hrl").
+2 -2
View File
@@ -142,8 +142,8 @@ mod_opt_type(servers) ->
econf:options(
#{
certfile => econf:pem()
}, [{return, map}])
)}, [{return, map}]),
}, [{return, map}]))},
[{return, map}]),
[{return, map}]),
fun(Servers) ->
maps:fold(
+5 -6
View File
@@ -620,9 +620,6 @@ web_menu_host(Acc, _Host, Lang) ->
%%---------------
%% Web Admin Page
-define(TDTD(L, N),
?XE(<<"tr">>, [?XCT(<<"td">>, L), ?XC(<<"td">>, integer_to_binary(N))])).
web_page_main(_, #request{path = [<<"muc">>], lang = Lang} = R) ->
PageTitle = translate:translate(Lang, ?T("Multi-User Chat")),
Title = ?H1GL(PageTitle, <<"modules/#mod_muc">>, <<"mod_muc">>),
@@ -1474,7 +1471,7 @@ get_room_occupants(Pid) ->
get_room_occupants_number(Room, Host) ->
case get_room_pid_validate(Room, Host, <<"name">>, <<"service">>) of
{Pid, _, _} when is_pid(Pid )->
{Pid, _, _} when is_pid(Pid)->
{ok, #{occupants_number := N}} = mod_muc_room:get_info(Pid),
N;
_ ->
@@ -1504,8 +1501,10 @@ send_direct_invitation(RoomName, RoomService, Password, Reason, UsersStrings) ->
get_users_to_invite(RoomJid, UsersStrings) ->
OccupantsTuples = get_room_occupants(RoomJid#jid.luser,
RoomJid#jid.lserver),
OccupantsJids = [jid:decode(JidString)
|| {JidString, _Nick, _} <- OccupantsTuples],
OccupantsJids = try [jid:decode(JidString)
|| {JidString, _Nick, _} <- OccupantsTuples]
catch _:{bad_jid, _} -> throw({error, "Malformed JID of invited user"})
end,
lists:filtermap(
fun(UserString) ->
UserJid = jid:decode(UserString),
+7 -5
View File
@@ -540,7 +540,7 @@ normal_state({route, <<"">>,
case NewStateData of
stop ->
Conf = StateData#state.config,
{stop, normal, StateData#state{config = Conf#config{persistent = false}}};
{stop, normal, StateData#state{config = Conf#config{persistent = {destroying, Conf#config.persistent}}}};
_ when NewStateData#state.just_created ->
close_room_if_temporary_and_empty(NewStateData);
_ ->
@@ -736,7 +736,7 @@ handle_event({destroy, Reason}, _StateName,
[jid:encode(StateData#state.jid), Reason]),
add_to_log(room_existence, destroyed, StateData),
Conf = StateData#state.config,
{stop, shutdown, StateData#state{config = Conf#config{persistent = false}}};
{stop, shutdown, StateData#state{config = Conf#config{persistent = {destroying, Conf#config.persistent}}}};
handle_event(destroy, StateName, StateData) ->
?INFO_MSG("Destroyed MUC room ~ts",
[jid:encode(StateData#state.jid)]),
@@ -856,7 +856,7 @@ handle_sync_event({muc_unsubscribe, From}, _From, StateName,
from = From, sub_els = [#muc_unsubscribe{}]},
case process_iq_mucsub(From, IQ, StateData) of
{result, _, stop} ->
{stop, normal, StateData#state{config = Conf#config{persistent = false}}};
{stop, normal, StateData#state{config = Conf#config{persistent = {destroying, Conf#config.persistent}}}};
{result, _, NewState} ->
{reply, ok, StateName, NewState};
{ignore, NewState} ->
@@ -1015,8 +1015,10 @@ terminate(Reason, _StateName,
_ ->
add_to_log(room_existence, stopped, StateData),
case (StateData#state.config)#config.persistent of
false ->
ejabberd_hooks:run(room_destroyed, LServer, [LServer, Room, Host]);
false ->
ejabberd_hooks:run(room_destroyed, LServer, [LServer, Room, Host, false]);
{destroying, Persistent} ->
ejabberd_hooks:run(room_destroyed, LServer, [LServer, Room, Host, Persistent]);
_ ->
ok
end
+1 -1
View File
@@ -46,7 +46,7 @@ start(Host, _Opts) ->
gen_server:start({local, gen_mod:get_module_proc(Host, ?MODULE)}, ?MODULE, [Host], []).
stop(Host) ->
gen_server:stop({local, gen_mod:get_module_proc(Host, ?MODULE)}).
gen_server:stop(gen_mod:get_module_proc(Host, ?MODULE)).
init([Host]) ->
ejabberd_mnesia:create(?MODULE, muc_rtbl,
+3 -1
View File
@@ -1002,7 +1002,9 @@ get_queue_length(LUser, LServer) ->
count_offline_messages(LUser, LServer).
webadmin_user(Acc, User, Server, R) ->
Acc ++ [make_command(get_offline_count, R, [{<<"user">>, User}, {<<"host">>, Server}], [])].
Acc ++ [make_command(get_offline_count, R, [{<<"user">>, User}, {<<"host">>, Server}],
[{result_links, [{value, arg_host, 4, <<"user/", User/binary, "/queue/">>}]}]
)].
%%%
%%%
+1 -1
View File
@@ -217,7 +217,7 @@ need_transform(_) ->
transform({offline_msg, {U, S}, Timestamp, Expire, From, To, _, Packet}) ->
#offline_msg{us = {U, S}, timestamp = Timestamp, expire = Expire,
from = From ,to = To, packet = Packet};
from = From, to = To, packet = Packet};
transform(#offline_msg{us = {U, S}, from = From, to = To,
packet = El} = R) ->
R#offline_msg{us = {iolist_to_binary(U), iolist_to_binary(S)},
+2 -2
View File
@@ -127,8 +127,8 @@ remove_old_messages(Days, LServer) ->
of
{updated, N} ->
?INFO_MSG("~p message(s) deleted from offline spool", [N]);
_Error ->
?ERROR_MSG("Cannot delete message in offline spool: ~p", [_Error])
Error ->
?ERROR_MSG("Cannot delete message in offline spool: ~p", [Error])
end,
{atomic, ok}.
+26
View File
@@ -40,8 +40,14 @@
import_start/2, import_stop/2, import/5, import_info/0,
mod_opt_type/1, mod_options/1, depends/2]).
-export([webadmin_menu_hostuser/4, webadmin_page_hostuser/4]).
-import(ejabberd_web_admin, [make_command/4, make_command/2]).
-include("logger.hrl").
-include_lib("xmpp/include/xmpp.hrl").
-include("ejabberd_http.hrl").
-include("ejabberd_web_admin.hrl").
-include("mod_privacy.hrl").
-include("translate.hrl").
@@ -78,6 +84,8 @@ start(Host, Opts) ->
{hook, user_send_packet, user_send_packet, 50},
{hook, privacy_check_packet, check_packet, 50},
{hook, remove_user, remove_user, 50},
{hook, webadmin_menu_hostuser, webadmin_menu_hostuser, 50},
{hook, webadmin_page_hostuser, webadmin_page_hostuser, 50},
{iq_handler, ejabberd_sm, ?NS_PRIVACY, process_iq}]}.
stop(_Host) ->
@@ -840,6 +848,24 @@ export(LServer) ->
Mod = gen_mod:db_mod(LServer, ?MODULE),
Mod:export(LServer).
%%%
%%% WebAdmin
%%%
webadmin_menu_hostuser(Acc, _Host, _Username, _Lang) ->
Acc ++ [{<<"privacy">>, <<"Privacy Lists">>}].
webadmin_page_hostuser(_, Host, User,
#request{us = _US, path = [<<"privacy">>]} = R) ->
Res = ?H1GL(<<"Privacy Lists">>, <<"modules/#mod_privacy">>, <<"mod_privacy">>)
++ [make_command(privacy_set, R, [{<<"user">>, User}, {<<"host">>, Host}], [])],
{stop, Res};
webadmin_page_hostuser(Acc, _, _, _) -> Acc.
%%%
%%% Documentation
%%%
depends(_Host, _Opts) ->
[].
+23
View File
@@ -41,10 +41,16 @@
-export([get_commands_spec/0, bookmarks_to_pep/2]).
-export([webadmin_menu_hostuser/4, webadmin_page_hostuser/4]).
-import(ejabberd_web_admin, [make_command/4, make_command/2]).
-include("logger.hrl").
-include_lib("xmpp/include/xmpp.hrl").
-include("mod_private.hrl").
-include("ejabberd_commands.hrl").
-include("ejabberd_http.hrl").
-include("ejabberd_web_admin.hrl").
-include("translate.hrl").
-include("pubsub.hrl").
@@ -71,6 +77,8 @@ start(Host, Opts) ->
{hook, pubsub_publish_item, pubsub_publish_item, 50},
{hook, pubsub_delete_item, pubsub_delete_item, 50},
{hook, pubsub_tree_call, pubsub_tree_call, 50},
{hook, webadmin_menu_hostuser, webadmin_menu_hostuser, 50},
{hook, webadmin_page_hostuser, webadmin_page_hostuser, 50},
{iq_handler, ejabberd_sm, ?NS_PRIVATE, process_sm_iq}]}.
stop(Host) ->
@@ -544,6 +552,21 @@ bookmarks_to_pep(User, Server) ->
{error, <<"Cannot retrieve bookmarks from private XML storage">>}
end.
%%%===================================================================
%%% WebAdmin
%%%===================================================================
webadmin_menu_hostuser(Acc, _Host, _Username, _Lang) ->
Acc ++ [{<<"private">>, <<"Private XML Storage">>}].
webadmin_page_hostuser(_, Host, User,
#request{path = [<<"private">>]} = R) ->
Res = ?H1GL(<<"Private XML Storage">>, <<"modules/#mod_private">>, <<"mod_private">>)
++ [make_command(private_set, R, [{<<"user">>, User}, {<<"host">>, Host}], []),
make_command(private_get, R, [{<<"user">>, User}, {<<"host">>, Host}], [])],
{stop, Res};
webadmin_page_hostuser(Acc, _, _, _) -> Acc.
%%%===================================================================
%%% Cache
%%%===================================================================
+188 -9
View File
@@ -25,7 +25,7 @@
-author('amuhar3@gmail.com').
-protocol({xep, 356, '0.2.1', '16.09', "", ""}).
-protocol({xep, 356, '0.4.1', '24.10', "", ""}).
-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}]}].
@@ -108,6 +117,7 @@ mod_doc() ->
"carefully, only if you trust a component."), "",
?T("NOTE: This module is complementary to _`mod_delegation`_, "
"but can also be used separately.")],
note => "improved in 24.10",
opts =>
[{roster,
#{value => ?T("Options"),
@@ -130,6 +140,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 +195,9 @@ mod_doc() ->
example =>
["modules:",
" mod_privilege:",
" iq:",
" http://jabber.org/protocol/pubsub:",
" get: all",
" roster:",
" get: all",
" presence:",
@@ -190,6 +224,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 +250,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 +411,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 +424,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 +474,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,
@@ -391,10 +501,15 @@ code_change(_OldVsn, State, _Extra) ->
%%%===================================================================
-spec get_permissions(binary()) -> permissions().
get_permissions(ServerHost) ->
try ets:lookup_element(?MODULE, ServerHost, 2)
catch _:badarg -> #{}
case ets:lookup(?MODULE, ServerHost) of
[] -> #{};
[{_, Permissions}] -> Permissions
end.
%%
%% Message
%%
-spec forward_message(message()) -> ok.
forward_message(#message{to = To} = Msg) ->
ServerHost = To#jid.lserver,
@@ -435,6 +550,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 <privileged_iq/> 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),
@@ -451,6 +605,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),
@@ -472,7 +646,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) ->
+7
View File
@@ -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);
+13 -19
View File
@@ -265,10 +265,7 @@ init([ServerHost|_]) ->
ejabberd_router:register_route(
Host, ServerHost, {apply, ?MODULE, route}),
{Plugins, NodeTree, PepMapping} = init_plugins(Host, ServerHost, Opts),
DefaultModule = plugin(Host, hd(Plugins)),
DefaultNodeCfg = merge_config(
[mod_pubsub_opt:default_node_config(Opts),
DefaultModule:options()]),
DefaultNodeCfg = mod_pubsub_opt:default_node_config(Opts),
lists:foreach(
fun(H) ->
T = gen_mod:get_module_proc(H, config),
@@ -3029,7 +3026,8 @@ broadcast_stanza(Host, _Node, _Nidx, _Type, NodeOptions, SubsByDepth, NotifyType
end,
lists:foreach(fun(To) ->
ejabberd_router:route(
xmpp:set_to(StanzaToSend, jid:make(To)))
xmpp:set_to(xmpp:put_meta(StanzaToSend, ignore_sm_bounce, true),
jid:make(To)))
end, LJIDs)
end, SubIDsByJID).
@@ -3051,8 +3049,7 @@ broadcast_stanza({LUser, LServer, LResource}, Publisher, Node, Nidx, Type, NodeO
extended_headers([Publisher])),
Pred = fun(To) -> delivery_permitted(Owner, To, NodeOptions) end,
ejabberd_sm:route(jid:make(LUser, LServer, SenderResource),
{pep_message, <<((Node))/binary, "+notify">>, Stanza, Pred}),
ejabberd_router:route(xmpp:set_to(Stanza, jid:make(LUser, LServer)));
{pep_message, <<((Node))/binary, "+notify">>, Stanza, Pred});
broadcast_stanza(Host, _Publisher, Node, Nidx, Type, NodeOptions, SubsByDepth, NotifyType, BaseStanza, SHIM) ->
broadcast_stanza(Host, Node, Nidx, Type, NodeOptions, SubsByDepth, NotifyType, BaseStanza, SHIM).
@@ -3369,22 +3366,19 @@ get_option(Options, Var, Def) ->
-spec node_options(host(), binary()) -> [{atom(), any()}].
node_options(Host, Type) ->
DefaultOpts = node_plugin_options(Host, Type),
case lists:member(Type, config(Host, plugins)) of
true ->
config(Host, default_node_config, DefaultOpts);
false -> DefaultOpts
end.
ConfigOpts = config(Host, default_node_config),
PluginOpts = node_plugin_options(Host, Type),
merge_config([ConfigOpts, PluginOpts]).
-spec node_plugin_options(host(), binary()) -> [{atom(), any()}].
node_plugin_options(Host, Type) ->
Module = plugin(Host, Type),
case catch Module:options() of
{'EXIT', {undef, _}} ->
case {lists:member(Type, config(Host, plugins)), catch Module:options()} of
{true, Opts} when is_list(Opts) ->
Opts;
{_, _} ->
DefaultModule = plugin(Host, ?STDNODE),
DefaultModule:options();
Result ->
Result
DefaultModule:options()
end.
-spec node_owners_action(host(), binary(), nodeIdx(), [ljid()]) -> [ljid()].
@@ -4200,7 +4194,7 @@ delete_old_items(N) ->
fun(#pubsub_node{id = Nidx, type = Type}) ->
case node_action(Host, Type,
remove_extra_items,
[Nidx , N]) of
[Nidx, N]) of
{result, _} ->
ok;
{error, _} ->
+1 -1
View File
@@ -1,7 +1,7 @@
%%%----------------------------------------------------------------------
%%% File : mod_push_sql.erl
%%% Author : Evgeniy Khramtsov <ekhramtsov@process-one.net>
%%% Purpose :
%%% Purpose :
%%% Created : 26 Oct 2017 by Evgeny Khramtsov <ekhramtsov@process-one.net>
%%%
%%%
+10 -7
View File
@@ -573,24 +573,24 @@ may_remove_resource(From) -> From.
get_ip_access(Host) ->
mod_register_opt:ip_access(Host).
check_ip_access({User, Server, Resource}, IPAccess) ->
check_ip_access(Server, {User, Server, Resource}, IPAccess) ->
case ejabberd_sm:get_user_ip(User, Server, Resource) of
{IPAddress, _PortNumber} ->
check_ip_access(IPAddress, IPAccess);
check_ip_access(Server, IPAddress, IPAccess);
_ ->
deny
end;
check_ip_access(undefined, _IPAccess) ->
check_ip_access(_Server, undefined, _IPAccess) ->
deny;
check_ip_access(IPAddress, IPAccess) ->
acl:match_rule(global, IPAccess, IPAddress).
check_ip_access(Server, IPAddress, IPAccess) ->
acl:match_rule(Server, IPAccess, IPAddress).
check_access(User, Server, Source) ->
JID = jid:make(User, Server),
Access = mod_register_opt:access(Server),
IPAccess = get_ip_access(Server),
case acl:match_rule(Server, Access, JID) of
allow -> check_ip_access(Source, IPAccess);
allow -> check_ip_access(Server, Source, IPAccess);
deny -> deny
end.
@@ -654,7 +654,10 @@ mod_doc() ->
?T("Specify rules to restrict what usernames can be registered. "
"If a rule returns 'deny' on the requested username, "
"registration of that user name is denied. There are no "
"restrictions by default.")}},
"restrictions by default. "
"If 'AccessName' is 'none', then registering new accounts using "
"In-Band Registration is disabled and the corresponding "
"stream feature is not announced to clients.")}},
{access_from,
#{value => ?T("AccessName"),
desc =>
+5 -1
View File
@@ -1096,7 +1096,11 @@ make_webadmin_roster_table(Host, Username, R, RPath) ->
webadmin_user(Acc, User, Server, R) ->
Acc
++ [make_command(get_roster_count, R, [{<<"user">>, User}, {<<"host">>, Server}], [])].
++ [make_command(get_roster_count,
R,
[{<<"user">>, User}, {<<"host">>, Server}],
[{result_links,
[{value, arg_host, 4, <<"user/", User/binary, "/roster/">>}]}])].
%%% @format-end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+4 -4
View File
@@ -340,16 +340,16 @@ update_roster_sql({LUser, LServer, SJID, Name, SSubscription, SAsk, AskMessage},
raw_to_record(LServer,
[User, LServer, SJID, Nick, SSubscription, SAsk, SAskMessage,
_SServer, _SSubscribe, _SType]) ->
SServer, SSubscribe, SType]) ->
raw_to_record(LServer,
{User, LServer, SJID, Nick, SSubscription, SAsk, SAskMessage,
_SServer, _SSubscribe, _SType});
SServer, SSubscribe, SType});
raw_to_record(LServer,
{User, SJID, Nick, SSubscription, SAsk, SAskMessage,
_SServer, _SSubscribe, _SType}) ->
SServer, SSubscribe, SType}) ->
raw_to_record(LServer,
{User, LServer, SJID, Nick, SSubscription, SAsk, SAskMessage,
_SServer, _SSubscribe, _SType});
SServer, SSubscribe, SType});
raw_to_record(LServer,
{User, LServer, SJID, Nick, SSubscription, SAsk, SAskMessage,
_SServer, _SSubscribe, _SType}) ->
+143
View File
@@ -0,0 +1,143 @@
%%%-------------------------------------------------------------------
%%% Created : 20 Oct 2024 by Pawel Chmielowski <pawel@process-one.net>
%%%
%%%
%%% 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
%%% 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.
%%%
%%%-------------------------------------------------------------------
-module(mod_s2s_bidi).
-behaviour(gen_mod).
-protocol({xep, 288, '1.0.1', '24.10', "complete", ""}).
%% gen_mod API
-export([start/2, stop/1, reload/3, depends/2, mod_options/1]).
-export([mod_doc/0]).
%% Hooks
-export([s2s_in_packet/2, s2s_out_packet/2,
s2s_in_features/2, s2s_in_auth_result/3, s2s_out_unauthenticated_features/2, s2s_in_handle_info/2]).
-include_lib("xmpp/include/xmpp.hrl").
-include("logger.hrl").
-include("translate.hrl").
%%%===================================================================
%%% API
%%%===================================================================
start(_Host, _Opts) ->
{ok, [{hook, s2s_in_pre_auth_features, s2s_in_features, 50},
{hook, s2s_in_post_auth_features, s2s_in_features, 50},
{hook, s2s_in_unauthenticated_packet, s2s_in_packet, 50},
{hook, s2s_in_authenticated_packet, s2s_in_packet, 50},
{hook, s2s_in_handle_info, s2s_in_handle_info, 50},
{hook, s2s_in_auth_result, s2s_in_auth_result, 50},
{hook, s2s_out_unauthenticated_features, s2s_out_unauthenticated_features, 50},
{hook, s2s_out_packet, s2s_out_packet, 50}]}.
stop(_Host) ->
ok.
reload(_Host, _NewOpts, _OldOpts) ->
ok.
depends(_Host, _Opts) ->
[].
mod_options(_Host) ->
[].
mod_doc() ->
#{desc =>
[?T("The module adds support for "
"https://xmpp.org/extensions/xep-0288.html"
"[XEP-0288: Bidirectional Server-to-Server Connections] that allows using "
"single s2s connection to communicate in both directions.")],
note => "added in 24.10",
opts => [],
example =>
["modules:",
" mod_s2s_bidi: {}"]}.
s2s_in_features(Acc, _) ->
[#s2s_bidi{}|Acc].
s2s_in_packet(State, #s2s_bidi{}) ->
{stop, State#{bidi_enabled => true}};
s2s_in_packet(State, _) ->
State.
s2s_out_unauthenticated_features(#{db_verify := _} = State, _) ->
State;
s2s_out_unauthenticated_features(State, #stream_features{} = Pkt) ->
try xmpp:try_subtag(Pkt, #s2s_bidi{}) of
#s2s_bidi{} ->
ejabberd_s2s_out:send(State#{bidi_enabled => true}, #s2s_bidi{})
catch _:{xmpp_codec, _Why} ->
State
end.
s2s_out_packet(#{bidi_enabled := true, ip := {IP, _}} = State, Pkt0)
when ?is_stanza(Pkt0) ->
To = xmpp:get_to(Pkt0),
case check_from_to(State, xmpp:get_from(Pkt0), To) of
ok ->
Pkt = xmpp:put_meta(Pkt0, ip, IP),
LServer = ejabberd_router:host_of_route(To#jid.lserver),
State1 = ejabberd_hooks:run_fold(s2s_in_authenticated_packet,
LServer, State, [Pkt]),
{Pkt1, State2} = ejabberd_hooks:run_fold(s2s_receive_packet, LServer,
{Pkt, State1}, []),
case Pkt1 of
drop -> ok;
_ -> ejabberd_router:route(Pkt1)
end,
{stop, State2};
{error, Err} ->
{stop, ejabberd_s2s_out:send(State, Err)}
end;
s2s_out_packet(#{db_verify := _} = State, #stream_features{}) ->
State;
s2s_out_packet(State, #stream_features{} = Pkt) ->
try xmpp:try_subtag(Pkt, #s2s_bidi{}) of
#s2s_bidi{} ->
ejabberd_s2s_out:send(State#{bidi_enabled => true}, #s2s_bidi{})
catch _:{xmpp_codec, _Why} ->
State
end;
s2s_out_packet(State, _Pkt) ->
State.
s2s_in_handle_info(State, {route, Pkt}) when ?is_stanza(Pkt) ->
ejabberd_s2s_in:send(State, Pkt);
s2s_in_handle_info(State, _Info) ->
State.
check_from_to(#{remote_server := RServer}, #jid{lserver = FromServer},
#jid{lserver = ToServer}) ->
if
RServer /= FromServer -> {error, xmpp:serr_invalid_from()};
true ->
case ejabberd_router:is_my_route(ToServer) of
false -> {error, xmpp:serr_host_unknown()};
_ -> ok
end
end.
s2s_in_auth_result(#{server := LServer, bidi_enabled := true} = State, true, RServer) ->
ejabberd_s2s:register_connection({LServer, RServer}),
State;
s2s_in_auth_result(State, _, _) ->
State.
+121
View File
@@ -0,0 +1,121 @@
%%%-------------------------------------------------------------------
%%% Created : 20 Oct 2024 by Pawel Chmielowski <pawel@process-one.net>
%%%
%%%
%%% 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
%%% 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.
%%%
%%%-------------------------------------------------------------------
-module(mod_scram_upgrade).
-behaviour(gen_mod).
-protocol({xep, 480, '0.1', '24.10', "complete", ""}).
%% gen_mod API
-export([start/2, stop/1, reload/3, depends/2, mod_options/1, mod_opt_type/1]).
-export([mod_doc/0]).
%% Hooks
-export([c2s_inline_features/2, c2s_handle_sasl2_inline/1,
c2s_handle_sasl2_task_next/4, c2s_handle_sasl2_task_data/3]).
-include_lib("xmpp/include/xmpp.hrl").
-include_lib("xmpp/include/scram.hrl").
-include("logger.hrl").
-include("translate.hrl").
%%%===================================================================
%%% API
%%%===================================================================
start(_Host, _Opts) ->
{ok, [{hook, c2s_inline_features, c2s_inline_features, 50},
{hook, c2s_handle_sasl2_inline, c2s_handle_sasl2_inline, 10},
{hook, c2s_handle_sasl2_task_next, c2s_handle_sasl2_task_next, 10},
{hook, c2s_handle_sasl2_task_data, c2s_handle_sasl2_task_data, 10}]}.
stop(_Host) ->
ok.
reload(_Host, _NewOpts, _OldOpts) ->
ok.
depends(_Host, _Opts) ->
[].
mod_opt_type(offered_upgrades) ->
econf:list(econf:enum([sha256, sha512])).
mod_options(_Host) ->
[{offered_upgrades, [sha256, sha512]}].
mod_doc() ->
#{desc =>
[?T("The module adds support for "
"https://xmpp.org/extensions/xep-0480.html"
"[XEP-0480: SASL Upgrade Tasks] that allows users to upgrade "
"passwords to more secure representation.")],
note => "added in 24.10",
opts => [{offered_upgrades,
#{value => "list(sha256, sha512)",
desc => ?T("List with upgrade types that should be offered")}}],
example =>
["modules:",
" mod_scram_upgrade:",
" offered_upgrades:",
" - sha256",
" - sha512"]}.
c2s_inline_features({Sasl, Bind, Extra}, Host) ->
Methods = lists:map(
fun(sha256) -> #sasl_upgrade{cdata = <<"UPGR-SCRAM-SHA-256">>};
(sha512) -> #sasl_upgrade{cdata = <<"UPGR-SCRAM-SHA-512">>}
end, mod_scram_upgrade_opt:offered_upgrades(Host)),
{Sasl, Bind, Methods ++ Extra}.
c2s_handle_sasl2_inline({State, Els, _Results} = Acc) ->
case lists:keyfind(sasl_upgrade, 1, Els) of
false ->
Acc;
#sasl_upgrade{cdata = Type} ->
{stop, {State, {continue, [Type]}, []}}
end.
c2s_handle_sasl2_task_next({_, State}, Task, _Els, _InlineEls) ->
Algo = case Task of
<<"UPGR-SCRAM-SHA-256">> -> sha256;
<<"UPGR-SCRAM-SHA-512">> -> sha512
end,
Salt = p1_rand:bytes(16),
{task_data, [#scram_upgrade_salt{cdata = Salt, iterations = 4096}],
State#{scram_upgrade => {Algo, Salt, 4096}}}.
c2s_handle_sasl2_task_data({_, #{user := User, server := Server,
scram_upgrade := {Algo, Salt, Iter}} = State},
Els, InlineEls) ->
case xmpp:get_subtag(#sasl2_task_data{sub_els = Els}, #scram_upgrade_hash{}) of
#scram_upgrade_hash{data = SaltedPassword} ->
StoredKey = scram:stored_key(Algo, scram:client_key(Algo, SaltedPassword)),
ServerKey = scram:server_key(Algo, SaltedPassword),
ejabberd_auth:set_password(User, Server,
#scram{hash = Algo, iterationcount = Iter, salt = Salt,
serverkey = ServerKey, storedkey = StoredKey}),
State2 = maps:remove(scram_upgrade, State),
InlineEls = lists:keydelete(sasl_upgrade, 1, InlineEls),
case ejabberd_c2s:handle_sasl2_inline(InlineEls, State2) of
{State3, NewEls, Results} ->
{success, NewEls, Results, State3}
end;
_ ->
{abort, State}
end.
+13
View File
@@ -0,0 +1,13 @@
%% Generated automatically
%% DO NOT EDIT: run `make options` instead
-module(mod_scram_upgrade_opt).
-export([offered_upgrades/1]).
-spec offered_upgrades(gen_mod:opts() | global | binary()) -> ['sha256' | 'sha512'].
offered_upgrades(Opts) when is_map(Opts) ->
gen_mod:get_opt(offered_upgrades, Opts);
offered_upgrades(Host) ->
gen_mod:get_module_opt(Host, mod_scram_upgrade, offered_upgrades).
-1
View File
@@ -52,7 +52,6 @@
-define(GROUP_CACHE, shared_roster_ldap_group_cache).
-define(DISPLAYED_CACHE, shared_roster_ldap_displayed_cache).
-define(LDAP_SEARCH_TIMEOUT, 5). %% Timeout for LDAP search queries in seconds
-define(INVALID_SETTING_MSG, "~ts is not properly set! ~ts will not function.").
-record(state,
{host = <<"">> :: binary(),
+3 -2
View File
@@ -122,11 +122,12 @@ c2s_stream_features(Acc, Host) ->
Acc
end.
c2s_inline_features({Sasl, Bind} = Acc, Host) ->
c2s_inline_features({Sasl, Bind, Extra} = Acc, Host) ->
case gen_mod:is_loaded(Host, ?MODULE) of
true ->
{[#feature_sm{xmlns = ?NS_STREAM_MGMT_3} | Sasl],
[#bind2_feature{var = ?NS_STREAM_MGMT_3} | Bind]};
[#bind2_feature{var = ?NS_STREAM_MGMT_3} | Bind],
Extra};
false ->
Acc
end.
+75 -1
View File
@@ -43,12 +43,17 @@
-export([init/1, handle_call/3, handle_cast/2,
handle_info/2, terminate/2, code_change/3]).
-export([route/1]).
-export([webadmin_menu_hostuser/4, webadmin_page_hostuser/4]).
-import(ejabberd_web_admin, [make_command/4, make_command/2, make_table/2]).
-include("logger.hrl").
-include_lib("xmpp/include/xmpp.hrl").
-include("mod_vcard.hrl").
-include("translate.hrl").
-include("ejabberd_stacktrace.hrl").
-include("ejabberd_http.hrl").
-include("ejabberd_web_admin.hrl").
-define(VCARD_CACHE, vcard_cache).
@@ -98,6 +103,8 @@ init([Host|_]) ->
ejabberd_hooks:add(disco_sm_features, Host, ?MODULE,
get_sm_features, 50),
ejabberd_hooks:add(vcard_iq_set, Host, ?MODULE, vcard_iq_set, 50),
ejabberd_hooks:add(webadmin_menu_hostuser, Host, ?MODULE, webadmin_menu_hostuser, 50),
ejabberd_hooks:add(webadmin_page_hostuser, Host, ?MODULE, webadmin_page_hostuser, 50),
MyHosts = gen_mod:get_opt_hosts(Opts),
Search = mod_vcard_opt:search(Opts),
if Search ->
@@ -161,6 +168,8 @@ terminate(_Reason, #state{hosts = MyHosts, server_host = Host}) ->
gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_VCARD),
ejabberd_hooks:delete(disco_sm_features, Host, ?MODULE, get_sm_features, 50),
ejabberd_hooks:delete(vcard_iq_set, Host, ?MODULE, vcard_iq_set, 50),
ejabberd_hooks:delete(webadmin_menu_hostuser, Host, ?MODULE, webadmin_menu_hostuser, 50),
ejabberd_hooks:delete(webadmin_page_hostuser, Host, ?MODULE, webadmin_page_hostuser, 50),
Mod = gen_mod:db_mod(Host, ?MODULE),
Mod:stop(Host),
lists:foreach(
@@ -391,6 +400,12 @@ make_vcard_search(User, LUser, LServer, VCARD) ->
lorgunit = LOrgUnit}.
-spec vcard_iq_set(iq()) -> iq() | {stop, stanza_error()}.
vcard_iq_set(#iq{from = #jid{user = FromUser, lserver = FromLServer},
to = #jid{user = ToUser, lserver = ToLServer},
lang = Lang})
when (FromUser /= ToUser) or (FromLServer /= ToLServer) ->
Txt = ?T("User not allowed to perform an IQ set on another user's vCard."),
{stop, xmpp:err_forbidden(Txt, Lang)};
vcard_iq_set(#iq{from = From, lang = Lang, sub_els = [VCard]} = IQ) ->
#jid{user = User, lserver = LServer} = From,
case set_vcard(User, LServer, VCard) of
@@ -398,13 +413,17 @@ vcard_iq_set(#iq{from = From, lang = Lang, sub_els = [VCard]} = IQ) ->
%% Should not be here?
Txt = ?T("Nodeprep has failed"),
{stop, xmpp:err_internal_server_error(Txt, Lang)};
{error, not_implemented} ->
Txt = ?T("Updating the vCard is not supported by the vCard storage backend"),
{stop, xmpp:err_feature_not_implemented(Txt, Lang)};
ok ->
IQ
end;
vcard_iq_set(Acc) ->
Acc.
-spec set_vcard(binary(), binary(), xmlel() | vcard_temp()) -> {error, badarg|binary()} | ok.
-spec set_vcard(binary(), binary(), xmlel() | vcard_temp()) ->
{error, badarg | not_implemented | binary()} | ok.
set_vcard(User, LServer, VCARD) ->
case jid:nodeprep(User) of
error ->
@@ -550,6 +569,61 @@ export(LServer) ->
Mod = gen_mod:db_mod(LServer, ?MODULE),
Mod:export(LServer).
%%%
%%% WebAdmin
%%%
webadmin_menu_hostuser(Acc, _Host, _Username, _Lang) ->
Acc ++ [{<<"vcard">>, <<"vCard">>}].
webadmin_page_hostuser(_, Host, User,
#request{path = [<<"vcard">>]} = R) ->
Head = ?H1GL(<<"vCard">>, <<"modules/#mod_vcard">>, <<"mod_vcard">>),
Set = [make_command(set_nickname, R, [{<<"user">>, User}, {<<"host">>, Host}], []),
make_command(set_vcard, R, [{<<"user">>, User}, {<<"host">>, Host}], []),
make_command(set_vcard2, R, [{<<"user">>, User}, {<<"host">>, Host}], []),
make_command(set_vcard2_multi, R, [{<<"user">>, User}, {<<"host">>, Host}], [])],
timer:sleep(100), % setting vcard takes a while, let's delay the get commands
FieldNames = [<<"VERSION">>, <<"FN">>, <<"NICKNAME">>, <<"BDAY">>],
FieldNames2 =
[{<<"N">>, <<"FAMILY">>},
{<<"N">>, <<"GIVEN">>},
{<<"N">>, <<"MIDDLE">>},
{<<"ADR">>, <<"CTRY">>},
{<<"ADR">>, <<"LOCALITY">>},
{<<"EMAIL">>, <<"USERID">>}],
Get = [make_command(get_vcard, R, [{<<"user">>, User}, {<<"host">>, Host}], []),
?XE(<<"blockquote">>,
[make_table([<<"name">>, <<"value">>],
[{?C(FieldName),
make_command(get_vcard,
R,
[{<<"user">>, User},
{<<"host">>, Host},
{<<"name">>, FieldName}],
[{only, value}])}
|| FieldName <- FieldNames])]),
make_command(get_vcard2, R, [{<<"user">>, User}, {<<"host">>, Host}], []),
?XE(<<"blockquote">>,
[make_table([<<"name">>, <<"subname">>, <<"value">>],
[{?C(FieldName),
?C(FieldSubName),
make_command(get_vcard2,
R,
[{<<"user">>, User},
{<<"host">>, Host},
{<<"name">>, FieldName},
{<<"subname">>, FieldSubName}],
[{only, value}])}
|| {FieldName, FieldSubName} <- FieldNames2])]),
make_command(get_vcard2_multi, R, [{<<"user">>, User}, {<<"host">>, Host}], [])],
{stop, Head ++ Get ++ Set};
webadmin_page_hostuser(Acc, _, _, _) -> Acc.
%%%
%%% Documentation
%%%
depends(_Host, _Opts) ->
[].
+1 -1
View File
@@ -263,7 +263,7 @@ remove_user(LUser, LServer) ->
" where lusername=%(LUser)s and %(LServer)H"))
end).
export(_Server) ->
export(_Server) ->
[{vcard,
fun(Host, #vcard{us = {LUser, LServer}, vcard = VCARD})
when LServer == Host ->
+2 -3
View File
@@ -39,9 +39,8 @@ get_nameservers() ->
is_good_ns(Addr) ->
element(1,
inet_res:nnslookup("a.root-servers.net", in, a, [{Addr,53}],
timer:seconds(5)
)
) =:= ok.
timer:seconds(5)))
=:= ok.
reg() ->
{ok, R} = win32reg:open([read]),
+1 -1
View File
@@ -18,7 +18,7 @@ GO
USE ejabberd_test;
GO
CREATE LOGIN ejabberd_test WITH PASSWORD = 'ejabberd_Test1';
CREATE LOGIN ejabberd_test WITH PASSWORD = 'ejabberd_Test1', CHECK_POLICY = OFF;
GO
CREATE USER ejabberd_test FOR LOGIN ejabberd_test;
+2
View File
@@ -305,6 +305,8 @@ warn_type({var, _, 'Type'}, #state{module = mod_delegation}, "not an atom") ->
ok;
warn_type({var, _, 'NS'}, #state{module = mod_delegation}, "not a binary") ->
ok;
warn_type({var, _, _}, #state{module = gen_mod}, _) ->
ok;
warn_type(Form, State, Warning) ->
log("~s:~p: Warning: " ++ Warning ++ ": ~s~n",
[State#state.file,
+9 -9
View File
@@ -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.6.2'
expat_vsn='2.6.3'
zlib_vsn='1.3.1'
yaml_vsn='0.2.5'
ssl_vsn='3.3.1'
otp_vsn='26.2.5'
elixir_vsn='1.16.3'
ssl_vsn='3.3.2'
otp_vsn='26.2.5.4'
elixir_vsn='1.17.2'
pam_vsn='1.6.1'
png_vsn='1.6.42'
png_vsn='1.6.43'
jpeg_vsn='9f'
webp_vsn='1.3.2'
webp_vsn='1.4.0'
gd_vsn='2.3.3'
odbc_vsn='2.3.12'
sqlite_vsn='3450100'
sqlite_vsn='3460100'
root_dir="${BUILD_DIR:-$HOME/build}"
bootstrap_dir="$root_dir/bootstrap"
ct_prefix_dir="$root_dir/x-tools"
@@ -179,7 +179,7 @@ check_vsn()
check_configured_dep_vsns()
{
check_vsn 'OpenSSL' "$ssl_vsn" \
'https://www.openssl.org/source/' \
'https://openssl-library.org/source/' \
'openssl-\(3\.[1-9]\.[0-9.]*\)\.tar\.gz'
check_vsn 'LibYAML' "$yaml_vsn" \
'https://pyyaml.org/wiki/LibYAML' \
@@ -878,7 +878,7 @@ else
curl -fsSLO "https://github.com/libexpat/libexpat/releases/download/R_$(printf '%s' "$expat_vsn" | sed 's/\./_/g')/$expat_tar"
curl -fsSLO "https://zlib.net/fossils/$zlib_tar"
curl -fsSLO "https://pyyaml.org/download/libyaml/$yaml_tar"
curl -fsSLO "https://www.openssl.org/source/$ssl_tar"
curl -fsSLO "https://github.com/openssl/openssl/releases/download/openssl-$ssl_vsn/$ssl_tar"
curl -fsSLO "https://github.com/erlang/otp/releases/download/OTP-$otp_vsn/$otp_tar"
curl -fsSLO "https://github.com/elixir-lang/elixir/archive/v$elixir_vsn.tar.gz"
curl -fsSLO "https://github.com/linux-pam/linux-pam/releases/download/v$pam_vsn/$pam_tar"