email_verify.go 2.8 KB

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