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