Administration Synapse

Administration graphique dans Hiboo

Nous opérons l’administration graphique dans Hiboo, pour :

Outil d’administration CLI

Plutôt que des outils d’administration complexes, nous utilisons pour administrer Synapse (notre serveur Matrix) une simple fonction Bash simplifiant l’accès à l’API. La documentation détaillée de l’API est disponible sur la documentation de synapse.

Pour installer la fonction, il faut ajouter dans son Bashrc (ou ZSHrc, ou équivalent) :

function synadm { curl -X "$1" -H "Content-Type: application/json" -H "Authorization: Bearer $SYNAPSE_TOKEN" "https://$SYNAPSE_HS/_synapse/admin/$2" "${@:3}" }

Pour l’employer, on commence par exporter les variables :

export SYNAPSE_HS=matrix.tedomum.net
export SYNAPSE_TOKEN=XXXXX

Puis simplement (en employant jq pour l’affichage JSON) :

synadm GET v1/rooms | jq .

Informations sur les utilisateurs

Ces commandes ne sont fonctionnelles que pour des utilisateurs locaux.

Rechercher un utilisateur contenant un mot clé :

# Afficher les profils
synadm GET 'v2/users?name=bot' | jq

# Afficher uniquement les mxid
synadm GET 'v2/users?name=bot' | jq -r '.users[].name'

Afficher le profil d’un utilisateur :

# Profil basique
synadm GET v2/users/@user:tedomum.net | jq

# Informations de connexion
synadm GET v1/whois/@user:tedomum.net | jq

# Toutes les IP connues de l'utilisateur
synadm GET v1/whois/@user:tedomum.net |  jq '.devices[].sessions[].connections | map(.ip) | unique'

Lister les objets d’un utilisateur :

# Salons de l'utilisateur
synadm GET v1/users/@kaiyou:tedomum.net/joined_rooms | jq

# Connexions en cours de l'utilisateur
synadm GET v2/users/@kaiyou:tedomum.net/devices | jq

# Media (à utiliser uniquement sur signalement de contenu illégal)
synadm GET v1/users/@kaiyou:tedomum.net/media | jq

# Cibles de notifications push
synadm GET v1/users/@kaiyou:tedomum.net/pushers | jq

Attention, la majorité des médias est chiffrée de base par les clients. Cette commande ne permet pas de vérifier le contenu d’un média (et tant mieux !), mais permet de détecter un spam de média par exemple (même taille sur des centaines de médias).

Créer un utilisateur

Lorsque les inscriptions sont closes, il est possible de créer un utilisateur en utilisant les commandes ci-dessous :

docker-compose exec synapse python /usr/local/lib/python3.7/site-packages/synapse/_scripts/register_new_matrix_user.py -c /data/homeserver.yaml http://localhost:8008

Le script demande une localpart – il s’agit du login utilisateur –, puis le mot de passe.

ATTENTION : dans notre cas, vu que Matrix est relié à Hiboo, il faudra utiliser l’option Claim a profile pour le relier à son compte Hiboo.

Modération sur les utilisateurs

Ces commandes ne sont fonctionnelles que pour des utilisateurs locaux.

Ne pas utiliser ces actions sauf si la suppression dans Hiboo fonctionne mal. Dans tous les cas, il convient de conserver l’information synchrone avec Hiboo.

Modifier le mot de passe de l’utilisateur force aussi sa déconnexion, sans nécessairement désactiver définitivement le compte. C’est ce qu’utilise Hiboo pour le blocage de compte, avec un mot de passe aléatoire jamais transmis à l’utilisateur qui s’authentifie de toute façon via Hiboo :

synadm POST v1/reset_password/@user:tedomum.net -d '{"new_password": "<mdp aleatoire>", "logout_devices": true}'

Désactiver un compte utilisateur est définitif, c’est l’action à mener pour la suppression manuelle lorsqu’elle est demandée via Hiboo. La purge correspond à la purge dans Hiboo : elle ne supprime pas tous les messages du compte puisque c’est techniquement impossible, mais elle les empêche de fédérer à l’avenir, donc d’être plus propagés qu’il ne le sont. Attention, c’est irréversible.

synadm POST v1/deactivate/@user:tedomum.net -d '{"erase": true}'

Le shadow ban est utile en gestion de crise lorsqu’un utilisateur change de compte pour contourner les ban, puisque le compte reste actif et laisse croire que le spam est bien envoyé. Attention, c’est irréversible.

synadm POST v1/users/@user:tedomum.net/shadow_ban

Gestion des rooms

Lister les rooms et en rechercher emploient la même commande :

# Lister les rooms sans critère
synadm GET v1/rooms | jq

# Chercher un mot clé
synadm GET 'v1/rooms?search_term=spam' | jq


# Lister tout dans un fichier (pour post-traitement)
synadm GET 'v1/rooms?limit=9999999' > rooms.json
jq < rooms.json

Pour obtenir les informations détaillées, la clé est toujours l’identifiant opaque de room et non un alias :

# Informations générales
synadm GET 'v1/rooms/!OhSiGLbNAQMVgDlMaF:tedomum.net' | jq

# Lister les membres
synadm GET 'v1/rooms/!OhSiGLbNAQMVgDlMaF:tedomum.net/members' | jq

# Lister les membres locaux
synadm GET 'v1/rooms/!OhSiGLbNAQMVgDlMaF:tedomum.net/members' | jq '.members[] | select(. | endswith(":tedomum.net"))'

