Cross Domain, Iframe, LocalStorage et Html5

Cross Domain, Iframe, LocalStorage et Html5

Aujourd’hui je vais vous parler d’une chose sur lequel j’ai butté une journée entière. Voici ce que je devais réaliser :

Envoyer des infos en arrière plan dans le localStorage du domaine B depuis le domaine A

Si vous ne le savez pas, les navigateurs ont un localstorage de 5Mo (10Mo pour certains navigateurs) par Domaine. De plus, vu que le localstorage est côté navigateur, nous devrons le manipuler avec du JavaScript. C’est pourquoi, la réponse logique (et après recherche) reste donc l’utilisation des IFrames. Le souci, c’est que maintenant, les navigateurs modernes ne permettent plus la manipulation des IFrames si son domaine est différent de la page source.

En cherchant un peu plus, je suis tombé sur la fonction PostMessage() introduite avec HTML5 permettant d’outrepasser cette limitation tout en gardant le côté sécurisé.

Justement, ce problème va nous permettre de voir plusieurs technologies propres à l’HTML5 :

  • LocalStorage : Permet de stocker des valeurs au sein du navigateur sans limite de durée. Le LocalStorage est rattaché au domaine.
  • PostMessage : Fonction propre aux IFrames permettant d’envoyer des événements depuis la page parente. Fonctionne si l’Iframe est dans un domaine différent.

Nous allons voir chacune des deux parties avec le code à implémenter.

Tout à l’heure, j’ai parlé à plusieurs reprises de domaine. En fait il s’agit du site web. Si vous essayez de communiquer avec une iframe ciblant un site web différent du votre (par exemple google.fr alors que vous êtes foo.bar), alors les navigateurs bloqueront la communication par mesure de sécurité.

Domaine A

Dans le domaine A, nous allons voir 2 parties. La vue HTML avec la mise en place de l’IFRame (c’est tout bête mais il y a un petit détail important), puis la partie Javascript avec l’utilisation de PostMessage.

Vue HTML

<html>
    <head>
        ...
    </head>
    <body>
        ...
        <iframe src="http://mondomaineb/foo.html" frameborder="0" style="display: none;" id="postmessage"></iframe>
    <body>
</html>

Partie Javascript

//...
//le [0] sert à récupérer l'objet DOM
var iframe = $("#postmessage")[0].contentWindow;
iframe.postMessage({
    foo : 'value1',
    bar : 'value2'
}, "*");
//...

Domaine B

Dans le Domaine B, seule la partie Javascript va être necessaire. Néanmoins, si vous devez communiquer un retour avec le domaine A, vous devriez encore repasser par une IFrame. Mais ceci ne concerne pas cet exemple.

Il faut savoir que, pour pouvoir capturer un événement postMessage, nous devons ajouter un Listener sur l’événement message. Si vous oubliez cette partie, votre postMessage communiquera avec un mur. De plus, la fonction lancée par ce Listener n’a qu’un seul paramètre : Le paramètre event. Grâce à lui, vous pouvez connaître l’origine du message et ainsi le traiter uniquement s’il vient du Domaine A.

//...
function postMessageB(evt){
    if(
        evt.origin === 'http://mondomaineA'
    ){
        var foo = evt.data.foo;
        var bar = evt.ata.bar;

        // affichera dans votre navigateur le message "value1 value2" depuis l'iframe.
        alert(foor+" "+bar);   
    }else{
        return;
    }
}

window.addEventListener("message", postMessageB, false);
//...

Conclusion

Voilà. Normalement, vous savez dorénavant utiliser postMessage. Si vous avez des questions, des soucis ou que vous souhaitez aussi me corriger, n’hésitez pas à me laisser un commentaire. Sur ce, bon week-end à tous.

NodeJS : Service et redémarrage automatique

NodeJS : Service et redémarrage automatique

Depuis que je travaillais sous NodeJS au travail, je me posais une question sur sa mise en place côté serveur. Comment l’exécuter en tant que service et comment faire pour qu’il se relance automatiquement en cas de gros crash. Effectivement, si votre serveur NodeJS crash à cause d’une erreur de développement, il se coupe. De plus, nodeJS se lance au premier plan, avec l’output sur stdin et stderr. Nous allons donc voir ces deux points pour avoir une solution solide aà mettre en place sur vos serveurs.

