Unhosted

Aventures Unhosted

Une traduction approximative du Journal de bord officiel du No Cookie Crew

d’après Unhosted Adventures
by Michiel B. de Jong

5. Facebook et Twitter depuis nodejs

No Cookie Crew - Avertissement n°3 : Ce tutoriel nécessite que vous mettiez une nouvelle fois votre serveur personnel à jour en utilisant un client ssh/scp. De plus, pour enregistrer votre serveur personnel auprès de chacune des API, vous allez devoir vous connecter à Twitter et Facebook, en acceptant une dernière fois leurs cookies sur votre appareil…

Connexion à Facebook

Se connecter à Facebook est plus facile que vous ne le pensez. Tout d'abord, vous devez bien évidemment avoir un compte Facebook, alors commencez par vous en créer un si vous n'en avez pas encore. Ensuite, il vous est nécessaire de visiter le Graph API Explorer, et de cliquer sur ‘Obtenir un jeton d'accès’ (‘Get Acces Token’). Connectez-vous avec votre propre compte, et cliquez sur ‘Obtenir un jeton d'accès’ une nouvelle fois pour ouvrir la boîte de dialogue des demandes de droits d'accès étendus. De là, allez dans ‘les droits d'accès étendus’ ('Extended Permissions'), et activez ‘publish_stream’, cela devrait ressembler à ceci :

Facebook permissions

Le OAuth “dance” vous demandera d'octroyer au “Graph API Explorer” l'accès à votre compte Facebook, requête que vous devez évidemment autoriser pour que cela fonctionne.

Une fois de retour sur le “Graph API Explorer”, vous pouvez vous amuser à parcourir les différents types de données auxquelles vous avez maintenant accès. Vous pouvez également en savoir plus à ce sujet dans le Guide de mise en route Facebook. Par exemple, si vous effectuez un POST vers /me/feed tout en ajoutant un champ "message" (cliquez sur "Ajouter un champ") avec une chaîne de caractères, cela affichera le message sur votre ‘timeline’.

Mais notre but ici est de copier le jeton (‘token’) depuis le “Graph API Explorer”, et de l'enregistrer dans un fichier de configuration sur votre serveur personnel. Une fois cela fait, vous pouvez utiliser la classe http.Request de nodejs pour faire des requêtes http à l'API de Facebook. Voici un exemple de script qui met à jour votre statut sur votre “timeline” Facebook :

var https = require('https'),
    config = require('./config').config;

function postToFacebook(str, cb) {
  var req = https.request({
    host: 'graph.facebook.com',
    path: '/me/feed',
    method: 'POST'
  }, function(res) {
    res.setEncoding('utf8');
    res.on('data', function(chunk) {
      console.log('got chunk '+chunk);
    });
    res.on('end', function() {
      console.log('response end with status '+res.status);
    });
  });
  req.end('message='+encodeURIComponent(str)
    +'&access_token='+encodeURIComponent(config.facebookToken));
  console.log('sent');
};

postToFacebook('test from my personal server');

Le résultat devrait ressembler à ceci :

fb-from-explorer

Si vous cliquez sur "apps" en haut à droite dans le menu du “Graph API Explorer” (en étant bien sûr connecté avec votre compte), vous pouvez définir votre propre application client. L'avantage ici est que le résultat affiché dans la “timeline” est un peu plus sympa’, en effet cette option vous pemret de définir l'attribut 'via' et afficher le nom de domaine de votre serveur personnel en lieu et place de cette confuse et incorrecte mention “via Graph API Explorer” :

fb-from-app

Normalement, vous devriez voir ici le nom d'une application effective, comme par exemple, “via Foursquare” ou “via Spotify”. Étant donné qu'ici nous déplaçons l'application en dehors du serveur pour la placer au sein du navigateur, et que le jeton d'accès (“access token”) lui, est conservé au sein de votre serveur personnel, et non dans votre application web unhosted, il vous est alors possible de modifier le texte et d'afficher l'origine effective du billet, il est donc ici correct d'indiquer que ce billet a été posté depuis votre serveur personnel.

Cela signifie que pour tous ceux qui fédèrent leur serveur personnel à Facebook, chacun de ces serveurs sera effectivement une “application cliente Facebook”, mais chacune de ces “applications clientes” n'aura qu'un seul utilisateur, puisque chaque utilisateur, individuellement, enregistre son propre serveur de passerelle personnel en tant que telle.

Il y a un deuxième avantage à enregistrer votre propre application : cela vous permet d'obtenir une “appId” et un “clientSecret” à l'aide desquels vous allez pouvoir échanger le ‘jeton d'une heure’ (“one-hour token”) pour un ‘jeton de 60 jours’ (“60-day token”). Pour cela, il vous est possible d'appeler une fois la fonction nodejs suivante, en donnant comme arguments votre “appId”, votre “clientSecret”, et le jeton de courte durée (“short-lived token”) :

