diff --git a/pages/register.html b/pages/register.html index 417867e..42c86fd 100644 --- a/pages/register.html +++ b/pages/register.html @@ -45,7 +45,6 @@ @@ -85,7 +83,15 @@ async function verify() { } } +let verificationSent = false; + async function register() { + if (verificationSent) { + // No need to resend registration data, reopen verification modal, + showVerificationModal(); + return; + } + let emailInput = document.getElementById("input-email"); if (!emailInput.reportValidity()) { return; @@ -106,9 +112,10 @@ async function register() { }; let response = await postNewUser(postData); - if (response.ok) { + if (response.ok) { let json = await response.json(); if (json.confirm_email) { + verificationSent = true; // Open email confirmation modal showVerificationModal(); } else { diff --git a/src/db/verification.go b/src/db/verification.go index 32601a4..acd1db7 100644 --- a/src/db/verification.go +++ b/src/db/verification.go @@ -1,6 +1,8 @@ package db -import "database/sql" +import ( + "database/sql" +) type Verification struct { ID uint64 `json:"id"` @@ -55,10 +57,10 @@ func (db *DB) GetVerification(id uint64) (*Verification, error) { return verification, nil } -// Returns the first email verification by email +// Returns the last email verification by email func (db *DB) GetVerificationByEmail(email string) (*Verification, error) { rows, err := db.Query( - "SELECT * FROM verifications WHERE email=?", + "SELECT * FROM verifications WHERE (email=?) ORDER BY life_seconds DESC", email, ) if err != nil { diff --git a/src/server/endpoints.go b/src/server/endpoints.go index c66b0fa..34dd59f 100644 --- a/src/server/endpoints.go +++ b/src/server/endpoints.go @@ -108,7 +108,7 @@ func (s *Server) EndpointUserCreate(w http.ResponseWriter, req *http.Request) { } // Send email verification message - verification, err := GenerateVerificationCode(s.db, user.Email) + verification, err := GenerateVerificationCode(s.db, user.Email, 5, uint64(time.Hour.Seconds())) if err != nil { logger.Error("[Server][EndpointUserCreate] Failed to generate verification code for %s: %s", user.Email, err) http.Error(w, "Failed to generate confirmation code", http.StatusInternalServerError) @@ -120,7 +120,7 @@ func (s *Server) EndpointUserCreate(w http.ResponseWriter, req *http.Request) { email.NewEmail( s.config.Verification.Emailer.User, "Dela: Email verification", - fmt.Sprintf("Your email verification code: %s\nPlease, verify your email in %f hours.\nThis email was specified during Dela account creation. Ignore this message if it wasn't you", verification.Code, float32(verification.LifeSeconds)/3600), + fmt.Sprintf("

Your email verification code is: %s

Please, verify your email in %.1f hours. Your account will be deleted after some time without verified status.

This email was specified during Dela account creation. Ignore this message if it wasn't you.

", verification.Code, float32(verification.LifeSeconds)/3600), []string{user.Email}, ), ) @@ -130,8 +130,8 @@ func (s *Server) EndpointUserCreate(w http.ResponseWriter, req *http.Request) { return } - // Autodelete user account if email was not verified in time - time.AfterFunc(time.Second*time.Duration(verification.LifeSeconds), func() { + // Autodelete user account after some more time if email was not verified in time + time.AfterFunc((time.Second*time.Duration(verification.LifeSeconds))*5, func() { err = s.db.DeleteUnverifiedUserClean(user.Email) if err != nil { logger.Error("[Server][EndpointUserCreate] Failed to autodelete unverified user %s: %s", user.Email, err) @@ -173,8 +173,8 @@ func (s *Server) EndpointUserVerify(w http.ResponseWriter, req *http.Request) { // Retrieve user user, err := s.db.GetUser(answer.Email) if err != nil { - logger.Error("[Server][EndpointUserVerify] Failed to retrieve information on \"%s\": %s", answer.Email, err) - http.Error(w, "Failed to get user information", http.StatusInternalServerError) + // Most likely already deleted this user's account + http.Error(w, "Account no longer exists, try registering again", http.StatusInternalServerError) return } @@ -193,6 +193,13 @@ func (s *Server) EndpointUserVerify(w http.ResponseWriter, req *http.Request) { return } + // Check for lifetime + if time.Now().Unix() > int64(dbCode.IssuedUnix+dbCode.LifeSeconds) { + // Expired! + http.Error(w, "This code is expired!", http.StatusForbidden) + return + } + // All's good! err = s.db.UserSetEmailConfirmed(user.Email) if err != nil { diff --git a/src/server/validation.go b/src/server/validation.go index 45a5fc4..dcf3f41 100644 --- a/src/server/validation.go +++ b/src/server/validation.go @@ -127,12 +127,12 @@ func GetLoginFromReq(req *http.Request) string { /* Generates a new verification code for given email with 8-digit numeric code, -current issue time and one hour lifetime. +current issue time and provided life time. Inserts newly created email verification into database. */ -func GenerateVerificationCode(dbase *db.DB, email string) (*db.Verification, error) { +func GenerateVerificationCode(dbase *db.DB, email string, length uint, lifeTimeSeconds uint64) (*db.Verification, error) { verification := db.NewVerification( - email, misc.GenerateNumericCode(8), uint64(time.Now().Unix()), uint64(time.Hour.Seconds()), + email, misc.GenerateNumericCode(length), uint64(time.Now().Unix()), lifeTimeSeconds, ) err := dbase.CreateVerification(*verification)