func TestResetPasswordHandlerTokenMatchestUsedPasswordReset(t *testing.T) { pool := newConnPool(t) user := &data.User{ Name: data.NewString("test"), Email: data.NewString("*****@*****.**"), } SetPassword(user, "password") userID, err := data.CreateUser(pool, user) if err != nil { t.Fatalf("repo.CreateUser returned error: %v", err) } _, localhost, _ := net.ParseCIDR("127.0.0.1/32") pwr := &data.PasswordReset{ Token: data.NewString("0123456789abcdef"), Email: data.NewString("*****@*****.**"), UserID: data.NewInt32(userID), RequestTime: data.NewTime(time.Now()), RequestIP: data.NewIPNet(*localhost), CompletionTime: data.NewTime(time.Now()), CompletionIP: data.NewIPNet(*localhost), } err = data.InsertPasswordReset(pool, pwr) if err != nil { t.Fatalf("repo.CreatePasswordReset returned error: %v", err) } buf := bytes.NewBufferString(`{"token": "0123456789abcdef", "password": "******"}`) req, err := http.NewRequest("POST", "http://example.com/", buf) if err != nil { t.Fatalf("http.NewRequest returned error: %v", err) } env := &environment{pool: pool} w := httptest.NewRecorder() ResetPasswordHandler(w, req, env) if w.Code != 404 { t.Errorf("Expected HTTP status %d, instead received %d", 404, w.Code) } user, err = data.SelectUserByPK(pool, userID) if err != nil { t.Fatalf("repo.GetUser returned error: %v", err) } if IsPassword(user, "bigsecret") { t.Error("Expected password not to be changed but it was") } }
func TestDataSessions(t *testing.T) { pool := newConnPool(t) userID, err := data.CreateUser(pool, newUser()) if err != nil { t.Fatal(err) } sessionID := []byte("deadbeef") err = data.InsertSession(pool, &data.Session{ ID: data.NewBytes(sessionID), UserID: data.NewInt32(userID), }, ) if err != nil { t.Fatal(err) } user, err := data.SelectUserBySessionID(pool, sessionID) if err != nil { t.Fatal(err) } if user.ID.Value != userID { t.Errorf("Expected %v, got %v", userID, user.ID) } err = data.DeleteSession(pool, sessionID) if err != nil { t.Fatal(err) } _, err = data.SelectUserBySessionID(pool, sessionID) if err != data.ErrNotFound { t.Fatalf("Expected %v, got %v", data.ErrNotFound, err) } err = data.DeleteSession(pool, sessionID) if err != data.ErrNotFound { t.Fatalf("Expected %v, got %v", notFound, err) } }
func TestExportOPML(t *testing.T) { pool := newConnPool(t) userID, err := data.CreateUser(pool, &data.User{ Name: data.NewString("test"), Email: data.NewString("*****@*****.**"), PasswordDigest: data.NewBytes([]byte("digest")), PasswordSalt: data.NewBytes([]byte("salt")), }) if err != nil { t.Fatal(err) } err = data.InsertSubscription(pool, userID, "http://example.com/feed.rss") if err != nil { t.Fatal(err) } req, err := http.NewRequest("GET", "http://example.com/", nil) if err != nil { t.Fatal(err) } env := &environment{pool: pool} env.user = &data.User{ID: data.NewInt32(userID), Name: data.NewString("test")} w := httptest.NewRecorder() ExportFeedsHandler(w, req, env) if w.Code != 200 { t.Fatalf("Expected HTTP status 200, instead received %d", w.Code) } expected := `<?xml version="1.0" encoding="UTF-8"?> <opml version="1.0"><head><title>The Pithy Reader Export for test</title></head><body><outline text="http://example.com/feed.rss" title="http://example.com/feed.rss" type="rss" xmlUrl="http://example.com/feed.rss"></outline></body></opml>` if w.Body.String() != expected { t.Fatalf("Expected:\n%s\nGot:\n%s\n", expected, w.Body.String()) } }
func TestResetPasswordHandlerTokenMatchestValidPasswordReset(t *testing.T) { pool := newConnPool(t) user := &data.User{ Name: data.NewString("test"), Email: data.NewString("*****@*****.**"), } SetPassword(user, "password") userID, err := data.CreateUser(pool, user) if err != nil { t.Fatalf("repo.CreateUser returned error: %v", err) } _, requestIP, _ := net.ParseCIDR("127.0.0.1/32") pwr := &data.PasswordReset{ Token: data.NewString("0123456789abcdef"), Email: data.NewString("*****@*****.**"), UserID: data.NewInt32(userID), RequestTime: data.NewTime(time.Now()), RequestIP: data.NewIPNet(*requestIP), } err = data.InsertPasswordReset(pool, pwr) if err != nil { t.Fatalf("repo.CreatePasswordReset returned error: %v", err) } buf := bytes.NewBufferString(`{"token": "0123456789abcdef", "password": "******"}`) req, err := http.NewRequest("POST", "http://example.com/", buf) if err != nil { t.Fatalf("http.NewRequest returned error: %v", err) } env := &environment{pool: pool} w := httptest.NewRecorder() ResetPasswordHandler(w, req, env) if w.Code != 200 { t.Errorf("Expected HTTP status %d, instead received %d", 200, w.Code) } user, err = data.SelectUserByPK(pool, userID) if err != nil { t.Fatalf("repo.GetUser returned error: %v", err) } if !IsPassword(user, "bigsecret") { t.Error("Expected password to be changed but it was not") } var response struct { Name string `json:"name"` SessionID string `json:"sessionID"` } decoder := json.NewDecoder(w.Body) if err := decoder.Decode(&response); err != nil { t.Errorf("Unable to decode response: %v", err) } }
func RegisterHandler(w http.ResponseWriter, req *http.Request, env *environment) { var registration struct { Name string `json:"name"` Email string `json:"email"` Password string `json:"password"` } decoder := json.NewDecoder(req.Body) if err := decoder.Decode(®istration); err != nil { w.WriteHeader(422) fmt.Fprintf(w, "Error decoding request: %v", err) return } if registration.Name == "" { w.WriteHeader(422) fmt.Fprintln(w, `Request must include the attribute "name"`) return } if len(registration.Name) > 30 { w.WriteHeader(422) fmt.Fprintln(w, `"name" must be less than 30 characters`) return } err := validatePassword(registration.Password) if err != nil { w.WriteHeader(422) fmt.Fprintln(w, err) return } user := &data.User{} user.Name = data.NewString(registration.Name) user.Email = newStringFallback(registration.Email, data.Undefined) SetPassword(user, registration.Password) userID, err := data.CreateUser(env.pool, user) if err != nil { if err, ok := err.(data.DuplicationError); ok { w.WriteHeader(422) fmt.Fprintf(w, `"%s" is already taken`, err.Field) return } else { http.Error(w, "Internal server error", http.StatusInternalServerError) return } } sessionID, err := genSessionID() if err != nil { http.Error(w, "Internal server error", http.StatusInternalServerError) return } err = data.InsertSession(env.pool, &data.Session{ ID: data.NewBytes(sessionID), UserID: data.NewInt32(userID), }, ) if err != nil { http.Error(w, "Internal server error", http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) var response struct { Name string `json:"name"` SessionID string `json:"sessionID"` } response.Name = registration.Name response.SessionID = hex.EncodeToString(sessionID) encoder := json.NewEncoder(w) encoder.Encode(response) }