var https = require('https');

function longLiveMyToken(token, appId, clientSecret) {
  var req = https.request({
    host: 'graph.facebook.com',
    path: '/oauth/access_token',
    method: 'POST'
  }, function(res) {
    res.setEncoding('utf8');
    res.on('data', function(chunk) {
      console.log(chunk);
    });
    res.on('end', function() {
      console.log('status: '+res.status);
    });
  });
  req.end('grant_type=fb_exchange_token'
    +'&client_id='+encodeURIComponent(appId)
    +'&client_secret='+encodeURIComponent(clientSecret)
    +'&fb_exchange_token='+encodeURIComponent(token)
   );
};

Une fois ce script exécuté sur votre serveur, vous verrez le jeton à long terme (“long-lived token”) en sortie de console, de là, il vous sera possible de le coller dans votre fichier de configuration. Il vous est également possible d'utiliser le “Graph API Browser” pour cotrôler (“Debug”) " les jetons d'accès (“access tokens”) - de cette manière il vous est possible d'observer la portée de leurs autorisations et leurs durées de vie. Pour autant que je sache, vous n'aurez à répéter cette opération d'échange seulement tous les 60 jours, mais nous pourrions peut-être automatiser celle-ci. Nous n'avons pas nous inquiéter à ce sujet avant deux mois maintenant. :)

Connexion à Twitter

Et puisque c’est vraiment trop facile avec nodejs, voici donc l'équivalent de script côté serveur pour twitter :

var twitter = require('ntwitter'),
    config = require('./config').config;

var twit = new twitter({
  consumer_key: config.twitterConsumerKey,
  consumer_secret: config.twitterConsumerSecret,
  access_token_key: config.twitterAccessToken,
  , access_token_secret: config.twitterAccessTokenSecret
});

