25
1
mirror of https://github.com/processone/ejabberd.git synced 2024-11-22 16:20:52 +01:00

Merge branch 'master' into mix

This commit is contained in:
Evgeny Khramtsov 2018-12-10 11:57:04 +03:00
commit 74e8c0376f
23 changed files with 574 additions and 757 deletions

10
CHANGELOG.md Normal file
View File

@ -0,0 +1,10 @@
# Version NEXT
*
# Version 18.12
* MAM data store compression
* Proxy protocol support (http://www.haproxy.org/download/1.8/doc/proxy-protocol.txt)
* MUC Self-Ping optimization (XEP-0410)
* Bookmarks conversion (XEP-0411)

View File

@ -1,665 +0,0 @@
###
### ejabberd configuration file
###
###
### The parameters used in this configuration file are explained in more detail
### in the ejabberd Installation and Operation Guide.
### Please consult the Guide in case of doubts, it is included with
### your copy of ejabberd, and is also available online at
### http://www.process-one.net/en/ejabberd/docs/
### The configuration file is written in YAML.
### Refer to http://en.wikipedia.org/wiki/YAML for the brief description.
### However, ejabberd treats different literals as different types:
###
### - unquoted or single-quoted strings. They are called "atoms".
### Example: dog, 'Jupiter', '3.14159', YELLOW
###
### - numeric literals. Example: 3, -45.0, .0
###
### - quoted or folded strings.
### Examples of quoted string: "Lizzard", "orange".
### Example of folded string:
### > Art thou not Romeo,
### and a Montague?
### =======
### LOGGING
##
## loglevel: Verbosity of log files generated by ejabberd.
## 0: No ejabberd log at all (not recommended)
## 1: Critical
## 2: Error
## 3: Warning
## 4: Info
## 5: Debug
##
loglevel: 4
##
## rotation: Describe how to rotate logs. Either size and/or date can trigger
## log rotation. Setting count to N keeps N rotated logs. Setting count to 0
## does not disable rotation, it instead rotates the file and keeps no previous
## versions around. Setting size to X rotate log when it reaches X bytes.
## To disable rotation set the size to 0 and the date to ""
## Date syntax is taken from the syntax newsyslog uses in newsyslog.conf.
## Some examples:
## $D0 rotate every night at midnight
## $D23 rotate every day at 23:00 hr
## $W0D23 rotate every week on Sunday at 23:00 hr
## $W5D16 rotate every week on Friday at 16:00 hr
## $M1D0 rotate on the first day of every month at midnight
## $M5D6 rotate on every 5th day of the month at 6:00 hr
##
log_rotate_size: 10485760
log_rotate_date: ""
log_rotate_count: 1
##
## overload protection: If you want to limit the number of messages per second
## allowed from error_logger, which is a good idea if you want to avoid a flood
## of messages when system is overloaded, you can set a limit.
## 100 is ejabberd's default.
log_rate_limit: 100
##
## watchdog_admins: Only useful for developers: if an ejabberd process
## consumes a lot of memory, send live notifications to these XMPP
## accounts.
##
## watchdog_admins:
## - "bob@example.com"
### ================
### SERVED HOSTNAMES
##
## hosts: Domains served by ejabberd.
## You can define one or several, for example:
## hosts:
## - "example.net"
## - "example.com"
## - "example.org"
##
hosts:
- "localhost"
##
## route_subdomains: Delegate subdomains to other XMPP servers.
## For example, if this ejabberd serves example.org and you want
## to allow communication with an XMPP server called im.example.org.
##
## route_subdomains: s2s
### ===============
### LISTENING PORTS
##
## listen: The ports ejabberd will listen on, which service each is handled
## by and what options to start it with.
##
listen:
-
port: 5222
module: ejabberd_c2s
##
## If TLS is compiled in and you installed a SSL
## certificate, specify the full path to the
## file and uncomment these lines:
##
## certfile: "/path/to/ssl.pem"
## starttls: true
##
## To enforce TLS encryption for client connections,
## use this instead of the "starttls" option:
##
## starttls_required: true
##
## Custom OpenSSL options
##
## protocol_options:
## - "no_sslv3"
## - "no_tlsv1"
max_stanza_size: 65536
shaper: c2s_shaper
access: c2s
-
port: 5269
module: ejabberd_s2s_in
##
## ejabberd_service: Interact with external components (transports, ...)
##
## -
## port: 8888
## module: ejabberd_service
## access: all
## shaper_rule: fast
## ip: "127.0.0.1"
## hosts:
## "icq.example.org":
## password: "secret"
## "sms.example.org":
## password: "secret"
##
## ejabberd_stun: Handles STUN Binding requests
##
## -
## port: 3478
## transport: udp
## module: ejabberd_stun
##
## To handle XML-RPC requests that provide admin credentials:
##
## -
## port: 4560
## module: ejabberd_xmlrpc
-
port: 5280
module: ejabberd_http
## request_handlers:
## "/pub/archive": mod_http_fileserver
web_admin: true
http_bind: true
## register: true
captcha: true
##
## s2s_use_starttls: Enable STARTTLS + Dialback for S2S connections.
## Allowed values are: false optional required required_trusted
## You must specify a certificate file.
##
## s2s_use_starttls: optional
##
## s2s_certfile: Specify a certificate file.
##
## s2s_certfile: "/path/to/ssl.pem"
## Custom OpenSSL options
##
## s2s_protocol_options:
## - "no_sslv3"
## - "no_tlsv1"
##
## domain_certfile: Specify a different certificate for each served hostname.
##
## host_config:
## "example.org":
## domain_certfile: "/path/to/example_org.pem"
## "example.com":
## domain_certfile: "/path/to/example_com.pem"
##
## S2S whitelist or blacklist
##
## Default s2s policy for undefined hosts.
##
## s2s_access: s2s
##
## Outgoing S2S options
##
## Preferred address families (which to try first) and connect timeout
## in milliseconds.
##
## outgoing_s2s_families:
## - ipv4
## - ipv6
## outgoing_s2s_timeout: 10000
### ==============
### AUTHENTICATION
##
## auth_method: Method used to authenticate the users.
## The default method is the internal.
## If you want to use a different method,
## comment this line and enable the correct ones.
##
auth_method: internal
##
## Store the plain passwords or hashed for SCRAM:
## auth_password_format: plain
## auth_password_format: scram
##
## Define the FQDN if ejabberd doesn't detect it:
## fqdn: "server3.example.com"
##
## Authentication using external script
## Make sure the script is executable by ejabberd.
##
## auth_method: external
## extauth_program: "/path/to/authentication/script"
##
## Authentication using ODBC
## Remember to setup a database in the next section.
##
## auth_method: odbc
##
## Authentication using PAM
##
## auth_method: pam
## pam_service: "pamservicename"
##
## Authentication using LDAP
##
## auth_method: ldap
##
## List of LDAP servers:
## ldap_servers:
## - "localhost"
##
## Encryption of connection to LDAP servers:
## ldap_encrypt: none
## ldap_encrypt: tls
##
## Port to connect to on LDAP servers:
## ldap_port: 389
## ldap_port: 636
##
## LDAP manager:
## ldap_rootdn: "dc=example,dc=com"
##
## Password of LDAP manager:
## ldap_password: "******"
##
## Search base of LDAP directory:
## ldap_base: "dc=example,dc=com"
##
## LDAP attribute that holds user ID:
## ldap_uids:
## - "mail": "%u@mail.example.org"
##
## LDAP filter:
## ldap_filter: "(objectClass=shadowAccount)"
##
## Anonymous login support:
## auth_method: anonymous
## anonymous_protocol: sasl_anon | login_anon | both
## allow_multiple_connections: true | false
##
## host_config:
## "public.example.org":
## auth_method: anonymous
## allow_multiple_connections: false
## anonymous_protocol: sasl_anon
##
## To use both anonymous and internal authentication:
##
## host_config:
## "public.example.org":
## auth_method:
## - internal
## - anonymous
### ==============
### DATABASE SETUP
## ejabberd by default uses the internal Mnesia database,
## so you do not necessarily need this section.
## This section provides configuration examples in case
## you want to use other database backends.
## Please consult the ejabberd Guide for details on database creation.
##
## MySQL server:
##
## odbc_type: mysql
## odbc_server: "server"
## odbc_database: "database"
## odbc_username: "username"
## odbc_password: "password"
##
## If you want to specify the port:
## odbc_port: 1234
##
## PostgreSQL server:
##
## odbc_type: pgsql
## odbc_server: "server"
## odbc_database: "database"
## odbc_username: "username"
## odbc_password: "password"
##
## If you want to specify the port:
## odbc_port: 1234
##
## If you use PostgreSQL, have a large database, and need a
## faster but inexact replacement for "select count(*) from users"
##
## pgsql_users_number_estimate: true
##
## ODBC compatible or MSSQL server:
##
## odbc_type: odbc
## odbc_server: "DSN=ejabberd;UID=ejabberd;PWD=ejabberd"
##
## Number of connections to open to the database for each virtual host
##
## odbc_pool_size: 10
##
## Interval to make a dummy SQL request to keep the connections to the
## database alive. Specify in seconds: for example 28800 means 8 hours
##
## odbc_keepalive_interval: undefined
### ===============
### TRAFFIC SHAPERS
shaper:
##
## The "normal" shaper limits traffic speed to 1000 B/s
##
normal: 1000
##
## The "fast" shaper limits traffic speed to 50000 B/s
##
fast: 50000
##
## This option specifies the maximum number of elements in the queue
## of the FSM. Refer to the documentation for details.
##
max_fsm_queue: 1000
###. ====================
###' ACCESS CONTROL LISTS
acl:
##
## The 'admin' ACL grants administrative privileges to XMPP accounts.
## You can put here as many accounts as you want.
##
## admin:
## user:
## - "aleksey": "localhost"
## - "ermine": "example.org"
##
## Blocked users
##
## blocked:
## user:
## - "baduser": "example.org"
## - "test"
## Local users: don't modify this.
##
local:
user_regexp: ""
##
## More examples of ACLs
##
## jabberorg:
## server:
## - "jabber.org"
## aleksey:
## user:
## - "aleksey": "jabber.ru"
## test:
## user_regexp: "^test"
## user_glob: "test*"
##
## Loopback network
##
loopback:
ip:
- "127.0.0.0/8"
##
## Bad XMPP servers
##
## bad_servers:
## server:
## - "xmpp.zombie.org"
## - "xmpp.spam.com"
##
## Define specific ACLs in a virtual host.
##
## host_config:
## "localhost":
## acl:
## admin:
## user:
## - "bob-local": "localhost"
### ============
### ACCESS RULES
access:
## Maximum number of simultaneous sessions allowed for a single user:
max_user_sessions:
all: 10
## Maximum number of offline messages that users can have:
max_user_offline_messages:
admin: 5000
all: 100
## This rule allows access only for local users:
local:
local: allow
## Only non-blocked users can use c2s connections:
c2s:
blocked: deny
all: allow
## For C2S connections, all users except admins use the "normal" shaper
c2s_shaper:
admin: none
all: normal
## All S2S connections use the "fast" shaper
s2s_shaper:
all: fast
## Only admins can send announcement messages:
announce:
admin: allow
## Only admins can use the configuration interface:
configure:
admin: allow
## Admins of this server are also admins of the MUC service:
muc_admin:
admin: allow
## Only accounts of the local ejabberd server can create rooms:
muc_create:
local: allow
## All users are allowed to use the MUC service:
muc:
all: allow
## Only accounts on the local ejabberd server can create Pubsub nodes:
pubsub_createnode:
local: allow
## In-band registration allows registration of any possible username.
## To disable in-band registration, replace 'allow' with 'deny'.
register:
all: allow
## Only allow to register from localhost
trusted_network:
loopback: allow
## Do not establish S2S connections with bad servers
## s2s:
## bad_servers: deny
## all: allow
## By default the frequency of account registrations from the same IP
## is limited to 1 account every 10 minutes. To disable, specify: infinity
## registration_timeout: 600
##
## Define specific Access Rules in a virtual host.
##
## host_config:
## "localhost":
## access:
## c2s:
## admin: allow
## all: deny
## register:
## all: deny
### ================
### DEFAULT LANGUAGE
##
## language: Default language used for server messages.
##
language: "en"
##
## Set a different default language in a virtual host.
##
## host_config:
## "localhost":
## language: "ru"
### =======
### CAPTCHA
##
## Full path to a script that generates the image.
##
## captcha_cmd: "/lib/ejabberd/priv/bin/captcha.sh"
##
## Host for the URL and port where ejabberd listens for CAPTCHA requests.
##
## captcha_host: "example.org:5280"
##
## Limit CAPTCHA calls per minute for JID/IP to avoid DoS.
##
## captcha_limit: 5
### =======
### MODULES
##
## Modules enabled in all ejabberd virtual hosts.
##
modules:
mod_adhoc: {}
## mod_admin_extra: {}
mod_announce: # recommends mod_adhoc
access: announce
mod_blocking: {} # requires mod_privacy
mod_caps: {}
mod_carboncopy: {}
mod_client_state:
queue_chat_states: true
queue_presence: false
mod_configure: {} # requires mod_adhoc
mod_disco: {}
## mod_echo: {}
mod_http_bind: {}
## mod_http_fileserver:
## docroot: "/var/www"
## accesslog: "/var/log/ejabberd/access.log"
mod_last: {}
mod_muc:
## host: "conference.@HOST@"
access: muc
access_create: muc_create
access_persistent: muc_create
access_admin: muc_admin
## mod_muc_log: {}
mod_offline:
access_max_user_messages: max_user_offline_messages
mod_ping: {}
## mod_pres_counter:
## count: 5
## interval: 60
mod_privacy: {}
mod_private: {}
## mod_proxy65: {}
mod_pubsub:
access_createnode: pubsub_createnode
## reduces resource consumption, but XEP incompliant
ignore_pep_from_offline: true
## XEP compliant, but increases resource consumption
## ignore_pep_from_offline: false
last_item_cache: false
plugins:
- "flat"
- "hometree"
- "pep" # pep requires mod_caps
mod_register:
##
## Protect In-Band account registrations with CAPTCHA.
##
## captcha_protected: true
##
## Set the minimum informational entropy for passwords.
##
## password_strength: 32
##
## After successful registration, the user receives
## a message with this subject and body.
##
welcome_message:
subject: "Welcome!"
body: |-
Hi.
Welcome to this XMPP server.
##
## When a user registers, send a notification to
## these XMPP accounts.
##
## registration_watchers:
## - "admin1@example.org"
##
## Only clients in the server machine can register accounts
##
ip_access: trusted_network
##
## Local c2s or remote s2s users cannot register accounts
##
## access_from: deny
access: register
mod_roster: {}
mod_shared_roster: {}
mod_stats: {}
mod_time: {}
mod_vcard: {}
mod_version: {}
##
## Enable modules with custom options in a specific virtual host
##
## host_config:
## "localhost":
## modules:
## mod_echo:
## host: "mirror.localhost"
##
## Enable modules management via ejabberdctl for installation and
## uninstallation of public/private contributed modules
## (enabled by default)
##
allow_contrib_modules: true
### Local Variables:
### mode: yaml
### End:
### vim: set filetype=yaml tabstop=8

View File

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

View File

@ -39,6 +39,24 @@ certfiles:
- "/etc/letsencrypt/live/localhost/fullchain.pem" - "/etc/letsencrypt/live/localhost/fullchain.pem"
- "/etc/letsencrypt/live/localhost/privkey.pem" - "/etc/letsencrypt/live/localhost/privkey.pem"
define_macro:
# TLS options for client not being able to use modern ciphers (Windows XP+, Android 3.0+)
CIPHERS_INTERMEDIATE: "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS"
PROTOCOL_OPTIONS_INTERMEDIATE:
- "no_sslv2"
- "no_sslv3"
# TLS options for client able to use moder ciphers (Windows 7+, Android 5.0+)
CIPHERS_MODERN: "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256"
PROTOCOL_OPTIONS_MODERN:
- "no_sslv2"
- "no_sslv3"
- "no_tlsv1"
- "no_tlsv1_1"
c2s_ciphers: CIPHERS_INTERMEDIATE
c2s_protocol_options: PROTOCOL_OPTIONS_INTERMEDIATE
listen: listen:
- -
port: 5222 port: 5222
@ -64,6 +82,8 @@ listen:
"/ws": ejabberd_http_ws "/ws": ejabberd_http_ws
web_admin: true web_admin: true
captcha: true captcha: true
ciphers: CIPHERS_INTERMEDIATE
protocol_options: PROTOCOL_OPTIONS_INTERMEDIATE
tls: true tls: true
s2s_use_starttls: optional s2s_use_starttls: optional
@ -75,7 +95,6 @@ acl:
ip: ip:
- "127.0.0.0/8" - "127.0.0.0/8"
- "::1/128" - "::1/128"
- "::FFFF:127.0.0.1/128"
access_rules: access_rules:
local: local:

View File

@ -3,7 +3,7 @@ defmodule Ejabberd.Mixfile do
def project do def project do
[app: :ejabberd, [app: :ejabberd,
version: "18.9.0", version: "18.12.0",
description: description(), description: description(),
elixir: "~> 1.4", elixir: "~> 1.4",
elixirc_paths: ["lib"], elixirc_paths: ["lib"],
@ -73,7 +73,7 @@ defmodule Ejabberd.Mixfile do
{:jiffy, "~> 0.14.7"}, {:jiffy, "~> 0.14.7"},
{:p1_oauth2, "~> 0.6.1"}, {:p1_oauth2, "~> 0.6.1"},
{:distillery, "~> 1.0"}, {:distillery, "~> 1.0"},
{:pkix, github: "processone/pkix"}, {:pkix, "~> 1.0"},
{:ex_doc, ">= 0.0.0", only: :dev}, {:ex_doc, ">= 0.0.0", only: :dev},
{:eimp, "~> 1.0"}, {:eimp, "~> 1.0"},
{:base64url, "~> 0.0.1"}, {:base64url, "~> 0.0.1"},

View File

@ -1,15 +1,15 @@
%{ %{
"base64url": {:hex, :base64url, "0.0.1", "36a90125f5948e3afd7be97662a1504b934dd5dac78451ca6e9abf85a10286be", [:rebar], [], "hexpm"}, "base64url": {:hex, :base64url, "0.0.1", "36a90125f5948e3afd7be97662a1504b934dd5dac78451ca6e9abf85a10286be", [:rebar], [], "hexpm"},
"cache_tab": {:hex, :cache_tab, "1.0.16", "0223820e5071d3252b9921db9dcc74a09ec8a660120271fdb47c3c40b6b52bee", [:rebar3], [{:p1_utils, "1.0.13", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"}, "cache_tab": {:hex, :cache_tab, "1.0.17", "0020e1036d7074d83a71be28b329ceb3e7f9d41cc5a8529b06c32ce4d8ee4995", [:rebar3], [{:p1_utils, "1.0.13", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
"distillery": {:hex, :distillery, "1.5.3", "b2f4fc34ec71ab4f1202a796f9290e068883b042319aa8c9aa45377ecac8597a", [:mix], [], "hexpm"}, "distillery": {:hex, :distillery, "1.5.5", "c6132d5c0152bdce6850fb6c942d58f1971b169b6965d908dc4e8767cfa51a95", [:mix], [], "hexpm"},
"earmark": {:hex, :earmark, "1.2.5", "4d21980d5d2862a2e13ec3c49ad9ad783ffc7ca5769cf6ff891a4553fbaae761", [:mix], [], "hexpm"}, "earmark": {:hex, :earmark, "1.3.0", "17f0c38eaafb4800f746b457313af4b2442a8c2405b49c645768680f900be603", [:mix], [], "hexpm"},
"eimp": {:hex, :eimp, "1.0.9", "daf0d2904be3ef5e4128d946e158113cdb4d52555023746d29b83ce86b531f3c", [:rebar3], [{:p1_utils, "1.0.13", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"}, "eimp": {:hex, :eimp, "1.0.9", "daf0d2904be3ef5e4128d946e158113cdb4d52555023746d29b83ce86b531f3c", [:rebar3], [{:p1_utils, "1.0.13", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
"epam": {:hex, :epam, "1.0.4", "2a5e40cbf9b2cf41df515782894c3b33c81b8ad32fff2fc847c3f725071dfaed", [:rebar3], [], "hexpm"}, "epam": {:hex, :epam, "1.0.4", "2a5e40cbf9b2cf41df515782894c3b33c81b8ad32fff2fc847c3f725071dfaed", [:rebar3], [], "hexpm"},
"eredis": {:hex, :eredis, "1.1.0", "8d8d74496f35216679b97726b75fb1c8715e99dd7f3ef9f9824a2264c3e0aac0", [:rebar3], [], "hexpm"}, "eredis": {:hex, :eredis, "1.1.0", "8d8d74496f35216679b97726b75fb1c8715e99dd7f3ef9f9824a2264c3e0aac0", [:rebar3], [], "hexpm"},
"esip": {:hex, :esip, "1.0.26", "b50c92f8ac3e8e8ba901f0a6cc7e0e47fdc832b0f3044eddb6032ca26845cf97", [:rebar3], [{:fast_tls, "1.0.25", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.13", [hex: :p1_utils, repo: "hexpm", optional: false]}, {:stun, "1.0.25", [hex: :stun, repo: "hexpm", optional: false]}], "hexpm"}, "esip": {:hex, :esip, "1.0.27", "13a94542b659a9b3e4e013aedaf2f6a92de53d35945902d693657a67c6955b83", [:rebar3], [{:fast_tls, "1.0.26", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.13", [hex: :p1_utils, repo: "hexpm", optional: false]}, {:stun, "1.0.26", [hex: :stun, repo: "hexpm", optional: false]}], "hexpm"},
"ex_doc": {:hex, :ex_doc, "0.18.3", "f4b0e4a2ec6f333dccf761838a4b253d75e11f714b85ae271c9ae361367897b7", [:mix], [{:earmark, "~> 1.1", [hex: :earmark, repo: "hexpm", optional: false]}], "hexpm"}, "ex_doc": {:hex, :ex_doc, "0.19.1", "519bb9c19526ca51d326c060cb1778d4a9056b190086a8c6c115828eaccea6cf", [:mix], [{:earmark, "~> 1.1", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.7", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"},
"ezlib": {:hex, :ezlib, "1.0.4", "2434e4bb549cb060d5ac02261ba48fbe1a69b2ae4e1bf7485a3b27b3f3ec618d", [:rebar3], [], "hexpm"}, "ezlib": {:hex, :ezlib, "1.0.4", "2434e4bb549cb060d5ac02261ba48fbe1a69b2ae4e1bf7485a3b27b3f3ec618d", [:rebar3], [], "hexpm"},
"fast_tls": {:hex, :fast_tls, "1.0.25", "cbf875fe709d6fd03d3266c920bfe15f4d22736535d73421300cebf9d86bd851", [:rebar3], [{:p1_utils, "1.0.13", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"}, "fast_tls": {:hex, :fast_tls, "1.0.26", "38d78859ca56e8600aca3ef73137582a279a280d71f7581c64a1eddbde38accb", [:rebar3], [{:p1_utils, "1.0.13", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
"fast_xml": {:hex, :fast_xml, "1.1.34", "d76fc639d3607a44c4f0fb2dfdee1067b6c37b02b39706d8f067cb77eb2f6016", [:rebar3], [{:p1_utils, "1.0.13", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"}, "fast_xml": {:hex, :fast_xml, "1.1.34", "d76fc639d3607a44c4f0fb2dfdee1067b6c37b02b39706d8f067cb77eb2f6016", [:rebar3], [{:p1_utils, "1.0.13", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
"fast_yaml": {:hex, :fast_yaml, "1.0.17", "e945ef64e0cb7c311c7b42804dbe32a24e13a2afc0ffe249b7e0f9f9ac08e176", [:rebar3], [{:p1_utils, "1.0.13", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"}, "fast_yaml": {:hex, :fast_yaml, "1.0.17", "e945ef64e0cb7c311c7b42804dbe32a24e13a2afc0ffe249b7e0f9f9ac08e176", [:rebar3], [{:p1_utils, "1.0.13", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
"goldrush": {:hex, :goldrush, "0.1.9", "f06e5d5f1277da5c413e84d5a2924174182fb108dabb39d5ec548b27424cd106", [:rebar3], [], "hexpm"}, "goldrush": {:hex, :goldrush, "0.1.9", "f06e5d5f1277da5c413e84d5a2924174182fb108dabb39d5ec548b27424cd106", [:rebar3], [], "hexpm"},
@ -19,18 +19,21 @@
"jose": {:hex, :jose, "1.8.4", "7946d1e5c03a76ac9ef42a6e6a20001d35987afd68c2107bcd8f01a84e75aa73", [:mix, :rebar3], [{:base64url, "~> 0.0.1", [hex: :base64url, repo: "hexpm", optional: false]}], "hexpm"}, "jose": {:hex, :jose, "1.8.4", "7946d1e5c03a76ac9ef42a6e6a20001d35987afd68c2107bcd8f01a84e75aa73", [:mix, :rebar3], [{:base64url, "~> 0.0.1", [hex: :base64url, repo: "hexpm", optional: false]}], "hexpm"},
"lager": {:hex, :lager, "3.6.7", "2fbf823944caa0fc10df5ec13f3f047524a249bb32f0d801b7900c9610264286", [:rebar3], [{:goldrush, "0.1.9", [hex: :goldrush, repo: "hexpm", optional: false]}], "hexpm"}, "lager": {:hex, :lager, "3.6.7", "2fbf823944caa0fc10df5ec13f3f047524a249bb32f0d801b7900c9610264286", [:rebar3], [{:goldrush, "0.1.9", [hex: :goldrush, repo: "hexpm", optional: false]}], "hexpm"},
"luerl": {:hex, :luerl, "0.3.1", "5412807630aac1aaf59ffe5a1bc09259c447b4faeb1d3fe2d4ef41b87676cb04", [:rebar3], [], "hexpm"}, "luerl": {:hex, :luerl, "0.3.1", "5412807630aac1aaf59ffe5a1bc09259c447b4faeb1d3fe2d4ef41b87676cb04", [:rebar3], [], "hexpm"},
"meck": {:hex, :meck, "0.8.10", "455aaef8403be46752272206613e7a15467c014d40994b22fb54cde4d1ff7075", [:rebar3], [], "hexpm"}, "makeup": {:hex, :makeup, "0.5.5", "9e08dfc45280c5684d771ad58159f718a7b5788596099bdfb0284597d368a882", [:mix], [{:nimble_parsec, "~> 0.4", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"},
"makeup_elixir": {:hex, :makeup_elixir, "0.10.0", "0f09c2ddf352887a956d84f8f7e702111122ca32fbbc84c2f0569b8b65cbf7fa", [:mix], [{:makeup, "~> 0.5.5", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm"},
"meck": {:hex, :meck, "0.8.12", "1f7b1a9f5d12c511848fec26bbefd09a21e1432eadb8982d9a8aceb9891a3cf2", [:rebar3], [], "hexpm"},
"moka": {:git, "https://github.com/processone/moka.git", "3eed3a6dd7dedb70a6cd18f86c7561a18626eb3b", [tag: "1.0.5c"]}, "moka": {:git, "https://github.com/processone/moka.git", "3eed3a6dd7dedb70a6cd18f86c7561a18626eb3b", [tag: "1.0.5c"]},
"p1_mysql": {:hex, :p1_mysql, "1.0.7", "9fbadf8fa283ae8657faa4f6bbe13f2e3b9da0cdcfbc699cfc120d0905282056", [:rebar3], [], "hexpm"}, "nimble_parsec": {:hex, :nimble_parsec, "0.4.0", "ee261bb53214943679422be70f1658fff573c5d0b0a1ecd0f18738944f818efe", [:mix], [], "hexpm"},
"p1_mysql": {:hex, :p1_mysql, "1.0.8", "34ed5fe2f0e16a6ee5805c0c6c1d30ffbc4c5c9753197cdf384ee6e82c57b506", [:rebar3], [], "hexpm"},
"p1_oauth2": {:hex, :p1_oauth2, "0.6.3", "fbd91ba86bd7f03d2a4f6e62affa86bab9930abfd6b473d61eefb148f246cd46", [:rebar3], [], "hexpm"}, "p1_oauth2": {:hex, :p1_oauth2, "0.6.3", "fbd91ba86bd7f03d2a4f6e62affa86bab9930abfd6b473d61eefb148f246cd46", [:rebar3], [], "hexpm"},
"p1_pgsql": {:hex, :p1_pgsql, "1.1.6", "631004602b06ca6f55d759001f180185685c7097e583f3b0f7dd9b8e05ba5db1", [:rebar3], [], "hexpm"}, "p1_pgsql": {:hex, :p1_pgsql, "1.1.6", "631004602b06ca6f55d759001f180185685c7097e583f3b0f7dd9b8e05ba5db1", [:rebar3], [], "hexpm"},
"p1_utils": {:hex, :p1_utils, "1.0.13", "176577cafb54a8c2fdc0a7fc62b9a21ab0f66588f4062792cd9e65f3e500bfdb", [:rebar3], [], "hexpm"}, "p1_utils": {:hex, :p1_utils, "1.0.13", "176577cafb54a8c2fdc0a7fc62b9a21ab0f66588f4062792cd9e65f3e500bfdb", [:rebar3], [], "hexpm"},
"pkix": {:git, "https://github.com/processone/pkix.git", "58856450e84f69c66b28c8807e898a30e1959680", []}, "pkix": {:hex, :pkix, "1.0.0", "d88658eccc30227e929efa91c6ca6a4d2b4d40b4db3635ebd6ed9e246ecfcf82", [:rebar3], [], "hexpm"},
"riak_pb": {:hex, :riak_pb, "2.3.2", "48ffbf66dbb3f136ab9a7134bac4e496754baa5ef58c4f50a61326736d996390", [:make, :mix, :rebar3], [{:hamcrest, "~> 0.4.1", [hex: :basho_hamcrest, repo: "hexpm", optional: false]}], "hexpm"}, "riak_pb": {:hex, :riak_pb, "2.3.2", "48ffbf66dbb3f136ab9a7134bac4e496754baa5ef58c4f50a61326736d996390", [:make, :mix, :rebar3], [{:hamcrest, "~> 0.4.1", [hex: :basho_hamcrest, repo: "hexpm", optional: false]}], "hexpm"},
"riakc": {:hex, :riakc, "2.5.3", "6132d9e687a0dfd314b2b24c4594302ca8b55568a5d733c491d8fb6cd4004763", [:make, :mix, :rebar3], [{:riak_pb, "~> 2.3", [hex: :riak_pb, repo: "hexpm", optional: false]}], "hexpm"}, "riakc": {:hex, :riakc, "2.5.3", "6132d9e687a0dfd314b2b24c4594302ca8b55568a5d733c491d8fb6cd4004763", [:make, :mix, :rebar3], [{:riak_pb, "~> 2.3", [hex: :riak_pb, repo: "hexpm", optional: false]}], "hexpm"},
"samerlib": {:git, "https://github.com/processone/samerlib", "fbbba035b1548ac4e681df00d61bf609645333a0", [tag: "0.8.0c"]}, "samerlib": {:git, "https://github.com/processone/samerlib", "fbbba035b1548ac4e681df00d61bf609645333a0", [tag: "0.8.0c"]},
"sqlite3": {:hex, :sqlite3, "1.1.6", "4ea71af0b45908b5f02c9b09e4c87177039ef404f20accb35049cd8924cc417c", [:rebar3], [], "hexpm"}, "sqlite3": {:hex, :sqlite3, "1.1.6", "4ea71af0b45908b5f02c9b09e4c87177039ef404f20accb35049cd8924cc417c", [:rebar3], [], "hexpm"},
"stringprep": {:hex, :stringprep, "1.0.14", "230a2d1c576bba168749d653fd6681166d02431ef07161a918444f3edb478ad0", [:rebar3], [{:p1_utils, "1.0.13", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"}, "stringprep": {:hex, :stringprep, "1.0.14", "230a2d1c576bba168749d653fd6681166d02431ef07161a918444f3edb478ad0", [:rebar3], [{:p1_utils, "1.0.13", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
"stun": {:hex, :stun, "1.0.25", "e324c94c28d636578db79eb26979cd07140f0dabcdc0d5b197650ba0bc44a31a", [:rebar3], [{:fast_tls, "1.0.25", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.13", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"}, "stun": {:hex, :stun, "1.0.26", "87b05229d0519f0db5c6b67b5c25ed3b79766beb96eba83d29bde4cae9e702e4", [:rebar3], [{:fast_tls, "1.0.26", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.13", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
"xmpp": {:hex, :xmpp, "1.2.5", "98ae86706013e51349e962b67c30293d14672603b5c7d782b2c79b52ceaa659f", [:rebar3], [{:ezlib, "1.0.4", [hex: :ezlib, repo: "hexpm", optional: false]}, {:fast_tls, "1.0.25", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:fast_xml, "1.1.34", [hex: :fast_xml, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.13", [hex: :p1_utils, repo: "hexpm", optional: false]}, {:stringprep, "1.0.14", [hex: :stringprep, repo: "hexpm", optional: false]}], "hexpm"}, "xmpp": {:hex, :xmpp, "1.2.8", "c506ea4c7e4b8d042654d54b080f4b6b4135c93658d7e156968a073c5b5f99a1", [:rebar3], [{:ezlib, "1.0.4", [hex: :ezlib, repo: "hexpm", optional: false]}, {:fast_tls, "1.0.26", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:fast_xml, "1.1.34", [hex: :fast_xml, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.13", [hex: :p1_utils, repo: "hexpm", optional: false]}, {:stringprep, "1.0.14", [hex: :stringprep, repo: "hexpm", optional: false]}], "hexpm"},
} }

View File

@ -20,7 +20,7 @@
{deps, [{lager, ".*", {git, "https://github.com/erlang-lager/lager", "3.6.7"}}, {deps, [{lager, ".*", {git, "https://github.com/erlang-lager/lager", "3.6.7"}},
{p1_utils, ".*", {git, "https://github.com/processone/p1_utils", {tag, "1.0.13"}}}, {p1_utils, ".*", {git, "https://github.com/processone/p1_utils", {tag, "1.0.13"}}},
{cache_tab, ".*", {git, "https://github.com/processone/cache_tab", {tag, "6493974"}}}, {cache_tab, ".*", {git, "https://github.com/processone/cache_tab", {tag, "1.0.17"}}},
{fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.0.26"}}}, {fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.0.26"}}},
{stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.14"}}}, {stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.14"}}},
{fast_xml, ".*", {git, "https://github.com/processone/fast_xml", {tag, "1.1.34"}}}, {fast_xml, ".*", {git, "https://github.com/processone/fast_xml", {tag, "1.1.34"}}},
@ -28,9 +28,9 @@
{fast_yaml, ".*", {git, "https://github.com/processone/fast_yaml", {tag, "1.0.17"}}}, {fast_yaml, ".*", {git, "https://github.com/processone/fast_yaml", {tag, "1.0.17"}}},
{jiffy, ".*", {git, "https://github.com/davisp/jiffy", {tag, "0.14.8"}}}, {jiffy, ".*", {git, "https://github.com/davisp/jiffy", {tag, "0.14.8"}}},
{p1_oauth2, ".*", {git, "https://github.com/processone/p1_oauth2", {tag, "0.6.3"}}}, {p1_oauth2, ".*", {git, "https://github.com/processone/p1_oauth2", {tag, "0.6.3"}}},
{pkix, ".*", {git, "https://github.com/processone/pkix"}}, {pkix, ".*", {git, "https://github.com/processone/pkix", {tag, "1.0.0"}}},
{jose, ".*", {git, "https://github.com/potatosalad/erlang-jose", {tag, "1.8.4"}}}, {jose, ".*", {git, "https://github.com/potatosalad/erlang-jose", {tag, "1.8.4"}}},
{eimp, ".*", {git, "https://github.com/processone/eimp", {tag, "1.0.8"}}}, {eimp, ".*", {git, "https://github.com/processone/eimp", {tag, "1.0.9"}}},
{if_var_true, stun, {stun, ".*", {git, "https://github.com/processone/stun", {tag, "1.0.26"}}}}, {if_var_true, stun, {stun, ".*", {git, "https://github.com/processone/stun", {tag, "1.0.26"}}}},
{if_var_true, sip, {esip, ".*", {git, "https://github.com/processone/esip", {tag, "1.0.27"}}}}, {if_var_true, sip, {esip, ".*", {git, "https://github.com/processone/esip", {tag, "1.0.27"}}}},
{if_var_true, mysql, {p1_mysql, ".*", {git, "https://github.com/processone/p1_mysql", {if_var_true, mysql, {p1_mysql, ".*", {git, "https://github.com/processone/p1_mysql",
@ -76,6 +76,7 @@
epam, epam,
ezlib, ezlib,
eimp, eimp,
pkix,
iconv]}}. iconv]}}.
{erl_first_files, ["src/ejabberd_sql_pt.erl", "src/ejabberd_config.erl", {erl_first_files, ["src/ejabberd_sql_pt.erl", "src/ejabberd_config.erl",

View File

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

View File

@ -41,7 +41,8 @@
get_password_s/2, get_password_with_authmodule/2, get_password_s/2, get_password_with_authmodule/2,
user_exists/2, user_exists_in_other_modules/3, user_exists/2, user_exists_in_other_modules/3,
remove_user/2, remove_user/3, plain_password_required/1, remove_user/2, remove_user/3, plain_password_required/1,
store_type/1, entropy/1, backend_type/1, password_format/1]). store_type/1, entropy/1, backend_type/1, password_format/1,
which_users_exists/1]).
%% gen_server callbacks %% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, -export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]). terminate/2, code_change/3]).
@ -411,6 +412,47 @@ user_exists_in_other_modules_loop([AuthModule | AuthModules], User, Server) ->
maybe maybe
end. end.
-spec which_users_exists(list({binary(), binary()})) -> list({binary(), binary()}).
which_users_exists(USPairs) ->
ByServer = lists:foldl(
fun({User, Server}, Dict) ->
LServer = jid:nameprep(Server),
LUser = jid:nodeprep(User),
case gb_trees:lookup(LServer, Dict) of
none ->
gb_trees:insert(LServer, gb_sets:singleton(LUser), Dict);
{value, Set} ->
gb_trees:update(LServer, gb_sets:add(LUser, Set), Dict)
end
end, gb_trees:empty(), USPairs),
Set = lists:foldl(
fun({LServer, UsersSet}, Results) ->
UsersList = gb_sets:to_list(UsersSet),
lists:foldl(
fun(M, Results2) ->
try M:which_users_exists(LServer, UsersList) of
{error, _} ->
Results2;
Res ->
gb_sets:union(
gb_sets:from_list([{U, LServer} || U <- Res]),
Results2)
catch
_:undef ->
lists:foldl(
fun(U, R2) ->
case user_exists(U, LServer) of
true ->
gb_sets:add({U, LServer}, R2);
_ ->
R2
end
end, Results2, UsersList)
end
end, Results, auth_modules(LServer))
end, gb_sets:empty(), gb_trees:to_list(ByServer)),
gb_sets:to_list(Set).
-spec remove_user(binary(), binary()) -> ok. -spec remove_user(binary(), binary()) -> ok.
remove_user(User, Server) -> remove_user(User, Server) ->
case validate_credentials(User, Server) of case validate_credentials(User, Server) of

View File

@ -35,7 +35,7 @@
-export([start/1, stop/1, set_password/3, try_register/3, -export([start/1, stop/1, set_password/3, try_register/3,
get_users/2, count_users/2, get_password/2, get_users/2, count_users/2, get_password/2,
remove_user/2, store_type/1, plain_password_required/1, remove_user/2, store_type/1, plain_password_required/1,
convert_to_scram/1, opt_type/1, export/1]). convert_to_scram/1, opt_type/1, export/1, which_users_exists/2]).
-include("scram.hrl"). -include("scram.hrl").
-include("logger.hrl"). -include("logger.hrl").
@ -247,6 +247,32 @@ users_number(LServer, [{prefix, Prefix}])
users_number(LServer, []) -> users_number(LServer, []) ->
users_number(LServer). users_number(LServer).
which_users_exists(LServer, LUsers) when length(LUsers) =< 100 ->
try ejabberd_sql:sql_query(
LServer,
?SQL("select @(username)s from users where username in %(LUsers)ls")) of
{selected, Matching} ->
[U || {U} <- Matching];
{error, _} = E ->
E
catch _:B ->
{error, B}
end;
which_users_exists(LServer, LUsers) ->
{First, Rest} = lists:split(100, LUsers),
case which_users_exists(LServer, First) of
{error, _} = E ->
E;
V ->
case which_users_exists(LServer, Rest) of
{error, _} = E2 ->
E2;
V2 ->
V ++ V2
end
end.
convert_to_scram(Server) -> convert_to_scram(Server) ->
LServer = jid:nameprep(Server), LServer = jid:nameprep(Server),
if if

View File

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

View File

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

View File

@ -69,7 +69,8 @@
default_host, default_host,
custom_headers, custom_headers,
trail = <<>>, trail = <<>>,
addr_re addr_re,
sock_peer_name = none
}). }).
-define(XHTML_DOCTYPE, -define(XHTML_DOCTYPE,
@ -143,6 +144,7 @@ init({SockMod, Socket}, Opts) ->
true -> [{[], ejabberd_xmlrpc}]; true -> [{[], ejabberd_xmlrpc}];
false -> [] false -> []
end, end,
SockPeer = proplists:get_value(sock_peer_name, Opts, none),
DefinedHandlers = proplists:get_value(request_handlers, Opts, []), DefinedHandlers = proplists:get_value(request_handlers, Opts, []),
RequestHandlers = DefinedHandlers ++ Captcha ++ Register ++ RequestHandlers = DefinedHandlers ++ Captcha ++ Register ++
Admin ++ Bind ++ XMLRPC, Admin ++ Bind ++ XMLRPC,
@ -159,6 +161,7 @@ init({SockMod, Socket}, Opts) ->
custom_headers = CustomHeaders, custom_headers = CustomHeaders,
options = Opts, options = Opts,
request_handlers = RequestHandlers, request_handlers = RequestHandlers,
sock_peer_name = SockPeer,
addr_re = RE}, addr_re = RE},
try receive_headers(State) of try receive_headers(State) of
V -> V V -> V
@ -463,6 +466,7 @@ process_request(#state{request_method = Method,
request_version = Version, request_version = Version,
sockmod = SockMod, sockmod = SockMod,
socket = Socket, socket = Socket,
sock_peer_name = SockPeer,
options = Options, options = Options,
request_host = Host, request_host = Host,
request_port = Port, request_port = Port,
@ -481,12 +485,16 @@ process_request(#state{request_method = Method,
{State2, false} -> {State2, false} ->
{State2, make_bad_request(State)}; {State2, make_bad_request(State)};
{State2, {LPath, LQuery, Data}} -> {State2, {LPath, LQuery, Data}} ->
PeerName = PeerName = case SockPeer of
none ->
case SockMod of case SockMod of
gen_tcp -> gen_tcp ->
inet:peername(Socket); inet:peername(Socket);
_ -> _ ->
SockMod:peername(Socket) SockMod:peername(Socket)
end;
{_, Peer} ->
{ok, Peer}
end, end,
IPHere = case PeerName of IPHere = case PeerName of
{ok, V} -> V; {ok, V} -> V;

View File

@ -204,6 +204,28 @@ accept(ListenSocket, Module, Opts, Sup, Interval) ->
NewInterval = check_rate_limit(Interval), NewInterval = check_rate_limit(Interval),
case gen_tcp:accept(ListenSocket) of case gen_tcp:accept(ListenSocket) of
{ok, Socket} -> {ok, Socket} ->
case proplists:get_value(use_proxy_protocol, Opts, false) of
true ->
case proxy_protocol:decode(gen_tcp, Socket, 10000) of
{error, Err} ->
?ERROR_MSG("(~w) Proxy protocol parsing failed: ~s",
[ListenSocket, inet:format_error(Err)]),
gen_tcp:close(Socket);
{{Addr, Port}, {PAddr, PPort}} = SP ->
Opts2 = [{sock_peer_name, SP} | Opts],
Receiver = case start_connection(Module, Socket, Opts2, Sup) of
{ok, RecvPid} ->
RecvPid;
_ ->
gen_tcp:close(Socket),
none
end,
?INFO_MSG("(~p) Accepted proxied connection ~s:~p -> ~s:~p",
[Receiver,
ejabberd_config:may_hide_data(inet_parse:ntoa(PAddr)),
PPort, inet_parse:ntoa(Addr), Port])
end;
_ ->
case {inet:sockname(Socket), inet:peername(Socket)} of case {inet:sockname(Socket), inet:peername(Socket)} of
{{ok, {Addr, Port}}, {ok, {PAddr, PPort}}} -> {{ok, {Addr, Port}}, {ok, {PAddr, PPort}}} ->
Receiver = case start_connection(Module, Socket, Opts, Sup) of Receiver = case start_connection(Module, Socket, Opts, Sup) of
@ -219,6 +241,7 @@ accept(ListenSocket, Module, Opts, Sup, Interval) ->
PPort, inet_parse:ntoa(Addr), Port]); PPort, inet_parse:ntoa(Addr), Port]);
_ -> _ ->
gen_tcp:close(Socket) gen_tcp:close(Socket)
end
end, end,
accept(ListenSocket, Module, Opts, Sup, NewInterval); accept(ListenSocket, Module, Opts, Sup, NewInterval);
{error, Reason} -> {error, Reason} ->
@ -665,7 +688,9 @@ listen_opt_type(max_fsm_queue) ->
listen_opt_type(shaper) -> listen_opt_type(shaper) ->
fun acl:shaper_rules_validator/1; fun acl:shaper_rules_validator/1;
listen_opt_type(access) -> listen_opt_type(access) ->
fun acl:access_rules_validator/1. fun acl:access_rules_validator/1;
listen_opt_type(use_proxy_protocol) ->
fun(B) when is_boolean(B) -> B end.
listen_options() -> listen_options() ->
[module, port, [module, port,
@ -675,6 +700,7 @@ listen_options() ->
{inet6, false}, {inet6, false},
{accept_interval, 0}, {accept_interval, 0},
{backlog, 5}, {backlog, 5},
{use_proxy_protocol, false},
{supervisor, true}]. {supervisor, true}].
opt_type(listen) -> fun validate_cfg/1; opt_type(listen) -> fun validate_cfg/1;

View File

@ -48,8 +48,8 @@
disconnect_removed_user/2, disconnect_removed_user/2,
get_user_resources/2, get_user_resources/2,
get_user_present_resources/2, get_user_present_resources/2,
set_presence/7, set_presence/6,
unset_presence/6, unset_presence/5,
close_session_unset_presence/5, close_session_unset_presence/5,
dirty_get_sessions_list/0, dirty_get_sessions_list/0,
dirty_get_my_sessions_list/0, dirty_get_my_sessions_list/0,
@ -316,26 +316,48 @@ del_user_info(User, Server, Resource, Key) ->
end. end.
-spec set_presence(sid(), binary(), binary(), binary(), -spec set_presence(sid(), binary(), binary(), binary(),
prio(), presence(), info()) -> ok. prio(), presence()) -> ok | {error, notfound}.
set_presence(SID, User, Server, Resource, Priority, set_presence(SID, User, Server, Resource, Priority, Presence) ->
Presence, Info) -> LUser = jid:nodeprep(User),
set_session(SID, User, Server, Resource, Priority, LServer = jid:nameprep(Server),
Info), LResource = jid:resourceprep(Resource),
Mod = get_sm_backend(LServer),
case get_sessions(Mod, LUser, LServer, LResource) of
[] -> {error, notfound};
Ss ->
case lists:keyfind(SID, 1, Ss) of
#session{info = Info} ->
set_session(SID, User, Server, Resource, Priority, Info),
ejabberd_hooks:run(set_presence_hook, ejabberd_hooks:run(set_presence_hook,
jid:nameprep(Server), LServer,
[User, Server, Resource, Presence]). [User, Server, Resource, Presence]);
false ->
{error, notfound}
end
end.
-spec unset_presence(sid(), binary(), binary(), -spec unset_presence(sid(), binary(), binary(),
binary(), binary(), info()) -> ok. binary(), binary()) -> ok | {error, notfound}.
unset_presence(SID, User, Server, Resource, Status, unset_presence(SID, User, Server, Resource, Status) ->
Info) -> LUser = jid:nodeprep(User),
set_session(SID, User, Server, Resource, undefined, LServer = jid:nameprep(Server),
Info), LResource = jid:resourceprep(Resource),
Mod = get_sm_backend(LServer),
case get_sessions(Mod, LUser, LServer, LResource) of
[] -> {error, notfound};
Ss ->
case lists:keyfind(SID, 1, Ss) of
#session{info = Info} ->
set_session(SID, User, Server, Resource, undefined, Info),
ejabberd_hooks:run(unset_presence_hook, ejabberd_hooks:run(unset_presence_hook,
jid:nameprep(Server), LServer,
[User, Server, Resource, Status]). [User, Server, Resource, Status]);
false ->
{error, notfound}
end
end.
-spec close_session_unset_presence(sid(), binary(), binary(), -spec close_session_unset_presence(sid(), binary(), binary(),
binary(), binary()) -> ok. binary(), binary()) -> ok.

View File

@ -55,7 +55,8 @@
freetds_config/0, freetds_config/0,
odbcinst_config/0, odbcinst_config/0,
init_mssql/1, init_mssql/1,
keep_alive/2]). keep_alive/2,
to_list/2]).
%% gen_fsm callbacks %% gen_fsm callbacks
-export([init/1, handle_event/3, handle_sync_event/4, -export([init/1, handle_event/3, handle_sync_event/4,
@ -258,6 +259,10 @@ to_bool(true) -> true;
to_bool(1) -> true; to_bool(1) -> true;
to_bool(_) -> false. to_bool(_) -> false.
to_list(EscapeFun, Val) ->
Escaped = lists:join(<<",">>, lists:map(EscapeFun, Val)),
[<<"(">>, Escaped, <<")">>].
encode_term(Term) -> encode_term(Term) ->
escape(list_to_binary( escape(list_to_binary(
erl_prettypr:format(erl_syntax:abstract(Term), erl_prettypr:format(erl_syntax:abstract(Term),

View File

@ -306,6 +306,20 @@ parse1([$%, $( | S], Acc, State) ->
false -> false ->
append_string("0=0", State3) append_string("0=0", State3)
end; end;
{list, InternalType} ->
Convert = erl_syntax:application(
erl_syntax:atom(ejabberd_sql),
erl_syntax:atom(to_list),
[erl_syntax:record_access(
erl_syntax:variable(?ESCAPE_VAR),
erl_syntax:atom(?ESCAPE_RECORD),
erl_syntax:atom(InternalType)),
erl_syntax:variable(Name)]),
State2#state{'query' = [{var, Var} | State2#state.'query'],
args = [Convert | State2#state.args],
params = [Var | State2#state.params],
param_pos = State2#state.param_pos + 1,
used_vars = [Name | State2#state.used_vars]};
_ -> _ ->
Convert = Convert =
erl_syntax:application( erl_syntax:application(
@ -335,6 +349,19 @@ parse_name(S, IsArg, State) ->
parse_name([], _Acc, _Depth, _IsArg, State) -> parse_name([], _Acc, _Depth, _IsArg, State) ->
throw({error, State#state.loc, throw({error, State#state.loc,
"expected ')', found end of string"}); "expected ')', found end of string"});
parse_name([$), $l, T | S], Acc, 0, true, State) ->
Type = case T of
$d -> {list, integer};
$s -> {list, string};
$b -> {list, boolean};
_ ->
throw({error, State#state.loc,
["unknown type specifier 'l", T, "'"]})
end,
{lists:reverse(Acc), Type, S, State};
parse_name([$), $l, T | _], _Acc, 0, false, State) ->
throw({error, State#state.loc,
["list type 'l", T, "' is not allowed for outputs"]});
parse_name([$), T | S], Acc, 0, IsArg, State) -> parse_name([$), T | S], Acc, 0, IsArg, State) ->
Type = Type =
case T of case T of

View File

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

View File

@ -325,15 +325,20 @@ handle2(Call, Auth, Args, Version) when is_atom(Call), is_list(Args) ->
format_command_result(Call, Auth, Res, Version) format_command_result(Call, Auth, Res, Version)
end. end.
get_elem_delete(A, L) -> get_elem_delete(A, L, F) ->
case proplists:get_all_values(A, L) of case proplists:get_all_values(A, L) of
[Value] -> {Value, proplists:delete(A, L)}; [Value] -> {Value, proplists:delete(A, L)};
[_, _ | _] -> [_, _ | _] ->
%% Crash reporting the error %% Crash reporting the error
exit({duplicated_attribute, A, L}); exit({duplicated_attribute, A, L});
[] -> [] ->
case F of
{list, _} ->
{[], L};
_ ->
%% Report the error and then force a crash %% Report the error and then force a crash
exit({attribute_not_found, A, L}) exit({attribute_not_found, A, L})
end
end. end.
format_args(Args, ArgsFormat) -> format_args(Args, ArgsFormat) ->
@ -342,7 +347,7 @@ format_args(Args, ArgsFormat) ->
{Args1, Res}) -> {Args1, Res}) ->
{ArgValue, Args2} = {ArgValue, Args2} =
get_elem_delete(ArgName, get_elem_delete(ArgName,
Args1), Args1, ArgFormat),
Formatted = format_arg(ArgValue, Formatted = format_arg(ArgValue,
ArgFormat), ArgFormat),
{Args2, Res ++ [Formatted]} {Args2, Res ++ [Formatted]}
@ -471,6 +476,9 @@ format_result(Code, {Name, restuple}) ->
format_result(Els, {Name, {list, {_, {tuple, [{_, atom}, _]}} = Fmt}}) -> format_result(Els, {Name, {list, {_, {tuple, [{_, atom}, _]}} = Fmt}}) ->
{misc:atom_to_binary(Name), {[format_result(El, Fmt) || El <- Els]}}; {misc:atom_to_binary(Name), {[format_result(El, Fmt) || El <- Els]}};
format_result(Els, {Name, {list, {_, {tuple, [{name, string}, {value, _}]}} = Fmt}}) ->
{misc:atom_to_binary(Name), {[format_result(El, Fmt) || El <- Els]}};
format_result(Els, {Name, {list, Def}}) -> format_result(Els, {Name, {list, Def}}) ->
{misc:atom_to_binary(Name), [element(2, format_result(El, Def)) || El <- Els]}; {misc:atom_to_binary(Name), [element(2, format_result(El, Def)) || El <- Els]};
@ -479,6 +487,11 @@ format_result(Tuple, {_Name, {tuple, [{_, atom}, ValFmt]}}) ->
{_, Val2} = format_result(Val, ValFmt), {_, Val2} = format_result(Val, ValFmt),
{misc:atom_to_binary(Name2), Val2}; {misc:atom_to_binary(Name2), Val2};
format_result(Tuple, {_Name, {tuple, [{name, string}, {value, _} = ValFmt]}}) ->
{Name2, Val} = Tuple,
{_, Val2} = format_result(Val, ValFmt),
{iolist_to_binary(Name2), Val2};
format_result(Tuple, {Name, {tuple, Def}}) -> format_result(Tuple, {Name, {tuple, Def}}) ->
Els = lists:zip(tuple_to_list(Tuple), Def), Els = lists:zip(tuple_to_list(Tuple), Def),
{misc:atom_to_binary(Name), {[format_result(El, ElDef) || {El, ElDef} <- Els]}}; {misc:atom_to_binary(Name), {[format_result(El, ElDef) || {El, ElDef} <- Els]}};

View File

@ -90,8 +90,17 @@ remove_expired_messages(_LServer) ->
remove_old_messages(Days, LServer) -> remove_old_messages(Days, LServer) ->
case ejabberd_sql:sql_query( case ejabberd_sql:sql_query(
LServer, LServer,
fun(pgsql, _) ->
ejabberd_sql:sql_query_t(
?SQL("DELETE FROM spool" ?SQL("DELETE FROM spool"
" WHERE created_at < NOW() - INTERVAL %(Days)d DAY")) of " WHERE created_at <"
" NOW() - INTERVAL '%(Days)d DAY'"));
(_, _) ->
ejabberd_sql:sql_query_t(
?SQL("DELETE FROM spool"
" WHERE created_at < NOW() - INTERVAL %(Days)d DAY"))
end)
of
{updated, N} -> {updated, N} ->
?INFO_MSG("~p message(s) deleted from offline spool", [N]); ?INFO_MSG("~p message(s) deleted from offline spool", [N]);
_Error -> _Error ->

View File

@ -37,9 +37,12 @@
import/5, import_start/2, mod_opt_type/1, set_data/2, import/5, import_start/2, mod_opt_type/1, set_data/2,
mod_options/1, depends/2, get_sm_features/5, pubsub_publish_item/6]). mod_options/1, depends/2, get_sm_features/5, pubsub_publish_item/6]).
-export([get_commands_spec/0, bookmarks_to_pep/2]).
-include("logger.hrl"). -include("logger.hrl").
-include("xmpp.hrl"). -include("xmpp.hrl").
-include("mod_private.hrl"). -include("mod_private.hrl").
-include("ejabberd_commands.hrl").
-define(PRIVATE_CACHE, private_cache). -define(PRIVATE_CACHE, private_cache).
@ -61,13 +64,20 @@ start(Host, Opts) ->
ejabberd_hooks:add(remove_user, Host, ?MODULE, remove_user, 50), ejabberd_hooks:add(remove_user, Host, ?MODULE, remove_user, 50),
ejabberd_hooks:add(disco_sm_features, Host, ?MODULE, get_sm_features, 50), ejabberd_hooks:add(disco_sm_features, Host, ?MODULE, get_sm_features, 50),
ejabberd_hooks:add(pubsub_publish_item, Host, ?MODULE, pubsub_publish_item, 50), ejabberd_hooks:add(pubsub_publish_item, Host, ?MODULE, pubsub_publish_item, 50),
gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_PRIVATE, ?MODULE, process_sm_iq). gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_PRIVATE, ?MODULE, process_sm_iq),
ejabberd_commands:register_commands(get_commands_spec()).
stop(Host) -> stop(Host) ->
ejabberd_hooks:delete(remove_user, Host, ?MODULE, remove_user, 50), ejabberd_hooks:delete(remove_user, Host, ?MODULE, remove_user, 50),
ejabberd_hooks:delete(disco_sm_features, Host, ?MODULE, get_sm_features, 50), ejabberd_hooks:delete(disco_sm_features, Host, ?MODULE, get_sm_features, 50),
ejabberd_hooks:delete(pubsub_publish_item, Host, ?MODULE, pubsub_publish_item, 50), ejabberd_hooks:delete(pubsub_publish_item, Host, ?MODULE, pubsub_publish_item, 50),
gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_PRIVATE). gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_PRIVATE),
case gen_mod:is_loaded_elsewhere(Host, ?MODULE) of
false ->
ejabberd_commands:unregister_commands(get_commands_spec());
true ->
ok
end.
reload(Host, NewOpts, OldOpts) -> reload(Host, NewOpts, OldOpts) ->
NewMod = gen_mod:db_mod(Host, NewOpts, ?MODULE), NewMod = gen_mod:db_mod(Host, NewOpts, ?MODULE),
@ -264,6 +274,50 @@ pubsub_publish_item(LServer, ?NS_STORAGE_BOOKMARKS,
pubsub_publish_item(_, _, _, _, _, _) -> pubsub_publish_item(_, _, _, _, _, _) ->
ok. ok.
%%%===================================================================
%%% Commands
%%%===================================================================
-spec get_commands_spec() -> [ejabberd_commands()].
get_commands_spec() ->
[#ejabberd_commands{name = bookmarks_to_pep, tags = [private],
desc = "Export private XML storage bookmarks to PEP",
module = ?MODULE, function = bookmarks_to_pep,
args = [{user, binary}, {server, binary}],
args_desc = ["Username", "Server"],
args_example = [<<"bob">>, <<"example.com">>],
result = {res, restuple},
result_desc = "Result tuple",
result_example = {ok, <<"Bookmarks exported">>}}].
-spec bookmarks_to_pep(binary(), binary())
-> {ok, binary()} | {error, binary()}.
bookmarks_to_pep(User, Server) ->
LUser = jid:nodeprep(User),
LServer = jid:nameprep(Server),
Mod = gen_mod:db_mod(LServer, ?MODULE),
Res = case use_cache(Mod, LServer) of
true ->
ets_cache:lookup(
?PRIVATE_CACHE, {LUser, LServer, ?NS_STORAGE_BOOKMARKS},
fun() ->
Mod:get_data(LUser, LServer, ?NS_STORAGE_BOOKMARKS)
end);
false ->
Mod:get_data(LUser, LServer, ?NS_STORAGE_BOOKMARKS)
end,
case Res of
{ok, El} ->
Data = [{?NS_STORAGE_BOOKMARKS, El}],
case publish_data(jid:make(User, Server), Data) of
ok ->
{ok, <<"Bookmarks exported to PEP node">>};
{error, Err} ->
{error, xmpp:format_stanza_error(Err)}
end;
_ ->
{error, <<"Cannot retrieve bookmarks from private XML storage">>}
end.
%%%=================================================================== %%%===================================================================
%%% Cache %%% Cache
%%%=================================================================== %%%===================================================================

View File

@ -2990,6 +2990,7 @@ send_last_pep(From, To) ->
Host = host(ServerHost), Host = host(ServerHost),
Publisher = jid:tolower(From), Publisher = jid:tolower(From),
Owner = jid:remove_resource(Publisher), Owner = jid:remove_resource(Publisher),
RecipientIsOwner = jid:remove_resource(jid:tolower(To)) == Owner,
lists:foreach( lists:foreach(
fun(#pubsub_node{nodeid = {_, Node}, type = Type, id = Nidx, options = Options}) -> fun(#pubsub_node{nodeid = {_, Node}, type = Type, id = Nidx, options = Options}) ->
case match_option(Options, send_last_published_item, on_sub_and_presence) of case match_option(Options, send_last_published_item, on_sub_and_presence) of
@ -2998,8 +2999,11 @@ send_last_pep(From, To) ->
Subscribed = case get_option(Options, access_model) of Subscribed = case get_option(Options, access_model) of
open -> true; open -> true;
presence -> true; presence -> true;
whitelist -> false; % subscribers are added manually %% TODO: Fix the 'whitelist'/'authorize'
authorize -> false; % likewise %% cases. Currently, only node owners
%% receive last PEP notifications.
whitelist -> RecipientIsOwner;
authorize -> RecipientIsOwner;
roster -> roster ->
Grps = get_option(Options, roster_groups_allowed, []), Grps = get_option(Options, roster_groups_allowed, []),
{OU, OS, _} = Owner, {OU, OS, _} = Owner,

184
src/proxy_protocol.erl Normal file
View File

@ -0,0 +1,184 @@
%%%----------------------------------------------------------------------
%%% File : ejabberd_http.erl
%%% Author : Paweł Chmielowski <pawel@process-one.net>
%%% Purpose :
%%% Created : 27 Nov 2018 by Paweł Chmielowski <pawel@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2018 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
%%% published by the Free Software Foundation; either version 2 of the
%%% License, or (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License along
%%% with this program; if not, write to the Free Software Foundation, Inc.,
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
%%%
%%%----------------------------------------------------------------------
-module(proxy_protocol).
-author("pawel@process-one.net").
%% API
-export([decode/3]).
decode(SockMod, Socket, Timeout) ->
V = SockMod:recv(Socket, 6, Timeout),
case V of
{ok, <<"PROXY ">>} ->
decode_v1(SockMod, Socket, Timeout);
{ok, <<16#0d, 16#0a, 16#0d, 16#0a, 16#00, 16#0d>>} ->
decode_v2(SockMod, Socket, Timeout);
_ ->
{error, eproto}
end.
decode_v1(SockMod, Socket, Timeout) ->
case read_until_rn(SockMod, Socket, <<>>, false, Timeout) of
{error, _} = Err ->
Err;
Val ->
case binary:split(Val, <<" ">>, [global]) of
[<<"TCP4">>, SAddr, DAddr, SPort, DPort] ->
try {inet_parse:ipv4strict_address(binary_to_list(SAddr)),
inet_parse:ipv4strict_address(binary_to_list(DAddr)),
binary_to_integer(SPort),
binary_to_integer(DPort)}
of
{{ok, DA}, {ok, SA}, DP, SP} ->
{{SA, SP}, {DA, DP}};
_ ->
{error, eproto}
catch
error:badarg ->
{error, eproto}
end;
[<<"TCP6">>, SAddr, DAddr, SPort, DPort] ->
try {inet_parse:ipv6strict_address(binary_to_list(SAddr)),
inet_parse:ipv6strict_address(binary_to_list(DAddr)),
binary_to_integer(SPort),
binary_to_integer(DPort)}
of
{{ok, DA}, {ok, SA}, DP, SP} ->
{{SA, SP}, {DA, DP}};
_ ->
{error, eproto}
catch
error:badarg ->
{error, eproto}
end;
[<<"UNKNOWN">> | _] ->
{undefined, undefined}
end
end.
decode_v2(SockMod, Socket, Timeout) ->
case SockMod:recv(Socket, 10, Timeout) of
{error, _} = Err ->
Err;
{ok, <<16#0a, 16#51, 16#55, 16#49, 16#54, 16#0a,
2:4, Command:4, Transport:8, AddrLen:16/big-unsigned-integer>>} ->
case SockMod:recv(Socket, AddrLen, Timeout) of
{error, _} = Err ->
Err;
{ok, Data} ->
case Command of
0 ->
case {inet:sockname(Socket), inet:peername(Socket)} of
{{ok, SA}, {ok, DA}} ->
{SA, DA};
{{error, _} = E, _} ->
E;
{_, {error, _} = E} ->
E
end;
1 ->
case Transport of
% UNSPEC or UNIX
V when V == 0; V == 16#31; V == 16#32 ->
{{unknown, unknown}, {unknown, unknown}};
% IPV4 over TCP or UDP
V when V == 16#11; V == 16#12 ->
case Data of
<<D1:8, D2:8, D3:8, D4:8,
S1:8, S2:8, S3:8, S4:8,
DP:16/big-unsigned-integer,
SP:16/big-unsigned-integer,
_/binary>> ->
{{{S1, S2, S3, S4}, SP},
{{D1, D2, D3, D4}, DP}};
_ ->
{error, eproto}
end;
% IPV6 over TCP or UDP
V when V == 16#21; V == 16#22 ->
case Data of
<<D1:16/big-unsigned-integer,
D2:16/big-unsigned-integer,
D3:16/big-unsigned-integer,
D4:16/big-unsigned-integer,
D5:16/big-unsigned-integer,
D6:16/big-unsigned-integer,
D7:16/big-unsigned-integer,
D8:16/big-unsigned-integer,
S1:16/big-unsigned-integer,
S2:16/big-unsigned-integer,
S3:16/big-unsigned-integer,
S4:16/big-unsigned-integer,
S5:16/big-unsigned-integer,
S6:16/big-unsigned-integer,
S7:16/big-unsigned-integer,
S8:16/big-unsigned-integer,
DP:16/big-unsigned-integer,
SP:16/big-unsigned-integer,
_/binary>> ->
{{{S1, S2, S3, S4, S5, S6, S7, S8}, SP},
{{D1, D2, D3, D4, D5, D6, D7, D8}, DP}};
_ ->
{error, eproto}
end
end;
_ ->
{error, eproto}
end
end;
<<16#0a, 16#51, 16#55, 16#49, 16#54, 16#0a, _/binary>> ->
{error, eproto};
_ ->
{error, eproto}
end.
read_until_rn(_SockMod, _Socket, Data, _, _) when size(Data) > 107 ->
{error, eproto};
read_until_rn(SockMod, Socket, Data, true, Timeout) ->
case SockMod:recv(Socket, 1, Timeout) of
{ok, <<"\n">>} ->
Data;
{ok, <<"\r">>} ->
read_until_rn(SockMod, Socket, <<Data/binary, "\r">>,
true, Timeout);
{ok, Other} ->
read_until_rn(SockMod, Socket, <<Data/binary, "\r", Other/binary>>,
false, Timeout);
{error, _} = Err ->
Err
end;
read_until_rn(SockMod, Socket, Data, false, Timeout) ->
case SockMod:recv(Socket, 2, Timeout) of
{ok, <<"\r\n">>} ->
Data;
{ok, <<Byte:8, "\r">>} ->
read_until_rn(SockMod, Socket, <<Data/binary, Byte:8>>,
true, Timeout);
{ok, Other} ->
read_until_rn(SockMod, Socket, <<Data/binary, Other/binary>>,
false, Timeout);
{error, _} = Err ->
Err
end.