PROJET AUTOBLOG


Planet-Libre

source: Planet-Libre

⇐ retour index

Chimrod : Pelican, disqus, et vie privée

dimanche 9 août 2015 à 00:00
Privacy !

Image: Frankielon (creativecommons)

Le moteur de blog statique propose nativement un plugin pour gérer les commentaires avec disqus. Il permet de donner un peu de dynamisme au blog, qui est entièrement statique… Sauf qu’il s’agit d’un service non libre, qui enregistre les données des utilisateurs…

Le plugin disqus_static permet d’intégrer à la page html les commentaires trouvés sur le service disqus. Cela permet de les inclure nativement dans l’article, et évite au lecteur du blog d’informer disqus de sa navigation sur le site. Voici la manière dont je l’utilise sur le blog.

Attention!

Cette configuration est moins pire que celle proposée par défaut par le blog, mais elle continue d’enregistrer l’ensemble des commentaires auprès d’une entreprise privée. Mieux vaut, si vous en avez la possibilité, basculer sur une solution hébergée comme isso.

Création du compte

En suivant la documentation du plugin, on enregistre notre application sur le site de l’api de disqus :

Configuration du compte

Le compte n’a besoin d’accéder aux commentaires qu’en mode lecture, penser aussi à renseigner le nom de domaine utilisé par le blog dans les paramètres du compte.

Configuration du plugin

Le compte et la clef seront renseignés dans un fichier à part, que nous allons nommer disqus.py. Normalement, il devrait juste contenir ces lignes:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Configuration des commentaires
DISQUS_SITENAME='Votre compte disqus'
DISQUS_SECRET_KEY = u'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
DISQUS_PUBLIC_KEY = u'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'

Pour éviter de diffuser ce fichier sur un serveur git public, ne pas oublier de l’ajouter au fichier .gitignore! Ainsi, nous serons sûr que notre clef privée ne sera jamais transmise sur internet…

Dans le fichier publish.conf, nous allons ajouter le chargement du plugin:

import sys
import os.path
try:
    sys.path.append(os.path.dirname(os.path.abspath(__file__)))
    from disqus import *
    PLUGINS.append("disqus_static")
except:
    pass

Cela permet de génerer le blog, même si la configuration pour les commentaires n’est pas présente.

Utiliser le fichier publish.conf permet de générer le blog sans faire appel à l’API pour éditer le blog, par contre, ceux-ci seront intégrés dès que l’on lancera la commande make publish pour publier le blog.

Changement du template

Maintenant que tout est prêt, il ne reste plus qu’à modifier son template pour éviter de charger disqus automatiquement. C’est dommage d’intégrer les commentaires dans la page, si ceux chargés par disqus sont affichés automatiquement…

Sur mon blog, il faut cliquer sur le bouton pour recharger les commentaires (ou pour en ajouter de nouveaux). C’est juste un peu de javascript, et vous pouvez vous inspirer de ce bout de code:

{% if DISQUS_SITENAME %}

 class="comments">

Commentaires :

id="disqus_thread"> {% if article.disqus_comments %} class="post-list"> {% for comment in article.disqus_comments recursive %} class="post"> class="post-content"> class="avatar hovercard"> alt="Avatar" src="{{ comment.author.avatar.small.cache }}">
class="post-body">
class="publisher-anchor-color">{{ comment.author.name }} class="time-ago" title="{{ comment.createdAt }}">{{ comment.createdAt }}
class="post-message-container"> class="post-message publisher-anchor-color "> {{ comment.message }}
{% if comment.children %} class="children"> {{ loop(comment.children) }} {% endif %} {% endfor %} {% else %} Aucun commentaire pour l'instant. {% endif %} id="disqus_comments"> onclick="load_disqus()">recharger <script type="text/javascript"> var disqus_identifier = "{{ article.url }}"; function load_disqus() { var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; dsq.src = '//{{ DISQUS_SITENAME }}.disqus.com/embed.js'; (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); var load_button = document.getElementById('disqus_comments'); load_button.parentNode.removeChild(load_button); }; {% endif %}

Gravatar de Chimrod
Original post of Chimrod.Votez pour ce billet sur Planet Libre.

Okki : Sortie de GNOME MPV 0.5

vendredi 7 août 2015 à 20:11
GNOME MPV 0.5

GNOME MPV, qui est une interface graphique en GTK+ au lecteur multimédia mpv, continue son petit bonhomme de chemin et vient de sortir une version 0.5 qui apporte les nouveautés suivantes :

Malheureusement, il n’a toujours pas droit à une traduction française.

Gravatar de Okki
Original post of Okki.Votez pour ce billet sur Planet Libre.

Articles similaires

Carl Chenet : Liens intéressants Journal du hacker semaine #32

vendredi 7 août 2015 à 00:00

Suivez-moi aussi sur Diaspora*diaspora-banner ou Twitter  ou sur Identi.ca

logo-journal-du-hacker

Pour cette 32ème semaine de 2015, 5 liens intéressants que vous avez peut-être ratés, relayés cette semaine par le Journal Du Hacker, votre source d’informations pour le Logiciel Libre francophone !

openshift

fsf

Pour ne plus rater aucun article de la communauté francophone, voici :

De plus le site web du Journal du hacker est « adaptatif (responsive) ». N’hésitez pas à le consulter depuis votre smartphone ou votre tablette !

Le Journal du hacker fonctionne de manière collaborative, grâce à la participation de ses membres. Rejoignez-nous pour proposer vos contenus à partager avec la communauté du Logiciel Libre francophone et faire connaître vos projets.

Et vous ? Qu’avez-vous pensé de ces articles ? N’hésitez pas à réagir directement dans les commentaires de l’article sur le Journal du hacker ou bien dans les commentaires de ce billet :)


