goffi goffi
later messages

Configuration avancée du conteneur Libervia

Cet article fait suite à l'article de la semaine dernière indiquant comment installer Libervia en moins de 10 min. Nous allons voir aujourd'hui comment utiliser un certificat TLS existant, intégrer le conteneur dans une configuration Apache, ou lancer automatiquement le service au démarrage de la machine.

Utiliser votre certificat TLS existant

Au premier lancement des conteneurs, un certificat auto-signé est automatiquement créé pour pouvoir utiliser Prosody ou le serveur HTTPS de Libervia. Ce genre de certificat est très bien pour du test, mais d'une part provoquera un avertissement dans les navigateurs, et d'autre part son authenticité n'est assurée par aucun organisme (les certificats TLS sont signés par des organismes que votre navigateur et/ou système connaissent, ce qui permet de les valider – principe qui n'est pas idéal, mais c'est un autre sujet –).

Pour utiliser votre propre certificat plutôt que celui généré par les conteneurs, il faut utiliser la variable d’environnement SAT_CONT_TLS_DIR avec un chemin absolu vers vos certificats.

Il faut qu'à l'intérieur de ce dossier se trouvent les fichiers « libervia.key » pour votre clef privée, et « libervia.crt » pour votre certificat public. Ces noms de fichiers sont fixés car déjà configurés dans Libervia et Prosody, si vous voulez les changer il faudra changer les 2 configurations à l'aide de ./libervia_cont.sh config et ./libervia_cont.sh config prosody, comme indiqué dans le dernier article.

Au niveau des permissions des certificats, vous pouvez les laisser accessibles uniquement au « group ID » 9999 qui correspond au groupe « tls-cert » sur les conteneurs.

Let's Encrypt

Comme Let's Encrypt est (à juste titre) à la mode, voyons voir de plus près ce cas particulier.

Le but ici est de ne pas avoir à changer la configuration à chaque renouvellement, qui ont lieu au plus tard tous les 3 mois. Let's Encrypt met ses certificats (par défaut, adaptez au besoin) dans /etc/letsencrypt/archive/<votre_nom_de_domaine>, mais les noms de fichiers changent à chaque renouvellement, et met un lien symbolique vers les certificats en cours dans /etc/letsencrypt/live/<votre_nom_de_domaine>.
Vous ne pouvez pas utiliser directement /etc/letsencrypt/live/ car vous auriez des liens symboliques pointant dans le vide, il va falloir monter le dossier archive également.

La variable d'environement SAT_CONT_DK_EXTRA permet de spécifier des paramètres pour la commande « docker run » qui seront utilisés pour tous les conteneurs (sauf sat_data). Nous allons l'utiliser pour monter toute l'arborescence letsencrypt, comme suit :

export SAT_CONT_DK_EXTRA="-v /etc/letsencrypt:/etc/letsencrypt"

Il va falloir éditer les configurations de Libervia et Prosody pour pointer vers les bons fichiers.
Pour Libervia, utilisez ./libervia_cont.sh config puis spécifiez dans la section [libervia] :

[libervia]
tls_private_key = /etc/letsencrypt/live/<nom_domaine>/privkey.pem 
tls_certificate = /etc/letsencrypt/live/<nom_domaine>/cert.pem 
tls_chain = /etc/letsencrypt/live/<nom_domaine>/chain.pem

N'oubliez pas l'option tls_chain qui permet de spécifier la chaîne de validation.

Pour prosody, c'est ./libervia_cont.sh config prosody qu'il faut utiliser, vous devez avoir modifié votre option ssl pour qu'elle ressemble à :

ssl = {
        key = "/etc/letsencrypt/live/<nom_domaine>/privkey.pem";
        certificate = "/etc/letsencrypt/live/<nom_domaine>/fullchain.pem";
}

dans les 2 cas il faut bien évidemment remplacer <nom_domaine> par votre nom de domaine tel qu'il apparaît dans /etc/letsencrypt/live. Assurez vous aussi que les permissions sont correctes, vous verrez si Prosody ou Libervia n'arrivent pas à lire les fichiers à l'aide de docker logs -f prosody et docker logs -f libervia respectivement.

Intégration à un serveur Apache

Si vous avez déjà un serveur Apache qui tourne, vous préfèrez sans doute intégrer Libervia à la configuration existante plutôt que sur un port séparé.

Pour cela nous allons utiliser un « proxy inverse » (reverse proxy) qui va rediriger une adresse de votre domaine sur le serveur de Libervia.

Si vous avez une configuration HTTPS, elle sera gérée par Apache lui-même, donc commençons par désactiver le serveur HTTPS de Libervia, et par supprimer le message d'avertissement en cas de connexion HTTP. Éditez sat.conf à l'aide de ./libervia_cont.sh config, et mettez ceci dans la section [libervia] :

[libervia]
connection_type = http
security_warning = 0

Désormais seul le port HTTP sera disponible.

Maintenant, nous allons configurer apache pour qu'il redirige les URL correspondant à votre instance de Libervia vers le serveur. Dans le répertoire /etc/apache2/mods-available/ créez un fichier libervia.conf qui ressemble à peu près à ça :

<VirtualHost *:80>
    ServerName www.<votre-serveur.tld>
    ServerAlias <votre-serveur.tld> libervia.<votre-serveur.tld>
    ServerAdmin webmaster@votre-server.tld
    ErrorLog /var/log/apache2/libervia-error.log
    CustomLog /var/log/apache2/libervia-access.log
    ProxyPass / http://127.0.0.1:8080/ nocanon
    ProxyPassReverse / 127.0.0.1
    AllowEncodedSlashes On
    RequestHeader set X-Forwarded-Proto "http"

    <proxy *>
        Require all granted
    </proxy>
</VirtualHost>

Il faut bien entendu remplacer <votre-serveur.tld> par votre nom de domaine, adapter SeverName et ServerAlias à ce que vous souhaitez utiliser, ainsi que les ports pour qu'ils correspondent à ceux que vous utilisez en pratique (si vous avez tout laissé par défaut, les ports indiqués sont valables).

Quelques explications sur la configuration : Passons sur les premières lignes et VirtualHost qui sont des classiques de configuration Apache, vous trouverez les informations nécessaires facilement sur le web au besoin. Les directives qui nous intéressent ici sont à partir de ProxyPass.

  • ProxyPass indique à Apache de rediriger les connexions sur le serveur local au port 8080, soit l'instance en cours de Libervia. Notez bien le « nocanon » qui est très important, il indique à Apache de ne pas utiliser des adresses canoniques, soit en d'autres terme de ne pas modifier les URLs envoyées à Libervia.
  • ProxyPassReverse concerne les redirections
  • AllowEncodedSlashes est nécessaire pour accepter les URLs contenant des « / » (%2F), qui sont utilisées dans Libervia.
  • RequestHeader permet d'ajouter l'en-tête « X-Forwarded-Proto » indiquant à Libervia le protocol utilisé au niveau du proxy

Quand un proxy est utilisé, l'adresse utilisée « vue » de l'extérieur (http(s)://www.<votre-serveur.tld>/[…]) n'est pas la même que celle utilisée pour accéder par Libervia, qui est ici http://127.0.0.1:8080. Or Libervia a besoin de connaître cette adresse pour construire des chemins absolus vers les documents, par exemple dans le flux Atom.
Normalement, ceci est fait automatiquement et vous n'avez besoin de toucher à rien pour que Libervia utilise les bonnes URL ; mais si jamais les URL produites n'étaient pas correctes, vous pourriez utiliser l'option « base_url_ext » pour forcer l'utilisation de la base indiquée. Ainsi pour forcer l'utilisation de http://www.goffi.org, je peux indiquer ceci dans ma configuration Libervia :

base_url_ext = http://www.goffi.org

Ou même « //www.goffi.org » pour laisser Libervia gérer le schema (c.-à-d. le protocol : http ou https). Encore une fois tout ceci devrait être géré automatiquement (*), et il est très peu probable que vous ayez à utiliser cette option. Venez me contacter sur sat@chat.jabberfr.org pour plus d'explications si nécessaire.

Une fois la configuration faite, il vous suffit pour activer le proxy de demander à Apache de prendre en compte la nouvelle configuration. Nous allons également nous assurer que le mode proxy_http est activé, aussi nous allons utiliser les commandes suivantes (en root) :

# a2enmod headers
# a2enmod proxy_http
# a2ensite libervia.cont
# systemctl reload apache2

(*) si vous avez téléchargé les images la dernière fois, ce comportement a été modifié depuis, c'est l'occasion de tester « ./libervia_cont.sh update ».

Utilisation d'un cache

Apache a des modules permettant la gestion d'un cache, qui permettra à la fois d'économiser les ressources, et de fournir la dernière page connue en cas d'indisponibilité du serveur (lors d'une maintenance par exemple). Dans le cas de Libervia, c'est principalement utile pour le blog statique.