# Etat de la room (membres, options, privilèges, etc.)
synadm GET 'v1/rooms/!OhSiGLbNAQMVgDlMaF:tedomum.net/state' | jq

Supprimer une room peut être utile lorsqu’elle est utilisée pour du spam, contient uniquement du contenu illicite, ou a un état problématique qui cause des bugs.

Supprimer une room ne la supprime que de notre serveur, n’exclut que nos utilisateurs, etc. Ne pas oublier que la room peut continuer d’exister sur les autres serveurs ; nous ne sommes pas modérateurs du réseau Matrix mais bien de notre serveur.

# Supprimer la room (en cas de spam par exemple)
synadm DELETE 'v1/rooms/!ROOMiD:tedomum.net' -d '{"block": false, "purge": true}'

# Supprimer et bloquer tout futur accès (room illégale)
synadm DELETE 'v1/rooms/!ROOMiD:tedomum.net' -d '{"block": true, "purge": true}'

Nettoyer l’historique d’une room permet de récupérer de l’espace, en particulier sur les rooms avec beaucoup d’activité en nombre de messages. Cela ne supprime pas les messages locaux :

# Attention au -30days pour configurer la date de purge
synadm POST v1/purge_history/!ROOMiD:tedomum.net' -d "{\"purge_up_to_ts\":\"$(date -d-30days +%s000)\"}"

Gestion des média

Nettoyer les média distants permet d’économiser de l’espace disque sur des médias qui ne sont que rarement consultés. Ils seront rechargés localement si un utilisateur les consulte.

# Attention au -30days pour configurer la date de purge
synadm POST "v1/purge_media_cache?before_ts=$(date -d-30days +%s000)"

Nettoyage du serveur

Afin de minimiser les ressources consommées par Synapse, certains nettoyages réguliers s’imposent. Pour cela, nous avons réalisé un script. Afin d’exécuter celui-ci, il suffit d’utiliser les commandes suivantes :

cd /srv/apps/matrix
./extemities.sh

D’autres actions sont décrites ci-dessous.

Supprimer les rooms vides

Les rooms ne sont pas automatiquement supprimées lorsque tous les utilisateurs locaux la quittent. Pour lister puis supprimer les rooms vides :

# Récupérer toutes les rooms dans un fichier
synadm GET 'v1/rooms?limit=999999' > rooms.json

# Lister les rooms vides, les compter
jq '.rooms | map(select(.joined_local_members == 0))' < rooms.json

# Compter les state events que cela représente
jq '.rooms | map(select(.joined_local_members == 0)) | map(.state_events) | add' < rooms.json

# Supprimer les rooms concernées (attention, long !)
jq -r '.rooms | map(select(.joined_local_members == 0)) | .[].room_id' < rooms.json | xargs -ti synadm DELETE 'v1/rooms/{}' -d '{"purge": true}'

Purger l’historique des plus grosses rooms

Pour obtenir la liste des plus grosses rooms, il est nécessaire d’exécuter directement la requête PostgreSQL suivante :

# Lister les rooms avec le plus d'événements (attention, lourd !)
SELECT room_id, stream_ordering, COUNT(event_id) AS c 
FROM events 
GROUP BY room_id, stream_ordering 
ORDER BY c DESC;

# Écrire le top 10 dans un fichier pour purger systématiquement les gros historiques
\copy (select room_id, stream_ordering, count(event_id) as c from events group by room_id, stream_ordering order by c desc limit 10) to /tmp/purge.txt;

Pour purger l’historique des salons en question :

# Une seule room
synadm POST 'v1/purge_history/!ROOMiD:tedomum.net' -d "{\"purge_up_to_ts\":$(date -d-30days +%s000)}"

# Toutes les rooms du fichier purge.txt
# ATTENTION, la purge est asynchrone, les différents salons sont donc lancés en parallèle et l'opération est très lourde
xargs -ti synadm POST 'v1/purge_history/{}' -d "{\"purge_up_to_ts\":$(date -d-30days +%s000)}" < purge.txt

Optimiser la table d’états

Pour lister les salons avec le plus d’événements d’état :

# Trier les salons par événement d'état
jq '.rooms | sort_by(.state_events) | reverse | .[].room_id' < rooms.json

# Comparer le nombre total d'événements d'état par rapport au top 10 des rooms
jq '.rooms | sort_by(.state_events) | reverse | .[:10] | map(.state_events) | add' < rooms.json
jq '.rooms | sort_by(.state_events) | map(.state_events) | add' < rooms.json

Pour générer les fichiers SQL de compression d’état par room :

export POSTGRES_USER=matrix
export POSTGRES_PASSWORD=xxx

# Pour une room
synapse-compress-state -p "host=localhost port=5432 user=$POSTGRES_USER password=$POSTGRES_PASSWORD dbname=$POSTGRES_USER" -r "!ROOMiD:tedomum.net" -o "!ROOMiD:tedomum.net.sql"

# Pour toutes les rooms du top 100
jq -r '.rooms | sort_by(.state_events) | reverse | .[:100] | .[].room_id' < rooms.json \
 | xargs -ti synapse-compress-state -p "host=localhost port=5432 user=$POSTGRES_USER password=$POSTGRES_PASSWORD dbname=$POSTGRES_USER" -r "{}" -o "{}.sql" 

# Appliquer tous les SQL
ls *.sql | xargs -n 1 psql -i