Résultats des Opens du Web

Nous avons obtenus un total de 61 points, répartis de la façon suivante :

  • Damien à gagné 22 points sur les deux épreuves de développement
  • Kévin à gagné 14 points sur les deux épreuves d’intégration et aucun point avec son logo dans l’épreuve de design
  • J’ai gagné 25 points sur les 3 épreuves d’administration.

Bravo à Kévin, qui s’est sacrifié sur les épreuves d’intégration et design pour nous laisser faire les épreuves d’administration et de développement. Ce n’est pas son métier, et je ne suis pas certain que j’aurais réussi à ramener 14 points sur ces épreuves 😉

On a gagné les Opens du Web

Hier soir, Damien, Kevin et moi avons participé à la troisième édition des Open du Web à Paris. Et nous avons décroché la première place en équipe.

Les Opens du Web, c’est un concours dont les épreuves portent sur différents métiers du Web, à savoir programmation, intégration, design, administration, optimisation de référencement et gestion de communauté… Comme tous les trois, nous avons un profil de développeur, on pensait être mal partis. Les premières heures de l’épreuve nous ont confortés dans cette opinion. Et le dénouement a été une grande surprise…

Le concours avait lieu simultanément à Paris, Lille et Bordeaux. À Paris, il s’est déroulé dans les locaux de Sup’Internet. Et plus particulièrement, dans un parking souterrain digne des LAN de mon adolescence ;-). Ouvert aux quatre vents, il y règne un froid glacial, et la jolie demoiselle qui fait les présentations sur scène a bien du mal enthousiasmer la foule. Tristan Nitot dit quelques mots… Les participants s’installent, nous faisons connaissance avec les PC sous Ubuntu prêtés pour l’occasion… Quelques petits détails techniques réglés et nous pouvons attaquer ! Damien prend la programmation, Kévin, l’intégration, je prends l’administration…

La première épreuve est super simple : mettre en place une authentification par clés sur un serveur SSH. Je demande une machine virtuelle, deux minutes plus tard, je me logue. 30s plus tard, impossible de se reconnecter. Un organisateur vient et m’annonce que le serveur hôte est au bord du suicide, mais que les admins sont en train de lui remonter le moral, il faut patienter un peu. Quelques minutes plus tard, je peux enfin commencer à travailler. Première étape, je me crée des clefs pour pouvoir me connecter avec mon compte administrateur sur la machine. Je ne sais pas si c’est le stress du concours ou le froid, mais je me mélange les pinceaux et bloque au moins 30 minutes sur une erreur de débutant : le dossier .ssh n’avait pas le droit d’exécution ! Une fois cette bêtise réglée, je crée l’utilisateur demandé, copie la clé publique, tente de me connecter, mais rien : connexion impossible… J’active les logs de debug sur le client, puis sur le serveur. Et à force de fouiller, je me rend compte que la machine virtuelle fournie est configurée par défaut via PAM pour aller chercher les comptes SSH dans une base SQL distante. Je n’ai jamais vraiment bidouillé PAM, je tâtonne un peu. Une fois la config de PAM remise à plat, j’ai pu me connecter. Je désactive la connexion par mot de passe et valide mon épreuve. Ouf… Ça fait déjà plus d’une heure trente que je suis sur un exercice aussi trivial !

Pendant ce temps, mes collègues avaient fini depuis belle lurette leur première épreuve, mais un bug dans le système du concours les a empêché de passer à la seconde épreuve… Kévin qui avait fini en premier, pour ne pas perdre de temps, a eu le temps de valider la première étape de design avec un très joli logo. Damien m’a donné un coup de main pour résoudre mes soucis avec ma machine virtuelle… Nous voici donc prêt pour la deuxième épreuve… Il reste un tout petit peu plus d’une heure : c’est pas gagné…

Pour la seconde épreuve, il fallait configurer un pare-feu iptables ; facile ! Sauf que, si je le fais sur la machine virtuelle, je vais couper l’accès à ssh ?!? Après avoir demandé au jury si c’est bien ce qu’ils veulent, et une réponse à moitié satisfaisante, je décide de juste faire un script de configuration, libre à eux de l’exécuter pour se couper l’accès. Le voici :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/bin/bash

iptables -F
iptables -X

