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