code.gitea.io/gitea@v1.22.3/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  	// FIXME: hash only a SHA1
    52  	CommitType := git.Sha1ObjectFormat
    53  	if pr.MergeCommitSHA != "" && !CommitType.IsValid(pr.MergeCommitSHA) {
    54  		WarnAndNotice("PR #%d in %s has invalid MergeCommitSHA: %s", pr.Number, g, pr.MergeCommitSHA)
    55  		pr.MergeCommitSHA = ""
    56  	}
    57  	if pr.Head.SHA != "" && !CommitType.IsValid(pr.Head.SHA) {
    58  		WarnAndNotice("PR #%d in %s has invalid HeadSHA: %s", pr.Number, g, pr.Head.SHA)
    59  		pr.Head.SHA = ""
    60  		valid = false
    61  	}
    62  	if pr.Base.SHA != "" && !CommitType.IsValid(pr.Base.SHA) {
    63  		WarnAndNotice("PR #%d in %s has invalid BaseSHA: %s", pr.Number, g, pr.Base.SHA)
    64  		pr.Base.SHA = ""
    65  		valid = false
    66  	}
    67  
    68  	// SECURITY: Refs must be valid refs or SHAs
    69  	if pr.Head.Ref != "" && !git.IsValidRefPattern(pr.Head.Ref) {
    70  		WarnAndNotice("PR #%d in %s has invalid HeadRef: %s", pr.Number, g, pr.Head.Ref)
    71  		pr.Head.Ref = ""
    72  		valid = false
    73  	}
    74  	if pr.Base.Ref != "" && !git.IsValidRefPattern(pr.Base.Ref) {
    75  		WarnAndNotice("PR #%d in %s has invalid BaseRef: %s", pr.Number, g, pr.Base.Ref)
    76  		pr.Base.Ref = ""
    77  		valid = false
    78  	}
    79  
    80  	pr.EnsuredSafe = true
    81  
    82  	return valid
    83  }