mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-26 16:26:24 +01:00
Merge branch 'master' into mix
This commit is contained in:
commit
74e8c0376f
10
CHANGELOG.md
Normal file
10
CHANGELOG.md
Normal 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)
|
@ -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
|
@ -3,7 +3,7 @@
|
||||
|
||||
AC_PREREQ(2.53)
|
||||
AC_INIT(ejabberd, m4_esyscmd([echo `git describe --tags 2>/dev/null || echo 0.0` | sed 's/-g.*//;s/-/./' | tr -d '\012']), [ejabberd@process-one.net], [ejabberd])
|
||||
REQUIRE_ERLANG_MIN="6.4 (Erlang/OTP 17.5)"
|
||||
REQUIRE_ERLANG_MIN="8.0 (Erlang/OTP 19.0)"
|
||||
REQUIRE_ERLANG_MAX="100.0.0 (No Max)"
|
||||
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
|
@ -39,6 +39,24 @@ certfiles:
|
||||
- "/etc/letsencrypt/live/localhost/fullchain.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:
|
||||
-
|
||||
port: 5222
|
||||
@ -64,6 +82,8 @@ listen:
|
||||
"/ws": ejabberd_http_ws
|
||||
web_admin: true
|
||||
captcha: true
|
||||
ciphers: CIPHERS_INTERMEDIATE
|
||||
protocol_options: PROTOCOL_OPTIONS_INTERMEDIATE
|
||||
tls: true
|
||||
|
||||
s2s_use_starttls: optional
|
||||
@ -75,7 +95,6 @@ acl:
|
||||
ip:
|
||||
- "127.0.0.0/8"
|
||||
- "::1/128"
|
||||
- "::FFFF:127.0.0.1/128"
|
||||
|
||||
access_rules:
|
||||
local:
|
||||
|
4
mix.exs
4
mix.exs
@ -3,7 +3,7 @@ defmodule Ejabberd.Mixfile do
|
||||
|
||||
def project do
|
||||
[app: :ejabberd,
|
||||
version: "18.9.0",
|
||||
version: "18.12.0",
|
||||
description: description(),
|
||||
elixir: "~> 1.4",
|
||||
elixirc_paths: ["lib"],
|
||||
@ -73,7 +73,7 @@ defmodule Ejabberd.Mixfile do
|
||||
{:jiffy, "~> 0.14.7"},
|
||||
{:p1_oauth2, "~> 0.6.1"},
|
||||
{:distillery, "~> 1.0"},
|
||||
{:pkix, github: "processone/pkix"},
|
||||
{:pkix, "~> 1.0"},
|
||||
{:ex_doc, ">= 0.0.0", only: :dev},
|
||||
{:eimp, "~> 1.0"},
|
||||
{:base64url, "~> 0.0.1"},
|
||||
|
25
mix.lock
25
mix.lock
@ -1,15 +1,15 @@
|
||||
%{
|
||||
"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"},
|
||||
"distillery": {:hex, :distillery, "1.5.3", "b2f4fc34ec71ab4f1202a796f9290e068883b042319aa8c9aa45377ecac8597a", [:mix], [], "hexpm"},
|
||||
"earmark": {:hex, :earmark, "1.2.5", "4d21980d5d2862a2e13ec3c49ad9ad783ffc7ca5769cf6ff891a4553fbaae761", [:mix], [], "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.5", "c6132d5c0152bdce6850fb6c942d58f1971b169b6965d908dc4e8767cfa51a95", [: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"},
|
||||
"epam": {:hex, :epam, "1.0.4", "2a5e40cbf9b2cf41df515782894c3b33c81b8ad32fff2fc847c3f725071dfaed", [: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"},
|
||||
"ex_doc": {:hex, :ex_doc, "0.18.3", "f4b0e4a2ec6f333dccf761838a4b253d75e11f714b85ae271c9ae361367897b7", [:mix], [{:earmark, "~> 1.1", [hex: :earmark, 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.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"},
|
||||
"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_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"},
|
||||
@ -19,18 +19,21 @@
|
||||
"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"},
|
||||
"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"]},
|
||||
"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_pgsql": {:hex, :p1_pgsql, "1.1.6", "631004602b06ca6f55d759001f180185685c7097e583f3b0f7dd9b8e05ba5db1", [: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"},
|
||||
"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"]},
|
||||
"sqlite3": {:hex, :sqlite3, "1.1.6", "4ea71af0b45908b5f02c9b09e4c87177039ef404f20accb35049cd8924cc417c", [:rebar3], [], "hexpm"},
|
||||
"stringprep": {:hex, :stringprep, "1.0.14", "230a2d1c576bba168749d653fd6681166d02431ef07161a918444f3edb478ad0", [:rebar3], [{:p1_utils, "1.0.13", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
|
||||
"stun": {:hex, :stun, "1.0.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"},
|
||||
"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"},
|
||||
"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.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"},
|
||||
}
|
||||
|
@ -20,7 +20,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"}}},
|
||||
{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"}}},
|
||||
{stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.14"}}},
|
||||
{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"}}},
|
||||
{jiffy, ".*", {git, "https://github.com/davisp/jiffy", {tag, "0.14.8"}}},
|
||||
{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"}}},
|
||||
{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, 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",
|
||||
@ -76,6 +76,7 @@
|
||||
epam,
|
||||
ezlib,
|
||||
eimp,
|
||||
pkix,
|
||||
iconv]}}.
|
||||
|
||||
{erl_first_files, ["src/ejabberd_sql_pt.erl", "src/ejabberd_config.erl",
|
||||
|
@ -152,10 +152,10 @@ start_apps() ->
|
||||
crypto:start(),
|
||||
ejabberd:start_app(sasl),
|
||||
ejabberd:start_app(ssl),
|
||||
ejabberd:start_app(pkix),
|
||||
ejabberd:start_app(p1_utils),
|
||||
ejabberd:start_app(fast_yaml),
|
||||
ejabberd:start_app(fast_tls),
|
||||
ejabberd:start_app(pkix),
|
||||
ejabberd:start_app(xmpp),
|
||||
ejabberd:start_app(cache_tab),
|
||||
ejabberd:start_app(eimp).
|
||||
|
@ -41,7 +41,8 @@
|
||||
get_password_s/2, get_password_with_authmodule/2,
|
||||
user_exists/2, user_exists_in_other_modules/3,
|
||||
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
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||
terminate/2, code_change/3]).
|
||||
@ -411,6 +412,47 @@ user_exists_in_other_modules_loop([AuthModule | AuthModules], User, Server) ->
|
||||
maybe
|
||||
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.
|
||||
remove_user(User, Server) ->
|
||||
case validate_credentials(User, Server) of
|
||||
|
@ -35,7 +35,7 @@
|
||||
-export([start/1, stop/1, set_password/3, try_register/3,
|
||||
get_users/2, count_users/2, get_password/2,
|
||||
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("logger.hrl").
|
||||
@ -247,6 +247,32 @@ users_number(LServer, [{prefix, Prefix}])
|
||||
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) ->
|
||||
LServer = jid:nameprep(Server),
|
||||
if
|
||||
|
@ -708,13 +708,11 @@ process_presence_out(#{lserver := LServer, jid := JID,
|
||||
end.
|
||||
|
||||
-spec process_self_presence(state(), presence()) -> state().
|
||||
process_self_presence(#{ip := IP, conn := Conn, lserver := LServer,
|
||||
auth_module := AuthMod, sid := SID,
|
||||
process_self_presence(#{lserver := LServer, sid := SID,
|
||||
user := U, server := S, resource := R} = State,
|
||||
#presence{type = unavailable} = Pres) ->
|
||||
Status = xmpp:get_text(Pres#presence.status),
|
||||
Info = [{ip, IP}, {conn, Conn}, {auth_module, AuthMod}],
|
||||
ejabberd_sm:unset_presence(SID, U, S, R, Status, Info),
|
||||
ejabberd_sm:unset_presence(SID, U, S, R, Status),
|
||||
{Pres1, State1} = ejabberd_hooks:run_fold(
|
||||
c2s_self_presence, LServer, {Pres, State}, []),
|
||||
State2 = broadcast_presence_unavailable(State1, Pres1),
|
||||
@ -732,13 +730,11 @@ process_self_presence(#{lserver := LServer} = State,
|
||||
process_self_presence(State, _Pres) ->
|
||||
State.
|
||||
|
||||
-spec update_priority(state(), presence()) -> ok.
|
||||
update_priority(#{ip := IP, conn := Conn, auth_module := AuthMod,
|
||||
sid := SID, user := U, server := S, resource := R},
|
||||
-spec update_priority(state(), presence()) -> ok | {error, notfound}.
|
||||
update_priority(#{sid := SID, user := U, server := S, resource := R},
|
||||
Pres) ->
|
||||
Priority = get_priority_from_presence(Pres),
|
||||
Info = [{ip, IP}, {conn, Conn}, {auth_module, AuthMod}],
|
||||
ejabberd_sm:set_presence(SID, U, S, R, Priority, Pres, Info).
|
||||
ejabberd_sm:set_presence(SID, U, S, R, Priority, Pres).
|
||||
|
||||
-spec broadcast_presence_unavailable(state(), presence()) -> state().
|
||||
broadcast_presence_unavailable(#{jid := JID, pres_a := PresA} = State, Pres) ->
|
||||
|
@ -500,7 +500,8 @@ get_config_option_key(Name, Val) ->
|
||||
|
||||
maps_to_lists(IMap) ->
|
||||
maps:fold(fun(Name, Map, Res) when Name == host_config orelse Name == append_host_config ->
|
||||
[{Name, [{Host, maps_to_lists(SMap)} || {Host,SMap} <- maps:values(Map)]} | Res];
|
||||
[{Name, [{jid:nameprep(Host), maps_to_lists(SMap)} ||
|
||||
{Host,SMap} <- maps:values(Map)]} | Res];
|
||||
(Name, Map, Res) when is_map(Map) ->
|
||||
[{Name, maps:values(Map)} | Res];
|
||||
(Name, Val, Res) ->
|
||||
@ -513,8 +514,9 @@ merge_configs(Terms, ResMap) ->
|
||||
New = lists:foldl(fun(SVal, OMap) ->
|
||||
NVal = if Name == host_config orelse Name == append_host_config ->
|
||||
{Host, Opts} = SVal,
|
||||
{_, SubMap} = maps:get(Host, OMap, {Host, #{}}),
|
||||
{Host, merge_configs(Opts, SubMap)};
|
||||
HostNP = jid:nameprep(Host),
|
||||
{_, SubMap} = maps:get(HostNP, OMap, {HostNP, #{}}),
|
||||
{HostNP, merge_configs(Opts, SubMap)};
|
||||
true ->
|
||||
SVal
|
||||
end,
|
||||
|
@ -69,7 +69,8 @@
|
||||
default_host,
|
||||
custom_headers,
|
||||
trail = <<>>,
|
||||
addr_re
|
||||
addr_re,
|
||||
sock_peer_name = none
|
||||
}).
|
||||
|
||||
-define(XHTML_DOCTYPE,
|
||||
@ -143,6 +144,7 @@ init({SockMod, Socket}, Opts) ->
|
||||
true -> [{[], ejabberd_xmlrpc}];
|
||||
false -> []
|
||||
end,
|
||||
SockPeer = proplists:get_value(sock_peer_name, Opts, none),
|
||||
DefinedHandlers = proplists:get_value(request_handlers, Opts, []),
|
||||
RequestHandlers = DefinedHandlers ++ Captcha ++ Register ++
|
||||
Admin ++ Bind ++ XMLRPC,
|
||||
@ -159,6 +161,7 @@ init({SockMod, Socket}, Opts) ->
|
||||
custom_headers = CustomHeaders,
|
||||
options = Opts,
|
||||
request_handlers = RequestHandlers,
|
||||
sock_peer_name = SockPeer,
|
||||
addr_re = RE},
|
||||
try receive_headers(State) of
|
||||
V -> V
|
||||
@ -463,6 +466,7 @@ process_request(#state{request_method = Method,
|
||||
request_version = Version,
|
||||
sockmod = SockMod,
|
||||
socket = Socket,
|
||||
sock_peer_name = SockPeer,
|
||||
options = Options,
|
||||
request_host = Host,
|
||||
request_port = Port,
|
||||
@ -481,12 +485,16 @@ process_request(#state{request_method = Method,
|
||||
{State2, false} ->
|
||||
{State2, make_bad_request(State)};
|
||||
{State2, {LPath, LQuery, Data}} ->
|
||||
PeerName =
|
||||
PeerName = case SockPeer of
|
||||
none ->
|
||||
case SockMod of
|
||||
gen_tcp ->
|
||||
inet:peername(Socket);
|
||||
_ ->
|
||||
SockMod:peername(Socket)
|
||||
end;
|
||||
{_, Peer} ->
|
||||
{ok, Peer}
|
||||
end,
|
||||
IPHere = case PeerName of
|
||||
{ok, V} -> V;
|
||||
|
@ -204,6 +204,28 @@ accept(ListenSocket, Module, Opts, Sup, Interval) ->
|
||||
NewInterval = check_rate_limit(Interval),
|
||||
case gen_tcp:accept(ListenSocket) of
|
||||
{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
|
||||
{{ok, {Addr, Port}}, {ok, {PAddr, PPort}}} ->
|
||||
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]);
|
||||
_ ->
|
||||
gen_tcp:close(Socket)
|
||||
end
|
||||
end,
|
||||
accept(ListenSocket, Module, Opts, Sup, NewInterval);
|
||||
{error, Reason} ->
|
||||
@ -665,7 +688,9 @@ listen_opt_type(max_fsm_queue) ->
|
||||
listen_opt_type(shaper) ->
|
||||
fun acl:shaper_rules_validator/1;
|
||||
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() ->
|
||||
[module, port,
|
||||
@ -675,6 +700,7 @@ listen_options() ->
|
||||
{inet6, false},
|
||||
{accept_interval, 0},
|
||||
{backlog, 5},
|
||||
{use_proxy_protocol, false},
|
||||
{supervisor, true}].
|
||||
|
||||
opt_type(listen) -> fun validate_cfg/1;
|
||||
|
@ -48,8 +48,8 @@
|
||||
disconnect_removed_user/2,
|
||||
get_user_resources/2,
|
||||
get_user_present_resources/2,
|
||||
set_presence/7,
|
||||
unset_presence/6,
|
||||
set_presence/6,
|
||||
unset_presence/5,
|
||||
close_session_unset_presence/5,
|
||||
dirty_get_sessions_list/0,
|
||||
dirty_get_my_sessions_list/0,
|
||||
@ -316,26 +316,48 @@ del_user_info(User, Server, Resource, Key) ->
|
||||
end.
|
||||
|
||||
-spec set_presence(sid(), binary(), binary(), binary(),
|
||||
prio(), presence(), info()) -> ok.
|
||||
prio(), presence()) -> ok | {error, notfound}.
|
||||
|
||||
set_presence(SID, User, Server, Resource, Priority,
|
||||
Presence, Info) ->
|
||||
set_session(SID, User, Server, Resource, Priority,
|
||||
Info),
|
||||
set_presence(SID, User, Server, Resource, Priority, Presence) ->
|
||||
LUser = jid:nodeprep(User),
|
||||
LServer = jid:nameprep(Server),
|
||||
LResource = jid:resourceprep(Resource),
|
||||
Mod = get_sm_backend(LServer),
|
||||
case get_sessions(Mod, LUser, LServer, LResource) of
|
||||
[] -> {error, notfound};
|
||||
Ss ->
|
||||
case lists:keyfind(SID, 1, Ss) of
|
||||
#session{info = Info} ->
|
||||
set_session(SID, User, Server, Resource, Priority, Info),
|
||||
ejabberd_hooks:run(set_presence_hook,
|
||||
jid:nameprep(Server),
|
||||
[User, Server, Resource, Presence]).
|
||||
LServer,
|
||||
[User, Server, Resource, Presence]);
|
||||
false ->
|
||||
{error, notfound}
|
||||
end
|
||||
end.
|
||||
|
||||
-spec unset_presence(sid(), binary(), binary(),
|
||||
binary(), binary(), info()) -> ok.
|
||||
binary(), binary()) -> ok | {error, notfound}.
|
||||
|
||||
unset_presence(SID, User, Server, Resource, Status,
|
||||
Info) ->
|
||||
set_session(SID, User, Server, Resource, undefined,
|
||||
Info),
|
||||
unset_presence(SID, User, Server, Resource, Status) ->
|
||||
LUser = jid:nodeprep(User),
|
||||
LServer = jid:nameprep(Server),
|
||||
LResource = jid:resourceprep(Resource),
|
||||
Mod = get_sm_backend(LServer),
|
||||
case get_sessions(Mod, LUser, LServer, LResource) of
|
||||
[] -> {error, notfound};
|
||||
Ss ->
|
||||
case lists:keyfind(SID, 1, Ss) of
|
||||
#session{info = Info} ->
|
||||
set_session(SID, User, Server, Resource, undefined, Info),
|
||||
ejabberd_hooks:run(unset_presence_hook,
|
||||
jid:nameprep(Server),
|
||||
[User, Server, Resource, Status]).
|
||||
LServer,
|
||||
[User, Server, Resource, Status]);
|
||||
false ->
|
||||
{error, notfound}
|
||||
end
|
||||
end.
|
||||
|
||||
-spec close_session_unset_presence(sid(), binary(), binary(),
|
||||
binary(), binary()) -> ok.
|
||||
|
@ -55,7 +55,8 @@
|
||||
freetds_config/0,
|
||||
odbcinst_config/0,
|
||||
init_mssql/1,
|
||||
keep_alive/2]).
|
||||
keep_alive/2,
|
||||
to_list/2]).
|
||||
|
||||
%% gen_fsm callbacks
|
||||
-export([init/1, handle_event/3, handle_sync_event/4,
|
||||
@ -258,6 +259,10 @@ to_bool(true) -> true;
|
||||
to_bool(1) -> true;
|
||||
to_bool(_) -> false.
|
||||
|
||||
to_list(EscapeFun, Val) ->
|
||||
Escaped = lists:join(<<",">>, lists:map(EscapeFun, Val)),
|
||||
[<<"(">>, Escaped, <<")">>].
|
||||
|
||||
encode_term(Term) ->
|
||||
escape(list_to_binary(
|
||||
erl_prettypr:format(erl_syntax:abstract(Term),
|
||||
|
@ -306,6 +306,20 @@ parse1([$%, $( | S], Acc, State) ->
|
||||
false ->
|
||||
append_string("0=0", State3)
|
||||
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 =
|
||||
erl_syntax:application(
|
||||
@ -335,6 +349,19 @@ parse_name(S, IsArg, State) ->
|
||||
parse_name([], _Acc, _Depth, _IsArg, State) ->
|
||||
throw({error, State#state.loc,
|
||||
"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) ->
|
||||
Type =
|
||||
case T of
|
||||
|
@ -38,6 +38,7 @@
|
||||
iq_handler/1, disco_features/5,
|
||||
is_carbon_copy/1, mod_opt_type/1, depends/2,
|
||||
mod_options/1]).
|
||||
-export([c2s_copy_session/2, c2s_session_opened/1, c2s_session_resumed/1]).
|
||||
%% For debugging purposes
|
||||
-export([list/2]).
|
||||
|
||||
@ -45,6 +46,7 @@
|
||||
-include("xmpp.hrl").
|
||||
|
||||
-type direction() :: sent | received.
|
||||
-type c2s_state() :: ejabberd_c2s:state().
|
||||
|
||||
-spec is_carbon_copy(stanza()) -> boolean().
|
||||
is_carbon_copy(#message{meta = #{carbon_copy := true}}) ->
|
||||
@ -57,6 +59,9 @@ start(Host, _Opts) ->
|
||||
%% why priority 89: to define clearly that we must run BEFORE mod_logdb hook (90)
|
||||
ejabberd_hooks:add(user_send_packet,Host, ?MODULE, user_send_packet, 89),
|
||||
ejabberd_hooks:add(user_receive_packet,Host, ?MODULE, user_receive_packet, 89),
|
||||
ejabberd_hooks:add(c2s_copy_session, Host, ?MODULE, c2s_copy_session, 50),
|
||||
ejabberd_hooks:add(c2s_session_resumed, Host, ?MODULE, c2s_session_resumed, 50),
|
||||
ejabberd_hooks:add(c2s_session_opened, Host, ?MODULE, c2s_session_opened, 50),
|
||||
gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_CARBONS_2, ?MODULE, iq_handler).
|
||||
|
||||
stop(Host) ->
|
||||
@ -64,7 +69,10 @@ stop(Host) ->
|
||||
ejabberd_hooks:delete(disco_local_features, Host, ?MODULE, disco_features, 50),
|
||||
%% why priority 89: to define clearly that we must run BEFORE mod_logdb hook (90)
|
||||
ejabberd_hooks:delete(user_send_packet,Host, ?MODULE, user_send_packet, 89),
|
||||
ejabberd_hooks:delete(user_receive_packet,Host, ?MODULE, user_receive_packet, 89).
|
||||
ejabberd_hooks:delete(user_receive_packet,Host, ?MODULE, user_receive_packet, 89),
|
||||
ejabberd_hooks:delete(c2s_copy_session, Host, ?MODULE, c2s_copy_session, 50),
|
||||
ejabberd_hooks:delete(c2s_session_resumed, Host, ?MODULE, c2s_session_resumed, 50),
|
||||
ejabberd_hooks:delete(c2s_session_opened, Host, ?MODULE, c2s_session_opened, 50).
|
||||
|
||||
reload(_Host, _NewOpts, _OldOpts) ->
|
||||
ok.
|
||||
@ -123,6 +131,29 @@ user_receive_packet({Packet, #{jid := JID} = C2SState}) ->
|
||||
Pkt -> {Pkt, C2SState}
|
||||
end.
|
||||
|
||||
-spec c2s_copy_session(c2s_state(), c2s_state()) -> c2s_state().
|
||||
c2s_copy_session(State, #{user := U, server := S, resource := R}) ->
|
||||
case ejabberd_sm:get_user_info(U, S, R) of
|
||||
offline -> State;
|
||||
Info ->
|
||||
case lists:keyfind(carboncopy, 1, Info) of
|
||||
{_, CC} -> State#{carboncopy => CC};
|
||||
false -> State
|
||||
end
|
||||
end.
|
||||
|
||||
-spec c2s_session_resumed(c2s_state()) -> c2s_state().
|
||||
c2s_session_resumed(#{user := U, server := S, resource := R,
|
||||
carboncopy := CC} = State) ->
|
||||
ejabberd_sm:set_user_info(U, S, R, carboncopy, CC),
|
||||
maps:remove(carboncopy, State);
|
||||
c2s_session_resumed(State) ->
|
||||
State.
|
||||
|
||||
-spec c2s_session_opened(c2s_state()) -> c2s_state().
|
||||
c2s_session_opened(State) ->
|
||||
maps:remove(carboncopy, State).
|
||||
|
||||
% Modified from original version:
|
||||
% - registered to the user_send_packet hook, to be called only once even for multicast
|
||||
% - do not support "private" message mode, and do not modify the original packet in any way
|
||||
|
@ -325,15 +325,20 @@ handle2(Call, Auth, Args, Version) when is_atom(Call), is_list(Args) ->
|
||||
format_command_result(Call, Auth, Res, Version)
|
||||
end.
|
||||
|
||||
get_elem_delete(A, L) ->
|
||||
get_elem_delete(A, L, F) ->
|
||||
case proplists:get_all_values(A, L) of
|
||||
[Value] -> {Value, proplists:delete(A, L)};
|
||||
[_, _ | _] ->
|
||||
%% Crash reporting the error
|
||||
exit({duplicated_attribute, A, L});
|
||||
[] ->
|
||||
case F of
|
||||
{list, _} ->
|
||||
{[], L};
|
||||
_ ->
|
||||
%% Report the error and then force a crash
|
||||
exit({attribute_not_found, A, L})
|
||||
end
|
||||
end.
|
||||
|
||||
format_args(Args, ArgsFormat) ->
|
||||
@ -342,7 +347,7 @@ format_args(Args, ArgsFormat) ->
|
||||
{Args1, Res}) ->
|
||||
{ArgValue, Args2} =
|
||||
get_elem_delete(ArgName,
|
||||
Args1),
|
||||
Args1, ArgFormat),
|
||||
Formatted = format_arg(ArgValue,
|
||||
ArgFormat),
|
||||
{Args2, Res ++ [Formatted]}
|
||||
@ -471,6 +476,9 @@ format_result(Code, {Name, restuple}) ->
|
||||
format_result(Els, {Name, {list, {_, {tuple, [{_, atom}, _]}} = Fmt}}) ->
|
||||
{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}}) ->
|
||||
{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),
|
||||
{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}}) ->
|
||||
Els = lists:zip(tuple_to_list(Tuple), Def),
|
||||
{misc:atom_to_binary(Name), {[format_result(El, ElDef) || {El, ElDef} <- Els]}};
|
||||
|
@ -90,8 +90,17 @@ remove_expired_messages(_LServer) ->
|
||||
remove_old_messages(Days, LServer) ->
|
||||
case ejabberd_sql:sql_query(
|
||||
LServer,
|
||||
fun(pgsql, _) ->
|
||||
ejabberd_sql:sql_query_t(
|
||||
?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} ->
|
||||
?INFO_MSG("~p message(s) deleted from offline spool", [N]);
|
||||
_Error ->
|
||||
|
@ -37,9 +37,12 @@
|
||||
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]).
|
||||
|
||||
-export([get_commands_spec/0, bookmarks_to_pep/2]).
|
||||
|
||||
-include("logger.hrl").
|
||||
-include("xmpp.hrl").
|
||||
-include("mod_private.hrl").
|
||||
-include("ejabberd_commands.hrl").
|
||||
|
||||
-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(disco_sm_features, Host, ?MODULE, get_sm_features, 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) ->
|
||||
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(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) ->
|
||||
NewMod = gen_mod:db_mod(Host, NewOpts, ?MODULE),
|
||||
@ -264,6 +274,50 @@ pubsub_publish_item(LServer, ?NS_STORAGE_BOOKMARKS,
|
||||
pubsub_publish_item(_, _, _, _, _, _) ->
|
||||
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
|
||||
%%%===================================================================
|
||||
|
@ -2990,6 +2990,7 @@ send_last_pep(From, To) ->
|
||||
Host = host(ServerHost),
|
||||
Publisher = jid:tolower(From),
|
||||
Owner = jid:remove_resource(Publisher),
|
||||
RecipientIsOwner = jid:remove_resource(jid:tolower(To)) == Owner,
|
||||
lists:foreach(
|
||||
fun(#pubsub_node{nodeid = {_, Node}, type = Type, id = Nidx, options = Options}) ->
|
||||
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
|
||||
open -> true;
|
||||
presence -> true;
|
||||
whitelist -> false; % subscribers are added manually
|
||||
authorize -> false; % likewise
|
||||
%% TODO: Fix the 'whitelist'/'authorize'
|
||||
%% cases. Currently, only node owners
|
||||
%% receive last PEP notifications.
|
||||
whitelist -> RecipientIsOwner;
|
||||
authorize -> RecipientIsOwner;
|
||||
roster ->
|
||||
Grps = get_option(Options, roster_groups_allowed, []),
|
||||
{OU, OS, _} = Owner,
|
||||
|
184
src/proxy_protocol.erl
Normal file
184
src/proxy_protocol.erl
Normal 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.
|
Loading…
Reference in New Issue
Block a user