Programmation
Thursday, 07 February 2013
|
Écrit par
Grégory Soutadé

Logo Dynastie

Après 7 mois de développement, la version 0.1 de Dynastie est en ligne. Dynastie est un générateur de blog statique, c'est-à-dire qu'il va générer un ensemble de pages HTML statiques à partir de modèles (template) et d'articles. Contrairement à l'ensemble des moteurs de site web dynamiques où les pages sont regénérées à chaque connexion. L'avantage d'un tel procédé est qu'on ne fait le travail qu'une seule fois. Il suffit ensuite de servir les pages qui existent déjà avec nginx (qui est très bon pour ça). On optimise ainsi le temps de réponse et la charge serveur (qui n'est pas très puissant).

C'est tellement simple à réaliser qu'il y a une multitude de générateur disponibles sur le net. J'aurais pu utiliser un de ceux là, mais il manquait plusieurs fonctionnalités :

  • Un éditeur WYSIWYG accessible via une interface web
  • Écrit en Python
  • La compression gzip des pages générées
  • Qui accepte le HTML en entrée
  • Qui n'utilise pas Disqus
  • Qui n'utilise pas Mako/Jinja/Cheetah (des moteurs Python)
  • Qui est simple

Au début, j'ai commencé par un site en PHP, mais j'ai rapidement abandonné au profit de Python et surtout du framework Django. J'ai tout de suite été conquis par sa simplicité. Bref, Dynastie supporte toutes les fonctions traditionnelles d'un blog et même plus :

  • Index dans l'ordre anti chronologique
  • Categories
  • Tags
  • Flux RSS/Atom
  • Commentaires (dynamiques et sans Disqus)
  • Recherche (dynamique)
  • éditeur WYSIWYG en ligne
  • Coloration syntaxique (avec Pygments)
  • Prévisualisation
  • Multi blogs
  • Multi utilisateurs
  • On ne regénère que ce qui est nécessaire

Les principes de Dynastie sont simples :

  • Les articles sont stockés dans des fichiers HTML séparés
  • Les méta informations (titres, tags, commentaires, ...) sont stockées dans une base de données SQLite ce qui permet une manipulation aisée
  • Les modèles sont stockés sous le dossier "sites/<nom du site>", ils sont constitués de pages HTML avec des directives en XML (contrairement à la plupart des générateurs) pour interagir avec le moteur

Lors de la génération, Dynastie mélange tous ces éléments dans le dossier "sites/<nom du site>_output". Il copie aussi tous les fichiers ne commençant pas par "_" (qui sont les fichiers de modèle en général). Mais ça ne s'arrête pas là : il est possible d'ajouter "à la volée" des commentaires ainsi que de faire des recherches dans les pages du site généré. C'est cet aspect à la fois DYNAmique et StaTIquE qui a donné son nom au générateur.

Tous ces éléments d'architecture justifient sa création, qui est plus qu'une simple copie. Bien sûr, le design général du site fait pitié, mais c'est simple et efficace !

Dynastie process

Thursday, 31 January 2013
|
Écrit par
Grégory Soutadé

Si vous avez des ennuis, prenez un avocat ! Vous aurez toujours des ennuis, mais vous aurez un avocat !

Aujourd'hui nous allons répondre à une problématique concernant la sécurité et le travail en équipe. Lorsque le travail requiert des besoins importants en terme sécurité, il arrive de devoir mettre en place des dossiers chiffrés pour protéger des documents confidentiels. Pour cela, la solution idéale est TrueCrypt : le volume sécurisé est monté et seul l'utilisateur peut y accéder (pas de montage réseau possible). Mais quand on travaille à plusieurs sur les mêmes documents, il faut créer un TrueCrypt par machine et synchroniser les fichiers "à la main"...

Travail en équipe avec TrueCrypt

Bref, ce temps est révolu. En combinant SSHFS et EncFS on peut créer des dossiers chiffrés et y accéder à distance de façon sécurisée (à tous les niveaux). Il faut mettre en place un "serveur" qui va centraliser les dossiers et une installation sur chaque client comme suit

Travail en équipe avec EncFS et SSHFS

Sur le serveur

Installer encfs

sudo apt-get install enfs

Éditer le fichier /etc/fuse.conf pour autoriser les utilisateur non root à utiliser fuse
Décommenter "user_allow_other"

La commande "ls -l /dev/fuse" devrait donner le résultat suivant

crw-rw---- 1 root fuse 10, 229 Jan 24 12:05 /dev/fuse

Si le groupe "fuse" n'a toujours pas accès à /dev/fuse, il faut redémarrer la machine (c'est le cas notamment sous Debian).

