]> sipb.mit.edu Git - ikiwiki.git/blobdiff - IkiWiki/Render.pm
improve fix for symlink attacks to check subdirectories for symlinks too
[ikiwiki.git] / IkiWiki / Render.pm
index 8f755e8f5a79c354cb604693455a25a010dc5005..9e340c26e162abe5623524d4b4ced32942e6c834 100644 (file)
@@ -9,7 +9,8 @@ sub linkify ($$) { #{{{
        my $page=shift;
 
        $content =~ s{(\\?)$config{wiki_link_regexp}}{
-               $1 ? "[[$2]]" : htmllink($page, $2)
+               $2 ? ( $1 ? "[[$2|$3]]" : htmllink($page, titlepage($3), 0, 0, pagetitle($2)))
+                  : ( $1 ? "[[$3]]" :    htmllink($page, titlepage($3)))
        }eg;
        
        return $content;
@@ -127,7 +128,7 @@ sub blog_list ($$) { #{{{
        }
 
        @list=sort { $pagectime{$b} <=> $pagectime{$a} } @list;
-       return @list if @list <= $maxitems;
+       return @list if ! $maxitems || @list <= $maxitems;
        return @list[0..$maxitems - 1];
 } #}}}
 
@@ -138,7 +139,7 @@ sub get_inline_content ($$) { #{{{
        my $file=$pagesources{$page};
        my $type=pagetype($file);
        if ($type ne 'unknown') {
-               return htmlize($type, linkify(readfile("$config{srcdir}/$file"), $parentpage));
+               return htmlize($type, linkify(readfile(srcfile($file)), $parentpage));
        }
        else {
                return "";
@@ -149,26 +150,43 @@ sub postprocess_html_inline { #{{{
        my $parentpage=shift;
        my %params=@_;
        
-       if (! exists $params{show}) {
-               $params{show}=10;
-       }
        if (! exists $params{pages}) {
                return "";
        }
+       if (! exists $params{archive}) {
+               $params{archive}="no";
+       }
+       if (! exists $params{show} && $params{archive} eq "no") {
+               $params{show}=10;
+       }
        $inlinepages{$parentpage}=$params{pages};
        
+       my $ret="";
+       
+       if (exists $params{rootpage}) {
+               my $formtemplate=HTML::Template->new(blind_cache => 1,
+                       filename => "$config{templatedir}/blogpost.tmpl");
+               $formtemplate->param(cgiurl => $config{cgiurl});
+               $formtemplate->param(rootpage => $params{rootpage});
+               my $form=$formtemplate->output;
+               $ret.=$form;
+       }
+       
        my $template=HTML::Template->new(blind_cache => 1,
-               filename => "$config{templatedir}/inlinepage.tmpl");
+               filename => (($params{archive} eq "no") 
+                               ? "$config{templatedir}/inlinepage.tmpl"
+                               : "$config{templatedir}/inlinepagetitle.tmpl"));
        
-       my $ret="";
        foreach my $page (blog_list($params{pages}, $params{show})) {
+               next if $page eq $parentpage;
                $template->param(pagelink => htmllink($parentpage, $page));
-               $template->param(content => get_inline_content($parentpage, $page));
+               $template->param(content => get_inline_content($parentpage, $page))
+                       if $params{archive} eq "no";
                $template->param(ctime => scalar(gmtime($pagectime{$page})));
                $ret.=$template->output;
        }
        
-       return $ret;
+       return "</p>$ret<p>";
 } #}}}
 
 sub genpage ($$$) { #{{{
@@ -184,10 +202,10 @@ sub genpage ($$$) { #{{{
                filename => "$config{templatedir}/page.tmpl");
        
        if (length $config{cgiurl}) {
-               $template->param(editurl => "$config{cgiurl}?do=edit&page=$page");
-               $template->param(prefsurl => "$config{cgiurl}?do=prefs");
+               $template->param(editurl => cgiurl(do => "edit", page => $page));
+               $template->param(prefsurl => cgiurl(do => "prefs"));
                if ($config{rcs}) {
-                       $template->param(recentchangesurl => "$config{cgiurl}?do=recentchanges");
+                       $template->param(recentchangesurl => cgiurl(do => "recentchanges"));
                }
        }
 
@@ -197,8 +215,8 @@ sub genpage ($$$) { #{{{
                $template->param(historyurl => $u);
        }
 
-       if ($config{rss}) {
-               $template->param(rssurl => rsspage($page));
+       if ($config{rss} && $inlinepages{$page}) {
+               $template->param(rssurl => rsspage(basename($page)));
        }
        
        $template->param(
@@ -209,6 +227,7 @@ sub genpage ($$$) { #{{{
                backlinks => [backlinks($page)],
                discussionlink => htmllink($page, "Discussion", 1, 1),
                mtime => scalar(gmtime($mtime)),
+               styleurl => styleurl($page),
        );
        
        return $template->output;
@@ -231,7 +250,7 @@ sub absolute_urls ($$) { #{{{
        $content=~s/<a\s+href="(?!http:\/\/)([^"]+)"/<a href="$url$1"/ig;
        $content=~s/<img\s+src="(?!http:\/\/)([^"]+)"/<img src="$url$1"/ig;
        return $content;
-} #}}}zo
+} #}}}
 
 sub genrss ($$$) { #{{{
        my $content=shift;
@@ -255,10 +274,10 @@ sub genrss ($$$) { #{{{
                if (! exists $params{pages}) {
                        return "";
                }
-               $inlinepages{$parentpage}=$params{pages};
                
                $isblog=1;
                foreach my $page (blog_list($params{pages}, $params{show})) {
+                       next if $page eq $parentpage;
                        push @items, {
                                itemtitle => pagetitle(basename($page)),
                                itemurl => "$config{url}/$renderedfiles{$page}",
@@ -272,16 +291,6 @@ sub genrss ($$$) { #{{{
        
        $content = postprocess($page, $content, inline => $gen_blog);
 
-       # Regular page gets a feed that is updated every time the
-       # page is changed, so the mtime is encoded in the guid.
-       push @items, {
-               itemtitle => pagetitle(basename($page)),
-               itemguid => "$url?mtime=$mtime",
-               itemurl => $url,
-               itempubdate => date_822($mtime),
-               itemcontent => absolute_urls($content, $url),
-       } unless $isblog;
-       
        $template->param(
                title => $config{wikiname},
                pageurl => $url,
@@ -306,9 +315,9 @@ sub check_overwrite ($$) { #{{{
 } #}}}
 
 sub mtime ($) { #{{{
-       my $page=shift;
+       my $file=shift;
        
-       return (stat($page))[9];
+       return (stat($file))[9];
 } #}}}
 
 sub findlinks ($$) { #{{{
@@ -317,7 +326,7 @@ sub findlinks ($$) { #{{{
 
        my @links;
        while ($content =~ /(?<!\\)$config{wiki_link_regexp}/g) {
-               push @links, lc($1);
+               push @links, titlepage($2);
        }
        # Discussion links are a special case since they're not in the text
        # of the page, but on its template.
@@ -328,33 +337,35 @@ sub render ($) { #{{{
        my $file=shift;
        
        my $type=pagetype($file);
-       my $content=readfile("$config{srcdir}/$file");
+       my $srcfile=srcfile($file);
+       my $content=readfile($srcfile);
        if ($type ne 'unknown') {
                my $page=pagename($file);
                
                $links{$page}=[findlinks($content, $page)];
+               delete $inlinepages{$page};
                
                $content=linkify($content, $page);
                $content=htmlize($type, $content);
                
                check_overwrite("$config{destdir}/".htmlpage($page), $page);
-               writefile("$config{destdir}/".htmlpage($page),
-                       genpage($content, $page, mtime("$config{srcdir}/$file")));
+               writefile(htmlpage($page), $config{destdir},
+                       genpage($content, $page, mtime($srcfile)));
                $oldpagemtime{$page}=time;
                $renderedfiles{$page}=htmlpage($page);
 
                # TODO: should really add this to renderedfiles and call
                # check_overwrite, as above, but currently renderedfiles
                # only supports listing one file per page.
-               if ($config{rss}) {
-                       writefile("$config{destdir}/".rsspage($page),
-                               genrss($content, $page, mtime("$config{srcdir}/$file")));
+               if ($config{rss} && exists $inlinepages{$page}) {
+                       writefile(rsspage($page), $config{destdir},
+                               genrss($content, $page, mtime($srcfile)));
                }
        }
        else {
                $links{$file}=[];
                check_overwrite("$config{destdir}/$file", $file);
-               writefile("$config{destdir}/$file", $content);
+               writefile($file, $config{destdir}, $content);
                $oldpagemtime{$file}=time;
                $renderedfiles{$file}=$file;
        }
@@ -379,9 +390,7 @@ sub refresh () { #{{{
                no_chdir => 1,
                wanted => sub {
                        if (/$config{wiki_file_prune_regexp}/) {
-                               no warnings 'once';
                                $File::Find::prune=1;
-                               use warnings "all";
                        }
                        elsif (! -d $_ && ! -l $_) {
                                my ($f)=/$config{wiki_file_regexp}/; # untaint
@@ -396,6 +405,30 @@ sub refresh () { #{{{
                        }
                },
        }, $config{srcdir});
+       find({
+               no_chdir => 1,
+               wanted => sub {
+                       if (/$config{wiki_file_prune_regexp}/) {
+                               $File::Find::prune=1;
+                       }
+                       elsif (! -d $_ && ! -l $_) {
+                               my ($f)=/$config{wiki_file_regexp}/; # untaint
+                               if (! defined $f) {
+                                       warn("skipping bad filename $_\n");
+                               }
+                               else {
+                                       # Don't add files that are in the
+                                       # srcdir.
+                                       $f=~s/^\Q$config{underlaydir}\E\/?//;
+                                       if (! -e "$config{srcdir}/$f" && 
+                                           ! -l "$config{srcdir}/$f") {
+                                               push @files, $f;
+                                               $exists{pagename($f)}=1;
+                                       }
+                               }
+                       }
+               },
+       }, $config{underlaydir});
 
        my %rendered;
 
@@ -408,7 +441,8 @@ sub refresh () { #{{{
                        push @add, $file;
                        $links{$page}=[];
                        $pagesources{$page}=$file;
-                       $pagectime{$page}=time unless exists $pagectime{$page};
+                       $pagectime{$page}=mtime(srcfile($file))
+                               unless exists $pagectime{$page};
                }
        }
        my @del;
@@ -428,7 +462,7 @@ sub refresh () { #{{{
                my $page=pagename($file);
                
                if (! exists $oldpagemtime{$page} ||
-                   mtime("$config{srcdir}/$file") > $oldpagemtime{$page}) {
+                   mtime(srcfile($file)) > $oldpagemtime{$page}) {
                        debug("rendering changed file $file");
                        render($file);
                        $rendered{$file}=1;
@@ -453,25 +487,34 @@ FILE:             foreach my $file (@files) {
                                                next FILE;
                                        }
                                }
-                               if (exists $inlinepages{$page} &&
-                                   globlist_match($p, $inlinepages{$page})) {
-                                       debug("rendering $file, which inlines $p");
-                                       render($file);
-                                       $rendered{$file}=1;
-                               }
                        }
                }
        }
 
-       # handle backlinks; if a page has added/removed links, update the
-       # pages it links to
+       # Handle backlinks; if a page has added/removed links, update the
+       # pages it links to. Also handle inlining here.
        # TODO: inefficient; pages may get rendered above and again here;
        # problem is the backlinks could be wrong in the first pass render
        # above
-       if (%rendered) {
+       if (%rendered || @del) {
+               foreach my $f (@files) {
+                       my $p=pagename($f);
+                       if (exists $inlinepages{$p}) {
+                               foreach my $file (keys %rendered, @del) {
+                                       my $page=pagename($file);
+                                       if (globlist_match($page, $inlinepages{$p})) {
+                                               debug("rendering $f, which inlines $page");
+                                               render($f);
+                                               last;
+                                       }
+                               }
+                       }
+               }
+               
                my %linkchanged;
                foreach my $file (keys %rendered, @del) {
                        my $page=pagename($file);
+                       
                        if (exists $links{$page}) {
                                foreach my $link (map { bestlink($page, $_) } @{$links{$page}}) {
                                        if (length $link &&