iptables -P INPUT DROP
#iptables -A INPUT -m conntrack --ctstate ESTABLISHED -j ACCEPT
#iptables -A INPUT -m state --state ESTABLISHED -j ACCEPT
iptables -I INPUT -p tcp -s 10.180.30.200 --dport 22 -j ACCEPT
iptables -I INPUT -p tcp --dport 443 -j ACCEPT
iptables -I INPUT -p tcp -s 10.180.30.200 --dport 80 -j ACCEPT

iptables-save > /etc/iptables.up.rules

cat <<EOF > /etc/network/if-pre-up.d/iptables
#!/bin/bash
/sbin/iptables-restore < /etc/iptables.up.rules
EOF
chmod +x /etc/network/if-pre-up.d/iptables

Hop, épreuve 2 validée, il reste environ 45 minutes… Pour l’épreuve 3, il faut faire un script de backup, qui télécharge des fichiers, vérifie les sommes de contrôle, mail l’admin en cas d’erreur, puis archive le tout en effaçant les archives de plus de 7 jours. Voici ma solution :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/bin/bash

URL=http://concours.open-du-web.fr/odw/adminsys-3/OK
MAILS="puyb@puyb.net jury-adminsys@open-du-web.fr"
ARCHIVE=/var/backup/$(date +%F-%T).tar.gz


DIR=$(mktemp -d)

cd "$DIR"
wget --quiet "$URL/files.md5"

for i in $(cut -d' ' -f3 files.md5); do
    wget --quiet "$URL/$i";
done

if ! md5sum -c files.md5 &> md5.log; then
    for i in $MAILS; do
        echo $(echo "Il y a une erreur dans le backup"; cat md5.log) | mail -s"Erreur dans le backup" $i;
    done
else
    mkdir -p "$(dirname $ARCHIVE)";
    tar -zcf $ARCHIVE *
    find "$(dirname $ARCHIVE)" -type f -mtime +7 -exec rm {} \;

fi;

cd -
rm -r "$DIR"

Ainsi que le script d’installation, qui a beaucoup plus au jury, malgré un petit bug qui écrase la crontab :

1
2
3
4
5
#!/bin/bash

cp backup.sh /usr/local/bin
chmod +x /usr/local/bin/backup.sh
echo "* 3  * * *   root    /usr/local/bin/backup.sh" > /etc/crontab

Voilà, il reste à peine 10 minutes, je décide d’aider Kévin dans la réalisation de son CSS. Il le validera quelques secondes avant la fin de l’épreuve.

Damien devait faire un blog en PHP, voici son code et un petit mot de lui :

Première épreuve, on nous donne une base de données et il faut faire une page web qui permet de se logger avec un formulaire (email + password) en créant une session.
Après avoir chargé le .sql dans mysql que je venais d’installer et d’avoir enfin démarré apache avec php activé, j’étais prêt à me lancer.
Globalement pour quelque chose de ce genre là, la partie SQL n’est pas très compliquée, il y avait une petite subtilité ici (1) mais rien de bien méchant. Comme à mon habitude je suis parti sur du PDO (2) pour faire les choses proprement et n’avoir aucun souci d’injection SQL. Un peu de temps pour me remettre dans le bain avec PHP et voilà la première épreuve de dev finie proprement avec tous les points bonus qui fonctionnent (notamment sécurité grâce à PDO et bouton de déconnexion).
Il y avait quelques soucis avec le portail des épreuves donc j’ai essayé d’aider Stéphane sur la partie admin sys (surtout soutenu moralement finalement ;)), une demie-heure plus tard je pouvais enfin passer à l’épreuve d’après.
La deuxième épreuve demandait d’afficher les posts contenus dans la base de donnée comme pour un moteur de blogs, avec possibilité de filtrer l’auteur et une affichage de la date de post un peu évoluée (style « Il y a 35 minutes »). La requète à la base de données est très simple. Après quelques minutes à choisir le format de sortie pour les posts (finalement un div avec titre en h2, sous-titre en h3 et texte derrière) et à fixer l’encoding en utf-8, le plus compliqué a été le formattage de la date, j’ai donc découvert les classes DateTime et DateInterval qui m’ont finalement permis de tout faire proprement !
Pour le filtrage j’ai affichée une petite liste avec les auteurs pour que ça soit plus simple, et puis voilà tout fonctionne bien.
Je m’aperçoit 10 minutes avant la fin en vérifiant le sujet qu’il faut afficher uniquement les 10 derniers posts par ordre chronologique ! Logique pour un blog. Heureusement c’est uniquement une modification à faire dans la requète SQL donc c’est fait sans problème lors des quelques dernières minutes.
Au final c’était assez étonnant de coder dans le froid, les doigts se déplacent moins rapidement ! Et le système d’épreuves m’a un peu rappelé prologin quand j’ai participé il y a plusieurs années ! Un peu de nostalgie, un peu de développement fun, un peu de pression à cause de la limite de temps tout en essayant de faire les choses proprement ! Merci Stéphane de m’avoir invité 🙂
(Petites notes en ce qui concerne le code, en faisant l’épreuve 2 je me suis aperçu que j’avais testé deux fois « user » dans REQUEST au lieu de tester « user » et « pass », et après avoir rendu l’épreuve 2 je me suis dit que j’aurais pu réutiliser la connexion à la base de données au lieu d’en créer une à chaque fois, mais j’ai pas vraiment eu le temps de le faire)

