feat(security): #286 fix mail sending
All checks were successful
Build Docker Image / Build-Docker-Image (push) Successful in 46s
Build and Push Docker Image / Build-And-Push-Docker-Image (push) Successful in 50s

This commit was merged in pull request #300.
This commit is contained in:
2024-12-09 23:19:51 +01:00
parent eab42c26f8
commit 8cf2210aaf
5 changed files with 76 additions and 32 deletions

View File

@@ -59,9 +59,9 @@ var (
func (handler AuthImpl) handleSignInPage() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
session := middleware.GetSession(r)
if session != nil {
if !session.User.EmailVerified {
user := middleware.GetUser(r)
if user != nil {
if !user.EmailVerified {
utils.DoRedirect(w, r, "/auth/verify")
} else {
utils.DoRedirect(w, r, "/")
@@ -122,10 +122,10 @@ func (handler AuthImpl) handleSignIn() http.HandlerFunc {
func (handler AuthImpl) handleSignUpPage() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
session := middleware.GetSession(r)
user := middleware.GetUser(r)
if session != nil {
if !session.User.EmailVerified {
if user != nil {
if !user.EmailVerified {
utils.DoRedirect(w, r, "/auth/verify")
} else {
utils.DoRedirect(w, r, "/")
@@ -140,31 +140,30 @@ func (handler AuthImpl) handleSignUpPage() http.HandlerFunc {
func (handler AuthImpl) handleSignUpVerifyPage() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
session := middleware.GetSession(r)
if session == nil {
user := middleware.GetUser(r)
if user == nil {
utils.DoRedirect(w, r, "/auth/signin")
return
}
if session.User.EmailVerified {
if user.EmailVerified {
utils.DoRedirect(w, r, "/")
return
}
signIn := auth.VerifyComp()
handler.render.RenderLayout(r, w, signIn, session.User)
handler.render.RenderLayout(r, w, signIn, user)
}
}
func (handler AuthImpl) handleVerifyResendComp() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
session := middleware.GetSession(r)
if session == nil {
user := middleware.GetUser(r)
if user == nil {
utils.DoRedirect(w, r, "/auth/signin")
return
}
user := session.User
go handler.service.SendVerificationMail(user.Id, user.Email)
_, err := w.Write([]byte("<p class=\"mt-8\">Verification email sent</p>"))
@@ -195,11 +194,13 @@ func (handler AuthImpl) handleSignUp() http.HandlerFunc {
var password = r.FormValue("password")
_, err := utils.WaitMinimumTime(securityWaitDuration, func() (interface{}, error) {
log.Info("Signing up %v", email)
user, err := handler.service.SignUp(email, password)
if err != nil {
return nil, err
}
log.Info("Sending verification email to %v", user.Email)
go handler.service.SendVerificationMail(user.Id, user.Email)
return nil, nil
})
@@ -248,34 +249,34 @@ func (handler AuthImpl) handleSignOut() http.HandlerFunc {
func (handler AuthImpl) handleDeleteAccountPage() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
session := middleware.GetSession(r)
if session == nil {
user := middleware.GetUser(r)
if user == nil {
utils.DoRedirect(w, r, "/auth/signin")
return
}
comp := auth.DeleteAccountComp()
handler.render.RenderLayout(r, w, comp, session.User)
handler.render.RenderLayout(r, w, comp, user)
}
}
func (handler AuthImpl) handleDeleteAccountComp() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
session := middleware.GetSession(r)
if session == nil {
user := middleware.GetUser(r)
if user == nil {
utils.DoRedirect(w, r, "/auth/signin")
return
}
password := r.FormValue("password")
_, err := handler.service.SignIn(session.User.Email, password)
_, err := handler.service.SignIn(user.Email, password)
if err != nil {
utils.TriggerToast(w, r, "error", "Password not correct")
return
}
err = handler.service.DeleteAccount(session.User)
err = handler.service.DeleteAccount(user)
if err != nil {
utils.TriggerToast(w, r, "error", "Internal Server Error")
return
@@ -290,23 +291,23 @@ func (handler AuthImpl) handleChangePasswordPage() http.HandlerFunc {
isPasswordReset := r.URL.Query().Has("token")
session := middleware.GetSession(r)
user := middleware.GetUser(r)
if session == nil && !isPasswordReset {
if user == nil && !isPasswordReset {
utils.DoRedirect(w, r, "/auth/signin")
return
}
comp := auth.ChangePasswordComp(isPasswordReset)
handler.render.RenderLayout(r, w, comp, session.User)
handler.render.RenderLayout(r, w, comp, user)
}
}
func (handler AuthImpl) handleChangePasswordComp() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
session := middleware.GetSession(r)
if session == nil {
user := middleware.GetUser(r)
if user == nil {
utils.DoRedirect(w, r, "/auth/signin")
return
}
@@ -314,7 +315,7 @@ func (handler AuthImpl) handleChangePasswordComp() http.HandlerFunc {
currPass := r.FormValue("current-password")
newPass := r.FormValue("new-password")
err := handler.service.ChangePassword(session.User, currPass, newPass)
err := handler.service.ChangePassword(user, currPass, newPass)
if err != nil {
utils.TriggerToast(w, r, "error", "Password not correct")
return
@@ -327,14 +328,14 @@ func (handler AuthImpl) handleChangePasswordComp() http.HandlerFunc {
func (handler AuthImpl) handleResetPasswordPage() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
session := middleware.GetSession(r)
if session == nil {
user := middleware.GetUser(r)
if user == nil {
utils.DoRedirect(w, r, "/auth/signin")
return
}
comp := auth.ResetPasswordComp()
handler.render.RenderLayout(r, w, comp, session.User)
handler.render.RenderLayout(r, w, comp, user)
}
}

View File

@@ -29,6 +29,16 @@ func Authenticate(service service.Auth) func(http.Handler) http.Handler {
}
}
func GetUser(r *http.Request) *service.User {
session := GetSession(r)
if session == nil {
return nil
}
return session.User
}
func GetSession(r *http.Request) *service.Session {
obj := r.Context().Value(SessionKey)
if obj == nil {

28
less Normal file
View File

@@ -0,0 +1,28 @@
__ _ ___
/ /\ | | | |_)
/_/--\ |_| |_| \_ v1.52.3, built with Go go1.22.5
mkdir /home/tiwun/source/me-fit/tmp
watching .
watching db
watching handler
watching handler/middleware
watching log
watching migration
watching mocks
!exclude node_modules
watching service
!exclude static
watching template
watching template/auth
watching template/mail
watching template/workout
!exclude tmp
watching types
watching utils
building...
(✓) Complete [ updates=12 duration=10.258748ms ]
cleaning...
deleting /home/tiwun/source/me-fit/tmp
see you again~

View File

@@ -220,7 +220,7 @@ func (service AuthImpl) SignUp(email string, password string) (*User, error) {
func (service AuthImpl) SendVerificationMail(userId uuid.UUID, email string) {
tokens, err := service.db.GetTokensByUserIdAndType(userId, db.TokenTypeEmailVerify)
if err != nil {
if err != nil && err != db.ErrNotFound {
return
}
@@ -304,7 +304,7 @@ func (service AuthImpl) DeleteAccount(user *User) error {
return err
}
go service.mail.SendMail(user.Email, "Account deleted", "Your account has been deleted")
service.mail.SendMail(user.Email, "Account deleted", "Your account has been deleted")
return nil
}
@@ -370,7 +370,7 @@ func (service AuthImpl) SendForgotPasswordMail(email string) error {
log.Error("Could not render reset password email: %v", err)
return types.ErrInternal
}
go service.mail.SendMail(email, "Reset Password", mail.String())
service.mail.SendMail(email, "Reset Password", mail.String())
return nil
}

View File

@@ -22,6 +22,10 @@ func NewMailImpl(server *types.Settings) MailImpl {
}
func (m MailImpl) SendMail(to string, subject string, message string) {
go m.internalSendMail(to, subject, message)
}
func (m MailImpl) internalSendMail(to string, subject string, message string) {
if m.server.Smtp == nil {
return
}
@@ -32,6 +36,7 @@ func (m MailImpl) SendMail(to string, subject string, message string) {
msg := fmt.Sprintf("From: %v <%v>\nTo: %v\nSubject: %v\nMIME-version: 1.0;\nContent-Type: text/html; charset=\"UTF-8\";\n\n%v", s.FromName, s.FromMail, to, subject, message)
log.Info("Sending mail to %v", to)
err := smtp.SendMail(s.Host+":"+s.Port, auth, s.FromMail, []string{to}, []byte(msg))
if err != nil {
log.Error("Error sending mail: %v", err)