Add a generic hash capability to the newsletter.
[platal.git] / modules / platal.php
1 <?php
2 /***************************************************************************
3 * Copyright (C) 2003-2008 Polytechnique.org *
4 * http://opensource.polytechnique.org/ *
5 * *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the Free Software *
18 * Foundation, Inc., *
19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
20 ***************************************************************************/
21
22 function bugize($list)
23 {
24 $list = split(',', $list);
25 $ans = array();
26
27 foreach ($list as $bug) {
28 $clean = str_replace('#', '', $bug);
29 $ans[] = "<a href='http://trackers.polytechnique.org/task/$clean'>$bug</a>";
30 }
31
32 return join(',', $ans);
33 }
34
35
36 class PlatalModule extends PLModule
37 {
38 function handlers()
39 {
40 return array(
41 'index' => $this->make_hook('index', AUTH_PUBLIC),
42 'cacert.pem' => $this->make_hook('cacert', AUTH_PUBLIC),
43 'changelog' => $this->make_hook('changelog', AUTH_PUBLIC),
44
45 // Preferences thingies
46 'prefs' => $this->make_hook('prefs', AUTH_COOKIE),
47 'prefs/rss' => $this->make_hook('prefs_rss', AUTH_COOKIE),
48 'prefs/webredirect'
49 => $this->make_hook('webredir', AUTH_MDP),
50 'prefs/skin' => $this->make_hook('skin', AUTH_COOKIE),
51
52 // password related thingies
53 'password' => $this->make_hook('password', AUTH_MDP),
54 'tmpPWD' => $this->make_hook('tmpPWD', AUTH_PUBLIC),
55 'password/smtp' => $this->make_hook('smtppass', AUTH_MDP),
56 'recovery' => $this->make_hook('recovery', AUTH_PUBLIC),
57 'exit' => $this->make_hook('exit', AUTH_PUBLIC),
58 'review' => $this->make_hook('review', AUTH_PUBLIC),
59 'deconnexion.php' => $this->make_hook('exit', AUTH_PUBLIC),
60 );
61 }
62
63 function handler_index(&$page)
64 {
65 if (S::logged()) {
66 pl_redirect('events');
67 } else if (!@$GLOBALS['IS_XNET_SITE']) {
68 pl_redirect('review');
69 }
70 }
71
72 function handler_cacert(&$page)
73 {
74 $data = file_get_contents("/etc/ssl/xorgCA/cacert.pem","r");
75 header("Pragma:");
76 header("Set-Cookie:");
77 header("Cache-Control:");
78 header("Expires:");
79 header("Content-Type: application/x-x509-ca-cert");
80 header("Content-Length: ".strlen($data));
81 echo $data;
82 exit;
83 }
84
85 function handler_changelog(&$page)
86 {
87 $page->changeTpl('platal/changeLog.tpl');
88
89 $clog = pl_entities(file_get_contents(dirname(__FILE__).'/../ChangeLog'));
90 $clog = preg_replace('/=+\s*/', '</pre><hr /><pre>', $clog);
91 // url catch only (not all wiki syntax)
92 $clog = preg_replace(array(
93 '/((?:https?|ftp):\/\/(?:\.*,*[\w@~%$£µ&i#\-+=_\/\?;])*)/ui',
94 '/(\s|^)www\.((?:\.*,*[\w@~%$£µ&i#\-+=_\/\?;])*)/iu',
95 '/(?:mailto:)?([a-z0-9.\-+_]+@([\-.+_]?[a-z0-9])+)/i'),
96 array(
97 '<a href="\\0">\\0</a>',
98 '\\1<a href="http://www.\\2">www.\\2</a>',
99 '<a href="mailto:\\0">\\0</a>'),
100 $clog);
101 $clog = preg_replace('!(#[0-9]+(,[0-9]+)*)!e', 'bugize("\1")', $clog);
102 $clog = preg_replace('!vim:.*$!', '', $clog);
103 $clog = preg_replace("!(<hr />(\\s|\n)*)?<pre>(\s|\n)*</pre>((\\s|\n)*<hr />)?!m", "", "<pre>$clog</pre>");
104 $page->assign('ChangeLog', $clog);
105 }
106
107 function __set_rss_state($state)
108 {
109 if ($state) {
110 $_SESSION['core_rss_hash'] = rand_url_id(16);
111 XDB::execute('UPDATE auth_user_quick
112 SET core_rss_hash={?} WHERE user_id={?}',
113 S::v('core_rss_hash'), S::v('uid'));
114 } else {
115 XDB::execute('UPDATE auth_user_quick
116 SET core_rss_hash="" WHERE user_id={?}',
117 S::v('uid'));
118 S::kill('core_rss_hash');
119 }
120 }
121
122 function handler_prefs(&$page)
123 {
124 $page->changeTpl('platal/preferences.tpl');
125 $page->assign('xorg_title','Polytechnique.org - Mes préférences');
126
127 if (Post::has('mail_fmt')) {
128 $fmt = Post::v('mail_fmt');
129 if ($fmt != 'texte') $fmt = 'html';
130 XDB::execute("UPDATE auth_user_quick
131 SET core_mail_fmt = '$fmt'
132 WHERE user_id = {?}",
133 S::v('uid'));
134 $_SESSION['mail_fmt'] = $fmt;
135 }
136
137 if (Post::has('rss')) {
138 $this->__set_rss_state(Post::b('rss'));
139 }
140 }
141
142 function handler_webredir(&$page)
143 {
144 $page->changeTpl('platal/webredirect.tpl');
145
146 $page->assign('xorg_title','Polytechnique.org - Redirection de page WEB');
147
148 $log =& S::v('log');
149 $url = Env::v('url');
150
151 if (Env::v('submit') == 'Valider' and Env::has('url')) {
152 XDB::execute('UPDATE auth_user_quick
153 SET redirecturl = {?} WHERE user_id = {?}',
154 $url, S::v('uid'));
155 $log->log('carva_add', 'http://'.Env::v('url'));
156 $page->trig("Redirection activée vers <a href='http://$url'>$url</a>");
157 } elseif (Env::v('submit') == "Supprimer") {
158 XDB::execute("UPDATE auth_user_quick
159 SET redirecturl = ''
160 WHERE user_id = {?}",
161 S::v('uid'));
162 $log->log("carva_del", $url);
163 Post::kill('url');
164 $page->trig('Redirection supprimée');
165 }
166
167 $res = XDB::query('SELECT redirecturl
168 FROM auth_user_quick
169 WHERE user_id = {?}',
170 S::v('uid'));
171 $page->assign('carva', $res->fetchOneCell());
172 }
173
174 function handler_prefs_rss(&$page)
175 {
176 $page->changeTpl('platal/filrss.tpl');
177
178 $page->assign('goback', Env::v('referer', 'login'));
179
180 if (Env::v('act_rss') == 'Activer') {
181 $this->__set_rss_state(true);
182 $page->trig("Ton Fil RSS est activé.");
183 }
184 }
185
186 function handler_password(&$page)
187 {
188 global $globals;
189
190 if (Post::has('response2')) {
191 require_once 'secure_hash.inc.php';
192
193 $_SESSION['password'] = $password = Post::v('response2');
194
195 XDB::execute('UPDATE auth_user_md5
196 SET password={?}
197 WHERE user_id={?}', $password,
198 S::v('uid'));
199
200 // If GoogleApps is enabled, and the user did choose to use synchronized passwords,
201 // updates the Google Apps password as well.
202 if ($globals->mailstorage->googleapps_domain) {
203 require_once 'googleapps.inc.php';
204 $account = new GoogleAppsAccount(S::v('uid'), S::v('forlife'));
205 if ($account->active() && $account->sync_password) {
206 $account->set_password($password);
207 }
208 }
209
210 $log =& S::v('log');
211 $log->log('passwd', '');
212
213 if (Cookie::v('ORGaccess')) {
214 setcookie('ORGaccess', hash_encrypt($password), (time()+25920000), '/', '' ,0);
215 }
216
217 $page->changeTpl('platal/motdepasse.success.tpl');
218 $page->run();
219 }
220
221 $page->changeTpl('platal/motdepasse.tpl');
222 $page->addJsLink('motdepasse.js');
223 $page->assign('xorg_title','Polytechnique.org - Mon mot de passe');
224 }
225
226 function handler_smtppass(&$page)
227 {
228 $page->changeTpl('platal/acces_smtp.tpl');
229 $page->assign('xorg_title','Polytechnique.org - Acces SMTP/NNTP');
230
231 require_once 'wiki.inc.php';
232 wiki_require_page('Xorg.SMTPSécurisé');
233 wiki_require_page('Xorg.NNTPSécurisé');
234
235 $uid = S::v('uid');
236 $pass = Env::v('smtppass1');
237 $log = S::v('log');
238
239 if (Env::v('op') == "Valider" && strlen($pass) >= 6
240 && Env::v('smtppass1') == Env::v('smtppass2'))
241 {
242 XDB::execute('UPDATE auth_user_md5 SET smtppass = {?}
243 WHERE user_id = {?}', $pass, $uid);
244 $page->trig('Mot de passe enregistré');
245 $log->log("passwd_ssl");
246 } elseif (Env::v('op') == "Supprimer") {
247 XDB::execute('UPDATE auth_user_md5 SET smtppass = ""
248 WHERE user_id = {?}', $uid);
249 $page->trig('Compte SMTP et NNTP supprimé');
250 $log->log("passwd_del");
251 }
252
253 $res = XDB::query("SELECT IF(smtppass != '', 'actif', '')
254 FROM auth_user_md5
255 WHERE user_id = {?}", $uid);
256 $page->assign('actif', $res->fetchOneCell());
257 }
258
259 function handler_recovery(&$page)
260 {
261 global $globals;
262
263 $page->changeTpl('platal/recovery.tpl');
264
265 if (!Env::has('login') || !Env::has('birth')) {
266 return;
267 }
268
269 if (!ereg('[0-3][0-9][0-1][0-9][1][9]([0-9]{2})', Env::v('birth'))) {
270 $page->trig('Date de naissance incorrecte ou incohérente');
271 return;
272 }
273
274 $birth = sprintf('%s-%s-%s',
275 substr(Env::v('birth'), 4, 4),
276 substr(Env::v('birth'), 2, 2),
277 substr(Env::v('birth'), 0, 2));
278
279 $mailorg = strtok(Env::v('login'), '@');
280
281 // paragraphe rajouté : si la date de naissance dans la base n'existe pas, on l'update
282 // avec celle fournie ici en espérant que c'est la bonne
283
284 $res = XDB::query(
285 "SELECT user_id, naissance
286 FROM auth_user_md5 AS u
287 INNER JOIN aliases AS a ON (u.user_id=a.id AND type != 'homonyme')
288 WHERE a.alias={?} AND u.perms IN ('admin','user') AND u.deces=0", $mailorg);
289 list($uid, $naissance) = $res->fetchOneRow();
290
291 if ($naissance == $birth) {
292 $res = XDB::query("SELECT COUNT(*)
293 FROM emails
294 WHERE uid = {?} AND flags != 'panne' AND flags != 'filter'", $uid);
295 $count = intval($res->fetchOneCell());
296 if ($count == 0) {
297 $page->assign('no_addr', true);
298 return;
299 }
300
301 $page->assign('ok', true);
302
303 $url = rand_url_id();
304 XDB::execute('INSERT INTO perte_pass (certificat,uid,created)
305 VALUES ({?},{?},NOW())', $url, $uid);
306 $res = XDB::query('SELECT email
307 FROM emails
308 WHERE uid = {?} AND email = {?}',
309 $uid, Post::v('email'));
310 if ($res->numRows()) {
311 $mails = $res->fetchOneCell();
312 } else {
313 $res = XDB::query('SELECT email
314 FROM emails
315 WHERE uid = {?} AND NOT FIND_IN_SET("filter", flags)', $uid);
316 $mails = implode(', ', $res->fetchColumn());
317 }
318 $mymail = new PlMailer();
319 $mymail->setFrom('"Gestion des mots de passe" <support+password@' . $globals->mail->domain . '>');
320 $mymail->addTo($mails);
321 $mymail->setSubject('Ton certificat d\'authentification');
322 $mymail->setTxtBody("Visite la page suivante qui expire dans six heures :
323 {$globals->baseurl}/tmpPWD/$url
324
325 Si en cliquant dessus tu n'y arrives pas, copie intégralement l'adresse dans la barre de ton navigateur. Si tu n'as pas utilisé ce lien dans six heures, tu peux tout simplement recommencer cette procédure.
326
327 --
328 Polytechnique.org
329 \"Le portail des élèves & anciens élèves de l'Ecole polytechnique\"
330
331 Mail envoyé à ".Env::v('login') . (Post::has('email') ? "
332 Adresse de secours : " . Post::v('email') : ""));
333 $mymail->send();
334
335 // on cree un objet logger et on log l'evenement
336 $logger = $_SESSION['log'] = new CoreLogger($uid);
337 $logger->log('recovery', $mails);
338 } else {
339 $page->trig('Les informations que tu as rentrées ne permettent pas de récupérer ton mot de passe.<br />'.
340 'Si tu as un homonyme, utilise prenom.nom.promo comme login');
341 }
342 }
343
344 function handler_tmpPWD(&$page, $certif = null)
345 {
346 global $globals;
347 XDB::execute('DELETE FROM perte_pass
348 WHERE DATE_SUB(NOW(), INTERVAL 380 MINUTE) > created');
349
350 $res = XDB::query('SELECT uid FROM perte_pass WHERE certificat={?}', $certif);
351 $ligne = $res->fetchOneAssoc();
352 if (!$ligne) {
353 $page->changeTpl('platal/index.tpl');
354 $page->kill("Cette adresse n'existe pas ou n'existe plus sur le serveur.");
355 }
356
357 $uid = $ligne["uid"];
358 if (Post::has('response2')) {
359 $password = Post::v('response2');
360 XDB::query('UPDATE auth_user_md5 SET password={?}
361 WHERE user_id={?} AND perms IN("admin","user")',
362 $password, $uid);
363 XDB::query('DELETE FROM perte_pass WHERE certificat={?}', $certif);
364
365 // If GoogleApps is enabled, and the user did choose to use synchronized passwords,
366 // updates the Google Apps password as well.
367 if ($globals->mailstorage->googleapps_domain) {
368 require_once 'googleapps.inc.php';
369 $account = new GoogleAppsAccount($uid);
370 if ($account->active() && $account->sync_password) {
371 $account->set_password($password);
372 }
373 }
374
375 $logger = new CoreLogger($uid);
376 $logger->log("passwd","");
377 $page->changeTpl('platal/tmpPWD.success.tpl');
378 } else {
379 $page->changeTpl('platal/motdepasse.tpl');
380 $page->addJsLink('motdepasse.js');
381 }
382 }
383
384 function handler_skin(&$page)
385 {
386 global $globals;
387
388 $page->changeTpl('platal/skins.tpl');
389 $page->assign('xorg_title','Polytechnique.org - Skins');
390
391 if (Env::has('newskin')) { // formulaire soumis, traitons les données envoyées
392 XDB::execute('UPDATE auth_user_quick
393 SET skin={?} WHERE user_id={?}',
394 Env::i('newskin'), S::v('uid'));
395 S::kill('skin');
396 set_skin();
397 }
398
399 $res = XDB::query('SELECT id FROM skins WHERE skin_tpl={?}', S::v('skin'));
400 $page->assign('skin_id', $res->fetchOneCell());
401
402 $sql = "SELECT s.*,auteur,count(*) AS nb
403 FROM skins AS s
404 LEFT JOIN auth_user_quick AS a ON s.id=a.skin
405 WHERE skin_tpl != '' AND ext != ''
406 GROUP BY id ORDER BY s.date DESC";
407 $page->assign('skins', XDB::iterator($sql));
408 }
409
410 function handler_exit(&$page, $level = null)
411 {
412 if (S::has('suid')) {
413 $a4l = S::v('forlife');
414 $suid = S::v('suid');
415 $log = S::v('log');
416 $log->log("suid_stop", S::v('forlife') . " by " . $suid['forlife']);
417 $_SESSION = $suid;
418 S::kill('suid');
419 pl_redirect('admin/user/' . $a4l);
420 }
421
422 if ($level == 'forget' || $level == 'forgetall') {
423 setcookie('ORGaccess', '', time() - 3600, '/', '', 0);
424 Cookie::kill('ORGaccess');
425 if (isset($_SESSION['log']))
426 $_SESSION['log']->log("cookie_off");
427 }
428
429 if ($level == 'forgetuid' || $level == 'forgetall') {
430 setcookie('ORGuid', '', time() - 3600, '/', '', 0);
431 Cookie::kill('ORGuid');
432 setcookie('ORGdomain', '', time() - 3600, '/', '', 0);
433 Cookie::kill('ORGdomain');
434 }
435
436 if (isset($_SESSION['log'])) {
437 $ref = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '';
438 $_SESSION['log']->log('deconnexion',$ref);
439 }
440
441 XorgSession::destroy();
442
443 if (Get::has('redirect')) {
444 http_redirect(rawurldecode(Get::v('redirect')));
445 } else {
446 $page->changeTpl('platal/exit.tpl');
447 }
448 }
449
450 function handler_review(&$page, $action = null, $mode = null)
451 {
452 require_once 'wiki.inc.php';
453 require_once dirname(__FILE__) . '/platal/review.inc.php';
454 $dir = wiki_work_dir();
455 $dom = 'Review';
456 if (@$GLOBALS['IS_XNET_SITE']) {
457 $dom .= 'Xnet';
458 }
459 if (!is_dir($dir)) {
460 $page->kill("Impossible de trouver le wiki");
461 }
462 if (!file_exists($dir . '/' . $dom . '.Admin')) {
463 $page->kill("Impossible de trouver la page d'administration");
464 }
465 $conf = preg_grep('/^text=/', explode("\n", file_get_contents($dir . '/' . $dom . '.Admin')));
466 $conf = preg_split('/(text\=|\%0a)/', array_shift($conf), -1, PREG_SPLIT_NO_EMPTY);
467 $wiz = new PlWizard('Tour d\'horizon', 'core/plwizard.tpl', true);
468 foreach ($conf as $line) {
469 $list = preg_split('/\s*[*|]\s*/', $line, -1, PREG_SPLIT_NO_EMPTY);
470 $wiz->addPage('ReviewPage', $list[0], $list[1]);
471 }
472 $wiz->apply($page, 'review', $action, $mode);
473 }
474 }
475
476 // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
477 ?>