You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

common.go 2.8KB

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