001/* 002 * Copyright 2023 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.runtime.request; 017 018import java.io.File; 019import java.io.IOException; 020import java.util.Enumeration; 021import java.util.HashMap; 022import java.util.Hashtable; 023import java.util.Map; 024 025import javax.servlet.http.HttpServletRequest; 026 027import org.apache.cocoon.servlet.multipart.MultipartException; 028import org.apache.cocoon.servlet.multipart.MultipartHttpServletRequest; 029import org.apache.cocoon.servlet.multipart.PartOnDisk; 030import org.apache.cocoon.servlet.multipart.RejectedPart; 031 032import org.ametys.runtime.config.ConfigManager; 033import org.ametys.runtime.servlet.AnalyseFileForVirusHelper; 034 035/** 036 * Extension of the cocoon request factory to allow antivirus scanning of uploaded file 037 */ 038public class RequestFactory extends org.apache.cocoon.servlet.multipart.RequestFactory 039{ 040 // check for antivirus activation at instantiation 041 private boolean _antivirusEnabled; 042 043 /** 044 * Default constructor see {@link org.apache.cocoon.servlet.multipart.RequestFactory} for documentation 045 * @param saveUploadedFilesToDisk to save files to disk 046 * @param uploadDirectory where to save files on disk 047 * @param allowOverwrite to allow overwrite 048 * @param silentlyRename to rename silently 049 * @param maxUploadSize the maximum size of an uploaded file 050 * @param defaultCharEncoding the default encoding 051 */ 052 public RequestFactory(boolean saveUploadedFilesToDisk, 053 File uploadDirectory, 054 boolean allowOverwrite, 055 boolean silentlyRename, 056 int maxUploadSize, 057 String defaultCharEncoding) 058 { 059 super(saveUploadedFilesToDisk, uploadDirectory, allowOverwrite, silentlyRename, maxUploadSize, defaultCharEncoding); 060 061 // Check antivirus activation 062 if (ConfigManager.getInstance().isComplete()) 063 { 064 _antivirusEnabled = AnalyseFileForVirusHelper.isAntivirusEnabled(); 065 } 066 } 067 068 @Override 069 public HttpServletRequest getServletRequest(HttpServletRequest request) throws IOException, MultipartException 070 { 071 HttpServletRequest servletRequest = super.getServletRequest(request); 072 // Check the activation of the antivirus to ensure minimal impact if antivirus is disabled 073 if (servletRequest instanceof MultipartHttpServletRequest multipart && _antivirusEnabled) 074 { 075 Map<String, RejectedPart> rejectedParam = new HashMap<>(); 076 Enumeration<String> parameterNames = multipart.getParameterNames(); 077 while (parameterNames.hasMoreElements()) 078 { 079 String name = parameterNames.nextElement(); 080 Object value = multipart.get(name); 081 if (value instanceof PartOnDisk diskPart) 082 { 083 File file = diskPart.getFile(); 084 // Check file here 085 if (!AnalyseFileForVirusHelper.analysefile(file.getAbsolutePath())) 086 { 087 // Delete dangerous file instantly 088 file.delete(); 089 // Record the name of param to remove 090 rejectedParam.put(name, new RejectedPart(diskPart.getHeaders(), 0, 0, 0)); 091 } 092 } 093 } 094 095 if (!rejectedParam.isEmpty()) 096 { 097 Hashtable<String, Object> params = new Hashtable<>(); 098 // some part were rejected. 099 // We have to copy the request parameters 100 parameterNames = multipart.getParameterNames(); 101 while (parameterNames.hasMoreElements()) 102 { 103 String name = parameterNames.nextElement(); 104 if (rejectedParam.containsKey(name)) 105 { 106 // We represent a contaminated part with a rejected part with max size = 0byte 107 params.put(name, rejectedParam.get(name)); 108 } 109 else 110 { 111 params.put(name, multipart.get(name)); 112 } 113 } 114 115 // and wrap the request with the new parameters including the rejected parts 116 servletRequest = new MultipartHttpServletRequest(servletRequest, params); 117 } 118 } 119 return servletRequest; 120 } 121}