MOD évite de faire plein de "register" à la suite et ainsi de saturer la bd de plein...
authorGreg Burri <greg.burri@gmail.com>
Mon, 5 May 2008 19:29:06 +0000 (19:29 +0000)
committerGreg Burri <greg.burri@gmail.com>
Mon, 5 May 2008 19:29:06 +0000 (19:29 +0000)
doc/TODO.txt
doc/protocole3.txt
js/euphorik.js
modules/erl/euphorik_bd.erl
modules/erl/euphorik_minichat.erl
modules/erl/euphorik_protocole.erl
modules/erl/euphorik_requests.erl
modules/include/euphorik_bd.hrl
modules/include/euphorik_defines.hrl

index ea55a31..22e81b6 100755 (executable)
       * Un kick : l'utilisateur (ip) est kické et bannis pour 15 min\r
       * Un ban : l'utilisateur (ip) est kické et bannis pour 3 jours
       * Modification de la BD -> ajouter une relation "banned_ip"\r
-* Traiter les tags TODO et FIXME dans le code\r
+* Traiter les tags TODO et FIXME dans le code
+   * Mettre les constantes au niveau du serveur dans euphorik_defines.hrl (par exemple les temps lié au flood)\r
 * Cleaner le code (erl, js, xhtml, css) et eventuellement profiler un peu (le refresh est lent sous opera)\r
 * Restructurer le code Erlang : déplacer certaines fonctions d'un module à l'autre (ev. créer des modules)\r
 * Choisir une licence et la mettre un peu partout dans les sources, voir : http://www.gnu.org/licenses/gpl-howto.fr.html\r
-* Trouver un moyen pour éviter la création à la suite de plusieurs comptes (via register). \r
 * Finir le script de mise en production\r
    * Make des modules.\r
    * Compactage des js lors de la mise en production (afin d'optimiser la bande passante lors de l'accès au site), regarder comment fait jQuery.\r
 [ok] Tester avec des caractères accentués sur Firefox, Safari, Opera et IE7. Les messages doivent être envoyés en UTF8.
 [ok] Tester avec des caractères exotiques (jap, coréen, etc..)
 [ok] Modifier la syntaxe des smiles actuels (pour pas qu'ils entre en conflit avec totoz)
+[ok] Trouver un moyen pour éviter la création à la suite de plusieurs comptes (via register). 
+
 
 === Bugs ===
 1 : Critique
index 585794a..feae1f0 100644 (file)
@@ -89,7 +89,8 @@ ou
             "racine" : 123,
             "page" : 1
          }
-      ]\r
+      ],
+      "ek_master" : true | false\r
    }
  \r
  
@@ -184,11 +185,8 @@ ou
       "message_id" : 123,\r
       "contenu" : "Salut +++ poulpe"\r
    }
-ou\r
-   {\r
-      "reply" : "error",\r
-      "error_message" : "blabla"\r
-   }
+ou
+   <error>
 \r
 \r
 === Envoie d'un troll ===
@@ -219,12 +217,26 @@ c -> s
       "answer_to" : [ 345, 532, ... ]\r
    }
  
-s -> c\r
-   {\r
-      "reply" : "ok" | "error",\r
-      "error_message" : "blabla"\r
+s -> c
+   <ok>
+ou
+   <error>
+
+
+=== Bannissement ===
+
+c -> s
+   {
+      "action" : "ban",
+      "cookie" : "LKJDLAKSJBFLKASN",
+      "duration" : 3, // en heure
+      "user_id" : 67
    }
\r
+   
+s -> c
+   <ok>
+ou
+   <error>\r
  \r
 === Ajout d'une correction d'un messages ===\r
 Le client envoie un correctif sous la forme de texte supplémentaire à appondre au dernier messages.\r
index e8311da..3503c7e 100755 (executable)
@@ -426,6 +426,7 @@ Client.prototype.resetDonneesPersonnelles = function()
    this.nickFormat = "nick"
    
    this.pagePrincipale = 1
+   this.ek_master = false
    
    // les conversations, une conversation est un objet possédant les attributs suivants :
    // - racine (entier)
@@ -706,6 +707,7 @@ Client.prototype.chargerDonnees = function(data)
       // les conversations
       thisClient.conversations = data["conversations"]
       
+      thisClient.ek_master = data["ek_master"]
    }
    this.dernierMessageErreur = data["error_message"]
 }
index c836776..7703bd3 100755 (executable)
@@ -45,6 +45,14 @@ create_tables() ->
       {attributes, record_info(fields, user)},
       {index, [cookie, login]},\r
       {disc_copies, [node()]}\r