Assurez-vous d'abord que le cache est activé à l'aide de :

 # a2enmod cache_disk

qui activera à la fois les modules cache et cache_disk. Ensuite à l'intérieur de la configuration du VirtualHost que nous avons faites plus haut :

<IfModule mod_cache_disk.c>
    CacheEnable disk /
    CacheRoot "/var/cache/apache2/mod_cache_disk/libervia/"
    CacheDirLevels 3
    CacheDirLength 5
    CacheIgnoreHeaders Set-Cookie
    CacheMaxFileSize 200000000
    CacheIgnoreNoLastMod On
    CacheDefaultExpire 300
</IfModule>

Vous pourrez vous reporter à la documentation pour la plupart des directives utilisées ici, mais il est nécessaire d’en préciser quelques-unes :

  • CacheIgnoreHeaders Set-Cookie évitera de mettre en cache les cookies qui sont utilisés pour la session dynamique de Libervia, cette directive est essentielle pour la sécurité
  • CacheIgnoreNoLastMod On permet de mettre en cache des documents qui ne possèdent pas de date de dernière modification, ce qui est le cas actuellement des pages servies par Libervia
  • CacheDefaultExpire indique un cache qui expire après 10 min. Libervia ne gère pas (encore) les indications nécessaires à une gestion automatique du cache, aussi on indique ici la durée voulue. Le cache étant essentiellement utilisé pour le blog statique, j'ai mis 10 min pour qu'une mise à jour apparaîsse suffisament vite.

À moins d'avoir un site extrêmement populaire, il ne devrait pas y avoir de problème de performance pour le blog statique même sans cache, il est à mon sens surtout utile ici pour continuer à servir les pages pendant les maintenances.

Utilisation de tls

L'utilisation de TLS n'est pas plus compliquée que pour un autre site Apache.
Voici à quoi peut ressembler une configuration si vous activez le proxy, le chiffrement TLS, et un cache :

<IfModule mod_ssl.c>
<VirtualHost *:443>
        ServerName www.<votre_site.tld>
        ServerAlias <votre_site.tld> libervia.<votre_site.tld>
        ServerAdmin webmaster@<votre_site.tld>
        LogFormat "h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\" %{cache-status}e" with_cache
        ErrorLog /var/log/apache2/libervia-error.log
        CustomLog /var/log/apache2/libervia-access.log with_cache
        ProxyPass / http://127.0.0.1:8080/ nocanon
        ProxyPassReverse / http://127.0.0.1:8080/
        AllowEncodedSlashes On

        <proxy *>
                Require all granted
        </proxy>
        SSLCertificateFile /etc/letsencrypt/live/<votre_site.tld>/cert.pem
        SSLCertificateKeyFile /etc/letsencrypt/live/<votre_site.tld>/privkey.pem
        Include /etc/letsencrypt/options-ssl-apache.conf
        SSLCertificateChainFile /etc/letsencrypt/live/<votre_site.tld>/chain.pem

        <IfModule mod_cache_disk.c>
                CacheEnable disk /
                CacheRoot "/var/cache/apache2/mod_cache_disk/libervia/"
                CacheDirLevels 3
                CacheDirLength 5
                CacheIgnoreHeaders Set-Cookie
                CacheMaxFileSize 200000000
                CacheIgnoreNoLastMod On
                CacheDefaultExpire 300
        </IfModule>

</VirtualHost>
</IfModule>

Notez que le « RequestHeader set X-Forwarded-Proto » a désormais la valeur "https" ainsi que le « with_cache » dans les logs, ajoutant des informations utiles (est-ce que la page est servie par le cache ou Libervia ?).

Pour le reste, reportez-vous à la documentation Apache.

Démarrage automatique

Dernier point de cette partie sur la configuration avancée, nous allons voir comment lancer automatiquement notre instance de Libervia au démarrage de la machine. Nous allons pour cela utiliser SystemD qui est désormais le gestionnaire de démarrage par défaut de la plupart des distributions, donc probablement de la vôtre.
Il vous suffit d'utiliser une configuration similaire à la suivante, dans un fichier libervia.service à placer dans /etc/systemd/system :

[Unit]
Description=Libervia (Salut à Toi) XMPP Docker service
After=docker.service
Requires=docker.service

[Service]
User=libervia

Environment= \
SAT_CONT_DOMAIN=votre_domain.tld \
SAT_CONT_PORT_8080=8000

ExecStartPre=/home/goffi/dev/sat_docs/docker/libervia_cont.sh start -p
ExecStart=/usr/bin/docker wait libervia
ExecStop=/home/goffi/dev/sat_docs/docker/libervia_cont.sh stop

[Install]
WantedBy=multi-user.target

Ce fichier indique que le containeur doit attendre que Docker soit lancé. L'utilisateur ici est libervia, changez-le pour celui que vous avez ajouté au groupe « docker ».
Environment vous permet de configurer les options comme le port ou le nom de domaine utilisé, notez bien le "\" en fin de ligne (dernier caractère avant le retour à la ligne, sans espace) qui indique de considérer la ligne suivante comme la suite de la commande.

Le serveur est en fait lancé avec la directive ExecStartPre, afin de pouvoir connaître sont état avec « docker wait ». C'est une petite astuce qui évite des complications, car les conteneurs sont lancés par le démon Docker et non le script lui-même.

À suivre…

Voilà pour cette seconde partie de la série sur l'installation d'un blog Libervia. Ce n'était pas la partie la plus amusante, mais vous n'avez a priori à faire cette configuration qu'une seule fois, et elle n'est pas si compliquée que cela.

La prochaine fois nous importerons un blog depuis Dotclear.

Installer une instance de Libervia (SàT) en moins de 10 min

Bon avouons le tout de suite, je triche, 2 fois. La première c'est que nous allons utiliser les images Docker autrement dit des versions pré-installées et qui facilitent la vie. La deuxième c'est que quand je dis « moins de 10 min », je ne compte pas le temps de téléchargement de ces images, qui peut bien évidemment varier selon la vitesse de votre connexion.

Ceci dit, voyons comment avoir une instance de Libervia, l'interface web du projet « Salut à Toi », fonctionnelle de manière triviale. Pour mémoire il s'agit d'un outil de communication (d'aucuns parlent de « réseau social ») basé sur le protocole standard et ouvert « XMPP », et donc compatible avec la multitude de logiciels déjà existants.

Préparatifs

Docker

Il vous faut essentiellement avoir Docker installé sur votre machine. Sur une Debian ou dérivée (Ubuntu, Linux Mint – attention dans ce dernier cas, elle a récemment été compromise –, etc) il suffit de faire :

# apt-get install docker.io

En tant que root (c.-à-d. précédez de « sudo » si nécessaire). Dans les autres cas, reportez-vous à la documentation officielle.

Il faut ensuite vous ajouter au groupe « docker », ce qui devrait pouvoir se faire avec

# adduser <votre_nom_d_utilisateur> docker && newgrp docker

