Aller au contenu | Aller au pied de page

mercredi, avril 30 2008

Le concept du deuxième

Si il est premier c'est le meilleur !

Hier je me disais que, dans notre société, le choix du premier n'est pas forcément le meilleur, ni même le plus représentatif.

Par exemple pour choisir notre représentant ultime, le président, nous votons pour une personne.
A mon sens c'est une aberration. Certes il en ressort une personne qui est apprécié du plus grand nombre mais quid des autres ?

La démocratie n'est ce pas justement l'art du compromis ?
Celui qui consiste à en représenter le plus grand nombre et ne laisser personne sur la touche ?

Un exemple démocratique

Prenons l'exemple d'une élection présidentielle justement.
Imaginons un président élu avec 50% des suffrages, mais que 45% ne voudrait surtout pas comme président (toute ressemblance avec la vérité est fortuite).
Est ce démocratique ? Est ce représentatif ?

Comment faire mieux : une idée chiffrée

Pour améliorer ce système je me suis dit qu'il serait plus intelligent lors d'une élection de faire un classement plutôt que de voter pour une seule personne.
Imaginons un panel de 1 000 personnes avec une représentation des votes suivante :

Candidat Position 1 Position 2 Position 3
Ségolène Royal 300 250 450
François Bayrou 200 700 100
Nicolas Sarkozy 500 50 450

On le voit, c'est le candidat Sarkozy qui apparait en tête. Paradoxalement c'est aussi celui qui est le moins en second : et ça compte.
Dans mon idée, pour faire un classement juste il nous faut faire la moyenne des résultats et prendre la personne dont la position moyenne se rapproche le plus de 1.

Si on effectue les calculs on obtient ceci :

Candidat Calcul Position moyenne
Ségolène Royal (300 * 1 + 250 * 2 + 450 * 3) / 1000 2,15
François Bayrou (200 * 1 + 700 * 2 + 100 * 3) / 1000 1.9
Nicolas Sarkozy (500 * 1 + 50 * 2 + 450 *3) / 1000 1.95

La lecture des chiffres montre que, moyennement, les résultats sont plus serrés que ne le laisse supposer une simple lecture du tableau.
Et bien sûr l'autre fait marquant c'est que le résultat n'est plus du tout le même.

Avec plus de candidats et un nombre de votants plus élevés je suppose que les résultats pourraient être assez surprenants.

Si j'imagine assez mal ce concept atterrir dans nos bureaux de votes, je pense que ça peut être un système d'ascension judicieux dans une entreprise ; dans le cadre d'une promotion par exemple.

mardi, avril 22 2008

ActionMailer et TLS : reloaded

J'avais déjà évoqué comment se connecter à un serveur SMTP en TLS dans un billet précédent mais quelques petites choses ont changé ; finalement c'est encore plus simple.

Étant donné que cela fait un moment que le dépôt de Kyle est HS, le plugin est maintenant disponible ici :
http://svn.douglasfshearer.com/rails/plugins/action_mailer_optional_tls

Pour l'installer il suffit d'utiliser le gestionnaire de plugins en commande :
ruby script/plugin install http://svn.douglasfshearer.com/rails/plugins/action_mailer_optional_tls

Côté configuration j'évite de tout coller dans le fichier environment.rb et je passe plutôt par les initializers qui sont chargés automatiquement au boot de l'appli, et dont c'est le rôle finalement.

Tu peux donc créer le fichier .rb de ton choix (par exemple tls.rb) dans le dossier initializers avec la même config qu'auparavant :

config.action_mailer.raise_delivery_errors = true
config.action_mailer.default_charset = "utf-8"
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
        :address => "smtp.domain.tld",
        :port => 25,
        :user_name =>'login',
        :password =>'pass',
        :authentication => :login,
        :domain => "domain.tld",
        :tls => true
}
config.action_mailer.perform_deliveries = true

Voilà pour la petite mise à jour.

samedi, avril 19 2008

Synchroniser Akregator et Google Reader, c'est pour bientôt.

La problématique

Même si on est de plus en plus dans une perspective full web où tout et n'importe quoi se transforme en webapp, dans bien des cas rien ne vaut une bonne application desktop.

Bien souvent, si l'on utilise un service online, c'est parce qu'on peut l'utiliser partout, et retrouver ses données dans l'état dans lequel on les a laissées.
Dans mon cas c'est ce dernier point qui m'a fait switcher d'Akregator vers Google Reader. Il est vrai que c'est pénible de n'avoir aucune donnée synchronisée d'un poste à l'autre.

Toutefois Akregator semble avoir fait pas mal d'avancées en la matière et de petites choses se mettent en place.
Un module de synchronisation a été créé et permet pour l'instant de synchroniser les flux en ajout et en suppression.
Pour l'instant il n'est pas possible de synchroniser les articles et leur état.

