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.

protected_tag.go 3.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. // Copyright 2021 The Gitea Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package models
  5. import (
  6. "regexp"
  7. "strings"
  8. "code.gitea.io/gitea/modules/base"
  9. "code.gitea.io/gitea/modules/timeutil"
  10. "github.com/gobwas/glob"
  11. )
  12. // ProtectedTag struct
  13. type ProtectedTag struct {
  14. ID int64 `xorm:"pk autoincr"`
  15. RepoID int64
  16. NamePattern string
  17. RegexPattern *regexp.Regexp `xorm:"-"`
  18. GlobPattern glob.Glob `xorm:"-"`
  19. AllowlistUserIDs []int64 `xorm:"JSON TEXT"`
  20. AllowlistTeamIDs []int64 `xorm:"JSON TEXT"`
  21. CreatedUnix timeutil.TimeStamp `xorm:"created"`
  22. UpdatedUnix timeutil.TimeStamp `xorm:"updated"`
  23. }
  24. // InsertProtectedTag inserts a protected tag to database
  25. func InsertProtectedTag(pt *ProtectedTag) error {
  26. _, err := x.Insert(pt)
  27. return err
  28. }
  29. // UpdateProtectedTag updates the protected tag
  30. func UpdateProtectedTag(pt *ProtectedTag) error {
  31. _, err := x.ID(pt.ID).AllCols().Update(pt)
  32. return err
  33. }
  34. // DeleteProtectedTag deletes a protected tag by ID
  35. func DeleteProtectedTag(pt *ProtectedTag) error {
  36. _, err := x.ID(pt.ID).Delete(&ProtectedTag{})
  37. return err
  38. }
  39. // EnsureCompiledPattern ensures the glob pattern is compiled
  40. func (pt *ProtectedTag) EnsureCompiledPattern() error {
  41. if pt.RegexPattern != nil || pt.GlobPattern != nil {
  42. return nil
  43. }
  44. var err error
  45. if len(pt.NamePattern) >= 2 && strings.HasPrefix(pt.NamePattern, "/") && strings.HasSuffix(pt.NamePattern, "/") {
  46. pt.RegexPattern, err = regexp.Compile(pt.NamePattern[1 : len(pt.NamePattern)-1])
  47. } else {
  48. pt.GlobPattern, err = glob.Compile(pt.NamePattern)
  49. }
  50. return err
  51. }
  52. // IsUserAllowed returns true if the user is allowed to modify the tag
  53. func (pt *ProtectedTag) IsUserAllowed(userID int64) (bool, error) {
  54. if base.Int64sContains(pt.AllowlistUserIDs, userID) {
  55. return true, nil
  56. }
  57. if len(pt.AllowlistTeamIDs) == 0 {
  58. return false, nil
  59. }
  60. in, err := IsUserInTeams(userID, pt.AllowlistTeamIDs)
  61. if err != nil {
  62. return false, err
  63. }
  64. return in, nil
  65. }
  66. // GetProtectedTags gets all protected tags of the repository
  67. func (repo *Repository) GetProtectedTags() ([]*ProtectedTag, error) {
  68. tags := make([]*ProtectedTag, 0)
  69. return tags, x.Find(&tags, &ProtectedTag{RepoID: repo.ID})
  70. }
  71. // GetProtectedTagByID gets the protected tag with the specific id
  72. func GetProtectedTagByID(id int64) (*ProtectedTag, error) {
  73. tag := new(ProtectedTag)
  74. has, err := x.ID(id).Get(tag)
  75. if err != nil {
  76. return nil, err
  77. }
  78. if !has {
  79. return nil, nil
  80. }
  81. return tag, nil
  82. }
  83. // IsUserAllowedToControlTag checks if a user can control the specific tag.
  84. // It returns true if the tag name is not protected or the user is allowed to control it.
  85. func IsUserAllowedToControlTag(tags []*ProtectedTag, tagName string, userID int64) (bool, error) {
  86. isAllowed := true
  87. for _, tag := range tags {
  88. err := tag.EnsureCompiledPattern()
  89. if err != nil {
  90. return false, err
  91. }
  92. if !tag.matchString(tagName) {
  93. continue
  94. }
  95. isAllowed, err = tag.IsUserAllowed(userID)
  96. if err != nil {
  97. return false, err
  98. }
  99. if isAllowed {
  100. break
  101. }
  102. }
  103. return isAllowed, nil
  104. }
  105. func (pt *ProtectedTag) matchString(name string) bool {
  106. if pt.RegexPattern != nil {
  107. return pt.RegexPattern.MatchString(name)
  108. }
  109. return pt.GlobPattern.Match(name)
  110. }