Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

www: Email rate limit #1448

Merged
merged 26 commits into from
Jul 21, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
31c535a
www: email rate limit
thi4go Jul 2, 2021
68967a0
implement limiter SendTo
thi4go Jul 5, 2021
265f0b2
add cdb tests and misc fixes
thi4go Jul 5, 2021
4e3f792
add mysql tests
thi4go Jul 5, 2021
04a3fb8
readability improvements and cleanups
thi4go Jul 6, 2021
e7570ff
nits from self review
thi4go Jul 6, 2021
ef2f6a9
fix mailer interface design & review nits
thi4go Jul 7, 2021
a307273
fix isEnabled and fix tests
thi4go Jul 7, 2021
1ba4048
create MailerDB interface and apply design refactor
thi4go Jul 9, 2021
5814ecd
review: add tests for mailer, use sql transaction, ditch in memory lo…
thi4go Jul 12, 2021
c527bec
fix mysql and cdb tests
thi4go Jul 12, 2021
c7d94b0
remove encode/decode pattern for EmailHistory; add constant for limit…
thi4go Jul 13, 2021
bcb2324
nits from self review; add missing comments to user.Database implemen…
thi4go Jul 13, 2021
2c3a639
merge with master
thi4go Jul 13, 2021
d5361c9
change pk to userid; refactor email handlers to parse correct recipie…
thi4go Jul 16, 2021
f956727
nits from self review: ditch userEmails in memory cache usage; update…
thi4go Jul 16, 2021
ea1a445
typo
thi4go Jul 16, 2021
7a04956
nit
thi4go Jul 16, 2021
782e7be
remove cms bits & address review comments
thi4go Jul 17, 2021
ce17824
mail: Refactor tests.
lukebp Jul 18, 2021
bcf76cb
Docs.
lukebp Jul 18, 2021
4a6c57b
typo
lukebp Jul 18, 2021
7dce859
mail: Refactor client tests from lukebp/1448-refactor
thi4go Jul 19, 2021
867914a
fix tests and review
thi4go Jul 19, 2021
ff7db3d
filterTimestamps tests
thi4go Jul 19, 2021
11ea2fe
skipVerify from config
thi4go Jul 20, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ require (
github.com/go-sql-driver/mysql v1.5.0
github.com/go-test/deep v1.0.1
github.com/golang/protobuf v1.4.3
github.com/google/go-cmp v0.5.4
github.com/google/trillian v1.3.13
github.com/google/uuid v1.1.1
github.com/gorilla/csrf v1.6.2
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,8 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
Expand Down
1 change: 1 addition & 0 deletions politeiawww/cmd/politeiawww_dbutil/politeiawww_dbutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,7 @@ func connectMySQL() (user.Database, error) {
}

fmt.Printf("MySQL : %v %v\n", *mysqlhost, network)

return mysqldb.New(*mysqlhost, *password, network, *encryptionKey)
}

Expand Down
3 changes: 3 additions & 0 deletions politeiawww/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ const (
defaultMySQLDBHost = "localhost:3306" // MySQL default host
defaultCockroachDBHost = "localhost:26257" // CockroachDB default host

defaultMailRateLimit = 100 // Email limit per user

// Environment variables.
envDBPass = "DBPASS"
)
Expand Down Expand Up @@ -337,6 +339,7 @@ func loadConfig() (*config.Config, []string, error) {
MinConfirmationsRequired: defaultPaywallMinConfirmations,
VoteDurationMin: defaultVoteDurationMin,
VoteDurationMax: defaultVoteDurationMax,
MailRateLimit: defaultMailRateLimit,
}

// Service options which are only added on Windows.
Expand Down
1 change: 1 addition & 0 deletions politeiawww/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ type Config struct {
MailAddress string `long:"mailaddress" description:"Email address for outgoing email in the format: name <address>"`
MailCert string `long:"mailcert" description:"Email server certificate file"`
MailSkipVerify bool `long:"mailskipverify" description:"Skip TLS verification when connecting to the mail server"`
MailRateLimit int `long:"mailratelimit" description:"Limits the amount of emails a user can receive in 24h"`
WebServerAddress string `long:"webserveraddress" description:"Web server address used to create email links (format: <scheme>://<host>[:<port>])"`

// XXX These should all be plugin settings
Expand Down
34 changes: 19 additions & 15 deletions politeiawww/email.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"time"

www "github.com/decred/politeia/politeiawww/api/www/v1"
"github.com/google/uuid"
)

