Adds XSRF protection to the Email module.
authorVincent Zanotti <vincent.zanotti@polytechnique.org>
Sun, 18 May 2008 18:51:21 +0000 (20:51 +0200)
committerVincent Zanotti <vincent.zanotti@polytechnique.org>
Sun, 18 May 2008 18:51:21 +0000 (20:51 +0200)
Signed-off-by: Vincent Zanotti <vincent.zanotti@polytechnique.org>
htdocs/javascript/ajax.js
modules/email.php
plugins/function.test_email.php
templates/emails/alias.tpl
templates/emails/broken.tpl
templates/emails/duplicated.tpl
templates/emails/index.tpl
templates/emails/send.tpl
templates/emails/submit_spam.tpl

index 854c4ef..9eb6a60 100644 (file)
@@ -140,9 +140,9 @@ function previewWiki(idFrom, idTo, withTitle, idShow)
     }
 }
 
-function sendTestEmail(forlife)
+function sendTestEmail(token, forlife)
 {
-    Ajax.update_html(null, 'emails/test' + (forlife == null ? '' : '/' + forlife),
+    Ajax.update_html(null, 'emails/test' + (forlife == null ? '' : '/' + forlife) + '?token=' + token,
                      function() {
                         showTempMessage('mail_sent', "Un mail a été envoyé avec succès"
                                         + (forlife == null ? " sur ton adresse." : " sur l'adresse de " + forlife),
index 371ed49..e00cf76 100644 (file)
@@ -50,6 +50,10 @@ class EmailModule extends PLModule
         $uid = S::v('uid');
 
         if ($action == 'best' && $email) {
+            if (!S::has_xsrf_token()) {
+                return PL_FORBIDDEN;
+            }
+
             // bestalias is the first bit : 1
             // there will be maximum 8 bits in flags : 255
             XDB::execute("UPDATE  aliases SET flags=flags & (255 - 1) WHERE id={?}", $uid);
@@ -99,7 +103,7 @@ class EmailModule extends PLModule
 
         $page->assign('demande', AliasReq::get_request($uid));
 
-        if ($action == 'delete' && $value) {
+        if ($action == 'delete' && $value && S::has_xsrf_token()) {
             //Suppression d'un alias
             XDB::execute(
                 'DELETE virtual, virtual_redirect
@@ -107,6 +111,8 @@ class EmailModule extends PLModule
              INNER JOIN virtual_redirect USING (vid)
                   WHERE alias = {?} AND (redirect = {?} OR redirect = {?})', $value,
                 $forlife.'@'.$globals->mail->domain, $forlife.'@'.$globals->mail->domain2);
+        } elseif ($action == 'delete' && $value) {
+            $page->trig("La suppression de ton alias a échouée, merci de réessayer.");
         }
 
         //Récupération des alias éventuellement existants
@@ -121,7 +127,7 @@ class EmailModule extends PLModule
         list($alias, $visibility) = $res->fetchOneRow();
         $page->assign('actuel', $alias);
 
-        if ($action == 'ask' && Env::has('alias') and Env::has('raison')) {
+        if ($action == 'ask' && Env::has('alias') && Env::has('raison') && S::has_xsrf_token()) {
             //Si l'utilisateur vient de faire une damande
 
             $alias  = Env::v('alias');
@@ -167,10 +173,13 @@ class EmailModule extends PLModule
                 $page->assign('success',$alias);
                 return;
             }
-        }
-        elseif ($action == 'set'
-            && ($value == 'public' || $value == 'private'))
-        {
+        } elseif ($action == 'ask' && Env::has('alias') && Env::has('raison')) {
+            $page->trig("Ta demande d'alias n'a pas pu être enregistrée, merci de réessayer.");
+        } elseif ($action == 'set' && ($value == 'public' || $value == 'private')) {
+            if (!S::has_xsrf_token()) {
+                return PL_FORBIDDEN;
+            }
+
             if ($value == 'public') {
                 XDB::execute("UPDATE auth_user_quick SET emails_alias_pub = 'public'
                                          WHERE user_id = {?}", S::v('uid'));
@@ -285,7 +294,7 @@ class EmailModule extends PLModule
         wiki_require_page('Xorg.Mails');
         $page->changeTpl('emails/submit_spam.tpl');
 
-        if (Post::has('send_email')) {
+        if (Post::has('send_email') && S::has_xsrf_token()) {
             $upload = PlUpload::get($_FILES['mail'], S::v('forlife'), 'spam.submit', true);
             if (!$upload) {
                 $page->trig('Une erreur a été rencontrée lors du transfert du fichier');
@@ -307,6 +316,8 @@ class EmailModule extends PLModule
             $mailer->send();
             $page->trig('Le message a été transmis à ' . $box);
             $upload->clear();
+        } elseif (Post::has('send_email')) {
+            $page->trig("La soumission du spam a échouée, merci de réessayer.");
         }
     }
 
@@ -320,6 +331,10 @@ class EmailModule extends PLModule
 
         // action si on recoit un formulaire
         if (Post::has('save')) {
+            if (!S::has_xsrf_token()) {
+                return PL_FORBIDDEN;
+            }
+
             unset($_POST['save']);
             if (trim(preg_replace('/-- .*/', '', Post::v('contenu'))) != "") {
                 $_POST['to_contacts'] = explode(';', @$_POST['to_contacts']);
@@ -329,7 +344,7 @@ class EmailModule extends PLModule
                                     VALUES  ({?}, {?})", S::i('uid'), $data);
             }
             exit;
-        } else if (Env::v('submit') == 'Envoyer') {
+        } else if (Env::v('submit') == 'Envoyer' && S::has_xsrf_token()) {
             function getEmails($aliases)
             {
                 if (!is_array($aliases)) {
@@ -396,6 +411,8 @@ class EmailModule extends PLModule
                     }
                 }
             }
+        } else if (Env::v('submit') == 'Envoyer') {
+            $page->trig("L'envoi de l'email a échoué, merci de réessayer.");
         } else {
             $res = XDB::query("SELECT  data
                                  FROM  email_send_save
@@ -425,6 +442,9 @@ class EmailModule extends PLModule
         global $globals;
         require_once 'emails.inc.php';
 
+        if (!S::has_xsrf_token()) {
+            return PL_FORBIDDEN;
+        }
         if (!S::has_perms() || !$forlife) {
             $forlife = S::v('bestalias');
         }
@@ -455,7 +475,7 @@ class EmailModule extends PLModule
 
         $page->changeTpl('emails/broken.tpl');
 
-        if ($warn == 'warn' && $email) {
+        if ($warn == 'warn' && $email && S::has_xsrf_token()) {
             $email = valide_email($email);
             // vérifications d'usage
             $sel = XDB::query(
@@ -494,7 +514,9 @@ L'équipe d'administration <support@" . $globals->mail->domain . '>';
                 $mail->send();
                 $page->trig("Mail envoyé ! :o)");
             }
-        } elseif (Post::has('email')) {
+        } elseif ($warn == 'warn' && $email) {
+            $page->trig("Nous n'avons pas pu prévenir ton correspondant, merci de réessayer.");
+        } elseif (Post::has('email') && S::has_xsrf_token()) {
             $email = valide_email(Post::v('email'));
 
             list(,$fqdn) = explode('@', $email);
@@ -532,6 +554,8 @@ L'équipe d'administration <support@" . $globals->mail->domain . '>';
                     $page->assign_by_ref('x', $x);
                 }
             }
+        } elseif (Post::has('email')) {
+            $page->trig("Nous n'avons pas réussi à satisfaire ta demande, merci de réessayer.");
         }
     }
 
@@ -545,8 +569,11 @@ L'équipe d'administration <support@" . $globals->mail->domain . '>';
                         'dangerous' => 'Usurpations par cette adresse');
         $page->assign('states', $states);
 
+        if (Post::has('action') && !S::has_xsrf_token()) {
+            $page->kill("L'action n'a pas pu être réalisée, merci de réessayer.");
+        }
         switch (Post::v('action')) {
-        case 'create':
+          case 'create':
             if (trim(Post::v('emailN')) != '') {
                 Xdb::execute('INSERT IGNORE INTO emails_watch (email, state, detection, last, uid, description)
                                           VALUES ({?}, {?}, CURDATE(), NOW(), {?}, {?})',
@@ -554,13 +581,13 @@ L'équipe d'administration <support@" . $globals->mail->domain . '>';
             };
             break;
 
-        case 'edit':
+          case 'edit':
             Xdb::execute('UPDATE emails_watch
                              SET state = {?}, last = NOW(), uid = {?}, description = {?}
                            WHERE email = {?}', Post::v('stateN'), S::i('uid'), Post::v('descriptionN'), Post::v('emailN'));
             break;
 
-        default:
+          default:
             if ($action == 'delete' && !is_null($email)) {
                 Xdb::execute('DELETE FROM emails_watch WHERE email = {?}', $email);
             }
index d9e68ff..80ad621 100644 (file)
 
 function smarty_function_test_email($params, &$smarty) {
     $label = isset($params['title']) ? $params['title'] : 'Envoyer un mail de test';
+    $token = "'" . S::v('xsrf_token') . (isset($params['forlife']) ? "', " : "'");
     $forlife = isset($params['forlife']) ? "'" . $params['forlife'] . "'" : '';
     return '<div class="center">'
          . '  <div id="mail_sent" style="position: absolute;"></div><br />'
-         . '  <form action="emails/test" method="get" onsubmit="return sendTestEmail(' . $forlife . ')">'
+         . '  <form action="emails/test" method="get" onsubmit="return sendTestEmail(' . $token . $forlife . ')">'
+         . '    <input type="hidden" name="token" value="' . S::v('xsrf_token') . '" />'
          . '    <div><input type="submit" name="send" value="' . $label . '" /></div>'
          . '  </form>'
          . '</div>';
index 24f5060..929e443 100644 (file)
@@ -42,7 +42,7 @@
       <td class="orange">
         <input type="checkbox" {if $mail_public}checked="checked"{/if}
             onclick="
-                Ajax.update_html(null,'{$globals->baseurl}/emails/alias/set/'+(this.checked?'public':'private'));
+                Ajax.update_html(null,'{$globals->baseurl}/emails/alias/set/'+(this.checked?'public':'private')+'?token={xsrf_token}');
                 document.getElementById('mail_public').innerHTML = (this.checked?'public et apparaît donc sur ta fiche':'privé et n\'apparaît nulle part sur le site') + '.';
             " />
       </td>
@@ -82,6 +82,7 @@
 
   <br />
   <form action="emails/alias/ask" method="post">
+    {xsrf_token_field}
     <table class="bicol" cellpadding="4" summary="Demande d'alias">
       <tr>
         <th>Demande d'alias</th>
   {if $actuel}
   <form action="emails/alias/delete/{$actuel}" method="post"
       onsubmit="return confirm('Es-tu sûr de vouloir supprimer {$actuel} ?')">
+    {xsrf_token_field}
     <table class="bicol" cellpadding="4" summary="Suppression d'alias">
       <tr>
         <th>Suppression d'alias</th>
index 3d9f4f5..85e915d 100644 (file)
@@ -44,7 +44,7 @@ correspondant si tu veux que nous puissions te répondre.
   <p>
     Nous pensons qu'il serait une bonne idée de le prévenir que cette adresse email ne fonctionne plus.
     Si tu veux que nous lui envoyions un mail automatique de ta part pour le prévenir,
-    <a href="emails/broken/warn/{$email}">clique sur ce lien</a>.
+    <a href="emails/broken/warn/{$email}?token={xsrf_token}">clique sur ce lien</a>.
   </p>
 {elseif $x}
 <h2>Patte Cassée</h2>
@@ -68,6 +68,7 @@ correspondant si tu veux que nous puissions te répondre.
 <br />
 <div class="center">
   <form action="emails/broken" method="post">
+  {xsrf_token_field}
   <table class="tinybicol" cellpadding="3" summary="Saisie email en panne">
     <tr>
       <th>Adresse email défectueuse</th>
index eb9571d..3da2e30 100644 (file)
@@ -57,7 +57,7 @@
     </td>
     <td class="right">
       <a href="admin/emails/duplicated/edit/{$doublon.mail}">{icon name=page_edit title="Editer"}</a>
-      <a href="admin/emails/duplicated/delete/{$doublon.mail}">{icon name=delete title="Supprimer"}</a>
+      <a href="admin/emails/duplicated/delete/{$doublon.mail}?token={xsrf_token}">{icon name=delete title="Supprimer"}</a>
     </td>
   </tr>
   {/foreach}
@@ -65,6 +65,7 @@
 {elseif $action eq "create" || $action eq "edit"}
 [<a href="admin/emails/duplicated">Retour à la liste des doublons</a>]<br /><br />
 <form method="post" action="admin/emails/duplicated">
+{xsrf_token_field}
 <table class="tinybicol">
   <tr>
     <th colspan="2">Commenter le doublon</th>
index 849ab0b..d4d2159 100644 (file)
@@ -39,7 +39,7 @@
       Tes adresses polytechniciennes sont&nbsp;:<br /><br />
         <div>
           {iterate from=$aliases item=a}
-          <input type='radio' {if $a.best}checked="checked"{/if} name='best' value='{$a.alias}' onclick='Ajax.update_html(null,"{$globals->baseurl}/emails/best/{$a.alias}",bestaliasUpdated)' />
+          <input type='radio' {if $a.best}checked="checked"{/if} name='best' value='{$a.alias}' onclick='Ajax.update_html(null,"{$globals->baseurl}/emails/best/{$a.alias}?token={xsrf_token}",bestaliasUpdated)' />
           {if $a.a_vie}(**){/if}{if $a.cent_ans}(*){/if} <strong>{$a.alias}</strong>@{#globals.mail.domain#} et @{#globals.mail.domain2#}
           {if $a.expire}<span class='erreur'>(expire le {$a.expire|date_format})</span>{/if}
           <br />
index 9219ee2..1a3095f 100644 (file)
@@ -68,6 +68,7 @@
     }
     $.post(platal_baseurl + "emails/send",
            { save: true,
+             token: '{xsrf_token}',
              from: form.from.value,
              to_contacts: toc,
              cc_contacts: ccc,
 </script>
 
 <form action="emails/send" method="post" enctype="multipart/form-data" id="form_mail" onsubmit="return check(this);">
+  {xsrf_token_field}
   <table class="bicol" cellpadding="2" cellspacing="0">
     <tr> 
       <th colspan="2">Destinataires</th>
index cb932f6..c14730f 100644 (file)
@@ -23,6 +23,7 @@
 <h1>Soumettre un spam</h1>
 
 <form method="post" action="{$platal->pl_self()}" enctype="multipart/form-data">
+  {xsrf_token_field}
   <table class="tinybicol">
     <tr>
       <td>