Skip to content

Commit 0a8e794

Browse files
committed
Fix password has comparison
1 parent 19dca4b commit 0a8e794

File tree

10 files changed

+99
-65
lines changed

10 files changed

+99
-65
lines changed

.env

+26-28
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,35 @@
1-
# API_PORT=8080
1+
# Postgres Live
2+
DB_HOST=127.0.0.1
3+
DB_DRIVER=postgres
4+
API_SECRET=98hbun98h #This is used when creating a JWT. It can be anything you want
5+
DB_USER=steven
6+
DB_PASSWORD=
7+
DB_NAME=fullstack_api
8+
DB_PORT=5432 #Default postgres port
29

3-
# # Postgres
10+
# Postgres Test
11+
TestDbHost=127.0.0.1
12+
TestDbDriver=postgres
13+
TestApiSecret=98hbun98h
14+
TestDbUser=steven
15+
TestDbPassword=
16+
TestDbName=fullstack_api_test
17+
TestDbPort=5432
18+
19+
# Mysql Live
420
# DB_HOST=127.0.0.1
5-
# DB_DRIVER=postgres
6-
# API_SECRET=98hbun98h
21+
# DB_DRIVER=mysql
22+
# API_SECRET=98hbun98h #This is used when creating a JWT. It can be anything you want
723
# DB_USER=steven
8-
# DB_PASSWORD=
24+
# DB_PASSWORD=here
925
# DB_NAME=fullstack_api
10-
# DB_PORT=5432
26+
# DB_PORT=3306 #Default mysql port
1127

12-
# # Test Postgres
28+
# Mysql Test
1329
# TestDbHost=127.0.0.1
14-
# TestDbDriver=postgres
30+
# TestDbDriver=mysql
1531
# TestApiSecret=98hbun98h
1632
# TestDbUser=steven
17-
# TestDbPassword=
33+
# TestDbPassword=here
1834
# TestDbName=fullstack_api_test
19-
# TestDbPort=5432
20-
21-
# Mysql
22-
DB_HOST=127.0.0.1
23-
DB_DRIVER=mysql
24-
API_SECRET=98hbun98h
25-
DB_USER=steven
26-
DB_PASSWORD=here
27-
DB_NAME=fullstack_api
28-
DB_PORT=3306
29-
30-
# Test Mysql
31-
TestDbHost=127.0.0.1
32-
TestDbDriver=mysql
33-
TestApiSecret=98hbun98h
34-
TestDbUser=steven
35-
TestDbPassword=here
36-
TestDbName=fullstack_api_test
37-
TestDbPort=3306
35+
# TestDbPort=3306

api/auth/token.go

+5-4
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@ package auth
33
import (
44
"fmt"
55
"net/http"
6+
"os"
67
"strconv"
78
"strings"
89
"time"
910

1011
jwt "github.com/dgrijalva/jwt-go"
1112
"github.com/victorsteven/fullstack/api/utils/console"
12-
"github.com/victorsteven/fullstack/config"
1313
)
1414