(1) La base de données contenait md5(userid . password). D’habitude on va calculer le hash en php, récupérer le hash depuis SQL et comparer les deux. Mais ici le hash est différent en fonction du userid (et non de l’email). Il y avait donc à mon avis plusieurs façons de faire, la première était de récupérer le userid et le hash, de calculer le hash avec le pot de passe donné et de comparer avec ce qui vient de la base de données, mais j’ai préféré le faire directement dans la base de données puisqu’elle sait le faire.
(2) Le point qui me tient particulièrement à coeur quand je manipule des bases de données, c’est d’éviter les injections SQL, pour ça il existe les « prepared statements » qui sont disponibles notamment dans mysqli, mais je préfère aller encore au-delà en utilisant directement PDO qui est plus intuitive à utiliser et permet même de facilement changer de type de base (mysql/postgresql/sqlite).

Épreuves 1 et 2 du défit « programmation » (zip)

Après avoir discuté un peu avec les recruteurs qui ne se sont pas déjà sauvés en courant ou ne sont pas morts de froid, et avec les autres participants, le verdict tombe : nous somme premier de la catégorie “équipes”… Surprise !

Vu les problèmes de machines virtuelles, le jury a décidé de ne pas nommer tout de suite de gagnant en catégorie admin. La délibération est en cours.

J’ai beaucoup apprécié de jouer ce petit jeu malgré le froid. À refaire !

Maintenant, je pense que l’organisation à encore plein de points a améliorer :
– Trouver un lieu plus accueillant… Je sais avec le concert à la fin, ce n’est pas facile de faire ça dans une salle de cours…
– Ne pas utiliser de Wi-Fi ! Ça lag. Ça se déconnecte. Quand on fait l’épreuve d’admin, avoir un délai de plus d’une seconde entre l’appui sur une touche et le retour à l’écran, c’est affreux…
– Bien tester le moteur de jeu… Les bugs avec les requêtes SQL qui apparaissent au milieu du navigateur, c’est rigolo. On s’est demandé à un moment si déboguer le moteur du jeu n’était pas une épreuve 😉
– Bien vérifier la faisabilité des exercices (les machines virtuelles mal configurées, c’est pas cool)
– Créer des machines virtuelle en avance… Ça évitera de perdre un quart d’heure parce que toutes les machines sont démarrées en même temps
– Préciser dans les exercices ce qui est attendu : pour le premier exercice, je suis partis du principe qu’il fallait configurer directement la machine virtuelle, mais pour les suivants, il a fallu deviner qu’il fallait donner un script et / ou documenter son approche…

Bon, je pinaille peut-être un peu… Mais c’est juste pour que ce soit encore mieux l’année prochaine…

Migration des URL dotclear vers wordpress

Je viens de faire une petite modification du .htaccess du site pour que les anciennes URL du site (qui étaient gérées par dotclear 1.2) ne retournent plus de 404 et pointent vers les bons articles. J’ai aussi ajouté une redirection pour le flux RSS…

1
2
3
RewriteRule ^(\d{4}/\d{2})/\d{2}/\d+-(.*)$ $1/$2/ [P]
RewriteRule ^rss.php /feed/ [P]
RewriteRule ^atom.php /feed/atom/ [P]

Authentication for NginX

