gitea源码

external_login_user.go 6.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. // Copyright 2017 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package user
  4. import (
  5. "context"
  6. "fmt"
  7. "time"
  8. "code.gitea.io/gitea/models/db"
  9. "code.gitea.io/gitea/modules/util"
  10. "xorm.io/builder"
  11. )
  12. // ErrExternalLoginUserAlreadyExist represents a "ExternalLoginUserAlreadyExist" kind of error.
  13. type ErrExternalLoginUserAlreadyExist struct {
  14. ExternalID string
  15. UserID int64
  16. LoginSourceID int64
  17. }
  18. // IsErrExternalLoginUserAlreadyExist checks if an error is a ExternalLoginUserAlreadyExist.
  19. func IsErrExternalLoginUserAlreadyExist(err error) bool {
  20. _, ok := err.(ErrExternalLoginUserAlreadyExist)
  21. return ok
  22. }
  23. func (err ErrExternalLoginUserAlreadyExist) Error() string {
  24. return fmt.Sprintf("external login user already exists [externalID: %s, userID: %d, loginSourceID: %d]", err.ExternalID, err.UserID, err.LoginSourceID)
  25. }
  26. func (err ErrExternalLoginUserAlreadyExist) Unwrap() error {
  27. return util.ErrAlreadyExist
  28. }
  29. // ErrExternalLoginUserNotExist represents a "ExternalLoginUserNotExist" kind of error.
  30. type ErrExternalLoginUserNotExist struct {
  31. UserID int64
  32. LoginSourceID int64
  33. }
  34. // IsErrExternalLoginUserNotExist checks if an error is a ExternalLoginUserNotExist.
  35. func IsErrExternalLoginUserNotExist(err error) bool {
  36. _, ok := err.(ErrExternalLoginUserNotExist)
  37. return ok
  38. }
  39. func (err ErrExternalLoginUserNotExist) Error() string {
  40. return fmt.Sprintf("external login user link does not exists [userID: %d, loginSourceID: %d]", err.UserID, err.LoginSourceID)
  41. }
  42. func (err ErrExternalLoginUserNotExist) Unwrap() error {
  43. return util.ErrNotExist
  44. }
  45. // ExternalLoginUser makes the connecting between some existing user and additional external login sources
  46. type ExternalLoginUser struct {
  47. ExternalID string `xorm:"pk NOT NULL"`
  48. UserID int64 `xorm:"INDEX NOT NULL"`
  49. LoginSourceID int64 `xorm:"pk NOT NULL"`
  50. RawData map[string]any `xorm:"TEXT JSON"`
  51. Provider string `xorm:"index VARCHAR(25)"`
  52. Email string
  53. Name string
  54. FirstName string
  55. LastName string
  56. NickName string
  57. Description string
  58. AvatarURL string `xorm:"TEXT"`
  59. Location string
  60. AccessToken string `xorm:"TEXT"`
  61. AccessTokenSecret string `xorm:"TEXT"`
  62. RefreshToken string `xorm:"TEXT"`
  63. ExpiresAt time.Time
  64. }
  65. type ExternalUserMigrated interface {
  66. GetExternalName() string
  67. GetExternalID() int64
  68. }
  69. type ExternalUserRemappable interface {
  70. GetUserID() int64
  71. RemapExternalUser(externalName string, externalID, userID int64) error
  72. ExternalUserMigrated
  73. }
  74. func init() {
  75. db.RegisterModel(new(ExternalLoginUser))
  76. }
  77. // GetExternalLogin checks if a externalID in loginSourceID scope already exists
  78. func GetExternalLogin(ctx context.Context, externalLoginUser *ExternalLoginUser) (bool, error) {
  79. return db.GetEngine(ctx).Get(externalLoginUser)
  80. }
  81. // LinkExternalToUser link the external user to the user
  82. func LinkExternalToUser(ctx context.Context, user *User, externalLoginUser *ExternalLoginUser) error {
  83. has, err := db.Exist[ExternalLoginUser](ctx, builder.Eq{
  84. "external_id": externalLoginUser.ExternalID,
  85. "login_source_id": externalLoginUser.LoginSourceID,
  86. })
  87. if err != nil {
  88. return err
  89. } else if has {
  90. return ErrExternalLoginUserAlreadyExist{externalLoginUser.ExternalID, user.ID, externalLoginUser.LoginSourceID}
  91. }
  92. _, err = db.GetEngine(ctx).Insert(externalLoginUser)
  93. return err
  94. }
  95. // RemoveAccountLink will remove all external login sources for the given user
  96. func RemoveAccountLink(ctx context.Context, user *User, loginSourceID int64) (int64, error) {
  97. deleted, err := db.GetEngine(ctx).Delete(&ExternalLoginUser{UserID: user.ID, LoginSourceID: loginSourceID})
  98. if err != nil {
  99. return deleted, err
  100. }
  101. if deleted < 1 {
  102. return deleted, ErrExternalLoginUserNotExist{user.ID, loginSourceID}
  103. }
  104. return deleted, err
  105. }
  106. // RemoveAllAccountLinks will remove all external login sources for the given user
  107. func RemoveAllAccountLinks(ctx context.Context, user *User) error {
  108. _, err := db.GetEngine(ctx).Delete(&ExternalLoginUser{UserID: user.ID})
  109. return err
  110. }
  111. // GetUserIDByExternalUserID get user id according to provider and userID
  112. func GetUserIDByExternalUserID(ctx context.Context, provider, userID string) (int64, error) {
  113. var id int64
  114. _, err := db.GetEngine(ctx).Table("external_login_user").
  115. Select("user_id").
  116. Where("provider=?", provider).
  117. And("external_id=?", userID).
  118. Get(&id)
  119. if err != nil {
  120. return 0, err
  121. }
  122. return id, nil
  123. }
  124. // UpdateExternalUserByExternalID updates an external user's information
  125. func UpdateExternalUserByExternalID(ctx context.Context, external *ExternalLoginUser) error {
  126. has, err := db.Exist[ExternalLoginUser](ctx, builder.Eq{
  127. "external_id": external.ExternalID,
  128. "login_source_id": external.LoginSourceID,
  129. })
  130. if err != nil {
  131. return err
  132. } else if !has {
  133. return ErrExternalLoginUserNotExist{external.UserID, external.LoginSourceID}
  134. }
  135. _, err = db.GetEngine(ctx).Where("external_id=? AND login_source_id=?", external.ExternalID, external.LoginSourceID).AllCols().Update(external)
  136. return err
  137. }
  138. // EnsureLinkExternalToUser link the external user to the user
  139. func EnsureLinkExternalToUser(ctx context.Context, external *ExternalLoginUser) error {
  140. has, err := db.Exist[ExternalLoginUser](ctx, builder.Eq{
  141. "external_id": external.ExternalID,
  142. "login_source_id": external.LoginSourceID,
  143. })
  144. if err != nil {
  145. return err
  146. }
  147. if has {
  148. _, err = db.GetEngine(ctx).Where("external_id=? AND login_source_id=?", external.ExternalID, external.LoginSourceID).AllCols().Update(external)
  149. return err
  150. }
  151. _, err = db.GetEngine(ctx).Insert(external)
  152. return err
  153. }
  154. // FindExternalUserOptions represents an options to find external users
  155. type FindExternalUserOptions struct {
  156. db.ListOptions
  157. Provider string
  158. UserID int64
  159. LoginSourceID int64
  160. HasRefreshToken bool
  161. Expired bool
  162. OrderBy string
  163. }
  164. func (opts FindExternalUserOptions) ToConds() builder.Cond {
  165. cond := builder.NewCond()
  166. if len(opts.Provider) > 0 {
  167. cond = cond.And(builder.Eq{"provider": opts.Provider})
  168. }
  169. if opts.UserID > 0 {
  170. cond = cond.And(builder.Eq{"user_id": opts.UserID})
  171. }
  172. if opts.Expired {
  173. cond = cond.And(builder.Lt{"expires_at": time.Now()})
  174. }
  175. if opts.HasRefreshToken {
  176. cond = cond.And(builder.Neq{"refresh_token": ""})
  177. }
  178. if opts.LoginSourceID != 0 {
  179. cond = cond.And(builder.Eq{"login_source_id": opts.LoginSourceID})
  180. }
  181. return cond
  182. }
  183. func (opts FindExternalUserOptions) ToOrders() string {
  184. return opts.OrderBy
  185. }
  186. func IterateExternalLogin(ctx context.Context, opts FindExternalUserOptions, f func(ctx context.Context, u *ExternalLoginUser) error) error {
  187. return db.Iterate(ctx, opts.ToConds(), f)
  188. }