Prérequis

Pour commencer, je tiens à préciser que tous ces tests ont été effectués sur un Mac OSX, un serveur Ubuntu 12.10 64bits et un Ubuntu Desktop 12.10 64 bits. La version de NodeJS utilisée est la dernière en date au moment de l’écriture de cet article. À savoir la version 0.10.7.

Superviser les crash et mises à jour de son projet Node.

Comme dit plus haut, si jamais un crash non intercepté dans votre code a lieux, nodeJS affiche la stack trace dans son output et se quitte. Si vous exécutez votre script sur votre serveur et que l’erreur survient à 3h du matin, vous aurez l’agréable surprise de recevoir 5000 mails, autant de messages en absence pour vous dire qu’il y a un problème.

Je me suis donc tourneé vers différentes solutions existantes :

  • Forever : Si vous souhqitez seulement exécuter votre script en tant que daemon, alors forever est pour vous. Il vous permet de lancer/redémarrer/arrêter indépendamment chacun de vos scripts nodeJS. Seul souci pour ma problématique, il ne s’utilise pas comme un service unix.
  • nodemon : Nodemon relance votre script si un fichier a été modifié mais en cas d’erreur, il attends qu’un fichier soit modifié pour se relancer.
  • always : Ce script semble être abandonné car la fonctionnalité du redémarrage en cas d’erreur ne marche pas.
  • supervisor : Supervisor lance un script nodejs sur stdin, il redémarre le script tout seul en cas d’erreur et je crois même qu’il le redémarre aussi en cas de modification des fichiers sources.

Parmi tous ces choix, je me suis arrêté sur supervisor car il fait le minimum requis et il s’emboitera très bien avec la mise en place d’un service pour lancer le tout. Nous allons donc installer supervisor en module node global afin de pouvoir l’utiliser directement en commande au sein du terminal :

sudo npm install supervisor -g

Puis ensuite, pour lancer votre script :

supervisor script.js

Normalement, en cas d’erreur, supervisor relancera automatiquement votre script.

Mise en place du service

Maintenant que nous avons trouvé comment redémarrer automatiquement notre script nodeJS, nous allons le « transformer » en service. De plus, nous le rajouterons à notre liste des services à exécuter au démarrage.

Pour cela, nous allons utiliser un programme codeé en python du nom de supervisor. Encore un programme Supervisor ? Oui et il va nous permettre de faire ceci :

  • exécuter directement le programme avec un utilisateur propre
  • exécuter le programme directement dans le répertoire cible
  • définir les variables d’environnement

Autant de choses utiles pour ma problématique. Voici la procédure d’installation du programme supervisor :

sudo apt-get install python-setuptools
sudo easy_install supervisor

Ensuite, créez le fichier /etc/init.d/supervisord et placez y le code suivant afin d’utiliser supervisor comme un service :

#! /bin/bash -e

SUPERVISORD=/usr/local/bin/supervisord
PIDFILE=/tmp/supervisord.pid
OPTS="-c /etc/supervisord.conf"

test -x $SUPERVISORD || exit 0

. /lib/lsb/init-functions

export PATH="${PATH:+$PATH:}/usr/local/bin:/usr/sbin:/sbin"

case "$1" in
  start)
    log_begin_msg "Starting Supervisor daemon manager..."
    start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $SUPERVISORD -- $OPTS || log_end_msg 1
    log_end_msg 0
    ;;
  stop)
    log_begin_msg "Stopping Supervisor daemon manager..."
    start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE || log_end_msg 1
    log_end_msg 0
    ;;

  restart|reload|force-reload)
    log_begin_msg "Restarting Supervisor daemon manager..."
    start-stop-daemon --stop --quiet --oknodo --retry 30 --pidfile $PIDFILE
    start-stop-daemon --start --quiet --pidfile /var/run/sshd.pid --exec $SUPERVISORD -- $OPTS || log_end_msg 1
    log_end_msg 0
    ;;

  *)
    log_success_msg "Usage: /etc/init.d/supervisor
{start|stop|reload|force-reload|restart}"
    exit 1
esac

exit 0

Nous le rendons ensuite exécutable et nous le rajoutons aux programmes relancés au démarrage :

sudo chmod +x /etc/init.d/supervisord
sudo update-rc.d supervisord defaults

