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  }