+   ]),
+   mnesia:create_table(ip_table, [
+      {attributes, record_info(fields, ip_table)},
+      {disc_copies, [node()]}
+   ]),
+   mnesia:create_table(troll, [
+      {attributes, record_info(fields, troll)},
+      {disc_copies, [node()]}
    ]).
 
 
@@ -94,7 +102,34 @@ vers_version(6) ->
       end,
       record_info(fields, user),
       user
-   ).   
+   );
+% Ajout de la table 'ip_table'
+% Ajout du statut 'ek_master' pour les users
+vers_version(7) ->
+   mnesia:transform_table(
+      user,
+      fun({user, Id, Cookie, Pseudo, Login, Password, Email, Date_creation, Date_derniere_connexion, Css, Nick_format, Indice_flood, Page_Principale, Conversations}) ->
+            {user,  Id, Cookie, Pseudo, Login, Password, Email, Date_creation, Date_derniere_connexion, Css, Nick_format, Indice_flood, Page_Principale, Conversations, false, undefined}
+      end,
+      record_info(fields, user),
+      user
+   ),
+   mnesia:create_table(ip_table, [
+      {attributes, record_info(fields, ip_table)},
+      {disc_copies, [node()]}
+   ]),
+   mnesia:create_table(troll, [
+      {attributes, record_info(fields, troll)},
+      {disc_copies, [node()]}
+   ]);
+vers_version(8) ->
+   mnesia:transform_table(
+      ip_table,
+      fun() -> null end,
+      record_info(fields, ip_table),
+      ip_table
+   ).
+   
 
 
 % exemple de peuplage de la BD, utilisé pour les tests
index 6f229ac..35a9d97 100755 (executable)
    nouveau_message/3,
    reset/0,
    % reservé :
+   can_register/1,
    resultat_transaction/1\r
 ]).\r
 \r
--include("../include/euphorik_bd.hrl").\r
+-include("../include/euphorik_bd.hrl").
+-include("../include/euphorik_defines.hrl").\r
 -include_lib("stdlib/include/qlc.hrl").\r
 
 % Un message est considéré comme du spam s'il est posté 1 seconde ou moins après le dernier posté
@@ -424,8 +426,35 @@ repond_a(M_id) ->
             E#reponse_minichat.repondant =:= M_id,
             M#minichat.id =:= E#reponse_minichat.cible]))
       end
