github.com/decred/politeia@v1.4.0/politeiawww/legacy/useremail.go (about)

     1  // Copyright (c) 2017-2020 The Decred developers
     2  // Use of this source code is governed by an ISC
     3  // license that can be found in the LICENSE file.
     4  
     5  package legacy
     6  
     7  import (
     8  	"bytes"
     9  	"net/url"
    10  	"text/template"
    11  
    12  	www "github.com/decred/politeia/politeiawww/api/www/v1"
    13  	"github.com/google/uuid"
    14  )
    15  
    16  const (
    17  	// GUI routes. These are used in notification emails to direct the
    18  	// user to the correct GUI pages.
    19  	guiRouteRegisterNewUser = "/register"
    20  )
    21  
    22  // emailUserEmailVerify sends a new user verification email to the provided
    23  // email address. This function is not rate limited by the smtp client because
    24  // the user is only created/updated when this function is successfully executed
    25  // and an email with the verification token is sent to the user. This email is
    26  // also already limited by the verification token expiry hours policy.
    27  func (p *Politeiawww) emailUserEmailVerify(email, token, username string) error {
    28  	link, err := p.createEmailLink(www.RouteVerifyNewUser, email,
    29  		token, username)
    30  	if err != nil {
    31  		return err
    32  	}
    33  
    34  	tplData := userEmailVerify{
    35  		Username: username,
    36  		Link:     link,
    37  	}
    38  
    39  	subject := "Verify Your Email"
    40  	body, err := createBody(userEmailVerifyTmpl, tplData)
    41  	if err != nil {
    42  		return err
    43  	}
    44  
    45  	return p.mail.SendTo(subject, body, []string{email})
    46  }
    47  
    48  // emailUserKeyUpdate emails the link with the verification token used for
    49  // setting a new key pair if the email server is set up.
    50  func (p *Politeiawww) emailUserKeyUpdate(username, publicKey, token string, recipient map[uuid.UUID]string) error {
    51  	link, err := p.createEmailLink(www.RouteVerifyUpdateUserKey, "", token, "")
    52  	if err != nil {
    53  		return err
    54  	}
    55  
    56  	tplData := userKeyUpdate{
    57  		PublicKey: publicKey,
    58  		Username:  username,
    59  		Link:      link,
    60  	}
    61  
    62  	subject := "Verify Your New Identity"
    63  	body, err := createBody(userKeyUpdateTmpl, tplData)
    64  	if err != nil {
    65  		return err
    66  	}
    67  
    68  	return p.mail.SendToUsers(subject, body, recipient)
    69  }
    70  
    71  // emailUserPasswordReset emails the link with the reset password verification
    72  // token to the provided email address.
    73  func (p *Politeiawww) emailUserPasswordReset(username, token string, recipient map[uuid.UUID]string) error {
    74  	// Setup URL
    75  	u, err := url.Parse(p.cfg.WebServerAddress + www.RouteResetPassword)
    76  	if err != nil {
    77  		return err
    78  	}
    79  	q := u.Query()
    80  	q.Set("verificationtoken", token)
    81  	q.Set("username", username)
    82  	u.RawQuery = q.Encode()
    83  
    84  	// Setup email
    85  	subject := "Reset Your Password"
    86  	tplData := userPasswordReset{
    87  		Link: u.String(),
    88  	}
    89  	body, err := createBody(userPasswordResetTmpl, tplData)
    90  	if err != nil {
    91  		return err
    92  	}
    93  
    94  	// Send email
    95  	return p.mail.SendToUsers(subject, body, recipient)
    96  }
    97  
    98  // emailUserAccountLocked notifies the user its account has been locked and
    99  // emails the link with the reset password verification token if the email
   100  // server is set up.
   101  func (p *Politeiawww) emailUserAccountLocked(username string, recipient map[uuid.UUID]string) error {
   102  	var email string
   103  	for _, e := range recipient {
   104  		email = e
   105  	}
   106  	link, err := p.createEmailLink(ResetPasswordGuiRoute,
   107  		email, "", "")
   108  	if err != nil {
   109  		return err
   110  	}
   111  
   112  	tplData := userAccountLocked{
   113  		Link:     link,
   114  		Username: username,
   115  	}
   116  
   117  	subject := "Locked Account - Reset Your Password"
   118  	body, err := createBody(userAccountLockedTmpl, tplData)
   119  	if err != nil {
   120  		return err
   121  	}
   122  
   123  	return p.mail.SendToUsers(subject, body, recipient)
   124  }
   125  
   126  // emailUserPasswordChanged notifies the user that his password was changed,
   127  // and verifies if he was the author of this action, for security purposes.
   128  func (p *Politeiawww) emailUserPasswordChanged(username string, recipient map[uuid.UUID]string) error {
   129  	tplData := userPasswordChanged{
   130  		Username: username,
   131  	}
   132  
   133  	subject := "Password Changed - Security Notification"
   134  	body, err := createBody(userPasswordChangedTmpl, tplData)
   135  	if err != nil {
   136  		return err
   137  	}
   138  
   139  	return p.mail.SendToUsers(subject, body, recipient)
   140  }
   141  
   142  func (p *Politeiawww) createEmailLink(path, email, token, username string) (string, error) {
   143  	l, err := url.Parse(p.cfg.WebServerAddress + path)
   144  	if err != nil {
   145  		return "", err
   146  	}
   147  
   148  	q := l.Query()
   149  	if email != "" {
   150  		q.Set("email", email)
   151  	}
   152  	if token != "" {
   153  		q.Set("verificationtoken", token)
   154  	}
   155  	if username != "" {
   156  		q.Set("username", username)
   157  	}
   158  	l.RawQuery = q.Encode()
   159  
   160  	return l.String(), nil
   161  }
   162  
   163  func createBody(tpl *template.Template, tplData interface{}) (string, error) {
   164  	var buf bytes.Buffer
   165  	err := tpl.Execute(&buf, tplData)
   166  	if err != nil {
   167  		return "", err
   168  	}
   169  
   170  	return buf.String(), nil
   171  }
   172  
   173  // User email verify - Send verification link to new user
   174  type userEmailVerify struct {
   175  	Username string // User username
   176  	Link     string // Verification link
   177  }
   178  
   179  const userEmailVerifyText = `
   180  Thanks for joining Politeia, {{.Username}}!
   181  
   182  Click the link below to verify your email and complete your registration.
   183  
   184  {{.Link}}
   185  
   186  You are receiving this notification because this email address was used to
   187  register a Politeia account.  If you did not perform this action, please ignore
   188  this email.
   189  `
   190  
   191  var userEmailVerifyTmpl = template.Must(
   192  	template.New("userEmailVerify").Parse(userEmailVerifyText))
   193  
   194  // User key update - Send key verification link to user
   195  type userKeyUpdate struct {
   196  	PublicKey string // User new public key
   197  	Username  string
   198  	Link      string // Verify key link
   199  }
   200  
   201  const userKeyUpdateText = `
   202  Click the link below to verify your new identity:
   203  
   204  {{.Link}}
   205  
   206  You are receiving this notification because a new identity was generated for
   207  {{.Username}} on Politeia with the following public key. 
   208  
   209  Public key: {{.PublicKey}} 
   210  
   211  If you did not perform this action, please contact a Politeia administrators in
   212  the Politeia channel on Matrix.
   213  
   214  https://chat.decred.org/#/room/#politeia:decred.org
   215  `
   216  
   217  var userKeyUpdateTmpl = template.Must(
   218  	template.New("userKeyUpdate").Parse(userKeyUpdateText))
   219  
   220  // User password reset - Send password reset link to user
   221  type userPasswordReset struct {
   222  	Link string // Password reset link
   223  }
   224  
   225  const userPasswordResetText = `
   226  Click the link below to continue resetting your password:
   227  
   228  {{.Link}}
   229  
   230  A password reset was initiated for this Politeia account.  If you did not
   231  perform this action, it's possible that your account has been compromised.
   232  Please contact a Politeia administrator in the Politeia channel on Matrix.
   233  
   234  https://chat.decred.org/#/room/#politeia:decred.org
   235  `
   236  
   237  var userPasswordResetTmpl = template.Must(
   238  	template.New("userPasswordReset").Parse(userPasswordResetText))
   239  
   240  // User account locked - Send reset password link to user
   241  type userAccountLocked struct {
   242  	Link     string // Reset password link
   243  	Username string
   244  }
   245  
   246  const userAccountLockedText = `
   247  The Politeia account for {{.Username}} was locked due to too many login
   248  attempts. You need to reset your password in order to unlock your account:
   249  
   250  {{.Link}}
   251  
   252  If these login attempts were not made by you, please notify a Politeia
   253  administrators in the Politeia channel on Matrix.
   254  
   255  https://chat.decred.org/#/room/#politeia:decred.org
   256  `
   257  
   258  var userAccountLockedTmpl = template.Must(
   259  	template.New("userAccountLocked").Parse(userAccountLockedText))
   260  
   261  // User password changed - Send to user
   262  type userPasswordChanged struct {
   263  	Username string
   264  }
   265  
   266  const userPasswordChangedText = `
   267  The password has been changed for your Politeia account with the username
   268  {{.Username}}. 
   269  
   270  If you did not perform this action, it's possible that your account has been
   271  compromised.  Please contact a Politeia administrator in the Politeia channel
   272  on Matrix.
   273  
   274  https://chat.decred.org/#/room/#politeia:decred.org
   275  `
   276  
   277  var userPasswordChangedTmpl = template.Must(
   278  	template.New("userPasswordChanged").Parse(userPasswordChangedText))