On my home server, I use NginX to serve some webapps and some static files. I wanted a global authentication mechanism that can work for all services. I decided to build mine directly in NginX.

The system is cookie based. A unique token is attributed to the user and stored in the cookie. A file named after the token is also created on the server. If the user doesn’t have the cookie set or if its value doesn’t point to a valid file, he is redirected to an authentication app.

The authentication app is a node JS app responsible for verifying login. A login form is submitted by the user. The username and the password are compared to a list stored in a small json file. If the informations match, the token is created and stored in the cookie and in the file. The user is then redirected to the location he wanted to reach. I also add a sign up form with activation. The app is based on the express framework, with the help of jade and stylus for the presentation.

Now, the NginX configuration :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    server {
        listen 80;
        server_name plonk.puyb.net plonk 192.168.0.254 localhost;

        location /auth/ {
            alias /srv/http/auth/;
            proxy_pass http://localhost:3000/;
            proxy_redirect default;
        }

        location / {
        if ($http_cookie ~* "AUTH_COOKIE=([a-z0-9]+)(?:/|$)") {
            set $auth_cookie $1;
        }

        if (!-f /var/lib/nginx/cookies/$auth_cookie) {
            rewrite ^ http://plonk.puyb.net/auth/?redirect=$request_uri break;
        }

        root /srv/http;
        index index.html index.php;
    }
}

The node JS app server run on port 3000.

The node JS app is on GitHub : Puyb/nginx-auth.

What can I improve ?
– This system lacks a mechanism to delete token files… How to do it ? I can simply delete files in a cron job a couple of hours after the creation date. But some users may be disconnected even if they are still using the system. The cookie is set only at login time. Unlike other cookie based systems, the cookie isn’t refreshed at each request. So if I set an expiration time, the session will expire a fixed amount of time after the login, even if the user is still active. I don’t have a solution yet… I’ll work on it later…

To log out, you just have to delete the cookie. You can do it in javascript :

1
document.cookie='AUTH_COOKIE=;expires=' + new Date().toGMTString()

Plonk v4

Voici un article que j’ai commencé à écrire il y a quelques mois déjà, mais que je n’avais jamais pris le temps de publier… Voilà, c’est réparé 😉

Cette année, j’ai mis à jours mon serveur auto-hébergé, le bien nommé plonk…
Depuis 1999, c’est la 4e itération matérielle… Beaucoup de chemin parcouru depuis le frêle pentium 166…

Ce serveur fait office de serveur de stockage, sauvegarde, web, média-center, enregistreur numérique et à peut près tout ce qui peut me passer par la tête…

La nouveauté de cette année étant que je lui confie aussi le rôle de média-center, rôle qui était jusqu’ici assuré par une autre machine…

Voici le détail de la configuration matérielle sauce 2012…

Boîtier Chenbro ES34169 : Un boitier très compact offrant 4 tiroirs SATA extractibles à chaud
Une carte mère Asus E45M1 deluxe, architecturée autour d’un AMD Fusion E450 double cœur à 1.6GHz, une carte ATI intégrée, du bluetooth, du wifi, HDMI, USB3, etc…
Un SSD OCZ Extreme II de 64Go pour le système
4 disque WD Caviar Green de 1,5 To pour les données

et maintenant, les trucs plus exotiques :
– le boitier était extrêmement bruyant. C’est dommage quand on a que des composants sans ventilateur ;-)… J’ai donc ajouté un système de régulation des ventilateurs.

– les disques durs chauffaient beaucoup (parfois plus de 60°C). Et ce, malgré la ventilation bruyante du boitier… J’ai donc ajouté deux ventilateurs en façade directement sur les disques… Le tout piloté par la sonde de température via un régulateur HFX MiniNG, c’est parfaitement silencieux…
– la carte mère n’étant équipée que de 5 ports SATA, il me manquait un port pour brancher le lecteur de DVD. En fait, j’ai installé en interne un lecteur de DVD USB…

– la télécommande Motorolla NYXboard, spécialement conçu pour XBMC

