api_configs.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. // Copyright (C) 2019 Nicola Murino
  2. //
  3. // This program is free software: you can redistribute it and/or modify
  4. // it under the terms of the GNU Affero General Public License as published
  5. // by the Free Software Foundation, version 3.
  6. //
  7. // This program is distributed in the hope that it will be useful,
  8. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. // GNU Affero General Public License for more details.
  11. //
  12. // You should have received a copy of the GNU Affero General Public License
  13. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. package httpd
  15. import (
  16. "net/http"
  17. "github.com/go-chi/render"
  18. "github.com/rs/xid"
  19. "golang.org/x/oauth2"
  20. "github.com/drakkan/sftpgo/v2/internal/dataprovider"
  21. "github.com/drakkan/sftpgo/v2/internal/kms"
  22. "github.com/drakkan/sftpgo/v2/internal/logger"
  23. "github.com/drakkan/sftpgo/v2/internal/smtp"
  24. "github.com/drakkan/sftpgo/v2/internal/util"
  25. )
  26. type smtpTestRequest struct {
  27. smtp.Config
  28. Recipient string `json:"recipient"`
  29. }
  30. func (r *smtpTestRequest) hasRedactedSecret() bool {
  31. return r.Password == redactedSecret || r.OAuth2.ClientSecret == redactedSecret || r.OAuth2.RefreshToken == redactedSecret
  32. }
  33. func testSMTPConfig(w http.ResponseWriter, r *http.Request) {
  34. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  35. var req smtpTestRequest
  36. err := render.DecodeJSON(r.Body, &req)
  37. if err != nil {
  38. sendAPIResponse(w, r, err, "", http.StatusBadRequest)
  39. return
  40. }
  41. if req.hasRedactedSecret() {
  42. configs, err := dataprovider.GetConfigs()
  43. if err != nil {
  44. sendAPIResponse(w, r, err, "", http.StatusInternalServerError)
  45. return
  46. }
  47. configs.SetNilsToEmpty()
  48. if err := configs.SMTP.TryDecrypt(); err == nil {
  49. if req.Password == redactedSecret {
  50. req.Password = configs.SMTP.Password.GetPayload()
  51. }
  52. if req.OAuth2.ClientSecret == redactedSecret {
  53. req.OAuth2.ClientSecret = configs.SMTP.OAuth2.ClientSecret.GetPayload()
  54. }
  55. if req.OAuth2.RefreshToken == redactedSecret {
  56. req.OAuth2.RefreshToken = configs.SMTP.OAuth2.RefreshToken.GetPayload()
  57. }
  58. }
  59. }
  60. if req.AuthType == 3 {
  61. if err := req.Config.OAuth2.Validate(); err != nil {
  62. sendAPIResponse(w, r, err, "", http.StatusBadRequest)
  63. return
  64. }
  65. }
  66. if err := req.SendEmail([]string{req.Recipient}, nil, "SFTPGo - Testing Email Settings",
  67. "It appears your SFTPGo email is setup correctly!", smtp.EmailContentTypeTextPlain); err != nil {
  68. logger.Info(logSender, "", "unable to send test email: %v", err)
  69. sendAPIResponse(w, r, err, "", http.StatusInternalServerError)
  70. return
  71. }
  72. sendAPIResponse(w, r, nil, "SMTP connection OK", http.StatusOK)
  73. }
  74. type oauth2TokenRequest struct {
  75. smtp.OAuth2Config
  76. BaseRedirectURL string `json:"base_redirect_url"`
  77. }
  78. func handleSMTPOAuth2TokenRequestPost(w http.ResponseWriter, r *http.Request) {
  79. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  80. var req oauth2TokenRequest
  81. err := render.DecodeJSON(r.Body, &req)
  82. if err != nil {
  83. sendAPIResponse(w, r, err, "", http.StatusBadRequest)
  84. return
  85. }
  86. if req.BaseRedirectURL == "" {
  87. sendAPIResponse(w, r, nil, "base redirect url is required", http.StatusBadRequest)
  88. return
  89. }
  90. if req.ClientSecret == redactedSecret {
  91. configs, err := dataprovider.GetConfigs()
  92. if err != nil {
  93. sendAPIResponse(w, r, err, "", http.StatusInternalServerError)
  94. return
  95. }
  96. configs.SetNilsToEmpty()
  97. if err := configs.SMTP.TryDecrypt(); err == nil {
  98. req.OAuth2Config.ClientSecret = configs.SMTP.OAuth2.ClientSecret.GetPayload()
  99. }
  100. }
  101. cfg := req.OAuth2Config.GetOAuth2()
  102. cfg.RedirectURL = req.BaseRedirectURL + webOAuth2RedirectPath
  103. clientSecret := kms.NewPlainSecret(cfg.ClientSecret)
  104. clientSecret.SetAdditionalData(xid.New().String())
  105. pendingAuth := newOAuth2PendingAuth(req.Provider, cfg.RedirectURL, cfg.ClientID, clientSecret)
  106. oauth2Mgr.addPendingAuth(pendingAuth)
  107. stateToken := createOAuth2Token(pendingAuth.State, util.GetIPFromRemoteAddress(r.RemoteAddr))
  108. if stateToken == "" {
  109. sendAPIResponse(w, r, nil, "unable to create state token", http.StatusInternalServerError)
  110. return
  111. }
  112. u := cfg.AuthCodeURL(stateToken, oauth2.AccessTypeOffline)
  113. sendAPIResponse(w, r, nil, u, http.StatusOK)
  114. }