MFA fix, added IP blacklist, update webmail client
This commit is contained in:
@@ -3,6 +3,7 @@ package webui
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"html/template"
|
||||
"image/png"
|
||||
"net/http"
|
||||
"strings"
|
||||
@@ -55,32 +56,32 @@ func (a *App) webmailChangePassword(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
if !db.CheckPassword(current, mbox.PasswordHash) {
|
||||
setFlash(w, "error", "Current password is incorrect")
|
||||
http.Redirect(w, r, MailboxPrefix+"/", http.StatusFound)
|
||||
http.Redirect(w, r, MailboxPrefix+"/account", http.StatusFound)
|
||||
return
|
||||
}
|
||||
if !isStrongPassword(newPassword) {
|
||||
setFlash(w, "error", "New password must be at least 10 characters and include a letter, a number, and a symbol")
|
||||
http.Redirect(w, r, MailboxPrefix+"/", http.StatusFound)
|
||||
http.Redirect(w, r, MailboxPrefix+"/account", http.StatusFound)
|
||||
return
|
||||
}
|
||||
if newPassword != confirm {
|
||||
setFlash(w, "error", "New passwords don't match")
|
||||
http.Redirect(w, r, MailboxPrefix+"/", http.StatusFound)
|
||||
http.Redirect(w, r, MailboxPrefix+"/account", http.StatusFound)
|
||||
return
|
||||
}
|
||||
hash, err := db.HashPassword(newPassword)
|
||||
if err != nil {
|
||||
setFlash(w, "error", "Something went wrong")
|
||||
http.Redirect(w, r, MailboxPrefix+"/", http.StatusFound)
|
||||
http.Redirect(w, r, MailboxPrefix+"/account", http.StatusFound)
|
||||
return
|
||||
}
|
||||
if err := a.DB.SetMailboxPasswordHash(mbox.ID, hash); err != nil {
|
||||
setFlash(w, "error", "Something went wrong")
|
||||
http.Redirect(w, r, MailboxPrefix+"/", http.StatusFound)
|
||||
http.Redirect(w, r, MailboxPrefix+"/account", http.StatusFound)
|
||||
return
|
||||
}
|
||||
setFlash(w, "success", "Password updated")
|
||||
http.Redirect(w, r, MailboxPrefix+"/", http.StatusFound)
|
||||
http.Redirect(w, r, MailboxPrefix+"/account", http.StatusFound)
|
||||
}
|
||||
|
||||
func (a *App) webmailTOTPSetupBegin(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -88,12 +89,12 @@ func (a *App) webmailTOTPSetupBegin(w http.ResponseWriter, r *http.Request) {
|
||||
key, err := totp.Generate(totp.GenerateOpts{Issuer: "mailgoserver", AccountName: mbox.Email})
|
||||
if err != nil {
|
||||
setFlash(w, "error", "Could not generate a TOTP secret")
|
||||
http.Redirect(w, r, MailboxPrefix+"/", http.StatusFound)
|
||||
http.Redirect(w, r, MailboxPrefix+"/account", http.StatusFound)
|
||||
return
|
||||
}
|
||||
if err := a.DB.SetMailboxTOTPSecret(mbox.ID, key.Secret(), false); err != nil {
|
||||
setFlash(w, "error", "Could not save the TOTP secret")
|
||||
http.Redirect(w, r, MailboxPrefix+"/", http.StatusFound)
|
||||
http.Redirect(w, r, MailboxPrefix+"/account", http.StatusFound)
|
||||
return
|
||||
}
|
||||
img, err := key.Image(256, 256)
|
||||
@@ -104,7 +105,9 @@ func (a *App) webmailTOTPSetupBegin(w http.ResponseWriter, r *http.Request) {
|
||||
qrDataURI = "data:image/png;base64," + base64.StdEncoding.EncodeToString(buf.Bytes())
|
||||
}
|
||||
}
|
||||
a.render(w, r, "webmail_totp_setup.html", M{"secret": key.Secret(), "qr_data_uri": qrDataURI})
|
||||
// See totpSetupBegin's matching comment in account.go — data: URIs need to be
|
||||
// typed as template.URL or html/template silently strips them to "#ZgotmplZ".
|
||||
a.render(w, r, "webmail_totp_setup.html", M{"secret": key.Secret(), "qr_data_uri": template.URL(qrDataURI)})
|
||||
}
|
||||
|
||||
func (a *App) webmailTOTPSetupConfirm(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -112,17 +115,17 @@ func (a *App) webmailTOTPSetupConfirm(w http.ResponseWriter, r *http.Request) {
|
||||
code := strings.TrimSpace(r.FormValue("code"))
|
||||
if mbox.TOTPSecret == "" || !totp.Validate(code, mbox.TOTPSecret) {
|
||||
setFlash(w, "error", "That code didn't match — try scanning the QR code again")
|
||||
http.Redirect(w, r, MailboxPrefix+"/", http.StatusFound)
|
||||
http.Redirect(w, r, MailboxPrefix+"/account", http.StatusFound)
|
||||
return
|
||||
}
|
||||
if err := a.DB.SetMailboxTOTPSecret(mbox.ID, mbox.TOTPSecret, true); err != nil {
|
||||
setFlash(w, "error", "Something went wrong enabling MFA")
|
||||
http.Redirect(w, r, MailboxPrefix+"/", http.StatusFound)
|
||||
http.Redirect(w, r, MailboxPrefix+"/account", http.StatusFound)
|
||||
return
|
||||
}
|
||||
_ = a.DB.LogAuthAttempt("mailbox_mfa", mbox.Email, requestIP(r), true, "TOTP authenticator enabled")
|
||||
_ = a.DB.LogAuthAttempt("mailbox_mfa", mbox.Email, a.requestIP(r), true, "TOTP authenticator enabled")
|
||||
setFlash(w, "success", "Authenticator app MFA enabled")
|
||||
http.Redirect(w, r, MailboxPrefix+"/", http.StatusFound)
|
||||
http.Redirect(w, r, MailboxPrefix+"/account", http.StatusFound)
|
||||
}
|
||||
|
||||
func (a *App) webmailTOTPDisable(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -130,10 +133,10 @@ func (a *App) webmailTOTPDisable(w http.ResponseWriter, r *http.Request) {
|
||||
if err := a.DB.DisableMailboxTOTP(mbox.ID); err != nil {
|
||||
setFlash(w, "error", "Something went wrong")
|
||||
} else {
|
||||
_ = a.DB.LogAuthAttempt("mailbox_mfa", mbox.Email, requestIP(r), true, "TOTP authenticator disabled")
|
||||
_ = a.DB.LogAuthAttempt("mailbox_mfa", mbox.Email, a.requestIP(r), true, "TOTP authenticator disabled")
|
||||
setFlash(w, "success", "Authenticator app MFA disabled")
|
||||
}
|
||||
http.Redirect(w, r, MailboxPrefix+"/", http.StatusFound)
|
||||
http.Redirect(w, r, MailboxPrefix+"/account", http.StatusFound)
|
||||
}
|
||||
|
||||
// webmailAddAppPassword mirrors addAppPassword (mailbox_apppasswords.go) but for
|
||||
@@ -150,16 +153,16 @@ func (a *App) webmailAddAppPassword(w http.ResponseWriter, r *http.Request) {
|
||||
hash, err := db.HashPassword(secret)
|
||||
if err != nil {
|
||||
setFlash(w, "error", "Error creating app password")
|
||||
http.Redirect(w, r, MailboxPrefix+"/", http.StatusFound)
|
||||
http.Redirect(w, r, MailboxPrefix+"/account", http.StatusFound)
|
||||
return
|
||||
}
|
||||
if _, err := a.DB.CreateAppPassword(mbox.ID, label, hash, nil); err != nil {
|
||||
setFlash(w, "error", "Error creating app password")
|
||||
http.Redirect(w, r, MailboxPrefix+"/", http.StatusFound)
|
||||
http.Redirect(w, r, MailboxPrefix+"/account", http.StatusFound)
|
||||
return
|
||||
}
|
||||
setFlash(w, "success", "App password created — copy it now, it will not be shown again: "+secret)
|
||||
http.Redirect(w, r, MailboxPrefix+"/", http.StatusFound)
|
||||
http.Redirect(w, r, MailboxPrefix+"/account", http.StatusFound)
|
||||
}
|
||||
|
||||
func (a *App) webmailRevokeAppPassword(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -170,5 +173,5 @@ func (a *App) webmailRevokeAppPassword(w http.ResponseWriter, r *http.Request) {
|
||||
} else {
|
||||
setFlash(w, "success", "App password revoked")
|
||||
}
|
||||
http.Redirect(w, r, MailboxPrefix+"/", http.StatusFound)
|
||||
http.Redirect(w, r, MailboxPrefix+"/account", http.StatusFound)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user