D’un point de vu logiciel, le serveur utilise Arch Linux, configuré avec systemd, le médiacenter XBMC, la TNT est confiée à TVHeadend, le serveur web est Nginx. Je reviendrais en détails sur certains aspect de la configuration.
Les disques durs sont formaté en BTRFS en mode RAID 10, pour pouvoir profiter de toutes les avancés comme les snapshots, ou d’une plus grande sécurité face à la corruption de données (CRC). J’ai eu un problème de disque dur (les disques, âgés de 3 ans, ont quasiment tous lâchés à quelques mois d’intervalle), je n’ai perdu aucune donnée et la remise en route du système à nécessité quasiment aucune manipulation de ma part… Par contre la reconstruction à été très longue (plus de 12h), mais la partition était utilisable pendant l’opération.

Les disques durs sont configurés pour se mettre en veille en cas d’inactivité.
Le système consomme environs 20W avec les disques en veille et jusqu’à 45W avec les 4 disques allumés en lisant un film en full HD… L’ancien système consommait entre 60 et 80W et le média-center consommait 30W. Je pense que l’économie d’énergie peut à elle seule me faire économiser plus de 70€ par an d’électricité.

Voilà pour la description sommaire… Je reviendrais plus tard sur certain détails de la configuration…

GpxViewer sur GitHub

Sur les conseils de Kevin, j’ai ouvert un compte GitHub et j’y ai ajouté un dépôt GpxViewer. Il m’a même déjà soumis un correctif…

Vous pourrez trouver le projet sous Puyb/gpxviewer

Nouveau blog

Je viens de remplacer le vieillissant DotClear 1.2 qui animait ce blog depuis sa création par un rutilant WordPress… Si vous voyez des choses qui ne fonctionnent pas, n’hésitez pas à me les rapporter…

J’en ai aussi profité pour changer le titre… Et oui, je n’étais pas très inspiré 😉

GPX file viewer

Last year, I bought a GPS tracker watch, Kalenji Keymaze 700, to record my skates (and bike) trips and training sessions. As usual, the software bundled with the watch was windows only. I found a small python script made for a similar tracker, that extracts GPX files. But I found nothing satisfying to view and analyse the GPX files under linux, so I hacked a small javascript app to display my logs.

 

 

 

Stage roller en provence 2012

The basic functionnalities are :
– display the track on a google map view
– show global informations about the session (time, average speed, distance, etc…)
– show altitude, speed, and heartrate graphs
– show instant informations when hovering graphs, and point the location on the map
– allow zooming on the graphs
– graphs can be based on time or distance
– detect pauses (when the speed is below 7 kph) and take them in account to compute average speed

Some things I want to improve in the futur :
– compute instant speed (speed is actually recorded by the watch, but many GPX files lack this kind of informations)
– get altitudes from Google or any other online service (altitudes reported by GPS are often imprecises)
– smooth speed and altitude to wipe out errors
– use openstreet map instead of the deprecated google map api v2
– allow an offline mode
– show colors on the track to display informations (ie: speed, heartrate, altitude or grade)
– allow to draw a virtual finish line for loop tracks, and use that line to count laps, and display laps statistics.
– add a settings screen and find a way to save settings for each file

Exemple de relevé lors de l’ascension du col de l’homme mort en roller

You can view the script in action here (and also view some of my trips 😉 )

You can download the script here. Update : You can now find it on GitHup

As usual, this script is provided under the GPL v3 licence. I hope you’ll find some good way to use it. Let me know 😉

6H roller de Paris

Cette année, avec mon club, le PUC Roller, nous avons décider d’organiser une course d’endurance à Roller dans Paris. Les premiers 6H de Paris auront lieu dans le bois de Boulogne le 5 août 2012 !

Venez nombreux !

Site des 6H de Paris

WebDAV en Javascript

I wrote a small WebDAV javascript librairy based on the prototype framework.

The API is simple :

1
2
3
4
5
6
7
8
9
10
var dav = new DAV('http://someserver/');

var txt = dav.get('somefile.txt');

dav.each('/somedir/', function(name, info) {
console.log(name, info);
});

txt += "\nModified";
dav.put('somefile.txt', txt);

Of course, the Same Origin Policy may limit the sites you can reach. But it work perfectly to get, list and modify files on the same server.

To configure apache to accept DAV requests, just add a Dav On in a <Directory> directive and enable the dav* modules…

While developing this script, I found that Ajax.Request doesn’t allow to make request other than GET and POST. WebDAV need more verbs, like PUT or PROPFIND. So I made a new Ajax.FreeRequest function that doesn’t check the verb used.

The script is licensed under the terms of the GPL V3 and can be downloaded here: dav-0.1.js