Skip to content

Commit

Permalink
refactor(SPV-1106): add access endpoint errors
Browse files Browse the repository at this point in the history
  • Loading branch information
dzolt-4chain committed Oct 23, 2024
1 parent f9b0bde commit 5730152
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 27 deletions.
33 changes: 33 additions & 0 deletions bhserrors/definitions.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,24 @@
package bhserrors

// ////////////////////////////////// AUTH ERRORS

// ErrGeneric is a generic error that something went wrong
var ErrGeneric = BHSError{Message: "Something went wrong. Internal server error", StatusCode: 500, Code: "ErrGeneric"}

// ////////////////////////////////// AUTH ERRORS

// ErrMissingAuthHeader is when request does not have auth header
var ErrMissingAuthHeader = BHSError{Message: "Empty auth header", StatusCode: 401, Code: "ErrMissingAuthHeader"}

// ErrInvalidAuthHeader is when request does not have a valid auth header
var ErrInvalidAuthHeader = BHSError{Message: "Invalid auth header", StatusCode: 401, Code: "ErrInvalidAuthHeader"}

// ErrInvalidAccessToken is when access token is invalid
var ErrInvalidAccessToken = BHSError{Message: "Invalid access token", StatusCode: 401, Code: "ErrInvalidAccessToken"}

// ErrUnauthorized is a generic error when user is unauthorized to make a request
var ErrUnauthorized = BHSError{Message: "Not authorized", StatusCode: 401, Code: "ErrUnauthorized"}

// ////////////////////////////////// MERKLE ROOTS ERRORS

// ErrMerklerootNotFound is when provided merkleroot from user was not found in Block Header Service's database
Expand All @@ -10,3 +29,17 @@ var ErrMerklerootNotInLongestChain = BHSError{Message: "Provided merkleroot is n

// ErrInvalidBatchSize is when user provided incorrect batchSize
var ErrInvalidBatchSize = BHSError{Message: "batchSize must be 0 or a positive integer", Code: "ErrInvalidBatchSize", StatusCode: 400}

// ////////////////////////////////// TOKEN ERRORS

// ErrAdminTokenNotFound is when admin token was not found in Block Header Service
var ErrAdminTokenNotFound = BHSError{Message: "Admin token not found", StatusCode: 401, Code: "ErrAdminTokenNotFound"}

// ErrTokenNotFound is when token was not found in Block Header Service
var ErrTokenNotFound = BHSError{Message: "Token not found", StatusCode: 404, Code: "ErrTokenNotFound"}

// ErrCreateToken is when create token fails
var ErrCreateToken = BHSError{Message: "Failed to create new token", StatusCode: 400, Code: "ErrCreateToken"}

// ErrDeleteToken is when delete token fails
var ErrDeleteToken = BHSError{Message: "Failed to delete token", StatusCode: 400, Code: "ErrDeleteToken"}
28 changes: 18 additions & 10 deletions database/sql/tokens.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ package sql

import (
"context"
"database/sql"

"github.com/bitcoin-sv/block-headers-service/bhserrors"
"github.com/bitcoin-sv/block-headers-service/repository/dto"
"github.com/pkg/errors"
)

const (
Expand Down Expand Up @@ -39,19 +38,22 @@ func (h *HeadersDb) CreateToken(ctx context.Context, token *dto.DbToken) error {
}()

if _, err := tx.NamedExecContext(ctx, h.db.Rebind(sqlInsertToken), *token); err != nil {
return errors.Wrap(err, "failed to insert token")
return bhserrors.ErrCreateToken.Wrap(err)
}
return errors.Wrap(tx.Commit(), "failed to commit tx")

err = tx.Commit()
if err != nil {
return bhserrors.ErrCreateToken.Wrap(err)
}

return nil
}

// GetTokenByValue method will search and return token by value.
func (h *HeadersDb) GetTokenByValue(ctx context.Context, token string) (*dto.DbToken, error) {
var dbToken dto.DbToken
if err := h.db.GetContext(ctx, &dbToken, h.db.Rebind(sqlGetToken), token); err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, errors.New("could not find token")
}
return nil, errors.Wrapf(err, "failed to get token using value %s", token)
return nil, bhserrors.ErrTokenNotFound.Wrap(err)
}
return &dbToken, nil
}
Expand All @@ -67,8 +69,14 @@ func (h *HeadersDb) DeleteToken(ctx context.Context, token string) error {
}()

if _, err = tx.NamedExecContext(ctx, h.db.Rebind(sqlDeleteToken), map[string]interface{}{"token": token}); err != nil {
return errors.Wrap(err, "failed to delete token")
return bhserrors.ErrDeleteToken.Wrap(err)
}

err = tx.Commit()
if err != nil {
return bhserrors.ErrDeleteToken.Wrap(err)

}

return errors.Wrap(tx.Commit(), "failed to commit tx")
return nil
}
13 changes: 6 additions & 7 deletions transports/http/auth/auth_token_middleware.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package auth

