コード例 #1
0
ファイル: http_test.go プロジェクト: jackc/tpr
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")
	}
}
コード例 #2
0
ファイル: http_test.go プロジェクト: jackc/tpr
func TestResetPasswordHandlerTokenMatchestInvalidPasswordReset(t *testing.T) {
	pool := newConnPool(t)

	_, localhost, _ := net.ParseCIDR("127.0.0.1/32")
	pwr := &data.PasswordReset{
		Token:       data.NewString("0123456789abcdef"),
		Email:       data.NewString("*****@*****.**"),
		RequestTime: data.NewTime(time.Now()),
		RequestIP:   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)
	}
}
コード例 #3
0
ファイル: data_test.go プロジェクト: jackc/tpr
func TestDataDeleteSubscription(t *testing.T) {
	pool := newConnPool(t)

	userID, err := data.CreateUser(pool, newUser())
	if err != nil {
		t.Fatal(err)
	}

	err = data.InsertSubscription(pool, userID, "http://foo")
	if err != nil {
		t.Fatal(err)
	}

	subscriptions, err := data.SelectSubscriptions(pool, userID)
	if err != nil {
		t.Fatal(err)
	}
	if len(subscriptions) != 1 {
		t.Fatalf("Found %d subscriptions, expected 1", len(subscriptions))
	}
	feedID := subscriptions[0].FeedID.Value

	update := &data.ParsedFeed{Name: "baz", Items: []data.ParsedItem{
		{URL: "http://baz/bar", Title: "Baz", PublicationTime: data.NewTime(time.Now())},
	}}

	nullString := data.String{Status: data.Null}

	err = data.UpdateFeedWithFetchSuccess(pool, feedID, update, nullString, time.Now().Add(-20*time.Minute))
	if err != nil {
		t.Fatal(err)
	}

	err = data.DeleteSubscription(pool, userID, feedID)
	if err != nil {
		t.Fatal(err)
	}

	subscriptions, err = data.SelectSubscriptions(pool, userID)
	if err != nil {
		t.Fatal(err)
	}
	if len(subscriptions) != 0 {
		t.Errorf("Found %d subscriptions, expected 0", len(subscriptions))
	}

	// feed should have been deleted as it was the last user
	staleFeeds, err := data.GetFeedsUncheckedSince(pool, time.Now())
	if err != nil {
		t.Fatal(err)
	}
	if len(staleFeeds) != 0 {
		t.Errorf("Found %d staleFeeds, expected 0", len(staleFeeds))
	}
}
コード例 #4
0
ファイル: feed_updater.go プロジェクト: jackc/tpr
// Try multiple time formats one after another until one works or all fail
func parseTime(value string) (data.Time, error) {
	formats := []string{
		"2006-01-02T15:04:05-07:00",
		"2006-01-02T15:04:05Z",
		time.RFC822,
		"02 Jan 2006 15:04 MST",           // RFC822 with 4 digit year
		"02 Jan 2006 15:04:05 MST",        // RFC822 with 4 digit year and seconds
		"Mon, _2 Jan 2006 15:04:05 MST",   // RFC1123 with 1-2 digit days
		"Mon, _2 Jan 2006 15:04:05 -0700", // RFC1123 with numeric time zone and with 1-2 digit days
		"Mon, _2 Jan 2006",
		"2006-01-02",
	}
	for _, f := range formats {
		t, err := time.Parse(f, value)
		if err == nil {
			return data.NewTime(t), nil
		}
	}

	return data.Time{}, errors.New("Unable to parse time")
}
コード例 #5
0
ファイル: data_test.go プロジェクト: jackc/tpr
func TestDataUpdateFeedWithFetchSuccess(t *testing.T) {
	pool := newConnPool(t)

	userID, err := data.CreateUser(pool, newUser())
	if err != nil {
		t.Fatal(err)
	}

	now := time.Now()

	url := "http://bar"
	err = data.InsertSubscription(pool, userID, url)
	if err != nil {
		t.Fatal(err)
	}

	subscriptions, err := data.SelectSubscriptions(pool, userID)
	if err != nil {
		t.Fatal(err)
	}
	if len(subscriptions) != 1 {
		t.Fatalf("Found %d subscriptions, expected 1", len(subscriptions))
	}
	feedID := subscriptions[0].FeedID.Value

	update := &data.ParsedFeed{Name: "baz", Items: []data.ParsedItem{
		{URL: "http://baz/bar", Title: "Baz", PublicationTime: data.NewTime(now)},
	}}

	nullString := data.String{Status: data.Null}

	err = data.UpdateFeedWithFetchSuccess(pool, feedID, update, nullString, now)
	if err != nil {
		t.Fatal(err)
	}

	buffer := &bytes.Buffer{}
	err = data.CopyUnreadItemsAsJSONByUserID(pool, buffer, userID)
	if err != nil {
		t.Fatal(err)
	}

	type UnreadItemsFromJSON struct {
		ID int32 `json:id`
	}

	var unreadItems []UnreadItemsFromJSON
	err = json.Unmarshal(buffer.Bytes(), &unreadItems)
	if err != nil {
		t.Fatal(err)
	}
	if len(unreadItems) != 1 {
		t.Fatalf("Found %d unreadItems, expected 1", len(unreadItems))
	}

	// Update again and ensure item does not get created again
	err = data.UpdateFeedWithFetchSuccess(pool, feedID, update, nullString, now)
	if err != nil {
		t.Fatal(err)
	}

	buffer.Reset()
	err = data.CopyUnreadItemsAsJSONByUserID(pool, buffer, userID)
	if err != nil {
		t.Fatal(err)
	}

	err = json.Unmarshal(buffer.Bytes(), &unreadItems)
	if err != nil {
		t.Fatal(err)
	}
	if len(unreadItems) != 1 {
		t.Fatalf("Found %d unreadItems, expected 1", len(unreadItems))
	}
}
コード例 #6
0
ファイル: http_test.go プロジェクト: jackc/tpr
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)
	}
}
コード例 #7
0
ファイル: http.go プロジェクト: jackc/tpr
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
	}
}
コード例 #8
0
ファイル: feed_updater_test.go プロジェクト: jackc/tpr
    </item>
    <item>
      <title>Blizzard</title>
      <link>http://example.org/blizzard</link>
      <pubDate>Sat, 04 Jan 2014 08:15:00 GMT</pubDate>
    </item>
  </channel>
</rss>
</xml>`),
		&data.ParsedFeed{
			Name: "News",
			Items: []data.ParsedItem{
				{
					Title:           "Snow Storm",
					URL:             "http://example.org/snow-storm",
					PublicationTime: data.NewTime(time.Date(2014, 1, 3, 22, 45, 0, 0, time.UTC)),
				},
				{
					Title:           "Blizzard",
					URL:             "http://example.org/blizzard",
					PublicationTime: data.NewTime(time.Date(2014, 1, 4, 8, 15, 0, 0, time.UTC)),
				},
			}},
		"",
	},
	{"RSS - v1",
		[]byte(`<?xml version='1.0' encoding='UTF-8'?>
<rdf>
  <channel>
    <title>News</title>
  </channel>