From c821cee108257e0d124c2b7516017af4be334463 Mon Sep 17 00:00:00 2001 From: intrigeri Date: Thu, 1 Jan 2009 23:10:16 +0100 Subject: [PATCH] po(cansave): check PO validity using new isvalidpo function ... because Po4a's parser does not care about malformed PO data. Use gettext's msgfmt program instead. Signed-off-by: intrigeri --- IkiWiki/Plugin/po.pm | 47 ++++++++++++++++++++++++++++++++++++++++++-- doc/plugins/po.mdwn | 4 ++++ 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/IkiWiki/Plugin/po.pm b/IkiWiki/Plugin/po.pm index 35e7c13ff..8f11a5f5a 100644 --- a/IkiWiki/Plugin/po.pm +++ b/IkiWiki/Plugin/po.pm @@ -388,11 +388,12 @@ sub cansave ($$$$) { my ($page, $content, $cgi, $session) = (shift, shift, shift, shift); if (istranslation($page)) { - if (defined po_to_markup($page, $content, "nonfatal")) { + my $res = isvalidpo($content); + if ($res) { return undef; } else { - return "Could not parse this page's content; is this valid gettext?"; + return "$res"; } } return undef; @@ -942,6 +943,48 @@ sub po_to_markup ($$;$) { return $content; } +# returns a SuccessReason or FailReason object +sub isvalidpo ($) { + my $content = shift; + + # NB: we don't use po_to_markup here, since Po4a parser does + # not mind invalid PO content + $content = '' unless defined $content; + $content = decode_utf8(encode_utf8($content)); + + # There are incompatibilities between some File::Temp versions + # (including 0.18, bundled with Lenny's perl-modules package) + # and others (e.g. 0.20, previously present in the archive as + # a standalone package): under certain circumstances, some + # return a relative filename, whereas others return an absolute one; + # we here use this module in a way that is at least compatible + # with 0.18 and 0.20. Beware, hit'n'run refactorers! + my $infile = new File::Temp(TEMPLATE => "ikiwiki-po-isvalidpo.XXXXXXXXXX", + DIR => File::Spec->tmpdir, + UNLINK => 1)->filename; + + sub failure ($) { + my $msg = '[po/isvalidpo:'.$page.'] ' . shift; + unlink $infile; + return IkiWiki::FailReason->new("$msg"); + } + + writefile(basename($infile), File::Spec->tmpdir, $content) + or return failure("failed to write $infile"); + + my $res = (system("msgfmt", "--check", $infile) == 0); + + # Unlinking should happen automatically, thanks to File::Temp, + # but it does not work here, probably because of the way writefile() + # and Locale::Po4a::write() work. + unlink $infile; + + if ($res) { + return IkiWiki::SuccessReason->new("valid gettext data"); + } + return IkiWiki::FailReason->new("invalid gettext data"); +} + # ,---- # | PageSpec's # `---- diff --git a/doc/plugins/po.mdwn b/doc/plugins/po.mdwn index c150092bf..a32d66af1 100644 --- a/doc/plugins/po.mdwn +++ b/doc/plugins/po.mdwn @@ -399,6 +399,10 @@ use in our case, I suggest we define `ENV{COLUMNS}` before loading `refreshpofiles()` runs this external program. A po4a developer answered he does "not expect any security issues from it". +### msgfmt + +`isvalidpo()` runs this external program. Its security should be checked. + ### Fuzzing input I was not able to find any public information about gettext or po4a -- 2.44.0