import (
"errors"
"net/http"
"strings"

"github.com/bitcoin-sv/block-headers-service/bhserrors"
"github.com/bitcoin-sv/block-headers-service/config"
"github.com/bitcoin-sv/block-headers-service/domains"
"github.com/bitcoin-sv/block-headers-service/service"
Expand Down Expand Up @@ -34,13 +33,13 @@ func (h *TokenMiddleware) ApplyToAPI(c *gin.Context) {
if h.cfg.UseAuth {
rawToken, err := h.parseAuthHeader(c)
if err != nil {
c.AbortWithStatusJSON(http.StatusUnauthorized, err.Error())
bhserrors.AbortWithErrorResponse(c, err, nil)
return
}

token, err := h.getToken(rawToken)
if err != nil {
c.AbortWithStatusJSON(http.StatusUnauthorized, err.Error())
bhserrors.AbortWithErrorResponse(c, err, nil)
return
}

Expand All @@ -51,12 +50,12 @@ func (h *TokenMiddleware) ApplyToAPI(c *gin.Context) {
func (h *TokenMiddleware) parseAuthHeader(c *gin.Context) (string, error) {
header := c.GetHeader(authorizationHeader)
if header == "" {
return "", errors.New("empty auth header")
return "", bhserrors.ErrMissingAuthHeader
}

headerParts := strings.Split(header, " ")
if len(headerParts) != 2 || headerParts[0] != "Bearer" {
return "", errors.New("invalid auth header")
return "", bhserrors.ErrInvalidAuthHeader
}

return headerParts[1], nil
Expand All @@ -65,7 +64,7 @@ func (h *TokenMiddleware) parseAuthHeader(c *gin.Context) (string, error) {
func (h *TokenMiddleware) getToken(token string) (*domains.Token, error) {
t, err := h.tokens.GetToken(token)
if err != nil {
return nil, errors.New("invalid access token")
return nil, bhserrors.ErrInvalidAccessToken
}
return t, nil
}
12 changes: 5 additions & 7 deletions transports/http/auth/require_auth.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package auth

import (
"errors"
"net/http"

"github.com/bitcoin-sv/block-headers-service/bhserrors"
"github.com/bitcoin-sv/block-headers-service/domains"
"github.com/gin-gonic/gin"
)
Expand All @@ -17,7 +15,7 @@ func RequireAdmin(handler gin.HandlerFunc, requireAdmin bool) gin.HandlerFunc {
if err := validateToken(c); err == nil {
handler(c)
} else {
c.AbortWithStatusJSON(http.StatusUnauthorized, err.Error())
bhserrors.AbortWithErrorResponse(c, err, nil)
}
}
}
Expand All @@ -27,14 +25,14 @@ func RequireAdmin(handler gin.HandlerFunc, requireAdmin bool) gin.HandlerFunc {
func validateToken(c *gin.Context) error {
token, exist := c.Get("token")
if !exist {
return errors.New("token not found")
return bhserrors.ErrAdminTokenNotFound
}
t, ok := token.(*domains.Token)
if !ok {
return errors.New("something went wrong")
return bhserrors.ErrGeneric
}
if !t.IsAdmin {
return errors.New("not authorized")
return bhserrors.ErrUnauthorized
}
return nil // the token is valid
}
9 changes: 6 additions & 3 deletions transports/http/endpoints/api/access/endpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,23 @@ package access
import (
"net/http"

"github.com/bitcoin-sv/block-headers-service/bhserrors"
"github.com/bitcoin-sv/block-headers-service/config"
"github.com/bitcoin-sv/block-headers-service/service"
"github.com/bitcoin-sv/block-headers-service/transports/http/auth"
router "github.com/bitcoin-sv/block-headers-service/transports/http/endpoints/routes"
"github.com/gin-gonic/gin"
"github.com/rs/zerolog"
)

type handler struct {
service service.Tokens
log *zerolog.Logger
}

// NewHandler creates new endpoint handler.
func NewHandler(s *service.Services) router.APIEndpoints {
return &handler{service: s.Tokens}
return &handler{service: s.Tokens, log: s.Logger}
}

// RegisterAPIEndpoints registers routes that are part of service API.
Expand Down Expand Up @@ -63,7 +66,7 @@ func (h *handler) createToken(c *gin.Context) {
if err == nil {
c.JSON(http.StatusOK, bh)
} else {
c.JSON(http.StatusBadRequest, err.Error())
bhserrors.ErrorResponse(c, err, h.log)
}
}

Expand All @@ -84,6 +87,6 @@ func (h *handler) revokeToken(c *gin.Context) {
if err == nil {
c.JSON(http.StatusOK, "Token revoked")
} else {
c.JSON(http.StatusBadRequest, err.Error())
bhserrors.ErrorResponse(c, err, h.log)
}
}

0 comments on commit 5730152

Please sign in to comment.