From e50ffaaf9e1f24f853e81b2444e7b2f0977ea470 Mon Sep 17 00:00:00 2001 From: tamsin johnson Date: Wed, 7 Feb 2024 15:54:12 -0800 Subject: [PATCH] lets-go:11.3 signup with bcrypt --- snippetbox/cmd/web/handlers.go | 21 ++++++++++++----- snippetbox/db/initdb.d/init.sql | 2 +- snippetbox/go.mod | 1 + snippetbox/go.sum | 2 ++ snippetbox/internal/models/users.go | 35 +++++++++++++++++++---------- 5 files changed, 42 insertions(+), 19 deletions(-) diff --git a/snippetbox/cmd/web/handlers.go b/snippetbox/cmd/web/handlers.go index 50f03dd..b73a2b1 100644 --- a/snippetbox/cmd/web/handlers.go +++ b/snippetbox/cmd/web/handlers.go @@ -142,13 +142,22 @@ func (app *application) userSignupPost(w http.ResponseWriter, r *http.Request) { return } - // id, err := app.users.Insert(form.Username, form.Email, form.Password) - // if err != nil { - // app.serverError(w, r, err) - // return - // } + err = app.users.Insert(form.Username, form.Email, form.Password) + if err != nil { + if errors.Is(err, models.ErrDuplicateEmail) { + form.AddFieldError("email", "Email address is already in use") - app.sessionManager.Put(r.Context(), "flash", fmt.Sprintf("CREATED A USER! (%d)", 1)) + data := app.newTemplateData(r) + data.Form = form + app.render(w, r, http.StatusUnprocessableEntity, "signup.tmpl", data) + } else { + app.serverError(w, r, err) + } + + return + } + + app.sessionManager.Put(r.Context(), "flash", fmt.Sprintf("Signup was successful (%s). Please log in.", form.Username)) http.Redirect(w, r, "/", http.StatusSeeOther) } diff --git a/snippetbox/db/initdb.d/init.sql b/snippetbox/db/initdb.d/init.sql index b940096..4d6d707 100644 --- a/snippetbox/db/initdb.d/init.sql +++ b/snippetbox/db/initdb.d/init.sql @@ -26,7 +26,7 @@ CREATE TABLE users ( username VARCHAR(255) NOT NULL, email VARCHAR(255) NOT NULL, hashed_password CHAR(60) NOT NULL, - created DATETIME NOT NULL, + created DATETIME NOT NULL ); ALTER TABLE users ADD CONSTRAINT users_uc_email UNIQUE (email); diff --git a/snippetbox/go.mod b/snippetbox/go.mod index ee02b0b..b0f5f89 100644 --- a/snippetbox/go.mod +++ b/snippetbox/go.mod @@ -9,4 +9,5 @@ require ( github.com/go-sql-driver/mysql v1.7.1 // indirect github.com/julienschmidt/httprouter v1.3.0 // indirect github.com/justinas/alice v1.2.0 // indirect + golang.org/x/crypto v0.19.0 // indirect ) diff --git a/snippetbox/go.sum b/snippetbox/go.sum index 5c3c4b5..7fb4bff 100644 --- a/snippetbox/go.sum +++ b/snippetbox/go.sum @@ -11,3 +11,5 @@ github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4d github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/justinas/alice v1.2.0 h1:+MHSA/vccVCF4Uq37S42jwlkvI2Xzl7zTPCN5BnZNVo= github.com/justinas/alice v1.2.0/go.mod h1:fN5HRH/reO/zrUflLfTN43t3vXvKzvZIENsNEe7i7qA= +golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= diff --git a/snippetbox/internal/models/users.go b/snippetbox/internal/models/users.go index 9ee2226..8826b8a 100644 --- a/snippetbox/internal/models/users.go +++ b/snippetbox/internal/models/users.go @@ -2,7 +2,12 @@ package models import ( "database/sql" + "errors" + "strings" "time" + + "github.com/go-sql-driver/mysql" + "golang.org/x/crypto/bcrypt" ) type User struct { @@ -18,21 +23,27 @@ type UserModel struct { } // Insert -func (m *UserModel) Insert(username, email, password string) (int, error) { - // stmt := `INSERT INTO users (username, email, password, created) - // VALUES(?, ?, ?, UTC_TIMESTAMP())` +func (m *UserModel) Insert(username, email, password string) error { + hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), 15) + if err != nil { + return err + } - // result, err := m.DB.Exec(stmt, username, email, password) - // if err != nil { - // return 0, err - // } + stmt := `INSERT INTO users (username, email, hashed_password, created) + VALUES(?, ?, ?, UTC_TIMESTAMP())` - // id, err := result.LastInsertId() - // if err != nil { - // return 0, err - // } + _, err = m.DB.Exec(stmt, username, email, string(hashedPassword)) + if err != nil { + var mySQLError *mysql.MySQLError + if errors.As(err, &mySQLError) { + if mySQLError.Number == 1062 && strings.Contains(mySQLError.Message, "users_uc_email") { + return ErrDuplicateEmail + } + } + return err + } - return 0, nil + return nil } // Authenticate