A clean, Markdown-based publishing platform made for writers. Write together, and build a community. https://writefreely.org
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
 
 
 
 
 

134 rader
3.8 KiB

  1. package writefreely
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "github.com/writeas/web-core/log"
  7. "net/http"
  8. "net/url"
  9. "strings"
  10. )
  11. type giteaOauthClient struct {
  12. ClientID string
  13. ClientSecret string
  14. AuthLocation string
  15. ExchangeLocation string
  16. InspectLocation string
  17. CallbackLocation string
  18. Scope string
  19. MapUserID string
  20. MapUsername string
  21. MapDisplayName string
  22. MapEmail string
  23. HttpClient HttpClient
  24. }
  25. var _ oauthClient = giteaOauthClient{}
  26. const (
  27. giteaDisplayName = "Gitea"
  28. )
  29. func (c giteaOauthClient) GetProvider() string {
  30. return "gitea"
  31. }
  32. func (c giteaOauthClient) GetClientID() string {
  33. return c.ClientID
  34. }
  35. func (c giteaOauthClient) GetCallbackLocation() string {
  36. return c.CallbackLocation
  37. }
  38. func (c giteaOauthClient) buildLoginURL(state string) (string, error) {
  39. u, err := url.Parse(c.AuthLocation)
  40. if err != nil {
  41. return "", err
  42. }
  43. q := u.Query()
  44. q.Set("client_id", c.ClientID)
  45. q.Set("redirect_uri", c.CallbackLocation)
  46. q.Set("response_type", "code")
  47. q.Set("state", state)
  48. q.Set("scope", c.Scope)
  49. u.RawQuery = q.Encode()
  50. return u.String(), nil
  51. }
  52. func (c giteaOauthClient) exchangeOauthCode(ctx context.Context, code string) (*TokenResponse, error) {
  53. form := url.Values{}
  54. form.Add("grant_type", "authorization_code")
  55. form.Add("redirect_uri", c.CallbackLocation)
  56. form.Add("scope", c.Scope)
  57. form.Add("code", code)
  58. req, err := http.NewRequest("POST", c.ExchangeLocation, strings.NewReader(form.Encode()))
  59. if err != nil {
  60. return nil, err
  61. }
  62. req.WithContext(ctx)
  63. req.Header.Set("User-Agent", ServerUserAgent(""))
  64. req.Header.Set("Accept", "application/json")
  65. req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
  66. req.SetBasicAuth(c.ClientID, c.ClientSecret)
  67. resp, err := c.HttpClient.Do(req)
  68. if err != nil {
  69. return nil, err
  70. }
  71. if resp.StatusCode != http.StatusOK {
  72. return nil, errors.New("unable to exchange code for access token")
  73. }
  74. var tokenResponse TokenResponse
  75. if err := limitedJsonUnmarshal(resp.Body, tokenRequestMaxLen, &tokenResponse); err != nil {
  76. return nil, err
  77. }
  78. if tokenResponse.Error != "" {
  79. return nil, errors.New(tokenResponse.Error)
  80. }
  81. return &tokenResponse, nil
  82. }
  83. func (c giteaOauthClient) inspectOauthAccessToken(ctx context.Context, accessToken string) (*InspectResponse, error) {
  84. req, err := http.NewRequest("GET", c.InspectLocation, nil)
  85. if err != nil {
  86. return nil, err
  87. }
  88. req.WithContext(ctx)
  89. req.Header.Set("User-Agent", ServerUserAgent(""))
  90. req.Header.Set("Accept", "application/json")
  91. req.Header.Set("Authorization", "Bearer "+accessToken)
  92. resp, err := c.HttpClient.Do(req)
  93. if err != nil {
  94. return nil, err
  95. }
  96. if resp.StatusCode != http.StatusOK {
  97. return nil, errors.New("unable to inspect access token")
  98. }
  99. // since we don't know what the JSON from the server will look like, we create a
  100. // generic interface and then map manually to values set in the config
  101. var genericInterface map[string]interface{}
  102. if err := limitedJsonUnmarshal(resp.Body, infoRequestMaxLen, &genericInterface); err != nil {
  103. return nil, err
  104. }
  105. // map each relevant field in inspectResponse to the mapped field from the config
  106. var inspectResponse InspectResponse
  107. inspectResponse.UserID, _ = genericInterface[c.MapUserID].(string)
  108. // log.Info("Userid from Gitea: %s", inspectResponse.UserID)
  109. if inspectResponse.UserID == "" {
  110. log.Error("[CONFIGURATION ERROR] Gitea OAuth provider returned empty UserID value (`%s`).\n Do you need to configure a different `map_user_id` value for this provider?", c.MapUserID)
  111. return nil, fmt.Errorf("no UserID (`%s`) value returned", c.MapUserID)
  112. }
  113. inspectResponse.Username, _ = genericInterface[c.MapUsername].(string)
  114. inspectResponse.DisplayName, _ = genericInterface[c.MapDisplayName].(string)
  115. inspectResponse.Email, _ = genericInterface[c.MapEmail].(string)
  116. return &inspectResponse, nil
  117. }