diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index dc310ab..0000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: Test - -on: - pull_request: - branches: dev - push: - branches: dev - -jobs: - test: - runs-on: ubuntu-latest - - steps: - - name: Checkout repository and submodules - uses: actions/checkout@v2 - with: - submodules: recursive - - - name: install python3-venv - run: sudo apt-get install python3-venv - - - name: build test image - run: docker build . -t prosody - - - name: run tests - run: cd ./tests/ && ./test.bash diff --git a/.gitignore b/.gitignore index 9f0f847..07f43b8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1 @@ -data/* -tests/certs/ -tests/venv/ -tests/__pycache__/ +data/* \ No newline at end of file diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 4608d8c..0000000 --- a/.gitmodules +++ /dev/null @@ -1,9 +0,0 @@ -[submodule "tests/bats/bats-support"] - path = tests/bats/bats-support - url = https://github.com/bats-core/bats-support.git -[submodule "tests/bats/bats-core"] - path = tests/bats/bats-core - url = https://github.com/bats-core/bats-core.git -[submodule "tests/bats/bats-assert"] - path = tests/bats/bats-assert - url = https://github.com/bats-core/bats-assert.git diff --git a/CHANGELOG.md b/CHANGELOG.md index ea1e879..a2ebbb2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,127 +2,7 @@ ## Unreleased -### Adjust config - -* Replace deprecated legacy_ssl with c2s_direct_tls. -* Removed use_libevent = true. This means the default is now used which is epoll. - -### Test - -Added a test to check that no deprecated config settings are used. - -## v1.3.0 - -* Updated to Prosody version [0.12.4](https://blog.prosody.im/prosody-0.12.4-released/) - -### Breaking Change - -Switched from [http_upload](https://modules.prosody.im/mod_http_upload) to [http_file_share](https://prosody.im/doc/modules/mod_http_file_share). -This means that previous uploads will NOT work after upgrading. -ENV variable `HTTP_UPLOAD_FILE_SIZE_LIMIT` was removed. - -The new module uses the following variables: - -* HTTP_FILE_SHARE_SIZE_LIMIT -* HTTP_FILE_SHARE_DAILY_QUOTA - -See [readme.md](readme.md) for explanations and defaults. - -## v1.2.10 - -* Update docker base image to debian bookworm -* [Add LDAP authentication support](https://github.com/SaraSmiseth/prosody/pull/50) -* Add environment variable HTTP_MAX_CONTENT_SIZE for setting http_max_content_size. -* Add environment variable HTTP_UPLOAD_FILE_SIZE_LIMIT for setting http_upload_file_size_limit. -* Add domain_http_upload to disco_items to support http_upload on some clients and if http_upload is not a subdomain. - -## v1.2.9 - -* Update prosody to version 0.12.3 -* Update luarocks to version 3.9.2 - -## v1.2.8 - -* Updated to Prosody version [0.12.1](https://blog.prosody.im/prosody-0.12.1-released/). - -## v1.2.7 - -* Updated to Prosody version [0.12.0](https://blog.prosody.im/prosody-0.12.0-released/). -* Updated luarocks to version 3.9.0. - -## v1.2.6 - -* Updated to Prosody version [0.11.13](https://blog.prosody.im/prosody-0.11.13-released/). - -## v1.2.5 - -* Updated to Prosody version [0.11.12](https://blog.prosody.im/prosody-0.11.12-released/). - -## v1.2.4 - -* Updated to Prosody version [0.11.11](https://blog.prosody.im/prosody-0.11.11-released/). -* Updated luarocks to version 3.8.0. - -## v1.2.3 - -* Updated to Prosody version [0.11.10](https://blog.prosody.im/prosody-0.11.10-released/). - -## v1.2.2 - -- Update debian from buster-slim to bullseye-slim (#27) - -## v1.2.1 - -* Updated to Prosody version [0.11.9](https://blog.prosody.im/prosody-0.11.9-released/). - -## v1.2.0 - -### New features - -* New environment variables for database settings. It is now possible to use MariaDB or Postgres instead of SQLite. SQLite is the default. See [README](https://github.com/SaraSmiseth/prosody#environment-variables). - -### Updates - -* Updated luarocks to version 3.7.0. - -## v1.1.4 - -### Updates - -* Updated to Prosody version [0.11.8](https://blog.prosody.im/prosody-0.11.8-released/). -* Updated luarocks to version 3.5.0. - -## v1.1.3 - -### New features - -* Set pidfile in prosody.cfg.lua. -* Created a tests folder which contains pytest and bats tests. - -### Bug fixes - -* Fixed using list ENV variables with multiple values. - -## v1.1.2 - -### Updates - -* Updated to Prosody version [0.11.7](https://blog.prosody.im/prosody-0.11.7-released/). -* Updated luarocks to version 3.4.0. - -### New features - -* Made 04-server_contact_info.cfg.lua configurable with ENV variables. Fixes [#4](https://github.com/SaraSmiseth/prosody/issues/4). -* Made 03-e2e-policy.cfg.lua configurable with ENV variables. Fixes [#9](https://github.com/SaraSmiseth/prosody/issues/9). -* Added E2E_POLICY_WHITELIST ENV variable to configure e2e_policy_whitelist. Fixes [#10](https://github.com/SaraSmiseth/prosody/issues/10). - -### Bug fixes - -* Cherry picked [commit](https://github.com/zipizap/prosody/commit/fa13a990a1b87745ae5f5fe8297cb0669f9e8779) from [zipizap/prosody](https://github.com/zipizap/prosody) which fixes a bug with env-vars not beeing initialized. - -### Other changes - -* Changed hashing of downloaded packages in Dockerfile to sha256. +* Nothing yet ## v1.1.1 diff --git a/Dockerfile b/Dockerfile index 22c805b..fe52a34 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,56 +1,32 @@ -FROM debian:bookworm-slim - -ARG BUILD_DATE -ARG VCS_REF -ARG VERSION - -ARG LUAROCKS_VERSION=3.11.1 -ARG PROSODY_VERSION=0.12.5 - -ARG LUAROCKS_SHA256="c3fb3d960dffb2b2fe9de7e3cb004dc4d0b34bb3d342578af84f84325c669102" -ARG PROSODY_DOWNLOAD_SHA256="778fb7707a0f10399595ba7ab9c66dd2a2288c0ae3a7fe4ab78f97d462bd399f" - -LABEL luarocks.version="${LUAROCKS_VERSION}" -LABEL org.opencontainers.image.authors="Sara Smiseth" -LABEL org.opencontainers.image.created="${BUILD_DATE}" -LABEL org.opencontainers.image.description="This docker image provides you with a configured Prosody XMPP server." -LABEL org.opencontainers.image.documentation="https://github.com/SaraSmiseth/prosody/blob/dev/readme.md" -LABEL org.opencontainers.image.revision="${VCS_REF}" -LABEL org.opencontainers.image.source="https://github.com/SaraSmiseth/prosody/archive/dev.zip" -LABEL org.opencontainers.image.title="prosody" -LABEL org.opencontainers.image.url="https://github.com/SaraSmiseth/prosody" -LABEL org.opencontainers.image.vendor="Sara Smiseth" -LABEL org.opencontainers.image.version="${VERSION}" -LABEL prosody.version="${PROSODY_VERSION}" +FROM debian:buster-slim RUN apt-get update \ && DEBIAN_FRONTEND=noninteractive apt-get install -y \ libevent-dev `# this is no build dependency, but needed for luaevent` \ - libicu72 \ - libidn2-0 \ - libpq-dev \ - libsqlite3-0 \ + libidn11 \ lua5.2 \ lua-bitop \ - lua-dbi-mysql \ - lua-dbi-postgresql \ lua-expat \ lua-filesystem \ - lua-ldap \ lua-socket \ lua-sec \ - lua-unbound \ + sqlite3 \ wget \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* -RUN buildDeps='gcc git libc6-dev libidn2-dev liblua5.2-dev libsqlite3-dev libssl-dev libicu-dev make unzip' \ +ENV PROSODY_VERSION 0.11.6 +ENV PROSODY_DOWNLOAD_URL https://prosody.im/downloads/source/prosody-${PROSODY_VERSION}.tar.gz +ENV PROSODY_DOWNLOAD_SHA1 3c24f3faf7735c570213da74eba6343c3afdf50d +ENV LUAROCKS_VERSION 3.3.1 + +RUN buildDeps='gcc git libc6-dev libidn11-dev liblua5.2-dev libsqlite3-dev libssl-dev make unzip' \ && set -x \ && apt-get update && apt-get install -y $buildDeps --no-install-recommends \ && rm -rf /var/lib/apt/lists/* \ \ - && wget -O prosody.tar.gz "https://prosody.im/downloads/source/prosody-${PROSODY_VERSION}.tar.gz" \ - && echo "${PROSODY_DOWNLOAD_SHA256} *prosody.tar.gz" | sha256sum -c - \ + && wget -O prosody.tar.gz "${PROSODY_DOWNLOAD_URL}" \ + && echo "${PROSODY_DOWNLOAD_SHA1} *prosody.tar.gz" | sha1sum -c - \ && mkdir -p /usr/src/prosody \ && tar -xzf prosody.tar.gz -C /usr/src/prosody --strip-components=1 \ && rm prosody.tar.gz \ @@ -62,7 +38,6 @@ RUN buildDeps='gcc git libc6-dev libidn2-dev liblua5.2-dev libsqlite3-dev libssl && mkdir /usr/src/luarocks \ && cd /usr/src/luarocks \ && wget https://luarocks.org/releases/luarocks-${LUAROCKS_VERSION}.tar.gz \ - && echo "${LUAROCKS_SHA256} luarocks-${LUAROCKS_VERSION}.tar.gz" | sha256sum -c - \ && tar zxpf luarocks-${LUAROCKS_VERSION}.tar.gz \ && cd luarocks-${LUAROCKS_VERSION} \ && ./configure \ @@ -71,9 +46,7 @@ RUN buildDeps='gcc git libc6-dev libidn2-dev liblua5.2-dev libsqlite3-dev libssl \ && luarocks install luaevent \ && luarocks install luadbi \ - `#&& luarocks install luadbi-mysql MYSQL_INCDIR=/usr/include/mariadb/` \ && luarocks install luadbi-sqlite3 \ - && luarocks install stringy \ \ && apt-get purge -y --auto-remove $buildDeps @@ -83,31 +56,33 @@ RUN groupadd -r prosody \ && useradd -r -g prosody prosody \ && chown prosody:prosody /usr/local/var/lib/prosody -RUN mkdir -p /var/run/prosody/ \ - && chown prosody:prosody /var/run/prosody/ - # https://github.com/prosody/prosody-docker/issues/25 -ENV __FLUSH_LOG=yes +ENV __FLUSH_LOG yes VOLUME ["/usr/local/var/lib/prosody"] COPY prosody.cfg.lua /usr/local/etc/prosody/prosody.cfg.lua -COPY docker-entrypoint.bash /entrypoint.bash +COPY docker-entrypoint.sh /entrypoint.sh COPY conf.d/*.cfg.lua /usr/local/etc/prosody/conf.d/ COPY *.bash /usr/local/bin/ RUN download-prosody-modules.bash \ && docker-prosody-module-install.bash \ + bookmarks `# XEP-0411: Bookmarks Conversion` \ + carbons `# message carbons (XEP-0280)` \ cloud_notify `# XEP-0357: Push Notifications` \ + csi `# client state indication (XEP-0352)` \ e2e_policy `# require end-2-end encryption` \ filter_chatstates `# disable "X is typing" type messages` \ + smacks `# stream management (XEP-0198)` \ throttle_presence `# presence throttling in CSI` \ + http_upload `# file sharing (XEP-0363)` \ vcard_muc `# XEP-0153: vCard-Based Avatar (MUC)` \ && rm -rf "/usr/src/prosody-modules" USER prosody -ENTRYPOINT ["/entrypoint.bash"] +ENTRYPOINT ["/entrypoint.sh"] CMD ["prosody", "-F"] diff --git a/conf.d/02-storage.cfg.lua b/conf.d/02-storage.cfg.lua index 29b0711..b8cb6d7 100644 --- a/conf.d/02-storage.cfg.lua +++ b/conf.d/02-storage.cfg.lua @@ -1,12 +1,7 @@ default_storage = "sql" - sql = { - driver = os.getenv("DB_DRIVER") or "SQLite3"; - database = os.getenv("DB_DATABASE") or "prosody.sqlite"; - host = os.getenv("DB_HOST"); - port = os.getenv("DB_PORT"); - username = os.getenv("DB_USERNAME"); - password = os.getenv("DB_PASSWORD"); + driver = "SQLite3"; + database = "prosody.sqlite"; } -- make 0.10-distributed mod_mam use sql store @@ -20,4 +15,3 @@ storage = { -- https://modules.prosody.im/mod_mam.html archive_expires_after = "1y" -http_max_content_size = os.getenv("HTTP_MAX_CONTENT_SIZE") or 1024 * 1024 * 10 -- Default is 10MB diff --git a/conf.d/03-e2e-policy.cfg.lua b/conf.d/03-e2e-policy.cfg.lua index 19fab10..ba094e5 100644 --- a/conf.d/03-e2e-policy.cfg.lua +++ b/conf.d/03-e2e-policy.cfg.lua @@ -1,12 +1,7 @@ -local stringy = require "stringy" - -e2e_policy_chat = os.getenv("E2E_POLICY_CHAT") or "required" -e2e_policy_muc = os.getenv("E2E_POLICY_MUC") or "required" - -local whitelist = os.getenv("E2E_POLICY_WHITELIST") or "" -e2e_policy_whitelist = stringy.split(whitelist, ", ") - +e2e_policy_chat = "required" +e2e_policy_muc = "required" +e2e_policy_whitelist = {} e2e_policy_message_optional_chat = "For security reasons, OMEMO, OTR or PGP encryption is STRONGLY recommended for conversations on this server." e2e_policy_message_required_chat = "For security reasons, OMEMO, OTR or PGP encryption is required for conversations on this server." e2e_policy_message_optional_muc = "For security reasons, OMEMO, OTR or PGP encryption is STRONGLY recommended for MUC on this server." -e2e_policy_message_required_muc = "For security reasons, OMEMO, OTR or PGP encryption is required for MUC on this server." +e2e_policy_message_required_muc = "For security reasons, OMEMO, OTR or PGP encryption is required for MUC on this server." \ No newline at end of file diff --git a/conf.d/04-server_contact_info.cfg.lua b/conf.d/04-server_contact_info.cfg.lua index 971392d..a1f0d40 100644 --- a/conf.d/04-server_contact_info.cfg.lua +++ b/conf.d/04-server_contact_info.cfg.lua @@ -1,18 +1,10 @@ -local stringy = require "stringy" - local domain = os.getenv("DOMAIN") -local abuse = os.getenv("SERVER_CONTACT_INFO_ABUSE") or "xmpp:abuse@" .. domain -local admin = os.getenv("SERVER_CONTACT_INFO_ADMIN") or "xmpp:admin@" .. domain -local feedback = os.getenv("SERVER_CONTACT_INFO_FEEDBACK") or "xmpp:feedback@" .. domain -local sales = os.getenv("SERVER_CONTACT_INFO_SALES") or "xmpp:sales@" .. domain -local security = os.getenv("SERVER_CONTACT_INFO_SECURITY") or "xmpp:security@" .. domain -local support = os.getenv("SERVER_CONTACT_INFO_SUPPORT") or "xmpp:support@" .. domain contact_info = { - abuse = stringy.split(abuse, ", "); - admin = stringy.split(admin, ", "); - feedback = stringy.split(feedback, ", "); - sales = stringy.split(sales, ", "); - security = stringy.split(security, ", "); - support = stringy.split(support, ", "); + abuse = { "xmpp:abuse@" .. domain }; + admin = { "xmpp:admin@" .. domain }; + feedback = { "xmpp:feedback@" .. domain }; + sales = { "xmpp:sales@" .. domain }; + security = { "xmpp:security@" .. domain }; + support = { "xmpp:support@" .. domain }; } diff --git a/conf.d/05-vhost.cfg.lua b/conf.d/05-vhost.cfg.lua index 1f5bcec..e4fe3f1 100644 --- a/conf.d/05-vhost.cfg.lua +++ b/conf.d/05-vhost.cfg.lua @@ -1,16 +1,16 @@ local domain = os.getenv("DOMAIN") -local domain_http_upload = os.getenv("DOMAIN_HTTP_UPLOAD") or "upload." .. domain -local domain_muc = os.getenv("DOMAIN_MUC") or "conference." .. domain -local domain_proxy = os.getenv("DOMAIN_PROXY") or "proxy." .. domain -local domain_pubsub = os.getenv("DOMAIN_PUBSUB") or "pubsub." .. domain +local domain_http_upload = os.getenv("DOMAIN_HTTP_UPLOAD") +local domain_muc = os.getenv("DOMAIN_MUC") +local domain_proxy = os.getenv("DOMAIN_PROXY") +local domain_pubsub = os.getenv("DOMAIN_PUBSUB") -- XEP-0368: SRV records for XMPP over TLS -- https://compliance.conversations.im/test/xep0368/ -c2s_direct_tls_ssl = { +legacy_ssl_ssl = { certificate = "certs/" .. domain .. "/fullchain.pem"; key = "certs/" .. domain .. "/privkey.pem"; } -c2s_direct_tls_ports = { 5223 } +legacy_ssl_ports = { 5223 } -- https://prosody.im/doc/certificates#service_certificates -- https://prosody.im/doc/ports#ssl_configuration @@ -20,16 +20,10 @@ https_ssl = { } VirtualHost (domain) -disco_items = { - { domain_http_upload }, -} -- Set up a http file upload because proxy65 is not working in muc -Component (domain_http_upload) "http_file_share" - http_file_share_expires_after = 60 * 60 * 24 * 7 -- a week in seconds - local size_limit = os.getenv("HTTP_FILE_SHARE_SIZE_LIMIT") or 10 * 1024 * 1024 -- Default is 10MB - http_file_share_size_limit = size_limit - http_file_share_daily_quota = os.getenv("HTTP_FILE_SHARE_DAILY_QUOTA") or 10 * size_limit -- Default is 10x the size limit +Component (domain_http_upload) "http_upload" + http_upload_expire_after = 60 * 60 * 24 * 7 -- a week in seconds Component (domain_muc) "muc" name = "Prosody Chatrooms" diff --git a/data/.gitkeep b/data/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/docker-entrypoint.bash b/docker-entrypoint.bash deleted file mode 100755 index 3d85187..0000000 --- a/docker-entrypoint.bash +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash -set -e - -if [[ "$1" != "prosody" ]]; then - exec prosodyctl $* - exit 0; -fi - -if [ "$LOCAL" -a "$PASSWORD" -a "$DOMAIN" ] ; then - prosodyctl register $LOCAL $DOMAIN $PASSWORD -fi - -if [ -z "$DOMAIN" ]; then - echo "[ERROR] DOMAIN must be set!" - exit 1 -fi - -exec "$@" diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh new file mode 100755 index 0000000..4d614f7 --- /dev/null +++ b/docker-entrypoint.sh @@ -0,0 +1,29 @@ +#!/bin/bash +set -e + +if [[ "$1" != "prosody" ]]; then + exec prosodyctl $* + exit 0; +fi + +if [ "$LOCAL" -a "$PASSWORD" -a "$DOMAIN" ] ; then + prosodyctl register $LOCAL $DOMAIN $PASSWORD +fi + +if [ -z "$DOMAIN" ]; then + echo "[ERROR] DOMAIN must be set!" + exit 1 +fi + +export ALLOW_REGISTRATION=${ALLOW_REGISTRATION:-true} +export DOMAIN_HTTP_UPLOAD=${DOMAIN_HTTP_UPLOAD:-"upload.$DOMAIN"} +export DOMAIN_MUC=${DOMAIN_MUC:-"conference.$DOMAIN"} +export DOMAIN_PROXY=${DOMAIN_PROXY:-"proxy.$DOMAIN"} +export DOMAIN_PUBSUB=${DOMAIN_PUBSUB:-"pubsub.$DOMAIN"} +export LOG_LEVEL=${LOG_LEVEL:-"info"} +export C2S_REQUIRE_ENCRYPTION=${C2S_REQUIRE_ENCRYPTION:-true} +export S2S_REQUIRE_ENCRYPTION=${S2S_REQUIRE_ENCRYPTION:-true} +export S2S_SECURE_AUTH=${S2S_SECURE_AUTH:-true} +export PROSODY_ADMINS=${PROSODY_ADMINS:-""} + +exec "$@" diff --git a/prosody.cfg.lua b/prosody.cfg.lua index b53faeb..9b887b8 100644 --- a/prosody.cfg.lua +++ b/prosody.cfg.lua @@ -1,33 +1,20 @@ -- see example config at https://hg.prosody.im/0.9/file/0.9.10/prosody.cfg.lua.dist -- easily extendable by putting into different config files within conf.d folder -local stringy = require "stringy" +admins = { os.getenv("PROSODY_ADMINS") }; -local prosody_admins = os.getenv("PROSODY_ADMINS") or ""; -admins = stringy.split(prosody_admins, ", "); +use_libevent = true; -- improves performance -pidfile = "/var/run/prosody/prosody.pid" +allow_registration = os.getenv("ALLOW_REGISTRATION"); -allow_registration = os.getenv("ALLOW_REGISTRATION") or "true"; +c2s_require_encryption = os.getenv("C2S_REQUIRE_ENCRYPTION"); +s2s_require_encryption = os.getenv("S2S_REQUIRE_ENCRYPTION"); +s2s_secure_auth = os.getenv("S2S_SECURE_AUTH"); -c2s_require_encryption = os.getenv("C2S_REQUIRE_ENCRYPTION") or "true"; -s2s_require_encryption = os.getenv("S2S_REQUIRE_ENCRYPTION") or "true"; -s2s_secure_auth = os.getenv("S2S_SECURE_AUTH") or "true"; - -authentication = os.getenv("AUTHENTICATION") or "internal_hashed"; - -ldap_base = os.getenv("LDAP_BASE"); -ldap_server = os.getenv("LDAP_SERVER") or "localhost"; -ldap_rootdn = os.getenv("LDAP_ROOTDN") or ""; -ldap_password = os.getenv("LDAP_PASSWORD") or ""; -ldap_filter = os.getenv("LDAP_FILTER") or "(uid=$user)"; -ldap_scope = os.getenv("LDAP_SCOPE") or "subtree"; -ldap_tls = os.getenv("LDAP_TLS") or "false"; -ldap_mode = os.getenv("LDAP_MODE") or "bind"; -ldap_admin_filter = os.getenv("LDAP_ADMIN_FILTER") or ""; +authentication = "internal_hashed"; log = { - {levels = {min = os.getenv("LOG_LEVEL") or "info"}, to = "console"}; + {levels = {min = os.getenv("LOG_LEVEL")}, to = "console"}; }; Include "conf.d/*.cfg.lua"; diff --git a/readme.md b/readme.md index de5ab62..9f0e227 100644 --- a/readme.md +++ b/readme.md @@ -1,13 +1,11 @@ # Prosody XMPP Docker image ![Docker](https://github.com/SaraSmiseth/prosody/workflows/Docker/badge.svg?branch=dev) -![Git repository size](https://img.shields.io/github/repo-size/SaraSmiseth/prosody) -[![Docker pulls](https://img.shields.io/docker/pulls/sarasmiseth/prosody.svg)](https://hub.docker.com/r/sarasmiseth/prosody/) -[![Docker stars](https://img.shields.io/docker/stars/sarasmiseth/prosody.svg)](https://hub.docker.com/r/sarasmiseth/prosody/) -[![Github open issues](https://img.shields.io/github/issues-raw/SaraSmiseth/prosody)](https://github.com/SaraSmiseth/prosody/issues) -[![Github open pull requests](https://img.shields.io/github/issues-pr-raw/SaraSmiseth/prosody)](https://github.com/SaraSmiseth/prosody/pulls) +[![docker image](https://images.microbadger.com/badges/image/sarasmiseth/prosody:latest.svg)](https://microbadger.com/images/sarasmiseth/prosody:latest) +[![docker pulls](https://img.shields.io/docker/pulls/sarasmiseth/prosody.svg)](https://hub.docker.com/r/sarasmiseth/prosody/) +[![docker stars](https://img.shields.io/docker/stars/sarasmiseth/prosody.svg)](https://hub.docker.com/r/sarasmiseth/prosody/) -This docker image provides you with a configured [Prosody](https://prosody.im/) XMPP server. The image is based on `debian:bookworm-slim`. +This docker image provides you with a configured [Prosody](https://prosody.im/) XMPP server. The image is based on `debian:buster-slim`. The server was tested using the Android App [Conversations](https://conversations.im/) and the Desktop client [Gajim](https://gajim.org). Multiple [architectures](https://hub.docker.com/r/sarasmiseth/prosody/tags) are supported. I use it on my raspberry pi 4. @@ -36,11 +34,11 @@ While Conversations got everything set-up out-of-the-box, Gajim was used with th - [Symlinks](#symlinks) - [Permissions](#permissions) - [Run](#run) - - [Volumes permissions](#volumes-permissions) - [Docker tags](#docker-tags) - [Configuration](#configuration) - [Environment variables](#environment-variables) - [DNS](#dns) + - [server_contact_info](#server_contact_info) - [Extend](#extend) - [Upgrade](#upgrade) - [Test your server](#test-your-server) @@ -141,7 +139,6 @@ For example ```cp -L src dest```. ##### Permissions See official [documentation](https://prosody.im/doc/certificates#permissions) for more information. -Check [Volumes permissions](#volumes-permissions) as well. ### Run @@ -152,7 +149,7 @@ version: '3.7' services: server: - image: sarasmiseth/prosody:latest + image: sarasmiseth/prosody:v1.0.0 restart: unless-stopped ports: - "5000:5000" @@ -167,18 +164,9 @@ services: - ./data:/usr/local/var/lib/prosody ``` -Boot it via: ```docker compose up -d```. +Boot it via: ```docker-compose up -d```. -Inspect logs: ```docker compose logs -f```. - -### Volumes permissions - -The prosody user inside the container has the `uid=999` and `gid=999`. If you use the example `docker-compose.yml` from above make sure, that the `./data` folder and the `./certs` folder have the correct permissions. - -``` shell -sudo chown 999:999 ./certs -sudo chown 999:999 ./data -``` +Inspect logs: ```docker-compose logs -f```. ### Docker tags @@ -195,47 +183,19 @@ sudo chown 999:999 ./data #### Environment variables -| Variable | Description | Type | Default value | -| -------------------------------- | -------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- | -------------------------- | -| **ALLOW_REGISTRATION** | Whether to allow registration of new accounts via Jabber clients | *optional* | true | -| **DOMAIN** | domain | **required** | null | -| **DOMAIN_HTTP_UPLOAD** | Domain which lets clients upload files over HTTP | *optional* | upload.**DOMAIN** | -| **DOMAIN_MUC** | Domain for Multi-user chat (MUC) for allowing you to create hosted chatrooms/conferences for XMPP users | *optional* | conference.**DOMAIN** | -| **DOMAIN_PROXY** | Domain for SOCKS5 bytestream proxy for server-proxied file transfers | *optional* | proxy.**DOMAIN** | -| **DOMAIN_PUBSUB** | Domain for a XEP-0060 pubsub service | *optional* | pubsub.**DOMAIN** | -| **AUTHENTICATION** | authentication | *optional* | "internal_hashed" | -| **LDAP_BASE** | LDAP base directory which stores user accounts | **required** if **AUTHENTICATION** is "ldap" | | -| **LDAP_SERVER** | Space-separated list of hostnames or IPs, optionally with port numbers (e.g. “localhost:8389”) | *optional* | "localhost" | -| **LDAP_ROOTDN** | The distinguished name to auth against | *optional* | "" | -| **LDAP_PASSWORD** | Password for rootdn | *optional* | "" | -| **LDAP_FILTER** | Search filter, with $user and $host substituted for user- and hostname | *optional* | "(uid=$user)" | -| **LDAP_SCOPE** | Search scope. other values: “base” and “onelevel” | *optional* | "subtree" | -| **LDAP_TLS** | Enable TLS (StartTLS) to connect to LDAP (can be true or false). The non-standard ‘LDAPS’ protocol is not supported. | *optional* | "false" | -| **LDAP_MODE** | How passwords are validated. | *optional* | "bind" | -| **LDAP_ADMIN_FILTER** | Search filter to match admins, works like ldap_filter | *optional* | "" | -| **DB_DRIVER** | May also be "PostgreSQL" or "MySQL" or "SQLite3" (case sensitive!) | *optional* | SQLite3 | -| **DB_DATABASE** | The database name to use. For SQLite3 this the database filename (relative to the data storage directory). | *optional* | prosody.sqlite | -| **DB_HOST** | The address of the database server | *optional* | | -| **DB_PORT** | Port on which the database is listening | *optional* | | -| **DB_USERNAME** | The username to authenticate to the database | *optional* | | -| **DB_PASSWORD** | The password to authenticate to the database | *optional* | | -| **HTTP_MAX_CONTENT_SIZE** | Max http content size in bytes | *optional* | 10485760 | -| **HTTP_FILE_SHARE_SIZE_LIMIT** | Max http file share size in bytes | *optional* | 10485760 | -| **HTTP_FILE_SHARE_DAILY_QUOTA** | Daily quota in bytes | *optional* | 10 times share size limit | -| **E2E_POLICY_CHAT** | Policy for chat messages. Possible values: "none", "optional" and "required". | *optional* | "required" | -| **E2E_POLICY_MUC** | Policy for MUC messages. Possible values: "none", "optional" and "required". | *optional* | "required" | -| **E2E_POLICY_WHITELIST** | Make this module ignore messages sent to and from this JIDs or MUCs. | *optional* | "" | -| **LOG_LEVEL** | Min log level. Change to debug for more information | *optional* | info | -| **C2S_REQUIRE_ENCRYPTION** | Whether to force all client-to-server connections to be encrypted or not | *optional* | true | -| **S2S_REQUIRE_ENCRYPTION** | Whether to force all server-to-server connections to be encrypted or not | *optional* | true | -| **S2S_SECURE_AUTH** | Require encryption and certificate authentication | *optional* | true | -| **SERVER_CONTACT_INFO_ABUSE** | A list of strings. Each string should be an URI. See [here](https://prosody.im/doc/modules/mod_server_contact_info). | *optional* | "xmpp:abuse@**DOMAIN**" | -| **SERVER_CONTACT_INFO_ADMIN** | A list of strings. Each string should be an URI. See [here](https://prosody.im/doc/modules/mod_server_contact_info). | *optional* | "xmpp:admin@**DOMAIN**" | -| **SERVER_CONTACT_INFO_FEEDBACK** | A list of strings. Each string should be an URI. See [here](https://prosody.im/doc/modules/mod_server_contact_info). | *optional* | "xmpp:feedback@**DOMAIN**" | -| **SERVER_CONTACT_INFO_SALES** | A list of strings. Each string should be an URI. See [here](https://prosody.im/doc/modules/mod_server_contact_info). | *optional* | "xmpp:sales@**DOMAIN**" | -| **SERVER_CONTACT_INFO_SECURITY** | A list of strings. Each string should be an URI. See [here](https://prosody.im/doc/modules/mod_server_contact_info). | *optional* | "xmpp:security@**DOMAIN**" | -| **SERVER_CONTACT_INFO_SUPPORT** | A list of strings. Each string should be an URI. See [here](https://prosody.im/doc/modules/mod_server_contact_info). | *optional* | "xmpp:support@**DOMAIN**" | -| **PROSODY_ADMINS** | Specify who is an administrator. List of adresses. Eg. "me@example.com", "admin@example.net" | *optional* | "" | +| Variable | Description | Type | Default value | +| -------------------------- | ------------------------------------------------------------------------------------------------------- | ------------ | --------------------- | +| **ALLOW_REGISTRATION** | Whether to allow registration of new accounts via Jabber clients | *optional* | true | +| **DOMAIN** | domain | **required** | null | +| **DOMAIN_HTTP_UPLOAD** | Domain which lets clients upload files over HTTP | *optional* | upload.**DOMAIN** | +| **DOMAIN_MUC** | Domain for Multi-user chat (MUC) for allowing you to create hosted chatrooms/conferences for XMPP users | *optional* | conference.**DOMAIN** | +| **DOMAIN_PROXY** | Domain for SOCKS5 bytestream proxy for server-proxied file transfers | *optional* | proxy.**DOMAIN** | +| **DOMAIN_PUBSUB** | Domain for a XEP-0060 pubsub service | *optional* | pubsub.**DOMAIN** | +| **LOG_LEVEL** | Min log level. Change to debug for more information | *optional* | info | +| **C2S_REQUIRE_ENCRYPTION** | Whether to force all client-to-server connections to be encrypted or not | *optional* | true | +| **S2S_REQUIRE_ENCRYPTION** | Whether to force all server-to-server connections to be encrypted or not | *optional* | true | +| **S2S_SECURE_AUTH** | Require encryption and certificate authentication | *optional* | true | +| **PROSODY_ADMINS** | Specify who is an administrator. List of adresses. Eg. "me@example.com", "admin@example.net" | *optional* | "" | #### DNS @@ -250,6 +210,20 @@ You need these DNS record pointing to your server: where domain.tld is the environment variable DOMAIN. +#### server_contact_info + +This module lets you advertise various contact addresses for your XMPP service via XEP-0157. +It is configured for the following contacts: + +* abuse +* admin +* feedback +* sales +* security +* support + +You can change them in [05-server_contact_info.cfg.lua](./conf.d/04-server_contact_info.cfg.lua). + ### Extend There is a helper script that eases installing additional prosody modules: ```docker-prosody-module-install``` @@ -265,7 +239,7 @@ If you need additional configuration just overwrite the respective _cfg.lua_ fil When migrating from prosody 0.10, you need to update the database once: ```bash -docker compose exec server bash +docker-compose exec server bash prosodyctl mod_storage_sql upgrade ``` diff --git a/tests/bats/bats-assert b/tests/bats/bats-assert deleted file mode 160000 index 397c735..0000000 --- a/tests/bats/bats-assert +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 397c735212bf1a06cfdd0cb7806c5a6ea79582bf diff --git a/tests/bats/bats-core b/tests/bats/bats-core deleted file mode 160000 index 410dd22..0000000 --- a/tests/bats/bats-core +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 410dd229a5ed005c68167cc90ed0712ad2a1c909 diff --git a/tests/bats/bats-support b/tests/bats/bats-support deleted file mode 160000 index 3c8fadc..0000000 --- a/tests/bats/bats-support +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3c8fadc5097c9acfc96d836dced2bb598e48b009 diff --git a/tests/docker-compose.yml b/tests/docker-compose.yml deleted file mode 100644 index b67723b..0000000 --- a/tests/docker-compose.yml +++ /dev/null @@ -1,80 +0,0 @@ -services: - prosody: - image: prosody - restart: unless-stopped - ports: - - "5000:5000" - - "5222:5222" - - "5223:5223" - - "5269:5269" - - "5281:5281" - environment: - DOMAIN: example.com - E2E_POLICY_WHITELIST: "admin@example.com, user1@example.com" - LOG_LEVEL: debug - PROSODY_ADMINS: "admin@example.com, admin2@example.com" - volumes: - - ./certs:/usr/local/etc/prosody/certs - - prosody_postgres: - image: prosody - restart: unless-stopped - ports: - - "5000:5000" - - "5222:5222" - - "5223:5223" - - "5269:5269" - - "5281:5281" - environment: - DOMAIN: example.com - E2E_POLICY_WHITELIST: "admin@example.com, user1@example.com" - LOG_LEVEL: debug - PROSODY_ADMINS: "admin@example.com, admin2@example.com" - #DB_DRIVER: "MySQL" - DB_DRIVER: "PostgreSQL" - DB_DATABASE: "prosody" - DB_HOST: "postgres" - DB_PORT: "5432" - DB_USERNAME: "prosody" - DB_PASSWORD: "prosody" - volumes: - - ./certs:/usr/local/etc/prosody/certs - depends_on: - - postgres - - postgres: - image: postgres:16-alpine - restart: unless-stopped - environment: - POSTGRES_DB: prosody - POSTGRES_USER: prosody - POSTGRES_PASSWORD: prosody - - prosody_ldap: - image: prosody - restart: unless-stopped - ports: - - "5000:5000" - - "5222:5222" - - "5223:5223" - - "5269:5269" - - "5281:5281" - environment: - DOMAIN: example.com - E2E_POLICY_WHITELIST: "admin@example.com, user1@example.com" - LOG_LEVEL: debug - PROSODY_ADMINS: "admin@example.com, admin2@example.com" - AUTHENTICATION: "ldap" - LDAP_BASE: "dc=example,dc=com" - LDAP_SERVER: "glauth" - LDAP_ROOTDN: "cn=svc,dc=example,dc=com" - LDAP_PASSWORD: "12345678" - volumes: - - ./certs:/usr/local/etc/prosody/certs - depends_on: - - glauth - - glauth: - image: glauth/glauth - volumes: - - "./glauth/config.cfg:/app/config/config.cfg" diff --git a/tests/glauth/config.cfg b/tests/glauth/config.cfg deleted file mode 100644 index f180ac4..0000000 --- a/tests/glauth/config.cfg +++ /dev/null @@ -1,52 +0,0 @@ -[ldap] - enabled = true - listen = "0.0.0.0:389" - -[ldaps] - enabled = false - -[backend] - datastore = "config" - baseDN = "dc=example,dc=com" - -[[groups]] - name = "svc" - gidnumber = 5500 - -[[groups]] - name = "people" - gidnumber = 5501 - -[[users]] - name = "svc" - uidnumber = 5000 - primarygroup = 5500 - passsha256 = "ef797c8118f02dfb649607dd5d3f8c7623048c9c063d532cc95c5ed7a898a64f" - -[[users.capabilities]] - action = "search" - object = "*" - -[[users]] - name = "admin" - uidnumber = 5001 - primarygroup = 5501 - passsha256 = "ef797c8118f02dfb649607dd5d3f8c7623048c9c063d532cc95c5ed7a898a64f" - -[[users]] - name = "user1" - uidnumber = 5002 - primarygroup = 5501 - passsha256 = "ef797c8118f02dfb649607dd5d3f8c7623048c9c063d532cc95c5ed7a898a64f" - -[[users]] - name = "user2" - uidnumber = 5003 - primarygroup = 5501 - passsha256 = "ef797c8118f02dfb649607dd5d3f8c7623048c9c063d532cc95c5ed7a898a64f" - -[[users]] - name = "user3" - uidnumber = 5004 - primarygroup = 5501 - passsha256 = "ef797c8118f02dfb649607dd5d3f8c7623048c9c063d532cc95c5ed7a898a64f" diff --git a/tests/readme.md b/tests/readme.md deleted file mode 100644 index af1c31b..0000000 --- a/tests/readme.md +++ /dev/null @@ -1,28 +0,0 @@ -# Tests - -Pytest is used to login and send messages to other accounts. -Bats is used to check the log for debug messages. - -## Dependencies - -* docker -* docker-compose -* python 3 - -## Run tests - -Execute [`test.bash`](test.bash). - -## Upgrade python packages - -The following will install the newest version of packages in requirements.txt. - -``` bash -cat requirements.txt | sed 's/==.*//g' | xargs pip install -U -``` - -If updates are available --> update and create new version with: - -``` bash -pip-chill > requirements.txt -``` diff --git a/tests/requirements.txt b/tests/requirements.txt deleted file mode 100644 index dbe0b29..0000000 --- a/tests/requirements.txt +++ /dev/null @@ -1,4 +0,0 @@ -aioxmpp==0.13.3 -pip-chill==1.0.3 -pytest-asyncio==0.21.0 -pytz==2023.3 diff --git a/tests/test.bash b/tests/test.bash deleted file mode 100755 index 33a374b..0000000 --- a/tests/test.bash +++ /dev/null @@ -1,77 +0,0 @@ -#!/bin/bash - -set -e - -# generate certs for testing - -generateCert() { - local DOMAIN="$1" - if [[ ! -d certs/"$DOMAIN" ]] ; then - mkdir -p certs/"$DOMAIN" - cd certs/"$DOMAIN" - openssl req -x509 -newkey rsa:4096 -keyout privkey.pem -out fullchain.pem -days 365 -subj "/CN=$DOMAIN" -nodes - chmod 777 *.pem - cd ../../ - fi -} - -registerTestUser() { - local userName="$1" - local containerName="$2" - echo "Registering TestUser '$userName' in container '$containerName'" - sudo docker compose exec "$containerName" /bin/bash -c "prosodyctl register $userName example.com 12345678" -} - -registerTestUsers() { - local containerName="$1" - registerTestUser admin "$containerName" - registerTestUser user1 "$containerName" - registerTestUser user2 "$containerName" - registerTestUser user3 "$containerName" -} - -runTests() { - local containerName="$1" - python --version \ - && python3 --version \ - && python3 -m venv venv \ - && source venv/bin/activate \ - && python --version \ - && pip --version \ - && pip install -r requirements.txt \ - && pytest \ - && deactivate \ - && sleep 5 \ - && sudo docker compose logs "$containerName" \ - && export batsContainerName="$containerName" \ - && ./bats/bats-core/bin/bats tests.bats \ - && ./bats/bats-core/bin/bats tests-"$containerName".bats -} - -generateCert "example.com" -generateCert "conference.example.com" -generateCert "proxy.example.com" -generateCert "pubsub.example.com" -generateCert "upload.example.com" - -# Run tests for first container with postgres -# Start postgres first and wait for 10 seconds before starting prosody. -sudo docker compose down -sudo docker compose up -d postgres -sleep 10 -sudo docker compose up -d prosody_postgres - -registerTestUsers prosody_postgres -runTests prosody_postgres -sudo docker compose down - -# Run tests for second container with SQLite -sudo docker compose up -d prosody -registerTestUsers prosody -runTests prosody -sudo docker compose down - -# Run tests for prosody with ldap -sudo docker compose up -d prosody_ldap -runTests prosody_ldap -sudo docker compose down diff --git a/tests/test_prosody.py b/tests/test_prosody.py deleted file mode 100644 index b7b13fa..0000000 --- a/tests/test_prosody.py +++ /dev/null @@ -1,120 +0,0 @@ -import aiosasl -import aioxmpp -import aioxmpp.dispatcher -import asyncio -import pytest - -@pytest.fixture -def client(client_username, password): - - jid = aioxmpp.JID.fromstr(client_username) - - client = aioxmpp.PresenceManagedClient( - jid, - aioxmpp.make_security_layer( - password, - no_verify=True - ), - override_peer=[("localhost", 5222, aioxmpp.connector.STARTTLSConnector())], - ) - return client - -@pytest.fixture -def client_with_message_dispatcher(client): - def message_received(msg): - print(msg) - print(msg.body) - assert msg.body == "Hello World!" - - # obtain an instance of the service - message_dispatcher = client.summon( - aioxmpp.dispatcher.SimpleMessageDispatcher - ) - - # register a message callback here - message_dispatcher.register_callback( - aioxmpp.MessageType.CHAT, - None, - message_received, - ) - return client - -@pytest.mark.asyncio -@pytest.mark.parametrize("client_username, password", [("admin@example.com", "12345678")]) -async def test_send_message_from_admin_to_user1(client): - recipient_jid = aioxmpp.JID.fromstr("user1@example.com") - async with client.connected() as stream: - msg = aioxmpp.Message( - to=recipient_jid, - type_=aioxmpp.MessageType.CHAT, - ) - # None is for "default language" - msg.body[None] = "Hello World!" - - await client.send(msg) - -@pytest.mark.asyncio -@pytest.mark.parametrize("client_username, password", [("admin@example.com", "12345678")]) -async def test_send_message_from_admin_to_user2(client): - recipient_jid = aioxmpp.JID.fromstr("user2@example.com") - async with client.connected() as stream: - msg = aioxmpp.Message( - to=recipient_jid, - type_=aioxmpp.MessageType.CHAT, - ) - msg.body[None] = "Hello World!" - - await client.send(msg) - -@pytest.mark.asyncio -@pytest.mark.parametrize("client_username, password", [("user1@example.com", "12345678")]) -async def test_send_message_from_user1_to_user2(client): - recipient_jid = aioxmpp.JID.fromstr("user2@example.com") - async with client.connected() as stream: - msg = aioxmpp.Message( - to=recipient_jid, - type_=aioxmpp.MessageType.CHAT, - ) - msg.body[None] = "Hello World!" - - await client.send(msg) - -@pytest.mark.asyncio -@pytest.mark.parametrize("client_username, password", [("user2@example.com", "12345678")]) -async def test_send_message_from_user2_to_user3(client): - recipient_jid = aioxmpp.JID.fromstr("user3@example.com") - async with client.connected() as stream: - msg = aioxmpp.Message( - to=recipient_jid, - type_=aioxmpp.MessageType.CHAT, - ) - msg.body[None] = "Hello World!" - - await client.send(msg) - -@pytest.mark.asyncio -@pytest.mark.parametrize("client_username, password", [("user2@example.com", "12345678")]) -async def test_send_message_from_user2_to_nonexisting(client): - recipient_jid = aioxmpp.JID.fromstr("nonexisting@example.com") - async with client.connected() as stream: - msg = aioxmpp.Message( - to=recipient_jid, - type_=aioxmpp.MessageType.CHAT, - ) - msg.body[None] = "Hello World!" - - await client.send(msg) - -@pytest.mark.asyncio -@pytest.mark.parametrize("client_username, password", [("user2@example.com", "wrong password")]) -async def test_can_not_log_in_with_wrong_password(client): - with pytest.raises(aiosasl.AuthenticationFailure): - recipient_jid = aioxmpp.JID.fromstr("nonexisting@example.com") - async with client.connected() as stream: - msg = aioxmpp.Message( - to=recipient_jid, - type_=aioxmpp.MessageType.CHAT, - ) - msg.body[None] = "Hello World!" - - await client.send(msg) diff --git a/tests/tests-prosody.bats b/tests/tests-prosody.bats deleted file mode 100644 index e2efe54..0000000 --- a/tests/tests-prosody.bats +++ /dev/null @@ -1,10 +0,0 @@ -# For tests with pipes see: https://github.com/sstephenson/bats/issues/10 - -load 'bats/bats-support/load' -load 'bats/bats-assert/load' - -@test "Should use sqlite" { - run bash -c "sudo docker compose logs $batsContainerName | grep -E \"Connecting to \[SQLite3\] \/usr\/local\/var\/lib\/prosody\/prosody\.sqlite\.\.\.\"" - assert_success - assert_output -} diff --git a/tests/tests-prosody_ldap.bats b/tests/tests-prosody_ldap.bats deleted file mode 100644 index 64c92b2..0000000 --- a/tests/tests-prosody_ldap.bats +++ /dev/null @@ -1,16 +0,0 @@ -# For tests with pipes see: https://github.com/sstephenson/bats/issues/10 - -load 'bats/bats-support/load' -load 'bats/bats-assert/load' - -@test "Should use sqlite" { - run bash -c "sudo docker compose logs $batsContainerName | grep -E \"Connecting to \[SQLite3\] \/usr\/local\/var\/lib\/prosody\/prosody\.sqlite\.\.\.\"" - assert_success - assert_output -} - -@test "Should use ldap" { - run bash -c "sudo docker compose logs $batsContainerName | grep -E \"Host 'example.com' now set to use user provider 'ldap'\"" - assert_success - assert_output -} diff --git a/tests/tests-prosody_postgres.bats b/tests/tests-prosody_postgres.bats deleted file mode 100644 index f33fecb..0000000 --- a/tests/tests-prosody_postgres.bats +++ /dev/null @@ -1,10 +0,0 @@ -# For tests with pipes see: https://github.com/sstephenson/bats/issues/10 - -load 'bats/bats-support/load' -load 'bats/bats-assert/load' - -@test "Should use postgres" { - run bash -c "sudo docker compose logs $batsContainerName | grep -E \"Connecting to \[PostgreSQL\] prosody\.\.\.\"" - assert_success - assert_output -} diff --git a/tests/tests.bats b/tests/tests.bats deleted file mode 100644 index 3655520..0000000 --- a/tests/tests.bats +++ /dev/null @@ -1,98 +0,0 @@ -# For tests with pipes see: https://github.com/sstephenson/bats/issues/10 - -load 'bats/bats-support/load' -load 'bats/bats-assert/load' - -@test "Should send 5 messages" { - run bash -c "sudo docker compose logs $batsContainerName | grep -E \"Received\[c2s\]: