From 347e37b2e0fc6c3287b51a01be5cc318d4dfe384 Mon Sep 17 00:00:00 2001 From: David Cook Date: Fri, 13 Mar 2026 02:42:14 +0000 Subject: [PATCH] Bug 42080: (follow-up) allow some file types, checked by libmagic, to be viewed inline This patch uses File::LibMagic to determine the real file type using libmagic and magic numbers of invoice files, and allows a select group of file types to be viewed inline for user convenience. Note that a default Content-Security-Policy is still included to offer an extra layer of protection against XSS. Test plan: 0a. Apply the patch 0b. koha-plack --restart kohadev 1. Enable the syspref AcqEnableFiles (ie set to Do) 2. Find or create an active vendor 3. Create a basket if one doesn't already exist 4. Receive a shipment for the vendor 5. Create an invoice 6. Click "Finish receiving" 7. Click "Manage invoice files" 8. Upload a range of files including SVG, PDF, PNG, TXT 9. Click on the "Download" button 10. Note that the file downloads for all types 11. Click on the link in the "Name" column 12. Note that only the PDF and PNG display inline in the browser. The other file types should be downloaded same as if you clicked the "Download" button. Signed-off-by: David Cook --- acqui/invoice-files.pl | 32 ++++++++++++++++--- .../prog/en/modules/acqui/invoice-files.tt | 2 +- .../prog/en/modules/acqui/invoice.tt | 2 +- 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/acqui/invoice-files.pl b/acqui/invoice-files.pl index 34b99f3b89a..6886642d853 100755 --- a/acqui/invoice-files.pl +++ b/acqui/invoice-files.pl @@ -28,6 +28,7 @@ Manage files associated with invoice =cut use Modern::Perl; +use File::LibMagic; use CGI; use C4::Auth qw( get_template_and_user ); @@ -45,6 +46,15 @@ my ( $template, $loggedinuser, $cookie, $flags ) = get_template_and_user( } ); +#NOTE: 'image/svg+xml' is not a safe type as the XML can contain Javascript +my $allowed_ftypes = { + 'application/pdf' => 1, + 'image/png' => 1, + 'image/jpeg' => 1, + 'image/gif' => 1, + 'image/webp' => 1, +}; + my $invoiceid = $input->param('invoiceid') // ''; my $op = $input->param('op') // ''; my %errors; @@ -58,11 +68,23 @@ if ( $op eq 'download' ) { my $fname = $file->{'file_name'}; my $ftype = $file->{'file_type'}; - print $input->header( - -type => $file->{'file_type'}, - -charset => 'utf-8', - 'Content-Security-Policy' => "default-src 'none'; script-src 'none';" - ); + + my $magic = File::LibMagic->new(); + my $magic_info = $magic->info_from_string( $file->{'file_content'} ); + my $magic_mime_type = $magic_info->{mime_type}; + if ( $input->param('view') && ( $magic_mime_type && $allowed_ftypes->{$magic_mime_type} ) ) { + print $input->header( + -type => $file->{'file_type'}, + -charset => 'utf-8', + 'Content-Security-Policy' => "default-src 'none';" + ); + } else { + print $input->header( + -type => $file->{'file_type'}, + -charset => 'utf-8', + -attachment => $file->{'file_name'}, + ); + } print $file->{'file_content'}; } else { my $details = GetInvoiceDetails($invoiceid); diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/invoice-files.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/invoice-files.tt index 3507581aa0f..aeb50dbc9dd 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/invoice-files.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/invoice-files.tt @@ -64,7 +64,7 @@ [% FOREACH f IN files %] - [% f.file_name | html %] + [% f.file_name | html %] [% f.file_type | html %] [% f.file_description | html %] [% f.date_uploaded | $KohaDates %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/invoice.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/invoice.tt index a1feabc25ce..ae09cbc0a6f 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/invoice.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/invoice.tt @@ -500,7 +500,7 @@ [% FOREACH f IN files %] - [% f.file_name | html %] + [% f.file_name | html %] [% f.file_type | html %] [% f.file_description | html %] -- 2.39.5