func TestDataUsersLifeCycle(t *testing.T) { pool := newConnPool(t) input := &data.User{ Name: data.NewString("test"), Email: data.NewString("*****@*****.**"), PasswordDigest: data.NewBytes([]byte("digest")), PasswordSalt: data.NewBytes([]byte("salt")), } userID, err := data.CreateUser(pool, input) if err != nil { t.Fatal(err) } user, err := data.SelectUserByName(pool, input.Name.Value) if err != nil { t.Fatal(err) } if user.ID.Value != userID { t.Errorf("Expected %v, got %v", userID, user.ID) } if user.Name != input.Name { t.Errorf("Expected %v, got %v", input.Name, user.Name) } if user.Email != input.Email { t.Errorf("Expected %v, got %v", input.Email, user.Email) } if bytes.Compare(user.PasswordDigest.Value, input.PasswordDigest.Value) != 0 { t.Errorf("Expected user (%v) and input (%v) PasswordDigest to match, but they did not", user.PasswordDigest, input.PasswordDigest) } if bytes.Compare(user.PasswordSalt.Value, input.PasswordSalt.Value) != 0 { t.Errorf("Expected user (%v), and input (%v) PasswordSalt to match, but they did not", user.PasswordSalt, input.PasswordSalt) } user, err = data.SelectUserByEmail(pool, input.Email.Value) if err != nil { t.Fatal(err) } if user.ID.Value != userID { t.Errorf("Expected %v, got %v", userID, user.ID) } if user.Name != input.Name { t.Errorf("Expected %v, got %v", input.Name, user.Name) } if user.Email != input.Email { t.Errorf("Expected %v, got %v", input.Email, user.Email) } if bytes.Compare(user.PasswordDigest.Value, input.PasswordDigest.Value) != 0 { t.Errorf("Expected user (%v) and input (%v) PasswordDigest to match, but they did not", user.PasswordDigest, input.PasswordDigest) } if bytes.Compare(user.PasswordSalt.Value, input.PasswordSalt.Value) != 0 { t.Errorf("Expected user (%v), and input (%v) PasswordSalt to match, but they did not", user.PasswordSalt, input.PasswordSalt) } user, err = data.SelectUserByPK(pool, userID) if err != nil { t.Fatal(err) } if user.ID.Value != userID { t.Errorf("Expected %v, got %v", userID, user.ID) } if user.Name != input.Name { t.Errorf("Expected %v, got %v", input.Name, user.Name) } if user.Email != input.Email { t.Errorf("Expected %v, got %v", input.Email, user.Email) } if bytes.Compare(user.PasswordDigest.Value, input.PasswordDigest.Value) != 0 { t.Errorf("Expected user (%v) and input (%v) PasswordDigest to match, but they did not", user.PasswordDigest, input.PasswordDigest) } if bytes.Compare(user.PasswordSalt.Value, input.PasswordSalt.Value) != 0 { t.Errorf("Expected user (%v), and input (%v) PasswordSalt to match, but they did not", user.PasswordSalt, input.PasswordSalt) } }
func RequestPasswordResetHandler(w http.ResponseWriter, req *http.Request, env *environment) { pwr := &data.PasswordReset{} pwr.RequestTime = data.NewTime(time.Now()) if host, _, err := net.SplitHostPort(req.RemoteAddr); err == nil { if ip := net.ParseIP(host); ip != nil { mask := net.CIDRMask(len(ip)*8, len(ip)*8) pwr.RequestIP = data.NewIPNet(net.IPNet{IP: ip, Mask: mask}) } } token, err := genLostPasswordToken() if err != nil { w.WriteHeader(500) fmt.Fprintln(w, `Internal server error`) env.logger.Error("getLostPasswordToken failed", "error", err) return } pwr.Token = data.NewString(token) var reset struct { Email string `json:"email"` } decoder := json.NewDecoder(req.Body) if err := decoder.Decode(&reset); err != nil { w.WriteHeader(422) fmt.Fprintf(w, "Error decoding request: %v", err) return } if reset.Email == "" { w.WriteHeader(422) fmt.Fprint(w, "Error decoding request: missing email") return } pwr.Email = data.NewString(reset.Email) user, err := data.SelectUserByEmail(env.pool, reset.Email) switch err { case nil: pwr.UserID = user.ID case data.ErrNotFound: default: w.WriteHeader(500) fmt.Fprintln(w, `Internal server error`) return } err = data.InsertPasswordReset(env.pool, pwr) if err != nil { w.WriteHeader(500) fmt.Fprintln(w, `Internal server error`) env.logger.Error("repo.CreatePasswordReset failed", "error", err) return } if user == nil { env.logger.Warn("Password reset requested for missing email", "email", reset.Email) return } if env.mailer == nil { w.WriteHeader(500) fmt.Fprintln(w, `Internal server error`) env.logger.Error("Mail is not configured -- cannot send password reset email") return } err = env.mailer.SendPasswordResetMail(reset.Email, token) if err != nil { w.WriteHeader(500) fmt.Fprintln(w, `Internal server error`) env.logger.Error("env.mailer.SendPasswordResetMail failed", "error", err) return } }