diff --git a/application.properties b/application.properties index ee0e529b4..06390b478 100644 --- a/application.properties +++ b/application.properties @@ -2,5 +2,5 @@ #Tue Jun 20 09:06:54 EST 2017 app.grails.version=2.5.6 app.name=fieldcapture -app.version=1.60.1 +app.version=1.60.2-SNAPSHOT diff --git a/grails-app/controllers/au/org/ala/merit/ImageController.groovy b/grails-app/controllers/au/org/ala/merit/ImageController.groovy index ce7ef5708..bafeac04c 100644 --- a/grails-app/controllers/au/org/ala/merit/ImageController.groovy +++ b/grails-app/controllers/au/org/ala/merit/ImageController.groovy @@ -97,7 +97,12 @@ class ImageController { * The content type of the file is derived purely from the file extension. */ def get() { - File f = new File(imageService.fullPath(params.id)) + String filename = FilenameUtils.getName(params.id) + if (filename != params.id) { + response.status = 404 + return + } + File f = new File(imageService.fullPath(filename)) if (!f.exists()) { response.status = 404 return diff --git a/test/unit/au/org/ala/merit/ImageControllerSpec.groovy b/test/unit/au/org/ala/merit/ImageControllerSpec.groovy new file mode 100644 index 000000000..1a0fae0cd --- /dev/null +++ b/test/unit/au/org/ala/merit/ImageControllerSpec.groovy @@ -0,0 +1,60 @@ +package au.org.ala.merit + +import grails.test.mixin.TestFor +import org.apache.commons.io.IOUtils +import org.apache.http.HttpStatus +import spock.lang.Specification + +@TestFor(ImageController) +class ImageControllerSpec extends Specification { + + File uploadPath + File temp + + void setup() { + + controller.imageService = new ImageService() // to use the fullPath method without needing to mock it + controller.imageService.grailsApplication = controller.grailsApplication + temp = File.createTempDir("tmp", "") + uploadPath = new File(temp, "upload") + uploadPath.mkdir() + + controller.grailsApplication.config.upload.images.path = uploadPath.getAbsolutePath() + + // Setup two files, one that should be accessible, and one that should not. + File validFile = new File(uploadPath, "validFile.png") + validFile.createNewFile() + + File privateFile = new File(temp, "privateFile.png") + privateFile.createNewFile() + } + + void "Files can be retrieved from the temporary upload directory by filename"() { + when: + params.id = "validFile.png" + controller.get() + + then: + response.contentType == "image/png" + response.status == HttpStatus.SC_OK + } + + void "If a file doesn't exist, a 404 will be returned"() { + when: + params.id = "missingFile.png" + controller.get() + + then: + response.status == HttpStatus.SC_NOT_FOUND + } + + void "A file cannot be retrieved from outside the designated uploads directory"() { + when: + params.id = "../privateFile.png" + controller.get() + + then: + new File(uploadPath, params.id).exists() + response.status == HttpStatus.SC_NOT_FOUND + } +}