const (
Expand Down Expand Up @@ -52,8 +53,11 @@ func (p *politeiawww) createEmailLink(path, email, token, username string) (stri
return l.String(), nil
}

// emailUserEmailVerify sends a new user verification email to the
// provided email address.
// emailUserEmailVerify sends a new user verification email to the provided
// email address. This function is not rate limited by the smtp client because
// the user is only created/updated when this function is successfully executed
// and an email with the verification token is sent to the user. This email is
// also already limited by the verification token expiry hours policy.
func (p *politeiawww) emailUserEmailVerify(email, token, username string) error {
link, err := p.createEmailLink(www.RouteVerifyNewUser, email,
token, username)
Expand All @@ -71,14 +75,13 @@ func (p *politeiawww) emailUserEmailVerify(email, token, username string) error
if err != nil {
return err
}
recipients := []string{email}

return p.mail.SendTo(subject, body, recipients)
return p.mail.SendTo(subject, body, []string{email})
}

// emailUserKeyUpdate emails the link with the verification token used for
// setting a new key pair if the email server is set up.
func (p *politeiawww) emailUserKeyUpdate(username, email, publicKey, token string) error {
func (p *politeiawww) emailUserKeyUpdate(username, publicKey, token string, recipient map[uuid.UUID]string) error {
link, err := p.createEmailLink(www.RouteVerifyUpdateUserKey, "", token, "")
if err != nil {
return err
Expand All @@ -95,14 +98,13 @@ func (p *politeiawww) emailUserKeyUpdate(username, email, publicKey, token strin
if err != nil {
return err
}
recipients := []string{email}

return p.mail.SendTo(subject, body, recipients)
return p.mail.SendToUsers(subject, body, recipient)
}

// emailUserPasswordReset emails the link with the reset password verification
// token to the provided email address.
func (p *politeiawww) emailUserPasswordReset(email, username, token string) error {
func (p *politeiawww) emailUserPasswordReset(username, token string, recipient map[uuid.UUID]string) error {
// Setup URL
u, err := url.Parse(p.cfg.WebServerAddress + www.RouteResetPassword)
if err != nil {
Expand All @@ -124,13 +126,17 @@ func (p *politeiawww) emailUserPasswordReset(email, username, token string) erro
}

// Send email
return p.mail.SendTo(subject, body, []string{email})
return p.mail.SendToUsers(subject, body, recipient)
}

// emailUserAccountLocked notifies the user its account has been locked and
// emails the link with the reset password verification token if the email
// server is set up.
func (p *politeiawww) emailUserAccountLocked(username, email string) error {
func (p *politeiawww) emailUserAccountLocked(username string, recipient map[uuid.UUID]string) error {
var email string
for _, e := range recipient {
email = e
}
link, err := p.createEmailLink(ResetPasswordGuiRoute,
email, "", "")
if err != nil {
Expand All @@ -147,14 +153,13 @@ func (p *politeiawww) emailUserAccountLocked(username, email string) error {
if err != nil {
return err
}
recipients := []string{email}

return p.mail.SendTo(subject, body, recipients)
return p.mail.SendToUsers(subject, body, recipient)
}

// emailUserPasswordChanged notifies the user that his password was changed,
// and verifies if he was the author of this action, for security purposes.
func (p *politeiawww) emailUserPasswordChanged(username, email string) error {
func (p *politeiawww) emailUserPasswordChanged(username string, recipient map[uuid.UUID]string) error {
tplData := userPasswordChanged{
Username: username,
}
Expand All @@ -164,9 +169,8 @@ func (p *politeiawww) emailUserPasswordChanged(username, email string) error {
if err != nil {
return err
}
recipients := []string{email}

return p.mail.SendTo(subject, body, recipients)
return p.mail.SendToUsers(subject, body, recipient)
}

// emailUserCMSInvite emails the invitation link for the Contractor Management
Expand Down
Loading