mirror of
https://github.com/gitbucket/gitbucket.git
synced 2025-12-27 02:39:53 +01:00
Add file name validation
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
package gitbucket.core.controller
|
||||
|
||||
import java.io.File
|
||||
|
||||
import gitbucket.core.account.html
|
||||
import gitbucket.core.helper
|
||||
import gitbucket.core.model._
|
||||
@@ -284,7 +286,9 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
||||
response.setDateHeader("Last-Modified", account.updatedDate.getTime)
|
||||
account.image
|
||||
.map { image =>
|
||||
Some(RawData(FileUtil.getMimeType(image), new java.io.File(getUserUploadDir(userName), image)))
|
||||
Some(
|
||||
RawData(FileUtil.getMimeType(image), new File(getUserUploadDir(userName), FileUtil.checkFilename(image)))
|
||||
)
|
||||
}
|
||||
.getOrElse {
|
||||
if (account.isGroupAccount) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package gitbucket.core.controller
|
||||
|
||||
import java.io.FileInputStream
|
||||
import java.io.{File, FileInputStream}
|
||||
|
||||
import gitbucket.core.api.{ApiError, JsonFormat}
|
||||
import gitbucket.core.model.Account
|
||||
@@ -327,7 +327,7 @@ trait AccountManagementControllerBase extends ControllerBase {
|
||||
protected def updateImage(userName: String, fileId: Option[String], clearImage: Boolean): Unit =
|
||||
if (clearImage) {
|
||||
getAccountByUserName(userName).flatMap(_.image).map { image =>
|
||||
new java.io.File(getUserUploadDir(userName), image).delete()
|
||||
new File(getUserUploadDir(userName), FileUtil.checkFilename(image)).delete()
|
||||
updateAvatarImage(userName, None)
|
||||
}
|
||||
} else {
|
||||
@@ -338,9 +338,9 @@ trait AccountManagementControllerBase extends ControllerBase {
|
||||
uploadDir.mkdirs()
|
||||
}
|
||||
Thumbnails
|
||||
.of(new java.io.File(getTemporaryDir(session.getId), fileId))
|
||||
.of(new File(getTemporaryDir(session.getId), FileUtil.checkFilename(fileId)))
|
||||
.size(324, 324)
|
||||
.toFile(new java.io.File(uploadDir, filename))
|
||||
.toFile(new File(uploadDir, FileUtil.checkFilename(filename)))
|
||||
updateAvatarImage(userName, Some(filename))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package gitbucket.core.controller
|
||||
|
||||
import java.io.File
|
||||
|
||||
import gitbucket.core.model.Account
|
||||
import gitbucket.core.service.{AccountService, RepositoryService, ReleaseService}
|
||||
import gitbucket.core.service.{AccountService, ReleaseService, RepositoryService}
|
||||
import gitbucket.core.servlet.Database
|
||||
import gitbucket.core.util._
|
||||
import gitbucket.core.util.SyntaxSugars._
|
||||
@@ -31,7 +33,8 @@ class FileUploadController
|
||||
post("/image") {
|
||||
execute(
|
||||
{ (file, fileId) =>
|
||||
FileUtils.writeByteArrayToFile(new java.io.File(getTemporaryDir(session.getId), fileId), file.get)
|
||||
FileUtils
|
||||
.writeByteArrayToFile(new File(getTemporaryDir(session.getId), FileUtil.checkFilename(fileId)), file.get)
|
||||
session += Keys.Session.Upload(fileId) -> file.name
|
||||
},
|
||||
FileUtil.isImage
|
||||
@@ -41,7 +44,8 @@ class FileUploadController
|
||||
post("/tmp") {
|
||||
execute(
|
||||
{ (file, fileId) =>
|
||||
FileUtils.writeByteArrayToFile(new java.io.File(getTemporaryDir(session.getId), fileId), file.get)
|
||||
FileUtils
|
||||
.writeByteArrayToFile(new File(getTemporaryDir(session.getId), FileUtil.checkFilename(fileId)), file.get)
|
||||
session += Keys.Session.Upload(fileId) -> file.name
|
||||
},
|
||||
_ => true
|
||||
@@ -52,9 +56,9 @@ class FileUploadController
|
||||
execute(
|
||||
{ (file, fileId) =>
|
||||
FileUtils.writeByteArrayToFile(
|
||||
new java.io.File(
|
||||
new File(
|
||||
getAttachedDir(params("owner"), params("repository")),
|
||||
fileId + "." + FileUtil.getExtension(file.getName)
|
||||
FileUtil.checkFilename(fileId + "." + FileUtil.getExtension(file.getName))
|
||||
),
|
||||
file.get
|
||||
)
|
||||
@@ -129,12 +133,15 @@ class FileUploadController
|
||||
val owner = params("owner")
|
||||
val repository = params("repository")
|
||||
val tag = params("tag")
|
||||
execute({ (file, fileId) =>
|
||||
FileUtils.writeByteArrayToFile(
|
||||
new java.io.File(getReleaseFilesDir(owner, repository), tag + "/" + fileId),
|
||||
file.get
|
||||
)
|
||||
}, _ => true)
|
||||
execute(
|
||||
{ (file, fileId) =>
|
||||
FileUtils.writeByteArrayToFile(
|
||||
new File(getReleaseFilesDir(owner, repository), FileUtil.checkFilename(tag + "/" + fileId)),
|
||||
file.get
|
||||
)
|
||||
},
|
||||
_ => true
|
||||
)
|
||||
}
|
||||
.getOrElse(BadRequest())
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ trait ReleaseControllerBase extends ControllerBase {
|
||||
response.setHeader("Content-Disposition", s"attachment; filename=${asset.label}")
|
||||
RawData(
|
||||
FileUtil.getMimeType(asset.label),
|
||||
new File(getReleaseFilesDir(repository.owner, repository.name), tagName + "/" + fileId)
|
||||
new File(getReleaseFilesDir(repository.owner, repository.name), FileUtil.checkFilename(tagName + "/" + fileId))
|
||||
)
|
||||
}).getOrElse(NotFound())
|
||||
})
|
||||
@@ -111,7 +111,10 @@ trait ReleaseControllerBase extends ControllerBase {
|
||||
files.foreach {
|
||||
case (fileId, fileName) =>
|
||||
val size =
|
||||
new java.io.File(getReleaseFilesDir(repository.owner, repository.name), tagName + "/" + fileId).length
|
||||
new File(
|
||||
getReleaseFilesDir(repository.owner, repository.name),
|
||||
FileUtil.checkFilename(tagName + "/" + fileId)
|
||||
).length
|
||||
createReleaseAsset(repository.owner, repository.name, tagName, fileId, fileName, size, loginAccount)
|
||||
}
|
||||
|
||||
@@ -153,15 +156,18 @@ trait ReleaseControllerBase extends ControllerBase {
|
||||
files.foreach {
|
||||
case (fileId, fileName) =>
|
||||
val size =
|
||||
new java.io.File(getReleaseFilesDir(repository.owner, repository.name), tagName + "/" + fileId).length
|
||||
new File(
|
||||
getReleaseFilesDir(repository.owner, repository.name),
|
||||
FileUtil.checkFilename(tagName + "/" + fileId)
|
||||
).length
|
||||
createReleaseAsset(repository.owner, repository.name, tagName, fileId, fileName, size, loginAccount)
|
||||
}
|
||||
|
||||
assets.foreach { asset =>
|
||||
if (!files.exists { case (fileId, _) => fileId == asset.fileName }) {
|
||||
val file = new java.io.File(
|
||||
val file = new File(
|
||||
getReleaseFilesDir(repository.owner, repository.name),
|
||||
release.tag + "/" + asset.fileName
|
||||
FileUtil.checkFilename(release.tag + "/" + asset.fileName)
|
||||
)
|
||||
FileUtils.forceDelete(file)
|
||||
}
|
||||
@@ -175,7 +181,9 @@ trait ReleaseControllerBase extends ControllerBase {
|
||||
post("/:owner/:repository/releases/:tag/delete")(writableUsersOnly { repository =>
|
||||
val tagName = params("tag")
|
||||
getRelease(repository.owner, repository.name, tagName).foreach { release =>
|
||||
FileUtils.deleteDirectory(new File(getReleaseFilesDir(repository.owner, repository.name), release.tag))
|
||||
FileUtils.deleteDirectory(
|
||||
new File(getReleaseFilesDir(repository.owner, repository.name), FileUtil.checkFilename(release.tag))
|
||||
)
|
||||
}
|
||||
deleteRelease(repository.owner, repository.name, tagName)
|
||||
redirect(s"/${repository.owner}/${repository.name}/releases")
|
||||
|
||||
@@ -896,7 +896,8 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
}
|
||||
|
||||
newFiles.foreach { file =>
|
||||
val bytes = FileUtils.readFileToByteArray(new File(getTemporaryDir(session.getId), file.id))
|
||||
val bytes =
|
||||
FileUtils.readFileToByteArray(new File(getTemporaryDir(session.getId), FileUtil.checkFilename(file.id)))
|
||||
builder.add(
|
||||
JGitUtil.createDirCacheEntry(file.name, FileMode.REGULAR_FILE, inserter.insert(Constants.OBJ_BLOB, bytes))
|
||||
)
|
||||
|
||||
@@ -7,7 +7,7 @@ import gitbucket.core.model.Profile._
|
||||
import gitbucket.core.model.Profile.profile.blockingApi._
|
||||
import gitbucket.core.model.Profile.dateColumnType
|
||||
import gitbucket.core.util.Directory._
|
||||
import gitbucket.core.util.StringUtil
|
||||
import gitbucket.core.util.{FileUtil, StringUtil}
|
||||
import org.apache.commons.io.FileUtils
|
||||
|
||||
trait CommitsService {
|
||||
@@ -83,7 +83,7 @@ trait CommitsService {
|
||||
newLine: Option[Int],
|
||||
diffJson: String
|
||||
): Unit = {
|
||||
val dir = new java.io.File(getDiffDir(owner, repository), commitId)
|
||||
val dir = new File(getDiffDir(owner, repository), FileUtil.checkFilename(commitId))
|
||||
if (!dir.exists) {
|
||||
dir.mkdirs()
|
||||
}
|
||||
@@ -99,7 +99,7 @@ trait CommitsService {
|
||||
oldLine: Option[Int],
|
||||
newLine: Option[Int]
|
||||
): Option[String] = {
|
||||
val dir = new java.io.File(getDiffDir(owner, repository), commitId)
|
||||
val dir = new File(getDiffDir(owner, repository), FileUtil.checkFilename(commitId))
|
||||
val file = diffFile(dir, fileName, oldLine, newLine)
|
||||
if (file.exists) {
|
||||
Option(FileUtils.readFileToString(file, "UTF-8"))
|
||||
|
||||
@@ -52,7 +52,7 @@ object FileUtil {
|
||||
}
|
||||
|
||||
def getLfsFilePath(owner: String, repository: String, oid: String): String =
|
||||
Directory.getLfsDir(owner, repository) + "/" + oid
|
||||
Directory.getLfsDir(owner, repository) + "/" + checkFilename(oid)
|
||||
|
||||
def readableSize(size: Long): String = FileUtils.byteCountToDisplaySize(size)
|
||||
|
||||
@@ -76,6 +76,16 @@ object FileUtil {
|
||||
file
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of java.io.File safely.
|
||||
*/
|
||||
def checkFilename(name: String): String = {
|
||||
if (name.contains("..")) {
|
||||
throw new IllegalArgumentException(s"Invalid file name: ${name}")
|
||||
}
|
||||
name
|
||||
}
|
||||
|
||||
lazy val MaxFileSize =
|
||||
if (System.getProperty("gitbucket.maxFileSize") != null)
|
||||
System.getProperty("gitbucket.maxFileSize").toLong
|
||||
|
||||
Reference in New Issue
Block a user