diff --git a/bhserrors/definitions.go b/bhserrors/definitions.go index 2cac823c..bfbd6faa 100644 --- a/bhserrors/definitions.go +++ b/bhserrors/definitions.go @@ -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 @@ -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"} diff --git a/database/sql/tokens.go b/database/sql/tokens.go index 32d4079f..96ed0b3c 100644 --- a/database/sql/tokens.go +++ b/database/sql/tokens.go @@ -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 ( @@ -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 } @@ -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 } diff --git a/transports/http/auth/auth_token_middleware.go b/transports/http/auth/auth_token_middleware.go index dc736d38..1f8a16a2 100644 --- a/transports/http/auth/auth_token_middleware.go +++ b/transports/http/auth/auth_token_middleware.go @@ -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" @@ -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 } @@ -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 @@ -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 } diff --git a/transports/http/auth/require_auth.go b/transports/http/auth/require_auth.go index 20b111e7..24e0e5c6 100644 --- a/transports/http/auth/require_auth.go +++ b/transports/http/auth/require_auth.go @@ -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" ) @@ -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) } } } @@ -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 } diff --git a/transports/http/endpoints/api/access/endpoints.go b/transports/http/endpoints/api/access/endpoints.go index fd0e9c8c..4e3dea43 100644 --- a/transports/http/endpoints/api/access/endpoints.go +++ b/transports/http/endpoints/api/access/endpoints.go @@ -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. @@ -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) } } @@ -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) } }