diff options
author | Daniel Baumann <daniel@debian.org> | 2024-10-18 20:33:49 +0200 |
---|---|---|
committer | Daniel Baumann <daniel@debian.org> | 2024-12-12 23:57:56 +0100 |
commit | e68b9d00a6e05b3a941f63ffb696f91e554ac5ec (patch) | |
tree | 97775d6c13b0f416af55314eb6a89ef792474615 /services/context/upload/upload.go | |
parent | Initial commit. (diff) | |
download | forgejo-e68b9d00a6e05b3a941f63ffb696f91e554ac5ec.tar.xz forgejo-e68b9d00a6e05b3a941f63ffb696f91e554ac5ec.zip |
Adding upstream version 9.0.3.
Signed-off-by: Daniel Baumann <daniel@debian.org>
Diffstat (limited to 'services/context/upload/upload.go')
-rw-r--r-- | services/context/upload/upload.go | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/services/context/upload/upload.go b/services/context/upload/upload.go new file mode 100644 index 0000000..77a7eb9 --- /dev/null +++ b/services/context/upload/upload.go @@ -0,0 +1,105 @@ +// Copyright 2019 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package upload + +import ( + "mime" + "net/http" + "net/url" + "path" + "regexp" + "strings" + + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/services/context" +) + +// ErrFileTypeForbidden not allowed file type error +type ErrFileTypeForbidden struct { + Type string +} + +// IsErrFileTypeForbidden checks if an error is a ErrFileTypeForbidden. +func IsErrFileTypeForbidden(err error) bool { + _, ok := err.(ErrFileTypeForbidden) + return ok +} + +func (err ErrFileTypeForbidden) Error() string { + return "This file extension or type is not allowed to be uploaded." +} + +var wildcardTypeRe = regexp.MustCompile(`^[a-z]+/\*$`) + +// Verify validates whether a file is allowed to be uploaded. +func Verify(buf []byte, fileName, allowedTypesStr string) error { + allowedTypesStr = strings.ReplaceAll(allowedTypesStr, "|", ",") // compat for old config format + + allowedTypes := []string{} + for _, entry := range strings.Split(allowedTypesStr, ",") { + entry = strings.ToLower(strings.TrimSpace(entry)) + if entry != "" { + allowedTypes = append(allowedTypes, entry) + } + } + + if len(allowedTypes) == 0 { + return nil // everything is allowed + } + + fullMimeType := http.DetectContentType(buf) + mimeType, _, err := mime.ParseMediaType(fullMimeType) + if err != nil { + log.Warn("Detected attachment type could not be parsed %s", fullMimeType) + return ErrFileTypeForbidden{Type: fullMimeType} + } + extension := strings.ToLower(path.Ext(fileName)) + + // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#Unique_file_type_specifiers + for _, allowEntry := range allowedTypes { + if allowEntry == "*/*" { + return nil // everything allowed + } else if strings.HasPrefix(allowEntry, ".") && allowEntry == extension { + return nil // extension is allowed + } else if mimeType == allowEntry { + return nil // mime type is allowed + } else if wildcardTypeRe.MatchString(allowEntry) && strings.HasPrefix(mimeType, allowEntry[:len(allowEntry)-1]) { + return nil // wildcard match, e.g. image/* + } + } + + log.Info("Attachment with type %s blocked from upload", fullMimeType) + return ErrFileTypeForbidden{Type: fullMimeType} +} + +// AddUploadContext renders template values for dropzone +func AddUploadContext(ctx *context.Context, uploadType string) { + if uploadType == "release" { + ctx.Data["UploadUrl"] = ctx.Repo.RepoLink + "/releases/attachments" + ctx.Data["UploadRemoveUrl"] = ctx.Repo.RepoLink + "/releases/attachments/remove" + ctx.Data["UploadLinkUrl"] = ctx.Repo.RepoLink + "/releases/attachments" + ctx.Data["UploadAccepts"] = strings.ReplaceAll(setting.Repository.Release.AllowedTypes, "|", ",") + ctx.Data["UploadMaxFiles"] = setting.Attachment.MaxFiles + ctx.Data["UploadMaxSize"] = setting.Attachment.MaxSize + } else if uploadType == "comment" { + ctx.Data["UploadUrl"] = ctx.Repo.RepoLink + "/issues/attachments" + ctx.Data["UploadRemoveUrl"] = ctx.Repo.RepoLink + "/issues/attachments/remove" + if len(ctx.Params(":index")) > 0 { + ctx.Data["UploadLinkUrl"] = ctx.Repo.RepoLink + "/issues/" + url.PathEscape(ctx.Params(":index")) + "/attachments" + } else { + ctx.Data["UploadLinkUrl"] = ctx.Repo.RepoLink + "/issues/attachments" + } + ctx.Data["UploadAccepts"] = strings.ReplaceAll(setting.Attachment.AllowedTypes, "|", ",") + ctx.Data["UploadMaxFiles"] = setting.Attachment.MaxFiles + ctx.Data["UploadMaxSize"] = setting.Attachment.MaxSize + } else if uploadType == "repo" { + ctx.Data["UploadUrl"] = ctx.Repo.RepoLink + "/upload-file" + ctx.Data["UploadRemoveUrl"] = ctx.Repo.RepoLink + "/upload-remove" + ctx.Data["UploadLinkUrl"] = ctx.Repo.RepoLink + "/upload-file" + ctx.Data["UploadAccepts"] = strings.ReplaceAll(setting.Repository.Upload.AllowedTypes, "|", ",") + ctx.Data["UploadMaxFiles"] = setting.Repository.Upload.MaxFiles + ctx.Data["UploadMaxSize"] = setting.Repository.Upload.FileMaxSize + } +} |