2023-09-24 18:24:16 +01:00
|
|
|
package server
|
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/1f349/tulip/database"
|
2023-09-29 16:37:23 +01:00
|
|
|
"github.com/1f349/tulip/pages"
|
2023-09-24 18:24:16 +01:00
|
|
|
"github.com/emersion/go-message/mail"
|
|
|
|
"github.com/julienschmidt/httprouter"
|
|
|
|
"net/http"
|
|
|
|
)
|
|
|
|
|
2024-02-09 15:24:40 +00:00
|
|
|
func (h *HttpServer) MailVerify(rw http.ResponseWriter, _ *http.Request, params httprouter.Params) {
|
2023-09-24 18:24:16 +01:00
|
|
|
code := params.ByName("code")
|
|
|
|
|
2024-02-09 15:24:40 +00:00
|
|
|
k := mailLinkKey{mailLinkVerifyEmail, code}
|
2023-09-24 18:24:16 +01:00
|
|
|
|
|
|
|
userSub, ok := h.mailLinkCache.Get(k)
|
|
|
|
if !ok {
|
|
|
|
http.Error(rw, "Invalid email verification code", http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if h.DbTx(rw, func(tx *database.Tx) error {
|
|
|
|
return tx.VerifyUserEmail(userSub)
|
|
|
|
}) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
h.mailLinkCache.Delete(k)
|
|
|
|
|
|
|
|
http.Error(rw, "Email address has been verified, you may close this tab and return to the login page.", http.StatusOK)
|
|
|
|
}
|
|
|
|
|
2024-02-09 15:24:40 +00:00
|
|
|
func (h *HttpServer) MailPassword(rw http.ResponseWriter, _ *http.Request, params httprouter.Params) {
|
2023-09-29 16:37:23 +01:00
|
|
|
code := params.ByName("code")
|
|
|
|
|
2024-02-09 15:24:40 +00:00
|
|
|
k := mailLinkKey{mailLinkResetPassword, code}
|
|
|
|
_, ok := h.mailLinkCache.Get(k)
|
2023-09-29 16:37:23 +01:00
|
|
|
if !ok {
|
|
|
|
http.Error(rw, "Invalid password reset code", http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
pages.RenderPageTemplate(rw, "reset-password", map[string]any{
|
2023-10-10 18:06:43 +01:00
|
|
|
"ServiceName": h.conf.ServiceName,
|
2024-02-09 15:24:40 +00:00
|
|
|
"Code": code,
|
2023-09-29 16:37:23 +01:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2024-02-09 15:24:40 +00:00
|
|
|
func (h *HttpServer) MailPasswordPost(rw http.ResponseWriter, req *http.Request, _ httprouter.Params) {
|
2023-09-29 16:37:23 +01:00
|
|
|
pw := req.PostFormValue("new_password")
|
|
|
|
rpw := req.PostFormValue("confirm_password")
|
2024-02-09 15:24:40 +00:00
|
|
|
code := req.PostFormValue("code")
|
2023-09-29 16:37:23 +01:00
|
|
|
|
|
|
|
// reverse passwords are possible
|
|
|
|
if len(pw) == 0 {
|
|
|
|
http.Error(rw, "Cannot set an empty password", http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
// bcrypt only allows up to 72 bytes anyway
|
|
|
|
if len(pw) > 64 {
|
|
|
|
http.Error(rw, "Security by extremely long password is a weird flex", http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if rpw != pw {
|
|
|
|
http.Error(rw, "Passwords do not match", http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-02-09 15:24:40 +00:00
|
|
|
k := mailLinkKey{mailLinkResetPassword, code}
|
|
|
|
userSub, ok := h.mailLinkCache.Get(k)
|
2023-09-29 16:37:23 +01:00
|
|
|
if !ok {
|
|
|
|
http.Error(rw, "Invalid password reset code", http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-02-09 15:24:40 +00:00
|
|
|
h.mailLinkCache.Delete(k)
|
|
|
|
|
2023-09-29 16:37:23 +01:00
|
|
|
// reset password database call
|
|
|
|
if h.DbTx(rw, func(tx *database.Tx) error {
|
|
|
|
return tx.UserResetPassword(userSub, pw)
|
|
|
|
}) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
http.Error(rw, "Reset password successfully, you can login now.", http.StatusOK)
|
2023-09-24 18:24:16 +01:00
|
|
|
}
|
|
|
|
|
2024-02-09 15:24:40 +00:00
|
|
|
func (h *HttpServer) MailDelete(rw http.ResponseWriter, _ *http.Request, params httprouter.Params) {
|
2023-09-24 18:24:16 +01:00
|
|
|
code := params.ByName("code")
|
|
|
|
|
2024-02-09 15:24:40 +00:00
|
|
|
k := mailLinkKey{mailLinkDelete, code}
|
2023-09-24 18:24:16 +01:00
|
|
|
userSub, ok := h.mailLinkCache.Get(k)
|
|
|
|
if !ok {
|
|
|
|
http.Error(rw, "Invalid email delete code", http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
var userInfo *database.User
|
|
|
|
if h.DbTx(rw, func(tx *database.Tx) (err error) {
|
|
|
|
userInfo, err = tx.GetUser(userSub)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
return tx.UpdateUser(userSub, database.RoleToDelete, false)
|
|
|
|
}) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
h.mailLinkCache.Delete(k)
|
|
|
|
|
|
|
|
// parse email for headers
|
|
|
|
address, err := mail.ParseAddress(userInfo.Email)
|
|
|
|
if err != nil {
|
|
|
|
http.Error(rw, "500 Internal Server Error: Failed to parse user email address", http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-10-10 18:06:43 +01:00
|
|
|
err = h.conf.Mail.SendEmailTemplate("mail-account-delete", "Account Deletion", userInfo.Name, address, nil)
|
2023-09-24 18:24:16 +01:00
|
|
|
if err != nil {
|
|
|
|
http.Error(rw, "Failed to send confirmation email.", http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
http.Error(rw, "You will receive an email shortly to verify this action, you may close this tab.", http.StatusOK)
|
|
|
|
}
|