D'après l'équipe KDE en charge de ce module la difficulté n'est pas réellement technique puisque les API de google sont assez simples à utiliser.
Ce qui pose problème c'est que les informations ne sont pas stockées de la même manière d'un gestionnaire de flux à l'autre.
Toute la difficulté est de faire un module le plus générique possible puisque l'objectif est de pouvoir se synchroniser avec un maximum d'agrégateurs en ligne.

Disponible pour quand ?

Le module de synchronisation des flux uniquement devrait être disponible dans KDE 4.1.
Pour une synchronisation complète il faudra attendre la sortie du nouveau gestionnaire d'informations personnelles de KDE : Akonadi, ce qui devrait coïncider avec la version 4.2 de KDE.

Une preview ?

vendredi, avril 18 2008

La vie en quelques définitions ...

Bernard Werber, mon auteur préféré, a publié une liste de quelques définitions frappées au coin du bon sens.

Je pense que la plupart de ceux qui lisent ce blog seront particulièrement sensibles à la définition du consultant.

mercredi, avril 16 2008

Contribution à Protoflow, un effet de coverflow en javascript

À la recherche du script cover flow

Dans le cadre de la réalisation d'un projet spécifique j'étais à la recherche d'un effet javascript permettant de simuler un coverflow sur une collection d'images.

Je suis d'abord tombé sur imageflow, que j'ai testé et qui fonctionne bien.

Mais de préférence je souhaitais un script basé sur prototype pour profiter de son incroyable potentiel puisqu'il est intégré à rails de base.
Je suis donc tombé sur Protoflow.

Protoflow plus sexy, mais avec moins de features

Le souci avec Protoflow c'est qu'il possédait moins de fonctionnalités qu'imageFlow, comme la gestion du clavier, de la souris et quelques soucis comme la mauvaise gestion des liens englobant les images.

