X-Git-Url: http://git.vanrenterghem.biz/git.ikiwiki.info.git/blobdiff_plain/8859b2feaf39aeb581254b9be83b53dac5573966..7e2240481c1d17de8674f0e2d04c41b7d60260be:/ikiwiki diff --git a/ikiwiki b/ikiwiki index 058b3ffa2..84c7a2513 100755 --- a/ikiwiki +++ b/ikiwiki @@ -306,6 +306,17 @@ sub finalize ($$) { #{{{ return $template->output; } #}}} +# Important security check. Make sure to call this before saving any files +# to the source directory. +sub check_overwrite ($$) { #{{{ + my $dest=shift; + my $src=shift; + + if (! exists $renderedfiles{$src} && -e $dest) { + error("$dest exists and was not rendered from $src before, not overwriting"); + } +} #}}} + sub render ($) { #{{{ my $file=shift; @@ -320,12 +331,14 @@ sub render ($) { #{{{ $content=htmlize($type, $content); $content=finalize($content, $page); + check_overwrite("$destdir/".htmlpage($page), $page); writefile("$destdir/".htmlpage($page), $content); $oldpagemtime{$page}=time; $renderedfiles{$page}=htmlpage($page); } else { $links{$file}=[]; + check_overwrite("$destdir/$file", $file); writefile("$destdir/$file", $content); $oldpagemtime{$file}=time; $renderedfiles{$file}=$file; @@ -433,7 +446,19 @@ sub rcs_recentchanges ($) { #{{{ $state='body'; } elsif ($state eq 'body' && /$div/) { - push @ret, { rev => $rev, user => $user, + my $committype="web"; + if (defined $message[0] && + $message[0]->{line}=~/^web commit by (\w+):?(.*)/) { + $user="$1"; + $message[0]->{line}=$2; + } + else { + $committype="svn"; + } + + push @ret, { rev => $rev, + user => htmllink("", $user, 1), + committype => $committype, when => $when, message => [@message], pages => [@pages] } if @pages; return @ret if @ret >= $num; @@ -696,6 +721,35 @@ sub cgi_recentchanges ($) { #{{{ print $q->header, $template->output; } #}}} +sub userinfo_get ($$) { #{{{ + my $user=shift; + my $field=shift; + + eval q{use Storable}; + my $userdata=eval{ Storable::lock_retrieve("$srcdir/.ikiwiki/userdb") }; + if (! defined $userdata || ! ref $userdata || + ! exists $userdata->{$user} || ! ref $userdata->{$user}) { + return ""; + } + return $userdata->{$user}->{$field}; +} #}}} + +sub userinfo_set ($$) { #{{{ + my $user=shift; + my $info=shift; + + eval q{use Storable}; + my $userdata=eval{ Storable::lock_retrieve("$srcdir/.ikiwiki/userdb") }; + if (! defined $userdata || ! ref $userdata) { + $userdata={}; + } + $userdata->{$user}=$info; + my $oldmask=umask(077); + my $ret=Storable::lock_store($userdata, "$srcdir/.ikiwiki/userdb"); + umask($oldmask); + return $ret; +} #}}} + sub cgi_signin ($$) { #{{{ my $q=shift; my $session=shift; @@ -707,7 +761,6 @@ sub cgi_signin ($$) { #{{{ header => 1, method => 'POST', validate => { - name => '/^\w+$/', confirm_password => { perl => q{eq $form->field("password")}, }, @@ -727,9 +780,6 @@ sub cgi_signin ($$) { #{{{ $form->field(name => "password", type => "password", required => 0); $form->field(name => "confirm_password", type => "password", required => 0); $form->field(name => "email", required => 0); - if ($session->param("name")) { - $form->field(name => "name", value => $session->param("name")); - } if ($q->param("do") ne "signin") { $form->text("You need to log in before you can edit pages."); } @@ -745,26 +795,52 @@ sub cgi_signin ($$) { #{{{ $form->field(name => $opt, required => 1); } - # Validate password differently depending on how form was - # submitted. + # Validate password differently depending on how + # form was submitted. if ($form->submitted eq 'Login') { $form->field( name => "password", validate => sub { - # TODO get real user password - shift eq "foo"; + length $form->field("name") && + shift eq userinfo_get($form->field("name"), 'password'); }, ); + $form->field(name => "name", validate => '/^\w+$/'); } else { $form->field(name => "password", validate => 'VALUE'); } + # And make sure the entered name exists when logging + # in or sending email, and does not when registering. + if ($form->submitted eq 'Register') { + $form->field( + name => "name", + validate => sub { + my $name=shift; + length $name && + ! userinfo_get($name, "regdate"); + }, + ); + } + else { + $form->field( + name => "name", + validate => sub { + my $name=shift; + length $name && + userinfo_get($name, "regdate"); + }, + ); + } } else { - # Comments only shown first time. + # First time settings. $form->field(name => "name", comment => "use FirstnameLastName"); $form->field(name => "confirm_password", comment => "(only needed"); $form->field(name => "email", comment => "for registration)"); + if ($session->param("name")) { + $form->field(name => "name", value => $session->param("name")); + } } if ($form->submitted && $form->validate) { @@ -781,16 +857,47 @@ sub cgi_signin ($$) { #{{{ } } elsif ($form->submitted eq 'Register') { - # TODO: save registration info - $form->field(name => "confirm_password", type => "hidden"); - $form->field(name => "email", type => "hidden"); - $form->text("Registration successful. Now you can Login."); - print $session->header(); - print misctemplate($form->title, $form->render(submit => ["Login"])); + my $user_name=$form->field('name'); + if (userinfo_set($user_name, { + 'email' => $form->field('email'), + 'password' => $form->field('password'), + 'regdate' => time + })) { + $form->field(name => "confirm_password", type => "hidden"); + $form->field(name => "email", type => "hidden"); + $form->text("Registration successful. Now you can Login."); + print $session->header(); + print misctemplate($form->title, $form->render(submit => ["Login"])); + } + else { + error("Error saving registration."); + } } elsif ($form->submitted eq 'Mail Password') { - # TODO mail password + my $user_name=$form->field("name"); + my $template=HTML::Template->new( + filename => "$templatedir/passwordmail.tmpl" + ); + $template->param( + user_name => $user_name, + user_password => userinfo_get($user_name, "password"), + wikiurl => $url, + wikiname => $wikiname, + REMOTE_ADDR => $ENV{REMOTE_ADDR}, + ); + + eval q{use Mail::Sendmail}; + my ($fromhost) = $cgiurl =~ m!/([^/]+)!; + print STDERR "$< $> >>> $cgiurl ".(getpwuid($>))[0]."@".$fromhost."\n"; + sendmail( + To => userinfo_get($user_name, "email"), + From => "$wikiname admin <".(getpwuid($>))[0]."@".$fromhost.">", + Subject => "$wikiname information", + Message => $template->output, + ) or error("Failed to send mail"); + $form->text("Your password has been emailed to you."); + $form->field(name => "name", required => 0); print $session->header(); print misctemplate($form->title, $form->render(submit => ["Login", "Register", "Mail Password"])); } @@ -810,8 +917,10 @@ sub cgi_editpage ($$) { #{{{ fields => [qw(do from page content comments)], header => 1, method => 'POST', - validate => {}, - required => [qw{}], + validate => { + content => '/.+/', + }, + required => [qw{content}], javascript => 0, params => $q, action => $q->request_uri, @@ -833,6 +942,10 @@ sub cgi_editpage ($$) { #{{{ $form->field(name => "content", type => "textarea", rows => 20, cols => 80); + if ($form->submitted eq "Cancel") { + print $q->redirect("$url/".htmlpage($page)); + return; + } if (! $form->submitted || ! $form->validate) { if ($form->field("do") eq "create") { if (exists $pagesources{lc($page)}) { @@ -880,7 +993,7 @@ sub cgi_editpage ($$) { #{{{ $form->tmpl_param("can_commit", $svn); $form->tmpl_param("indexlink", indexlink()); - print $form->render(submit => ["Save Page"]); + print $form->render(submit => ["Save Page", "Cancel"]); } else { # save page @@ -903,7 +1016,8 @@ sub cgi_editpage ($$) { #{{{ else { $message.="from $ENV{REMOTE_ADDR}"; } - if (length $form->field('comments')) { + if (defined $form->field('comments') && + length $form->field('comments')) { $message.=": ".$form->field('comments'); } @@ -919,7 +1033,9 @@ sub cgi_editpage ($$) { #{{{ refresh(); } - print $q->redirect("$url/".htmlpage($page)); + # The trailing question mark tries to avoid broken + # caches and get the most recent version of the page. + print $q->redirect("$url/".htmlpage($page)."?"); } } #}}} @@ -941,12 +1057,22 @@ sub cgi () { #{{{ } CGI::Session->name("ikiwiki_session"); - my $session = CGI::Session->new(undef, $q, - { Directory=> "$srcdir/.ikiwiki/sessions" }); + + my $oldmask=umask(077); + my $session = CGI::Session->new("driver:db_file", $q, + { FileName => "$srcdir/.ikiwiki/sessions.db" }); + umask($oldmask); # Everything below this point needs the user to be signed in. - if ((! $anonok && ! defined $session->param("name")) || $do eq 'signin') { + if ((! $anonok && ! defined $session->param("name") || + ! userinfo_get($session->param("name"), "regdate")) || $do eq 'signin') { cgi_signin($q, $session); + + # Force session flush with safe umask. + my $oldmask=umask(077); + $session->flush; + umask($oldmask); + return; }