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