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
$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
*
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;
}
* @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')
// 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
// 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;
}
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
// 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');
}
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
+ . '))';
+}
+
/**
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
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)){
*/
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);