Fix MDP auth within a session.
[platal.git] / modules / platal.php
CommitLineData
e59506eb 1<?php
2/***************************************************************************
179afa7f 3 * Copyright (C) 2003-2008 Polytechnique.org *
e59506eb 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
5de0b7e1 22function 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
e59506eb 36class PlatalModule extends PLModule
37{
38 function handlers()
39 {
40 return array(
c9178c75 41 'index' => $this->make_hook('index', AUTH_PUBLIC),
ddb64990 42 'cacert.pem' => $this->make_hook('cacert', AUTH_PUBLIC),
5de0b7e1 43 'changelog' => $this->make_hook('changelog', AUTH_PUBLIC),
44
4da0b8d7 45 // Preferences thingies
bee33d93 46 'prefs' => $this->make_hook('prefs', AUTH_COOKIE),
47 'prefs/rss' => $this->make_hook('prefs_rss', AUTH_COOKIE),
bce2f8eb 48 'prefs/webredirect'
bee33d93 49 => $this->make_hook('webredir', AUTH_MDP),
50 'prefs/skin' => $this->make_hook('skin', AUTH_COOKIE),
4da0b8d7 51
52 // password related thingies
1a5da857 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),
8858cfc1 56 'recovery' => $this->make_hook('recovery', AUTH_PUBLIC),
5de0b7e1 57 'exit' => $this->make_hook('exit', AUTH_PUBLIC),
ddb64990 58 'review' => $this->make_hook('review', AUTH_PUBLIC),
58abb43b 59 'deconnexion.php' => $this->make_hook('exit', AUTH_PUBLIC),
e59506eb 60 );
61 }
62
c9178c75 63 function handler_index(&$page)
64 {
ab66bf7f 65 // Include X-XRDS-Location response-header for Yadis discovery
78507d96 66 global $globals;
ab66bf7f
AA
67 header('X-XRDS-Location: ' . $globals->baseurl . '/openid/idp_xrds');
68
69 // Redirect to the suitable page
cab08090 70 if (S::logged()) {
8b00e0e0 71 pl_redirect('events');
ddb64990 72 } else if (!@$GLOBALS['IS_XNET_SITE']) {
78d4079a 73 $this->handler_review($page);
c9178c75 74 }
c9178c75 75 }
76
5de0b7e1 77 function handler_cacert(&$page)
78 {
ca877168 79 $data = file_get_contents("/etc/ssl/xorgCA/cacert.pem","r");
80 header("Pragma:");
dc41059a 81 header("Set-Cookie:");
82 header("Cache-Control:");
83 header("Expires:");
84 header("Content-Type: application/x-x509-ca-cert");
ca877168 85 header("Content-Length: ".strlen($data));
5de0b7e1 86 echo $data;
87 exit;
88 }
89
78d4079a 90 function handler_changelog(&$page, $core = null)
5de0b7e1 91 {
8b1f8e12 92 $page->changeTpl('platal/changeLog.tpl');
5de0b7e1 93
78d4079a
FB
94 function formatChangeLog($file) {
95 $clog = pl_entities(file_get_contents($file));
96 $clog = preg_replace('/===+\s*/', '</pre><hr /><pre>', $clog);
97 // url catch only (not all wiki syntax)
98 $clog = preg_replace(array(
99 '/((?:https?|ftp):\/\/(?:\.*,*[\w@~%$£µ&i#\-+=_\/\?;])*)/ui',
100 '/(\s|^)www\.((?:\.*,*[\w@~%$£µ&i#\-+=_\/\?;])*)/iu',
101 '/(?:mailto:)?([a-z0-9.\-+_]+@([\-.+_]?[a-z0-9])+)/i'),
102 array(
103 '<a href="\\0">\\0</a>',
104 '\\1<a href="http://www.\\2">www.\\2</a>',
105 '<a href="mailto:\\0">\\0</a>'),
106 $clog);
107 $clog = preg_replace('!(#[0-9]+(,[0-9]+)*)!e', 'bugize("\1")', $clog);
108 $clog = preg_replace('!vim:.*$!', '', $clog);
109 return preg_replace("!(<hr />(\\s|\n)*)?<pre>(\s|\n)*</pre>((\\s|\n)*<hr />)?!m", "", "<pre>$clog</pre>");
110 }
111 if ($core != 'core') {
112 $page->assign('core', false);
113 $page->assign('ChangeLog', formatChangeLog(dirname(__FILE__).'/../ChangeLog'));
114 } else {
115 $page->assign('core', true);
116 $page->assign('ChangeLog', formatChangeLog(dirname(__FILE__).'/../core/ChangeLog'));
117 }
5de0b7e1 118 }
119
7927d719 120 function __set_rss_state($state)
121 {
7927d719 122 if ($state) {
123 $_SESSION['core_rss_hash'] = rand_url_id(16);
08cce2ff 124 XDB::execute('UPDATE auth_user_quick
7927d719 125 SET core_rss_hash={?} WHERE user_id={?}',
cab08090 126 S::v('core_rss_hash'), S::v('uid'));
7927d719 127 } else {
08cce2ff 128 XDB::execute('UPDATE auth_user_quick
7927d719 129 SET core_rss_hash="" WHERE user_id={?}',
cab08090 130 S::v('uid'));
131 S::kill('core_rss_hash');
7927d719 132 }
133 }
134
e59506eb 135 function handler_prefs(&$page)
136 {
8b1f8e12 137 $page->changeTpl('platal/preferences.tpl');
46f272fe 138 $page->setTitle('Mes préférences');
e59506eb 139
bee33d93 140 if (Post::has('mail_fmt')) {
5e2307dc 141 $fmt = Post::v('mail_fmt');
e59506eb 142 if ($fmt != 'texte') $fmt = 'html';
08cce2ff 143 XDB::execute("UPDATE auth_user_quick
e59506eb 144 SET core_mail_fmt = '$fmt'
145 WHERE user_id = {?}",
cab08090 146 S::v('uid'));
e59506eb 147 $_SESSION['mail_fmt'] = $fmt;
e59506eb 148 }
149
bee33d93 150 if (Post::has('rss')) {
5e2307dc 151 $this->__set_rss_state(Post::b('rss'));
e59506eb 152 }
e67b4436
VZ
153
154 # FIXME: this code is not multi-domain compatible. We should decide how
155 # carva will extend to users not in the main domain.
156 $res = XDB::query("SELECT alias
157 FROM aliases
158 WHERE id = {?} AND FIND_IN_SET('bestalias', flags)",
159 S::user()->id());
160 $page->assign('bestalias', $res->fetchOneCell());
e59506eb 161 }
9bae6004 162
bce2f8eb 163 function handler_webredir(&$page)
164 {
8b1f8e12 165 $page->changeTpl('platal/webredirect.tpl');
bce2f8eb 166
46f272fe 167 $page->setTitle('Redirection de page WEB');
bce2f8eb 168
cab08090 169 $log =& S::v('log');
5e2307dc 170 $url = Env::v('url');
bce2f8eb 171
5e2307dc 172 if (Env::v('submit') == 'Valider' and Env::has('url')) {
08cce2ff 173 XDB::execute('UPDATE auth_user_quick
bce2f8eb 174 SET redirecturl = {?} WHERE user_id = {?}',
cab08090 175 $url, S::v('uid'));
732e5855 176 S::logger()->log('carva_add', 'http://'.Env::v('url'));
a7d35093 177 $page->trigSuccess("Redirection activée vers <a href='http://$url'>$url</a>");
5e2307dc 178 } elseif (Env::v('submit') == "Supprimer") {
08cce2ff 179 XDB::execute("UPDATE auth_user_quick
bce2f8eb 180 SET redirecturl = ''
181 WHERE user_id = {?}",
cab08090 182 S::v('uid'));
732e5855 183 S::logger()->log("carva_del", $url);
bce2f8eb 184 Post::kill('url');
a7d35093 185 $page->trigSuccess('Redirection supprimée');
bce2f8eb 186 }
187
08cce2ff 188 $res = XDB::query('SELECT redirecturl
bce2f8eb 189 FROM auth_user_quick
190 WHERE user_id = {?}',
cab08090 191 S::v('uid'));
bce2f8eb 192 $page->assign('carva', $res->fetchOneCell());
e67b4436
VZ
193
194 # FIXME: this code is not multi-domain compatible. We should decide how
195 # carva will extend to users not in the main domain.
196 $res = XDB::query("SELECT alias
197 FROM aliases
198 WHERE id = {?} AND FIND_IN_SET('bestalias', flags)",
199 S::user()->id());
200 $page->assign('bestalias', $res->fetchOneCell());
bce2f8eb 201 }
202
4da0b8d7 203 function handler_prefs_rss(&$page)
7927d719 204 {
8b1f8e12 205 $page->changeTpl('platal/filrss.tpl');
7927d719 206
5e2307dc 207 $page->assign('goback', Env::v('referer', 'login'));
7927d719 208
5e2307dc 209 if (Env::v('act_rss') == 'Activer') {
7927d719 210 $this->__set_rss_state(true);
a7d35093 211 $page->trigSuccess("Ton Fil RSS est activé.");
7927d719 212 }
7927d719 213 }
214
7c77c3ee 215 function handler_password(&$page)
216 {
84270653
VZ
217 global $globals;
218
40d428d8 219 if (Post::has('response2')) {
40d428d8 220 S::assert_xsrf_token();
7c77c3ee 221
5e2307dc 222 $_SESSION['password'] = $password = Post::v('response2');
7c77c3ee 223
eaf30d86 224 XDB::execute('UPDATE auth_user_md5
9ffe0e77 225 SET password={?}
226 WHERE user_id={?}', $password,
227 S::v('uid'));
7c77c3ee 228
84270653
VZ
229 // If GoogleApps is enabled, and the user did choose to use synchronized passwords,
230 // updates the Google Apps password as well.
231 if ($globals->mailstorage->googleapps_domain) {
232 require_once 'googleapps.inc.php';
d56cb887 233 $account = new GoogleAppsAccount(S::user());
f5c4bf30 234 if ($account->active() && $account->sync_password) {
84270653
VZ
235 $account->set_password($password);
236 }
237 }
238
604dfd58
FB
239 S::logger()->log('passwd');
240 Platal::session()->setAccessCookie(true);
7c77c3ee 241
8b1f8e12 242 $page->changeTpl('platal/motdepasse.success.tpl');
7c77c3ee 243 $page->run();
244 }
245
8b1f8e12 246 $page->changeTpl('platal/motdepasse.tpl');
c99ef281 247 $page->addJsLink('motdepasse.js');
46f272fe 248 $page->setTitle('Mon mot de passe');
7c77c3ee 249 }
250
1a5da857 251 function handler_smtppass(&$page)
252 {
8b1f8e12 253 $page->changeTpl('platal/acces_smtp.tpl');
46f272fe 254 $page->setTitle('Acces SMTP/NNTP');
eaf30d86 255
8f201b69
FB
256 $wp = new PlWikiPage('Xorg.SMTPSécurisé');
257 $wp->buildCache();
258 $wp = new PlWikiPage('Xorg.NNTPSécurisé');
259 $wp->buildCache();
1a5da857 260
cab08090 261 $uid = S::v('uid');
5e2307dc 262 $pass = Env::v('smtppass1');
cab08090 263 $log = S::v('log');
1a5da857 264
eaf30d86
PH
265 if (Env::v('op') == "Valider" && strlen($pass) >= 6
266 && Env::v('smtppass1') == Env::v('smtppass2'))
1a5da857 267 {
08cce2ff 268 XDB::execute('UPDATE auth_user_md5 SET smtppass = {?}
1a5da857 269 WHERE user_id = {?}', $pass, $uid);
a7d35093 270 $page->trigSuccess('Mot de passe enregistré');
732e5855 271 S::logger()->log("passwd_ssl");
5e2307dc 272 } elseif (Env::v('op') == "Supprimer") {
08cce2ff 273 XDB::execute('UPDATE auth_user_md5 SET smtppass = ""
1a5da857 274 WHERE user_id = {?}', $uid);
a7d35093 275 $page->trigSuccess('Compte SMTP et NNTP supprimé');
732e5855 276 S::logger()->log("passwd_del");
1a5da857 277 }
278
eaf30d86 279 $res = XDB::query("SELECT IF(smtppass != '', 'actif', '')
1a5da857 280 FROM auth_user_md5
281 WHERE user_id = {?}", $uid);
282 $page->assign('actif', $res->fetchOneCell());
1a5da857 283 }
284
8858cfc1 285 function handler_recovery(&$page)
286 {
287 global $globals;
288
8b1f8e12 289 $page->changeTpl('platal/recovery.tpl');
8858cfc1 290
291 if (!Env::has('login') || !Env::has('birth')) {
fd8f77de 292 return;
8858cfc1 293 }
294
5e2307dc 295 if (!ereg('[0-3][0-9][0-1][0-9][1][9]([0-9]{2})', Env::v('birth'))) {
a7d35093 296 $page->trigError('Date de naissance incorrecte ou incohérente');
c9110c6c 297 return;
8858cfc1 298 }
c9110c6c 299
300 $birth = sprintf('%s-%s-%s',
5e2307dc 301 substr(Env::v('birth'), 4, 4),
302 substr(Env::v('birth'), 2, 2),
303 substr(Env::v('birth'), 0, 2));
8858cfc1 304
5e2307dc 305 $mailorg = strtok(Env::v('login'), '@');
8858cfc1 306
a7de4ef7 307 // paragraphe rajouté : si la date de naissance dans la base n'existe pas, on l'update
308 // avec celle fournie ici en espérant que c'est la bonne
8858cfc1 309
08cce2ff 310 $res = XDB::query(
8858cfc1 311 "SELECT user_id, naissance
312 FROM auth_user_md5 AS u
3a5c1551 313 INNER JOIN aliases AS a ON (u.user_id=a.id AND type != 'homonyme')
8858cfc1 314 WHERE a.alias={?} AND u.perms IN ('admin','user') AND u.deces=0", $mailorg);
315 list($uid, $naissance) = $res->fetchOneRow();
316
317 if ($naissance == $birth) {
8c28edc9 318 $res = XDB::query("SELECT COUNT(*)
319 FROM emails
320 WHERE uid = {?} AND flags != 'panne' AND flags != 'filter'", $uid);
321 $count = intval($res->fetchOneCell());
322 if ($count == 0) {
323 $page->assign('no_addr', true);
324 return;
325 }
326
8858cfc1 327 $page->assign('ok', true);
328
eaf30d86
PH
329 $url = rand_url_id();
330 XDB::execute('INSERT INTO perte_pass (certificat,uid,created)
a4d5829b 331 VALUES ({?},{?},NOW())', $url, $uid);
332 $res = XDB::query('SELECT email
333 FROM emails
334 WHERE uid = {?} AND email = {?}',
335 $uid, Post::v('email'));
336 if ($res->numRows()) {
337 $mails = $res->fetchOneCell();
338 } else {
339 $res = XDB::query('SELECT email
340 FROM emails
341 WHERE uid = {?} AND NOT FIND_IN_SET("filter", flags)', $uid);
342 $mails = implode(', ', $res->fetchColumn());
343 }
1e33266a 344 $mymail = new PlMailer();
1d55fe45 345 $mymail->setFrom('"Gestion des mots de passe" <support+password@' . $globals->mail->domain . '>');
8858cfc1 346 $mymail->addTo($mails);
347 $mymail->setSubject('Ton certificat d\'authentification');
348 $mymail->setTxtBody("Visite la page suivante qui expire dans six heures :
349{$globals->baseurl}/tmpPWD/$url
350
e887e90d 351Si 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.
8858cfc1 352
eaf30d86 353--
8858cfc1 354Polytechnique.org
a7de4ef7 355\"Le portail des élèves & anciens élèves de l'Ecole polytechnique\"
8858cfc1 356
faefdbb7 357Email envoyé à ".Env::v('login') . (Post::has('email') ? "
a4d5829b 358Adresse de secours : " . Post::v('email') : ""));
8858cfc1 359 $mymail->send();
360
361 // on cree un objet logger et on log l'evenement
cf40e1ae 362 S::logger(uid)->log('recovery', $mails);
8858cfc1 363 } else {
a7d35093 364 $page->trigError('Les informations que tu as rentrées ne permettent pas de récupérer ton mot de passe.<br />'.
3a5c1551 365 'Si tu as un homonyme, utilise prenom.nom.promo comme login');
8858cfc1 366 }
8858cfc1 367 }
368
6c49d0af 369 function handler_tmpPWD(&$page, $certif = null)
370 {
84270653 371 global $globals;
08cce2ff 372 XDB::execute('DELETE FROM perte_pass
6c49d0af 373 WHERE DATE_SUB(NOW(), INTERVAL 380 MINUTE) > created');
374
08cce2ff 375 $res = XDB::query('SELECT uid FROM perte_pass WHERE certificat={?}', $certif);
6c49d0af 376 $ligne = $res->fetchOneAssoc();
377 if (!$ligne) {
8b1f8e12 378 $page->changeTpl('platal/index.tpl');
6c49d0af 379 $page->kill("Cette adresse n'existe pas ou n'existe plus sur le serveur.");
380 }
381
382 $uid = $ligne["uid"];
383 if (Post::has('response2')) {
5e2307dc 384 $password = Post::v('response2');
08cce2ff 385 XDB::query('UPDATE auth_user_md5 SET password={?}
6c49d0af 386 WHERE user_id={?} AND perms IN("admin","user")',
387 $password, $uid);
08cce2ff 388 XDB::query('DELETE FROM perte_pass WHERE certificat={?}', $certif);
84270653
VZ
389
390 // If GoogleApps is enabled, and the user did choose to use synchronized passwords,
391 // updates the Google Apps password as well.
392 if ($globals->mailstorage->googleapps_domain) {
393 require_once 'googleapps.inc.php';
d56cb887 394 $account = new GoogleAppsAccount(User::getSilent($uid));
f5c4bf30 395 if ($account->active() && $account->sync_password) {
84270653
VZ
396 $account->set_password($password);
397 }
398 }
399
cf40e1ae 400 S::logger($uid)->log("passwd", "");
8b1f8e12 401 $page->changeTpl('platal/tmpPWD.success.tpl');
6c49d0af 402 } else {
8b1f8e12 403 $page->changeTpl('platal/motdepasse.tpl');
c99ef281 404 $page->addJsLink('motdepasse.js');
6c49d0af 405 }
6c49d0af 406 }
407
9bae6004 408 function handler_skin(&$page)
409 {
410 global $globals;
411
8b1f8e12 412 $page->changeTpl('platal/skins.tpl');
46f272fe 413 $page->setTitle('Skins');
9bae6004 414
a7de4ef7 415 if (Env::has('newskin')) { // formulaire soumis, traitons les données envoyées
08cce2ff 416 XDB::execute('UPDATE auth_user_quick
63528107 417 SET skin={?} WHERE user_id={?}',
5e2307dc 418 Env::i('newskin'), S::v('uid'));
92e6a287 419 S::kill('skin');
47fa97fe 420 Platal::session()->setSkin();
9bae6004 421 }
422
92e6a287 423 $res = XDB::query('SELECT id FROM skins WHERE skin_tpl={?}', S::v('skin'));
424 $page->assign('skin_id', $res->fetchOneCell());
425
9bae6004 426 $sql = "SELECT s.*,auteur,count(*) AS nb
427 FROM skins AS s
428 LEFT JOIN auth_user_quick AS a ON s.id=a.skin
429 WHERE skin_tpl != '' AND ext != ''
430 GROUP BY id ORDER BY s.date DESC";
a3afa47c 431 $page->assign('skins', XDB::iterator($sql));
9bae6004 432 }
4da0b8d7 433
5de0b7e1 434 function handler_exit(&$page, $level = null)
435 {
0c02607e
FB
436 if (S::suid()) {
437 S::logger()->log('suid_stop', S::user()->login() . " by " . S::suid('hruid'));
47fa97fe 438 Platal::session()->stopSUID();
ae277b9f 439 pl_redirect('admin/user/' . S::user()->login());
5de0b7e1 440 }
441
442 if ($level == 'forget' || $level == 'forgetall') {
604dfd58 443 Platal::session()->killAccessCookie();
5de0b7e1 444 }
445
446 if ($level == 'forgetuid' || $level == 'forgetall') {
604dfd58 447 Platal::session()->killLoginFormCookies();
5de0b7e1 448 }
449
604dfd58 450 S::logger()->log('deconnexion', @$_SERVER['HTTP_REFERER']);
47fa97fe 451 Platal::session()->destroy();
5de0b7e1 452
453 if (Get::has('redirect')) {
5e2307dc 454 http_redirect(rawurldecode(Get::v('redirect')));
5de0b7e1 455 } else {
8b1f8e12 456 $page->changeTpl('platal/exit.tpl');
5de0b7e1 457 }
5de0b7e1 458 }
ddb64990
FB
459
460 function handler_review(&$page, $action = null, $mode = null)
461 {
78507d96
AA
462 // Include X-XRDS-Location response-header for Yadis discovery
463 global $globals;
464 header('X-XRDS-Location: ' . $globals->baseurl . '/openid/idp_xrds');
465
460d8f55 466 $this->load('review.inc.php');
ddb64990
FB
467 $dom = 'Review';
468 if (@$GLOBALS['IS_XNET_SITE']) {
469 $dom .= 'Xnet';
470 }
8f201b69
FB
471 $wp = new PlWikiPage($dom . '.Admin');
472 $conf = explode('%0a', $wp->getField('text'));
6d20fb1d 473 $wiz = new PlWizard('Tour d\'horizon', PlPage::getCoreTpl('plwizard.tpl'), true);
ddb64990
FB
474 foreach ($conf as $line) {
475 $list = preg_split('/\s*[*|]\s*/', $line, -1, PREG_SPLIT_NO_EMPTY);
476 $wiz->addPage('ReviewPage', $list[0], $list[1]);
477 }
478 $wiz->apply($page, 'review', $action, $mode);
479 }
e59506eb 480}
481
a7de4ef7 482// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
e59506eb 483?>