X-Git-Url: http://git.vanrenterghem.biz/git.ikiwiki.info.git/blobdiff_plain/a308b212ad697fb204fa8543d00c39a24f58de5f..f282512da75d19e38933f3083afa3c2a9dad463c:/IkiWiki/Plugin/img.pm diff --git a/IkiWiki/Plugin/img.pm b/IkiWiki/Plugin/img.pm index 1ab753352..ed2e9354d 100644 --- a/IkiWiki/Plugin/img.pm +++ b/IkiWiki/Plugin/img.pm @@ -21,6 +21,28 @@ sub getsetup () { rebuild => undef, section => "widget", }, + img_allowed_formats => { + type => "string", + default => [qw(jpeg png gif)], + description => "Image formats to process (jpeg, png, gif, pdf, svg or 'everything' to accept all)", + # ImageMagick has had arbitrary code execution flaws, + # and the whole delegates mechanism is scary from + # that perspective + safe => 0, + rebuild => 0, + }, +} + +sub allowed { + my $format = shift; + my $allowed = $config{img_allowed_formats}; + $allowed = ['jpeg', 'png'] unless defined $allowed && @$allowed; + + foreach my $a (@$allowed) { + return 1 if $a eq $format || $a eq 'everything'; + } + + return 0; } sub preprocess (@) { @@ -64,6 +86,69 @@ sub preprocess (@) { my $dir = $params{page}; my $base = IkiWiki::basename($file); + my $extension; + my $format; + + if ($base =~ m/\.([a-z0-9]+)$/) { + $extension = $1; + } + else { + error gettext("Unable to detect image type from extension"); + } + + # Never interpret well-known file extensions as any other format, + # in case the wiki configuration unwisely allows attaching + # arbitrary files named *.jpg, etc. + my $magic; + my $offset = 0; + open(my $in, '<', $srcfile) or error sprintf(gettext("failed to read %s: %s"), $file, $!); + binmode($in); + + if ($extension =~ m/^(jpeg|jpg)$/is) { + $format = 'jpeg'; + $magic = "\377\330\377"; + } + elsif ($extension =~ m/^(png)$/is) { + $format = 'png'; + $magic = "\211PNG\r\n\032\n"; + } + elsif ($extension =~ m/^(gif)$/is) { + $format = 'gif'; + $magic = "GIF8"; + } + elsif ($extension =~ m/^(svg)$/is) { + $format = 'svg'; + } + elsif ($extension =~ m/^(pdf)$/is) { + $format = 'pdf'; + $magic = "%PDF-"; + } + else { + # allow ImageMagick to auto-detect (potentially dangerous) + $format = ''; + } + + error sprintf(gettext("%s image processing disabled in img_allowed_formats configuration"), $format ? $format : "\"$extension\"") unless allowed($format ? $format : "everything"); + + # Try harder to protect ImageMagick from itself + if ($format eq 'svg') { + my $content; + read($in, $content, 5) or error sprintf(gettext("failed to read %s: %s"), $file, $!); + # This is an over-simplification, but ?xml is the check that + # ImageMagick uses. We also accept new(); my $imglink; - my $r = $im->Read("$srcfile\[$pagenumber]"); + my $imgdatalink; + my $r = $im->Read("$format:$srcfile\[$pagenumber]"); error sprintf(gettext("failed to read %s: %s"), $file, $r) if $r; - + + if (! defined $im->Get("width") || ! defined $im->Get("height")) { + error sprintf(gettext("failed to get dimensions of %s"), $file); + } + my ($dwidth, $dheight); if ($params{size} eq 'full') { @@ -123,15 +213,17 @@ sub preprocess (@) { $r = $im->Resize(geometry => "${dwidth}x${dheight}"); error sprintf(gettext("failed to resize: %s"), $r) if $r; + $im->set(($issvg || $ispdf) ? (magick => 'png') : ()); + my @blob = $im->ImageToBlob(); # don't actually write resized file in preview mode; # rely on width and height settings if (! $params{preview}) { - $im->set(($issvg || $ispdf) ? (magick => 'png') : ()); - my @blob = $im->ImageToBlob(); writefile($imglink, $config{destdir}, $blob[0], 1); } else { - $imglink = $file; + eval q{use MIME::Base64}; + error($@) if $@; + $imgdatalink = "data:image/".$im->Get("magick").";base64,".encode_base64($blob[0]); } } @@ -148,14 +240,9 @@ sub preprocess (@) { } my ($fileurl, $imgurl); - if (! $params{preview}) { - $fileurl=urlto($file, $params{destpage}); - $imgurl=urlto($imglink, $params{destpage}); - } - else { - $fileurl=urlto($file); - $imgurl=urlto($imglink); - } + my $urltobase = $params{preview} ? undef : $params{destpage}; + $fileurl=urlto($file, $urltobase); + $imgurl=$imgdatalink ? $imgdatalink : urlto($imglink, $urltobase); if (! exists $params{class}) { $params{class}="img";