1
0

general_protocol.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. // Copyright 2019 The Gogs 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 srcgraph
  5. import (
  6. "net/http"
  7. "time"
  8. "github.com/Unknwon/com"
  9. adapter "github.com/sourcegraph/external-service-adapter"
  10. log "gopkg.in/clog.v1"
  11. "github.com/gogs/gogs/models"
  12. "github.com/gogs/gogs/models/errors"
  13. "github.com/gogs/gogs/pkg/setting"
  14. )
  15. func NewHandler() http.HandlerFunc {
  16. h := adapter.NewHandler(externalServicer{}, adapter.Options{
  17. URL: setting.AppURL,
  18. PathPrefix: "/-/srcgraph",
  19. MaxPageLen: 100000, // Current version returns all repositories at once, does not matter
  20. })
  21. return h.ServeHTTP
  22. }
  23. type externalServicer struct{}
  24. func (es externalServicer) ListRepos(ai adapter.AuthInfo, params adapter.Params) ([]*adapter.Repo, adapter.Page, error) {
  25. return es.listUserRepos("", ai, params)
  26. }
  27. func (es externalServicer) ListUserRepos(user string, ai adapter.AuthInfo, params adapter.Params) ([]*adapter.Repo, adapter.Page, error) {
  28. return es.listUserRepos(user, ai, params)
  29. }
  30. func toRepo(r *models.Repository) *adapter.Repo {
  31. var parent *adapter.Repo
  32. if r.IsFork {
  33. parent = toRepo(r.BaseRepo)
  34. }
  35. cl := r.CloneLink()
  36. return &adapter.Repo{
  37. ID: com.ToStr(r.ID),
  38. Name: r.Name,
  39. Slug: r.Name,
  40. FullName: r.FullName(),
  41. SCM: "git",
  42. Description: r.Description,
  43. IsPrivate: r.IsPrivate,
  44. Parent: parent,
  45. Links: []adapter.Link{
  46. {adapter.CloneSSH, cl.SSH},
  47. {adapter.CloneHTTP, cl.HTTPS},
  48. },
  49. }
  50. }
  51. func (es externalServicer) listUserRepos(username string, ai adapter.AuthInfo, params adapter.Params) ([]*adapter.Repo, adapter.Page, error) {
  52. authUser, err := userFromAuthInfo(ai)
  53. if err != nil {
  54. if errors.IsUserNotExist(err) {
  55. return nil, adapter.Page{}, errors.New("403 Forbidden")
  56. }
  57. log.Error(2, "Failed to get user from auth info: %v", err)
  58. return nil, adapter.Page{}, errors.New("500 Internal Server Error")
  59. }
  60. // Fall back to authenticated user
  61. if username == "" {
  62. username = authUser.Name
  63. }
  64. user, err := models.GetUserByName(username)
  65. if err != nil {
  66. if errors.IsUserNotExist(err) {
  67. return nil, adapter.Page{}, errors.New("404 Not Found")
  68. }
  69. log.Error(2, "Failed to get user by username %q: %v", username, err)
  70. return nil, adapter.Page{}, errors.New("500 Internal Server Error")
  71. }
  72. // Only list public repositories if user requests someone else's repository list,
  73. // or an organization isn't a member of.
  74. var ownRepos []*models.Repository
  75. if user.IsOrganization() {
  76. ownRepos, _, err = user.GetUserRepositories(authUser.ID, params.Page, user.NumRepos)
  77. } else {
  78. ownRepos, err = models.GetUserRepositories(&models.UserRepoOptions{
  79. UserID: user.ID,
  80. Private: authUser.ID == user.ID,
  81. Page: params.Page,
  82. PageSize: user.NumRepos,
  83. })
  84. }
  85. if err != nil {
  86. log.Error(2, "Failed to get repositories of user %q: %v", username, err)
  87. return nil, adapter.Page{}, errors.New("500 Internal Server Error")
  88. }
  89. if err = models.RepositoryList(ownRepos).LoadAttributes(); err != nil {
  90. log.Error(2, "Failed to load attributes of repositories: %v", err)
  91. return nil, adapter.Page{}, errors.New("500 Internal Server Error")
  92. }
  93. // Early return for querying other user's repositories
  94. if authUser.ID != user.ID {
  95. repos := make([]*adapter.Repo, len(ownRepos))
  96. for i := range ownRepos {
  97. repos[i] = toRepo(ownRepos[i])
  98. }
  99. return repos, adapter.Page{Last: 1}, nil
  100. }
  101. accessibleRepos, err := user.GetRepositoryAccesses()
  102. if err != nil {
  103. log.Error(2, "Failed to get accessible repositories of user %q: %v", username, err)
  104. return nil, adapter.Page{}, errors.New("500 Internal Server Error")
  105. }
  106. numOwnRepos := len(ownRepos)
  107. repos := make([]*adapter.Repo, numOwnRepos+len(accessibleRepos))
  108. for i := range ownRepos {
  109. repos[i] = toRepo(ownRepos[i])
  110. }
  111. i := numOwnRepos
  112. for repo := range accessibleRepos {
  113. repos[i] = toRepo(repo)
  114. i++
  115. }
  116. return repos, adapter.Page{Last: 1}, nil
  117. }
  118. func userFromAuthInfo(ai adapter.AuthInfo) (*models.User, error) {
  119. if ai.Method == adapter.AuthBasic {
  120. u, err := models.UserLogin(ai.Username, ai.Password, -1)
  121. if err != nil {
  122. return nil, err
  123. }
  124. if u.IsEnabledTwoFactor() {
  125. return nil, errors.New(
  126. "User with two-factor authentication enabled cannot perform HTTP/HTTPS operations via plain username and password." +
  127. " Please create and use personal access token on user settings page.")
  128. }
  129. return u, nil
  130. }
  131. t, err := models.GetAccessTokenBySHA(ai.Token)
  132. if err != nil {
  133. if models.IsErrAccessTokenEmpty(err) || models.IsErrAccessTokenNotExist(err) {
  134. return nil, errors.UserNotExist{}
  135. }
  136. return nil, err
  137. }
  138. t.Updated = time.Now()
  139. u, err := models.GetUserByID(t.UID)
  140. if err != nil {
  141. return nil, err
  142. }
  143. return u, models.UpdateAccessToken(t)
  144. }