Ou, si vous avez sudo installé et configuré (c'est le cas sur Ubuntu par exemple):

# sudo adduser $(whoami) docker && newgrp docker

À partir de maintenant, il n'est plus besoin d'être root, vous pouvez faire la suite avec votre utilisateur normal, qui vient d'être ajouté au groupe « docker ».

libervia_cont.sh

La deuxième chose à faire est d'installer le script libervia_cont.sh qui aide grandement à la gestion des conteneurs de Libervia. Pour cela, il suffit d'entrer :

wget https://repos.goffi.org/sat_docs/raw-file/tip/docker/libervia_cont.sh && chmod a+x libervia_cont.sh

(si wget n'est pas présent, installez-le, par exemple avec « apt-get install wget »)

Lancement

Pour lancer Libervia, il vous faut maintenant entrer :

./libervia_cont.sh

Et c'est tout ! Si si, je vous assure, le script et Docker se chargent de télécharger les images (ce qui peut prendre un peu de temps selon votre connexion) et de les lancer, À la fin, vous allez voir une liste de ports s'afficher, en particulier vous devez avoir une ligne qui ressemble à :

port 8080 (HTTP):                       0.0.0.0:32771

Le numéro à la fin est le port choisi par Docker pour accéder à Libervia via HTTP, il vous suffit d'ouvrir votre butineur sur http://localhost:32771 (en remplaçant 32771 par le port que vous avez bien sûr) et vous devriez voir apparaître la page d'accueil de Libervia. Le serveur n'est accessible qu'après quelques secondes.

Libervia login

Plutôt simple non ? Bon comme c'était trop facile, voyons voir comment configurer tout ça.

Configuration

ports

Une des options les plus importantes est l'option -p, qui permet de lancer Libervia avec des ports fixes, ainsi vous pourrez atteindre Libervia sur le port 8080 et non un port qui change à chaque lancement.

Vous pouvez spécifier des ports différents grâce aux variables d'environnement SAT_CONT_PORT_xxxxxxxx est le port que vous voulez remplacer. Ainsi si vous voulez utiliser les ports 80 et 443 qui sont les ports standard HTTP et HTTPS, plutôt que 8080 et 8443, il vous suffit de faire, avant de lancer libervia_cont.sh :

export SAT_CONT_PORT_8080=80
export SAT_CONT_PORT_8443=443

nom de domaine

Si vous avez déjà votre nom de domaine (l'obtention d'un nom de domaine et sa configuration dépassent le cadre de cet article, mais les explications ne manquent pas sur le web), vous pouvez le spécifier avec l'argument -d ou avec la variable d'environement SAT_CONT_DOMAIN, exemple :

export SAT_CONT_DOMAIN=goffi.org

éditer les fichiers

Vous pouvez éditer le fichier de configuration de SàT/Libervia en tapant simplement

./libervia_cont.sh config

De même, pour éditer la configuration du Prosody intégré, faites

./libervia_cont.sh config prosody

Sauvegardes

Le script gère également les commandes de sauvegardes. Pour faire une sauvegarde, il suffit de taper

./libervia_cont.sh backup

Ceci crééra un fichier sat_data_backup_<date_de_sauvegarde>.tar.gz. Pour le restaurer plus tard, vous n'aurez qu'à faire

./libervia_cont.sh restore sat_data_backup_<date_de_sauvegarde>.tar.gz

À suivre…

Cet article est le premier d'une petite série où je vais vous expliquer comment mettre en place et publier dans un blog comme le mien (qui tourne désormais avec SàT/Libervia) grâce à ce que nous venons d'installer. La prochaine fois (demain ?) j'expliquerai la configuration avancée (certificat personnalisé, lancement automatique).

Si vous parlez anglais, l'utilisation des images Docker et du script libervia_cont.sh sont documentés sur le wiki.

Nous aimerions beaucoup faciliter l'installation de Libervia avec d'autres méthodes, par exemple avec des scripts pour YunoHost, un peu d'aide serait très appréciée, car nous sommes déjà bien chargés. Si vous pensez pouvoir participer, venez en discuter sur le salon sat@chat.jabberfr.org.

N.B. : comme vous l'avez vu l'image contient un serveur XMPP (Prosody) pré-configuré pour simplifier l'installation. Cependant Salut à Toi et donc Libervia marchent bien évidemment avec tout autre serveur (les fonctionnalités seront juste adaptées selon ce qui est disponible), et vous pouvez créer un profil externe, sur un autre serveur (vous pouvez même entrer directement un jid et un mot de passe existant dans Libervia). Il est probable qu'il existe de futures variantes de ces images sans serveur XMPP pré-installé, ou avec un autre.

Libervia (Salut à toi) 0.6.0 : des avancées majeures !

Salut à vous,

Nous avons le plaisir d'annoncer la sortie de Salut à Toi (SàT) 0.6.0 et donc de son interface web « Libervia ». Pour mémoire, SàT est un « couteau suisse de la communication », un outil libre et décentralisé permettant de partager publiquement ou de façon privée des messages, des fichiers, des articles de blog, de microblog, etc.

Le projet a de nombreuses fonctionnalités allant du chiffrement de bout en bout aux jeux, et peut également servir de base pour créer de nouveaux réseaux.
C'est aussi un projet éthique, géré par une association loi 1901, suivant un « contrat social », utilisant exclusivement des logiciels libres, militant pour la décentralisation, et fermement opposé à la publicité.


Cette version a vu un très gros travail sur le système de blogs : Libervia offre un moteur de blog décentralisé, accessible à des groupes restreints ou de l'extérieur, et entièrement basé sur le protocole standard et ouvert « XMPP ». L'utilisation de ce standard permet de communiquer avec d'autres projets comme Movim ou Jappix, créant ainsi un grand réseau libre.

Le partage de fichiers en pair à pair (P2P) a aussi été grandement amélioré grâce au protocole « Jingle », ouvrant la voie pour de futures applications comme la visioconférence.

L'annonce officielle est disponible sur le blog suivant (basé sur Libervia) : https://libervia.org/blog/salut-a-toi.

Une dépêche Linuxfr plus détaillée est en cours de modération et devrait être publiée sous peu.

Une campagne de financement participatif est en cours pour faire une version de bureau (une étape déjà franchie), et une version Android. Cette campagne étant très proche de la fin, c'est le moment de nous soutenir !


 http://ftp.goffi.org/media/screenshots/0.6/overview.png 

 

site officiel : http://salut-a-toi.org
démo : https://libervia.org
campagne de financement : https://www.arizuka.com/fr/projects/libervia
N'hésitez pas à nous contacter (http://salut-a-toi.org/community.html)

L'équipe « Salut à Toi »

Libervia/Salut à Toi à « fêtons Linux » (Lausanne 28/11/2015)

Un rapide billet pour vous dire que nous avons été invités à participer à « fêtons Linux », une journée de rencontre autour des logiciels libres et de Gnu/Linux.

J'y ferai 2 conférences, une technique de 45 min pour expliquer le cœur du projet (à 13h), et une plus grand public de 20 min (à 14h30), et bien sûr je serai présent toute la journée pour discuter (je passerai également par Genève s'il y a du monde qui veut s'y retrouver).

Un grand merci à l'organisation.

Nous avons également passé le premier palier pour notre campagne de financement, c'est à dire que nous sommes engagés à faire un prototype de version de bureau. Mais il nous manque encore un peu moins de 2000 € pour la version Android, et nous avons 2 semaines pour y arriver, aussi faite tourner ce lien partout ou vous pouvez, nous avons besoin d'un coup de pouce pour nous faire connaître : www.arizuka.com/fr/projects/libervia (ou en anglais: www.arizuka.com/en/projects/libervia). Merci !

Je n'ai pas eu le temps d'écrire d'article cette semaine car je suis débordé par le développement : nous espérons sortir la nouvelle version très bientôt.

À bientôt

N.B.: j'ai dû temporairement mettre la modération a priori sur les commentaires, j'ai depuis 2 semaines une vague de spam qui passe les filtres en place.

centralisé, décentralisé, P2P, mais c'est quoi tout ça ?

Une petite mise au point technique, parce que je vois qu'il y a beaucoup de confusion sur les termes « centralisé » (encore lui ça va), « décentralisé », « distribué », « fédéré », « pair à pair », etc.

Il faut dire que la confusion est assez normale, il n'y a pas vraiment de définition de ces termes, et ce que les gens entendent en les employant dépend de leurs lectures, leur compréhension, et leur sensibilité.

Commençons par le plus simple : centralisé. Un système centralisé c'est un système où tout le monde dépend d'une même autorité, un serveur a priori dans le cas informatique. Bien qu'un système centralisé soit beaucoup plus simple à faire sur le plan technique (facile de trouver des gens ou des informations quand ils sont tous au même endroit), il peut avoir ses propres problèmes : montée en charge en particulier ; il est plus difficile d'absorber des données quand il n'y a qu'un centre de traitement, les tuyaux peuvent rapidement se trouver trop petits, etc.

Un système de communication centralisé pose de nombreux problèmes : il est évident qu'il est plus facile d'espionner, censurer ou modifier des données quand elles sont dépendantes d'un seul point. Même sans intention malicieuse, on a un point unique de défaillance (ce que les anglophones appellent « single point of failure »), c.-à-d. qu'une panne, une attaque, une catastrophe naturelle ou pas provoque l'arrêt du service voire la perte des archives.
Dans les cas les plus gros, on prend un hangar et on le remplit d'ordinateurs, ce sont les fameux centres de données ou « data centers ».

Là où ça se complique un peu, c'est qu'un système centralisé peut être physiquement en plusieurs endroits, ou utiliser des systèmes de répartition/répétition des données. Le principe est d'éviter l'engorgement ou les risques de pannes cités plus haut, mais même si ces machines sont séparées et communiquent entre elles à distance, elles sont a priori toujours sous la même autorité.


http://repos.goffi.org/sat_docs/raw-file/tip/schemas/decentralisation/centralised_simple.png


Passons maintenant aux systèmes décentralisés/distribués/fédérés. Certains vont pousser les haut-cris que je mette tout ça ensemble, parce qu'il n'y pas vraiment de définition et que chacun se fait plus ou moins la sienne.

« dé-centralisé » veut dire qui n'a pas de centre, ni plus ni moins. L'idée pour un système de communication, c'est que toute entité (individu, association, organisation, etc) puisse être une partie d'un réseau qui n'a pas d'autorité principale, et que ces autorités puissent parler entre elles.

On essaye ainsi d'éviter les problèmes de la centralisation, mais on se retrouve avec tout un tas de nouveaux problèmes, techniques pour la plupart : il est beaucoup plus difficile de retrouver des données ou des gens en plusieurs endroits, de se mettre d'accord sur la « langue » à utiliser pour communiquer (surtout quand on a des logiciels ou des versions d'un même logiciel différents), ou encore d'être sûr que la donnée qu'on a est à jour (est-ce que le message a été modifié ou supprimé ?).

« fédéré » est généralement employé pour parler de systèmes différents (noms de domaines différents par exemple, voire logiciels différents) qui peuvent communiquer entre eux. Un système décentralisé est fédéré par nature, sinon on a affaire à plusieurs systèmes centralisés indépendants. Disons que si on veut être pointilleux, on peut dire qu'un système décentralisé peut communiquer avec seulement certaines entités (je communique avec les serveurs de mon entreprise internationale, mais pas avec le reste du monde), et que la fédération implique l'idée que c'est ouvert à tous (ou presque, il y a souvent des gens qu'on ne veut pas, les spammeurs par exemple).

« distribué » ne devrait pas être employé pour les systèmes de communication. Le terme est normalement utilisé pour le calcul : si votre ordinateur a plusieurs processeurs, il distribue la charge de calcul entre eux, ou dans le cas de très grosses demandes (recherche par exemple), on peut demander à plusieurs machines distantes de faire chacun une partie d'une grosse opération mathématique. Dans ce cas, l'organisation de la répartition est souvent contrôlé par une même autorité (par exemple le laboratoire qui veut faire cette opération).
Par extension, le terme est aussi utilisé pour les systèmes de fichiers, et certains l'emploient pour les logiciels de communication, mais cela ne veut pas dire autre chose que décentralisé.


http://repos.goffi.org/sat_docs/raw-file/tip/schemas/decentralisation/decentralised_simple.png


Enfin, il y a le terme P2P ou « pair à pair » (« peer to peer » en anglais). En fait une connexion pair à pair n'est rien d'autre qu'une connexion directe entre 2 ordinateurs, mais on l'associe souvent aux technologies plus ou moins apparentées qui ont commencé à apparaître à la fin des années 90/au début des années 2000 et qui servaient (et servent toujours) principalement à partager des fichiers.

Après Napster (lancé mi 1999) qui était un bête système centralisé qui mettait en relation des machines pour une connexion directe, il y a eu beaucoup d'essais et d'évolutions pour trouver un système qui permet de se passer de serveurs, l'idée étant principalement de permettre au réseau de fonctionner même si on lui coupe l'accès à une partie de lui-même.

Je vous passe toutes les techniques qui sont utilisées : c'est un domaine très pointu, très intéressant, et qui demanderait facilement un livre pour être expliqué. Ça part des systèmes de répartition par propagation de proche en proche à la Usenet, jusqu'aux récentes chaînes de blocs (blockchain), en passant par les tables de hachage distribuée (Distributed Hash Table), etc.

Ce qui fait principalement la différence entre un système « décentralisé » et « entièrement P2P », c'est la place du serveur. Un serveur, dans les grandes lignes, c'est ce qui permet à votre logiciel (le « client ») de contacter d'autres clients via d'autres serveurs. Il est là pour tout un tas de raisons : identifier les gens, donner les bonnes données aux bonnes personnes, garder
les fichiers à donner à un client actuellement hors ligne quand il sera disponible, etc.
Si on supprime le serveur, inévitablement c'est votre client (ou un autre) qui va devoir se charger de ce travail, ce qui aura un impact sur votre bande passante, la charge de travail pour votre processeur (et donc la durée de vie de votre batterie le cas échéant), et compliquera la tâche de votre logiciel (plus difficile de savoir à qui parler et à qui faire confiance quand on n'a pas de serveur comme référence).

http://repos.goffi.org/sat_docs/raw-file/tip/schemas/decentralisation/fully_P2P_simple.png

Pour transformer un système décentralisé avec serveurs en système entièrement P2P (c.-à-d. sans serveur), je vais vous donner une recette : vous mettez un seul client sur votre serveur, et vous mettez le serveur et le client sur la même machine.
Bien sûr si vous voulez être vraiment indépendant, il va falloir supprimer le besoin de points de références, et en particulier le système de noms de domaine ou « Domain Name System ». C'est ce qui associe le nom de votre serveur (par exemple « libervia.org ») à l'adresse « IP » qui permet de vous retrouver sur Internet. Il va falloir aussi être capable de retrouver les données ou les gens un peu partout, et là on se retrouve avec les technologies intéressantes mais complexes évoquées plus haut (« D.H.T. », « Blockchain », « SuperPeer », etc).
 

Et XMPP dans tout ça ?

Je vais quand même parler un peu de XMPP. XMPP est un système dit « hybride », c'est à dire qu'il fonctionne normalement sur un modèle client/serveur, mais il peut faire du P2P à la demande (pour transférer un fichier ou faire de la visioconférence par exemple).
Il est même possible de fonctionner sans serveur sur un réseau local (comme expliqué ici), et il peut parfaitement devenir à terme un système entièrement P2P comme expliqué dans le paragraphe précédent.

Ceci dit, même si l'approche entièrement P2P est séduisante, je pense que l'architecture décentralisée sur un modèle client/serveur est un compromis bien plus efficace : elle limite le travail de votre client, permet une meilleure optimisation du trafic ou du calcul, et facilite l'échange asynchrone (quand deux personnes ne sont pas connectées en même temps). Bref, c'est tout sauf un modèle du passé comme on peut le lire parfois, et bien qu'il y ait plusieurs recherches et options intéressantes pour des systèmes entièrement P2P, il ne faudrait pas jeter le bébé avec l'eau du bain.

SàT: Comment ça marche ?

Salut à vous,

En parallèle de la série d'articles sur XMPP, j'en commence une pour expliquer « Salut à Toi », notre logiciel à tout faire basé sur ce protocole. Il y a beaucoup de choses qui tournent autour de ce logiciel, sur son organisation technique, sa philosophie, et ce qu'on peut faire avec. Aussi je vais faire des articles plus ou moins techniques (plutôt moins), et je vais bientôt expliquer quelques cas concrets d'utilisation.

Ce premier article est un peu technique, puisque je vais expliquer l'organisation générale du logiciel, et ce qu'elle a de particulier.

Donc pour vous donner une idée, SàT c'est dans les grandes lignes ça:

http://ftp.goffi.org/media/pictures/schemas/sat_simplified_overview.png

C'est un client XMPP. Si vous avez lu mes articles, vous savez que XMPP ne signifie pas que « messagerie instantanée », mais beaucoup, beaucoup plus de choses. Le projet SàT essaye non seulement de faire le maximum de ces choses, mais aussi d'expérimenter de nouvelles.

La partie centrale  est la partie « d'arrière-plan » ou « backend » en anglais. C'est elle qui gère le plus gros du logiciel. La partie à droite  sont les « frontaux » (« frontends » en anglais) ou encore les interfaces homme/machine. C'est elles qui gèrent tout l'affichage des informations, ou la réception des commandes et autres messages.

Ce qui fait la force de cette architecture, c'est qu'il est très facile de faire un nouveau frontal, et que le tout représente un seul client. Autrement dit : si vous créez un profil (voir plus bas) sur un frontal, il sera disponible sur tous les autres, si vous envoyez un message d'un côté, il sera visible sur tous les frontaux connectés, l'historique est commun, les fonctionnalités aussi.
En effet, quand on ajoute une fonctionnalité (les messages de groupe par exemple, la copie de fichier, les blogs), c'est dans le « backend » que nous le faisons, et elle se retrouve ainsi disponible partout. Évidemment dans certains cas ça demande du développement particulier pour les interfaces : nous avons un jeu de Tarot par exemple, et on ne dessine pas les cartes de la même manière dans l'interface console (appelée Primitivus) et dans l'interface web (appelée Libervia).

Les interfaces (ou frontaux) disponibles aujourd'hui sont:

  • Libervia : interface web 
  • Primivus : interface de console (avec des fenêtres de type ncurses
  • jp: ligne de commande, permet d'automatiser des tâches facilement, d'envoyer un fichier sans parcourir des menus, d'écrire depuis Vim, etc 

Nous avions une autre interface pour le bureau, appelée « Wix », mais nous l'avons abandonnée, car elle était peu pratique et peu utilisée. Notre campagne de financement en cours permettra de remplacer cette interface et par la même occasion de porter le projet sur Android.

Cette architecture a un autre avantage : il est facile d'intégrer SàT dans des logiciels existants, et avec n'importe quel langage de programmation, mais laissons cela de côté pour le moment.

SàT a également une architecture modulaire via l'utilisation de greffons (ou « plugins » en anglais) au niveau du  sur le schéma : le cœur ne gère que l'essentiel (messages simples, liste de contacts, système de logs, gestion des profils, etc), et toutes les fonctionnalités avancées sont disponibles sous forme de greffons (messages de groupe, blog/microblogs, syntaxes avancées, etc). L'idée est d'une part de pouvoir désactiver les fonctionnalités qu'on ne veut pas, et d'autres part de permettre d'étendre facilement le logiciel : un greffon sera d'autant plus intéressant qu'il sera disponible pour toutes les interfaces. Ainsi un de nos greffons gère les marque-pages (c.-à-d. une liste de salons de discussions) : ils sont utilisables à la fois avec Primitivus (en texte), avec Libervia (graphiquement via le web) ou encore avec jp (en ligne de commande). À terme nous comptons faire un système de téléchargement automatisé de greffons, un peu comme les dépôts de logiciels.

Nous avons besoin de travailler un peu côté serveur, pour notre composant PubSub ou notre annuaire par exemple, nous avons donc aussi quelques travaux de ce côté.

Enfin les profils dont je parlais plus haut sont des comptes locaux associés à un compte XMPP. Ainsi j'ai un profil pour mon compte sur le serveur jabber.fr et un autre pour celui sur libervia.org, je peux utiliser l'un ou l'autre ou les 2 en même temps.

Voilà pour une première introduction, un peu technique parce que je voulais expliquer l'originalité de l'architecture. La prochaine fois je pense parler un plus spécifiquement de Libervia, et du système de blogs/microblogs décentralisé.

N'oubliez pas que nous avons une campagne de financement en cours, et nous avons grand besoin de soutien ! Merci.

Parlons XMPP - épisode 9 - copie de fichiers et Jingle

(pour lire les épisodes précédents, suivez l'étiquette correspondante)

Bien que déjà répété un certain nombre de fois, je le redis : XMPP fait bien plus que de la messagerie instantanée. Une des fonctionnalités qui est apparue rapidement est la copie de fichiers, voyons cela de plus près

Le problème : XMPP étant du XML, il n'est pas vraiment adapté aux données purement binaires comme des fichiers. La solution est de passer par l'extérieur, c'est à dire une autre connexion non XML, et d'utiliser le flux XML pour la gérer, on parle de connexion « out-band ». Malheureusement, parfois il n'est pas possible d'établir cette connexion, alors on passe tout par le flux XML : c'est lent, peu efficace, mais ça fonctionne presque toujours, on parle de connexion « in-band » (qu'on pourrait traduire par « interne »).
Il y a aussi des cas où il est plus simple et efficace de rester « in-band », enfin surtout un : si on envoie très peu de données, comme une petite image (un avatar par exemple).

Comme souvent dans le monde XMPP, plusieurs solutions ont été proposées, expérimentées, parfois adoptées puis dépréciées, jusqu'à ce qu'on trouve et garde celle qui semble convenir le mieux, et qui est a priori la meilleure techniquement.
Commençons par la solution courante, appelée « Stream Initiation » (initiation de flux), elle est définie par la XEP-0095, et la copie de fichier l'utilise via la XEP-0096.

La copie de fichiers est la seule application qui utilise la XEP-0095. Nous avons 2 personnes en jeu : celle qui veut envoyer le fichier, qu'on appellera « l'expéditeur » (« sender » en anglais) et celui qui veut le recevoir, qu'on appellera « le destinataire » (« receiver » en anglais).

La XEP-0096 défini ce qu'on appelle un « profil » pour l'initiation de flux, le profil « transfert de fichier ». Elle sert principalement à transmettre les métadonnées du fichier : une description, sa taille, son nom, sa date de dernière modification, et un « hash », c'est à dire une somme de contrôle pour vérifier que le fichier a été correctement copié. C'est l'algorithme MD5 qui est utilisé ici, pourtant connu pour avoir des failles, même si elles ne sont pas dramatiques dans le cadre d'un transfert de fichier (l'expéditeur étant déjà validé par ailleurs).

Il est également possible d'indiquer une fourchette (« range ») à copier, c'est à dire un point de départ (« offset ») dans le fichier et une longueur (« length »), pratique si un transfert a été interrompu en plein milieu, par une coupure de courant par exemple.

Le reste, c'est la XEP-0095 qui s'en occupe, il s'agit juste de négocier la méthode à utiliser, le destinataire accepte ou non le flux, et choisi une des méthodes. Il y a 2 méthodes principales : la première est le transfert en interne (« In-Band Bytestreams », XEP-0047) qui se contente de transcoder les données en base64.

La deuxième (la XEP-0065, « SOCKS5 Bytestreams ») est plus intéressante, elle utilise SOCKS v5 pour établir une connexion externe (« out-band ») et tenter une connexion directe ou via un « proxy » qui est un élément externe relayant les données. L'utilisation d'un proxy est moins efficace qu'une connexion directe bien entendu (les données passent par un 3ᵉ point), mais est parfois nécessaire si une connexion directe est impossible à cause d'un pare-feu ou d'un NAT par exemple. XMPP permet, grâce à disco (la XEP-0030) de savoir automatiquement si votre serveur propose un proxy.
C'est donc la XEP-0065 qui est à l'origine du nom « proxy65 » couramment utilisé.
Petit détail qui a son importance : dans le cas du transfert direct, la connexion se fait du destinataire vers l'expéditeur (qui a ouvert un port pour l'occasion), aussi la connexion peut échouer dans beaucoup de cas (par exemple l'expéditeur est derrière un NAT). Une méthode a été faite pour améliorer la situation, mais elle n'a jamais été standardisée, vous pouvez la trouver ici : http://delta.affinix.com/specs/stream.html.

Voilà pour la méthode actuelle. Elle pose de nombreux problèmes : c'est uniquement l'expéditeur qui doit proposer et le destinataire accepte ou refuse, il n'y a pas de vraie méthode de secours (appelée « fallback » en anglais), c.-à-d. de méthode pour passer de SOCKS5 (ou « s5b ») au transfert « in-band » (ou « ibb »), et il y a souvent des difficultés pour établir une connexion directe comme expliqué au paragraphe précédent. Bref, ça n'est pas satisfaisant. Mais le problème est assez complexe, il n'est pas si simple de faire une connexion directe, c'est à dire pair à pair (ou « peer to peer » en anglais).

Heureusement, une nouvelle méthode est apparue, et elle est beaucoup plus souple et efficace : Jingle. Mais cet article étant déjà long, j'en parlerai la prochaine fois.

J'en profite pour annoncer que je vais commencer une série d'articles pour expliquer l'architecture et ce qu'on peut faire concrètement avec « Salut à Toi ».

Je vous rappelle aussi que nous avons une campagne de financement participatif en cours pour porter « Salut à Toi » sur Android et faire une version de bureau, et que nous avons bien besoin de soutien ! http://www.arizuka.com/fr/projects/libervia
Merci :)

Vous voulez du (micro)blogage, de la décentralisation et du chiffrement sur Android ?

Salut à vous !

 
Aujourd'hui nous lançons une petite campagne de financement participatif pour le développement d'une version Android de Libervia/Salut à Toi.
 
Nous souhaitons ici développer une application native, avec toutes les fonctionnalités avancées dont nous disposons déjà, telles que le (micro)blogage, le chiffrement de bout en bout via OTR (et il est possible que nous ajoutions OMEMO/Axolotl, une nouvelle méthode permettant de chiffrer les messages hors ligne ou dans une discussion de groupe), le partage de fichiers, ou des choses plus exotiques comme une télécommande universelle.
 
Ce développement fonctionnera également sur bureau (Gnu/Linux bien sûr, mais il devrait fonctionner sur d'autres plateformes comme Windows ou Mac OS X) avec la même interface.
 
Il existe déjà quelques clients Android (comme le très joli Movim de notre ami Edhelas, Conversations ou Xabber), mais aucun n'offre actuellement le même bouquet de fonctionnalités que Libervia/Salut à Toi, aussi ce développement sera un vrai plus.
 
D'autre part nous sommes particulièrement attentifs à l'éthique (cf notre contrat social) et nous sommes organsiés en association loi 1901 en autogestion, dans l'idée de faire une coopérative sur le long terme. Cette campagne est aussi l'occasion de tester un moyen de financement, et nous avons choisi Arizuka car ce site se concentre sur les projets de l'économie sociale et solidaire.
 
Voilà, donc maintenant on compte sur vous ! N'hésitez pas à poser vos question soit en commentaire, soit par courriel (goffi@goffi.org) soit sur notre salon de discussion XMPP: sat@chat.jabberfr.org
 
lien vers la campagne: http://www.arizuka.com/fr/projects/libervia
Salut à Toi: http://salut-a-toi.org
 

P.-S. : nous préparons aussi une (grosse) nouvelle version dans les semaines à venir, je ferai certainement une série d'articles pour expliquer les nouveautés et comment se servir de Libervia ou SàT en général.

Parlons XMPP - épisode 8 - PubSub et PEP

(pour lire les épisodes précédents, suivez l'étiquette correspondante)

Aujourd'hui nous allons expliquer dans les grandes lignes comment fonctionnent « PubSub » et « PEP », et voir à quoi cela peut servir. Cet article va reprendre en partie ce que j'ai dit à la conférence « PubSub, microblogage et XMPP » en juillet dernier aux RMLL.

PubSub signifie « Publish/Subscribe » (Publication/Abonnement), c'est un mécanisme qui permet à une ou plusieurs personnes de publier toutes sortes d'informations sur un endroit connu (qu'on appelle un nœud) et aux personnes qui le désirent de s'abonner, c'est à dire d'avoir accès au contenu et d'être averti des modifications, le tout avec un système d'accès simple. Il s'agit du patron de conception « observateur/observable » décentralisé et appliqué à XMPP.

Le fonctionnement est expliqué dans la XEP-0060, c'est une des XEPs les plus longues de XMPP mais le principe est relativement simple à comprendre. Sans reprendre le long glossaire du document, expliquons quelques termes :

  • le service PubSub est l'entité qui gère le mécanisme de publication, d'autorisation, d'abonnement, de notification. C'est une entité XMPP et un jid y est donc associé, c'est à lui que vous faites toutes les requêtes pour un nœud donné.
  • le nœud est un espace associé à une publication. On peut associer ça à l'adresse d'un flux Atom.
  • un « item » (élément) est une publication dans un nœud. On peut associer ça à un article dans un flux Atom.
  • cet « item » contient un « payload » (charge utile), c'est à dire un contenu significatif qui dépend de la fonctionnalité utilisée. En effet la XEP-0060 décrit un mécanisme générique et souple, qui est ensuite utilisé dans des cas pratiques par d'autres extensions.

Un service PubSub est généralement un composant de votre serveur, mais ça peut-être n'importe quelle entité : votre serveur lui-même (c'est le cas avec PEP que nous allons voir ci-dessous), ou un client voire votre client lui-même (mais c'est assez rare – je n'ai jamais vu de client le faire –, car en général on utilise le service de son serveur).

Le mécanisme général est très simple et centré sur les nœuds : chaque entité (associée à un jid) à un rôle lié à ce nœud selon qu'elle l'ait créé, qu'elle soit publieur, abonné, banni ou sans lien avec le nœud. À ces rôles sont donnés des autorisations : le droit d'écrire (avec le « publish model » ou modèle de publication) et le droit en lecture (avec l'« access model » ou modèle d'accès).

Reprenons de manière un peu plus formelle. Les rôles dont nous avons parlé sont appelés « affiliations », et on peut avoir les suivantes:

  • owner (propriétaire): en général celui qui a créé le nœud
  • publisher (publieur): celui ou ceux (il peut y en avoir plusieurs) qui ont accès en écriture
  • publish-only (publication seulement): droit d'écriture mais pas de lecture, c'est un cas peu fréquent.
  • member (membre): quelqu'un qui est abonné au nœud
  • none (rien): l'entité n'a pas de lien avec le nœud
  • outcast (banni): l'entité a été explicitement interdite d'accès au nœud

La section 4.1 de la XEP-0060 fourni un tableau qui montre les autorisations selon l'affiliation. Ainsi on voit que le propriétaire peut publier ou configurer un nœud.

Les modèles d'accès (pour la lecture) définis dans la XEP-0060 sont les suivants:

  • open (ouvert, public): tout le monde peut lire le nœud
  • presence (présence – oui je traduis même pour un seul accent –) : si une entité est autorisée à voir la présence du publieur, alors elle peut accéder au nœud
  • roster (liste de contacts): si une entité est dans un groupe défini (dans la configuration du nœud) de la liste de contacts du service pubsub, elle a accès au nœud.
  • whitelist (liste blanche): des entités sont explicitement autorisées dans la configuration du nœud

Et rapidement les modèles de publication:

  • publishers (publieurs): quelqu'un qui a l'affiliation publieur peut écrire
  • subscribers (abonnés): n'importe quel abonné peut écrire
  • open (ouvert/libre): tout le monde peut écrire

Il faut bien noter une chose essentielle dans PubSub : quand la combinaison autorisation/abonnement/configuration le permet, on reçoit une notification immédiatement quand un élément est publié, modifié ou supprimé. Autrement dit on n'est plus du tout dans l'analogie avec un flux Atom – où on doit aller vérifier régulièrement qu'il n'y a rien de nouveau –, on est prévenu si nécessaire. Ceci est beaucoup plus efficace, rapide, et économe en ressources.

Voilà pour la base. La XEP défini d'autres choses qu'il n'est pas forcément pertinent d'expliquer ici, comme les métadonnées ou les inscriptions temporaires. On peut toutefois s'arrêter sur les collections, qui ne sont que mentionnées dans la XEP-0060 mais décrites en détails dans la XEP-0248. Elles permettent de faire des arbres de nœuds, et ainsi de représenter des données avec des relations entre elles. Des exemples valent parfois mieux qu'un long discours: les collections peuvent être utilisées pour représenter un système de fichiers sur un disque dur, ou un arbre généalogique.

Tout ceci est souple, générique, puissant, et relativement facile à utiliser par un client. Mais la XEP étant très longue, et l'implémentation de la partie service plus complexe, les implémentations ont mis du temps à arriver (et encore aujourd'hui elles sont très inégales). Comme PubSub peut être intéressant même sans tout le mécanisme, une version simplifiée est décrite dans la XEP-0163: « Personal Eventing Protocol » (Protocole d'évènements personels).

Cette dernière se base sur PubSub, mais définit les règles suivantes qui simplifient beaucoup :

  • 1 compte (jid) = 1 service : probablement la règle la plus importante, elle évite d'avoir à chercher un service PubSub associé à un jid, puisque le service est l'adresse canonique (« bare jid ») de l'entité. Ainsi pour la microblogage (XEP-0277), il suffit de connaître le jid de la personne – le nœud étant défini dans la XEP – pour retrouver ses publications.

  • 1 publieur par nœud : le propriétaire et le publieur sont le même, et il n'y a qu'un publieur par nœud. On se coupe ainsi de l'édition collaborative par souci de simplification, et il faudra utiliser PubSub pour ce genre d'applications.

  • accès par présence par défaut : sans rien toucher, il suffit d'avoir quelqu'un dans sa liste de contacts (et qui a accès à la présence) pour qu'il soit autorisé à voir nos publications

  • notifications filtrées sur l'intérêt exprimé : pour éviter d'être submergé de notifications, une entité/un client doit explicitement indiquer qu'il est intéressé par tel ou tel nœud

  • options par défaut au plus simple

PEP était utilisé au début pour des événements (sans grand intérêt à mon sens) comme l'humeur ou la musique en cours d'écoute, mais depuis son utilisation a évolué.

Voici, pour finir, quelques exemples d'utilisation de PubSub ou PEP:

  • enregistrement de données publiques ou semi-publiques (XEP-0222), par exemple une clef publique de chiffrement
  • enregistrement de données privées (XEP-0223), très utile pour n'importe quelle donnée de petite taille
  • les marque-pages (XEP-0048) utilisés pour les salons de discussions utilisent PEP (la XEP-0048 a été modifiée après l'apparition de PEP pour s'y adapter)
  • le microblogage bien entendu (XEP-0277), qui utilise PEP et utilise du Atom pour sa « charge utile » (« payload ») et un accès en général public. Les commentaires sont sur un nœud PubSub séparé, en général avec un modèle de publication par abonnement.
  • la XEP-0214 utilise PubSub et les collections pour faire un dépôt de fichiers
  • le futur protocole de discussions de groupe « MUC 2 » devrait se baser sur PubSub

PubSub pourrait aussi être utilisé pour placer des points sur une carte, faire un wiki, organiser des événements, ou encore gérer et surveiller une batterie de serveurs qui nous préviendraient en cas de problème.

Je reviendrai sûrement plus tard sur tout ça pour expliquer le microblogage ou d'autres extensions.

La prochaine fois, je pense vous parler de Jingle (mais pas de la partie vidéo-conférence). J'espère qu'à ce stade vous commencez à comprendre que XMPP n'est pas une technologie, mais un ensemble de technologies coordonnées et qui se réutilisent les unes les autres quand nécessaire.

J'ai un peu réduit le rythme des articles ces derniers temps car je travaille sur mon projet, et qu'une partie a été traduite en anglais avec l'aide de pas mal de monde (merci encore !), tout cela prend du temps.

Si vous venez à la fête de l'huma ce week-end, vous pourrez me trouver au village du libre, où Parinux me prête gentiment un bout de stand (merci aussi !). Je n'y serai pas en permanence, car je compte aussi profiter un peu de la fête :)

Parlons XMPP - épisode 7 - cas pratiques: SleekXMPP et SàT

(pour lire les épisodes précédents, suivez l'étiquette correspondante)

Comme cela a été demandé plusieurs fois, nous allons pour cet article faire un petit cas pratique avec deux bots XMPP.

SleekXMPP

c'est SleekXMPP que nous allons tester, que je n'avais jamais utilisé avant cet article. Il s'agit d'une bibliothèque Python qui se veut simple, avec peu de dépendances, et gérant tout avec des greffons. Vous pouvez aussi utiliser le fork (amical) fait pour Poezio, Slixmpp qui a réécrit le cœur de la bibliothèque pour tout gérer en asynchrone (sans thread) via le récent asyncio (aussi il faut une version de Python >= à 3.4, alors que SleekXMPP fonctionne avec Python 2 et 3).

Sans entrer trop dans les détails, que vous trouverez sur le site officiel avec plusieurs tutoriels (http://sleekxmpp.com/), faisons un simple bot qui répond à des commandes ad-hoc (aucun lien avec Tintin, voir plutôt l'épisode 6):

Ce script est une adaptation de l'exemple donné dans le dépôt officiel (voir sa licence). Des explications sont données après le script, et il devrait fonctionner avec Python 2.6 ou supérieur ou 3.1 ou supérieur.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sleekxmpp
from sleekxmpp import jid

JID="mon_super_bot@mon_super_server.tld"
PWD="mon_super_mot_de_passe"
ADMIN=jid.JID("mon_admin@mon_super_server.tld")
CMD_ENVOI = u'envoi message'
CMD_DECO = u'déconnexion'
CMD_ADMIN = u'gros bouton rouge'


class MonSuperBot(sleekxmpp.ClientXMPP):

    def __init__(self):
        sleekxmpp.ClientXMPP.__init__(self, JID, PWD)
        self.add_event_handler("session_start", self.session_start)
        # note 1
        self.register_plugin('xep_0030')
        self.register_plugin('xep_0004')
        self.register_plugin('xep_0050')
        self.register_plugin('xep_0199', {'keepalive': True, 'frequency':15})

    def session_start(self, event):
        # note 2
        self.send_presence()
        self.get_roster()
        self['xep_0050'].add_command(node='monbot',
                                     name=u'Commandes de monbot',
                                     handler=self._handle_commands)

    def _handle_commands(self, iq, session):
        form = self['xep_0004'].makeForm('form', 'bot')
        form['instructions'] = u'Choisissez une commande'
        options = [CMD_ENVOI, CMD_DECO]

        # note 3
        if session['from'].bare == ADMIN:
            options.append(CMD_ADMIN)

        form.addField(var='command',
                      label=u'commande',
                      ftype='list-single',
                      required=True,
                      options=options
                      )

        session['payload'] = form
        session['next'] = self._handle_command_complete
        session['has_next'] = False

        return session

    def _handle_command_complete(self, payload, session):
        form = payload
        command = form['values']['command']

        if command == CMD_ENVOI:
            self.send_message(mto=session['from'],
                              mbody="Message important !",
                              mtype='headline')
        elif command == CMD_DECO:
            self.disconnect(wait=True) # note 4
        elif command == CMD_ADMIN:
            # note 5
            if session['from'].bare == ADMIN:
                session['notes'] = [('warning', 'BOOM !')]
            else:
                raise ValueError("ce n'est pas un admin !")
        return session


if __name__ == '__main__':
    xmpp = MonSuperBot()
    if xmpp.connect(): # note 6
        print(r"\o/")
        xmpp.process(block=True)
    else:
        print(":(")

Explications

Après avoir importé sleekxmpp, nous utilisons quelques constantes (n'oubliez pas bien sûr de remplacer JID et PWD par des valeurs adaptées) pour simplifier, les exemples officiels permettent de manière plus élégante de préciser jid et mot de passe en ligne de commande.

Notre bot se comportera comme un client, nous héritons donc de sleekxmpp.ClientXMPP.

au niveau de la note 1 nous implémentons les greffons qui gèrent les XEPs qui nous intéressent :

  • disco (XEP-0030) pour annoncer ad-hoc, comme expliqué dans l'épisode 3
  • les formulaires de données (x-data, XEP-0004) et les commandes « ad-hoc » (commands, XEP-0050), expliquées dans l'épisode 6
  • la XEP-0199 permet d'envoyer et de répondre à des « pings », afin de s'assurer que la connexion et les logiciels sont toujours actifs.

À la note 2 nous envoyons notre présence et demandons la liste de contacts (« roster »), ce qui est requis par les RFCs, certains serveurs pouvant refuser de répondre si ce n'est pas fait.
Ensuite nous utilisons le greffon des commandes « ad-hoc » pour ajouter le point d'entrée à nos commandes.

Ce point d'entrée appellera la méthode « _handle_commands », et nous utilisons un formulaire (comme expliqué dans la XEP-0004) pour spécifier nos commandes. La liste « options » nous sert à indiquer nos commandes dans l'ordre voulu.

Au niveau de la note 3, nous profitons de l’identification forte de XMPP pour vérifier très simplement si le demandeur utilise l'adresse (jid) de notre compte privilégié, que nous avons indiqué dans la constante « ADMIN ». Nous aurons ainsi un jeu de commandes différent si nous utilisons le compte privilégié ou un autre.
Évidemment si vous voulez profiter de l'authentification forte, il faut vous assurer que tout est en ordre au niveau des certificats et du chiffrement (ce que fait a priori SleekXMPP de base, consultez la documentation pour plus d'informations).

L'ajout de commande se fait ici par une liste à choix unique (« list-single »), mais vous pouvez demander d'autres choses comme des mots de passe ou des jids, tout est expliqué dans la XEP-0004.

Quelques précisions sur ad-hoc : à chaque « page » vous pouvez effectuer une action:

  • cancel pour annuler
  • prev pour revenir en arrière
  • execute pour lancer une commande ou continuer la session
  • next pour passer à la page suivante
  • complete pour finir la sesssion

Ces actions sont gérées par sleekXMPP à travers le dictionnaire « session », la meilleure documentation que j'ai trouvée sur le sujet est le code lui-même : dans le fichier « sleekxmpp/plugins/xep_0050/adhoc.py » présent dans les sources.

Ad-hoc permet également d'indiquer un message, une « note », pour donner l'état de votre commande, elle peut avoir un type « info », « warn » (warning: attention) ou « error » (erreur).

Dans le code nous indiquons que nous avons notre dernière « page » par « session['has_next'] = False », et qu'il faut traiter la réponse dans « _handle_command_complete ». Oui c'est un peu contre-intuitif d’avoir à la fois has_next à False, et un next, mais ce dernier correspond à la réponse et non à une nouvelle page.

Passons à ces réponses. Nous regardons ce qui est dans le formulaire pour savoir quoi faire. Dans le premier cas nous envoyons un message manchette ou « headline » (voir l'épisode 2)

Dans le deuxième cas (au niveau de la note 4) on fait une déconnexion. Alors j'ai eu un problème ici avec SleekXMPP, que j'utilise pour la première fois comme indiqué plus haut : il faudrait pour faire propre terminer la session ad-hoc avant de déconnecter, mais je n'ai pas trouvé de moyen simple de le faire, vu que la déconnexion est immédiate et qu'il faut retourner le dictionnaire session pour terminer la séquence. Peut-être que je suis passé à côté de quelque chose, n'hésitez pas préciser en commentaire si vous avez une astuce.

Passons à la note 5: je refais une vérification du jid avant de lancer la commande privilégiée. La raison est simple: le formulaire est envoyé du client au bot par le serveur sans être vérifié par ce dernier, c'est au bot à le faire. Il est interdit d'ajouter une nouvelle commande, mais comme je doute que SleekXMPP conserve le formulaire d’origine pour vérifier qu'il n'y a rien de nouveau, un attaquant pourrait ajouter la commande privilégiée sans être admin. Cette vérification permet de l'éviter.

Pour faire propre il faudrait envoyer une réponse XMPP précisant que l'action est interdite, mais pour faire simple je me suis contenté d'une exception ici.

Enfin, au niveau de la note 6 on se connecte. Pour un serveur local de test, si vous n'avez pas de serveur DNS configuré comme il faut, vous pouvez spécifier l'adresse ip ou le nom de domaine local en dur, ainsi que le port (par exemple « self.connect(('localhost', 5222)) ». Si votre certificat n'est pas valide, vous pouvez aussi utiliser « use_tls=False » (pour les tests uniquement !). La documentation de SleekXMPP vous indiquera plus clairement comment gérer correctement les certificats.

Enfin, un autre problème que j'ai eu avec SleekXMPP: il ne semble pas possible avec ma version (1.3.1) d'indiquer de ne pas utiliser de commande « exécuter » ou de spécifier son équivalence (ce qui est pourtant possible avec la XEP-0050). Il faudrait qu'elle soit absente ou équivalent à « compléter ». Vous allez ainsi avoir un bouton qui sera inutile, et provoquera même une erreur. Là encore si quelqu'un plus habitué à la bibliothèque peut indiquer en commentaire comment corriger cela. Utilisez donc le bouton « compléter » (ou « finir ») et non « exécuter » de votre client.

Voilà la capture de notre bot piloté par Gajim:

bot piloté par Gajim

Salut à Toi

Pour indiquer les ajouts faits au code, nous utilisons un bot dénommé « Sabot ». Nous gérons les sources avec Mercurial (sur https://repos.goffi.org/). Celui-ci permet d'exécuter une commande via des crochets (« hooks »), dont un qui est lancé à chaque série de commits: incoming. Nous avons donc ceci dans notre hgrc:

[hooks]
incoming.sabot = /chemin/vers/hg_sabot_hook.sh

Pour le bot, nous profitons du côté multi-interfaces de SàT: SàT a une architecture qui permet pour un même client (et donc les mêmes profils, comptes, etc) d'avoir différentes interfaces (console, ligne de commande, bureau, web, etc).

Nous avons donc créé le compte comme un compte normal grâce à Primitivus, l'interface console (nous sommes sur un serveur sans interface graphique disponible). On peut joindre le salon désiré (ici sat@chat.jabberfr.org), et le mêttre en favori (grâce à la XEP-0048), ainsi que gérer l'entrée automatique (« autojoin »). Il ne reste plus qu'à envoyer le message quand le script hg_sabot_hook.sh est appelé, ce que nous faisons à l'aide de « jp », l'interface en ligne de commande:

#!/bin/sh

#on s'assure d'abord que D-Bus est lancé
eval `/chemin/vers/dbus-launch.sh`

REPOS_BASE="http://repos.goffi.org/sat"
PROJECT_FULL="Salut à Toi"
REPOS="$REPOS_BASE/rev/$HG_NODE"
MUC="sat@chat.jabberfr.org"

hg log -r $HG_NODE --template "Commit from {author|person} on $PROJECT_FULL\n{desc}\n$REPOS" | jp message -cp sabot $MUC

(le vrai script est un tout petit peu plus long puisqu'il gère aussi les noms des autres dépôts).

L'option « -c » indique de se connecter si ça n'est pas le cas, et « -p sabot » précise qu'il faut utiliser le profil « sabot »

Le script dbus-launch.sh s'assure juste que D-Bus est bien lancé et réutilisé entre les sessions de l'utilisateur:

#!/bin/sh
DBUS_PATH="/tmp/.dbus.`whoami`"
if [ ! -e $DBUS_PATH ]; then
        dbus-launch --sh-syntax > $DBUS_PATH
        chmod 400 $DBUS_PATH
fi
cat $DBUS_PATH

Voilà pour ces cas pratiques. La prochaine fois, je parlerai soit de PubSub, soit de Jingle.

Powered by Salut à Toi
Subscribe to this news feed Atom feed