Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Approriate error messages on failures #54

Open
wants to merge 13 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions api/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,14 @@ func GeneratePasswordHash(password string) ([]byte, error) {
}

func ValidatePassword(hash []byte, password string) error {
return bcrypt.CompareHashAndPassword(hash, []byte(password))
err := bcrypt.CompareHashAndPassword(hash, []byte(password))
if errors.Is(err, bcrypt.ErrMismatchedHashAndPassword) {
return &ErrPasswordDidNotMatch
}
return err
}

func CreateToken(userId int) (string, error) {
//TODO check
claims := CustomClaims{
userId,
jwt.StandardClaims{
Expand All @@ -73,16 +76,26 @@ func ValidateToken(tokenString string) (userId int, err error) {
return PubKey, nil
})

if err != nil {
if ve, ok := err.(*jwt.ValidationError); !token.Valid && ok {
authError := AuthenticationError{"unknown reason"}
if ve.Errors&jwt.ValidationErrorExpired != 0 {
authError = ErrTokenExpired
} else if ve.Errors&jwt.ValidationErrorMalformed != 0 {
authError = AuthenticationError{"not a token string: " + tokenString}
}
log.Printf("authentication failed (%v) for token %v", authError.reason, tokenString)
return 0, &authError
} else if !ok {
// not a validation error
return 0, err
}

if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
if claims, ok := token.Claims.(jwt.MapClaims); ok {
// All claim values seems to be float. So we must convert to int after assertion to float
userId = int(claims["UserId"].(float64))
log.Printf("authentication complete for user %v", userId)
} else {
return 0, errors.New("get user_id failed")
return 0, errors.New("failed to get user id from token")
}

return userId, nil
Expand Down
12 changes: 12 additions & 0 deletions api/auth/error.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package auth

type AuthenticationError struct {
reason string
}

func (e *AuthenticationError) Error() string {
return "authentication failure: " + e.reason
}

var ErrPasswordDidNotMatch = AuthenticationError{"password did not match"}
var ErrTokenExpired = AuthenticationError{"token has expired"}
59 changes: 39 additions & 20 deletions api/controller/follow.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package controller

import (
"fmt"
"net/http"
"strconv"

Expand All @@ -17,19 +18,22 @@ type Follow struct {
func ShowFollow(c *gin.Context) {
target, err := strconv.ParseUint(c.Param("id"), 0, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
e := fmt.Sprintf("failed to cummunicate with the database: %v", err.Error())
c.JSON(http.StatusBadRequest, gin.H{"error": e})
return
}

srcUserId, ok := c.MustGet("userId").(int)
if !ok {
c.JSON(http.StatusInternalServerError, "invalid user id")
e := fmt.Sprintf("invalid user id: %v", c.MustGet("userId"))
c.JSON(http.StatusInternalServerError, gin.H{"error": e})
return
}

response, err := getFollowFromDB(uint(srcUserId), uint(target))
if err != nil {
c.JSON(http.StatusInternalServerError, err.Error())
e := fmt.Sprintf("failed to cummunicate with the database: %v", err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"error": e})
return
}

Expand All @@ -39,25 +43,30 @@ func ShowFollow(c *gin.Context) {
func FollowUser(c *gin.Context) {
destUserId, err := strconv.ParseUint(c.Param("id"), 0, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
e := fmt.Sprintf("failed to cummunicate with the database: %v", err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"error": e})
return
}

srcUserId, ok := c.MustGet("userId").(int)
if !ok {
c.JSON(http.StatusInternalServerError, "invalid user id")
e := fmt.Sprintf("invalid user id: %v", c.MustGet("userId"))
c.JSON(http.StatusInternalServerError, gin.H{"error": e})
return
}

_, err = db.CreateFollow(uint(srcUserId), uint(destUserId))
if err != nil {
c.JSON(http.StatusInternalServerError, err.Error())
e := fmt.Sprintf("failed to cummunicate with the database: %v", err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"error": e})

return
}

response, err := getFollowFromDB(uint(srcUserId), uint(destUserId))
if err != nil {
c.JSON(http.StatusInternalServerError, err.Error())
e := fmt.Sprintf("failed to cummunicate with the database: %v", err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"error": e})
return
}

Expand All @@ -67,25 +76,29 @@ func FollowUser(c *gin.Context) {
func UnfollowUser(c *gin.Context) {
destUserId, err := strconv.ParseUint(c.Param("id"), 0, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
e := fmt.Sprintf("failed to cummunicate with the database: %v", err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"error": e})
return
}

srcUserId, ok := c.MustGet("userId").(int)
if !ok {
c.JSON(http.StatusInternalServerError, "invalid user id")
e := fmt.Sprintf("invalid user id: %v", c.MustGet("userId"))
c.JSON(http.StatusInternalServerError, gin.H{"error": e})
return
}

err = db.DestroyFollow(uint(srcUserId), uint(destUserId))
if err != nil {
c.JSON(http.StatusInternalServerError, err.Error())
e := fmt.Sprintf("failed to cummunicate with the database: %v", err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"error": e})
return
}

response, err := getFollowFromDB(uint(srcUserId), uint(destUserId))
if err != nil {
c.JSON(http.StatusInternalServerError, err.Error())
e := fmt.Sprintf("failed to cummunicate with the database: %v", err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"error": e})
return
}

Expand All @@ -99,19 +112,22 @@ type Followees struct {
func ShowFollowees(c *gin.Context) {
source, ok := c.MustGet("userId").(int)
if !ok {
c.JSON(http.StatusInternalServerError, "invalid user id")
e := fmt.Sprintf("invalid user id: %v", c.MustGet("userId"))
c.JSON(http.StatusBadRequest, gin.H{"error": e})
return
}

followings, err := db.GetFollowing(uint(source))
if err != nil {
c.JSON(http.StatusInternalServerError, err.Error())
e := fmt.Sprintf("failed to cummunicate with the database: %v", err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"error": e})
return
}

followees, err := follows2users(followings, true)
if err != nil {
c.JSON(http.StatusInternalServerError, err.Error())
e := fmt.Sprintf("failed to cummunicate with the database: %v", err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"error": e})
return
}

Expand All @@ -129,19 +145,22 @@ type Followers struct {
func ShowFollowers(c *gin.Context) {
source, ok := c.MustGet("userId").(int)
if !ok {
c.JSON(http.StatusInternalServerError, "invalid user id")
e := fmt.Sprintf("invalid user id: %v", c.MustGet("userId"))
c.JSON(http.StatusBadRequest, gin.H{"error": e})
return
}

followeds, err := db.GetFollowed(uint(source))
if err != nil {
c.JSON(http.StatusInternalServerError, err.Error())
e := fmt.Sprintf("failed to cummunicate with the database: %v", err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"error": e})
return
}

followers, err := follows2users(followeds, false)
if err != nil {
c.JSON(http.StatusInternalServerError, err.Error())
e := fmt.Sprintf("failed to cummunicate with the database: %v", err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"error": e})
return
}

Expand All @@ -164,9 +183,9 @@ func getFollowFromDB(source, target uint) (Follow, error) {
}

return Follow{
Target: target,
Target: target,
Following: following,
Followed: followed,
Followed: followed,
}, nil
}

Expand All @@ -193,4 +212,4 @@ func follows2users(follows []db.Follow, forDest bool) ([]User, error) {
}

return users, nil
}
}
10 changes: 7 additions & 3 deletions api/controller/matching.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package controller

import (
"fmt"
"math/rand"
"net/http"

Expand All @@ -16,13 +17,15 @@ type MatchResponse struct {
func MakeMatch(c *gin.Context) {
userId, ok := c.MustGet("userId").(int)
if !ok {
c.JSON(http.StatusInternalServerError, "invalid user id")
e := fmt.Sprintf("invalid user id: %v", c.MustGet("userId"))
c.JSON(http.StatusBadRequest, gin.H{"error": e})
return
}

targetUsers, err := getMatchUsers(uint(userId))
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
e := fmt.Sprintf("failed to cummunicate with the database: %v", err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"error": e})
return
}

Expand All @@ -35,7 +38,8 @@ func MakeMatch(c *gin.Context) {

rawChatroom, err := db.CreateRoom([]uint{uint(userId), matchedUser.ID})
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
e := fmt.Sprintf("failed to cummunicate with the database: %v", err.Error())
c.JSON(http.StatusInternalServerError, gin.H{"error": e})
return
}
chatroom := fromDBRoom(rawChatroom)
Expand Down
Loading