-
Notifications
You must be signed in to change notification settings - Fork 640
/
Copy pathAttachmentCtrl.scala
113 lines (106 loc) · 4.18 KB
/
AttachmentCtrl.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package controllers
import akka.stream.scaladsl.FileIO
import models.Roles
import net.lingala.zip4j.ZipFile
import net.lingala.zip4j.model.ZipParameters
import net.lingala.zip4j.model.enums.{CompressionLevel, EncryptionMethod}
import org.elastic4play.Timed
import org.elastic4play.controllers.Authenticated
import org.elastic4play.models.AttachmentAttributeFormat
import org.elastic4play.services.{AttachmentSrv, ExecutionContextSrv}
import play.api.http.HttpEntity
import play.api.libs.Files.DefaultTemporaryFileCreator
import play.api.mvc._
import play.api.{Configuration, mvc}
import java.net.URLEncoder
import java.nio.file.Files
import javax.inject.{Inject, Singleton}
/**
* Controller used to access stored attachments (plain or zipped)
*/
@Singleton
class AttachmentCtrl(
password: String,
tempFileCreator: DefaultTemporaryFileCreator,
attachmentSrv: AttachmentSrv,
authenticated: Authenticated,
components: ControllerComponents,
executionContextSrv: ExecutionContextSrv
) extends AbstractController(components) {
@Inject() def this(
configuration: Configuration,
tempFileCreator: DefaultTemporaryFileCreator,
attachmentSrv: AttachmentSrv,
authenticated: Authenticated,
components: ControllerComponents,
executionContextSrv: ExecutionContextSrv
) =
this(
configuration.get[String]("datastore.attachment.password"),
tempFileCreator,
attachmentSrv,
authenticated,
components,
executionContextSrv
)
/**
* Download an attachment, identified by its hash, in plain format
* File name can be specified. This method is not protected : browser will
* open the document directly. It must be used only for safe file
*/
@Timed("controllers.AttachmentCtrl.download")
def download(hash: String, name: Option[String]): Action[AnyContent] = authenticated(Roles.read) { _ =>
executionContextSrv.withDefault { implicit ec =>
if (hash.startsWith("{{")) // angularjs hack
NoContent
else if (name.getOrElse("").intersect(AttachmentAttributeFormat.forbiddenChar).nonEmpty)
mvc.Results.BadRequest("File name is invalid")
else
Result(
header = ResponseHeader(
200,
Map("Content-Disposition" -> s"""attachment; filename="${URLEncoder.encode(name.getOrElse(hash), "utf-8")}"""", "Content-Transfer-Encoding" -> "binary")
),
body = HttpEntity.Streamed(attachmentSrv.source(hash), None, None)
)
}
}
/**
* Download an attachment, identified by its hash, in zip format.
* Zip file is protected by the password "malware"
* File name can be specified (zip extension is append)
*/
@Timed("controllers.AttachmentCtrl.downloadZip")
def downloadZip(hash: String, name: Option[String]): Action[AnyContent] = authenticated(Roles.read) { _ =>
executionContextSrv.withDefault { implicit ec =>
if (name.getOrElse("").intersect(AttachmentAttributeFormat.forbiddenChar).nonEmpty)
BadRequest("File name is invalid")
else {
val f = tempFileCreator.create("zip", hash).path
Files.delete(f)
val zipFile = new ZipFile(f.toFile)
zipFile.setPassword(password.toCharArray)
val zipParams = new ZipParameters
zipParams.setCompressionLevel(CompressionLevel.FASTEST)
zipParams.setEncryptFiles(true)
zipParams.setEncryptionMethod(EncryptionMethod.ZIP_STANDARD)
// zipParams.setsetPassword(password.toCharArray)
zipParams.setFileNameInZip(name.getOrElse(hash))
// zipParams.setSourceExternalStream(true)
zipFile.addStream(attachmentSrv.stream(hash), zipParams)
Result(
header = ResponseHeader(
200,
Map(
"Content-Disposition" -> s"""attachment; filename="${URLEncoder.encode(name.getOrElse(hash), "utf-8")}.zip"""",
"Content-Type" -> "application/zip",
"Content-Transfer-Encoding" -> "binary",
"Content-Length" -> Files.size(f).toString
)
),
body = HttpEntity.Streamed(FileIO.fromPath(f), Some(Files.size(f)), Some("application/zip"))
)
}
}
}
}