filecheck: New plugin factoring out the PageSpec additions that were originally part of the attachment plugin.
parent
c013f0a8bc
commit
78e34fbdc2
|
@ -10,6 +10,7 @@ sub import { #{{{
|
|||
hook(type => "checkconfig", id => "attachment", call => \&checkconfig);
|
||||
hook(type => "formbuilder_setup", id => "attachment", call => \&formbuilder_setup);
|
||||
hook(type => "formbuilder", id => "attachment", call => \&formbuilder);
|
||||
IkiWiki::loadplugin("filecheck");
|
||||
} # }}}
|
||||
|
||||
sub getsetup () { #{{{
|
||||
|
@ -288,192 +289,8 @@ sub attachment_list ($) { #{{{
|
|||
return sort { $b->{mtime_raw} <=> $a->{mtime_raw} || $a->{link} cmp $b->{link} } @ret;
|
||||
} #}}}
|
||||
|
||||
my %units=( #{{{ # size in bytes
|
||||
B => 1,
|
||||
byte => 1,
|
||||
KB => 2 ** 10,
|
||||
kilobyte => 2 ** 10,
|
||||
K => 2 ** 10,
|
||||
KB => 2 ** 10,
|
||||
kilobyte => 2 ** 10,
|
||||
M => 2 ** 20,
|
||||
MB => 2 ** 20,
|
||||
megabyte => 2 ** 20,
|
||||
G => 2 ** 30,
|
||||
GB => 2 ** 30,
|
||||
gigabyte => 2 ** 30,
|
||||
T => 2 ** 40,
|
||||
TB => 2 ** 40,
|
||||
terabyte => 2 ** 40,
|
||||
P => 2 ** 50,
|
||||
PB => 2 ** 50,
|
||||
petabyte => 2 ** 50,
|
||||
E => 2 ** 60,
|
||||
EB => 2 ** 60,
|
||||
exabyte => 2 ** 60,
|
||||
Z => 2 ** 70,
|
||||
ZB => 2 ** 70,
|
||||
zettabyte => 2 ** 70,
|
||||
Y => 2 ** 80,
|
||||
YB => 2 ** 80,
|
||||
yottabyte => 2 ** 80,
|
||||
# ikiwiki, if you find you need larger data quantities, either modify
|
||||
# yourself to add them, or travel back in time to 2008 and kill me.
|
||||
# -- Joey
|
||||
); #}}}
|
||||
|
||||
sub parsesize ($) { #{{{
|
||||
my $size=shift;
|
||||
|
||||
no warnings;
|
||||
my $base=$size+0; # force to number
|
||||
use warnings;
|
||||
foreach my $unit (sort keys %units) {
|
||||
if ($size=~/[0-9\s]\Q$unit\E$/i) {
|
||||
return $base * $units{$unit};
|
||||
}
|
||||
}
|
||||
return $base;
|
||||
} #}}}
|
||||
|
||||
sub humansize ($) { #{{{
|
||||
my $size=shift;
|
||||
|
||||
foreach my $unit (reverse sort { $units{$a} <=> $units{$b} || $b cmp $a } keys %units) {
|
||||
if ($size / $units{$unit} > 0.25) {
|
||||
return (int($size / $units{$unit} * 10)/10).$unit;
|
||||
}
|
||||
}
|
||||
return $size; # near zero, or negative
|
||||
} #}}}
|
||||
|
||||
package IkiWiki::PageSpec;
|
||||
|
||||
sub match_maxsize ($$;@) { #{{{
|
||||
my $page=shift;
|
||||
my $maxsize=eval{IkiWiki::Plugin::attachment::parsesize(shift)};
|
||||
if ($@) {
|
||||
return IkiWiki::FailReason->new("unable to parse maxsize (or number too large)");
|
||||
}
|
||||
|
||||
my %params=@_;
|
||||
my $file=exists $params{file} ? $params{file} : $IkiWiki::pagesources{$page};
|
||||
if (! defined $file) {
|
||||
return IkiWiki::FailReason->new("no file specified");
|
||||
}
|
||||
|
||||
if (-s $file > $maxsize) {
|
||||
return IkiWiki::FailReason->new("file too large (".(-s $file)." > $maxsize)");
|
||||
}
|
||||
else {
|
||||
return IkiWiki::SuccessReason->new("file not too large");
|
||||
}
|
||||
} #}}}
|
||||
|
||||
sub match_minsize ($$;@) { #{{{
|
||||
my $page=shift;
|
||||
my $minsize=eval{IkiWiki::Plugin::attachment::parsesize(shift)};
|
||||
if ($@) {
|
||||
return IkiWiki::FailReason->new("unable to parse minsize (or number too large)");
|
||||
}
|
||||
|
||||
my %params=@_;
|
||||
my $file=exists $params{file} ? $params{file} : $IkiWiki::pagesources{$page};
|
||||
if (! defined $file) {
|
||||
return IkiWiki::FailReason->new("no file specified");
|
||||
}
|
||||
|
||||
if (-s $file < $minsize) {
|
||||
return IkiWiki::FailReason->new("file too small");
|
||||
}
|
||||
else {
|
||||
return IkiWiki::SuccessReason->new("file not too small");
|
||||
}
|
||||
} #}}}
|
||||
|
||||
sub match_mimetype ($$;@) { #{{{
|
||||
my $page=shift;
|
||||
my $wanted=shift;
|
||||
|
||||
my %params=@_;
|
||||
my $file=exists $params{file} ? $params{file} : $IkiWiki::pagesources{$page};
|
||||
if (! defined $file) {
|
||||
return IkiWiki::FailReason->new("no file specified");
|
||||
}
|
||||
|
||||
# Use ::magic to get the mime type, the idea is to only trust
|
||||
# data obtained by examining the actual file contents.
|
||||
eval q{use File::MimeInfo::Magic};
|
||||
if ($@) {
|
||||
return IkiWiki::FailReason->new("failed to load File::MimeInfo::Magic ($@); cannot check MIME type");
|
||||
}
|
||||
my $mimetype=File::MimeInfo::Magic::magic($file);
|
||||
if (! defined $mimetype) {
|
||||
$mimetype="unknown";
|
||||
}
|
||||
|
||||
my $regexp=IkiWiki::glob2re($wanted);
|
||||
if ($mimetype!~/^$regexp$/i) {
|
||||
return IkiWiki::FailReason->new("file MIME type is $mimetype, not $wanted");
|
||||
}
|
||||
else {
|
||||
return IkiWiki::SuccessReason->new("file MIME type is $mimetype");
|
||||
}
|
||||
} #}}}
|
||||
|
||||
sub match_virusfree ($$;@) { #{{{
|
||||
my $page=shift;
|
||||
my $wanted=shift;
|
||||
|
||||
my %params=@_;
|
||||
my $file=exists $params{file} ? $params{file} : $IkiWiki::pagesources{$page};
|
||||
if (! defined $file) {
|
||||
return IkiWiki::FailReason->new("no file specified");
|
||||
}
|
||||
|
||||
if (! exists $IkiWiki::config{virus_checker} ||
|
||||
! length $IkiWiki::config{virus_checker}) {
|
||||
return IkiWiki::FailReason->new("no virus_checker configured");
|
||||
}
|
||||
|
||||
# The file needs to be fed into the virus checker on stdin,
|
||||
# because the file is not world-readable, and if clamdscan is
|
||||
# used, clamd would fail to read it.
|
||||
eval q{use IPC::Open2};
|
||||
error($@) if $@;
|
||||
open (IN, "<", $file) || return IkiWiki::FailReason->new("failed to read file");
|
||||
binmode(IN);
|
||||
my $sigpipe=0;
|
||||
$SIG{PIPE} = sub { $sigpipe=1 };
|
||||
my $pid=open2(\*CHECKER_OUT, "<&IN", $IkiWiki::config{virus_checker});
|
||||
my $reason=<CHECKER_OUT>;
|
||||
chomp $reason;
|
||||
1 while (<CHECKER_OUT>);
|
||||
close(CHECKER_OUT);
|
||||
waitpid $pid, 0;
|
||||
$SIG{PIPE}="DEFAULT";
|
||||
if ($sigpipe || $?) {
|
||||
if (! length $reason) {
|
||||
$reason="virus checker $IkiWiki::config{virus_checker}; failed with no output";
|
||||
}
|
||||
return IkiWiki::FailReason->new("file seems to contain a virus ($reason)");
|
||||
}
|
||||
else {
|
||||
return IkiWiki::SuccessReason->new("file seems virusfree ($reason)");
|
||||
}
|
||||
} #}}}
|
||||
|
||||
sub match_ispage ($$;@) { #{{{
|
||||
my $filename=shift;
|
||||
|
||||
if (defined IkiWiki::pagetype($filename)) {
|
||||
return IkiWiki::SuccessReason->new("file is a wiki page");
|
||||
}
|
||||
else {
|
||||
return IkiWiki::FailReason->new("file is not a wiki page");
|
||||
}
|
||||
} #}}}
|
||||
|
||||
sub match_user ($$;@) { #{{{
|
||||
shift;
|
||||
my $user=shift;
|
||||
|
|
|
@ -0,0 +1,192 @@
|
|||
#!/usr/bin/perl
|
||||
package IkiWiki::Plugin::filecheck;
|
||||
|
||||
use warnings;
|
||||
use strict;
|
||||
use IkiWiki 2.00;
|
||||
|
||||
my %units=( #{{{ # size in bytes
|
||||
B => 1,
|
||||
byte => 1,
|
||||
KB => 2 ** 10,
|
||||
kilobyte => 2 ** 10,
|
||||
K => 2 ** 10,
|
||||
KB => 2 ** 10,
|
||||
kilobyte => 2 ** 10,
|
||||
M => 2 ** 20,
|
||||
MB => 2 ** 20,
|
||||
megabyte => 2 ** 20,
|
||||
G => 2 ** 30,
|
||||
GB => 2 ** 30,
|
||||
gigabyte => 2 ** 30,
|
||||
T => 2 ** 40,
|
||||
TB => 2 ** 40,
|
||||
terabyte => 2 ** 40,
|
||||
P => 2 ** 50,
|
||||
PB => 2 ** 50,
|
||||
petabyte => 2 ** 50,
|
||||
E => 2 ** 60,
|
||||
EB => 2 ** 60,
|
||||
exabyte => 2 ** 60,
|
||||
Z => 2 ** 70,
|
||||
ZB => 2 ** 70,
|
||||
zettabyte => 2 ** 70,
|
||||
Y => 2 ** 80,
|
||||
YB => 2 ** 80,
|
||||
yottabyte => 2 ** 80,
|
||||
# ikiwiki, if you find you need larger data quantities, either modify
|
||||
# yourself to add them, or travel back in time to 2008 and kill me.
|
||||
# -- Joey
|
||||
); #}}}
|
||||
|
||||
sub parsesize ($) { #{{{
|
||||
my $size=shift;
|
||||
|
||||
no warnings;
|
||||
my $base=$size+0; # force to number
|
||||
use warnings;
|
||||
foreach my $unit (sort keys %units) {
|
||||
if ($size=~/[0-9\s]\Q$unit\E$/i) {
|
||||
return $base * $units{$unit};
|
||||
}
|
||||
}
|
||||
return $base;
|
||||
} #}}}
|
||||
|
||||
sub humansize ($) { #{{{
|
||||
my $size=shift;
|
||||
|
||||
foreach my $unit (reverse sort { $units{$a} <=> $units{$b} || $b cmp $a } keys %units) {
|
||||
if ($size / $units{$unit} > 0.25) {
|
||||
return (int($size / $units{$unit} * 10)/10).$unit;
|
||||
}
|
||||
}
|
||||
return $size; # near zero, or negative
|
||||
} #}}}
|
||||
|
||||
package IkiWiki::PageSpec;
|
||||
|
||||
sub match_maxsize ($$;@) { #{{{
|
||||
my $page=shift;
|
||||
my $maxsize=eval{IkiWiki::Plugin::attachment::parsesize(shift)};
|
||||
if ($@) {
|
||||
return IkiWiki::FailReason->new("unable to parse maxsize (or number too large)");
|
||||
}
|
||||
|
||||
my %params=@_;
|
||||
my $file=exists $params{file} ? $params{file} : $IkiWiki::pagesources{$page};
|
||||
if (! defined $file) {
|
||||
return IkiWiki::FailReason->new("no file specified");
|
||||
}
|
||||
|
||||
if (-s $file > $maxsize) {
|
||||
return IkiWiki::FailReason->new("file too large (".(-s $file)." > $maxsize)");
|
||||
}
|
||||
else {
|
||||
return IkiWiki::SuccessReason->new("file not too large");
|
||||
}
|
||||
} #}}}
|
||||
|
||||
sub match_minsize ($$;@) { #{{{
|
||||
my $page=shift;
|
||||
my $minsize=eval{IkiWiki::Plugin::attachment::parsesize(shift)};
|
||||
if ($@) {
|
||||
return IkiWiki::FailReason->new("unable to parse minsize (or number too large)");
|
||||
}
|
||||
|
||||
my %params=@_;
|
||||
my $file=exists $params{file} ? $params{file} : $IkiWiki::pagesources{$page};
|
||||
if (! defined $file) {
|
||||
return IkiWiki::FailReason->new("no file specified");
|
||||
}
|
||||
|
||||
if (-s $file < $minsize) {
|
||||
return IkiWiki::FailReason->new("file too small");
|
||||
}
|
||||
else {
|
||||
return IkiWiki::SuccessReason->new("file not too small");
|
||||
}
|
||||
} #}}}
|
||||
|
||||
sub match_mimetype ($$;@) { #{{{
|
||||
my $page=shift;
|
||||
my $wanted=shift;
|
||||
|
||||
my %params=@_;
|
||||
my $file=exists $params{file} ? $params{file} : $IkiWiki::pagesources{$page};
|
||||
if (! defined $file) {
|
||||
return IkiWiki::FailReason->new("no file specified");
|
||||
}
|
||||
|
||||
# Use ::magic to get the mime type, the idea is to only trust
|
||||
# data obtained by examining the actual file contents.
|
||||
eval q{use File::MimeInfo::Magic};
|
||||
if ($@) {
|
||||
return IkiWiki::FailReason->new("failed to load File::MimeInfo::Magic ($@); cannot check MIME type");
|
||||
}
|
||||
my $mimetype=File::MimeInfo::Magic::magic($file);
|
||||
if (! defined $mimetype) {
|
||||
$mimetype="unknown";
|
||||
}
|
||||
|
||||
my $regexp=IkiWiki::glob2re($wanted);
|
||||
if ($mimetype!~/^$regexp$/i) {
|
||||
return IkiWiki::FailReason->new("file MIME type is $mimetype, not $wanted");
|
||||
}
|
||||
else {
|
||||
return IkiWiki::SuccessReason->new("file MIME type is $mimetype");
|
||||
}
|
||||
} #}}}
|
||||
|
||||
sub match_virusfree ($$;@) { #{{{
|
||||
my $page=shift;
|
||||
my $wanted=shift;
|
||||
|
||||
my %params=@_;
|
||||
my $file=exists $params{file} ? $params{file} : $IkiWiki::pagesources{$page};
|
||||
if (! defined $file) {
|
||||
return IkiWiki::FailReason->new("no file specified");
|
||||
}
|
||||
|
||||
if (! exists $IkiWiki::config{virus_checker} ||
|
||||
! length $IkiWiki::config{virus_checker}) {
|
||||
return IkiWiki::FailReason->new("no virus_checker configured");
|
||||
}
|
||||
|
||||
# The file needs to be fed into the virus checker on stdin,
|
||||
# because the file is not world-readable, and if clamdscan is
|
||||
# used, clamd would fail to read it.
|
||||
eval q{use IPC::Open2};
|
||||
error($@) if $@;
|
||||
open (IN, "<", $file) || return IkiWiki::FailReason->new("failed to read file");
|
||||
binmode(IN);
|
||||
my $sigpipe=0;
|
||||
$SIG{PIPE} = sub { $sigpipe=1 };
|
||||
my $pid=open2(\*CHECKER_OUT, "<&IN", $IkiWiki::config{virus_checker});
|
||||
my $reason=<CHECKER_OUT>;
|
||||
chomp $reason;
|
||||
1 while (<CHECKER_OUT>);
|
||||
close(CHECKER_OUT);
|
||||
waitpid $pid, 0;
|
||||
$SIG{PIPE}="DEFAULT";
|
||||
if ($sigpipe || $?) {
|
||||
if (! length $reason) {
|
||||
$reason="virus checker $IkiWiki::config{virus_checker}; failed with no output";
|
||||
}
|
||||
return IkiWiki::FailReason->new("file seems to contain a virus ($reason)");
|
||||
}
|
||||
else {
|
||||
return IkiWiki::SuccessReason->new("file seems virusfree ($reason)");
|
||||
}
|
||||
} #}}}
|
||||
|
||||
sub match_ispage ($$;@) { #{{{
|
||||
my $filename=shift;
|
||||
|
||||
if (defined IkiWiki::pagetype($filename)) {
|
||||
return IkiWiki::SuccessReason->new("file is a wiki page");
|
||||
}
|
||||
else {
|
||||
return IkiWiki::FailReason->new("file is not a wiki page");
|
||||
}
|
||||
} #}}}
|
|
@ -14,6 +14,8 @@ ikiwiki (2.62) UNRELEASED; urgency=low
|
|||
chain will be used. (willu)
|
||||
* Drop suggests on texlive-science, add suggests on dvipng.
|
||||
* listdirectives: New plugin. (willu)
|
||||
* filecheck: New plugin factoring out the PageSpec additions that were
|
||||
originally part of the attachment plugin.
|
||||
|
||||
-- Joey Hess <joeyh@debian.org> Thu, 21 Aug 2008 16:20:58 -0400
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ check all attachments for virii, something like this could be used:
|
|||
|
||||
virusfree() and ((user(joey) and podcast/*.mp3 and mimetype(audio/mpeg) and maxsize(15mb)) or (!ispage() and maxsize(50kb)))
|
||||
|
||||
The regular [[ikiwiki/PageSpec]] syntax is expanded with thw following
|
||||
The regular [[ikiwiki/PageSpec]] syntax is expanded with the following
|
||||
additional tests:
|
||||
|
||||
* maxsize(size)
|
||||
|
|
|
@ -11,3 +11,5 @@ I am interested for [[todo/mbox]] --[[DavidBremner]]
|
|||
>> I don't think `ip()` and `user()` necessarily make sense for a mail box
|
||||
>> that is already on the disk, so no, I don't think I'll miss
|
||||
>> them. --[[DavidBremner]]
|
||||
|
||||
>>> Done, [[plugins/filecheck]] --[[Joey]]
|
||||
|
|
|
@ -22,13 +22,6 @@ Bear in mind that if you let anyone upload a particular kind of file
|
|||
|
||||
If you enable this plugin, be sure to lock it down, via the
|
||||
`allowed_attachments` setup file option. This is a special
|
||||
[[enhanced_PageSpec|ikiwiki/pagespec/attachment]].
|
||||
|
||||
This plugin will use the [[!cpan File::MimeInfo::Magic]] perl module, if
|
||||
available, for mimetype checking.
|
||||
|
||||
The `virusfree` [[PageSpec|ikiwiki/pagespec/attachment]] requires that
|
||||
ikiwiki be configured with a virus scanner program via the `virus_checker`
|
||||
option in the setup file. If using `clamav`, with `clamd`, set it to
|
||||
"clamdscan -". Or to use clamav without the `clamd` daemon, you
|
||||
could set it to "clamscan -".
|
||||
[[enhanced_PageSpec|ikiwiki/pagespec/attachment]] using tests provided by
|
||||
the [[filecheck]] plugin. That plugin will be automatically enabled when
|
||||
this plugin is enabled.
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
[[!template id=plugin name=filecheck core=0 author="[[Joey]]"]]
|
||||
[[!tag type/useful]]
|
||||
|
||||
This plugin enhances the regular [[ikiwiki/PageSpec]] syntax with
|
||||
some additional tests, for things like file size, mime type, and virus
|
||||
status. These tests are mostly useful for the [[attachment]] plugin, and
|
||||
are documented [[here|ikiwiki/pagespec/attachment]].
|
||||
|
||||
This plugin will use the [[!cpan File::MimeInfo::Magic]] perl module, if
|
||||
available, for mimetype checking.
|
||||
|
||||
The `virusfree` [[PageSpec|ikiwiki/pagespec/attachment]] requires that
|
||||
ikiwiki be configured with a virus scanner program via the `virus_checker`
|
||||
option in the setup file. If using `clamav`, with `clamd`, set it to
|
||||
"clamdscan -". Or to use clamav without the `clamd` daemon, you
|
||||
could set it to "clamscan -".
|
Loading…
Reference in New Issue