various fixes (#36697)

fixes bad address concat causing malformed address
Introduces new config options to for release attachments and number of
files to avoid sharing limits for PR/issue attachments and release ones

Fixes: https://github.com/go-gitea/gitea/issues/31638
Fixes: https://github.com/go-gitea/gitea/issues/35812
Doc update: https://gitea.com/gitea/docs/pulls/348
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
TheFox0x7
2026-02-22 08:01:43 +01:00
committed by GitHub
parent bb41bca739
commit eb59b1a24a
9 changed files with 32 additions and 17 deletions

View File

@@ -7,6 +7,7 @@ import (
"crypto/x509" "crypto/x509"
"encoding/pem" "encoding/pem"
"fmt" "fmt"
"net"
"net/http" "net/http"
"os" "os"
"strconv" "strconv"
@@ -124,8 +125,8 @@ func runACME(listenAddr string, m http.Handler) error {
defer finished() defer finished()
log.Info("Running Let's Encrypt handler on %s", setting.HTTPAddr+":"+setting.PortToRedirect) log.Info("Running Let's Encrypt handler on %s", setting.HTTPAddr+":"+setting.PortToRedirect)
// all traffic coming into HTTP will be redirect to HTTPS automatically (LE HTTP-01 validation happens here) // all traffic coming into HTTP will be redirected to HTTPS automatically (LE HTTP-01 validation happens here)
err := runHTTP("tcp", setting.HTTPAddr+":"+setting.PortToRedirect, "Let's Encrypt HTTP Challenge", myACME.HTTPChallengeHandler(http.HandlerFunc(runLetsEncryptFallbackHandler)), setting.RedirectorUseProxyProtocol) err := runHTTP("tcp", net.JoinHostPort(setting.HTTPAddr, setting.PortToRedirect), "Let's Encrypt HTTP Challenge", myACME.HTTPChallengeHandler(http.HandlerFunc(runLetsEncryptFallbackHandler)), setting.RedirectorUseProxyProtocol)
if err != nil { if err != nil {
log.Fatal("Failed to start the Let's Encrypt handler on port %s: %v", setting.PortToRedirect, err) log.Fatal("Failed to start the Let's Encrypt handler on port %s: %v", setting.PortToRedirect, err)
} }

View File

@@ -1180,7 +1180,15 @@ LEVEL = Info
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Comma-separated list of allowed file extensions (`.zip`), mime types (`text/plain`) or wildcard type (`image/*`, `audio/*`, `video/*`). Empty value or `*/*` allows all types. ;; Comma-separated list of allowed file extensions (`.zip`), mime types (`text/plain`) or wildcard type (`image/*`, `audio/*`, `video/*`). Empty value or `*/*` allows all types.
;ALLOWED_TYPES = ;ALLOWED_TYPES =
;;
;; Number of releases that are displayed on release page
;DEFAULT_PAGING_NUM = 10 ;DEFAULT_PAGING_NUM = 10
;;
;; Max size of each file in megabytes. Defaults to 2GB
;FILE_MAX_SIZE = 2048
;;
;; Max number of files per upload. Defaults to 5
;MAX_FILES = 5
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -1995,8 +2003,8 @@ LEVEL = Info
;; Comma-separated list of allowed file extensions (`.zip`), mime types (`text/plain`) or wildcard type (`image/*`, `audio/*`, `video/*`). Empty value or `*/*` allows all types. ;; Comma-separated list of allowed file extensions (`.zip`), mime types (`text/plain`) or wildcard type (`image/*`, `audio/*`, `video/*`). Empty value or `*/*` allows all types.
;ALLOWED_TYPES = .avif,.cpuprofile,.csv,.dmp,.docx,.fodg,.fodp,.fods,.fodt,.gif,.gz,.jpeg,.jpg,.json,.jsonc,.log,.md,.mov,.mp4,.odf,.odg,.odp,.ods,.odt,.patch,.pdf,.png,.pptx,.svg,.tgz,.txt,.webm,.webp,.xls,.xlsx,.zip ;ALLOWED_TYPES = .avif,.cpuprofile,.csv,.dmp,.docx,.fodg,.fodp,.fods,.fodt,.gif,.gz,.jpeg,.jpg,.json,.jsonc,.log,.md,.mov,.mp4,.odf,.odg,.odp,.ods,.odt,.patch,.pdf,.png,.pptx,.svg,.tgz,.txt,.webm,.webp,.xls,.xlsx,.zip
;; ;;
;; Max size of each file. Defaults to 2048MB ;; Max size of each file. Defaults to 100MB
;MAX_SIZE = 2048 ;MAX_SIZE = 100
;; ;;
;; Max number of files per upload. Defaults to 5 ;; Max number of files per upload. Defaults to 5
;MAX_FILES = 5 ;MAX_FILES = 5

View File

@@ -16,13 +16,9 @@ var Attachment AttachmentSettingType
func loadAttachmentFrom(rootCfg ConfigProvider) (err error) { func loadAttachmentFrom(rootCfg ConfigProvider) (err error) {
Attachment = AttachmentSettingType{ Attachment = AttachmentSettingType{
AllowedTypes: ".avif,.cpuprofile,.csv,.dmp,.docx,.fodg,.fodp,.fods,.fodt,.gif,.gz,.jpeg,.jpg,.json,.jsonc,.log,.md,.mov,.mp4,.odf,.odg,.odp,.ods,.odt,.patch,.pdf,.png,.pptx,.svg,.tgz,.txt,.webm,.webp,.xls,.xlsx,.zip", AllowedTypes: ".avif,.cpuprofile,.csv,.dmp,.docx,.fodg,.fodp,.fods,.fodt,.gif,.gz,.jpeg,.jpg,.json,.jsonc,.log,.md,.mov,.mp4,.odf,.odg,.odp,.ods,.odt,.patch,.pdf,.png,.pptx,.svg,.tgz,.txt,.webm,.webp,.xls,.xlsx,.zip",
MaxSize: 100,
// FIXME: this size is used for both "issue attachment" and "release attachment" MaxFiles: 5,
// The design is not right, these two should be different settings Enabled: true,
MaxSize: 2048,
MaxFiles: 5,
Enabled: true,
} }
sec, _ := rootCfg.GetSection("attachment") sec, _ := rootCfg.GetSection("attachment")
if sec == nil { if sec == nil {

View File

@@ -100,6 +100,8 @@ var (
Release struct { Release struct {
AllowedTypes string AllowedTypes string
DefaultPagingNum int DefaultPagingNum int
FileMaxSize int64
MaxFiles int64
} `ini:"repository.release"` } `ini:"repository.release"`
Signing struct { Signing struct {
@@ -241,9 +243,13 @@ var (
Release: struct { Release: struct {
AllowedTypes string AllowedTypes string
DefaultPagingNum int DefaultPagingNum int
FileMaxSize int64
MaxFiles int64
}{ }{
AllowedTypes: "", AllowedTypes: "",
DefaultPagingNum: 10, DefaultPagingNum: 10,
FileMaxSize: 2048,
MaxFiles: 5,
}, },
// Signing settings // Signing settings

View File

@@ -234,7 +234,7 @@ func CreateReleaseAttachment(ctx *context.APIContext) {
} }
// Create a new attachment and save the file // Create a new attachment and save the file
attach, err := attachment_service.UploadAttachmentGeneralSizeLimit(ctx, uploaderFile, setting.Repository.Release.AllowedTypes, &repo_model.Attachment{ attach, err := attachment_service.UploadAttachmentReleaseSizeLimit(ctx, uploaderFile, setting.Repository.Release.AllowedTypes, &repo_model.Attachment{
Name: filename, Name: filename,
UploaderID: ctx.Doer.ID, UploaderID: ctx.Doer.ID,
RepoID: ctx.Repo.Repository.ID, RepoID: ctx.Repo.Repository.ID,

View File

@@ -46,7 +46,7 @@ func uploadAttachment(ctx *context.Context, repoID int64, allowedTypes string) {
defer file.Close() defer file.Close()
uploaderFile := attachment.NewLimitedUploaderKnownSize(file, header.Size) uploaderFile := attachment.NewLimitedUploaderKnownSize(file, header.Size)
attach, err := attachment.UploadAttachmentGeneralSizeLimit(ctx, uploaderFile, allowedTypes, &repo_model.Attachment{ attach, err := attachment.UploadAttachmentReleaseSizeLimit(ctx, uploaderFile, allowedTypes, &repo_model.Attachment{
Name: header.Filename, Name: header.Filename,
UploaderID: ctx.Doer.ID, UploaderID: ctx.Doer.ID,
RepoID: repoID, RepoID: repoID,
@@ -56,7 +56,7 @@ func uploadAttachment(ctx *context.Context, repoID int64, allowedTypes string) {
ctx.HTTPError(http.StatusBadRequest, err.Error()) ctx.HTTPError(http.StatusBadRequest, err.Error())
return return
} }
ctx.ServerError("UploadAttachmentGeneralSizeLimit", err) ctx.ServerError("UploadAttachmentReleaseSizeLimit", err)
return return
} }

View File

@@ -58,6 +58,10 @@ func UploadAttachmentGeneralSizeLimit(ctx context.Context, file *UploaderFile, a
return uploadAttachment(ctx, file, allowedTypes, setting.Attachment.MaxSize<<20, attach) return uploadAttachment(ctx, file, allowedTypes, setting.Attachment.MaxSize<<20, attach)
} }
func UploadAttachmentReleaseSizeLimit(ctx context.Context, file *UploaderFile, allowedTypes string, attach *repo_model.Attachment) (*repo_model.Attachment, error) {
return uploadAttachment(ctx, file, allowedTypes, setting.Repository.Release.FileMaxSize<<20, attach)
}
func uploadAttachment(ctx context.Context, file *UploaderFile, allowedTypes string, maxFileSize int64, attach *repo_model.Attachment) (*repo_model.Attachment, error) { func uploadAttachment(ctx context.Context, file *UploaderFile, allowedTypes string, maxFileSize int64, attach *repo_model.Attachment) (*repo_model.Attachment, error) {
src := file.rd src := file.rd
if file.size < 0 { if file.size < 0 {

View File

@@ -95,8 +95,8 @@ func AddUploadContext(ctx *context.Context, uploadType string) {
ctx.Data["UploadRemoveUrl"] = ctx.Repo.RepoLink + "/releases/attachments/remove" ctx.Data["UploadRemoveUrl"] = ctx.Repo.RepoLink + "/releases/attachments/remove"
ctx.Data["UploadLinkUrl"] = ctx.Repo.RepoLink + "/releases/attachments" ctx.Data["UploadLinkUrl"] = ctx.Repo.RepoLink + "/releases/attachments"
ctx.Data["UploadAccepts"] = strings.ReplaceAll(setting.Repository.Release.AllowedTypes, "|", ",") ctx.Data["UploadAccepts"] = strings.ReplaceAll(setting.Repository.Release.AllowedTypes, "|", ",")
ctx.Data["UploadMaxFiles"] = setting.Attachment.MaxFiles ctx.Data["UploadMaxFiles"] = setting.Repository.Release.MaxFiles
ctx.Data["UploadMaxSize"] = setting.Attachment.MaxSize ctx.Data["UploadMaxSize"] = setting.Repository.Release.FileMaxSize
case "comment": case "comment":
ctx.Data["UploadUrl"] = ctx.Repo.RepoLink + "/issues/attachments" ctx.Data["UploadUrl"] = ctx.Repo.RepoLink + "/issues/attachments"
ctx.Data["UploadRemoveUrl"] = ctx.Repo.RepoLink + "/issues/attachments/remove" ctx.Data["UploadRemoveUrl"] = ctx.Repo.RepoLink + "/issues/attachments/remove"

View File

@@ -335,7 +335,7 @@ func TestAPIDeleteReleaseByTagName(t *testing.T) {
func TestAPIUploadAssetRelease(t *testing.T) { func TestAPIUploadAssetRelease(t *testing.T) {
defer tests.PrepareTestEnv(t)() defer tests.PrepareTestEnv(t)()
defer test.MockVariableValue(&setting.Attachment.MaxSize, 1)() defer test.MockVariableValue(&setting.Repository.Release.FileMaxSize, 1)()
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})