Gravatar de Carl Chenet
Original post of Carl Chenet.Votez pour ce billet sur Planet Libre.

Monitoring-FR : Meetup Monitoring à Paris, le 2 septembre

jeudi 6 août 2015 à 16:47

Un Meetup Monitoring est organisé à Paris le 2 septembre 2015, à partir de 19h par la société SOMONE. Le but de cette rencontre est de discuter avec d’autres experts de la supervision, de l’hypervision et du capacity planning. Le lieu de rendez-vous est dans les locaux de la société CRITEO, à Paris, au 32 rue Blanche, 75009 Paris (Plan).
Au programme de la soirée :

Monitoring-fr sera présent et fera une présentation sur la « vision de la Supervision Libre en entreprise ». Si vous souhaitez nous rencontrer, nous poser des questions ou échanger avec d’autres experts, venez nombreux! Pensez à vous inscrire directement sur le site de l’événement.

Le programme des talks est défini. Voici les présentations programmées :
# Unofficial Centreon Repositories for Debian
Par Eric Coquard (@kermith72, http://sugarbug.web4me.fr/)

La genèse du projet Package Centreon pour Debian, quelques exemples d’installations, la problématique de Debian Jessie.

# Nouveautés de Zabbix 3.0
Par Steve Destivelle (@stevedestivelle, Consultant chez SOMONE, http://steve.destivelle.me/)

Présentation des nouveautés de la prochaine version majeure de Zabbix.

# Surveiller et maintenir ses applications Node.js avec Keymetrics.io
Par Alexandre Strzelewicz (@strzel_a, CEO et co-fondateur de Keymetrics)

Je présenterai rapidement PM2, le gestionnaire de processus pour Node.js, suivit d’une présentation de Keymetrics.io et  d’une démonstration de l’ensemble.

# La vision de la supervision libre en entreprise
Par Romuald FRONTEAU (@rfronteau, co-fondateur de Monitoring-fr)

Cette présentation va évoquer la perception et la maturité des entreprises avec les projets de supervision Open Source par rapport au solution éditrice en fonction d’une étude du CIGREF basé sur la « Gouvernance et la maturité des projets Open source en entreprises » et le retour d’expérience d’administrateur Supervision au quotidien.

Gravatar de Monitoring-FR
Original post of Monitoring-FR.Votez pour ce billet sur Planet Libre.

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

jeudi 6 août 2015 à 15:43
<style type="text/css">/* Styles pour Pygments (coloration syntaxique) */ .hll { background-color: #ffffcc } .c { color: #408080; font-style: italic } /* Comment */ .err { border: 1px solid #FF0000 } /* Error */ .k { color: #008000; font-weight: bold } /* Keyword */ .o { color: #666666 } /* Operator */ .cm { color: #408080; font-style: italic } /* Comment.Multiline */ .cp { color: #BC7A00 } /* Comment.Preproc */ .c1 { color: #408080; font-style: italic } /* Comment.Single */ .cs { color: #408080; font-style: italic } /* Comment.Special */ .gd { color: #A00000 } /* Generic.Deleted */ .ge { font-style: italic } /* Generic.Emph */ .gr { color: #FF0000 } /* Generic.Error */ .gh { color: #000080; font-weight: bold } /* Generic.Heading */ .gi { color: #00A000 } /* Generic.Inserted */ .go { color: #888888 } /* Generic.Output */ .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ .gs { font-weight: bold } /* Generic.Strong */ .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ .gt { color: #0044DD } /* Generic.Traceback */ .kc { color: #008000; font-weight: bold } /* Keyword.Constant */ .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ .kp { color: #008000 } /* Keyword.Pseudo */ .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ .kt { color: #B00040 } /* Keyword.Type */ .m { color: #666666 } /* Literal.Number */ .s { color: #BA2121 } /* Literal.String */ .na { color: #7D9029 } /* Name.Attribute */ .nb { color: #008000 } /* Name.Builtin */ .nc { color: #0000FF; font-weight: bold } /* Name.Class */ .no { color: #880000 } /* Name.Constant */ .nd { color: #AA22FF } /* Name.Decorator */ .ni { color: #999999; font-weight: bold } /* Name.Entity */ .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ .nf { color: #0000FF } /* Name.Function */ .nl { color: #A0A000 } /* Name.Label */ .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ .nt { color: #008000; font-weight: bold } /* Name.Tag */ .nv { color: #19177C } /* Name.Variable */ .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ .w { color: #bbbbbb } /* Text.Whitespace */ .mb { color: #666666 } /* Literal.Number.Bin */ .mf { color: #666666 } /* Literal.Number.Float */ .mh { color: #666666 } /* Literal.Number.Hex */ .mi { color: #666666 } /* Literal.Number.Integer */ .mo { color: #666666 } /* Literal.Number.Oct */ .sb { color: #BA2121 } /* Literal.String.Backtick */ .sc { color: #BA2121 } /* Literal.String.Char */ .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ .s2 { color: #BA2121 } /* Literal.String.Double */ .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ .sh { color: #BA2121 } /* Literal.String.Heredoc */ .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ .sx { color: #008000 } /* Literal.String.Other */ .sr { color: #BB6688 } /* Literal.String.Regex */ .s1 { color: #BA2121 } /* Literal.String.Single */ .ss { color: #19177C } /* Literal.String.Symbol */ .bp { color: #008000 } /* Name.Builtin.Pseudo */ .vc { color: #19177C } /* Name.Variable.Class */ .vg { color: #19177C } /* Name.Variable.Global */ .vi { color: #19177C } /* Name.Variable.Instance */ .il { color: #666666 } /* Literal.Number.Integer.Long */

(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 :

À 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:

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.

Gravatar de Goffi
Original post of Goffi.Votez pour ce billet sur Planet Libre.