1515
func CreateToken(user_id uint32) (string, error) {
@@ -19,7 +19,8 @@ func CreateToken(user_id uint32) (string, error) {
1919
// claims["exp"] = time.Now().Add(time.Hour * 1).Unix()
2020
claims["exp"] = time.Now().Add(time.Hour * 24).Unix()
2121
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
22-
return token.SignedString(config.SECRETKEY)
22+
return token.SignedString([]byte(os.Getenv("API_SECRET")))
23+
2324
}
2425

2526
func TokenValid(r *http.Request) error {
@@ -28,7 +29,7 @@ func TokenValid(r *http.Request) error {
2829
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
2930
return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
3031
}
31-
return config.SECRETKEY, nil
32+
return []byte(os.Getenv("API_SECRET")), nil
3233
})
3334
if err != nil {
3435
return err
@@ -59,7 +60,7 @@ func ExtractTokenID(r *http.Request) (uint32, error) {
5960
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
6061
return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
6162
}
62-
return config.SECRETKEY, nil
63+
return []byte(os.Getenv("API_SECRET")), nil
6364
})
6465
if err != nil {
6566
return 0, err

api/controllers/login_controller.go

+10-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import (
99
"github.com/victorsteven/fullstack/api/models"
1010
"github.com/victorsteven/fullstack/api/responses"
1111
"github.com/victorsteven/fullstack/api/utils/channels"
12+
"github.com/victorsteven/fullstack/api/utils/formaterror"
13+
"golang.org/x/crypto/bcrypt"
1214
)
1315

1416
func (server *Server) Login(w http.ResponseWriter, r *http.Request) {
@@ -32,7 +34,8 @@ func (server *Server) Login(w http.ResponseWriter, r *http.Request) {
3234
}
3335
token, err := server.SignIn(user.Email, user.Password)
3436
if err != nil {
35-
responses.ERROR(w, http.StatusUnprocessableEntity, err)
37+
formattedError := formaterror.FormatError(err.Error())
38+
responses.ERROR(w, http.StatusUnprocessableEntity, formattedError)
3639
return
3740
}
3841
responses.JSON(w, http.StatusOK, token)
@@ -51,6 +54,12 @@ func (server *Server) SignIn(email, password string) (string, error) {
5154
ch <- false
5255
return
5356
}
57+
58+
err = models.VerifyPassword(user.Password, password)
59+
if err != nil && err == bcrypt.ErrMismatchedHashAndPassword {
60+
ch <- false
61+
return
62+
}
5463
ch <- true
5564
}(done)
5665

api/models/Post.go

-2
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ type Post struct {
1818
AuthorID uint32 `gorm:"not null" json:"author_id"`
1919
CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"`
2020
UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"updated_at"`
21-
// CreatedAt time.Time `json:"created_at"`
22-
// UpdatedAt time.Time `json:"updated_at"`
2321
}
2422

2523
func (p *Post) Prepare() {

api/models/User.go

+10-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ import (
88

99
"github.com/badoux/checkmail"
1010
"github.com/jinzhu/gorm"
11-
"github.com/victorsteven/fullstack/api/security"
1211
"github.com/victorsteven/fullstack/api/utils/channels"
12+
"golang.org/x/crypto/bcrypt"
1313
)
1414

1515
type User struct {
@@ -21,8 +21,16 @@ type User struct {
2121
UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"updated_at"`
2222
}
2323

24+
func Hash(password string) ([]byte, error) {
25+
return bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
26+
}
27+
28+
func VerifyPassword(hashedPassword, password string) error {
29+
return bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password))
30+
}
31+
2432
func (u *User) BeforeSave() error {
25-
hashedPassword, err := security.Hash(u.Password)
33+
hashedPassword, err := Hash(u.Password)
2634
if err != nil {
2735
return err
2836
}

api/security/password.go

-11
This file was deleted.

api/utils/formaterror/formaterror.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ func FormatError(err string) error {
1818
if strings.Contains(err, "title") {
1919
return errors.New("Title Already Taken")
2020
}
21-
22-
return nil
21+
if strings.Contains(err, "hashedPassword") {
22+
return errors.New("Incorrect Password")
23+
}
24+
return errors.New("Incorrect Details")
2325
}

tests/controllertests/login_controller_test.go

+39-10
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package controllertests
33
import (
44
"bytes"
55
"encoding/json"
6+
"errors"
67
"fmt"
78
"log"
89
"net/http"
@@ -18,18 +19,42 @@ func TestSignIn(t *testing.T) {
1819
if err != nil {
1920
log.Fatal(err)
2021
}
21-
2222
user, err := seedOneUser()
2323
if err != nil {
2424
fmt.Printf("This is the error %v\n", err)
2525
}
26-
fmt.Printf("This is the user: %v\n", user)
2726

28-
token, err := server.SignIn(user.Email, user.Password)
29-
if err != nil {
30-
log.Fatal(err)
27+
samples := []struct {
28+
email string
29+
password string
30+
errorMessage string
31+
}{
32+
{
33+
email: user.Email,
34+
password: "password", //Note the password has to be this, not the hashed one from the database
35+
errorMessage: "",
36+
},
37+
{
38+
email: user.Email,
39+
password: "Wrong password",
40+
errorMessage: "crypto/bcrypt: hashedPassword is not the hash of the given password",
41+
},
42+
{
43+
email: "Wrong email",
44+
password: "password",
45+
errorMessage: "record not found",
46+
},
47+
}
48+
49+
for _, v := range samples {
50+
51+
token, err := server.SignIn(v.email, v.password)
52+
if err != nil {
53+
assert.Equal(t, err, errors.New(v.errorMessage))
54+
} else {
55+
assert.NotEqual(t, token, "")
56+
}
3157
}
32-
assert.NotEqual(t, token, "")
3358
}
3459

3560
func TestLogin(t *testing.T) {
@@ -40,7 +65,6 @@ func TestLogin(t *testing.T) {
4065
if err != nil {
4166
fmt.Printf("This is the error %v\n", err)
4267
}
43-
4468
samples := []struct {
4569
inputJSON string
4670
statusCode int
@@ -53,10 +77,15 @@ func TestLogin(t *testing.T) {
5377
statusCode: 200,
5478
errorMessage: "",
5579
},
80+
{
81+
inputJSON: `{"email": "pet@gmail.com", "password": "wrong password"}`,
82+
statusCode: 422,
83+
errorMessage: "Incorrect Password",
84+
},
5685
{
5786
inputJSON: `{"email": "frank@gmail.com", "password": "password"}`,
5887
statusCode: 422,
59-
errorMessage: "record not found",
88+
errorMessage: "Incorrect Details",
6089
},
6190
{
6291
inputJSON: `{"email": "kangmail.com", "password": "password"}`,
@@ -84,7 +113,7 @@ func TestLogin(t *testing.T) {
84113

85114
req, err := http.NewRequest("POST", "/login", bytes.NewBufferString(v.inputJSON))
86115
if err != nil {
87-
log.Fatalf("this is the error: %v", err)
116+
t.Errorf("this is the error: %v", err)
88117
}
89118
rr := httptest.NewRecorder()
90119
handler := http.HandlerFunc(server.Login)
@@ -99,7 +128,7 @@ func TestLogin(t *testing.T) {
99128
responseMap := make(map[string]interface{})
100129
err = json.Unmarshal([]byte(rr.Body.String()), &responseMap)
101130
if err != nil {
102-
fmt.Printf("Cannot convert to json: %v", err)
131+
t.Errorf("Cannot convert to json: %v", err)
103132
}
104133
assert.Equal(t, responseMap["error"], v.errorMessage)
105134
}

tests/controllertests/post_controller_test.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ func TestCreatePost(t *testing.T) {
2525
if err != nil {
2626
log.Fatalf("Cannot seed user %v\n", err)
2727
}
28-
token, err := server.SignIn(user.Email, user.Password)
28+
token, err := server.SignIn(user.Email, "password") //Note the password in the database is already hashed, we want unhashed
2929
if err != nil {
3030
log.Fatalf("cannot login: %v\n", err)
3131
}
@@ -226,7 +226,7 @@ func TestUpdatePost(t *testing.T) {
226226
continue
227227
}
228228
PostUserEmail = user.Email
229-
PostUserPassword = user.Password
229+
PostUserPassword = "password" //Note the password in the database is already hashed, we want unhashed
230230
}
231231
//Login the user and get the authentication token
232232
token, err := server.SignIn(PostUserEmail, PostUserPassword)
@@ -375,7 +375,7 @@ func TestDeletePost(t *testing.T) {
375375
continue
376376
}
377377
PostUserEmail = user.Email
378-
PostUserPassword = user.Password
378+
PostUserPassword = "password" //Note the password in the database is already hashed, we want unhashed
379379
}
380380
//Login the user and get the authentication token
381381
token, err := server.SignIn(PostUserEmail, PostUserPassword)

tests/controllertests/user_controller_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ func TestUpdateUser(t *testing.T) {
194194
}
195195
AuthID = user.ID
196196
AuthEmail = user.Email
197-
AuthPassword = user.Password
197+
AuthPassword = "password" //Note the password in the database is already hashed, we want unhashed
198198
}
199199
//Login the user and get the authentication token
200200
token, err := server.SignIn(AuthEmail, AuthPassword)
@@ -342,7 +342,7 @@ func TestDeleteUser(t *testing.T) {
342342
}
343343
AuthID = user.ID
344344
AuthEmail = user.Email
345-
AuthPassword = user.Password
345+
AuthPassword = "password" ////Note the password in the database is already hashed, we want unhashed
346346
}
347347
//Login the user and get the authentication token
348348
token, err := server.SignIn(AuthEmail, AuthPassword)

0 commit comments

Comments
 (0)