feat(auth): use one time token instead of user id #158
This commit is contained in:
11
migration/004_user_tokens.up.sql
Normal file
11
migration/004_user_tokens.up.sql
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
-- E.G. email-verifications, password-resets, unsubscribe-from-newsletter etc.
|
||||||
|
CREATE TABLE user_token (
|
||||||
|
user_uuid TEXT NOT NULL UNIQUE,
|
||||||
|
|
||||||
|
type TEXT NOT NULL,
|
||||||
|
token TEXT NOT NULL UNIQUE PRIMARY KEY,
|
||||||
|
|
||||||
|
created_at DATETIME NOT NULL,
|
||||||
|
expires_at DATETIME
|
||||||
|
);
|
||||||
@@ -78,20 +78,38 @@ func HandleSignUpVerifyPage(db *sql.DB) http.HandlerFunc {
|
|||||||
|
|
||||||
func HandleSignUpVerifyResponsePage(db *sql.DB) http.HandlerFunc {
|
func HandleSignUpVerifyResponsePage(db *sql.DB) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
code := r.URL.Query().Get("code")
|
token := r.URL.Query().Get("token")
|
||||||
if code == "" {
|
if token == "" {
|
||||||
utils.DoRedirect(w, r, "/auth/verify")
|
utils.DoRedirect(w, r, "/auth/verify")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
userId, err := uuid.Parse(code)
|
result, err := db.Exec(`
|
||||||
|
UPDATE user
|
||||||
|
SET email_verified = true, email_verified_at = datetime()
|
||||||
|
WHERE user_uuid = (
|
||||||
|
SELECT user_uuid
|
||||||
|
FROM user_token
|
||||||
|
WHERE type = "email_verify"
|
||||||
|
AND token = ?
|
||||||
|
);
|
||||||
|
`, token)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.DoRedirect(w, r, "/auth/verify")
|
slog.Error("Could not update user: " + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
i, err := result.RowsAffected()
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("Could not get rows affected: " + err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = db.Exec("UPDATE user SET email_verified = true, email_verified_at = datetime() WHERE user_uuid = ?", userId)
|
if i == 0 {
|
||||||
utils.DoRedirect(w, r, "/")
|
utils.DoRedirect(w, r, "/")
|
||||||
|
} else {
|
||||||
|
utils.DoRedirect(w, r, "/auth/signin")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,19 +286,31 @@ func HandleVerifyResendComp(db *sql.DB) http.HandlerFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func sendVerificationEmail(db *sql.DB, r *http.Request, userId string, email string) {
|
func sendVerificationEmail(db *sql.DB, r *http.Request, userId string, email string) {
|
||||||
registerComp := tempMail.Register(userId)
|
var b []byte = make([]byte, 32)
|
||||||
|
_, err := rand.Reader.Read(b)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("Could not generate token: " + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
token := base64.StdEncoding.EncodeToString(b)
|
||||||
|
|
||||||
var writer strings.Builder
|
_, err = db.Exec("INSERT INTO user_token (user_uuid, type, token, created_at) VALUES (?, 'email_verify', ?, datetime())", userId, token)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("Could not insert token: " + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
registerComp.Render(r.Context(), &writer)
|
var w strings.Builder
|
||||||
utils.SendMail(email, "Welcome to ME-FIT", writer.String())
|
tempMail.Register(token).Render(r.Context(), &w)
|
||||||
|
|
||||||
|
utils.SendMail(email, "Welcome to ME-FIT", w.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func tryCreateSessionAndSetCookie(r *http.Request, w http.ResponseWriter, db *sql.DB, user_uuid uuid.UUID) bool {
|
func tryCreateSessionAndSetCookie(r *http.Request, w http.ResponseWriter, db *sql.DB, user_uuid uuid.UUID) bool {
|
||||||
var session_id_bytes []byte = make([]byte, 32)
|
var session_id_bytes []byte = make([]byte, 32)
|
||||||
_, err := rand.Reader.Read(session_id_bytes)
|
_, err := rand.Reader.Read(session_id_bytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Could not generate session ID: %v", err)
|
slog.Error("Could not generate session ID: " + err.Error())
|
||||||
auth.Error("Internal Server Error").Render(r.Context(), w)
|
auth.Error("Internal Server Error").Render(r.Context(), w)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ templ Register(mailCode string) {
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h4>Thank you for Sign Up!</h4>
|
<h4>Thank you for Sign Up!</h4>
|
||||||
<p>Click <a href={ templ.URL(utils.BaseUrl + "/auth/verify-email?code=" + mailCode) }>here</a> to verify your account.</p>
|
<p>Click <a href={ templ.URL(utils.BaseUrl + "/auth/verify-email?token=" + mailCode) }>here</a> to verify your account.</p>
|
||||||
<p>Kind regards</p>
|
<p>Kind regards</p>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user