-   )).\r
-   \r
+   )).
+   
+   
+% Si deux enregistrements consequtifs de la même IP sont fait en moins d'une seconde alors 
+% ip_table.nb_try_register est incrémenté de 1 sinon il est décrémenté de 1 (jusqu'a 0).
+% Si ip_table.nb_try_register vaut 5 alors l'ip ne peux plus s'enregistrer pour une heure.\r
+can_register(IP) ->
+   resultat_transaction(mnesia:transaction(
+      fun() ->
+         case qlc:e(qlc:q([I || I <- mnesia:table(ip_table), I#ip_table.ip =:= IP])) of
+            [] -> 
+               mnesia:write(#ip_table{ip = IP, date_last_try_register = now()}),
+               true;
+            [T] ->
+               Delta = delta_date_ms(T#ip_table.date_last_try_register, now()),
+               if T#ip_table.nb_try_register =:= ?NB_MAX_FLOOD_REGISTER, Delta < ?TEMPS_BAN_FLOOD_REGISTER ->
+                     false;
+                  true ->
+                     mnesia:write(#ip_table{
+                        ip = IP,
+                        date_last_try_register = now(),
+                        nb_try_register = T#ip_table.nb_try_register + if Delta < ?TEMPS_FLOOD_REGISTER -> 1; T#ip_table.nb_try_register > 0 -> -1; true -> 0 end
+                     }),
+                     true
+               end
+         end
+      end
+   )).
+   
    
 % Renvoie le résultat d'une transaction (en décomposant le tuple fournit)\r
 resultat_transaction({_, T}) ->
index 7519ba8..59f8def 100755 (executable)
@@ -5,7 +5,7 @@
 
 -module(euphorik_protocole).
 -export([
-   register/1,
+   register/2,
    login/1,
    logout/1,
    profile/1,
 
 
 % Une utilisateur s'enregistre avec un tuple {Login, Password}.
-register([{login, Login}, {password, Password}]) ->
-   case euphorik_minichat:user_by_login(Login) of
-      {ok, _} ->
-         erreur("Login déjà existant");
-      _ ->
-         User = euphorik_minichat:nouveau_user(Login, Password, generer_cookie()),
-         json_reponse_login_ok(User)
+register([{login, Login}, {password, Password}], IP) ->
+   Can_register = euphorik_minichat:can_register(IP),
+   if Can_register ->
+         case euphorik_minichat:user_by_login(Login) of
+            {ok, _} ->
+               erreur("Login déjà existant");
+            _ ->
+               User = euphorik_minichat:nouveau_user(Login, Password, generer_cookie()),
+               json_reponse_login_ok(User)
+         end;
+      true ->
+         erreur_register_flood()
    end;
 % Enregistrement sans {Login, Password}
-register([]) ->   
-   User = euphorik_minichat:nouveau_user("<nick>", generer_cookie()),
-   json_reponse_login_ok(User).
+register([], IP) ->   
+   Can_register = euphorik_minichat:can_register(IP),
+   if Can_register ->
+         User = euphorik_minichat:nouveau_user("<nick>", generer_cookie()),
+         json_reponse_login_ok(User);
+      true ->
+         erreur_register_flood()
+   end.
+   
+erreur_register_flood() ->
+   erreur("Trop de register (flood)").
+   
    
 \r
 % Un utilisateur se logge (avec un couple {login, mot de passe})
index 7ee5c7d..6562e52 100755 (executable)
@@ -19,36 +19,36 @@ tester() ->
    que_dal.\r
 
 \r
-% il faut catcher toutes les exceptions possibles\r
-out(A) ->\r
+out(A) ->
+   %io:format("~p~n~n", [A]),\r
    %inet:setopts(A#arg.clisock, inet:getopts(A#arg.clisock, [active])),\r
    {value, {_, Contenu}} = lists:keysearch("action", 1, yaws_api:parse_post(A)),\r
-   Ret = traiter_donnees(Contenu),
+   Ret = traiter_donnees(Contenu, 1),
    {content, "application/json", Ret}.\r
 
 \r
-traiter_donnees(Contenu) ->
+traiter_donnees(Contenu, IP) ->
    case json:decode_string(Contenu) of
       {ok, {struct, [{action, Action}| Reste]}} ->
-         json:encode(traiter_action(Action, Reste));
+         json:encode(traiter_action(Action, Reste, IP));
       _ ->
          error
    end.
    
 
 % authentification d'un client
-traiter_action("authentification", JSON) ->
+traiter_action("authentification", JSON, _) ->
    euphorik_protocole:login(JSON);
 % un client s'enregistre (pseudo + password)
-traiter_action("register", JSON) ->
-   euphorik_protocole:register(JSON);
+traiter_action("register", JSON, IP) ->
+   euphorik_protocole:register(JSON, IP);
 % modification du profile
-traiter_action("set_profile", JSON) ->
+traiter_action("set_profile", JSON, _) ->
    euphorik_protocole:profile(JSON);
 % un utilisateur attend un événement (par exemple l'arrivé d'un nouveau message)
-traiter_action("wait_event", JSON) ->
+traiter_action("wait_event", JSON, _) ->
    euphorik_protocole:wait_event(JSON);
 % un utilisateur envoie un message
-traiter_action("put_message", JSON) ->
+traiter_action("put_message", JSON, _) ->
    euphorik_protocole:put_message(JSON).
  
\ No newline at end of file
index 173ab09..6c6cb65 100755 (executable)
       nick_format = nick, %atom(), peut valoir 'nick', 'login' ou 'nick_login'
       indice_flood = 0, % integer() est incrémenté lorsque l'utilisateur envoie trop rapidement des messages.
       page_principale = 1, % la page de la conversation principale
-      conversations = [] % [{integer(), integer()}], la liste des messages correspondant au conversation ainsi que la page affichée\r
+      conversations = [], % [{integer(), integer()}], la liste des messages correspondant au conversation ainsi que la page affichée
+      ek_master = false,
+      last_ip % integer(), undefined si inconnu\r
    }). 
+
+
+% identificateur : (ip)
+-record(ip_table,
+   {
+      ip, % integer()
+      ban = false,
+      nb_try_register = 0,
+      nb_try_login = 0, % pour l'instant pas utilisé
+      date_last_try_register,
+      date_last_try_login % pour l'instant pas utilisé
+   }).
+   
+   
+-record(troll,
+   {
+      id,
+      id_user,
+      date, % erlang:now()
+      contenu, % chaine de caractère
+      date_choosen % la date à laquelle le troll est mis sur la page principale
+   }).
+   
\ No newline at end of file
index e69de29..5c2d357 100755 (executable)
@@ -0,0 +1,11 @@
+
+
+
+
+
+% le temps qu'une ip est bannie après avoir voulu s'etre enregistré trop de fois trop rapidement
+-define(TEMPS_BAN_FLOOD_REGISTER, 60 * 60 * 1000). % 1 heure : en ms
+% le temps entre deux tentatives de register pour compter un flood
+-define(TEMPS_FLOOD_REGISTER, 1500). % 1500 ms
+% après 5 flood l'ip fautive est considérée comme bannie
+-define(NB_MAX_FLOOD_REGISTER, 5).