[PLUGINS] ~maj des plugins
[lhc/web/www.git] / www / plugins / nospam / nospam_pipelines.php
index 0a7dec3..611acaa 100644 (file)
@@ -8,6 +8,7 @@
 
 if (!defined("_ECRIRE_INC_VERSION")) return;
 if (!defined('_SPAM_URL_MAX_OCCURENCES')) define('_SPAM_URL_MAX_OCCURENCES',3);
+if (!defined('_SPAM_ENCRYPT_NAME')) define('_SPAM_ENCRYPT_NAME',false);
 
 /**
  * Lister les formulaires a prendre en charge contre le SPAM
@@ -35,18 +36,126 @@ function nospam_recuperer_fond($flux) {
                $form = substr($fond, $pos + 12);
                if (in_array($form, nospam_lister_formulaires())) {
                        // on ajoute le champ 'nobot' si pas present dans le formulaire
-                       $texte = &$flux['data']['texte'];
-                       if ((false === strpos($texte, 'name="nobot"'))
-                               and (false !== $pos = strpos($texte, '</form>'))
-                       ) {
-                               $nobot = recuperer_fond("inclure/nobot", array('nobot' => ''));
-                               $texte = substr_replace($texte, $nobot, $pos, 0);
-                       }
+                       nospam_inserer_nobot($flux['data']['texte']);
                }
        }
        return $flux;
 }
 
+/**
+ * Ajouter le champ de formulaire 'nobot' au besoin
+ *
+ * @param array $flux
+ * @return array
+ */
+function nospam_formulaire_fond($flux) {
+       // determiner le nom du formulaire
+       $form = $flux['args']['form'];
+       if (in_array($form, nospam_lister_formulaires())) {
+               // on ajoute le champ 'nobot' si pas present dans le formulaire
+               nospam_inserer_nobot($flux['data']);
+       }
+       return $flux;
+}
+
+/**
+ * Inserer un champ nobot au hasard dans le form
+ * et crypter tous les name
+ * @param string $texte
+ */
+function nospam_inserer_nobot(&$texte){
+       if ((false === strpos($texte, 'name="email_nobot"'))
+               AND (false !== $pos = strpos($texte, '</form>'))
+       ) {
+               // essayer de s'inserer au hasard entre 2 li du form
+               if (preg_match_all(",<li\b[^>]*class=['\"]editer[^>]*,ims",$texte,$m)
+                 AND $p = strpos($texte,$m[0][rand(0,count($m[0])-1)])){
+                       $nobot = recuperer_fond("inclure/nobot", array('email_nobot' => '','div'=>'li'));
+                       $texte = substr_replace($texte, $nobot, $p, 0);
+               }
+               // et sinon a la fin
+               else {
+                       $nobot = recuperer_fond("inclure/nobot", array('email_nobot' => ''));
+                       $texte = substr_replace($texte, $nobot, $pos, 0);
+               }
+       }
+       if (_SPAM_ENCRYPT_NAME){
+               // recuperer toutes les balises input, textarea, select
+               $balises = array_merge(extraire_balises($texte,'input'));
+               foreach($balises as $k=>$b){
+                       if (in_array(extraire_attribut($b,"type"),array("hidden","file")))
+                               unset($balises[$k]);
+               }
+               $balises = array_merge($balises,
+                       extraire_balises($texte,'textarea'),
+                       extraire_balises($texte,'select'));
+
+               $key = "";
+               if (preg_match(",<input type='hidden' name='_jeton' value='([^>]*)' />,Uims",$texte,$m))
+                       $key = $m[1];
+
+               foreach($balises as $k=>$b){
+                       if ($name = extraire_attribut($b,"name")
+                         AND strncmp($name,"session_",8)!==0){
+                               // cas des truc[chose] : on ne brouille que truc
+                               $crypted_name = explode("[",$name);
+                               $crypted_name[0] = nospam_name_encode($crypted_name[0],$key);
+                               $crypted_name = implode("[",$crypted_name);
+                               $b_e = inserer_attribut($b,"name",$crypted_name);
+                               $texte = str_replace($b,$b_e,$texte);
+                       }
+               }
+       }
+}
+
+function nospam_name_encode($name,$key=""){
+       static $private_key=array();
+       static $encoded=array();
+       if (isset($encoded[$key][$name]))
+               return $encoded[$key][$name];
+       if (!$name) return $name;
+       if (!isset($private_key[$key])){
+               $private_key[$key] = nospam_private_key($key);
+               if (!function_exists('_xor'))
+                       include_spip("inc/filtres");
+       }
+       $cname = _xor("xx_$name",$key);
+       $cname = base64_encode($cname);
+       $cname = "x_".rtrim(strtr(base64_encode($cname), '+/', '-_'), '=');
+       return $encoded[$key][$name] = $cname;
+}
+
+function nospam_name_decode($name,$key=""){
+       static $private_key=array();
+       static $decoded=array();
+       if (isset($decoded[$key][$name]))
+               return $decoded[$key][$name];
+       if (!$name) return $name;
+       if (strncmp($name,"x_",2)!==0) return $name;
+       if (!isset($private_key[$key])){
+               $private_key[$key] = nospam_private_key($key);
+               if (!function_exists('_xor'))
+                       include_spip("inc/filtres");
+       }
+       $cname = substr($name,2);
+       $cname = base64_decode(str_pad(strtr($cname, '-_', '+/'), strlen($cname) % 4, '=', STR_PAD_RIGHT));
+       $cname = base64_decode($cname);
+       $cname = _xor($cname,$key);
+       if (strncmp($cname,"xx_",3)!==0) return $name;
+       return $decoded[$key][$name] = substr($cname,3);
+}
+
+function nospam_private_key($key){
+       $private_key = $key . __FILE__;
+       if (function_exists('sha1'))
+               $private_key = sha1($private_key);
+       else
+               $private_key = md5($private_key);
+       $private_key = pack("H*", $private_key);
+       return $private_key;
+}
+
+
 /**
  * Ajouter un jeton temporaire lie a l'heure et a l'IP pour limiter la reutilisation possible du formulaire
  *
@@ -62,6 +171,36 @@ function nospam_formulaire_charger($flux) {
                include_spip("inc/nospam");
                $jeton = creer_jeton($form);
                $flux['data']['_hidden'] .= "<input type='hidden' name='_jeton' value='$jeton' />";
+
+               if (_SPAM_ENCRYPT_NAME){
+                       // recuperer les autosave encryptes si possible
+                       if (is_array($flux['data'])
+                         AND isset($flux['data']['_autosave_id'])
+                         AND $cle_autosave = $flux['data']['_autosave_id']
+                         AND include_spip("inc/cvt_autosave")
+                         AND function_exists("autosave_clean_value")){
+
+                               $je_suis_poste = $flux['args']['je_suis_poste'];
+
+                               $cle_autosave = serialize($cle_autosave);
+                               $cle_autosave = $form."_".md5($cle_autosave);
+
+                               // si on a un backup en session et qu'on est au premier chargement, non poste
+                               // on restitue les donnees
+                               if (isset($GLOBALS['visiteur_session']['session_autosave_'.$cle_autosave])
+                                 AND !$je_suis_poste) {
+                                       parse_str($GLOBALS['visiteur_session']['session_autosave_'.$cle_autosave], $vars);
+                                       if (isset($vars['_jeton'])
+                                         AND $key = $vars['_jeton']){
+                                               foreach ($vars as $name=>$val) {
+                                                       if (($dname = nospam_name_decode($name,$key))!==$name
+                                                         AND isset($flux['data'][$dname]))
+                                                               $flux['data'][$dname] = (is_string($val)?autosave_clean_value($val):array_map('autosave_clean_value',$val));
+                                               }
+                                       }
+                               }
+                       }
+               }
        }
        return $flux;
 }
@@ -73,14 +212,47 @@ function nospam_formulaire_charger($flux) {
  * @return array
  */
 function nospam_formulaire_verifier($flux) {
+       static $deja = false;
        $form = $flux['args']['form'];
        if (in_array($form, nospam_lister_formulaires())) {
                include_spip("inc/nospam");
                $jeton = _request('_jeton');
+               // y a-t-il des names encryptes a decrypter ?
+               // si oui on les decrypte puis on relance la verif complete
+               // attention, du coup verifier() est appele 2 fois dans ce cas (peut poser probleme ?)
+               // donc on repasse ici une deuxieme fois, et il ne faut pas relancer le decryptage
+               if (_SPAM_ENCRYPT_NAME AND !$deja){
+                       $deja = true;
+                       $re_verifier = false;
+                       foreach($_POST as $k=>$v){
+                               $kd = nospam_name_decode($k,$jeton);
+                               if ($kd !== $k){
+                                       set_request($kd,$v);
+                                       $re_verifier = true;
+                               }
+                       }
+                       // si on a decode des champs, il faut relancer toute la chaine de verification et sortir
+                       if ($re_verifier){
+                               $verifier = charger_fonction("verifier","formulaires/$form/",true);
+                               $flux['data'] = pipeline(
+                                                 'formulaire_verifier',
+                                                       array(
+                                                               'args'=>array('form'=>$form,'args'=>$flux['args']['args']),
+                                                               'data'=>$verifier?call_user_func_array($verifier,$flux['args']['args']):array())
+                                                       );
+                               $deja = false;
+                               return $flux;
+                       }
+               }
                // le jeton prend en compte l'heure et l'ip de l'internaute
                if (_request('nobot') // trop facile !
+                       OR _request('email_nobot')
                        OR (!verifier_jeton($jeton, $form))
                ) {
+                       if (_request('email_nobot'))
+                               spip_log('email_nobot rempli : '._request('email_nobot'),'nospam');
+                       if (_request('nobot'))
+                               spip_log('nobot rempli : '._request('email_nobot'),'nospam');
                        #spip_log('pas de jeton pour '.var_export($flux,true),'nospam');
                        $flux['data']['message_erreur'] .= _T('nospam:erreur_jeton');
                        if ($form == 'forum')
@@ -118,7 +290,7 @@ function nospam_pre_edition($flux) {
                // ne pas publier automatiquement certains messages suspects ...
                // sauf si le posteur a de toute facon le pouvoir de moderer et de se publier
                include_spip('inc/autoriser');
-               if ($flux['data']['statut'] == 'publie'
+               if (in_array($flux['data']['statut'],array('prop','publie'))
                        AND (!isset($GLOBALS['visiteur_session']['statut']) OR !autoriser('modererforum'))
                ) {
                        // verifier le status de cette IP
@@ -138,13 +310,13 @@ function nospam_pre_edition($flux) {
                  // cas du spammeur qui envoie que des messages a 3 liens a haute frequence (passe a travers tous les filtres)
                  // au bout du 5e message en <10min ou 10e en <30min on va moderer tout message avec un lien
                  if (!$spammeur_connu){
-                         if (($nb=sql_countsel('spip_forum','(ip='.sql_quote($GLOBALS['ip']).$email.') AND '.sql_date_proche('date_heure','-30','minute')))>=7){
+                         if (($nb=sql_countsel('spip_forum','(ip='.sql_quote($GLOBALS['ip']).$email.') AND '.nospam_sql_date_proche('date_heure','-30','minute')))>=7){
                          spip_log("[Flood] $nb message pour (ip=".$GLOBALS['ip']."$email) dans les 30 dernieres minutes",'nospam');
                          $spammeur_connu = true;
                          }
                  }
                  if (!$spammeur_connu){
-                         if (($nb=sql_countsel('spip_forum','(ip='.sql_quote($GLOBALS['ip']).$email.') AND '.sql_date_proche('date_heure','-10','minute')))>=3){
+                         if (($nb=sql_countsel('spip_forum','(ip='.sql_quote($GLOBALS['ip']).$email.') AND '.nospam_sql_date_proche('date_heure','-10','minute')))>=3){
                          spip_log("[Flood] $nb message pour (ip=".$GLOBALS['ip']."$email) dans les 10 dernieres minutes",'nospam');
                          $spammeur_connu = true;
                          }
@@ -157,38 +329,43 @@ function nospam_pre_edition($flux) {
                        if ($spammeur_connu) {
                                // plus de 30 spams dans les dernieres 2h, faut se calmer ...
                                // ou plus de 10 spams dans la dernieres 1h, faut se calmer ...
-                               // ou IP blacklistee et plus de 5 messages prop/spam dans les dernieres 24h, faut se calmer ...
+                               // ou IP blacklistee et plus de 5 messages prop/spam dans les dernieres 48h, faut se calmer ...
                                if (
                                        (isset($GLOBALS['ip_blacklist'][$GLOBALS['ip']])
-                                  AND ($nb = sql_countsel('spip_forum', sql_in('statut',array('spam')).' AND (ip=' . sql_quote($GLOBALS['ip']).') AND ' . sql_date_proche('date_heure','-24','hour'))) >= 5
-                                        AND $h=24
+                                  AND ($nb = sql_countsel('spip_forum', sql_in('statut',array('spam')).' AND (ip=' . sql_quote($GLOBALS['ip']).') AND ' . nospam_sql_date_proche('date_heure','-48','hour'))) >= 5
+                                        AND $h=48
                                        )
                                        OR
-                                       (($nb = sql_countsel('spip_forum', 'statut=\'spam\' AND (ip=' . sql_quote($GLOBALS['ip']) . $email . ') AND ' . sql_date_proche('date_heure','-120','minute'))) >= 30
+                                       (($nb = sql_countsel('spip_forum', 'statut=\'spam\' AND (ip=' . sql_quote($GLOBALS['ip']) . $email . ') AND ' . nospam_sql_date_proche('date_heure','-120','minute'))) >= 30
                                                AND $h=2)
                                        OR
-                                       (($nb = sql_countsel('spip_forum', 'statut=\'spam\' AND (ip=' . sql_quote($GLOBALS['ip']) . $email .') AND ' . sql_date_proche('date_heure','-60','minute'))) >= 10
+                                       (($nb = sql_countsel('spip_forum', 'statut=\'spam\' AND (ip=' . sql_quote($GLOBALS['ip']) . $email .') AND ' . nospam_sql_date_proche('date_heure','-60','minute'))) >= 10
                                                AND $h=1)
                                        ){
                                        $flux['data']['statut'] = ''; // on n'en veut pas !
                                        spip_log("[Refuse] $nb spam pour (ip=" . $GLOBALS['ip'] . "$email) dans les $h dernieres heures", 'nospam');
                                        return $flux;
                                }
+                               spip_log("POST *suspect* spammeur_connu","nospam");
                        }
                        // sinon regarder si l'objet a une langue, et si le post est dans la meme langue ou non
                        // en cas de langue differente, on se mefie
-                       elseif ($flux['data']['objet']){
-                               $table = table_objet_sql($flux['data']['objet']);
-                               $trouver_table = charger_fonction("trouver_table","base");
-                               if ($desc = $trouver_table($table)
-                                 AND isset($desc['field']['lang'])){
-                                       $primary = id_table_objet($flux['data']['objet']);
-                                       $lang_objet = sql_getfetsel("lang",$table,"$primary=".intval($flux['data']['id_objet']));
-                                       include_spip("inc/detecter_langue");
-                                       $lang_post = _detecter_langue($flux['data']['texte']);
-                                       if ($lang_post!==$lang_objet)
-                                               $lang_suspecte = true;
+                       else{
+                               $lang_objet = ($GLOBALS['spip_lang']?$GLOBALS['spip_lang']:$GLOBALS['meta']['langue_site']);
+                               if ($flux['data']['objet']){
+                                       $table = table_objet_sql($flux['data']['objet']);
+                                       $trouver_table = charger_fonction("trouver_table","base");
+                                       if ($desc = $trouver_table($table)
+                                               AND isset($desc['field']['lang'])){
+                                               $primary = id_table_objet($flux['data']['objet']);
+                                               $lang_objet = sql_getfetsel("lang",$table,"$primary=".intval($flux['data']['id_objet']));
+                                       }
                                }
+                               include_spip("inc/detecter_langue");
+                               $lang_post = _detecter_langue($flux['data']['texte']);
+                               if ($lang_post!==$lang_objet)
+                                       $lang_suspecte = true;
+                               spip_log("POST ".($lang_suspecte?"*suspect* ":"")."en langue [$lang_post] sur $primary=".$flux['data']['id_objet']." en langue [$lang_objet]","nospam");
                        }
 
                        // si c'est un message bourre de liens, on le modere
@@ -262,7 +439,7 @@ function nospam_pre_edition($flux) {
                        // verifier que cette ip n'en est pas a son N-ieme post en peu de temps
                        // plus de 5 messages en 5 minutes c'est suspect ...
                        if ($flux['data']['statut'] != 'spam') {
-                               if (($nb = sql_countsel('spip_forum', 'ip=' . sql_quote($GLOBALS['ip']) . ' AND ' . sql_date_proche('date_heure','-5','minute'))) >= 5){
+                               if (($nb = sql_countsel('spip_forum', 'ip=' . sql_quote($GLOBALS['ip']) . ' AND ' . nospam_sql_date_proche('date_heure','-5','minute'))) >= 5){
                                        $flux['data']['statut'] = 'spam';
                                        spip_log("[Flood2] $nb message pour (ip=".$GLOBALS['ip']."$email) dans les 5 dernieres minutes : requalif en spam",'nospam');
                                }
@@ -272,6 +449,29 @@ function nospam_pre_edition($flux) {
        return $flux;
 }
 
+/**
+ * @param $champ
+ * @param $interval
+ * @param $unite
+ * @return string
+ */
+function nospam_sql_date_proche($champ, $interval, $unite) {
+       if (function_exists("sql_date_proche"))
+               return sql_date_proche($champ, $interval, $unite);
+
+       return '('
+       . $champ
+        . (($interval <= 0) ? '>' : '<')
+        . (($interval <= 0) ? 'DATE_SUB' : 'DATE_ADD')
+       . '('
+       . sql_quote(date('Y-m-d H:i:s'))
+       . ', INTERVAL '
+       . (($interval > 0) ? $interval : (0-$interval))
+       . ' '
+       . $unite
+       . '))';
+}
+
 
 
 /**
@@ -299,7 +499,7 @@ function nospam_flush_and_update(){
        nospam_update_ip_list();
 }
 
-if (!defined('_NOSPAM_IP_LIST_CACHE')) define('_NOSPAM_IP_LIST_CACHE',10800);
+if (!defined('_NOSPAM_IP_LIST_CACHE')) define('_NOSPAM_IP_LIST_CACHE',3600);
 /**
  * Recuperer la liste des IP black ou grey sur nospam.spip.net
  * si on a pas une liste a jour
@@ -327,6 +527,8 @@ function nospam_update_ip_list($async=false){
        include_spip("inc/distant");
        include_spip("inc/json");
        $res = recuperer_page($url_api);
+       if (!$res AND file_exists($f=_DIR_TMP."spamsignal-api-list.txt"))
+               lire_fichier($f,$res);
        if ($res
          AND function_exists("json_decode")
          AND $liste = json_decode($res,true)){
@@ -342,7 +544,7 @@ function nospam_update_ip_list($async=false){
  */
 function nospam_check_ip_status($ip){
        $file = _DIR_TMP."nospam_ip_list.txt";
-       if (!file_exists($file) OR filemtime($file)<time()-_NOSPAM_IP_LIST_CACHE)
+       if (!file_exists($file) OR filemtime($file)<time()-2*_NOSPAM_IP_LIST_CACHE)
                return;
 
        lire_fichier($file,$liste);