2006-03-23 07:51:15 +01:00
|
|
|
#!/usr/bin/perl
|
|
|
|
|
2008-07-11 12:07:48 +02:00
|
|
|
package IkiWiki;
|
|
|
|
|
2006-03-23 07:51:15 +01:00
|
|
|
use warnings;
|
|
|
|
use strict;
|
2006-05-02 08:53:33 +02:00
|
|
|
use IkiWiki;
|
2006-04-25 01:09:26 +02:00
|
|
|
use IkiWiki::UserInfo;
|
2006-07-04 00:14:52 +02:00
|
|
|
use open qw{:utf8 :std};
|
2006-07-03 22:18:16 +02:00
|
|
|
use Encode;
|
2006-03-23 07:51:15 +01:00
|
|
|
|
2008-12-17 21:22:16 +01:00
|
|
|
sub printheader ($) {
|
2006-08-27 22:25:05 +02:00
|
|
|
my $session=shift;
|
|
|
|
|
2011-06-03 20:41:13 +02:00
|
|
|
if (($ENV{HTTPS} && lc $ENV{HTTPS} ne "off") || $config{sslcookie}) {
|
2006-08-27 22:25:05 +02:00
|
|
|
print $session->header(-charset => 'utf-8',
|
2008-08-28 22:09:58 +02:00
|
|
|
-cookie => $session->cookie(-httponly => 1, -secure => 1));
|
2010-01-18 18:33:25 +01:00
|
|
|
}
|
|
|
|
else {
|
2008-08-28 22:09:58 +02:00
|
|
|
print $session->header(-charset => 'utf-8',
|
|
|
|
-cookie => $session->cookie(-httponly => 1));
|
2006-08-27 22:25:05 +02:00
|
|
|
}
|
2008-12-17 21:22:16 +01:00
|
|
|
}
|
2008-01-07 22:34:13 +01:00
|
|
|
|
2010-05-08 21:57:39 +02:00
|
|
|
sub prepform {
|
2007-08-22 23:06:13 +02:00
|
|
|
my $form=shift;
|
|
|
|
my $buttons=shift;
|
|
|
|
my $session=shift;
|
|
|
|
my $cgi=shift;
|
|
|
|
|
|
|
|
if (exists $hooks{formbuilder}) {
|
|
|
|
run_hooks(formbuilder => sub {
|
|
|
|
shift->(form => $form, cgi => $cgi, session => $session,
|
|
|
|
buttons => $buttons);
|
|
|
|
});
|
|
|
|
}
|
2007-12-12 09:01:15 +01:00
|
|
|
|
2010-05-08 21:57:39 +02:00
|
|
|
return $form;
|
|
|
|
}
|
|
|
|
|
|
|
|
sub showform ($$$$;@) {
|
|
|
|
my $form=prepform(@_);
|
|
|
|
shift;
|
|
|
|
my $buttons=shift;
|
|
|
|
my $session=shift;
|
|
|
|
my $cgi=shift;
|
|
|
|
|
2007-12-12 09:01:15 +01:00
|
|
|
printheader($session);
|
2011-01-05 21:58:27 +01:00
|
|
|
print cgitemplate($cgi, $form->title,
|
|
|
|
$form->render(submit => $buttons), @_);
|
2008-12-17 21:22:16 +01:00
|
|
|
}
|
2006-08-27 22:25:05 +02:00
|
|
|
|
2011-01-05 21:58:27 +01:00
|
|
|
sub cgitemplate ($$$;@) {
|
2011-01-05 18:49:04 +01:00
|
|
|
my $cgi=shift;
|
2011-01-05 21:58:27 +01:00
|
|
|
my $title=shift;
|
|
|
|
my $content=shift;
|
2011-01-05 18:49:04 +01:00
|
|
|
my %params=@_;
|
2011-01-05 21:58:27 +01:00
|
|
|
|
|
|
|
my $template=template("page.tmpl");
|
2011-01-05 18:49:04 +01:00
|
|
|
|
2011-01-05 21:58:27 +01:00
|
|
|
my $page="";
|
|
|
|
if (exists $params{page}) {
|
|
|
|
$page=delete $params{page};
|
2014-10-06 00:49:17 +02:00
|
|
|
$params{forcebaseurl}=urlto($page);
|
2011-01-05 21:58:27 +01:00
|
|
|
}
|
|
|
|
run_hooks(pagetemplate => sub {
|
|
|
|
shift->(
|
|
|
|
page => $page,
|
|
|
|
destpage => $page,
|
|
|
|
template => $template,
|
|
|
|
);
|
|
|
|
});
|
|
|
|
templateactions($template, "");
|
|
|
|
|
2014-10-06 00:49:17 +02:00
|
|
|
my $baseurl = baseurl();
|
|
|
|
|
2011-01-05 21:58:27 +01:00
|
|
|
$template->param(
|
|
|
|
dynamic => 1,
|
|
|
|
title => $title,
|
|
|
|
wikiname => $config{wikiname},
|
|
|
|
content => $content,
|
2014-10-06 00:49:17 +02:00
|
|
|
baseurl => $baseurl,
|
2011-01-05 21:58:27 +01:00
|
|
|
html5 => $config{html5},
|
|
|
|
%params,
|
|
|
|
);
|
|
|
|
|
|
|
|
return $template->output;
|
2011-01-05 18:49:04 +01:00
|
|
|
}
|
|
|
|
|
2008-12-17 21:22:16 +01:00
|
|
|
sub redirect ($$) {
|
2006-07-07 23:00:48 +02:00
|
|
|
my $q=shift;
|
2009-10-29 15:17:30 +01:00
|
|
|
eval q{use URI};
|
2014-10-06 00:06:48 +02:00
|
|
|
|
|
|
|
my $topurl;
|
|
|
|
if (defined $q && ! $config{w3mmode} && ! $config{reverse_proxy}) {
|
|
|
|
$topurl = $q->url;
|
|
|
|
}
|
|
|
|
|
|
|
|
my $url=URI->new(urlabs(shift, $topurl));
|
2006-07-07 23:00:48 +02:00
|
|
|
if (! $config{w3mmode}) {
|
|
|
|
print $q->redirect($url);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
print "Content-type: text/plain\n";
|
|
|
|
print "W3m-control: GOTO $url\n\n";
|
|
|
|
}
|
2008-12-17 21:22:16 +01:00
|
|
|
}
|
2006-07-07 23:00:48 +02:00
|
|
|
|
2008-12-17 21:22:16 +01:00
|
|
|
sub decode_cgi_utf8 ($) {
|
2010-01-18 18:08:26 +01:00
|
|
|
# decode_form_utf8 method is needed for 5.01
|
2008-05-21 21:30:56 +02:00
|
|
|
if ($] < 5.01) {
|
|
|
|
my $cgi = shift;
|
|
|
|
foreach my $f ($cgi->param) {
|
2014-10-15 23:32:02 +02:00
|
|
|
$cgi->param($f, map { decode_utf8 $_ }
|
|
|
|
@{$cgi->param_fetch($f)});
|
2008-05-21 21:30:56 +02:00
|
|
|
}
|
|
|
|
}
|
2008-12-17 21:22:16 +01:00
|
|
|
}
|
2008-05-21 21:30:56 +02:00
|
|
|
|
2014-09-10 05:11:51 +02:00
|
|
|
sub safe_decode_utf8 ($) {
|
|
|
|
my $octets = shift;
|
2015-01-25 05:49:23 +01:00
|
|
|
if (!Encode::is_utf8($octets)) {
|
2014-09-10 05:11:51 +02:00
|
|
|
return decode_utf8($octets);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return $octets;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-12-17 21:22:16 +01:00
|
|
|
sub decode_form_utf8 ($) {
|
2008-05-21 21:30:56 +02:00
|
|
|
if ($] >= 5.01) {
|
|
|
|
my $form = shift;
|
|
|
|
foreach my $f ($form->field) {
|
2014-09-10 05:11:51 +02:00
|
|
|
my @value=map { safe_decode_utf8($_) } $form->field($f);
|
2008-05-21 21:30:56 +02:00
|
|
|
$form->field(name => $f,
|
2010-01-09 22:07:01 +01:00
|
|
|
value => \@value,
|
2008-05-21 21:30:56 +02:00
|
|
|
force => 1,
|
|
|
|
);
|
|
|
|
}
|
2006-07-11 23:20:14 +02:00
|
|
|
}
|
2008-12-17 21:22:16 +01:00
|
|
|
}
|
2006-07-11 23:20:14 +02:00
|
|
|
|
2007-02-02 03:33:03 +01:00
|
|
|
# Check if the user is signed in. If not, redirect to the signin form and
|
|
|
|
# save their place to return to later.
|
2008-12-17 21:22:16 +01:00
|
|
|
sub needsignin ($$) {
|
2007-02-02 03:33:03 +01:00
|
|
|
my $q=shift;
|
|
|
|
my $session=shift;
|
|
|
|
|
|
|
|
if (! defined $session->param("name") ||
|
|
|
|
! userinfo_get($session->param("name"), "regdate")) {
|
2012-04-08 20:12:02 +02:00
|
|
|
$session->param(postsignin => $q->query_string);
|
2007-02-02 03:33:03 +01:00
|
|
|
cgi_signin($q, $session);
|
|
|
|
cgi_savesession($session);
|
|
|
|
exit;
|
|
|
|
}
|
2008-12-17 21:22:16 +01:00
|
|
|
}
|
2007-02-02 03:33:03 +01:00
|
|
|
|
2010-05-08 21:57:39 +02:00
|
|
|
sub cgi_signin ($$;$) {
|
2006-03-23 07:51:15 +01:00
|
|
|
my $q=shift;
|
|
|
|
my $session=shift;
|
2010-05-08 21:57:39 +02:00
|
|
|
my $returnhtml=shift;
|
2006-03-23 07:51:15 +01:00
|
|
|
|
2008-05-21 21:30:56 +02:00
|
|
|
decode_cgi_utf8($q);
|
2006-03-23 07:51:15 +01:00
|
|
|
eval q{use CGI::FormBuilder};
|
2006-11-08 22:03:33 +01:00
|
|
|
error($@) if $@;
|
2006-03-23 07:51:15 +01:00
|
|
|
my $form = CGI::FormBuilder->new(
|
|
|
|
title => "signin",
|
2007-04-30 23:27:58 +02:00
|
|
|
name => "signin",
|
2006-06-11 20:51:49 +02:00
|
|
|
charset => "utf-8",
|
2006-03-23 07:51:15 +01:00
|
|
|
method => 'POST',
|
|
|
|
required => 'NONE',
|
|
|
|
javascript => 0,
|
|
|
|
params => $q,
|
2010-11-24 00:12:21 +01:00
|
|
|
action => cgiurl(),
|
2006-03-23 07:51:15 +01:00
|
|
|
header => 0,
|
2007-04-30 23:27:58 +02:00
|
|
|
template => {type => 'div'},
|
2010-05-07 04:27:12 +02:00
|
|
|
stylesheet => 1,
|
2006-03-23 07:51:15 +01:00
|
|
|
);
|
2006-11-20 21:37:27 +01:00
|
|
|
my $buttons=["Login"];
|
2006-03-23 07:51:15 +01:00
|
|
|
|
2007-02-02 03:33:03 +01:00
|
|
|
$form->field(name => "do", type => "hidden", value => "signin",
|
|
|
|
force => 1);
|
2006-03-23 07:51:15 +01:00
|
|
|
|
Fixes for behavior changes in perl 5.10's CGI
Something has changed in CGI.pm in perl 5.10. It used to not care
if STDIN was opened using :utf8, but now it'll mis-encode utf-8 values
when used that way by ikiwiki. Now I have to binmode(STDIN) before
instantiating the CGI object.
In 57bba4dac132a06729eeec809f5e1a5adf829806, I changed from decoding
CGI::Formbuilder fields to utf-8, to decoding cgi parameters before setting
up the form object. As of perl 5.10, that approach no longer has any effect
(reason unknown). To get correctly encoded values in FormBuilder forms,
they must once again be decoded after the form is set up.
As noted in 57bba4da, this can cause one set of problems for
formbuilder_setup hooks if decode_form_utf8 is called before the hooks, and
a different set if it's called after. To avoid both sets of problems, call
it both before and after. (Only remaining problem is the sheer ugliness and
inefficiency of that..)
I think that these changes will also work with older perl versions, but I
haven't checked.
Also, in the case of the poll plugin, the cgi parameter needs to be
explcitly decoded before it is used to handle utf-8 values. (This may have
always been broken, not sure if it's related to perl 5.10 or not.)
2008-05-13 02:40:59 +02:00
|
|
|
decode_form_utf8($form);
|
2006-11-20 21:37:27 +01:00
|
|
|
run_hooks(formbuilder_setup => sub {
|
2007-08-17 07:34:59 +02:00
|
|
|
shift->(form => $form, cgi => $q, session => $session,
|
|
|
|
buttons => $buttons);
|
2006-11-20 21:37:27 +01:00
|
|
|
});
|
Fixes for behavior changes in perl 5.10's CGI
Something has changed in CGI.pm in perl 5.10. It used to not care
if STDIN was opened using :utf8, but now it'll mis-encode utf-8 values
when used that way by ikiwiki. Now I have to binmode(STDIN) before
instantiating the CGI object.
In 57bba4dac132a06729eeec809f5e1a5adf829806, I changed from decoding
CGI::Formbuilder fields to utf-8, to decoding cgi parameters before setting
up the form object. As of perl 5.10, that approach no longer has any effect
(reason unknown). To get correctly encoded values in FormBuilder forms,
they must once again be decoded after the form is set up.
As noted in 57bba4da, this can cause one set of problems for
formbuilder_setup hooks if decode_form_utf8 is called before the hooks, and
a different set if it's called after. To avoid both sets of problems, call
it both before and after. (Only remaining problem is the sheer ugliness and
inefficiency of that..)
I think that these changes will also work with older perl versions, but I
haven't checked.
Also, in the case of the poll plugin, the cgi parameter needs to be
explcitly decoded before it is used to handle utf-8 values. (This may have
always been broken, not sure if it's related to perl 5.10 or not.)
2008-05-13 02:40:59 +02:00
|
|
|
decode_form_utf8($form);
|
2006-03-23 07:51:15 +01:00
|
|
|
|
2007-08-22 23:06:13 +02:00
|
|
|
if ($form->submitted) {
|
|
|
|
$form->validate;
|
2006-03-23 07:51:15 +01:00
|
|
|
}
|
2007-08-22 23:06:13 +02:00
|
|
|
|
2010-05-08 21:57:39 +02:00
|
|
|
if ($returnhtml) {
|
|
|
|
$form=prepform($form, $buttons, $session, $q);
|
|
|
|
return $form->render(submit => $buttons);
|
|
|
|
}
|
|
|
|
|
2007-08-22 23:06:13 +02:00
|
|
|
showform($form, $buttons, $session, $q);
|
2008-12-17 21:22:16 +01:00
|
|
|
}
|
2006-03-23 07:51:15 +01:00
|
|
|
|
2008-12-17 21:22:16 +01:00
|
|
|
sub cgi_postsignin ($$) {
|
2006-11-20 10:40:09 +01:00
|
|
|
my $q=shift;
|
|
|
|
my $session=shift;
|
2007-02-24 01:20:36 +01:00
|
|
|
|
2006-11-20 10:40:09 +01:00
|
|
|
# Continue with whatever was being done before the signin process.
|
2007-02-24 01:20:36 +01:00
|
|
|
if (defined $session->param("postsignin")) {
|
|
|
|
my $postsignin=CGI->new($session->param("postsignin"));
|
|
|
|
$session->clear("postsignin");
|
|
|
|
cgi($postsignin, $session);
|
|
|
|
cgi_savesession($session);
|
|
|
|
exit;
|
|
|
|
}
|
|
|
|
else {
|
2009-02-26 07:59:05 +01:00
|
|
|
if ($config{sslcookie} && ! $q->https()) {
|
2009-07-23 00:41:33 +02:00
|
|
|
error(gettext("probable misconfiguration: sslcookie is set, but you are attempting to login via http, not https"));
|
2009-02-26 07:59:05 +01:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
error(gettext("login failed, perhaps you need to turn on cookies?"));
|
|
|
|
}
|
2007-02-24 01:20:36 +01:00
|
|
|
}
|
2008-12-17 21:22:16 +01:00
|
|
|
}
|
2006-11-20 10:40:09 +01:00
|
|
|
|
2008-12-17 21:22:16 +01:00
|
|
|
sub cgi_prefs ($$) {
|
2006-03-23 07:51:15 +01:00
|
|
|
my $q=shift;
|
|
|
|
my $session=shift;
|
|
|
|
|
2007-02-02 03:33:03 +01:00
|
|
|
needsignin($q, $session);
|
2008-05-21 21:30:56 +02:00
|
|
|
decode_cgi_utf8($q);
|
Fix CSRF attacks against the preferences and edit forms. Closes: #475445
The fix involved embedding the session id in the forms, and not allowing the
forms to be submitted if the embedded id does not match the session id.
In the case of the preferences form, if the session id is not embedded,
then the CGI parameters are cleared. This avoids a secondary attack where the
link to the preferences form prefills password or other fields, and
the user hits "submit" without noticing these prefilled values.
In the case of the editpage form, the anonok plugin can allow anyone to edit,
and so I chose not to guard against CSRF attacks against users who are not
logged in. Otherwise, it also embeds the session id and checks it.
For page editing, I assume that the user will notice if content or commit
message is changed because of CGI parameters, and won't blndly hit save page.
So I didn't block those CGI paramters. (It's even possible to use those CGI
parameters, for good, not for evil, I guess..)
The only other CSRF attack I can think of in ikiwiki involves the poll plugin.
It's certianly possible to set up a link that causes the user to unknowingly
vote in a poll. However, the poll plugin is not intended to be used for things
that people would want to attack, since anyone can after all edit the poll page
and fill in any values they like. So this "attack" is ignorable.
2008-04-10 22:35:30 +02:00
|
|
|
|
|
|
|
# The session id is stored on the form and checked to
|
|
|
|
# guard against CSRF.
|
|
|
|
my $sid=$q->param('sid');
|
|
|
|
if (! defined $sid) {
|
|
|
|
$q->delete_all;
|
|
|
|
}
|
|
|
|
elsif ($sid ne $session->id) {
|
|
|
|
error(gettext("Your login session has expired."));
|
|
|
|
}
|
|
|
|
|
2006-03-23 07:51:15 +01:00
|
|
|
eval q{use CGI::FormBuilder};
|
2006-11-08 22:03:33 +01:00
|
|
|
error($@) if $@;
|
2006-03-23 07:51:15 +01:00
|
|
|
my $form = CGI::FormBuilder->new(
|
|
|
|
title => "preferences",
|
2007-04-30 23:27:58 +02:00
|
|
|
name => "preferences",
|
2006-03-23 07:51:15 +01:00
|
|
|
header => 0,
|
2006-06-11 20:51:49 +02:00
|
|
|
charset => "utf-8",
|
2006-03-23 07:51:15 +01:00
|
|
|
method => 'POST',
|
|
|
|
validate => {
|
|
|
|
email => 'EMAIL',
|
|
|
|
},
|
|
|
|
required => 'NONE',
|
|
|
|
javascript => 0,
|
|
|
|
params => $q,
|
2010-11-24 00:12:21 +01:00
|
|
|
action => cgiurl(),
|
2007-04-30 23:27:58 +02:00
|
|
|
template => {type => 'div'},
|
2010-05-07 04:27:12 +02:00
|
|
|
stylesheet => 1,
|
2007-04-29 23:57:25 +02:00
|
|
|
fieldsets => [
|
|
|
|
[login => gettext("Login")],
|
|
|
|
[preferences => gettext("Preferences")],
|
|
|
|
[admin => gettext("Admin")]
|
|
|
|
],
|
2006-03-23 07:51:15 +01:00
|
|
|
);
|
2006-11-20 21:37:27 +01:00
|
|
|
my $buttons=["Save Preferences", "Logout", "Cancel"];
|
Fixes for behavior changes in perl 5.10's CGI
Something has changed in CGI.pm in perl 5.10. It used to not care
if STDIN was opened using :utf8, but now it'll mis-encode utf-8 values
when used that way by ikiwiki. Now I have to binmode(STDIN) before
instantiating the CGI object.
In 57bba4dac132a06729eeec809f5e1a5adf829806, I changed from decoding
CGI::Formbuilder fields to utf-8, to decoding cgi parameters before setting
up the form object. As of perl 5.10, that approach no longer has any effect
(reason unknown). To get correctly encoded values in FormBuilder forms,
they must once again be decoded after the form is set up.
As noted in 57bba4da, this can cause one set of problems for
formbuilder_setup hooks if decode_form_utf8 is called before the hooks, and
a different set if it's called after. To avoid both sets of problems, call
it both before and after. (Only remaining problem is the sheer ugliness and
inefficiency of that..)
I think that these changes will also work with older perl versions, but I
haven't checked.
Also, in the case of the poll plugin, the cgi parameter needs to be
explcitly decoded before it is used to handle utf-8 values. (This may have
always been broken, not sure if it's related to perl 5.10 or not.)
2008-05-13 02:40:59 +02:00
|
|
|
|
|
|
|
decode_form_utf8($form);
|
2006-11-20 21:37:27 +01:00
|
|
|
run_hooks(formbuilder_setup => sub {
|
2007-08-17 07:34:59 +02:00
|
|
|
shift->(form => $form, cgi => $q, session => $session,
|
|
|
|
buttons => $buttons);
|
2006-11-20 21:37:27 +01:00
|
|
|
});
|
Fixes for behavior changes in perl 5.10's CGI
Something has changed in CGI.pm in perl 5.10. It used to not care
if STDIN was opened using :utf8, but now it'll mis-encode utf-8 values
when used that way by ikiwiki. Now I have to binmode(STDIN) before
instantiating the CGI object.
In 57bba4dac132a06729eeec809f5e1a5adf829806, I changed from decoding
CGI::Formbuilder fields to utf-8, to decoding cgi parameters before setting
up the form object. As of perl 5.10, that approach no longer has any effect
(reason unknown). To get correctly encoded values in FormBuilder forms,
they must once again be decoded after the form is set up.
As noted in 57bba4da, this can cause one set of problems for
formbuilder_setup hooks if decode_form_utf8 is called before the hooks, and
a different set if it's called after. To avoid both sets of problems, call
it both before and after. (Only remaining problem is the sheer ugliness and
inefficiency of that..)
I think that these changes will also work with older perl versions, but I
haven't checked.
Also, in the case of the poll plugin, the cgi parameter needs to be
explcitly decoded before it is used to handle utf-8 values. (This may have
always been broken, not sure if it's related to perl 5.10 or not.)
2008-05-13 02:40:59 +02:00
|
|
|
decode_form_utf8($form);
|
2006-03-23 07:51:15 +01:00
|
|
|
|
Fix CSRF attacks against the preferences and edit forms. Closes: #475445
The fix involved embedding the session id in the forms, and not allowing the
forms to be submitted if the embedded id does not match the session id.
In the case of the preferences form, if the session id is not embedded,
then the CGI parameters are cleared. This avoids a secondary attack where the
link to the preferences form prefills password or other fields, and
the user hits "submit" without noticing these prefilled values.
In the case of the editpage form, the anonok plugin can allow anyone to edit,
and so I chose not to guard against CSRF attacks against users who are not
logged in. Otherwise, it also embeds the session id and checks it.
For page editing, I assume that the user will notice if content or commit
message is changed because of CGI parameters, and won't blndly hit save page.
So I didn't block those CGI paramters. (It's even possible to use those CGI
parameters, for good, not for evil, I guess..)
The only other CSRF attack I can think of in ikiwiki involves the poll plugin.
It's certianly possible to set up a link that causes the user to unknowingly
vote in a poll. However, the poll plugin is not intended to be used for things
that people would want to attack, since anyone can after all edit the poll page
and fill in any values they like. So this "attack" is ignorable.
2008-04-10 22:35:30 +02:00
|
|
|
$form->field(name => "do", type => "hidden", value => "prefs",
|
|
|
|
force => 1);
|
|
|
|
$form->field(name => "sid", type => "hidden", value => $session->id,
|
|
|
|
force => 1);
|
2007-04-29 23:57:25 +02:00
|
|
|
$form->field(name => "email", size => 50, fieldset => "preferences");
|
2006-03-23 07:51:15 +01:00
|
|
|
|
2006-11-20 21:37:27 +01:00
|
|
|
my $user_name=$session->param("name");
|
2008-08-01 23:37:24 +02:00
|
|
|
|
2006-03-23 07:51:15 +01:00
|
|
|
if (! $form->submitted) {
|
|
|
|
$form->field(name => "email", force => 1,
|
|
|
|
value => userinfo_get($user_name, "email"));
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($form->submitted eq 'Logout') {
|
|
|
|
$session->delete();
|
2010-11-23 01:00:11 +01:00
|
|
|
redirect($q, baseurl(undef));
|
2006-03-23 07:51:15 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
elsif ($form->submitted eq 'Cancel') {
|
2010-11-23 01:00:11 +01:00
|
|
|
redirect($q, baseurl(undef));
|
2006-03-23 07:51:15 +01:00
|
|
|
return;
|
|
|
|
}
|
2006-12-29 05:38:40 +01:00
|
|
|
elsif ($form->submitted eq 'Save Preferences' && $form->validate) {
|
2017-01-11 14:22:03 +01:00
|
|
|
my $email = $form->field('email');
|
|
|
|
if (defined $email) {
|
|
|
|
userinfo_set($user_name, 'email', $email) ||
|
2008-01-29 06:36:58 +01:00
|
|
|
error("failed to set email");
|
2006-03-23 07:51:15 +01:00
|
|
|
}
|
2008-08-01 23:37:24 +02:00
|
|
|
|
2006-12-29 05:38:40 +01:00
|
|
|
$form->text(gettext("Preferences saved."));
|
2006-03-23 07:51:15 +01:00
|
|
|
}
|
|
|
|
|
2010-05-15 03:45:22 +02:00
|
|
|
showform($form, $buttons, $session, $q,
|
|
|
|
prefsurl => "", # avoid showing the preferences link
|
|
|
|
);
|
2008-12-17 21:22:16 +01:00
|
|
|
}
|
2006-03-23 07:51:15 +01:00
|
|
|
|
2009-12-15 00:16:47 +01:00
|
|
|
sub cgi_custom_failure ($$$) {
|
|
|
|
my $q=shift;
|
|
|
|
my $httpstatus=shift;
|
2009-02-01 01:02:50 +01:00
|
|
|
my $message=shift;
|
|
|
|
|
2009-12-15 00:16:47 +01:00
|
|
|
print $q->header(
|
|
|
|
-status => $httpstatus,
|
|
|
|
-charset => 'utf-8',
|
|
|
|
);
|
2009-02-01 01:02:50 +01:00
|
|
|
print $message;
|
|
|
|
|
|
|
|
# Internet Explod^Hrer won't show custom 404 responses
|
|
|
|
# unless they're >= 512 bytes
|
|
|
|
print ' ' x 512;
|
|
|
|
|
|
|
|
exit;
|
|
|
|
}
|
|
|
|
|
2008-12-17 21:22:16 +01:00
|
|
|
sub check_banned ($$) {
|
2008-08-01 23:37:24 +02:00
|
|
|
my $q=shift;
|
|
|
|
my $session=shift;
|
|
|
|
|
2009-09-08 21:17:39 +02:00
|
|
|
my $banned=0;
|
2008-08-01 23:37:24 +02:00
|
|
|
my $name=$session->param("name");
|
2015-05-14 17:37:47 +02:00
|
|
|
my $cloak=cloak($name) if defined $name;
|
2009-09-08 21:17:39 +02:00
|
|
|
if (defined $name &&
|
2015-05-14 17:37:47 +02:00
|
|
|
grep { $name eq $_ || $cloak eq $_ } @{$config{banned_users}}) {
|
2009-09-08 21:17:39 +02:00
|
|
|
$banned=1;
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach my $b (@{$config{banned_users}}) {
|
|
|
|
if (pagespec_match("", $b,
|
2010-06-23 22:32:20 +02:00
|
|
|
ip => $session->remote_addr(),
|
2015-05-14 17:37:47 +02:00
|
|
|
name => defined $name ? $name : "")
|
|
|
|
|| pagespec_match("", $b,
|
|
|
|
ip => cloak($session->remote_addr()),
|
|
|
|
name => defined $cloak ? $cloak : "")) {
|
2009-09-08 21:17:39 +02:00
|
|
|
$banned=1;
|
|
|
|
last;
|
2008-08-01 23:37:24 +02:00
|
|
|
}
|
|
|
|
}
|
2009-09-08 21:17:39 +02:00
|
|
|
|
|
|
|
if ($banned) {
|
|
|
|
$session->delete();
|
|
|
|
cgi_savesession($session);
|
|
|
|
cgi_custom_failure(
|
2009-12-15 00:16:47 +01:00
|
|
|
$q, "403 Forbidden",
|
2009-09-08 21:17:39 +02:00
|
|
|
gettext("You are banned."));
|
|
|
|
}
|
2008-12-17 21:22:16 +01:00
|
|
|
}
|
2006-03-23 07:51:15 +01:00
|
|
|
|
2008-12-17 21:22:16 +01:00
|
|
|
sub cgi_getsession ($) {
|
2006-11-26 20:43:50 +01:00
|
|
|
my $q=shift;
|
|
|
|
|
2008-10-20 03:07:12 +02:00
|
|
|
eval q{use CGI::Session; use HTML::Entities};
|
2008-05-21 21:15:11 +02:00
|
|
|
error($@) if $@;
|
2008-10-20 03:07:12 +02:00
|
|
|
CGI::Session->name("ikiwiki_session_".encode_entities($config{wikiname}));
|
2006-11-26 20:43:50 +01:00
|
|
|
|
|
|
|
my $oldmask=umask(077);
|
2008-07-10 19:16:03 +02:00
|
|
|
my $session = eval {
|
|
|
|
CGI::Session->new("driver:DB_File", $q,
|
|
|
|
{ FileName => "$config{wikistatedir}/sessions.db" })
|
|
|
|
};
|
|
|
|
if (! $session || $@) {
|
protect $@ whenever a block using $@ is non-trivial
As noted in the Try::Tiny man page, eval/$@ can be quite awkward in
corner cases, because $@ has the same properties and problems as C's
errno. While writing a regression test for definetemplate
in which it couldn't find an appropriate template, I received
<span class="error">Error: failed to process template
<span class="createlink">deftmpl</span> </span>
instead of the intended
<span class="error">Error: failed to process template
<span class="createlink">deftmpl</span> template deftmpl not
found</span>
which turned out to be because the "catch"-analogous block called
gettext before it used $@, and gettext can call define_gettext,
which uses eval.
This commit alters all current "catch"-like blocks that use $@, except
those that just do trivial things with $@ (string interpolation, string
concatenation) and call a function (die, error, print, etc.)
2014-02-21 18:06:36 +01:00
|
|
|
my $error = $@;
|
|
|
|
error($error." ".CGI::Session->errstr());
|
2008-07-10 19:16:03 +02:00
|
|
|
}
|
|
|
|
|
2006-11-26 20:43:50 +01:00
|
|
|
umask($oldmask);
|
|
|
|
|
|
|
|
return $session;
|
2008-12-17 21:22:16 +01:00
|
|
|
}
|
2006-11-26 20:43:50 +01:00
|
|
|
|
2008-12-17 20:26:08 +01:00
|
|
|
# To guard against CSRF, the user's session id (sid)
|
|
|
|
# can be stored on a form. This function will check
|
|
|
|
# (for logged in users) that the sid on the form matches
|
|
|
|
# the session id in the cookie.
|
2008-12-17 21:22:16 +01:00
|
|
|
sub checksessionexpiry ($$) {
|
2008-12-17 20:26:08 +01:00
|
|
|
my $q=shift;
|
2008-11-22 22:53:33 +01:00
|
|
|
my $session = shift;
|
|
|
|
|
|
|
|
if (defined $session->param("name")) {
|
2008-12-17 20:26:08 +01:00
|
|
|
my $sid=$q->param('sid');
|
2008-11-22 22:53:33 +01:00
|
|
|
if (! defined $sid || $sid ne $session->id) {
|
|
|
|
error(gettext("Your login session has expired."));
|
|
|
|
}
|
|
|
|
}
|
2008-12-17 21:22:16 +01:00
|
|
|
}
|
2008-11-22 22:53:33 +01:00
|
|
|
|
2008-12-17 21:22:16 +01:00
|
|
|
sub cgi_savesession ($) {
|
2006-11-26 20:43:50 +01:00
|
|
|
my $session=shift;
|
|
|
|
|
|
|
|
# Force session flush with safe umask.
|
|
|
|
my $oldmask=umask(077);
|
|
|
|
$session->flush;
|
|
|
|
umask($oldmask);
|
2008-12-17 21:22:16 +01:00
|
|
|
}
|
2006-11-26 20:43:50 +01:00
|
|
|
|
2008-12-17 21:22:16 +01:00
|
|
|
sub cgi (;$$) {
|
2006-11-20 10:40:09 +01:00
|
|
|
my $q=shift;
|
|
|
|
my $session=shift;
|
|
|
|
|
2008-07-01 19:43:32 +02:00
|
|
|
eval q{use CGI};
|
|
|
|
error($@) if $@;
|
2016-01-18 09:45:18 +01:00
|
|
|
no warnings "once";
|
2008-07-01 19:43:32 +02:00
|
|
|
$CGI::DISABLE_UPLOADS=$config{cgi_disable_uploads};
|
2016-01-18 09:45:18 +01:00
|
|
|
use warnings;
|
2008-07-01 19:43:32 +02:00
|
|
|
|
2006-11-20 10:40:09 +01:00
|
|
|
if (! $q) {
|
Fixes for behavior changes in perl 5.10's CGI
Something has changed in CGI.pm in perl 5.10. It used to not care
if STDIN was opened using :utf8, but now it'll mis-encode utf-8 values
when used that way by ikiwiki. Now I have to binmode(STDIN) before
instantiating the CGI object.
In 57bba4dac132a06729eeec809f5e1a5adf829806, I changed from decoding
CGI::Formbuilder fields to utf-8, to decoding cgi parameters before setting
up the form object. As of perl 5.10, that approach no longer has any effect
(reason unknown). To get correctly encoded values in FormBuilder forms,
they must once again be decoded after the form is set up.
As noted in 57bba4da, this can cause one set of problems for
formbuilder_setup hooks if decode_form_utf8 is called before the hooks, and
a different set if it's called after. To avoid both sets of problems, call
it both before and after. (Only remaining problem is the sheer ugliness and
inefficiency of that..)
I think that these changes will also work with older perl versions, but I
haven't checked.
Also, in the case of the poll plugin, the cgi parameter needs to be
explcitly decoded before it is used to handle utf-8 values. (This may have
always been broken, not sure if it's related to perl 5.10 or not.)
2008-05-13 02:40:59 +02:00
|
|
|
binmode(STDIN);
|
2006-11-20 10:40:09 +01:00
|
|
|
$q=CGI->new;
|
Fixes for behavior changes in perl 5.10's CGI
Something has changed in CGI.pm in perl 5.10. It used to not care
if STDIN was opened using :utf8, but now it'll mis-encode utf-8 values
when used that way by ikiwiki. Now I have to binmode(STDIN) before
instantiating the CGI object.
In 57bba4dac132a06729eeec809f5e1a5adf829806, I changed from decoding
CGI::Formbuilder fields to utf-8, to decoding cgi parameters before setting
up the form object. As of perl 5.10, that approach no longer has any effect
(reason unknown). To get correctly encoded values in FormBuilder forms,
they must once again be decoded after the form is set up.
As noted in 57bba4da, this can cause one set of problems for
formbuilder_setup hooks if decode_form_utf8 is called before the hooks, and
a different set if it's called after. To avoid both sets of problems, call
it both before and after. (Only remaining problem is the sheer ugliness and
inefficiency of that..)
I think that these changes will also work with older perl versions, but I
haven't checked.
Also, in the case of the poll plugin, the cgi parameter needs to be
explcitly decoded before it is used to handle utf-8 values. (This may have
always been broken, not sure if it's related to perl 5.10 or not.)
2008-05-13 02:40:59 +02:00
|
|
|
binmode(STDIN, ":utf8");
|
2006-05-03 23:50:39 +02:00
|
|
|
|
2006-11-20 10:40:09 +01:00
|
|
|
run_hooks(cgi => sub { shift->($q) });
|
|
|
|
}
|
|
|
|
|
2006-03-23 07:51:15 +01:00
|
|
|
my $do=$q->param('do');
|
|
|
|
if (! defined $do || ! length $do) {
|
2006-07-10 23:13:41 +02:00
|
|
|
my $error = $q->cgi_error;
|
|
|
|
if ($error) {
|
|
|
|
error("Request not processed: $error");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
error("\"do\" parameter missing");
|
|
|
|
}
|
2006-03-23 07:51:15 +01:00
|
|
|
}
|
2009-01-31 15:48:44 +01:00
|
|
|
|
2006-11-20 13:03:35 +01:00
|
|
|
# Need to lock the wiki before getting a session.
|
|
|
|
lockwiki();
|
2008-02-03 06:23:04 +01:00
|
|
|
loadindex();
|
2006-03-23 07:51:15 +01:00
|
|
|
|
2006-11-20 10:40:09 +01:00
|
|
|
if (! $session) {
|
2006-11-26 20:43:50 +01:00
|
|
|
$session=cgi_getsession($q);
|
2006-11-20 10:40:09 +01:00
|
|
|
}
|
2006-03-23 07:51:15 +01:00
|
|
|
|
2006-11-20 02:52:18 +01:00
|
|
|
# Auth hooks can sign a user in.
|
|
|
|
if ($do ne 'signin' && ! defined $session->param("name")) {
|
|
|
|
run_hooks(auth => sub {
|
|
|
|
shift->($q, $session)
|
|
|
|
});
|
|
|
|
if (defined $session->param("name")) {
|
|
|
|
# Make sure whatever user was authed is in the
|
|
|
|
# userinfo db.
|
|
|
|
if (! userinfo_get($session->param("name"), "regdate")) {
|
|
|
|
userinfo_setall($session->param("name"), {
|
2011-06-09 16:58:05 +02:00
|
|
|
email => defined $session->param("email") ? $session->param("email") : "",
|
2006-11-20 02:52:18 +01:00
|
|
|
password => "",
|
|
|
|
regdate => time,
|
2007-02-15 03:22:08 +01:00
|
|
|
}) || error("failed adding user");
|
2006-11-20 02:52:18 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-02-02 03:33:03 +01:00
|
|
|
|
2008-08-01 23:37:24 +02:00
|
|
|
check_banned($q, $session);
|
|
|
|
|
2007-08-05 23:38:27 +02:00
|
|
|
run_hooks(sessioncgi => sub { shift->($q, $session) });
|
|
|
|
|
|
|
|
if ($do eq 'signin') {
|
2007-02-02 03:33:03 +01:00
|
|
|
cgi_signin($q, $session);
|
|
|
|
cgi_savesession($session);
|
|
|
|
}
|
2006-03-23 07:51:15 +01:00
|
|
|
elsif ($do eq 'prefs') {
|
|
|
|
cgi_prefs($q, $session);
|
|
|
|
}
|
2008-01-07 22:39:49 +01:00
|
|
|
elsif (defined $session->param("postsignin") || $do eq 'postsignin') {
|
2008-01-07 21:56:39 +01:00
|
|
|
cgi_postsignin($q, $session);
|
2007-01-12 21:56:54 +01:00
|
|
|
}
|
2006-03-23 07:51:15 +01:00
|
|
|
else {
|
|
|
|
error("unknown do parameter");
|
|
|
|
}
|
2008-12-17 21:22:16 +01:00
|
|
|
}
|
2006-03-23 07:51:15 +01:00
|
|
|
|
2008-08-06 01:58:33 +02:00
|
|
|
# Does not need to be called directly; all errors will go through here.
|
2008-12-17 21:22:16 +01:00
|
|
|
sub cgierror ($) {
|
2008-07-13 05:23:25 +02:00
|
|
|
my $message=shift;
|
|
|
|
|
2016-05-04 09:46:02 +02:00
|
|
|
eval q{use HTML::Entities};
|
|
|
|
$message = encode_entities($message);
|
|
|
|
|
2008-07-13 05:23:25 +02:00
|
|
|
print "Content-type: text/html\n\n";
|
2011-01-05 21:58:27 +01:00
|
|
|
print cgitemplate(undef, gettext("Error"),
|
2008-07-13 05:23:25 +02:00
|
|
|
"<p class=\"error\">".gettext("Error").": $message</p>");
|
|
|
|
die $@;
|
2008-12-17 21:22:16 +01:00
|
|
|
}
|
2008-07-13 05:23:25 +02:00
|
|
|
|
2006-03-23 07:51:15 +01:00
|
|
|
1
|