email_verify.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. package user
  2. import (
  3. "fmt"
  4. "net/http"
  5. "net/url"
  6. "github.com/porter-dev/porter/api/server/handlers"
  7. "github.com/porter-dev/porter/api/server/shared"
  8. "github.com/porter-dev/porter/api/server/shared/apierrors"
  9. "github.com/porter-dev/porter/api/server/shared/config"
  10. "github.com/porter-dev/porter/api/types"
  11. "github.com/porter-dev/porter/internal/analytics"
  12. "github.com/porter-dev/porter/internal/models"
  13. "github.com/porter-dev/porter/internal/notifier"
  14. )
  15. type VerifyEmailInitiateHandler struct {
  16. handlers.PorterHandler
  17. }
  18. func NewVerifyEmailInitiateHandler(
  19. config *config.Config,
  20. ) *VerifyEmailInitiateHandler {
  21. return &VerifyEmailInitiateHandler{
  22. PorterHandler: handlers.NewDefaultPorterHandler(config, nil, nil),
  23. }
  24. }
  25. func (v *VerifyEmailInitiateHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  26. user, _ := r.Context().Value(types.UserScope).(*models.User)
  27. err := startEmailVerification(v.Config(), w, r, user)
  28. if err != nil {
  29. v.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  30. }
  31. }
  32. type VerifyEmailFinalizeHandler struct {
  33. handlers.PorterHandlerReader
  34. }
  35. func NewVerifyEmailFinalizeHandler(
  36. config *config.Config,
  37. decoderValidator shared.RequestDecoderValidator,
  38. ) *VerifyEmailFinalizeHandler {
  39. return &VerifyEmailFinalizeHandler{
  40. PorterHandlerReader: handlers.NewDefaultPorterHandler(config, decoderValidator, nil),
  41. }
  42. }
  43. func (v *VerifyEmailFinalizeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  44. user, _ := r.Context().Value(types.UserScope).(*models.User)
  45. request := &types.VerifyEmailFinalizeRequest{}
  46. if err := v.DecodeAndValidateNoWrite(r, request); err != nil {
  47. http.Redirect(w, r, "/dashboard?error="+url.QueryEscape(err.Error()), 302)
  48. return
  49. }
  50. token, err := VerifyToken(
  51. v.Repo().PWResetToken(),
  52. handlers.IgnoreAPIError,
  53. w,
  54. r,
  55. &request.VerifyTokenFinalizeRequest,
  56. user.Email,
  57. )
  58. if err != nil {
  59. http.Redirect(w, r, "/dashboard?error="+url.QueryEscape("Email verification error: valid token required"), 302)
  60. return
  61. }
  62. user.EmailVerified = true
  63. user, err = v.Repo().User().UpdateUser(user)
  64. if err != nil {
  65. http.Redirect(w, r, "/dashboard?error="+url.QueryEscape("Could not verify email address"), 302)
  66. return
  67. }
  68. // invalidate the token
  69. token.IsValid = false
  70. _, err = v.Repo().PWResetToken().UpdatePWResetToken(token)
  71. if err != nil {
  72. http.Redirect(w, r, "/dashboard?error="+url.QueryEscape("Could not verify email address"), 302)
  73. return
  74. }
  75. v.Config().AnalyticsClient.Track(analytics.UserVerifyEmailTrack(&analytics.UserVerifyEmailTrackOpts{
  76. UserScopedTrackOpts: analytics.GetUserScopedTrackOpts(user.ID),
  77. Email: user.Email,
  78. }))
  79. http.Redirect(w, r, "/dashboard", 302)
  80. return
  81. }
  82. func startEmailVerification(
  83. config *config.Config,
  84. w http.ResponseWriter, r *http.Request,
  85. user *models.User,
  86. ) error {
  87. pwReset, rawToken, err := CreatePWResetTokenForEmail(
  88. config.Repo.PWResetToken(),
  89. handlers.IgnoreAPIError,
  90. w,
  91. r,
  92. &types.InitiateResetUserPasswordRequest{
  93. Email: user.Email,
  94. },
  95. )
  96. if err != nil {
  97. return err
  98. }
  99. queryVals := url.Values{
  100. "token": []string{rawToken},
  101. "token_id": []string{fmt.Sprintf("%d", pwReset.ID)},
  102. }
  103. return config.UserNotifier.SendEmailVerification(
  104. &notifier.SendEmailVerificationOpts{
  105. Email: user.Email,
  106. URL: fmt.Sprintf("%s/api/email/verify/finalize?%s", config.ServerConf.ServerURL, queryVals.Encode()),
  107. },
  108. )
  109. }