Commit 63b1ee09 authored by Lars Kruse's avatar Lars Kruse
Browse files

Merge branch 'feature/lars-696-matrix-chat'

Initial support for a Matrix-based chat.
parents d7b1667e d7d595ca
......@@ -21,12 +21,14 @@ grouprise/locale/*/LC_MESSAGES/django.mo
makefilet
.pybuild/
debian/debhelper-build-stamp
debian/element-web-installer/
debian/grouprise/
debian/grouprise-dependencies/
debian/grouprise-doc/
debian/grouprise-db-postgresql/
debian/grouprise-db-sqlite/
debian/grouprise-lmtpd/
debian/grouprise-matrix/
debian/stadtgestalten/
debian/*.debhelper
debian/tmp
......
......@@ -52,6 +52,7 @@ Architecture: all
Depends:
${misc:Depends},
adduser,
debconf,
grouprise-dependencies,
grouprise-db-postgresql | grouprise-db-sqlite,
moreutils,
......@@ -152,6 +153,35 @@ Description: Web platform that enables social action and solidarity
pre-packaged python virtual environment (venv) for running the
grouprise application.
Package: grouprise-matrix
Architecture: all
Depends:
element-web-installer,
jq,
matrix-synapse,
moreutils,
# this package is not shipped in buster or buster-backports ("bullseye" is necessary)
python3-matrix-nio,
Description: Matrix integration for grouprise platform
Grouprise is a web-based platform providing tools for groups and
initiatives in a local context.
.
This package contains necessary services and files for configuring
a Matrix server to be used as a chat manager for grouprise.
Package: element-web-installer
Architecture: all
Depends:
curl,
debconf,
gpgv,
jq,
moreutils,
Suggests: httpd
Description: Installer for the Matrix web client Element
Download the Element web client and keep it updated.
Local configuration is applied automatically.
Package: stadtgestalten
Architecture: any
Depends: grouprise
......
Overview
--------
This package provides a script for downloading, verifying and extracting a release of the
element-web [1] client for the Matrix [2] network.
The element-web client is extracted to /var/lib/element-web-installer/.
The element-web client is updated automatically via a daily cron job.
Configuration
-------------
Local customizations can be placed below /etc/element-web/. At least config.json [3]
Every file somewhere below this directory is symlinked into the directory of the extracted
element-web client, whenever the client is updated.
Web server configuration
------------------------
The web client's directory may simply be published by your webserver.
Example configuration for apache2:
<VirtualHost *>
ServerName example.org
DocumentRoot /var/lib/element-web-installer
<Directory /var/lib/element-web-installer>
Require all granted
Options SymLinksIfOwnerMatch
</Directory>
</VirtualHost>
Example configuration for nginx:
server {
server_name example.org;
root /var/lib/element-web-installer;
}
[1] https://element.io/
[2] https://matrix.org/
[3] https://github.com/vector-im/element-web/blob/develop/docs/config.md
12 4 * * * root chronic /usr/sbin/element-web-installer upgrade
All files below the directory /etc/element-web/ can be used to add files to the
element-web directory or override existing files (via symlinks).
Probably you want to add at least your config.json file [1] and maybe additional assets to be
published via HTTP (e.g. a custom logo).
[1] https://github.com/vector-im/element-web/blob/develop/docs/config.md
<VirtualHost *>
ServerName localhost
DocumentRoot /var/lib/element-web-installer/htdocs
<Directory /var/lib/element-web-installer/htdocs>
Require all granted
</Directory>
</VirtualHost>
#!/bin/sh
#
# Download, verify and extract a release of the element-web client.
#
# License: GPLv3 or later
#
set -eu
DOWNLOAD_BASE_URL=https://github.com
DOWNLOAD_PROJECT_URL_PATH=vector-im/element-web
DOWNLOAD_APP_NAME=element
SIGNING_KEYRING_PATH=${SIGNING_KEYRING_PATH:-/usr/share/element-web-installer/trustedkeys.gpg}
INSTALL_PATH=${INSTALL_PATH:-/var/lib/element-web-installer/htdocs}
SETTINGS_PATH=${SETTINGS_PATH:-/etc/element-web}
get_latest_version() {
curl -sSL --fail "$DOWNLOAD_BASE_URL/$DOWNLOAD_PROJECT_URL_PATH/releases/latest" \
| grep "<a href=\"/$DOWNLOAD_PROJECT_URL_PATH/releases/download/v[0-9.]\+/${DOWNLOAD_APP_NAME}-v[0-9.]\+.tar.gz[^.]" \
| cut -f 2 -d '"' \
| sed "s|^.*/${DOWNLOAD_APP_NAME}-v||; s|\.tar\.gz$||"
}
get_installed_version() {
# return the currently installed version (or empty, if not installed)
cat "$INSTALL_PATH/version" 2>/dev/null || true
}
get_download_url() {
local version="$1"
echo "$DOWNLOAD_BASE_URL/$DOWNLOAD_PROJECT_URL_PATH/releases/download/v$version/${DOWNLOAD_APP_NAME}-v$version.tar.gz"
}
get_download_signature_url() {
local version="$1"
echo "$(get_download_url "$version").asc"
}
apply_local_settings() {
local destination_path="$1"
(cd "$SETTINGS_PATH" && find . -type f) | cut -d / -f 2- | while read -r fname; do
mkdir -p "$destination_path/$(dirname "$fname")"
ln -sfn "$SETTINGS_PATH/$fname" "$destination_path/$fname"
done
}
extract_archive_to_destination() {
local archive_path="$1"
local destination_path="$2"
local temp_dest
mkdir -p "$(dirname "$destination_path")"
temp_dest=$(mktemp -d --tmpdir="$(dirname "$destination_path")" element-web-installer-XXXXXX)
# restrict the scope of trap
(
trap 'rm -rf "'"$temp_dest"'"' EXIT
tar -C "$temp_dest" --strip-components=1 -xzf "$archive_path"
chmod 755 "$temp_dest"
apply_local_settings "$temp_dest"
rm -rf "$destination_path"
mv "$temp_dest" "$destination_path"
trap - EXIT
)
}
extract_verified_download() {
local target_path="$1"
local target_version="$2"
local download_dir archive_path signature_path
download_dir=$(mktemp -d)
# restrict the scope of trap
(
trap 'rm -rf "'"$download_dir"'"' EXIT
archive_path=$download_dir/archive.tar.gz
signature_path=$download_dir/signature.asc
curl -sSL --fail "$(get_download_url "$target_version")" >"$archive_path"
curl -sSL --fail "$(get_download_signature_url "$target_version")" >"$signature_path"
# suppress the verification summary in case of success (via "chronic")
if chronic gpgv --keyring="$SIGNING_KEYRING_PATH" "$signature_path" "$archive_path"; then
extract_archive_to_destination "$archive_path" "$target_path"
else
echo >&2 "Failed to verify signature. Refusing to unpack downloaded package."
false
fi
trap - EXIT
)
}
if [ $# -gt 0 ]; then
ACTION=$1
shift
else
ACTION=status
fi
case "$ACTION" in
status)
printf 'Currently installed version:\t%s\n' "$(get_installed_version)"
printf 'Latest available version:\t%s\n' "$(get_latest_version)"
;;
upgrade)
wanted_version=${1:-latest}
[ "$wanted_version" = "latest" ] && wanted_version=$(get_latest_version)
if [ "$wanted_version" = "$(get_installed_version)" ]; then
echo "Version '$wanted_version' is already installed. Nothing needs to be done."
else
echo "Dowloading and extracting element-web version '$wanted_version' ..."
extract_verified_download "$INSTALL_PATH" "$wanted_version"
fi
;;
show-installed-version)
installed_version=$(get_installed_version)
if [ -z "$installed_version" ]; then
echo >&2 "element-web was not downloaded to '$INSTALL_PATH', yet."
exit 2
else
printf '%s\n' "$installed_version"
fi
;;
show-latest-version)
get_latest_version
;;
apply-configuration)
apply_local_settings "$INSTALL_PATH"
;;
help|--help)
echo "Syntax: $(basename "$0") ACTION"
echo " upgrade [VERSION] - upgrade the element directory ($INSTALL_PATH) to the specified version (default: latest) and apply the local configuration"
echo " apply-configuration - apply the local configuration ($SETTINGS_PATH) to the element directory ($INSTALL_PATH)"
echo " show-installed-version - output the currently installed version"
echo " show-latest-version - output the latest released version of element-web"
echo
;;
*)
"$0" help >&2
exit 1
;;
esac
server {
server_name localhost;
root /var/lib/element-web-installer/htdocs;
}
#!/usr/bin/dh-exec
debian/element-web-installer.d/README_configuration => /etc/element-web/README
debian/element-web-installer.d/element-web-installer /usr/sbin/
# source: https://packages.riot.im/element-release-key.gpg
# Retrieve key and apply ascii armor packaging:
# keyring=debian/element-web-installer.d/release-trustedkeys.gpg && echo -n >"$keyring" && curl -s "https://packages.riot.im/element-release-key.gpg" | gpg --no-default-keyring --keyring "$keyring" --import
debian/element-web-installer.d/release-trustedkeys.gpg => /usr/share/element-web-installer/trustedkeys.gpg
debian/element-web-installer.d/apache2/element-web.conf /etc/apache2/sites-available/
debian/element-web-installer.d/nginx/element-web /etc/nginx/sites-available/
#!/bin/sh
set -e
CONFIG_DIR=/etc/element-web
WEB_DIR=/var/lib/element-web-installer/htdocs
. /usr/share/debconf/confmodule
db_version 2.1
# debconf does not work with "set -u", thus we enable it after loading debconf
set -eu
ask_debconf_question() {
local question="$1"
local priority="$2"
local default_value="${3:-}"
local RET
if [ -n "$default_value" ] && ( ! db_get "$question" || [ -z "$RET" ] ); then
# the value is not configured via debconf, yet
db_set "$question" "$default_value"
fi
db_input "$priority" "$question" || true
# shellcheck disable=SC2119
db_go || true
db_get "$question" || true
printf '%s' "$RET"
}
reconfigure_config_json() {
local arg="$1"
jq "$arg" </etc/element-web/config.json | sponge /etc/element-web/config.json
}
configure_element() {
# determine webserver domain
local element_domain webserver_type homeserver_name homeserver_info
webserver_type=$(ask_debconf_question "element-web-installer/configure-webserver" "high")
if [ "$webserver_type" != "none" ]; then
element_domain=$(ask_debconf_question "element-web-installer/domain" "high" "$(hostname -f)")
fi
homeserver_name=$(ask_debconf_question "element-web-installer/matrix-homeserver-name" "high")
case "$webserver_type" in
apache2)
sed -i "s|ServerName.*$|ServerName $element_domain|g" /etc/apache2/sites-available/element-web.conf
if [ ! -e "/etc/apache2/sites-enabled/element-web.conf" ]; then
mkdir -p /etc/apache2/sites-enabled/
ln -s ../sites-available/element-web.conf /etc/apache2/sites-enabled/
if [ -x /usr/sbin/apache2 ]; then
service apache2 reload || true
fi
fi
;;
nginx)
sed -i "s|server_name .*$|server_name $element_domain;|g" /etc/nginx/sites-available/element-web
if [ ! -e "/etc/nginx/sites-enabled/element-web" ]; then
mkdir -p /etc/nginx/sites-enabled/
ln -s ../sites-available/element-web /etc/nginx/sites-enabled/
if [ -x /usr/sbin/nginx ]; then
service nginx reload || true
fi
fi
;;
none)
;;
*)
echo >&2 "Ignoring unknown webserver type for element-web: $webserver_type"
;;
esac
# discover the homeserver information
if homeserver_info="$(curl --silent --fail "https://$homeserver_name/.well-known/matrix/client")" \
&& [ -n "$homeserver_info" ] \
&& printf '%s' "$homeserver_info" | jq . >/dev/null 2>/dev/null; then
# inject the "server_name" if it is missing (it is not part of the well-known/matrix/client response)
if [ -z "$(printf '%s' "$homeserver_info" | jq -r '.["m.homeserver"].server_name // ""' >/dev/null)" ]; then
homeserver_info=$(printf '%s' "$homeserver_info" | jq '.["m.homeserver"].server_name |= "'"$homeserver_name"'"')
fi
reconfigure_config_json '.default_server_config |= '"$homeserver_info"
else
reconfigure_config_json '.default_server_config |= {"m.homeserver": {"base_url": "https://'"$homeserver_name"'", "server_name": "'"$homeserver_name"'"}}'
fi
# disable statistics gathering
reconfigure_config_json 'del (.piwik)'
reconfigure_config_json '.roomDirectory.servers |= ["'"$homeserver_name"'"]'
}
if [ "$1" = "configure" ]; then
/usr/sbin/element-web-installer upgrade
if [ ! -e "$CONFIG_DIR/config.json" ]; then
echo "Creating sample $CONFIG_DIR/config.json. Please adjust its content."
cp "$WEB_DIR/config.sample.json" "$CONFIG_DIR/config.json"
# create the symlink to config.json
/usr/sbin/element-web-installer apply-configuration
fi
configure_element
fi
set +eu
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.
#DEBHELPER#
exit 0
#!/bin/sh
set -eu
CONFIG_DIR=/etc/element-web
if [ "$1" = "remove" ] || [ "$1" = "purge" ]; then
rm -f "$CONFIG_DIR/config.json"
rm -f /etc/apache2/sites-enabled/element-web.conf
rm -f /etc/nginx/sites-enabled/element-web
for directory in /etc/apache2/sites-enabled /etc/nginx/sites-enabled; do
if [ -d "$directory" ]; then
rmdir --parents --ignore-fail-on-non-empty "$directory"
fi
done
fi
set +eu
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.
#DEBHELPER#
exit 0
Template: element-web-installer/domain
Type: string
Description: Domain served by element-web:
Template: element-web-installer/configure-webserver
Type: select
Choices: none, apache2, nginx
Description: Configure a webserver?
Template: element-web-installer/matrix-homeserver-name
Type: string
Default: matrix.org
Description: Name of the default Matrix homeserver:
# The following settings connect the matrix server to the grouprise instance.
# Most likely these settings do not require changes by local admins.
enable_registration: false
password_config:
enabled: true
password_providers:
- module: "grouprise.auth.matrix_synapse_auth_grouprise.GroupriseAuthProvider"
config:
enabled: true
settings_filename: /etc/grouprise/settings.py
# The following settings provide usable defaults for a matrix-synapse setup.
# These settings are not related to grouprise and may be adjusted by the local administrator.
listeners:
- port: 8008
tls: false
bind_addresses:
- '::'
- '0.0.0.0'
type: http
x_forwarded: true
resources:
# openid is required for matrix-dimension
- names: [client]
compress: true
- names: [federation]
compress: false
# the server is accessed via an SSL terminating proxy
no_tls: True
database:
name: psycopg2
args:
user: grouprise_matrix
password: secret_db_password
database: grouprise_matrix
host: localhost
cp_min: 5
cp_max: 10
# allow browsing the list of public rooms (e.g. via the element web interface)
allow_public_rooms_without_auth: true
allow_public_rooms_over_federation: true
enable_group_creation: true
# keep in sync with "client_max_body_size" in nginx site configuration
max_upload_size: "10M"
url_preview_enabled: true
url_preview_ip_range_blacklist: []
url_preview_ip_range_whitelist:
- '127.0.0.0/8'
- '10.0.0.0/8'
- '172.16.0.0/12'
- '192.168.0.0/16'
- '100.64.0.0/10'
- '169.254.0.0/16'
- '::1/128'
- 'fe80::/64'
- 'fc00::/7'
url_preview_accept_language:
- en
trusted_third_party_id_servers: []
location /stadt/chat/ {
alias /var/lib/element-web-installer/htdocs/;
}
server {
server_name example.org;
# for SSL: add "ssl http2"
listen 8448;
# for SSL: enable the certificate/key files
# for certbot: use "/etc/letsencrypt/live/" instead of "/var/lib/dehydrated/certs/"
#ssl_certificate /var/lib/dehydrated/certs/example.org/fullchain.pem;
#ssl_certificate_key /var/lib/dehydrated/certs/example.org/privkey.pem;
include snippets/grouprise-matrix.conf;
}
# matrix federation
location /_matrix {
proxy_pass http://localhost:8008;
include proxy_params;
client_max_body_size 10M;
}
#!/usr/bin/dh-exec
debian/grouprise-matrix.d/matrix-site.yaml => /etc/matrix-synapse/conf.d/grouprise-matrix-site.yaml
debian/grouprise-matrix.d/matrix-authentication.yaml => /etc/matrix-synapse/conf.d/grouprise-matrix-authentication.yaml
debian/grouprise-matrix.d/nginx-element.conf => /etc/nginx/snippets/grouprise-element.conf
debian/grouprise-matrix.d/nginx-matrix-site => /etc/nginx/sites-available/grouprise-matrix
debian/grouprise-matrix.d/nginx-matrix.conf => /etc/nginx/snippets/grouprise-matrix.conf
#!/bin/sh
set -e
GROUPRISE_CONFIG_FILE=/etc/grouprise/settings.py
ELEMENT_CONFIG_FILE=/etc/element-web/config.json
. /usr/share/debconf/confmodule
db_version 2.1
# debconf does not work with "set -u", thus we enable it after loading debconf
set -eu
ask_debconf_question() {
local question="$1"
local priority="$2"
local default_value="${3:-}"
local RET
if [ -n "$default_value" ] && ( ! db_get "$question" || [ -z "$RET" ] ); then
# the value is not configured via debconf, yet
db_set "$question" "$default_value"
fi
db_input "$priority" "$question" || true
# shellcheck disable=SC2119
db_go || true
db_get "$question" || true
printf '%s' "$RET"
}
configure_grouprise_matrix() {
local grouprise_domain webserver_type
grouprise_domain=$(ask_debconf_question "grouprise/domain" "high")
webserver_type=$(ask_debconf_question "grouprise/configure-webserver" "high")
case "$webserver_type" in
nginx)
for filename in grouprise-matrix.conf grouprise-element.conf; do
if ! grep -q "include snippets/$filename" /etc/nginx/sites-available/grouprise; then
sed -i "s|\(include snippets/grouprise.conf;\)|\1\n include snippets/$filename;|" \
/etc/nginx/sites-available/grouprise
fi
done
sed -i "s|server_name .*$|server_name $grouprise_domain;|g" /etc/nginx/sites-available/grouprise-matrix
sed -i "s|example\.org|$grouprise_domain|g" /etc/nginx/sites-available/grouprise-matrix
if [ ! -e "/etc/nginx/sites-enabled/grouprise-matrix" ]; then
mkdir -p /etc/nginx/sites-enabled/
ln -s ../sites-available/grouprise-matrix /etc/nginx/sites-enabled/
if [ -x /usr/sbin/nginx ]; then
service nginx reload || true
fi
fi
;;