code.gitea.io/gitea@v1.19.3/modules/upload/upload.go (about) 1 // Copyright 2019 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package upload 5 6 import ( 7 "mime" 8 "net/http" 9 "net/url" 10 "path" 11 "regexp" 12 "strings" 13 14 "code.gitea.io/gitea/modules/context" 15 "code.gitea.io/gitea/modules/log" 16 "code.gitea.io/gitea/modules/setting" 17 ) 18 19 // ErrFileTypeForbidden not allowed file type error 20 type ErrFileTypeForbidden struct { 21 Type string 22 } 23 24 // IsErrFileTypeForbidden checks if an error is a ErrFileTypeForbidden. 25 func IsErrFileTypeForbidden(err error) bool { 26 _, ok := err.(ErrFileTypeForbidden) 27 return ok 28 } 29 30 func (err ErrFileTypeForbidden) Error() string { 31 return "This file extension or type is not allowed to be uploaded." 32 } 33 34 var wildcardTypeRe = regexp.MustCompile(`^[a-z]+/\*$`) 35 36 // Verify validates whether a file is allowed to be uploaded. 37 func Verify(buf []byte, fileName, allowedTypesStr string) error { 38 allowedTypesStr = strings.ReplaceAll(allowedTypesStr, "|", ",") // compat for old config format 39 40 allowedTypes := []string{} 41 for _, entry := range strings.Split(allowedTypesStr, ",") { 42 entry = strings.ToLower(strings.TrimSpace(entry)) 43 if entry != "" { 44 allowedTypes = append(allowedTypes, entry) 45 } 46 } 47 48 if len(allowedTypes) == 0 { 49 return nil // everything is allowed 50 } 51 52 fullMimeType := http.DetectContentType(buf) 53 mimeType, _, err := mime.ParseMediaType(fullMimeType) 54 if err != nil { 55 log.Warn("Detected attachment type could not be parsed %s", fullMimeType) 56 return ErrFileTypeForbidden{Type: fullMimeType} 57 } 58 extension := strings.ToLower(path.Ext(fileName)) 59 60 // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#Unique_file_type_specifiers 61 for _, allowEntry := range allowedTypes { 62 if allowEntry == "*/*" { 63 return nil // everything allowed 64 } else if strings.HasPrefix(allowEntry, ".") && allowEntry == extension { 65 return nil // extension is allowed 66 } else if mimeType == allowEntry { 67 return nil // mime type is allowed 68 } else if wildcardTypeRe.MatchString(allowEntry) && strings.HasPrefix(mimeType, allowEntry[:len(allowEntry)-1]) { 69 return nil // wildcard match, e.g. image/* 70 } 71 } 72 73 log.Info("Attachment with type %s blocked from upload", fullMimeType) 74 return ErrFileTypeForbidden{Type: fullMimeType} 75 } 76 77 // AddUploadContext renders template values for dropzone 78 func AddUploadContext(ctx *context.Context, uploadType string) { 79 if uploadType == "release" { 80 ctx.Data["UploadUrl"] = ctx.Repo.RepoLink + "/releases/attachments" 81 ctx.Data["UploadRemoveUrl"] = ctx.Repo.RepoLink + "/releases/attachments/remove" 82 ctx.Data["UploadLinkUrl"] = ctx.Repo.RepoLink + "/releases/attachments" 83 ctx.Data["UploadAccepts"] = strings.ReplaceAll(setting.Repository.Release.AllowedTypes, "|", ",") 84 ctx.Data["UploadMaxFiles"] = setting.Attachment.MaxFiles 85 ctx.Data["UploadMaxSize"] = setting.Attachment.MaxSize 86 } else if uploadType == "comment" { 87 ctx.Data["UploadUrl"] = ctx.Repo.RepoLink + "/issues/attachments" 88 ctx.Data["UploadRemoveUrl"] = ctx.Repo.RepoLink + "/issues/attachments/remove" 89 if len(ctx.Params(":index")) > 0 { 90 ctx.Data["UploadLinkUrl"] = ctx.Repo.RepoLink + "/issues/" + url.PathEscape(ctx.Params(":index")) + "/attachments" 91 } else { 92 ctx.Data["UploadLinkUrl"] = ctx.Repo.RepoLink + "/issues/attachments" 93 } 94 ctx.Data["UploadAccepts"] = strings.ReplaceAll(setting.Attachment.AllowedTypes, "|", ",") 95 ctx.Data["UploadMaxFiles"] = setting.Attachment.MaxFiles 96 ctx.Data["UploadMaxSize"] = setting.Attachment.MaxSize 97 } else if uploadType == "repo" { 98 ctx.Data["UploadUrl"] = ctx.Repo.RepoLink + "/upload-file" 99 ctx.Data["UploadRemoveUrl"] = ctx.Repo.RepoLink + "/upload-remove" 100 ctx.Data["UploadLinkUrl"] = ctx.Repo.RepoLink + "/upload-file" 101 ctx.Data["UploadAccepts"] = strings.ReplaceAll(setting.Repository.Upload.AllowedTypes, "|", ",") 102 ctx.Data["UploadMaxFiles"] = setting.Repository.Upload.MaxFiles 103 ctx.Data["UploadMaxSize"] = setting.Repository.Upload.FileMaxSize 104 } 105 }