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.6KB

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