Merge remote branch 'origin/platal-1.0.0' into platal-1.0.1
[platal.git] / modules / platal.php
CommitLineData
e59506eb 1<?php
2/***************************************************************************
9f5bd98e 3 * Copyright (C) 2003-2010 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');
159 XDB::execute('REPLACE INTO carvas (uid, url)
160 VALUES ({?}, {?})',
161 S::i('uid'), $url);
162 S::logger()->log('carva_add', 'http://' . $url);
163 $page->trigSuccess("Redirection activée vers <a href='http://$url'>$url</a>");
164 }
165 } elseif (Env::v('submit') == 'Supprimer') {
166 XDB::execute('DELETE FROM carvas
167 WHERE uid = {?}', S::i('uid'));
bce2f8eb 168 Post::kill('url');
c1e98576 169 S::logger()->log('carva_del');
a7d35093 170 $page->trigSuccess('Redirection supprimée');
bce2f8eb 171 }
172
c1e98576
FB
173 $url = XDB::fetchOneCell('SELECT url
174 FROM carvas
175 WHERE uid = {?}', S::i('uid'));
176 $page->assign('carva', $url);
e67b4436
VZ
177
178 # FIXME: this code is not multi-domain compatible. We should decide how
179 # carva will extend to users not in the main domain.
180 $res = XDB::query("SELECT alias
181 FROM aliases
fe13bc1d 182 WHERE uid = {?} AND FIND_IN_SET('bestalias', flags)",
e67b4436
VZ
183 S::user()->id());
184 $page->assign('bestalias', $res->fetchOneCell());
bce2f8eb 185 }
186
4da0b8d7 187 function handler_prefs_rss(&$page)
7927d719 188 {
8b1f8e12 189 $page->changeTpl('platal/filrss.tpl');
7927d719 190
5e2307dc 191 $page->assign('goback', Env::v('referer', 'login'));
7927d719 192
5e2307dc 193 if (Env::v('act_rss') == 'Activer') {
7927d719 194 $this->__set_rss_state(true);
a7d35093 195 $page->trigSuccess("Ton Fil RSS est activé.");
7927d719 196 }
7927d719 197 }
198
7c77c3ee 199 function handler_password(&$page)
200 {
84270653
VZ
201 global $globals;
202
81b5a6c9 203 if (Post::has('pwhash') && Post::t('pwhash')) {
40d428d8 204 S::assert_xsrf_token();
7c77c3ee 205
81b5a6c9 206 S::set('password', $password = Post::t('pwhash'));
31e01c97
FB
207 XDB::execute('UPDATE accounts
208 SET password = {?}
209 WHERE uid={?}', $password,
210 S::i('uid'));
7c77c3ee 211
84270653
VZ
212 // If GoogleApps is enabled, and the user did choose to use synchronized passwords,
213 // updates the Google Apps password as well.
214 if ($globals->mailstorage->googleapps_domain) {
215 require_once 'googleapps.inc.php';
d56cb887 216 $account = new GoogleAppsAccount(S::user());
f5c4bf30 217 if ($account->active() && $account->sync_password) {
84270653
VZ
218 $account->set_password($password);
219 }
220 }
221
604dfd58
FB
222 S::logger()->log('passwd');
223 Platal::session()->setAccessCookie(true);
7c77c3ee 224
4baa7323 225 $page->changeTpl('platal/password.success.tpl');
7c77c3ee 226 $page->run();
227 }
228
4baa7323
SJ
229 $page->changeTpl('platal/password.tpl');
230 $page->addJsLink('password.js');
46f272fe 231 $page->setTitle('Mon mot de passe');
7c77c3ee 232 }
233
1a5da857 234 function handler_smtppass(&$page)
235 {
8b1f8e12 236 $page->changeTpl('platal/acces_smtp.tpl');
46f272fe 237 $page->setTitle('Acces SMTP/NNTP');
eaf30d86 238
8f201b69
FB
239 $wp = new PlWikiPage('Xorg.SMTPSécurisé');
240 $wp->buildCache();
241 $wp = new PlWikiPage('Xorg.NNTPSécurisé');
242 $wp->buildCache();
1a5da857 243
31e01c97 244 $uid = S::i('uid');
5e2307dc 245 $pass = Env::v('smtppass1');
1a5da857 246
eaf30d86 247 if (Env::v('op') == "Valider" && strlen($pass) >= 6
31e01c97 248 && Env::v('smtppass1') == Env::v('smtppass2')) {
0511895d
FB
249 XDB::execute('UPDATE accounts
250 SET weak_password = {?}
251 WHERE uid = {?}', $pass, $uid);
a7d35093 252 $page->trigSuccess('Mot de passe enregistré');
732e5855 253 S::logger()->log("passwd_ssl");
5e2307dc 254 } elseif (Env::v('op') == "Supprimer") {
0511895d
FB
255 XDB::execute('UPDATE accounts
256 SET weak_password = NULL
257 WHERE uid = {?}', $uid);
a7d35093 258 $page->trigSuccess('Compte SMTP et NNTP supprimé');
732e5855 259 S::logger()->log("passwd_del");
1a5da857 260 }
261
0511895d
FB
262 $res = XDB::query("SELECT weak_password IS NOT NULL
263 FROM accounts
264 WHERE uid = {?}", $uid);
1a5da857 265 $page->assign('actif', $res->fetchOneCell());
1a5da857 266 }
267
8858cfc1 268 function handler_recovery(&$page)
269 {
270 global $globals;
271
8b1f8e12 272 $page->changeTpl('platal/recovery.tpl');
8858cfc1 273
274 if (!Env::has('login') || !Env::has('birth')) {
fd8f77de 275 return;
8858cfc1 276 }
277
5e2307dc 278 if (!ereg('[0-3][0-9][0-1][0-9][1][9]([0-9]{2})', Env::v('birth'))) {
a7d35093 279 $page->trigError('Date de naissance incorrecte ou incohérente');
c9110c6c 280 return;
8858cfc1 281 }
c9110c6c 282
283 $birth = sprintf('%s-%s-%s',
5e2307dc 284 substr(Env::v('birth'), 4, 4),
285 substr(Env::v('birth'), 2, 2),
286 substr(Env::v('birth'), 0, 2));
8858cfc1 287
5e2307dc 288 $mailorg = strtok(Env::v('login'), '@');
8858cfc1 289
6846791e
FB
290 $profile = Profile::get(Env::t('login'));
291 if (is_null($profile) || $profile->birthdate != $birth) {
292 $page->trigError('Les informations que tu as rentrées ne permettent pas de récupérer ton mot de passe.<br />'.
293 'Si tu as un homonyme, utilise prenom.nom.promo comme login');
294 return;
295 }
8c28edc9 296
6846791e
FB
297 $user = $profile->owner();
298 if ($user->state != 'active') {
299 $page->trigError('Ton compte n\'est pas activé.');
300 return;
301 }
302
303 $res = XDB::query("SELECT COUNT(*)
304 FROM emails
305 WHERE uid = {?} AND flags != 'panne' AND flags != 'filter'", $user->id());
306 $count = intval($res->fetchOneCell());
307 if ($count == 0) {
308 $page->assign('no_addr', true);
309 return;
310 }
8858cfc1 311
6846791e
FB
312 $page->assign('ok', true);
313
314 $url = rand_url_id();
06f4daf9 315 XDB::execute('INSERT INTO account_lost_passwords (certificat,uid,created)
6846791e
FB
316 VALUES ({?},{?},NOW())', $url, $user->id());
317 $res = XDB::query('SELECT email
318 FROM emails
319 WHERE uid = {?} AND email = {?}',
320 $user->id(), Post::v('email'));
321 if ($res->numRows()) {
322 $mails = $res->fetchOneCell();
323 } else {
e46cf8c4 324 $res = XDB::query("SELECT email
a4d5829b 325 FROM emails
e46cf8c4 326 WHERE uid = {?} AND NOT FIND_IN_SET('filter', flags)", $user->id());
6846791e
FB
327 $mails = implode(', ', $res->fetchColumn());
328 }
329 $mymail = new PlMailer();
330 $mymail->setFrom('"Gestion des mots de passe" <support+password@' . $globals->mail->domain . '>');
331 $mymail->addTo($mails);
e46cf8c4 332 $mymail->setSubject("Ton certificat d'authentification");
6846791e 333 $mymail->setTxtBody("Visite la page suivante qui expire dans six heures :
8858cfc1 334{$globals->baseurl}/tmpPWD/$url
335
e887e90d 336Si 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 337
eaf30d86 338--
8858cfc1 339Polytechnique.org
3bf63218 340\"Le portail des élèves & anciens élèves de l'École polytechnique\"
8858cfc1 341
faefdbb7 342Email envoyé à ".Env::v('login') . (Post::has('email') ? "
a4d5829b 343Adresse de secours : " . Post::v('email') : ""));
6846791e 344 $mymail->send();
8858cfc1 345
6846791e
FB
346 // on cree un objet logger et on log l'evenement
347 S::logger($user->id())->log('recovery', $mails);
8858cfc1 348 }
349
6c49d0af 350 function handler_tmpPWD(&$page, $certif = null)
351 {
84270653 352 global $globals;
31e01c97 353 // XXX: recovery requires data from the profile
06f4daf9 354 XDB::execute('DELETE FROM account_lost_passwords
31e01c97 355 WHERE DATE_SUB(NOW(), INTERVAL 380 MINUTE) > created');
6c49d0af 356
31e01c97 357 $res = XDB::query('SELECT uid
06f4daf9 358 FROM account_lost_passwords WHERE certificat={?}', $certif);
6c49d0af 359 $ligne = $res->fetchOneAssoc();
360 if (!$ligne) {
8b1f8e12 361 $page->changeTpl('platal/index.tpl');
6c49d0af 362 $page->kill("Cette adresse n'existe pas ou n'existe plus sur le serveur.");
363 }
364
365 $uid = $ligne["uid"];
81b5a6c9
SJ
366 if (Post::has('pwhash') && Post::t('pwhash')) {
367 $password = Post::t('pwhash');
31e01c97
FB
368 XDB::query('UPDATE accounts
369 SET password={?}
370 WHERE uid = {?} AND state = \'active\'',
371 $password, $uid);
06f4daf9 372 XDB::query('DELETE FROM account_lost_passwords
31e01c97 373 WHERE certificat={?}', $certif);
84270653
VZ
374
375 // If GoogleApps is enabled, and the user did choose to use synchronized passwords,
376 // updates the Google Apps password as well.
377 if ($globals->mailstorage->googleapps_domain) {
378 require_once 'googleapps.inc.php';
d56cb887 379 $account = new GoogleAppsAccount(User::getSilent($uid));
f5c4bf30 380 if ($account->active() && $account->sync_password) {
84270653
VZ
381 $account->set_password($password);
382 }
383 }
384
cf40e1ae 385 S::logger($uid)->log("passwd", "");
8b1f8e12 386 $page->changeTpl('platal/tmpPWD.success.tpl');
6c49d0af 387 } else {
4baa7323
SJ
388 $page->changeTpl('platal/password.tpl');
389 $page->addJsLink('password.js');
6c49d0af 390 }
6c49d0af 391 }
392
9bae6004 393 function handler_skin(&$page)
394 {
395 global $globals;
396
8b1f8e12 397 $page->changeTpl('platal/skins.tpl');
46f272fe 398 $page->setTitle('Skins');
9bae6004 399
a7de4ef7 400 if (Env::has('newskin')) { // formulaire soumis, traitons les données envoyées
31e01c97
FB
401 XDB::execute('UPDATE accounts
402 SET skin = {?}
403 WHERE uid = {?}',
404 Env::i('newskin'), S::i('uid'));
92e6a287 405 S::kill('skin');
47fa97fe 406 Platal::session()->setSkin();
9bae6004 407 }
408
31e01c97
FB
409 $res = XDB::query('SELECT id
410 FROM skins
411 WHERE skin_tpl = {?}', S::v('skin'));
92e6a287 412 $page->assign('skin_id', $res->fetchOneCell());
413
31e01c97
FB
414 $sql = 'SELECT s.*, auteur, COUNT(*) AS nb
415 FROM skins AS s
416 LEFT JOIN accounts AS a ON (a.skin = s.id)
417 WHERE skin_tpl != \'\' AND ext != \'\'
418 GROUP BY id ORDER BY s.date DESC';
a3afa47c 419 $page->assign('skins', XDB::iterator($sql));
9bae6004 420 }
4da0b8d7 421
5de0b7e1 422 function handler_exit(&$page, $level = null)
423 {
0c02607e 424 if (S::suid()) {
20b087ff
FB
425 $old = S::user()->login();
426 S::logger()->log('suid_stop', $old . " by " . S::suid('hruid'));
47fa97fe 427 Platal::session()->stopSUID();
20b087ff
FB
428 $target = S::s('suid_startpage');
429 S::kill('suid_startpage');
430 if (!empty($target)) {
431 http_redirect($target);
432 }
433 pl_redirect('admin/user/' . $old);
5de0b7e1 434 }
435
436 if ($level == 'forget' || $level == 'forgetall') {
604dfd58 437 Platal::session()->killAccessCookie();
5de0b7e1 438 }
439
440 if ($level == 'forgetuid' || $level == 'forgetall') {
604dfd58 441 Platal::session()->killLoginFormCookies();
5de0b7e1 442 }
443
130b8708 444 if (S::logged()) {
59bec5bc
FB
445 S::logger()->log('deconnexion', @$_SERVER['HTTP_REFERER']);
446 Platal::session()->destroy();
130b8708 447 }
5de0b7e1 448
449 if (Get::has('redirect')) {
5e2307dc 450 http_redirect(rawurldecode(Get::v('redirect')));
5de0b7e1 451 } else {
8b1f8e12 452 $page->changeTpl('platal/exit.tpl');
5de0b7e1 453 }
5de0b7e1 454 }
ddb64990 455
aab2ffdd 456 function handler_review(&$page, $action = null, $mode = null)
ddb64990 457 {
78507d96
AA
458 // Include X-XRDS-Location response-header for Yadis discovery
459 global $globals;
34d91db6 460 header('X-XRDS-Location: ' . $globals->baseurl . '/openid/xrds');
78507d96 461
460d8f55 462 $this->load('review.inc.php');
ddb64990
FB
463 $dom = 'Review';
464 if (@$GLOBALS['IS_XNET_SITE']) {
465 $dom .= 'Xnet';
466 }
8f201b69
FB
467 $wp = new PlWikiPage($dom . '.Admin');
468 $conf = explode('%0a', $wp->getField('text'));
6d20fb1d 469 $wiz = new PlWizard('Tour d\'horizon', PlPage::getCoreTpl('plwizard.tpl'), true);
ddb64990
FB
470 foreach ($conf as $line) {
471 $list = preg_split('/\s*[*|]\s*/', $line, -1, PREG_SPLIT_NO_EMPTY);
472 $wiz->addPage('ReviewPage', $list[0], $list[1]);
473 }
474 $wiz->apply($page, 'review', $action, $mode);
475 }
e59506eb 476}
477
a7de4ef7 478// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
e59506eb 479?>