Browse Source

expose a user-visible error if direct email sending fails

See #1659
tags/v2.8.0-rc1
Shivaram Lingamneni 2 years ago
parent
commit
46572b871f
5 changed files with 43 additions and 11 deletions
  1. 25
    1
      irc/accounts.go
  2. 7
    2
      irc/email/email.go
  3. 0
    1
      irc/errors.go
  4. 10
    6
      irc/handlers.go
  5. 1
    1
      irc/nickserv.go

+ 25
- 1
irc/accounts.go View File

@@ -15,6 +15,8 @@ import (
15 15
 	"time"
16 16
 	"unicode"
17 17
 
18
+	"github.com/ergochat/irc-go/ircutils"
19
+
18 20
 	"github.com/ergochat/ergo/irc/connection_limits"
19 21
 	"github.com/ergochat/ergo/irc/email"
20 22
 	"github.com/ergochat/ergo/irc/migrations"
@@ -460,7 +462,7 @@ func (am *AccountManager) Register(client *Client, account string, callbackNames
460 462
 	code, err := am.dispatchCallback(client, account, callbackNamespace, callbackValue)
461 463
 	if err != nil {
462 464
 		am.Unregister(casefoldedAccount, true)
463
-		return errCallbackFailed
465
+		return &registrationCallbackError{underlying: err}
464 466
 	} else {
465 467
 		return am.server.store.Update(func(tx *buntdb.Tx) error {
466 468
 			_, _, err = tx.Set(verificationCodeKey, code, setOptions)
@@ -469,6 +471,28 @@ func (am *AccountManager) Register(client *Client, account string, callbackNames
469 471
 	}
470 472
 }
471 473
 
474
+type registrationCallbackError struct {
475
+	underlying error
476
+}
477
+
478
+func (r *registrationCallbackError) Error() string {
479
+	return `Account verification could not be sent`
480
+}
481
+
482
+func registrationCallbackErrorText(config *Config, client *Client, err error) string {
483
+	if callbackErr, ok := err.(*registrationCallbackError); ok {
484
+		// only expose a user-visible error if we are doing direct sending
485
+		if config.Accounts.Registration.EmailVerification.DirectSendingEnabled() {
486
+			errorText := ircutils.SanitizeText(callbackErr.underlying.Error(), 350)
487
+			return fmt.Sprintf(client.t("Could not dispatch registration e-mail: %s"), errorText)
488
+		} else {
489
+			return client.t("Could not dispatch registration e-mail")
490
+		}
491
+	} else {
492
+		return ""
493
+	}
494
+}
495
+
472 496
 // validatePassphrase checks whether a passphrase is allowed by our rules
473 497
 func validatePassphrase(passphrase string) error {
474 498
 	// sanity check the length

+ 7
- 2
irc/email/email.go View File

@@ -15,7 +15,7 @@ import (
15 15
 
16 16
 var (
17 17
 	ErrBlacklistedAddress = errors.New("Email address is blacklisted")
18
-	ErrInvalidAddress     = errors.New("Email address is blacklisted")
18
+	ErrInvalidAddress     = errors.New("Email address is invalid")
19 19
 	ErrNoMXRecord         = errors.New("Couldn't resolve MX record")
20 20
 )
21 21
 
@@ -73,6 +73,11 @@ func (config *MailtoConfig) Postprocess(heloDomain string) (err error) {
73 73
 	return config.DKIM.Postprocess()
74 74
 }
75 75
 
76
+// are we sending email directly, as opposed to deferring to an MTA?
77
+func (config *MailtoConfig) DirectSendingEnabled() bool {
78
+	return config.MTAReal.Server == ""
79
+}
80
+
76 81
 // get the preferred MX record hostname, "" on error
77 82
 func lookupMX(domain string) (server string) {
78 83
 	var minPref uint16
@@ -104,7 +109,7 @@ func SendMail(config MailtoConfig, recipient string, msg []byte) (err error) {
104 109
 
105 110
 	var addr string
106 111
 	var auth smtp.Auth
107
-	if config.MTAReal.Server != "" {
112
+	if !config.DirectSendingEnabled() {
108 113
 		addr = fmt.Sprintf("%s:%d", config.MTAReal.Server, config.MTAReal.Port)
109 114
 		if config.MTAReal.Username != "" && config.MTAReal.Password != "" {
110 115
 			auth = smtp.PlainAuth("", config.MTAReal.Username, config.MTAReal.Password, config.MTAReal.Server)

+ 0
- 1
irc/errors.go View File

@@ -34,7 +34,6 @@ var (
34 34
 	errAccountUpdateFailed            = errors.New(`Error while updating your account information`)
35 35
 	errAccountMustHoldNick            = errors.New(`You must hold that nickname in order to register it`)
36 36
 	errAuthzidAuthcidMismatch         = errors.New(`authcid and authzid must be the same`)
37
-	errCallbackFailed                 = errors.New("Account verification could not be sent")
38 37
 	errCertfpAlreadyExists            = errors.New(`An account already exists for your certificate fingerprint`)
39 38
 	errChannelNotOwnedByAccount       = errors.New("Channel not owned by the specified account")
40 39
 	errChannelTransferNotOffered      = errors.New(`You weren't offered ownership of that channel`)

+ 10
- 6
irc/handlers.go View File

@@ -63,14 +63,16 @@ func parseCallback(spec string, config *Config) (callbackNamespace string, callb
63 63
 	return
64 64
 }
65 65
 
66
-func registrationErrorToMessage(err error) (message string) {
66
+func registrationErrorToMessage(config *Config, client *Client, err error) (message string) {
67
+	if emailError := registrationCallbackErrorText(config, client, err); emailError != "" {
68
+		return emailError
69
+	}
70
+
67 71
 	switch err {
68 72
 	case errAccountAlreadyRegistered, errAccountAlreadyVerified, errAccountAlreadyUnregistered, errAccountAlreadyLoggedIn, errAccountCreation, errAccountMustHoldNick, errAccountBadPassphrase, errCertfpAlreadyExists, errFeatureDisabled, errAccountBadPassphrase:
69 73
 		message = err.Error()
70 74
 	case errLimitExceeded:
71 75
 		message = `There have been too many registration attempts recently; try again later`
72
-	case errCallbackFailed:
73
-		message = `Could not dispatch verification email`
74 76
 	default:
75 77
 		// default response: let's be risk-averse about displaying internal errors
76 78
 		// to the clients, especially for something as sensitive as accounts
@@ -2548,10 +2550,12 @@ func registerHandler(server *Server, client *Client, msg ircmsg.Message, rb *Res
2548 2550
 		rb.Add(nil, server.name, "FAIL", "REGISTER", "USERNAME_EXISTS", accountName, client.t("Username is already registered or otherwise unavailable"))
2549 2551
 	case errAccountBadPassphrase:
2550 2552
 		rb.Add(nil, server.name, "FAIL", "REGISTER", "INVALID_PASSWORD", accountName, client.t("Password was invalid"))
2551
-	case errCallbackFailed:
2552
-		rb.Add(nil, server.name, "FAIL", "REGISTER", "UNACCEPTABLE_EMAIL", accountName, client.t("Could not dispatch verification e-mail"))
2553 2553
 	default:
2554
-		rb.Add(nil, server.name, "FAIL", "REGISTER", "UNKNOWN_ERROR", accountName, client.t("Could not register"))
2554
+		if emailError := registrationCallbackErrorText(config, client, err); emailError != "" {
2555
+			rb.Add(nil, server.name, "FAIL", "REGISTER", "UNACCEPTABLE_EMAIL", accountName, emailError)
2556
+		} else {
2557
+			rb.Add(nil, server.name, "FAIL", "REGISTER", "UNKNOWN_ERROR", accountName, client.t("Could not register"))
2558
+		}
2555 2559
 	}
2556 2560
 	return
2557 2561
 }

+ 1
- 1
irc/nickserv.go View File

@@ -900,7 +900,7 @@ func nsRegisterHandler(service *ircService, server *Server, client *Client, comm
900 900
 		}
901 901
 	} else {
902 902
 		// details could not be stored and relevant numerics have been dispatched, abort
903
-		message := registrationErrorToMessage(err)
903
+		message := registrationErrorToMessage(config, client, err)
904 904
 		service.Notice(rb, client.t(message))
905 905
 	}
906 906
 }

Loading…
Cancel
Save