File Coverage

blib/lib/Mail/Exim/ACL/Attachments.pm
Criterion Covered Total %
statement 47 47 100.0
branch 12 14 85.7
condition 1 2 50.0
subroutine 8 8 100.0
pod 2 2 100.0
total 70 73 95.8


line stmt bran cond sub pod time code
1             package Mail::Exim::ACL::Attachments;
2              
3             # SPDX-License-Identifier: Artistic-1.0-Perl OR GPL-1.0-or-later
4              
5 1     1   126337 use 5.016;
  1         14  
6 1     1   5 use warnings;
  1         2  
  1         36  
7 1     1   12 use utf8;
  1         2  
  1         7  
8              
9             our $VERSION = 1.005;
10              
11 1     1   74 use Exporter qw(import);
  1         2  
  1         68  
12 1     1   721 use IO::Uncompress::Unzip;
  1         30961  
  1         965  
13              
14             our @EXPORT_OK = qw(check_filename check_zip);
15              
16             # https://docs.microsoft.com/en-us/deployoffice/compat/office-file-format-reference
17             # https://en.wikipedia.org/wiki/List_of_Microsoft_Office_filename_extensions
18             our %MACRO_ENABLED = (
19             doc => 'Word Document',
20             docb => 'Word Document',
21             docm => 'Word Document',
22             dot => 'Word Template',
23             dotm => 'Word Template',
24             one => 'OneNote Export File',
25             pot => 'PowerPoint Template',
26             potm => 'PowerPoint Template',
27             ppa => 'PowerPoint Add-in',
28             ppam => 'PowerPoint Add-in',
29             pps => 'PowerPoint Slide Show',
30             ppsm => 'PowerPoint Slide Show',
31             ppt => 'PowerPoint Presentation',
32             pptm => 'PowerPoint Presentation',
33             sldm => 'PowerPoint Slide',
34             vsd => 'Visio Drawing File',
35             vsdm => 'Visio Drawing File',
36             vss => 'Visio Stencil File',
37             vssm => 'Visio Stencil File',
38             vst => 'Visio Drawing Template',
39             vstm => 'Visio Drawing Template',
40             xla => 'Excel Add-in',
41             xlam => 'Excel Add-in',
42             xlm => 'Excel Macro',
43             xls => 'Excel Spreadsheet',
44             xlsb => 'Excel Spreadsheet',
45             xlsm => 'Excel Spreadsheet',
46             xlt => 'Excel Spreadsheet Template',
47             xltm => 'Excel Spreadsheet Template',
48             xlw => 'Excel Workspace',
49             );
50              
51             # https://support.office.com/en-us/article/blocked-attachments-in-outlook-434752e1-02d3-4e90-9124-8b81e49a8519
52             our %BLOCKED_BY_OUTLOOK = (
53             ade => 'Access Project Extension',
54             adp => 'Access Project',
55             app => 'Executable Application',
56             application => 'ClickOnce Deployment Manifest File',
57             'appref-ms' => 'ClickOnce Application Reference File',
58             asp => 'Active Server Page',
59             aspx => 'Active Server Page Extended',
60             asx => 'ASF Redirector file',
61             bas => 'BASIC Source Code',
62             bat => 'Batch Processing',
63             bgi => 'Borland Graphics Interface',
64             cab => 'Windows Cabinet File',
65             cer => 'Internet Security Certificate File',
66             chm => 'Compiled HTML Help',
67             cmd => 'Command File',
68             cnt => 'Microsoft Help Workshop Application',
69             com => 'Command',
70             cpl => 'Windows Control Panel Extension',
71             crt => 'Certificate File',
72             csh => 'csh Script',
73             der => 'DER Encoded X509 Certificate File',
74             diagcab => 'Microsoft Support diagnostic tools',
75             exe => 'Executable File',
76             fxp => 'FoxPro Compiled Source',
77             gadget => 'Windows Vista gadget',
78             grp => 'Microsoft program group',
79             hlp => 'Windows Help File',
80             hpj => 'AppWizard Help project',
81             hta => 'Hypertext Application',
82             htc => 'HTML component file',
83             inf => 'Information or Setup File',
84             ins => 'IIS Internet Communications Settings',
85             iso => 'Optical Disk Media File System',
86             isp => 'IIS Internet Service Provider Settings',
87             its => 'Internet Document Set',
88             jar => 'Java Archive',
89             jnlp => 'Java Network Launch Protocol',
90             js => 'JavaScript Source Code',
91             jse => 'JScript Encoded Script File',
92             ksh => 'UNIX Shell Script',
93             lnk => 'Windows Shortcut File',
94             mad => 'Access Module Shortcut',
95             maf => 'Access',
96             mag => 'Access Diagram Shortcut',
97             mam => 'Access Macro Shortcut',
98             maq => 'Access Query Shortcut',
99             mar => 'Access Report Shortcut',
100             mas => 'Access Stored Procedures',
101             mat => 'Access Table Shortcut',
102             mau => 'Media Attachment Unit',
103             mav => 'Access View Shortcut',
104             maw => 'Access Data Access Page',
105             mcf => 'Media Container Format',
106             mda => 'Access Add-in',
107             mdb => 'Access Application',
108             mde => 'Access MDE Database File',
109             mdt => 'Access Add-in Data',
110             mdw => 'Access Workgroup Information',
111             mdz => 'Access Wizard Template',
112             msc => 'Microsoft Management Console Snap-in Control File',
113             msh => 'Microsoft Shell',
114             msh1 => 'Microsoft Shell',
115             msh2 => 'Microsoft Shell',
116             mshxml => 'Microsoft Shell',
117             msh1xml => 'Microsoft Shell',
118             msh2xml => 'Microsoft Shell',
119             msi => 'Windows Installer File',
120             msp => 'Windows Installer Update',
121             mst => 'Windows SDK Setup Transform Script',
122             msu => 'Windows Update file',
123             ops => 'Office Profile Settings File',
124             osd => 'Open Software Description ',
125             pcd => 'Visual Test',
126             pif => 'Windows Program Information File',
127             pl => 'Perl script',
128             plg => 'Developer Studio Build Log',
129             prf => 'Windows System File',
130             prg => 'Program File',
131             printerexport => 'Printer backup file',
132             ps1 => 'Windows PowerShell',
133             ps1xml => 'Windows PowerShell',
134             ps2 => 'Windows PowerShell',
135             ps2xml => 'Windows PowerShell',
136             psc1 => 'Windows PowerShell',
137             psc2 => 'Windows PowerShell',
138             psd1 => 'Windows PowerShell',
139             psdm1 => 'Windows PowerShell',
140             pst => 'Outlook Personal Folder File',
141             py => 'Python script',
142             pyc => 'Python script',
143             pyo => 'Python script',
144             pyw => 'Python script',
145             pyz => 'Python script',
146             pyzw => 'Python script',
147             reg => 'Registry Data File',
148             scf => 'Windows Explorer Command',
149             scr => 'Windows Screen Saver',
150             sct => 'Windows Script Component',
151             shb => 'Windows Shortcut into a Document',
152             shs => 'Shell Scrap Object File',
153             theme => 'Desktop theme file settings',
154             tmp => 'Temporary File/Folder',
155             url => 'Internet Location',
156             vb => 'VBScript File or Any Visual Basic Source',
157             vbe => 'VBScript Encoded Script File',
158             vbp => 'Visual Basic project file',
159             vbs => 'VBScript File',
160             vhd => 'Virtual Hard Disk',
161             vhdx => 'Virtual Hard Disk Extended',
162             vsmacros => 'Visual Studio .NET Binary-based Macro Project',
163             vsw => 'Visio Workspace File',
164             webpnp => 'Internet printing file',
165             website => 'Pinned site shortcut from Internet Explorer',
166             ws => 'Windows Script File',
167             wsc => 'Windows Script Component',
168             wsf => 'Windows Script File',
169             wsh => 'Windows Script Host Settings File',
170             xbap => 'Browser applications',
171             xll => 'Excel Add-in',
172             xnk => 'Exchange Public Folder Shortcut',
173             );
174              
175             # File associations from 7-Zip and others
176             our %ARCHIVES = (
177             '7z' => '7-Zip Archive',
178             ace => 'ACE File',
179             arj => 'ARJ File',
180             bz2 => 'bzip2 File',
181             bzip2 => 'bzip2 File',
182             cpio => 'CPIO Archive',
183             deb => 'Debian Package',
184             dmg => 'Disk Image',
185             esd => 'Disk Image',
186             fat => 'Zip Archive',
187             gz => 'gzip File',
188             gzip => 'gzip File',
189             hfs => 'Disk Image',
190             lha => 'LHA File',
191             lzh => 'LZH File',
192             lzma => 'LZMA File',
193             ntfs => 'Disk Image',
194             rar => 'RAR Archive',
195             rpm => 'RPM File',
196             sfx => 'Self-extracting Archive',
197             squashfs => 'Disk Image',
198             swm => 'Disk Image',
199             tar => 'tar Archive',
200             taz => 'tar Archive',
201             tbz => 'tar Archive',
202             tbz2 => 'tar Archive',
203             tgz => 'tar Archive',
204             tpz => 'tar Archive',
205             txz => 'tar Archive',
206             uue => 'uuencoded File',
207             wim => 'Disk Image',
208             xar => 'XAR File',
209             xz => 'XZ File',
210             z => 'gzip File',
211             zip => 'Zip Archive',
212             );
213              
214             our %BLOCKLIST = (%MACRO_ENABLED, %BLOCKED_BY_OUTLOOK, %ARCHIVES);
215              
216             sub check_filename {
217 9     9 1 7272 my $filename = shift;
218              
219 9         18 my $extension = q{};
220 9 50       67 if ($filename =~ m{[.]\h*([^.]+)\z}) {
221 9         34 $extension = lc $1;
222             }
223              
224 9 100       26 if (exists $BLOCKLIST{$extension}) {
225 5         23 return 'blocked';
226             }
227              
228             # Reject split archives like "001" and "r01".
229 4 100       15 if ($extension =~ m{\A[r\d]\d{2,}\z}) {
230 2         9 return 'blocked';
231             }
232              
233 2         8 return 'ok';
234             }
235              
236             sub _get_filename {
237 4     4   7 my $zip = shift;
238              
239 4         6 my $filename;
240              
241 4         8 my $header = eval { $zip->getHeaderInfo };
  4         24  
242 4 100       29 if (defined $header) {
243 3         8 $filename = $header->{Name};
244             }
245              
246 4         9 return $filename;
247             }
248              
249             sub check_zip {
250 4     4 1 1901 my $input = shift;
251              
252 4         8 my $result = 'blocked';
253              
254 4         8 my $zip = eval { IO::Uncompress::Unzip->new($input) };
  4         25  
255 4 50       6171 if (defined $zip) {
256 4         8 my $status = 1;
257             STREAM:
258 4         10 while ($status > 0) {
259 4         10 my $filename = _get_filename($zip);
260 4 100       9 if (defined $filename) {
261 3         7 $result = check_filename($filename);
262             }
263             else {
264 1         3 $result = 'blocked';
265             }
266 4 100       13 if ($result ne 'ok') {
267 3         8 last STREAM;
268             }
269 1   50     3 $status = eval { $zip->nextStream } // -1;
  1         32  
270             }
271 4         217 $zip->close;
272             }
273              
274 4         77 return $result;
275             }
276              
277             1;
278             __END__