En effet ces liens étaient désactivés en changeant leur cible (href à #), ce qui empêchait l'utilisation combinée d'effets comme lightbox.

J'ai décidé de mettre les mains dans le cambouis et de soumettre mes retours.
J'ai donc envoyé un patch pour accroitre le nombre de fonctionnalités.

Finalement le patch a été intégré \o/
Je trouve ça sympa de contribuer sur des projets externes de temps en temps.

jeudi, mars 13 2008

Plugin highlight et pv pour weechat

Le besoin

Comme shingara, j'utilise weechat pour IRC et il nous manquait un plugin pour être notifié sur notre jabber à la réception d'un PV ou lors d'un highlight sur un channel.
Le but est de recevoir un message sur sa messagerie instantanée avec le nom de l'expéditeur et le contenu du message lorsque quelqu'un nous interpelle sur IRC.
Je me suis donc motivé pour écrire ce plugin in en me basant sur ses travaux en amont.

Qu'est ce qui change ?

Je suis donc parti de la révision 204 de son script (euh en fait y a d'autres choses dans le dépôt hein, vas faire un tour !) , basée sur celui de davux (c'est beau le libre hein ?), qui apparemment avait tendance à faire freezer weechat.

Au lieu d'utiliser xmpp4r j'utilise xmpp4r-simple qui est une lib plus légère et largement suffisante pour nos petits besoins.
Je pense avoir cerné ce qui potentiellement faisait planter weechat.
En effet lorsqu'on tente d'envoyer un message via XMPP, et que l'on ferme la connexion instantanément après, le message est non seulement perdu, et n'arrive donc jamais, mais a (semble t-il, je n'ai pas de certitudes) tendance à geler weechat.

Le script attend donc maintenant 3 secondes avant de fermer la connexion. D'une manière générale j'ai essayé d'améliorer la lisibilité et les perfs du script.
Au lieu d'instancier systématiquement un objet pour délivrer un message je passe par un singleton qui délivrera tous les messages pendant la durée de vie de weechat.

En terme de configuration il ne faut plus que le strict minimum : un couple jid / password qui désigne le compter jabber à utiliser pour envoyer les messages et un destinataire.
Il est possible de spécifier le port de connexion s'il est particulier, autrement le script utilise le port 5222.

Attention : Je n'ai pas testé mais il me semble logique qu'il ne faut pas utiliser le jid comme recipient, autrement le script risque de s'envoyer des messages à lui même.
En effet lorsque l'on utilise jabber c'est le dernier endroit depuis lequel on se connecte qui prend la main.

Au cas où ton compte destinataire ne serait pas connecté, les messages seront mis en file et tu les recevras à ta prochaine connexion.

Comment ça marche ?

L'usage est vraiment simple : il suffit de copier ce plugin dans ton .weechat/ruby/autoload et le plugin sera chargé au lancement de weechat. Ensuite tu édites ton fichier .weechat/plugins.rc et tu colles les informations te correspondant :

ruby.highlight_jabber_notify.jid = "jid@provider.tld"
ruby.highlight_jabber_notify.password = "toto42" # c'est pas ça ?
ruby.highlight_jabber_notify.port = "5222" # optionnel
ruby.highlight_jabber_notify.recipient = "recipient@provider.tld"

C'est tout. Le script est volontairement minimaliste mais on peut imaginer plus de configuration et de code pour n'être notifié que sur certains channels etc ...
J'ai aussi proposé ce script dans la section officielle du projet weechat (il est en attente d'approbation a été approuvé \o/).

jeudi, février 28 2008

Validations optionnelles en rails

Les validations

En rails les validations sont un concept particulièrement intéressant et pratique. Effectuées au niveau du modèle elles constituent le dernier rempart avant la modification de la base de donnée.

Cependant, suivant le contexte de l'application les vérifications ne sont pas forcément les même, certaines parties d'une application peuvent requérirent plus d'informations que d'autres, ce qui nous oblige à valider uniquement le nombre de champs minimal par défaut.

Prenons un cas concret : on a un modèle Contact. On veut que notre contact puisse laisser un avis sur le site mais aussi prendre un rendez vous.
Afin de dispatcher le rendez vous on a besoin de connaitre le code postal de ce contact.
Toutefois ce serait décourageant de demander le code postal d'une personne souhaitant uniquement laisser un avis.

Dans ce cas les seuls validateurs par défaut seront le nom et le prénom :

 # Dans le modèle
validates_presence_of :firstname
validates_presence_of :lastname

Coté vue :

 # Dans la vue
<%= error_messages_for :contact %>

Comment faire alors pour valider le code postal, si et seulement si nous somme en présence d'une demande de rendez vous ?

La mauvaise idée serait de penser faire le test dans notre contrôleur :

 # Dans le contrôleur
@contact.errors.add(:zip_code, "n'est pas valide.") unless params[:contact][:zip_code] =~ /^\d{5,6}$/
return render :action => 'form' unless @contact.save

Tout d'abord, ce code ne fonctionne pas (du moins en 1.2.6) : il est toujours possible d'insérer un enregistrement sans, ou avec un mauvais, code postal.
En effet la méthode save écrase le hash d'errors (tout comme la méthode valid?).
La méthode save ne teste donc pas si son modèle contient déjà des erreurs ou non. Ce qui signifie que si nos champs lastname et firstname sont remplis, le hash d'erreurs sera vide et l'enregistrement correct.

Pour avoir un code qui fonctionne voilà le genre d'insanités qu'il faudrait écrire :

 # Dans le contrôleur
if params[:contact][:zip_code] =~ /^\d{5,6}$/
      return render :action => 'form' unless @contact.save
else
      @contact.valid?
      @contact.errors.add(:zip_code, "n'est pas valide.")      
      return render :action => 'form'
end

Le fait d'insérer l'erreur après le valid? garantit à l'utilisateur de voir toutes les erreurs. Quoi de pire que de découvrir les champs requis au fur et à mesure de la saisie, après plusieurs soumissions.

Toutefois imagines la qualité du code au cas ou il y aurait plusieurs champs optionnels à vérifier. Quid aussi du côté DRY si on se retrouve à avoir le cas pour plusieurs formulaires ? Dupliquer ce morceau de code serait vraiment une mauvaise idée.

La bonne solution :validate ... :if

La meilleure idée c'est toujours de mettre nos validations dans le modèle :

 # Dans le modèle
def validate_zip_code
    errors.add(:zip_code, "n'est pas valide.") unless zip_code =~ /^\d{5,6}$/
end 

À ce niveau on pourrait choisir d'overrider validate dans notre contrôleur comme ceci :

 # Dans le contrôleur
def submit
    @contact = Contact.new(params[:contact])
  
    def @contact.validate
      validate_zip_code
    end

    ...
end

En effet, rien ne nous empêche d'ajouter des méthodes à notre objet au sein même de l'action, mais ça reste une mauvaise idée.
La notion d'ajout de méthodes dans un objet “à chaud” est un concept à manipuler avec précaution, qui peut s'avérer un casse tête à débugger sur du code volumineux.
De plus, dans le cas d'autre formulaires il serait dommage d'avoir à surcharger systématiquement la méthode validate.

Nous allons donc (quasiment) tout réaliser dans le modèle. Pour cela on rajoute un champ à notre modèle : optional_validations ...

 # Dans le modèle
  def optional_validations
    @optional_validations ||= []
  end

... ainsi qu'un validateur standard, doté du symbole :if :

 # Dans le modèle
validates_format_of :zip_code, :with => /^\d{5,6}$/, :if => Proc.new {|c| c.optional_validations.include?(:zip_code)}

Nous venons de mettre en place un getter qui renvoie notre propriété ou un tableau vide. Le validateur prend en paramètre une regex qui teste que le code postal contient bien 5 ou 6 chiffres au maximum.
Proc prend en argument un bloc de code. La variable c correspond à l'instance de contact courante.
La validation du code postal ne s'effectuera donc que si le symbole :zip_code est présent dans les validations optionnelles.

Il ne nous reste donc plus qu'à modifier légèrement notre contrôleur :

 # Dans le contrôleur
@contact.optional_validations << :zip_code

Le fait que notre getter renvoie un tableau vide permet d'éviter de faire un push sur nil dans le cas du premier ajout de symbole.

Voilà, nous avons maintenant à disposition un système de validations optionnelles souple et évolutif, qui impacte nos contrôleurs au minimum.

mardi, février 26 2008

iPhone : attendre, encore et toujours ...

Comme pour tous les nouveaux produits high tech bling bling qui sortent j'essaie d'être un peu raisonnable et de ne pas me jeter dessus dans un excès de geekerie.

Je préfère que ce soit les premiers qui essuient les pots cassés : problèmes software, matériel défectueux (même si ça arrive sur des produits rodés), etc ...

En ce moment j'ai toutes les bonnes raison d'attendre pour l'iPhone :

  • D'une part on évoque de plus en plus un iPhone 2, qui en plus d'intégrer la 3G (et même la 3.5G) se verrait munie d'une caméra embarquée. Il semble de plus en plus probable qu'Apple mette en place une version mobile d'iChat afin de faciliter la visio conférence. Cette fonctionnalité serait disponible sur les iphone et les touch. Il y aussi de fortes chances que l'on voit apparaitre du GPS. Le frein majeur à toutes ces évolutions étant l'autonomie de la batterie, un gros travail devra être fait à ce niveau.
  • Ensuite quelques bruits de couloir évoquent une baisse de celui-ci d'environ 100$. Même si ce n'est pas dans les habitudes d'Apple de casser les prix on est en droit d'y croire puisque que pour un grand nombre, le prix élevé reste le principal obstacle.
  • Je suis curieux de voir un peu le potentiel du SDK afin de pouvoir répondre à la fameuse question : jailbreakera, jailbreakera pas ? Si chaque application doit être validée par Apple afin de pouvoir être installée inutile de dire que ce serait une énorme déception.
  • Me concernant ce qui m'a toujours le plus rebuté c'est ce forfait data anormalement cher, facturé par orange. Ici ce que j'attend avec impatience c'est l'arrivée de free sur le marché de la 3G. Si free parvient à obtenir cette licence il disposera alors d'une force de frappe conséquente dans le domaine de la téléphonie (et autres applications) mobiles puisqu'il détient aussi une licence WiMAX.

Etant donné que Free a souvent mis des grands coups de pied dans la fourmilière on peut rêver de plusieurs choses :

  1. De la téléphonie 100% IP sur son mobile, et donc des coûts largement réduits, voire de l'illimité.
  2. La gratuité des appels depuis sa freebox vers les mobiles (d'ailleurs Alice commence à offrir des heures de communications).
  3. Une seule facture englobant sa box triple and play et son forfait mobile (cependant ne révons pas trop, le forfait ne serait sûrement plus de 29,99€)

Il est amusant de constater que la stratégie de Free est à l'opposé de celle de SFR : se servir de son implantation dans les foyers pour conquérir le marché de la mobilité.
Nul doute que les mois à venir nous réservent encore de belles suprises ...

vendredi, février 22 2008

Love.years++

love.jpg

mercredi, janvier 30 2008

Pas encore bilingue, translate est là pour toi !

Si comme moi tu passes pas mal de temps sur des sites de traduction, ce post est fait pour toi.

En effet 99% des bonnes docs étant écrite dans la langue de Shakespeare il n'est pas toujours évident de tout comprendre sans assistance.
C'est pourquoi je me retrouve assez souvent sur wordreference dans une journée.

Globalement wordreference est un très bon service. Toutefois après avoir cherché un peu je me suis rendu compte qu'il n'offrait pas d'API.
Je me suis donc résolu à créer mon propre script (en ruby) qui attaque le site en GET et qui parse le résultat à l'aide de l'excellente lib Hpricot.

Actuellement le script permet de faire les traductions suivantes :

  • Anglais vers français
  • Anglais vers italien
  • Français vers anglais
  • Italien vers anglais

Bizzarement, et c'est dommage, le site n'utilise pas le même format d'URL ni d'affichage pour les traductions en espagnol ; que ce soit depuis ou vers l'espagnol.
Toutefois rien n'empêche de patcher le script pour y remédier.

Pour utiliser ce script il te faut rubygems et hpricot. Rubygems est disponible sur la plupart des distributions ainsi que sous Mac OS X avec fink ou port.
Une fois rubygems installé il faut installer Hpricot à partir de ce dernier :

# gem install hpricot

ou

# gem install hpricot --source http://code.whytheluckystiff.net

Personnellement j'ai choisi la deuxième version pour avoir la build la plus récente.
Si tu as une erreur du genre : `require': no such file to load -- mkmf (LoadError) c'est sûrement qu'il te manque le paquet ruby1.8-dev Une fois installé tu peux utiliser le script de manière suivante :

./translate.rb house

Pour avoir un panel de ce que peut faire le script :

./translate.rb -h

Pour avoir quelques exemples :

./translate.rb -e

Note : Tu peux très bien mettre le script directement dans ton path pour l'utiliser depuis n'importe où, comme une commande normale :

$ sudo ln -s /path/to/translate.rb /usr/local/bin/translate

Le script est disponible sur ce post en annexe, mais la version la plus à jour se trouve dans mon dépôt mercurial.
J'essaierai de mettre une documentation un peu plus complète sur le script dans mon espace dédié sous peu.

Tout est dit, j'attends tes commentaires, retours ou patchs !

mardi, janvier 29 2008

Blog.refresh

Comme tout le monde tu me lis directement via un lecteur de flux, ce qui signifique que tu ne vas jamais réellement sur le blog.

C'est pourquoi je t'annonce ici que j'ai changé de thème, pour en faire un maison, plus adapté à mes besoins.

Les modifications sont presque exclusivement esthétiques. Par contre comme j'ai voulu un thème plus minimaliste j'ai viré la sidebar, qui encombrait inutilement.

J'en ai profité aussi pour passer de urchin.js à ga.js, le nouveau tracker de google. Si tu veux une explication des différences je te recommande le PDF fait par Google.

Je mettrai très certainement mon thème à disposition une fois que j'aurai fignollé quelques détails, histoire de remplir la section qui sert à ça. Pour le moment ça s'affiche bien sur les navigateurs qui coopérent, et presque bien sur les autres (comprendre que sur IE j'ai deux trois décalages de pixels, mais rien de compromettant).

Si tu détectes un bug ou un élément non stylé fais le moi savoir, histoire d'avoir un truc clean avant de le mettre à disposition.

jeudi, janvier 24 2008

D'où vient le monde ?

La réponse.

mardi, janvier 22 2008

Macbook & mésaventures ...

Les rumeurs

Avant de commencer à utiliser un mac je me suis souvent laisser dire que le matériel d'Apple était de bonne facture et que l'écart de prix se justifiait grâce à cela.
D'autre part les fans de la pomme vous jurerons que le prix excessif du matos n'a d'équivalent que le SAV sans faille.

Les symptômes

Sauf que voilà, moins d'un an et demi après avoir acheté mon macbook (18 septembre 2006), je peux vous confirmer que ce n'est pas pour les composants qu'on choisi un mac.
Il y a une dizaine de jour c'est la batterie qui m'a lachée, sans réels signes précuseurs ; affichant simplement une batterie avec une croix sous OS X.

Ça limite l'intérêt d'un portable quand on se ballade un fil à la pate.

Presque 200€ plus tard me voilà avec une batterie neuve et pimpante et un volume de RAM passé de 512mo à 2go (impossible de bosser sous eclipse avec 512).
Je devenais enfin productif sur mon macbook.

Les symptômes (bis repetita)

Hier c'est le disque dur qui a rendu l'âme, la tête qui se met à claquer, le dossier avec le point d'interrogation au boot, la loose.
Et mon matériel, j'en prends soin.
Ce qui me met en colère c'est qu'après maintes recherche il s'avère que mon disque dur fait parti d'une série noire, celle aux caractéristiques suivantes :

  1. Marque : Seagate
  2. Modèle : ST96812AS
  3. Firmware : 7.01

Alors franchement ça aurait été bien de la part d'Apple :

  1. De reconnaître le problème
  2. De prévenir les utilisateurs ayant acheté ce matériel (ils peuvent retrouver nos coordonnées, au moins pour ceux ayant acheté sur l'Apple store), afin qu'ils anticipent une perte de données
  3. De faire un geste, ou mieux de remplacer le disque

Bilan

Très franchement je ne regrette pas mon achat parce que le design est séduisant et que le système mac OS X s'adresse aussi bien aux débutants qu'aux utilisateurs avancées (pratique pour sa moitié).
Toutefois je voulais casser un peu le mythe du matériel irréprochable par le biais de ce billet.

Un reste d'espoir ?

J'ai contacté Apple afin d'obtenir un remplacement du disque en question. Pas de réponses pour le moment. Je noterai ici le résultat de ma demande.
Stay tuned.

Utiliser le même ssh-agent entre plusieurs shells.

La problématique : se connecter entre ses différents machines, en ssh et sans mot de passe

Lorsqu'on commence à avoir des machines dans tous les coins on aime pouvoir y accèder facilement, et de partout.

Souvent on se retrouve avec un petit réseau local contenant plusieurs machines partageant un seul point d'accès à internet. C'est à partir de cette IP publique que l'on peut se connecter à son réseau interne de l'extérieur.

Le problème c'est que tant qu'IPv6 ne sera pas établi (et que ou l'on pourra disposer de plusieurs adresses publiques sans sourciller) on en est réduit à une seule adresse et on se retrouve avec une machine qui sert de passerelle pour rebondir dans son réseau interne.

Machine externe -> Passerelle -> Machine interne

Une solution basique : un jeu de clés privée / publique

Imaginons que l'on souhaite se connecter depuis la passerelle sur la machine interne. On va générer un jeu de clé :

$ ssh-keygen -t dsa

On peut utiliser le fichier par défaut, par contre il faut mettre une passphrase. Une fois notre paire de clés générée on va copier notre clé publique sur la machine sur laquelle on souhaite se connecter :

$ ssh-copy-id -i ~/.ssh/key.pub login@interne

Cela aura pour effet d'aller copier notre clé publique dans le fichier authorized_keys de la machine interne. Dès lors quand on voudra se connecter sur la machine interne depuis la passerelle c'est la passphrase qui sera demandée.

À ce niveau on peut penser avoir juste déplacé le problème : toujours un mot de passe à taper.

Toutefois, pour ne pas avoir à retaper sa passphrase à chaque connexion on peut utiliser ssh-agent.
Pour cela on rattache ssh-agent à un processus sur la passerelle, par exemple ssh-agent /bin/bash.

Cela aura pour effet de lancer un nouveau shell auquel sera rattaché l'agent.
Ensuite on peut rajouter les clés privées à gérer par notre agent : ssh-add ~/.ssh/id_dsa.

ssh-add va nous demander la passphrase, une fois entrée c'est lui qui interceptera les demandes de passphrases de ssh.

Dès lors je peux me connecter de ma passerelle vers ma machine interne sans mot de passe.

Aller un peu plus loin : utiliser le même agent pour faciliter les rebonds ssh

Soit, mais si je connecte depuis la machine externe vers la passerelle, et que depuis la passerelle je souhaite rouvrir une connexion vers la machine interne ma passphrase sera re-demandée.

Pourquoi ? Parce que notre agent est associé à notre shell (ssh-agent /bin/bash). En dehors de ce shell le problème est le même.

Si on y regarde de plus près, comment cela fonctionne t-il vraiment ?

Au lancement du ssh-agent une socket est créée dans le /tmp, du genre /tmp/ssh-xxxpiddushell/agent.piddushell
En fait le ssh-agent est un processus fils du shell nouvellement créé. En plus de ça notre commande génére plusieurs variables d'environnements qui ne sont accessibles qu'à l'intérieur du nouveau shell.

Regardons ça de plus près :

$ env | grep -i ssh

Deux variables nous intéressent :

SSH_AGENT_PID=22659
SSH_AUTH_SOCK=/tmp/ssh-WgkOE22658/agent.22658

Récupérer l'environnement de notre agent, et l'exporter dans le nouveau shell

On le voit ces informations sont facilement accessibles. Partant de là si on se connecte depuis la machine externe vers la passerelle et que l'on fait un export de ces variables dans le nouveau shell alloué lors de notre connexion ssh on peut parfaitement se reconnecter sur la machine interne sans taper de mot de passe :

$ export SSH_AGENT_PID=22659
$ export SSH_AUTH_SOCK=/tmp/ssh-WgkOE22658/agent.22658
$ ssh interne

L'idée c'est d'alouer automatiquement ces variables, en réalisant l'export ... dans notre .bashrc
En fait il y a deux façons de faire : soit on force le nom de la socket, avec un ssh-agent -a, soit on récupère les informations dynamiquement.

Je penche pour la deuxième qui m'évite de penser à passer cette option lorsque que je lance mon agent (et oui, geek == fainéant). En plus il faudra toujours récupérer l'id du pid.

Pour ça deux commandes à mettre dans le .bashrc :

export SSH_AGENT_PID=$(ps aux | grep -v 'grep' | grep ssh-agent | grep $(env | grep "USER" | sed s/USER=// | head -n 1) | head -n 1 | awk '{print $2}')

if [ "" != "$SSH_AGENT_PID" ]; then
  export SSH_AUTH_SOCK=$(find /tmp -iname "agent.$(ps -p $SSH_AGENT_PID -o ppid=)")
fi

Explications :


  • ps aux liste les processus
  • grep -v fait une recherche inverse c'est à dire qu'il exclut les résultats demandés. En l'occurence je demande à grep de s'exclure lui même, sinon la commande apparait dans la liste des résultats
  • grep ssh-agent fait ce qu'on lui demande, il recherche les lignes qui matchent.
  • grep $(env | grep "USER" | sed s/USER=// | head -n 1) fait un grep sur le nom de l'utilisateur. En effet il peut y avoir plusieurs agents sur la machine, appartenant à des utilisateurs différents.
  • head -n 1 renvoie la première ligne uniquement
  • awk '{print $2}' permet de splitter la ligne selon les espaces ou tabulations. Ici on renvoie le deuxième bloc qui contient le pid. On pourrait aussi utiliser cut.
if [ "" != "$SSH_AGENT_PID" ]; then
        export SSH_AUTH_SOCK=$(find /tmp -iname "agent.$(ps -p $SSH_AGENT_PID -o ppid=)")
fi

Explications :

Cette commande recherche la socket correspond à ce ssh-agent s'il existe (présence du pid).
La socket est nommée dans un format spécial : agent.pidduparentdel'agent ; il nous faut donc récupérer le pid parent du pid de l'agent, celui du shell donc.
C'est ce que réalise cette commande : ps -p $SSH_AGENT_PID -o ppid=

Ensuite c'est un find tout bête qui nous renvoie le full path de la socket.

Une fois ces commandes dans votre .bashrc c'est fini, lors de la connexion de externe vers passerelle, un shell est alloué, le bashrc sourcé et les variables d'environnements disponibles, on peut donc se connecter à la machine interne sans soucis.

Bien sûr pour faciliter le tout on peut utiliser un jeu de clés entre la machine externe et la passerelle.

Une pincée de sécurité en plus : empêcher les connexions ssh par mot de passe

Une fois tout ça en place pourquoi ne pas désactiver l'authentification par password ? Dans le fichier /etc/ssh/sshd_config :

PasswordAuthentication no

et au passage :

PermitRootLogin no

Ainsi on est sûr que seules les machines dont la clé publique se trouve sur la machine hôte pourront se connecter.
Toutefois il vaut mieux avoir au moins 3 machines pour utiliser ce système, ou conserver ses clés en lieu sûr, sinon au premier plantage votre machine distante devient inaccessible.
Dommage quand on n'a pas d'accès physique à celle-ci ...

mardi, janvier 15 2008

Flickr et le bug de l'an 2008.

2 147 483 647 : Deux milliards cent quarante sept millions quatre cent quatre vingt trois mille six cent quarante sept.

C'est le nombre de photos (sûrement largement dépassé à l'heure ou j'écris) hébergées sur flickr. Le côté inhumain de ce chiffre fait froid dans le dos.

Le souci c'est que ce chiffre représente aussi une limite, celle de la représentation d'un entier signé.
La majorité des systèmes actuels possèdent une architecture 32 bits. Les entiers sont donc représentés sur 31 bits (1 bit pour le signe).

Tu vois où je veux en venir : 2^31 = 2 147 483 648

Est ce que les auteurs de flickr pensaient un jour atteindre ce chiffre ? J'en doute.
Ce qui est sûr c'est qu'ils ont en tout cas prévu le coup puisque flickr n'a pas planté et que l'on peut continuer à y mettre ses photos.

A priori ils ont dû stocker les identifiants des photos sous une forme autre qu'un entier (une chaîne par exemple) ou alors ils utilisent un système où les entiers sont représentés sur un nombre plus élevés de bits.

Par contre pas sûr que les éditeurs tiers ayant bâtis des applications sur l'API de flickr par exemple, aient anticipés ce genre de désagrément.

A suivre ...

jeudi, janvier 10 2008

Nouveau logo pour Archlinux

Suite au concours, le gagnant du concours a été désigné par un système de votes.

La simplicité du design colle bien à la philosophie de la distribution à mon goût. L'autre logo The minimalist était lui aussi très abouti.

Y a pu qu'à intégrer tout ça comme on dit.

mardi, janvier 1 2008

Installer et tester ruby 1.9

Décidément ça ne chôme pas en cette fin d'année puisque la version 1.9 de ruby est sortie à noël.

Je pense que ce changement de version ne fera pas autant débat que pour rails, d'une part parce que ce n'est pas une version majeure et d'autre part parce que le changelog est vraiment impressionnant.

D'ailleurs le changelog de référence est celui d'eigenclass qui le maintient manuellement depuis 2 ans. Woh. Tiens c'est .
Attention même si le système de numérotation a changé (plus de numéro pair pour les versions stables et impair pour les autres), c'est version n'est pas destinée à être utilisée en production.

Par contre c'est peut être l'occasion de commencer à mettre à jour ses scripts et de mettre son nez dans les nouvelles features.

Pour que tu puisses tester un peu la bête j'ai fait un petit script shell qui installe ça tout bien, sans virer les versions précédentes de ruby.
Le script récupère le tarball depuis le site, vérifie le hash md5, compile et installe ruby1.9 dans /usr/local/bin.
Un lien symbolic est réalisé : /usr/bin/ruby1.9 afin d'être utilisable pour ceux qui n'ont pas le /usr/local/bin dans leur path.

Voilà, plus d'excuses pour ne pas foncer tester.

mardi, décembre 11 2007

Rails 2

Si tu es là je suppose que c'est pour avoir une information pertinente.

Je vais donc éviter de lancer le classique :
Rails 2 est sorti. Youpi. Bang. Chouette.

Tu sais celui qui te laisse comme deux ronds de flan, qui ne te donne aucune info, et que tu as vu plus d'une dizaine de fois dans ton aggrégateur.
Pour éviter ça, je t'invite à aller voir le seul billet qui vaut le coup et qui te donne de vraies informations sur les nouveautés de rails 2.

Quoi tu es encore là ? Bon, les grands moyens :

redirect_to "http://weblog.rubyonrails.org/2007/12/7/rails-2-0-it-s-done"

Non mais.

lundi, décembre 10 2007

Problème de rendu des PNG sous Safari, la faute au gamma.

Le problème :

Plutôt qu'un long discours voilà le genre de souci que l'on peut avoir dans le rendu des PNG :

Firefox : Rendu sous Firefox

Safari : Rendu sous Safari

Soyons clair, le PNG est un bon format. Libre, il gère un nombre de couleurs plus élevé que ses concurrents (8bits en GIF, 24 en JPEG et 32 en PNG, dont 8 pour la transparence), une compression plus élevée et gère la transparence par le biais de son canal alpha.

Un des rares avantages de gif se situe au niveau de sa gestion des animations, même si le format APNG commence à être supporté par quelques navigateurs (firefox 3, opera 9.50).
Le JPEG quant à lui permet de générer des fichiers plus petits dans certains cas. Toutefois son algorithme destructif entraîne une perte d'informations irrémédiable.

Ce qui devrait être un autre point fort du PNG et qui nous intéresse ici est sa gestion du gamma. Originellement le gamma avait pour but de garantir un rendu uniforme de l'image sur des configurations différentes en agissant sur certains paramètres de l'image. Malheureusement ce qui devait être une force a eu pour incidence d'accroître le problème. En effet chaque programme est libre d'interpréter le gamma à sa façon puisqu'il n'existe aucune règle, norme ou spécification indiquant comment l'appliquer.

C'est là l'origine de notre problème, Safari interprète le gamma à sa manière, empêchant les couleurs PNG de coller à celles des CSS.

Les solutions :

Il en existe deux, ayant chacune des inconvénients :

  1. Passer au format gif, ce qui, à mon sens, est une regéression. Même si le format est maintenant libre, on sort des recommandations et on se retrouve avec un format d'image de moins bonne qualité. Le GIF conserve toutefois l'avantage d'être géré correctement par tous les navigateurs ; en partie parce que c'est le format le plus ancien.
  2. Conserver le format PNG, en supprimant les informations de gamma contenue dans le fichier. Cette solution fonctionne très bien sauf pour quelques navigateurs anciens. Sur Opera < 7, Safari < 2, et quelques vieilles version de Mozilla sur Mac OS 9, même en l'absence d'informations sur le gamma celui ci est interprété, ce qui évidemment occasionne les même déboires.

En pesant le pour et le contre j'ai opté pour une conservation du PNG. À un moment donné il faut avancer, même au détriment de la rétro compatibilité (sinon on utiliserait encore des balises font) ; surtout quand il s'agit d'utiliser une bonne technologie. D'autant plus que seul un nombre infime de personne doit être équipé de ces navigateurs.

Pour supprimer le gamma j'ai utilisé pngcrush, qui est cross-platform. Il s'utilise en ligne de commande :

pngcrush -rem gAMA -rem cHRM -rem iCCP -rem sRGB input.png output.png

Voilà, fini les informations de gamma. En plus ça réduit la taille du fichier de plus de 5%, ce qui n'est pas négligeable.

En savoir plus :

La triste histoire de la correction gamma au sein des PNG

vendredi, décembre 7 2007

Quel type (de développeur) es tu ?

A lire avec enthousiasme.

- page 1 de 3