code.gitea.io/gitea@v1.21.7/services/migrations/common.go (about) 1 // Copyright 2022 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package migrations 5 6 import ( 7 "fmt" 8 "strings" 9 10 system_model "code.gitea.io/gitea/models/system" 11 "code.gitea.io/gitea/modules/git" 12 "code.gitea.io/gitea/modules/log" 13 base "code.gitea.io/gitea/modules/migration" 14 ) 15 16 // WarnAndNotice will log the provided message and send a repository notice 17 func WarnAndNotice(fmtStr string, args ...any) { 18 log.Warn(fmtStr, args...) 19 if err := system_model.CreateRepositoryNotice(fmt.Sprintf(fmtStr, args...)); err != nil { 20 log.Error("create repository notice failed: ", err) 21 } 22 } 23 24 func hasBaseURL(toCheck, baseURL string) bool { 25 if len(baseURL) > 0 && baseURL[len(baseURL)-1] != '/' { 26 baseURL += "/" 27 } 28 return strings.HasPrefix(toCheck, baseURL) 29 } 30 31 // CheckAndEnsureSafePR will check that a given PR is safe to download 32 func CheckAndEnsureSafePR(pr *base.PullRequest, commonCloneBaseURL string, g base.Downloader) bool { 33 valid := true 34 // SECURITY: the patchURL must be checked to have the same baseURL as the current to prevent open redirect 35 if pr.PatchURL != "" && !hasBaseURL(pr.PatchURL, commonCloneBaseURL) { 36 // TODO: Should we check that this url has the expected format for a patch url? 37 WarnAndNotice("PR #%d in %s has invalid PatchURL: %s baseURL: %s", pr.Number, g, pr.PatchURL, commonCloneBaseURL) 38 pr.PatchURL = "" 39 valid = false 40 } 41 42 // SECURITY: the headCloneURL must be checked to have the same baseURL as the current to prevent open redirect 43 if pr.Head.CloneURL != "" && !hasBaseURL(pr.Head.CloneURL, commonCloneBaseURL) { 44 // TODO: Should we check that this url has the expected format for a patch url? 45 WarnAndNotice("PR #%d in %s has invalid HeadCloneURL: %s baseURL: %s", pr.Number, g, pr.Head.CloneURL, commonCloneBaseURL) 46 pr.Head.CloneURL = "" 47 valid = false 48 } 49 50 // SECURITY: SHAs Must be a SHA 51 if pr.MergeCommitSHA != "" && !git.IsValidSHAPattern(pr.MergeCommitSHA) { 52 WarnAndNotice("PR #%d in %s has invalid MergeCommitSHA: %s", pr.Number, g, pr.MergeCommitSHA) 53 pr.MergeCommitSHA = "" 54 } 55 if pr.Head.SHA != "" && !git.IsValidSHAPattern(pr.Head.SHA) { 56 WarnAndNotice("PR #%d in %s has invalid HeadSHA: %s", pr.Number, g, pr.Head.SHA) 57 pr.Head.SHA = "" 58 valid = false 59 } 60 if pr.Base.SHA != "" && !git.IsValidSHAPattern(pr.Base.SHA) { 61 WarnAndNotice("PR #%d in %s has invalid BaseSHA: %s", pr.Number, g, pr.Base.SHA) 62 pr.Base.SHA = "" 63 valid = false 64 } 65 66 // SECURITY: Refs must be valid refs or SHAs 67 if pr.Head.Ref != "" && !git.IsValidRefPattern(pr.Head.Ref) { 68 WarnAndNotice("PR #%d in %s has invalid HeadRef: %s", pr.Number, g, pr.Head.Ref) 69 pr.Head.Ref = "" 70 valid = false 71 } 72 if pr.Base.Ref != "" && !git.IsValidRefPattern(pr.Base.Ref) { 73 WarnAndNotice("PR #%d in %s has invalid BaseRef: %s", pr.Number, g, pr.Base.Ref) 74 pr.Base.Ref = "" 75 valid = false 76 } 77 78 pr.EnsuredSafe = true 79 80 return valid 81 }