Maintenant que supervisord est mis en place, nous devons le configurer. Pour cela, nous allons générer le fichier de configuration par défaut comme ceci :

sudo echo_supervisord_conf > supervisord.conf
sudo mv supervisord.conf /etc/supervisord.conf

Avant de rajouter les scripts NodeJS à exécuter, nous éditons maintenant les configurations de supervisor en touchant au fichier /etc/supervisord.conf et en modificant les valeurs suivantes comme indiqué :

chmod=0777       ; sockef file mode (default 0700)
user=user        ; utiliateur devat exécuter les programmes de supervisord

Maintenant, rajoutez ce qui suit en fin du fichier de configuration pour chaque programmes serveur nodeJS que vous devez exécuter :

[program:yourapplicationname]
command=supervisor votrescript.js
directory=/application/directory
environment=NODE_ENV=production  

Voilà. Pour lancer votre serveur nodeJS, exécutez simplement la commande sudo service supervisord start et remplacez start par stop pour y mettre fin.

Conclusion

Je ne sais pas si ce que j’ai fait est la meilleure méthode mais c’est celle que j’ai trouvé être la plus simple à réaliser et qui répondait à mo problème. Bien entendu, supervisord peut lancer en même temps différentes applications dans différents langages. Si vous avez des questions, des conseils ou d’autres solutions, n’hésitez surtout pas à me les proposer. Sur ce, je vous souhaite un bon week-end.

Node Sender Preview

Node Sender Preview

Hello Everyone.

Today I’ll show you the preview of Library NodeJS I’m doing: Node-Sender

This library can simply send a Push to devices running Android, iOS, Blackberry or Windows Phone. For the moment, only the Android GCM Push is functional. Others should follow shortly. Similarly, for now you can not install this module via NPM. That will come when I finish all platforms.

Android Quick Start

var Sender = require('node-sender');

var sender = new Sender();

sender.send(
    Sender.TYPE_ANDROID,                // OS type
    { msge : "Test Message NodeJS" },   // message to send
    "Registration Id",                  // phone registration id(s)
    { apiKey : "Api-Key GCM" },         // settings
    function(err, response){            // callback
        console.log(err);
        console.log(response);
    }
);

Download

If you are curious and want to test this library, you can find it on my Github repository.

Authentification sous MongoDB

Authentification sous MongoDB

Aujourd’hui, changement complet de technologie. Depuis quelques semaines au travail, nous migrons notre projet PHP/MySQL/JS vers du NodeJS/MongoDB avec une API REST. Je vais donc partager avec vous un point avec lequel j’ai eu un peu de mal : L’authentification avec MongoDB.

Je tiens à préciser que cet article ne remplace pas la documentation officielle et qu’ici, il ne s’agit que d’une mise en application à travers ce que j’ai compris. Si j’ai fait une erreur, merci de me le préciser en commentaires.

Précisions

Je ne m’attarderai pas sur qu’est-ce que MongoDB et quelles sont les différences avec une base de donnée relationnelle. Si vous voulez savoir ceci, je vous renvoie pour le moment vers cet article donnant la plupart des différences avec MySQL, CouchDB et MongoDB.

Mise en place

Si vous avez mongoDB installé sur votre serveur, vous savez aussi que vous avez, à l’instar de MySQL, un client disponible en ligne de commande, à savoir pour MongoDB : mongo. C’est avec cet outil que nous allons créer notre utilisateur.

Ensuite, il faut savoir que pour l’authentification, et ce peu importe la base de donnée cible, MongoDB s’appuie sur la liste des utilisateurs présents dans la base admin. Nous allons donc créer notre utilisateur simplement en faisant ceci :

use admin
db.addUser("nomduuser", "password")

Normalement, après avoir rentré ceci, mongo devrait vous retourner ce résultat :

{
    "user" : "test",
    "readOnly" : false,
    "pwd" : "a6de521abefc2fed4f5876855a3484f5",
    "_id" : ObjectId("517c027488495859945639e6")
} 

Votre user a été correctement créé. Au cas où, nous allons le vérifier grâce à la commande db.system.users.find() et elle devrait vous retourner la même chose que plus haut.

Bien, votre utilisateur a été créé mais vous pouvez vous connecter à votre serveur sans vous authentifier et effectuer toutes les actions que vous voulez. C’est normal car de base, MongoDB a désactivé la couche d’authentification.