function postToTwitter(str, cb) {
  twit.verifyCredentials(function (err, data) {
    if (err) {
      cb("Error verifying credentials: " + err);
    } else {
      twit.updateStatus(str, function (err, data) {
        if (err) {
          cb('Tweeting failed: ' + err);
        } else {
          cb('Success!')
        }
      });
    }
  });
}
postToTwitter('Sent from my personal server', function(result) {
  console.log(result);
}

Pour obtenir les valeurs de configuration pour le script twitter, vous devez vous connecter auprès de dev.twitter.com/apps et cliquer sur “Créer une nouvelle application”. Il vous est possible, ici aussi, de mettre votre propre nom de domaine comme nom d'application, puisque ce sera effectivement votre serveur qui agira en tant qu'application de connexion. Dans la partie “Réglage”, définissez les réglages de l'application à “Lire, Écrire et Messages en accès direct”, et par défaut, donner à l'application les droits d'agir pour le compte avec lequel vous avez enregistré celle-ci.

Au moment j'écris ces lignes, il y a un bug dans ntwitter qui fait échouer l'envoi de tweets contenants des apostrophes ou des points d'exclamation. Sur cette même pages, vous trouverez également un patch, donc si vous êtes vraiment impatient de tweetter des apostrophes, il est toujours possible de l'appliquer, mais personnellement je ne l'ai pas testé. J'en tiens juste compte le temps que le bug soit corrigé et reformule mes tweets de sorte qu'ils ne contiennent pas d’apostrophes. :)

Une passerelle basée sur WebSocket

L'étape suivante consiste à connecter tout ça avec WebSocket. Nous allons simplement intégrer nos fonctions “postToFacebook” et “postToTwitter” dans le script pinger.js que nous avons créé la semaine dernière. Cependant nous devons garder un point important en tête, c'est que nous ne voulons pas que n'importe qui puisse deviner le port WebSocket et puisse alors être en mesure de publier comme bon lui semble sur nos comptes Facebook et Twitter. Donc la solution pour cela est que nous distribuions un jeton d'accès à l'application web unhosted avec laquelle nous souhaitons nous connecter, et ensuite, de faire en sorte que cette application nous retourne ce jeton à chaque fois qu'elle souhaite publier quelque chose.

Téléchargez ce script côté serveur, assurez-vous d'avoir les bonnes variables dans le fichier «config.js" et que celui-ci se trouve dans le même répertoire. Vous pouvez alors l'exécuter en utilisant “forever” :

var sockjs = require('sockjs'),
    fs = require('fs'),
    https = require('https'),
    twitter = require('ntwitter'),
    config = require('./config').config,
    twit = new twitter({
      consumer_key: config.twitterConsumerKey,
      consumer_secret: config.twitterConsumerSecret,
      access_token_key: config.twitterAccessToken,
      access_token_secret: config.twitterAccessTokenSecret
    });

function postToTwitter(str, cb) {
  twit.verifyCredentials(function (err, data) {
    if (err) {
      cb("Error verifying credentials: " + err);
    } else {
      twit.updateStatus(str, function (err, data) {
        if (err) {
          cb('Tweeting failed: ' + err);
        } else {
          cb('Success!')
        }
      });
    }
  });
}

function postToFacebook(str, cb) {
  var req = https.request({
    host: 'graph.facebook.com',
    path: '/me/feed',
    method: 'POST'
  }, function(res) {
    res.setEncoding('utf8');
    var str = '';
    res.on('data', function(chunk) {
      str += chunk;
    });
    res.on('end', function() {
      cb({
        status: res.status,
        text: str
      });
    });
  });
  req.end("message="+encodeURIComponent(str)
    +'&access_token='+encodeURIComponent(config.facebookToken));
};

function handle(conn, chunk) {
  var obj;
  try {
    obj = JSON.parse(chunk);
  } catch(e) {
  }
  if(typeof(obj) == 'object' && obj.secret == config.secret 
     && typeof(obj.object) == 'object') {
    if(obj.world == 'twitter') {
      postToTwitter(obj.object.text, function(result) {
        conn.write(JSON.stringify(result));
      });
    } else if(obj.world == 'facebook') {
      postToFacebook(obj.object.text, function(result) {
        conn.write(JSON.stringify(result));
      });
    } else {
      conn.write(chunk);
    }
  }
}

var httpsServer = https.createServer({ 
  key: fs.readFileSync(config.tlsDir+'/tls.key'), 
  cert: fs.readFileSync(config.tlsDir+'/tls.cert'), 
  ca: fs.readFileSync(config.tlsDir+'/ca.pem') 
}, function(req, res) {
  res.writeHead(200); 
  res.end('connect a WebSocket please'); 
});
httpsServer.listen(config.port);

var sockServer = sockjs.createServer();
sockServer.on('connection', function(conn) {
  conn.on('data', function(chunk) {
    handle(conn, chunk);
  });
});
sockServer.installHandlers(httpsServer, {
  prefix:'/sock'
});
console.log('up');

Et alors, vous allez pouvoir utiliser cette simple application web Unhosted comme nouveau tableau de bord social.

Fédérés ou seulement mandatés ?

Alors maintenant vous allez pouvoir rester en contact avec vos amis sur Facebook et Twitter, sans jamais avoir à vous connecter à l'un de ces jardins clos que sont ces plates-formes monopoles du web 2.0.

Plusieurs personnes ici à Hacker Beach ont réagi lors de l'élaboration de ce billet, en disant que mandatés nos demandes via un serveur ne change pas le fait que nous utilisons ces plates-formes. Je comprends cette réaction, mais je ne suis pas d'accord, pour plusieurs raisons :

.Détacher les applications du “domaine nominatif”

De nombreux services en ligne offrent une application web hébergée, combinée à un service de stockage de données. Mais en dehors de cet hébergement d'applications et de ce stockage de données, beaucoup de ces services se caractérisent par un “Domaine nominatif” ("namespace"), un environnement délimité qui régit le qui et le quoi avec lesquels vous allez pouvoir interagir, et vous propose un jardin clos dans lesquelles vos données “vivent”.

Par exemple, l'application Facebook vous permettra de lire ce qui se passent dans le monde de Facebook, mais pas ce qui se passe à l'extérieur. Comme application, elle reste limitée au “domaine nominatif” Facebook. Cela signifie que cette application hébergée vous donne une vue restreinte de l'univers en ligne, c'est une application logicielle qui est spécifique à un seul “domaine nominatif”. Du point de vue applicatif, nous pouvons dire qu'elle est “verrouillée à un domaine nominatif”, de manière très similaire dont un périphérique de téléphonie mobile peut être lié -(“SIM-locked”)_ part rapport à un fournisseur de carte SIM.

La façon dont nous contournons cette restriction passe par l'interaction avec le “domaine nominatif” d'un service sans utiliser l'application “verrouillée à ce domaine nominatif” qui nous est offerte par ce fournisseur de services. Les applications “verrouillées à un domaine nominatif” limitent notre vision du monde aux interactions que ces fournisseurs d'applications veulent bien nous permettre.

En communiquant donc par le biais de l'API d'un service en lieu et place de l'interface web offerte, nous nous ouvrons la possibilité d'utiliser une application "déverrouillée" que nous pouvons développer nous même et que nous pouvons améliorer et adapter selon notre bon vouloir, et ce, sans les restrictions imposées par un quelconque fournisseur régissant un “domaine nominatif”. Lorsque nous utilisons une application “libérée des domaines nominatifs”, notre point de vue sur le monde connecté devient plus universel et libre, et moins contrôlé et influencé par des intérêts commerciaux.

.Échappez au Conglomérat du Cookie

Facebook et Google vont tenter de “platformiser” votre expérience du Web. Utiliser votre serveur comme un proxy entre votre navigateur et ces plates-formes web 2.0, vous permet d'éviter d'avoir leurs cookies au sein de votre navigateur pendant que vous poursuivez votre navigation sur le web.

.Les comptes liés à chacun de ces mondes sont des pantins, vous détenez votre identité

Depuis que vous utilisez votre propre nom de domaine et votre propre serveur Web pour votre identité principale, les identités avec lesquelles vous apparaissez sur les différentes plateformes fermées ne sont plus votre identité principale ; elles sont maintenant une ombre, ou un hologramme, de votre identité principale, qui elle, réside principalement sur ​​votre site Web indépendant.

.Vos données sont uniquement reflétées, vous détenez la version origonale.

Dès lors que tous les messages passent par la sortie de votre serveur, vous pouvez facilement relayer vos messages en dehors du “domaine nominatif” sur lequel vous les avez initialement publiés, et les garder aussi longtemps que vous le souhaitez dans l'historique de votre journal de données personnel. Il vous est également possible de publier facilement un même contenu sur plusieurs “domaines nominatifs” simultanément quand cela a un sens.

.Que faire si ils annulent votre clé API et éjectent votre “application” de leur plate-forme ?

Cela correspond à vous répertorier en tant qu'émetteur, sur la liste noire d'un serveur de courrier ; cela ne correspond pas à une rétractation de votre droit à envoyer des messages depuis votre serveur, seulement le résultat (de notre point de vue) d'un dysfonctionnement du serveur de réception.

Conclusion

Le grand avantage d'utiliser un serveur personnel de cette manière est que vous ne faites que l'envoi des données à chacun de ces univers web 2.0 que lorsque cela vous est nécessaire pour interagir avec d'autres personnes sur ces mêmes réseaux. Au fond, en utilisant uniquement des applications web Unhosted, vous vous retrouvez déconnecté du web 2.0, même si vos amis continuent toujours à voir vos messages et actions à travers ces identités “fantoches”. Ils n'ont aucune idée qu'ils regardent effectivement un hologramme quand ils interagissent avec vous.

Nous reviendrons à la fois sur Facebook et Twitter dans les prochains épisodes pour discuter d'autres choses comme le contrôle de plus d'un “identifiant Twitter”, de recevoir et de répondre aux demandes d'amis Facebook, et de bien d'autres choses encore. Ces exemples basiques servent principalement pour vous montrer combien il est facile de construire un serveur personnel qui se lie de façon transparente avec les mondes du web 2.0 existants.

De plus, si vous parcourez un peu la documentation des API de Twitter et Facebook, vous pourrez notez un certains nombre de choses sur lesquelles vous pouvez avoir un certain contrôle. Il vous est alors possible d'aller de l'avant et d'ajouter toutes ces fonctions à votre passerelle (assurez-vous seulement de toujours vérifier la validité du jeton (“secret”) envoyé sur le WebSocket), et ensuite d'améliorer cette application de tableau de bord social pour qu'elle puisse faire beaucoup plus de choses.

Vous pouvez ou non, ne pas être conscient du fait que la plupart des autres sites web2.0 ont des “REST APIs” très similaires, et que même lorsqu'une API est un peu plus compliqué, il existe probablement un module nodejs disponibles qui l'encapsule, comme dans le cas ici de Twitter. Il devrait être donc tout à fait possible de créer, par exemple, une application web Unhosted qui permette de publier des “issues” github, en utilisant votre serveur personnel comme passerelle vers les APIs appropriées.

Amusez-vous bien! J'ai déplacé cet épisode un peu en amont d'où il était placé à l'origine dans la série, de manière à ce que vous puissiez avoir une meilleure idée de l'endroit où nous allons, et même si vous avez encore à faire tout cela via ssh. La semaine prochaine, nous allons résoudre ce détails en ajoutant à notre serveur personnel, ce que l'on pourrait appeler une interface “WebShell”. Ainsi, vous pourrez utiliser une application web Unhosted pour télécharger, modifier et exécuter des scripts nodejs sur votre serveur, ou tout aussi bien faire la maintenance serveur que vous effectuez actuellement via ssh. Ce sera une autre étape importante pour le No Cookie Crew. Rendez-vous la semaine prochaine : même heure, même endroit!

Commentaires bienvenus!

Suivant: Le contrôle de votre serveur via un WebSocket