Créer un utilisateur spécifique pour le projet

sudo adduser PROJET

Ajouter l'utilisateur au groupe fuse

sudo adduser PROJET fuse

Démarrer un shell avec l'utilisateur PROJET

su PROJET cd

Créer le dossier qui sera chiffré

mkdir projet_enc

Faire le montage du dossier encfs dans le dossier "projet_enc_out"

encfs /home/PROJET/projet_enc /home/PROJET/projet_enc_out

Quitter

exit

Sur chaque client

Installer sshfs

sudo apt-get install sshfs

Éditer le fichier /etc/fuse.conf pour autoriser les utilisateur non root à utiliser fuse
Décommenter "user_allow_other"

La commande "ls -l /dev/fuse" devrait donner le résultat suivant

crw-rw---- 1 root fuse 10, 229 Jan 24 12:05 /dev/fuse

Si le groupe "fuse" n'a toujours pas accès à /dev/fuse, il faut redémarrer la machine (c'est le cas notamment sous Debian).

Ajouter courant l'utilisateur au groupe fuse

sudo adduser USER fuse

Créer le point de montage

mkdir projet_secret

Monter le dossier chiffré distant

sshfs -o uid=$UID gid=$GID PROJET@IP:/home/PROJET/projet_enc_out projet_secret

Démonter le dossier

Que ce soit sur le serveur ou sur le client, il n'y a qu'une seule commande

fusermount -u <point_de_montage>

Conclusion

À l'intérieur de ce dossier on peut ensuite créer un dépôt git et faire un clone : ça donne un git distant sécurisé (même si on a l'impression d'y accéder en local). On peut aussi inscrire les clés publiques pour l'utilisateur PROJET et donc restreindre l'accès à certaines machines uniquement, ce qui a pour effet de bord d'avoir un mot de passe différent pour chaque utilisateur et non un mot de passe commun !

Monday, 19 November 2012
|
Écrit par
Grégory Soutadé

GcaptchaZ est un petit soft qui permet de générer des CAPTCHA en ligne de commande. C'est la transcription en C du générateur PHP de Logz avec quelques modifications. Je trouve que les CAPTCHA générés sont beaucoup plus sympa et compréhensibles que les reCAPTCHA de Google et c'est 'à priori' le seul générateur en ligne de commande, les CAPTCHA étant normalement générés de manière dynamique et utilisés une seule fois.

Au début je voulais l'intégrer dans Dynastie, l'idée étant de générer un nombre fixe de CAPTCHA pour les commentaires, en gardant la correspondance fichier <--> résultat. Pour cela j'utilise une petite astuce : le nom du fichier devait être le résultat du CAPTCHA chiffré en AES 128 avec le MD5 d'une passphrase (ce qui évite aussi de lister les captchas si on les nomme avec un id incrémental). La seconde étape consiste à les répartir aléatoirement dans les commentaires et de vérifier qu'une adresse IP ne résout pas plus de trois fois le même CAPTCHA (en modifiant l'id dans le formulaire des commentaires).

Finalement il ne sera pas intégré (du moins pour le moment). En effet, lors de mes recherches je suis tombé sur une astuce plus intelligente. Le but des CAPTCHA est de n'être déchiffré que par un humain, ce qui a le désavantage d'énerver les utilisateurs quand ils sont incompréhensibles. Donc un CAPTCHA n'arrêtera pas un humain qui veut spammer un forum/blog... Par contre, les robots spammeurs remplissent automatiquement le formulaire de commentaire, l'astuce consiste donc à mettre un champ email invisible et de vérifier côté serveur s'il est rempli ou non.

Logo GcaptchaZ

Wednesday, 31 October 2012
|
Écrit par
Grégory Soutadé