Pour activer l’authentification, nous devrons modifier la configuration de mongoDB à partir du fichier mongod.conf en rajoutant simplement cette ligne :

auth = true

Ensuite, relancez simplement le processus mongod.

Pour tester l’authentification, vous avez plusieurs choix. Soit en lançant mongo, soit avec la commande mongo db.auth("login","password"), soit via votre application connectée au serveur ou soit via un logiciel d’administration pour MongoDB.

Personnellement, je les test grâce à l’application GenghisApp mais nous allons voir le cas avec la commande db.auth(). Relancez donc le client mongo et essayez d’ajouter un nouvel utilisateur. Vous devriez normalement avoir l’erreur suivante :

Sat Apr 27 19:09:58.263 JavaScript execution failed: error: 
{ "$err" : "not authorized for query on admin.system.users", "code" : 16550 } 
at src/mongo/shell/query.js:L128

C’est bon, le système d’authentification est en marche. Pour palier à ceci, faites juste la commande suivante :

db.auth("votrelogin","votremotdepasse")

Et mongoDB devrait vous laisser passer en retournant simplement 1. Si vous essayez de vous authentifier avec un login/password invalide, vous devriez avoir l’erreur suivante :

Error: 18 { ok: 0.0, errmsg: "auth fails" }
Lors des tests sur mon poste, la commande mongo me retournait une erreur d’authentification alors que GenghisApp arrivait bien à se connecter avec mon utilisateur. Apres plusieurs redémarrages de MongoDB, l’authentification s’est mise à marcher avec mongo.

Voilà, votre base MongoDB utilise maintenant l’authentification. Vous pouvez aller plus loin avec les différents droits existants au seins de MongoDB à l’instar de MySQL. Mais pour ça, je vous renvoie vers la Documentation officielle

Edition du 13 Mai :

Il semblerait qu’en plus de la base admin, si vous voulez accéder directement à votre application, vous devrez créer ce même utilisateur dans la base cible.

OSX, BASH et .bash_profile

OSX, BASH et .bash_profile

Bonjour à tous. Si vous êtes sur Mac OSX et que, comme moi, vous utilisez souvent votre terminal, vous avez dû vous apercevoir qu’il est plutôt sobre, qu’on ne voit pas la différence de couleur sur les types de fichiers/droits comme sous Ubuntu ou que quand on fait un petit setenv, on se fait gentiment renvoyer dans les roses.

Et bien laissez mois vous apprendre, ou vous répéter, que OSX utilise le shell BASH et donc, exécute des scripts particuliers pour enrichir et configurer votre terminal. À savoir ici, le fichier .bash_profile.

Nous n’allons pas voir en profondeur comment fonctionne ce fichier, de nombreux tutoriels existent. Google est votre amis si je puis dire. Non, ici nous allons juste voir comment enrichir notre variable PATH, comment définir de nouvelles variables qui peuvent s’avérer utiles (ex : ANDROID_HOME, ANT_HOME, …) et comment créer des alias de commandes. (ex untar au lieu de tar -zxf)

Justement, voici mon petit fichier ~/.bash_profile :

# alias de commandes unix
alias ls="ls -G"
alias untar="tar -zxf"

# definitions de nouvelles variables
export ANDROID_HOME=/usr/local/etc/android/sdk

# extension de $PATH
export PATH=${PATH}:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools

Mon .bash_profile permet ceci :

  • Afficher, avec ls, une couleur par type/droit des fichiers comme sous Ubuntu
  • Décompresser facilement les fichiers .tar.gz avec les arguments principaux
  • Définir la variable ANDROID_HOME
  • Rajouter les commandes android à mon PATH pour les exécuter facilement dans le terminal.

Quand vous avez modifié votre .bash_profile, n’oubliez surtout pas de le recharger grâce à la commande source ~/.bash_profile

Bien entendu, le .bash_profile permet pleins d’autres choses comme l’ajout de nouvelles commandes, la redéfinition de votre prompt, … Libre aà vous de faire ce que vous voulez et de rendre votre terminal encore plus puissant que ce qu’il est déjà.

Cet article marche pour tous les systèmes utilisants un shell unix. Même Cygwin sous Windows est compatible.