A clean, Markdown-based publishing platform made for writers. Write together, and build a community. https://writefreely.org
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.
 
 
 
 
 

116 lines
2.9 KiB

  1. package writefreely
  2. import (
  3. "context"
  4. "errors"
  5. "net/http"
  6. "net/url"
  7. "strings"
  8. )
  9. type gitlabOauthClient struct {
  10. ClientID string
  11. ClientSecret string
  12. AuthLocation string
  13. ExchangeLocation string
  14. InspectLocation string
  15. CallbackLocation string
  16. HttpClient HttpClient
  17. }
  18. var _ oauthClient = gitlabOauthClient{}
  19. const (
  20. gitlabHost = "https://gitlab.com"
  21. gitlabDisplayName = "GitLab"
  22. )
  23. func (c gitlabOauthClient) GetProvider() string {
  24. return "gitlab"
  25. }
  26. func (c gitlabOauthClient) GetClientID() string {
  27. return c.ClientID
  28. }
  29. func (c gitlabOauthClient) GetCallbackLocation() string {
  30. return c.CallbackLocation
  31. }
  32. func (c gitlabOauthClient) buildLoginURL(state string) (string, error) {
  33. u, err := url.Parse(c.AuthLocation)
  34. if err != nil {
  35. return "", err
  36. }
  37. q := u.Query()
  38. q.Set("client_id", c.ClientID)
  39. q.Set("redirect_uri", c.CallbackLocation)
  40. q.Set("response_type", "code")
  41. q.Set("state", state)
  42. q.Set("scope", "read_user")
  43. u.RawQuery = q.Encode()
  44. return u.String(), nil
  45. }
  46. func (c gitlabOauthClient) exchangeOauthCode(ctx context.Context, code string) (*TokenResponse, error) {
  47. form := url.Values{}
  48. form.Add("grant_type", "authorization_code")
  49. form.Add("redirect_uri", c.CallbackLocation)
  50. form.Add("scope", "read_user")
  51. form.Add("code", code)
  52. req, err := http.NewRequest("POST", c.ExchangeLocation, strings.NewReader(form.Encode()))
  53. if err != nil {
  54. return nil, err
  55. }
  56. req.WithContext(ctx)
  57. req.Header.Set("User-Agent", ServerUserAgent(""))
  58. req.Header.Set("Accept", "application/json")
  59. req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
  60. req.SetBasicAuth(c.ClientID, c.ClientSecret)
  61. resp, err := c.HttpClient.Do(req)
  62. if err != nil {
  63. return nil, err
  64. }
  65. if resp.StatusCode != http.StatusOK {
  66. return nil, errors.New("unable to exchange code for access token")
  67. }
  68. var tokenResponse TokenResponse
  69. if err := limitedJsonUnmarshal(resp.Body, tokenRequestMaxLen, &tokenResponse); err != nil {
  70. return nil, err
  71. }
  72. if tokenResponse.Error != "" {
  73. return nil, errors.New(tokenResponse.Error)
  74. }
  75. return &tokenResponse, nil
  76. }
  77. func (c gitlabOauthClient) inspectOauthAccessToken(ctx context.Context, accessToken string) (*InspectResponse, error) {
  78. req, err := http.NewRequest("GET", c.InspectLocation, nil)
  79. if err != nil {
  80. return nil, err
  81. }
  82. req.WithContext(ctx)
  83. req.Header.Set("User-Agent", ServerUserAgent(""))
  84. req.Header.Set("Accept", "application/json")
  85. req.Header.Set("Authorization", "Bearer "+accessToken)
  86. resp, err := c.HttpClient.Do(req)
  87. if err != nil {
  88. return nil, err
  89. }
  90. if resp.StatusCode != http.StatusOK {
  91. return nil, errors.New("unable to inspect access token")
  92. }
  93. var inspectResponse InspectResponse
  94. if err := limitedJsonUnmarshal(resp.Body, infoRequestMaxLen, &inspectResponse); err != nil {
  95. return nil, err
  96. }
  97. if inspectResponse.Error != "" {
  98. return nil, errors.New(inspectResponse.Error)
  99. }
  100. return &inspectResponse, nil
  101. }