This is a fast software DES implementation for 64 bits machines thats supports intel SSE instructions (SSE, SSE2, SSE3 and SSSE3). The x86_64 architecture lacks support for bit manipulation and the ones introduced by AMD are not used here. The main SSE instruction used is "pmovmskb" that will extract the most significant bit of each byte inside an XMM register. That allows to do linear permutations with few instructions, but for random permutations a simple mask-shift is used. The next generation of processors with AVX2 should includes some bit manipulation instructions that will even more speed up DES computation.

Currently, my implementation is about 10 times faster than the one in OpenSSL 1.0.1c, assembly optimized but 32 bits centered. The package includes a basic implementation in full C (des.c) for algorithm comprehension and the fast implementation in fast_des.c. fast_des.c is linked with the libcrypto.a of OpenSSL (configured with linux-x86_64) to do benchmarks. The benchmark is to do 1 000 000 full DES computation. I obtained these values :

fast_des.c Init value 123456789abcdef Fast des Time 0 29333426 85e813540f0ab405 Des Time 0 362639005 85e813540f0ab405 des.c : Init value 123456789abcdef Time 0 236431885 85e813540f0ab405

My configuration is compounded by an intel core i5 m450 @ 2.4Ghz, 4Gb of RAM, Linux 64, gcc 4.7.1. One funny thing is that if I compile fast_des.c with -O3 flag, performances dramatically falls just under OpenSSL implementation. On an core 2 duo E7500 @ 2.93GHz :

Init value 123456789abcdef Fast des Time 0 110037322 85e813540f0ab405 Des Time 0 352010444 85e813540f0ab405

Source file can be found here.

Monday, 22 October 2012
|
Écrit par
Grégory Soutadé

Working with OpenOffice/LibreOffice Spreadsheets with Python One improvement of OpenOffice was to introduce Python scripting beside VBA one. You can do internal or external scripting. External scripting is done via Python UNO interface, it's like CORBA objects (...). But resources on web are poor and sparse. Only two websites have a clear and complete information :
https://www.wzdftpd.net/downloads/oowall/pyUnoServerV2.py
http://stuvel.eu/ooo-python

This is a mini HOWTO you can use in your external scripts First you have to start server side OOo/LO :

libreoffice "--accept=socket,host=localhost,port=2002;urp;" --invisible

If you don't want to see OOo/LO interface, add --headless. WARNING: You need to close ALL OOo/LO instances before starting server !

Next, load a document :

def connect(port, filename): # get the uno component context from the PyUNO runtime localContext = uno.getComponentContext() # create the UnoUrlResolver resolver = localContext.ServiceManager.createInstanceWithContext( "com.sun.star.bridge.UnoUrlResolver", localContext) # connect to the running office ctx = resolver.resolve("uno:socket,host=localhost,port=" + str(port) + ";urp;StarOffice.ComponentContext") smgr = ctx.ServiceManager # get the central desktop object DESKTOP =smgr.createInstanceWithContext("com.sun.star.frame.Desktop", ctx) url = unohelper.systemPathToFileUrl( os.path.abspath(filename)) doc = DESKTOP.loadComponentFromURL(url, '_blank', 0, ()) return doc

You can get sheets inside document by creating an enumeration :

doc = connect(port, filename) sheets = doc.getSheets() sheet_enum = sheets.createEnumeration() while sheet_enum.hasMoreElements(): sheet = sheet_enum.nextElement() print sheet.getName()

Retrieve cells :

cell = sheet.getCellByPosition(col, row)

You can use following methods on cell objects : XCell

To retrieve cell type (CellContentType) :

cell.getType()

For me object (or enumeration) comparison fails, so I use string comparison :

if cell.getType().value != 'EMPTY':

cell.getValue() will return cell float value (0.0 if cell is empty or text). Most of the case you need to cast it into int value : int(cell.getValue()) or do all your code with float values !!

Be careful, sometimes cells values are formated with text but contains float/integer !! value = value_cell.getString() will return "0x45"

Now you have all basics to do a spreadsheet parser ! If you don't know how to handle an object, juste print it and look at its supportedInterfaces dictionary, OOo API doc will tells how to handle them.