MF-1348 - Add transport errors logging (#1544)

* MF-1348 - Add go-kit transport level logging

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Fix reviews

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Fix reviews

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Fix merge

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Fix remark

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Fix go test flags

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Use httputil errors in things and http service

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Fix SDK tests

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Use httputil errors in certs and provision service

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Use httputil errors in consumers service

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* General renaming and add ErrMissingToken

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Rename httputil -> apiutil and use errors in users servive

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Use apiutil errors in auth, bootstrap, readers, things and twins

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Replace errors.Contain by comparison

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Fix remarks

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Simplify validateID

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Simplify validateID

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Simplify and rename ExtractAuthToken -> ExtractBearerToken

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Fix readers

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Fix auth key test and remarks

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Improve comment

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Simplify validateUUID check

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

* Fix typo

Signed-off-by: Manuel Imperiale <manuel.imperiale@gmail.com>

Co-authored-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>
This commit is contained in:
Manuel Imperiale
2022-03-03 17:13:46 +01:00
committed by GitHub
parent cc5d5195ab
commit e5278c463f
88 changed files with 1026 additions and 964 deletions
+1 -1
View File
@@ -109,7 +109,7 @@ components:
parameters:
Authorization:
name: Authorization
description: |
description: |
Thing or User access token:
* For thing access use "Authorization: Thing <thing_key>"
* For user access use "Authorization: Bearer <user_token>"
+4 -4
View File
@@ -183,7 +183,7 @@ func (client grpcClient) AddPolicy(ctx context.Context, in *mainflux.AddPolicyRe
ctx, close := context.WithTimeout(ctx, client.timeout)
defer close()
res, err := client.addPolicy(ctx, addPolicyReq{Act: in.GetAct(), Obj: in.GetObj(), Sub: in.GetSub()})
res, err := client.addPolicy(ctx, policyReq{Act: in.GetAct(), Obj: in.GetObj(), Sub: in.GetSub()})
if err != nil {
return &mainflux.AddPolicyRes{}, err
}
@@ -198,7 +198,7 @@ func decodeAddPolicyResponse(_ context.Context, grpcRes interface{}) (interface{
}
func encodeAddPolicyRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
req := grpcReq.(addPolicyReq)
req := grpcReq.(policyReq)
return &mainflux.AddPolicyReq{
Sub: req.Sub,
Obj: req.Obj,
@@ -210,7 +210,7 @@ func (client grpcClient) DeletePolicy(ctx context.Context, in *mainflux.DeletePo
ctx, close := context.WithTimeout(ctx, client.timeout)
defer close()
res, err := client.deletePolicy(ctx, deletePolicyReq{Act: in.GetAct(), Obj: in.GetObj(), Sub: in.GetSub()})
res, err := client.deletePolicy(ctx, policyReq{Act: in.GetAct(), Obj: in.GetObj(), Sub: in.GetSub()})
if err != nil {
return &mainflux.DeletePolicyRes{}, err
}
@@ -225,7 +225,7 @@ func decodeDeletePolicyResponse(_ context.Context, grpcRes interface{}) (interfa
}
func encodeDeletePolicyRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
req := grpcReq.(deletePolicyReq)
req := grpcReq.(policyReq)
return &mainflux.DeletePolicyReq{
Sub: req.Sub,
Obj: req.Obj,
+2 -2
View File
@@ -72,7 +72,7 @@ func authorizeEndpoint(svc auth.Service) endpoint.Endpoint {
func addPolicyEndpoint(svc auth.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
req := request.(addPolicyReq)
req := request.(policyReq)
if err := req.validate(); err != nil {
return addPolicyRes{}, err
}
@@ -87,7 +87,7 @@ func addPolicyEndpoint(svc auth.Service) endpoint.Endpoint {
func deletePolicyEndpoint(svc auth.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
req := request.(deletePolicyReq)
req := request.(policyReq)
if err := req.validate(); err != nil {
return deletePolicyRes{}, err
}
+2 -2
View File
@@ -176,11 +176,11 @@ func TestIdentify(t *testing.T) {
code: codes.Unauthenticated,
},
{
desc: "identify user that doesn't exist",
desc: "identify user with empty token",
token: "",
idt: mainflux.UserIdentity{},
err: status.Error(codes.InvalidArgument, "received invalid token request"),
code: codes.InvalidArgument,
code: codes.Unauthenticated,
},
}
+24 -28
View File
@@ -5,7 +5,7 @@ package grpc
import (
"github.com/mainflux/mainflux/auth"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/mainflux/mainflux/internal/apiutil"
)
type identityReq struct {
@@ -15,12 +15,12 @@ type identityReq struct {
func (req identityReq) validate() error {
if req.token == "" {
return errors.ErrMalformedEntity
return apiutil.ErrBearerToken
}
if req.kind != auth.LoginKey &&
req.kind != auth.APIKey &&
req.kind != auth.RecoveryKey {
return errors.ErrMalformedEntity
return apiutil.ErrInvalidAuthKey
}
return nil
@@ -34,12 +34,12 @@ type issueReq struct {
func (req issueReq) validate() error {
if req.email == "" {
return errors.ErrAuthentication
return apiutil.ErrMissingEmail
}
if req.keyType != auth.LoginKey &&
req.keyType != auth.APIKey &&
req.keyType != auth.RecoveryKey {
return errors.ErrMalformedEntity
return apiutil.ErrInvalidAuthKey
}
return nil
@@ -54,10 +54,10 @@ type assignReq struct {
func (req assignReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
if req.groupID == "" || req.memberID == "" {
return errors.ErrMalformedEntity
return apiutil.ErrMissingID
}
return nil
}
@@ -72,13 +72,13 @@ type membersReq struct {
func (req membersReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
if req.groupID == "" {
return errors.ErrMalformedEntity
return apiutil.ErrMissingID
}
if req.memberType == "" {
return errors.ErrMalformedEntity
return apiutil.ErrMissingMemberType
}
return nil
}
@@ -95,43 +95,39 @@ type authReq struct {
func (req authReq) validate() error {
if req.Sub == "" {
return errors.ErrMalformedEntity
return apiutil.ErrMissingPolicySub
}
if req.Obj == "" {
return errors.ErrMalformedEntity
return apiutil.ErrMissingPolicyObj
}
if req.Act == "" {
return errors.ErrMalformedEntity
return apiutil.ErrMissingPolicyAct
}
return nil
}
type addPolicyReq struct {
type policyReq struct {
Sub string
Obj string
Act string
}
func (req addPolicyReq) validate() error {
if req.Sub == "" || req.Obj == "" || req.Act == "" {
return errors.ErrMalformedEntity
func (req policyReq) validate() error {
if req.Sub == "" {
return apiutil.ErrMissingPolicySub
}
return nil
}
type deletePolicyReq struct {
Sub string
Obj string
Act string
}
func (req deletePolicyReq) validate() error {
if req.Sub == "" || req.Obj == "" || req.Act == "" {
return errors.ErrMalformedEntity
if req.Obj == "" {
return apiutil.ErrMissingPolicyObj
}
if req.Act == "" {
return apiutil.ErrMissingPolicyAct
}
return nil
}
+15 -7
View File
@@ -11,6 +11,7 @@ import (
"github.com/golang/protobuf/ptypes/empty"
mainflux "github.com/mainflux/mainflux"
"github.com/mainflux/mainflux/auth"
"github.com/mainflux/mainflux/internal/apiutil"
"github.com/mainflux/mainflux/pkg/errors"
opentracing "github.com/opentracing/opentracing-go"
"google.golang.org/grpc/codes"
@@ -172,7 +173,7 @@ func encodeAuthorizeResponse(_ context.Context, grpcRes interface{}) (interface{
func decodeAddPolicyRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
req := grpcReq.(*mainflux.AddPolicyReq)
return addPolicyReq{Sub: req.GetSub(), Obj: req.GetObj(), Act: req.GetAct()}, nil
return policyReq{Sub: req.GetSub(), Obj: req.GetObj(), Act: req.GetAct()}, nil
}
func encodeAddPolicyResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
@@ -187,7 +188,7 @@ func decodeAssignRequest(_ context.Context, grpcReq interface{}) (interface{}, e
func decodeDeletePolicyRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
req := grpcReq.(*mainflux.DeletePolicyReq)
return deletePolicyReq{Sub: req.GetSub(), Obj: req.GetObj(), Act: req.GetAct()}, nil
return policyReq{Sub: req.GetSub(), Obj: req.GetObj(), Act: req.GetAct()}, nil
}
func encodeDeletePolicyResponse(_ context.Context, grpcRes interface{}) (interface{}, error) {
@@ -236,14 +237,21 @@ func encodeError(err error) error {
switch {
case errors.Contains(err, nil):
return nil
case errors.Contains(err, errors.ErrMalformedEntity):
return status.Error(codes.InvalidArgument, "received invalid token request")
case errors.Contains(err, errors.ErrAuthentication):
case errors.Contains(err, errors.ErrMalformedEntity),
err == apiutil.ErrInvalidAuthKey,
err == apiutil.ErrMissingID,
err == apiutil.ErrMissingMemberType,
err == apiutil.ErrMissingPolicySub,
err == apiutil.ErrMissingPolicyObj,
err == apiutil.ErrMissingPolicyAct:
return status.Error(codes.InvalidArgument, err.Error())
case errors.Contains(err, errors.ErrAuthentication),
errors.Contains(err, auth.ErrKeyExpired),
err == apiutil.ErrMissingEmail,
err == apiutil.ErrBearerToken:
return status.Error(codes.Unauthenticated, err.Error())
case errors.Contains(err, errors.ErrAuthorization):
return status.Error(codes.PermissionDenied, err.Error())
case errors.Contains(err, auth.ErrKeyExpired):
return status.Error(codes.Unauthenticated, err.Error())
default:
return status.Error(codes.Internal, "internal server error")
}
+5 -3
View File
@@ -18,7 +18,8 @@ import (
httpapi "github.com/mainflux/mainflux/auth/api/http"
"github.com/mainflux/mainflux/auth/jwt"
"github.com/mainflux/mainflux/auth/mocks"
"github.com/mainflux/mainflux/internal/httputil"
"github.com/mainflux/mainflux/internal/apiutil"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/uuid"
"github.com/opentracing/opentracing-go/mocktracer"
"github.com/stretchr/testify/assert"
@@ -47,7 +48,7 @@ func (tr testRequest) make() (*http.Response, error) {
return nil, err
}
if tr.token != "" {
req.Header.Set("Authorization", httputil.BearerPrefix+tr.token)
req.Header.Set("Authorization", apiutil.BearerPrefix+tr.token)
}
if tr.contentType != "" {
req.Header.Set("Content-Type", tr.contentType)
@@ -65,7 +66,8 @@ func newService() auth.Service {
}
func newServer(svc auth.Service) *httptest.Server {
mux := httpapi.MakeHandler(svc, mocktracer.New())
logger := logger.NewMock()
mux := httpapi.MakeHandler(svc, mocktracer.New(), logger)
return httptest.NewServer(mux)
}
+33 -21
View File
@@ -2,7 +2,7 @@ package groups
import (
"github.com/mainflux/mainflux/auth"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/mainflux/mainflux/internal/apiutil"
)
type createGroupReq struct {
@@ -15,10 +15,10 @@ type createGroupReq struct {
func (req createGroupReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
if len(req.Name) > maxNameSize || req.Name == "" {
return errors.Wrap(errors.ErrMalformedEntity, auth.ErrBadGroupName)
return apiutil.ErrNameSize
}
return nil
@@ -34,11 +34,11 @@ type updateGroupReq struct {
func (req updateGroupReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
if req.id == "" {
return errors.ErrMalformedEntity
return apiutil.ErrMissingID
}
return nil
@@ -56,11 +56,11 @@ type listGroupsReq struct {
func (req listGroupsReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
if req.level > auth.MaxLevel || req.level < auth.MinLevel {
return auth.ErrMaxLevelExceeded
return apiutil.ErrMaxLevelExceeded
}
return nil
@@ -78,11 +78,11 @@ type listMembersReq struct {
func (req listMembersReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
if req.id == "" {
return errors.ErrMalformedEntity
return apiutil.ErrMissingID
}
return nil
@@ -98,11 +98,11 @@ type listMembershipsReq struct {
func (req listMembershipsReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
if req.id == "" {
return errors.ErrMalformedEntity
return apiutil.ErrMissingID
}
return nil
@@ -117,11 +117,19 @@ type assignReq struct {
func (req assignReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
if req.Type == "" || req.groupID == "" || len(req.Members) == 0 {
return errors.ErrMalformedEntity
if req.Type == "" {
return apiutil.ErrMissingMemberType
}
if req.groupID == "" {
return apiutil.ErrMissingID
}
if len(req.Members) == 0 {
return apiutil.ErrEmptyList
}
return nil
@@ -135,11 +143,11 @@ type shareGroupAccessReq struct {
func (req shareGroupAccessReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
if req.ThingGroupID == "" || req.userGroupID == "" {
return errors.ErrMalformedEntity
return apiutil.ErrMissingID
}
return nil
@@ -151,11 +159,15 @@ type unassignReq struct {
func (req unassignReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
if req.groupID == "" || len(req.Members) == 0 {
return errors.ErrMalformedEntity
if req.groupID == "" {
return apiutil.ErrMissingID
}
if len(req.Members) == 0 {
return apiutil.ErrEmptyList
}
return nil
@@ -168,11 +180,11 @@ type groupReq struct {
func (req groupReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
if req.id == "" {
return errors.ErrMalformedEntity
return apiutil.ErrMissingID
}
return nil
+33 -73
View File
@@ -11,7 +11,8 @@ import (
"github.com/go-zoo/bone"
"github.com/mainflux/mainflux"
"github.com/mainflux/mainflux/auth"
"github.com/mainflux/mainflux/internal/httputil"
"github.com/mainflux/mainflux/internal/apiutil"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/opentracing/opentracing-go"
)
@@ -31,9 +32,9 @@ const (
)
// MakeHandler returns a HTTP handler for API endpoints.
func MakeHandler(svc auth.Service, mux *bone.Mux, tracer opentracing.Tracer) *bone.Mux {
func MakeHandler(svc auth.Service, mux *bone.Mux, tracer opentracing.Tracer, logger logger.Logger) *bone.Mux {
opts := []kithttp.ServerOption{
kithttp.ServerErrorEncoder(encodeError),
kithttp.ServerErrorEncoder(apiutil.LoggingErrorEncoder(logger, encodeError)),
}
mux.Post("/groups", kithttp.NewServer(
kitot.TraceServer(tracer, "create_group")(createGroupEndpoint(svc)),
@@ -127,13 +128,8 @@ func decodeShareGroupRequest(ctx context.Context, r *http.Request) (interface{},
return nil, errors.ErrUnsupportedContentType
}
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req := shareGroupAccessReq{
token: t,
token: apiutil.ExtractBearerToken(r),
userGroupID: bone.GetValue(r, "subjectGroupID"),
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
@@ -144,28 +140,23 @@ func decodeShareGroupRequest(ctx context.Context, r *http.Request) (interface{},
}
func decodeListGroupsRequest(_ context.Context, r *http.Request) (interface{}, error) {
l, err := httputil.ReadUintQuery(r, levelKey, defLevel)
l, err := apiutil.ReadUintQuery(r, levelKey, defLevel)
if err != nil {
return nil, err
}
m, err := httputil.ReadMetadataQuery(r, metadataKey, nil)
m, err := apiutil.ReadMetadataQuery(r, metadataKey, nil)
if err != nil {
return nil, err
}
t, err := httputil.ReadBoolQuery(r, treeKey, false)
if err != nil {
return nil, err
}
to, err := httputil.ExtractAuthToken(r)
t, err := apiutil.ReadBoolQuery(r, treeKey, false)
if err != nil {
return nil, err
}
req := listGroupsReq{
token: to,
token: apiutil.ExtractBearerToken(r),
level: l,
metadata: m,
tree: t,
@@ -175,38 +166,33 @@ func decodeListGroupsRequest(_ context.Context, r *http.Request) (interface{}, e
}
func decodeListMembersRequest(_ context.Context, r *http.Request) (interface{}, error) {
o, err := httputil.ReadUintQuery(r, offsetKey, defOffset)
o, err := apiutil.ReadUintQuery(r, offsetKey, defOffset)
if err != nil {
return nil, err
}
l, err := httputil.ReadUintQuery(r, limitKey, defLimit)
l, err := apiutil.ReadUintQuery(r, limitKey, defLimit)
if err != nil {
return nil, err
}
m, err := httputil.ReadMetadataQuery(r, metadataKey, nil)
m, err := apiutil.ReadMetadataQuery(r, metadataKey, nil)
if err != nil {
return nil, err
}
tree, err := httputil.ReadBoolQuery(r, treeKey, false)
tree, err := apiutil.ReadBoolQuery(r, treeKey, false)
if err != nil {
return nil, err
}
t, err := httputil.ReadStringQuery(r, groupType, "")
if err != nil {
return nil, err
}
to, err := httputil.ExtractAuthToken(r)
t, err := apiutil.ReadStringQuery(r, groupType, "")
if err != nil {
return nil, err
}
req := listMembersReq{
token: to,
token: apiutil.ExtractBearerToken(r),
id: bone.GetValue(r, "groupID"),
groupType: t,
offset: o,
@@ -218,28 +204,23 @@ func decodeListMembersRequest(_ context.Context, r *http.Request) (interface{},
}
func decodeListMembershipsRequest(_ context.Context, r *http.Request) (interface{}, error) {
o, err := httputil.ReadUintQuery(r, offsetKey, defOffset)
o, err := apiutil.ReadUintQuery(r, offsetKey, defOffset)
if err != nil {
return nil, err
}
l, err := httputil.ReadUintQuery(r, limitKey, defLimit)
l, err := apiutil.ReadUintQuery(r, limitKey, defLimit)
if err != nil {
return nil, err
}
m, err := httputil.ReadMetadataQuery(r, metadataKey, nil)
if err != nil {
return nil, err
}
t, err := httputil.ExtractAuthToken(r)
m, err := apiutil.ReadMetadataQuery(r, metadataKey, nil)
if err != nil {
return nil, err
}
req := listMembershipsReq{
token: t,
token: apiutil.ExtractBearerToken(r),
id: bone.GetValue(r, "memberID"),
offset: o,
limit: l,
@@ -254,17 +235,11 @@ func decodeGroupCreate(_ context.Context, r *http.Request) (interface{}, error)
return nil, errors.ErrUnsupportedContentType
}
var req createGroupReq
req := createGroupReq{token: apiutil.ExtractBearerToken(r)}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return nil, errors.Wrap(errors.ErrMalformedEntity, err)
}
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req.token = t
return req, nil
}
@@ -273,29 +248,20 @@ func decodeGroupUpdate(_ context.Context, r *http.Request) (interface{}, error)
return nil, errors.ErrUnsupportedContentType
}
var req updateGroupReq
req := updateGroupReq{
id: bone.GetValue(r, "groupID"),
token: apiutil.ExtractBearerToken(r),
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return nil, errors.Wrap(errors.ErrMalformedEntity, err)
}
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req.id = bone.GetValue(r, "groupID")
req.token = t
return req, nil
}
func decodeGroupRequest(_ context.Context, r *http.Request) (interface{}, error) {
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req := groupReq{
token: t,
token: apiutil.ExtractBearerToken(r),
id: bone.GetValue(r, "groupID"),
}
@@ -303,13 +269,8 @@ func decodeGroupRequest(_ context.Context, r *http.Request) (interface{}, error)
}
func decodeAssignRequest(_ context.Context, r *http.Request) (interface{}, error) {
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req := assignReq{
token: t,
token: apiutil.ExtractBearerToken(r),
groupID: bone.GetValue(r, "groupID"),
}
@@ -321,14 +282,9 @@ func decodeAssignRequest(_ context.Context, r *http.Request) (interface{}, error
}
func decodeUnassignRequest(_ context.Context, r *http.Request) (interface{}, error) {
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req := unassignReq{
assignReq{
token: t,
token: apiutil.ExtractBearerToken(r),
groupID: bone.GetValue(r, "groupID"),
},
}
@@ -360,7 +316,11 @@ func encodeResponse(_ context.Context, w http.ResponseWriter, response interface
func encodeError(_ context.Context, err error, w http.ResponseWriter) {
switch {
case errors.Contains(err, errors.ErrMalformedEntity):
case errors.Contains(err, errors.ErrMalformedEntity),
err == apiutil.ErrMissingID,
err == apiutil.ErrEmptyList,
err == apiutil.ErrMissingMemberType,
err == apiutil.ErrNameSize:
w.WriteHeader(http.StatusBadRequest)
case errors.Contains(err, errors.ErrAuthentication):
w.WriteHeader(http.StatusUnauthorized)
@@ -387,7 +347,7 @@ func encodeError(_ context.Context, err error, w http.ResponseWriter) {
if errorVal, ok := err.(errors.Error); ok {
w.Header().Set("Content-Type", contentType)
if err := json.NewEncoder(w).Encode(httputil.ErrorRes{Err: errorVal.Msg()}); err != nil {
if err := json.NewEncoder(w).Encode(apiutil.ErrorRes{Err: errorVal.Msg()}); err != nil {
w.WriteHeader(http.StatusInternalServerError)
}
}
+7 -5
View File
@@ -18,7 +18,8 @@ import (
httpapi "github.com/mainflux/mainflux/auth/api/http"
"github.com/mainflux/mainflux/auth/jwt"
"github.com/mainflux/mainflux/auth/mocks"
"github.com/mainflux/mainflux/internal/httputil"
"github.com/mainflux/mainflux/internal/apiutil"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/uuid"
"github.com/opentracing/opentracing-go/mocktracer"
"github.com/stretchr/testify/assert"
@@ -52,7 +53,7 @@ func (tr testRequest) make() (*http.Response, error) {
return nil, err
}
if tr.token != "" {
req.Header.Set("Authorization", httputil.BearerPrefix+tr.token)
req.Header.Set("Authorization", apiutil.BearerPrefix+tr.token)
}
if tr.contentType != "" {
req.Header.Set("Content-Type", tr.contentType)
@@ -76,7 +77,8 @@ func newService() auth.Service {
}
func newServer(svc auth.Service) *httptest.Server {
mux := httpapi.MakeHandler(svc, mocktracer.New())
logger := logger.NewMock()
mux := httpapi.MakeHandler(svc, mocktracer.New(), logger)
return httptest.NewServer(mux)
}
@@ -106,7 +108,7 @@ func TestIssue(t *testing.T) {
status int
}{
{
desc: "issue login key",
desc: "issue login key with empty token",
req: toJSON(lk),
ct: contentType,
token: "",
@@ -124,7 +126,7 @@ func TestIssue(t *testing.T) {
req: toJSON(rk),
ct: contentType,
token: loginSecret,
status: http.StatusUnauthorized,
status: http.StatusCreated,
},
{
desc: "issue login key wrong content type",
+16 -5
View File
@@ -7,7 +7,7 @@ import (
"time"
"github.com/mainflux/mainflux/auth"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/mainflux/mainflux/internal/apiutil"
)
type issueKeyReq struct {
@@ -18,9 +18,16 @@ type issueKeyReq struct {
// It is not possible to issue Reset key using HTTP API.
func (req issueKeyReq) validate() error {
if req.Type != auth.APIKey || req.token == "" {
return errors.ErrAuthentication
if req.token == "" {
return apiutil.ErrBearerToken
}
if req.Type != auth.LoginKey &&
req.Type != auth.RecoveryKey &&
req.Type != auth.APIKey {
return apiutil.ErrInvalidAPIKey
}
return nil
}
@@ -30,8 +37,12 @@ type keyReq struct {
}
func (req keyReq) validate() error {
if req.token == "" || req.id == "" {
return errors.ErrMalformedEntity
if req.token == "" {
return apiutil.ErrBearerToken
}
if req.id == "" {
return apiutil.ErrMissingID
}
return nil
}
+13 -18
View File
@@ -14,7 +14,8 @@ import (
"github.com/go-zoo/bone"
"github.com/mainflux/mainflux"
"github.com/mainflux/mainflux/auth"
"github.com/mainflux/mainflux/internal/httputil"
"github.com/mainflux/mainflux/internal/apiutil"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/opentracing/opentracing-go"
)
@@ -22,9 +23,9 @@ import (
const contentType = "application/json"
// MakeHandler returns a HTTP handler for API endpoints.
func MakeHandler(svc auth.Service, mux *bone.Mux, tracer opentracing.Tracer) *bone.Mux {
func MakeHandler(svc auth.Service, mux *bone.Mux, tracer opentracing.Tracer, logger logger.Logger) *bone.Mux {
opts := []kithttp.ServerOption{
kithttp.ServerErrorEncoder(encodeError),
kithttp.ServerErrorEncoder(apiutil.LoggingErrorEncoder(logger, encodeError)),
}
mux.Post("/keys", kithttp.NewServer(
kitot.TraceServer(tracer, "issue")(issueEndpoint(svc)),
@@ -54,13 +55,8 @@ func decodeIssue(_ context.Context, r *http.Request) (interface{}, error) {
if !strings.Contains(r.Header.Get("Content-Type"), contentType) {
return nil, errors.ErrUnsupportedContentType
}
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req := issueKeyReq{
token: t,
}
req := issueKeyReq{token: apiutil.ExtractBearerToken(r)}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return nil, errors.Wrap(errors.ErrMalformedEntity, err)
}
@@ -69,12 +65,8 @@ func decodeIssue(_ context.Context, r *http.Request) (interface{}, error) {
}
func decodeKeyReq(_ context.Context, r *http.Request) (interface{}, error) {
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req := keyReq{
token: t,
token: apiutil.ExtractBearerToken(r),
id: bone.GetValue(r, "id"),
}
return req, nil
@@ -100,9 +92,12 @@ func encodeResponse(_ context.Context, w http.ResponseWriter, response interface
func encodeError(_ context.Context, err error, w http.ResponseWriter) {
switch {
case errors.Contains(err, errors.ErrMalformedEntity):
case errors.Contains(err, errors.ErrMalformedEntity),
err == apiutil.ErrMissingID,
err == apiutil.ErrInvalidAPIKey:
w.WriteHeader(http.StatusBadRequest)
case errors.Contains(err, errors.ErrAuthentication):
case errors.Contains(err, errors.ErrAuthentication),
err == apiutil.ErrBearerToken:
w.WriteHeader(http.StatusUnauthorized)
case errors.Contains(err, errors.ErrNotFound):
w.WriteHeader(http.StatusNotFound)
@@ -116,7 +111,7 @@ func encodeError(_ context.Context, err error, w http.ResponseWriter) {
if errorVal, ok := err.(errors.Error); ok {
w.Header().Set("Content-Type", contentType)
if err := json.NewEncoder(w).Encode(httputil.ErrorRes{Err: errorVal.Msg()}); err != nil {
if err := json.NewEncoder(w).Encode(apiutil.ErrorRes{Err: errorVal.Msg()}); err != nil {
w.WriteHeader(http.StatusInternalServerError)
}
}
+5 -3
View File
@@ -18,7 +18,8 @@ import (
httpapi "github.com/mainflux/mainflux/auth/api/http"
"github.com/mainflux/mainflux/auth/jwt"
"github.com/mainflux/mainflux/auth/mocks"
"github.com/mainflux/mainflux/internal/httputil"
"github.com/mainflux/mainflux/internal/apiutil"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/uuid"
"github.com/opentracing/opentracing-go/mocktracer"
"github.com/stretchr/testify/assert"
@@ -49,7 +50,7 @@ func (tr testRequest) make() (*http.Response, error) {
return nil, err
}
if tr.token != "" {
req.Header.Set("Authorization", httputil.BearerPrefix+tr.token)
req.Header.Set("Authorization", apiutil.BearerPrefix+tr.token)
}
if tr.contentType != "" {
req.Header.Set("Content-Type", tr.contentType)
@@ -74,7 +75,8 @@ func newService() auth.Service {
}
func newServer(svc auth.Service) *httptest.Server {
mux := httpapi.MakeHandler(svc, mocktracer.New())
logger := logger.NewMock()
mux := httpapi.MakeHandler(svc, mocktracer.New(), logger)
return httptest.NewServer(mux)
}
+16 -10
View File
@@ -1,8 +1,6 @@
package policies
import (
"github.com/mainflux/mainflux/pkg/errors"
)
import "github.com/mainflux/mainflux/internal/apiutil"
// Action represents an enum for the policies used in the Mainflux.
type Action int
@@ -35,22 +33,30 @@ type policiesReq struct {
func (req policiesReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
if len(req.SubjectIDs) == 0 || len(req.Policies) == 0 || req.Object == "" {
return errors.ErrMalformedEntity
if len(req.SubjectIDs) == 0 {
return apiutil.ErrEmptyList
}
if len(req.Policies) == 0 {
return apiutil.ErrEmptyList
}
if req.Object == "" {
return apiutil.ErrMissingPolicyObj
}
for _, policy := range req.Policies {
if _, ok := actions[policy]; !ok {
return errors.ErrMalformedEntity
return apiutil.ErrMalformedPolicy
}
}
for _, subject := range req.SubjectIDs {
if subject == "" {
return errors.ErrMalformedEntity
for _, subID := range req.SubjectIDs {
if subID == "" {
return apiutil.ErrMissingPolicySub
}
}
+13 -14
View File
@@ -11,7 +11,8 @@ import (
"github.com/go-zoo/bone"
"github.com/mainflux/mainflux"
"github.com/mainflux/mainflux/auth"
"github.com/mainflux/mainflux/internal/httputil"
"github.com/mainflux/mainflux/internal/apiutil"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/opentracing/opentracing-go"
)
@@ -19,9 +20,9 @@ import (
const contentType = "application/json"
// MakeHandler returns a HTTP handler for API endpoints.
func MakeHandler(svc auth.Service, mux *bone.Mux, tracer opentracing.Tracer) *bone.Mux {
func MakeHandler(svc auth.Service, mux *bone.Mux, tracer opentracing.Tracer, logger logger.Logger) *bone.Mux {
opts := []kithttp.ServerOption{
kithttp.ServerErrorEncoder(encodeError),
kithttp.ServerErrorEncoder(apiutil.LoggingErrorEncoder(logger, encodeError)),
}
mux.Post("/policies", kithttp.NewServer(
@@ -46,14 +47,7 @@ func decodePoliciesRequest(ctx context.Context, r *http.Request) (interface{}, e
return nil, errors.ErrUnsupportedContentType
}
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req := policiesReq{
token: t,
}
req := policiesReq{token: apiutil.ExtractBearerToken(r)}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return nil, errors.Wrap(errors.ErrMalformedEntity, err)
}
@@ -81,9 +75,14 @@ func encodeResponse(_ context.Context, w http.ResponseWriter, response interface
func encodeError(_ context.Context, err error, w http.ResponseWriter) {
switch {
case errors.Contains(err, errors.ErrMalformedEntity):
case errors.Contains(err, errors.ErrMalformedEntity),
err == apiutil.ErrEmptyList,
err == apiutil.ErrMissingPolicyObj,
err == apiutil.ErrMissingPolicySub,
err == apiutil.ErrMalformedPolicy:
w.WriteHeader(http.StatusBadRequest)
case errors.Contains(err, errors.ErrAuthentication):
case errors.Contains(err, errors.ErrAuthentication),
err == apiutil.ErrBearerToken:
w.WriteHeader(http.StatusUnauthorized)
case errors.Contains(err, errors.ErrNotFound):
w.WriteHeader(http.StatusNotFound)
@@ -101,7 +100,7 @@ func encodeError(_ context.Context, err error, w http.ResponseWriter) {
if errorVal, ok := err.(errors.Error); ok {
w.Header().Set("Content-Type", contentType)
if err := json.NewEncoder(w).Encode(httputil.ErrorRes{Err: errorVal.Msg()}); err != nil {
if err := json.NewEncoder(w).Encode(apiutil.ErrorRes{Err: errorVal.Msg()}); err != nil {
w.WriteHeader(http.StatusInternalServerError)
}
}
+5 -4
View File
@@ -11,16 +11,17 @@ import (
"github.com/mainflux/mainflux/auth/api/http/groups"
"github.com/mainflux/mainflux/auth/api/http/keys"
"github.com/mainflux/mainflux/auth/api/http/policies"
"github.com/mainflux/mainflux/logger"
"github.com/opentracing/opentracing-go"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
// MakeHandler returns a HTTP handler for API endpoints.
func MakeHandler(svc auth.Service, tracer opentracing.Tracer) http.Handler {
func MakeHandler(svc auth.Service, tracer opentracing.Tracer, logger logger.Logger) http.Handler {
mux := bone.New()
mux = keys.MakeHandler(svc, mux, tracer)
mux = groups.MakeHandler(svc, mux, tracer)
mux = policies.MakeHandler(svc, mux, tracer)
mux = keys.MakeHandler(svc, mux, tracer, logger)
mux = groups.MakeHandler(svc, mux, tracer, logger)
mux = policies.MakeHandler(svc, mux, tracer, logger)
mux.GetFunc("/health", mainflux.Health("auth"))
mux.Handle("/metrics", promhttp.Handler())
return mux
-6
View File
@@ -14,12 +14,6 @@ const (
)
var (
// ErrMaxLevelExceeded malformed entity.
ErrMaxLevelExceeded = errors.New("level must be less than or equal 5")
// ErrBadGroupName malformed entity.
ErrBadGroupName = errors.New("incorrect group name")
// ErrAssignToGroup indicates failure to assign member to a group.
ErrAssignToGroup = errors.New("failed to assign member to a group")
+17 -12
View File
@@ -23,7 +23,8 @@ import (
"github.com/mainflux/mainflux/bootstrap"
bsapi "github.com/mainflux/mainflux/bootstrap/api"
"github.com/mainflux/mainflux/bootstrap/mocks"
"github.com/mainflux/mainflux/internal/httputil"
"github.com/mainflux/mainflux/internal/apiutil"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
mfsdk "github.com/mainflux/mainflux/pkg/sdk/go"
"github.com/mainflux/mainflux/things"
@@ -82,12 +83,14 @@ var (
CACert: "newca",
}
bsErrorRes = toJSON(httputil.ErrorRes{Err: bootstrap.ErrBootstrap.Error()})
authnRes = toJSON(httputil.ErrorRes{Err: errors.ErrAuthentication.Error()})
authzRes = toJSON(httputil.ErrorRes{Err: errors.ErrAuthorization.Error()})
malformedRes = toJSON(httputil.ErrorRes{Err: errors.ErrMalformedEntity.Error()})
extKeyRes = toJSON(httputil.ErrorRes{Err: bootstrap.ErrExternalKey.Error()})
extSecKeyRes = toJSON(httputil.ErrorRes{Err: bootstrap.ErrExternalKeySecure.Error()})
bsErrorRes = toJSON(apiutil.ErrorRes{Err: bootstrap.ErrBootstrap.Error()})
authnRes = toJSON(apiutil.ErrorRes{Err: errors.ErrAuthentication.Error()})
authzRes = toJSON(apiutil.ErrorRes{Err: errors.ErrAuthorization.Error()})
malformedRes = toJSON(apiutil.ErrorRes{Err: errors.ErrMalformedEntity.Error()})
extKeyRes = toJSON(apiutil.ErrorRes{Err: bootstrap.ErrExternalKey.Error()})
extSecKeyRes = toJSON(apiutil.ErrorRes{Err: bootstrap.ErrExternalKeySecure.Error()})
missingIDRes = toJSON(apiutil.ErrorRes{Err: apiutil.ErrMissingID.Error()})
missingKeyRes = toJSON(apiutil.ErrorRes{Err: apiutil.ErrBearerKey.Error()})
)
type testRequest struct {
@@ -120,7 +123,7 @@ func (tr testRequest) make() (*http.Response, error) {
}
if tr.token != "" {
req.Header.Set("Authorization", httputil.BearerPrefix+tr.token)
req.Header.Set("Authorization", apiutil.BearerPrefix+tr.token)
}
if tr.contentType != "" {
@@ -188,12 +191,14 @@ func newThingsService(auth mainflux.AuthServiceClient) things.Service {
}
func newThingsServer(svc things.Service) *httptest.Server {
mux := thingsapi.MakeHandler(mocktracer.New(), svc)
logger := logger.NewMock()
mux := thingsapi.MakeHandler(mocktracer.New(), svc, logger)
return httptest.NewServer(mux)
}
func newBootstrapServer(svc bootstrap.Service) *httptest.Server {
mux := bsapi.MakeHandler(svc, bootstrap.NewConfigReader(encKey))
logger := logger.NewMock()
mux := bsapi.MakeHandler(svc, bootstrap.NewConfigReader(encKey), logger)
return httptest.NewServer(mux)
}
@@ -1092,7 +1097,7 @@ func TestBootstrap(t *testing.T) {
externalID: "",
externalKey: c.ExternalKey,
status: http.StatusBadRequest,
res: malformedRes,
res: missingIDRes,
secure: false,
},
{
@@ -1108,7 +1113,7 @@ func TestBootstrap(t *testing.T) {
externalID: c.ExternalID,
externalKey: "",
status: http.StatusUnauthorized,
res: authnRes,
res: missingKeyRes,
secure: false,
},
{
+23 -19
View File
@@ -5,7 +5,7 @@ package api
import (
"github.com/mainflux/mainflux/bootstrap"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/mainflux/mainflux/internal/apiutil"
)
const maxLimitSize = 100
@@ -29,11 +29,15 @@ type addReq struct {
func (req addReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
if req.ExternalID == "" || req.ExternalKey == "" {
return errors.ErrMalformedEntity
if req.ExternalID == "" {
return apiutil.ErrMissingID
}
if req.ExternalKey == "" {
return apiutil.ErrBearerKey
}
return nil
@@ -46,11 +50,11 @@ type entityReq struct {
func (req entityReq) validate() error {
if req.key == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerKey
}
if req.id == "" {
return errors.ErrMalformedEntity
return apiutil.ErrMissingID
}
return nil
@@ -65,11 +69,11 @@ type updateReq struct {
func (req updateReq) validate() error {
if req.key == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerKey
}
if req.id == "" {
return errors.ErrMalformedEntity
return apiutil.ErrMissingID
}
return nil
@@ -85,11 +89,11 @@ type updateCertReq struct {
func (req updateCertReq) validate() error {
if req.key == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerKey
}
if req.thingID == "" {
return errors.ErrNotFound
return apiutil.ErrMissingID
}
return nil
@@ -103,11 +107,11 @@ type updateConnReq struct {
func (req updateConnReq) validate() error {
if req.key == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerKey
}
if req.id == "" {
return errors.ErrMalformedEntity
return apiutil.ErrMissingID
}
return nil
@@ -122,11 +126,11 @@ type listReq struct {
func (req listReq) validate() error {
if req.key == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerKey
}
if req.limit > maxLimitSize {
return errors.ErrMalformedEntity
return apiutil.ErrLimitSize
}
return nil
@@ -139,11 +143,11 @@ type bootstrapReq struct {
func (req bootstrapReq) validate() error {
if req.key == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerKey
}
if req.id == "" {
return errors.ErrMalformedEntity
return apiutil.ErrMissingID
}
return nil
@@ -157,16 +161,16 @@ type changeStateReq struct {
func (req changeStateReq) validate() error {
if req.key == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerKey
}
if req.id == "" {
return errors.ErrMalformedEntity
return apiutil.ErrMissingID
}
if req.State != bootstrap.Inactive &&
req.State != bootstrap.Active {
return errors.ErrMalformedEntity
return apiutil.ErrBootstrapState
}
return nil
+21 -21
View File
@@ -5,7 +5,7 @@ import (
"testing"
"github.com/mainflux/mainflux/bootstrap"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/mainflux/mainflux/internal/apiutil"
"github.com/stretchr/testify/assert"
)
@@ -22,21 +22,21 @@ func TestAddReqValidation(t *testing.T) {
token: "",
externalID: "external-id",
externalKey: "external-key",
err: errors.ErrAuthentication,
err: apiutil.ErrBearerToken,
},
{
desc: "empty external ID",
token: "token",
externalID: "",
externalKey: "external-key",
err: errors.ErrMalformedEntity,
err: apiutil.ErrMissingID,
},
{
desc: "empty external key",
token: "token",
externalID: "external-id",
externalKey: "",
err: errors.ErrMalformedEntity,
err: apiutil.ErrBearerKey,
},
}
@@ -63,13 +63,13 @@ func TestEntityReqValidation(t *testing.T) {
desc: "empty key",
key: "",
id: "id",
err: errors.ErrAuthentication,
err: apiutil.ErrBearerKey,
},
{
desc: "empty id",
key: "key",
id: "",
err: errors.ErrMalformedEntity,
err: apiutil.ErrMissingID,
},
}
@@ -94,13 +94,13 @@ func TestUpdateReqValidation(t *testing.T) {
desc: "empty key",
key: "",
id: "id",
err: errors.ErrAuthentication,
err: apiutil.ErrBearerKey,
},
{
desc: "empty id",
key: "key",
id: "",
err: errors.ErrMalformedEntity,
err: apiutil.ErrMissingID,
},
}
@@ -126,13 +126,13 @@ func TestUpdateCertReqValidation(t *testing.T) {
desc: "empty key",
key: "",
thingID: "thingID",
err: errors.ErrAuthentication,
err: apiutil.ErrBearerKey,
},
{
desc: "empty thing key",
desc: "empty thing id",
key: "key",
thingID: "",
err: errors.ErrNotFound,
err: apiutil.ErrMissingID,
},
}
@@ -158,13 +158,13 @@ func TestUpdateConnReqValidation(t *testing.T) {
desc: "empty key",
key: "",
id: "id",
err: errors.ErrAuthentication,
err: apiutil.ErrBearerKey,
},
{
desc: "empty id",
key: "key",
id: "",
err: errors.ErrMalformedEntity,
err: apiutil.ErrMissingID,
},
}
@@ -192,17 +192,17 @@ func TestListReqValidation(t *testing.T) {
key: "",
offset: 0,
limit: 1,
err: errors.ErrAuthentication,
err: apiutil.ErrBearerKey,
},
{
desc: "too large limit",
key: "key",
offset: 0,
limit: maxLimitSize + 1,
err: errors.ErrMalformedEntity,
err: apiutil.ErrLimitSize,
},
{
desc: "zero limit",
desc: "default limit",
key: "key",
offset: 0,
limit: defLimit,
@@ -233,13 +233,13 @@ func TestBootstrapReqValidation(t *testing.T) {
desc: "empty external key",
externKey: "",
externID: "id",
err: errors.ErrAuthentication,
err: apiutil.ErrBearerKey,
},
{
desc: "empty external id",
externKey: "key",
externID: "",
err: errors.ErrMalformedEntity,
err: apiutil.ErrMissingID,
},
}
@@ -267,21 +267,21 @@ func TestChangeStateReqValidation(t *testing.T) {
key: "",
id: "id",
state: bootstrap.State(1),
err: errors.ErrAuthentication,
err: apiutil.ErrBearerKey,
},
{
desc: "empty id",
key: "key",
id: "",
state: bootstrap.State(0),
err: errors.ErrMalformedEntity,
err: apiutil.ErrMissingID,
},
{
desc: "invalid state",
key: "key",
id: "id",
state: bootstrap.State(14),
err: errors.ErrMalformedEntity,
err: apiutil.ErrBootstrapState,
},
}
+30 -61
View File
@@ -14,7 +14,8 @@ import (
"github.com/go-zoo/bone"
"github.com/mainflux/mainflux"
"github.com/mainflux/mainflux/bootstrap"
"github.com/mainflux/mainflux/internal/httputil"
"github.com/mainflux/mainflux/internal/apiutil"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
@@ -33,9 +34,9 @@ var (
)
// MakeHandler returns a HTTP handler for API endpoints.
func MakeHandler(svc bootstrap.Service, reader bootstrap.ConfigReader) http.Handler {
func MakeHandler(svc bootstrap.Service, reader bootstrap.ConfigReader, logger logger.Logger) http.Handler {
opts := []kithttp.ServerOption{
kithttp.ServerErrorEncoder(encodeError),
kithttp.ServerErrorEncoder(apiutil.LoggingErrorEncoder(logger, encodeError)),
}
r := bone.New()
@@ -110,12 +111,7 @@ func decodeAddRequest(_ context.Context, r *http.Request) (interface{}, error) {
return nil, errors.ErrUnsupportedContentType
}
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req := addReq{token: t}
req := addReq{token: apiutil.ExtractBearerToken(r)}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return nil, errors.Wrap(errors.ErrMalformedEntity, err)
}
@@ -128,13 +124,10 @@ func decodeUpdateRequest(_ context.Context, r *http.Request) (interface{}, error
return nil, errors.ErrUnsupportedContentType
}
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
req := updateReq{
key: apiutil.ExtractBearerToken(r),
id: bone.GetValue(r, "id"),
}
req := updateReq{key: t}
req.id = bone.GetValue(r, "id")
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return nil, errors.Wrap(errors.ErrMalformedEntity, err)
}
@@ -147,16 +140,10 @@ func decodeUpdateCertRequest(_ context.Context, r *http.Request) (interface{}, e
return nil, errors.ErrUnsupportedContentType
}
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req := updateCertReq{
key: t,
key: apiutil.ExtractBearerToken(r),
thingID: bone.GetValue(r, "id"),
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return nil, errors.Wrap(errors.ErrMalformedEntity, err)
}
@@ -169,13 +156,10 @@ func decodeUpdateConnRequest(_ context.Context, r *http.Request) (interface{}, e
return nil, errors.ErrUnsupportedContentType
}
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
req := updateConnReq{
key: apiutil.ExtractBearerToken(r),
id: bone.GetValue(r, "id"),
}
req := updateConnReq{key: t}
req.id = bone.GetValue(r, "id")
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return nil, errors.Wrap(errors.ErrMalformedEntity, err)
}
@@ -184,12 +168,12 @@ func decodeUpdateConnRequest(_ context.Context, r *http.Request) (interface{}, e
}
func decodeListRequest(_ context.Context, r *http.Request) (interface{}, error) {
o, err := httputil.ReadUintQuery(r, offsetKey, defOffset)
o, err := apiutil.ReadUintQuery(r, offsetKey, defOffset)
if err != nil {
return nil, err
}
l, err := httputil.ReadUintQuery(r, limitKey, defLimit)
l, err := apiutil.ReadUintQuery(r, limitKey, defLimit)
if err != nil {
return nil, err
}
@@ -199,16 +183,9 @@ func decodeListRequest(_ context.Context, r *http.Request) (interface{}, error)
return nil, errors.ErrInvalidQueryParams
}
filter := parseFilter(q)
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req := listReq{
key: t,
filter: filter,
key: apiutil.ExtractBearerToken(r),
filter: parseFilter(q),
offset: o,
limit: l,
}
@@ -217,14 +194,9 @@ func decodeListRequest(_ context.Context, r *http.Request) (interface{}, error)
}
func decodeBootstrapRequest(_ context.Context, r *http.Request) (interface{}, error) {
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req := bootstrapReq{
id: bone.GetValue(r, "external_id"),
key: t,
key: apiutil.ExtractBearerToken(r),
}
return req, nil
@@ -235,13 +207,10 @@ func decodeStateRequest(_ context.Context, r *http.Request) (interface{}, error)
return nil, errors.ErrUnsupportedContentType
}
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
req := changeStateReq{
key: apiutil.ExtractBearerToken(r),
id: bone.GetValue(r, "id"),
}
req := changeStateReq{key: t}
req.id = bone.GetValue(r, "id")
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return nil, errors.Wrap(errors.ErrMalformedEntity, err)
}
@@ -250,13 +219,8 @@ func decodeStateRequest(_ context.Context, r *http.Request) (interface{}, error)
}
func decodeEntityRequest(_ context.Context, r *http.Request) (interface{}, error) {
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req := entityReq{
key: t,
key: apiutil.ExtractBearerToken(r),
id: bone.GetValue(r, "id"),
}
@@ -293,15 +257,20 @@ func encodeSecureRes(_ context.Context, w http.ResponseWriter, response interfac
func encodeError(_ context.Context, err error, w http.ResponseWriter) {
switch {
case errors.Contains(err, errors.ErrAuthentication),
err == apiutil.ErrBearerToken,
err == apiutil.ErrBearerKey:
w.WriteHeader(http.StatusUnauthorized)
case errors.Contains(err, errors.ErrUnsupportedContentType):
w.WriteHeader(http.StatusUnsupportedMediaType)
case errors.Contains(err, errors.ErrInvalidQueryParams),
errors.Contains(err, errors.ErrMalformedEntity):
errors.Contains(err, errors.ErrMalformedEntity),
err == apiutil.ErrMissingID,
err == apiutil.ErrBootstrapState,
err == apiutil.ErrLimitSize:
w.WriteHeader(http.StatusBadRequest)
case errors.Contains(err, errors.ErrNotFound):
w.WriteHeader(http.StatusNotFound)
case errors.Contains(err, errors.ErrAuthentication):
w.WriteHeader(http.StatusUnauthorized)
case errors.Contains(err, bootstrap.ErrExternalKey),
errors.Contains(err, bootstrap.ErrExternalKeySecure),
errors.Contains(err, errors.ErrAuthorization):
@@ -323,7 +292,7 @@ func encodeError(_ context.Context, err error, w http.ResponseWriter) {
if errorVal, ok := err.(errors.Error); ok {
w.Header().Set("Content-Type", contentType)
if err := json.NewEncoder(w).Encode(httputil.ErrorRes{Err: errorVal.Msg()}); err != nil {
if err := json.NewEncoder(w).Encode(apiutil.ErrorRes{Err: errorVal.Msg()}); err != nil {
w.WriteHeader(http.StatusInternalServerError)
}
}
+3 -1
View File
@@ -14,6 +14,7 @@ import (
"github.com/go-redis/redis/v8"
"github.com/mainflux/mainflux"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/opentracing/opentracing-go/mocktracer"
@@ -87,7 +88,8 @@ func newThingsService(auth mainflux.AuthServiceClient) things.Service {
}
func newThingsServer(svc things.Service) *httptest.Server {
mux := httpapi.MakeHandler(mocktracer.New(), svc)
logger := logger.NewMock()
mux := httpapi.MakeHandler(mocktracer.New(), svc, logger)
return httptest.NewServer(mux)
}
func TestAdd(t *testing.T) {
+3 -1
View File
@@ -21,6 +21,7 @@ import (
"github.com/mainflux/mainflux"
"github.com/mainflux/mainflux/bootstrap"
"github.com/mainflux/mainflux/bootstrap/mocks"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
mfsdk "github.com/mainflux/mainflux/pkg/sdk/go"
"github.com/mainflux/mainflux/things"
@@ -79,7 +80,8 @@ func newThingsService(auth mainflux.AuthServiceClient) things.Service {
}
func newThingsServer(svc things.Service) *httptest.Server {
mux := httpapi.MakeHandler(mocktracer.New(), svc)
logger := logger.NewMock()
mux := httpapi.MakeHandler(mocktracer.New(), svc, logger)
return httptest.NewServer(mux)
}
+16 -13
View File
@@ -3,9 +3,7 @@
package api
import (
"github.com/mainflux/mainflux/pkg/errors"
)
import "github.com/mainflux/mainflux/internal/apiutil"
const maxLimitSize = 100
@@ -19,12 +17,17 @@ type addCertsReq struct {
func (req addCertsReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
if req.ThingID == "" || req.TTL == "" || req.KeyType == "" || req.KeyBits == 0 {
return errors.ErrMalformedEntity
if req.ThingID == "" {
return apiutil.ErrMissingID
}
if req.TTL == "" || req.KeyType == "" || req.KeyBits == 0 {
return apiutil.ErrMissingCertData
}
return nil
}
@@ -37,10 +40,10 @@ type listReq struct {
func (req *listReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
if req.limit == 0 || req.limit > maxLimitSize {
return errors.ErrMalformedEntity
if req.limit > 1 || req.limit > maxLimitSize {
return apiutil.ErrLimitSize
}
return nil
}
@@ -52,10 +55,10 @@ type viewReq struct {
func (req *viewReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
if req.serialID == "" {
return errors.ErrMalformedEntity
return apiutil.ErrMissingID
}
return nil
@@ -68,11 +71,11 @@ type revokeReq struct {
func (req *revokeReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
if req.certID == "" {
return errors.ErrMalformedEntity
return apiutil.ErrMissingID
}
return nil
+19 -28
View File
@@ -12,7 +12,8 @@ import (
"github.com/go-zoo/bone"
"github.com/mainflux/mainflux"
"github.com/mainflux/mainflux/certs"
"github.com/mainflux/mainflux/internal/httputil"
"github.com/mainflux/mainflux/internal/apiutil"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
@@ -26,9 +27,9 @@ const (
)
// MakeHandler returns a HTTP handler for API endpoints.
func MakeHandler(svc certs.Service) http.Handler {
func MakeHandler(svc certs.Service, logger logger.Logger) http.Handler {
opts := []kithttp.ServerOption{
kithttp.ServerErrorEncoder(encodeError),
kithttp.ServerErrorEncoder(apiutil.LoggingErrorEncoder(logger, encodeError)),
}
r := bone.New()
@@ -86,20 +87,17 @@ func encodeResponse(_ context.Context, w http.ResponseWriter, response interface
}
func decodeListCerts(_ context.Context, r *http.Request) (interface{}, error) {
l, err := httputil.ReadUintQuery(r, limitKey, defLimit)
l, err := apiutil.ReadUintQuery(r, limitKey, defLimit)
if err != nil {
return nil, err
}
o, err := httputil.ReadUintQuery(r, offsetKey, defOffset)
if err != nil {
return nil, err
}
t, err := httputil.ExtractAuthToken(r)
o, err := apiutil.ReadUintQuery(r, offsetKey, defOffset)
if err != nil {
return nil, err
}
req := listReq{
token: t,
token: apiutil.ExtractBearerToken(r),
thingID: bone.GetValue(r, "thingId"),
limit: l,
offset: o,
@@ -108,13 +106,8 @@ func decodeListCerts(_ context.Context, r *http.Request) (interface{}, error) {
}
func decodeViewCert(_ context.Context, r *http.Request) (interface{}, error) {
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req := viewReq{
token: t,
token: apiutil.ExtractBearerToken(r),
serialID: bone.GetValue(r, "certId"),
}
@@ -125,11 +118,8 @@ func decodeCerts(_ context.Context, r *http.Request) (interface{}, error) {
if r.Header.Get("Content-Type") != contentType {
return nil, errors.ErrUnsupportedContentType
}
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req := addCertsReq{token: t}
req := addCertsReq{token: apiutil.ExtractBearerToken(r)}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return nil, err
}
@@ -138,12 +128,8 @@ func decodeCerts(_ context.Context, r *http.Request) (interface{}, error) {
}
func decodeRevokeCerts(_ context.Context, r *http.Request) (interface{}, error) {
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req := revokeReq{
token: t,
token: apiutil.ExtractBearerToken(r),
certID: bone.GetValue(r, "certId"),
}
@@ -152,10 +138,15 @@ func decodeRevokeCerts(_ context.Context, r *http.Request) (interface{}, error)
func encodeError(_ context.Context, err error, w http.ResponseWriter) {
switch {
case errors.Contains(err, errors.ErrAuthentication),
err == apiutil.ErrBearerToken:
w.WriteHeader(http.StatusUnauthorized)
case errors.Contains(err, errors.ErrUnsupportedContentType):
w.WriteHeader(http.StatusUnsupportedMediaType)
case errors.Contains(err, errors.ErrMalformedEntity),
errors.Contains(err, errors.ErrInvalidQueryParams):
err == apiutil.ErrMissingID,
err == apiutil.ErrMissingCertData,
err == apiutil.ErrLimitSize:
w.WriteHeader(http.StatusBadRequest)
case errors.Contains(err, errors.ErrConflict):
w.WriteHeader(http.StatusConflict)
@@ -171,7 +162,7 @@ func encodeError(_ context.Context, err error, w http.ResponseWriter) {
if errorVal, ok := err.(errors.Error); ok {
w.Header().Set("Content-Type", contentType)
if err := json.NewEncoder(w).Encode(httputil.ErrorRes{Err: errorVal.Msg()}); err != nil {
if err := json.NewEncoder(w).Encode(apiutil.ErrorRes{Err: errorVal.Msg()}); err != nil {
w.WriteHeader(http.StatusInternalServerError)
}
}
+3 -1
View File
@@ -21,6 +21,7 @@ import (
bsmocks "github.com/mainflux/mainflux/bootstrap/mocks"
"github.com/mainflux/mainflux/certs"
"github.com/mainflux/mainflux/certs/mocks"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
mfsdk "github.com/mainflux/mainflux/pkg/sdk/go"
"github.com/mainflux/mainflux/things"
@@ -413,7 +414,8 @@ func TestViewCert(t *testing.T) {
}
func newThingsServer(svc things.Service) *httptest.Server {
mux := httpapi.MakeHandler(mocktracer.New(), svc)
logger := logger.NewMock()
mux := httpapi.MakeHandler(mocktracer.New(), svc, logger)
return httptest.NewServer(mux)
}
+2 -2
View File
@@ -258,11 +258,11 @@ func startHTTPServer(tracer opentracing.Tracer, svc auth.Service, port string, c
p := fmt.Sprintf(":%s", port)
if certFile != "" || keyFile != "" {
logger.Info(fmt.Sprintf("Authentication service started using https, cert %s key %s, exposed port %s", certFile, keyFile, port))
errs <- http.ListenAndServeTLS(p, certFile, keyFile, httpapi.MakeHandler(svc, tracer))
errs <- http.ListenAndServeTLS(p, certFile, keyFile, httpapi.MakeHandler(svc, tracer, logger))
return
}
logger.Info(fmt.Sprintf("Authentication service started using http, exposed port %s", port))
errs <- http.ListenAndServe(p, httpapi.MakeHandler(svc, tracer))
errs <- http.ListenAndServe(p, httpapi.MakeHandler(svc, tracer, logger))
}
+2 -2
View File
@@ -325,11 +325,11 @@ func startHTTPServer(svc bootstrap.Service, cfg config, logger mflog.Logger, err
if cfg.serverCert != "" || cfg.serverKey != "" {
logger.Info(fmt.Sprintf("Bootstrap service started using https on port %s with cert %s key %s",
cfg.httpPort, cfg.serverCert, cfg.serverKey))
errs <- http.ListenAndServeTLS(p, cfg.serverCert, cfg.serverKey, api.MakeHandler(svc, bootstrap.NewConfigReader(cfg.encKey)))
errs <- http.ListenAndServeTLS(p, cfg.serverCert, cfg.serverKey, api.MakeHandler(svc, bootstrap.NewConfigReader(cfg.encKey), logger))
return
}
logger.Info(fmt.Sprintf("Bootstrap service started using http on port %s", cfg.httpPort))
errs <- http.ListenAndServe(p, api.MakeHandler(svc, bootstrap.NewConfigReader(cfg.encKey)))
errs <- http.ListenAndServe(p, api.MakeHandler(svc, bootstrap.NewConfigReader(cfg.encKey), logger))
}
func subscribeToThingsES(svc bootstrap.Service, client *r.Client, consumer string, logger mflog.Logger) {
+4 -4
View File
@@ -33,8 +33,8 @@ import (
)
const (
sep = ","
svcName = "cassandra-reader"
sep = ","
defLogLevel = "error"
defPort = "8180"
defCluster = "127.0.0.1"
@@ -284,9 +284,9 @@ func startHTTPServer(repo readers.MessageRepository, tc mainflux.ThingsServiceCl
if cfg.serverCert != "" || cfg.serverKey != "" {
logger.Info(fmt.Sprintf("Cassandra reader service started using https on port %s with cert %s key %s",
cfg.port, cfg.serverCert, cfg.serverKey))
errs <- http.ListenAndServeTLS(p, cfg.serverCert, cfg.serverKey, api.MakeHandler(repo, tc, ac, "cassandra-reader"))
errs <- http.ListenAndServeTLS(p, cfg.serverCert, cfg.serverKey, api.MakeHandler(repo, tc, ac, svcName, logger))
return
}
logger.Info(fmt.Sprintf("Cassandra reader service started, exposed port %s", cfg.port))
errs <- http.ListenAndServe(p, api.MakeHandler(repo, tc, ac, "cassandra-reader"))
errs <- http.ListenAndServe(p, api.MakeHandler(repo, tc, ac, svcName, logger))
}
+2 -2
View File
@@ -368,11 +368,11 @@ func startHTTPServer(svc certs.Service, cfg config, logger mflog.Logger, errs ch
if cfg.serverCert != "" || cfg.serverKey != "" {
logger.Info(fmt.Sprintf("Certs service started using https on port %s with cert %s key %s",
cfg.httpPort, cfg.serverCert, cfg.serverKey))
errs <- http.ListenAndServeTLS(p, cfg.serverCert, cfg.serverKey, api.MakeHandler(svc))
errs <- http.ListenAndServeTLS(p, cfg.serverCert, cfg.serverKey, api.MakeHandler(svc, logger))
return
}
logger.Info(fmt.Sprintf("Certs service started using http on port %s", cfg.httpPort))
errs <- http.ListenAndServe(p, api.MakeHandler(svc))
errs <- http.ListenAndServe(p, api.MakeHandler(svc, logger))
}
func loadCertificates(conf config) (tls.Certificate, *x509.Certificate, error) {
+1 -1
View File
@@ -110,7 +110,7 @@ func main() {
go func() {
p := fmt.Sprintf(":%s", cfg.port)
logger.Info(fmt.Sprintf("HTTP adapter service started on port %s", cfg.port))
errs <- http.ListenAndServe(p, api.MakeHandler(svc, tracer))
errs <- http.ListenAndServe(p, api.MakeHandler(svc, tracer, logger))
}()
go func() {
+3 -2
View File
@@ -29,6 +29,7 @@ import (
)
const (
svcName = "influxdb-reader"
defLogLevel = "error"
defPort = "8180"
defDB = "mainflux"
@@ -274,9 +275,9 @@ func startHTTPServer(repo readers.MessageRepository, tc mainflux.ThingsServiceCl
if cfg.serverCert != "" || cfg.serverKey != "" {
logger.Info(fmt.Sprintf("InfluxDB reader service started using https on port %s with cert %s key %s",
cfg.port, cfg.serverCert, cfg.serverKey))
errs <- http.ListenAndServeTLS(p, cfg.serverCert, cfg.serverKey, api.MakeHandler(repo, tc, ac, "influxdb-reader"))
errs <- http.ListenAndServeTLS(p, cfg.serverCert, cfg.serverKey, api.MakeHandler(repo, tc, ac, svcName, logger))
return
}
logger.Info(fmt.Sprintf("InfluxDB reader service started, exposed port %s", cfg.port))
errs <- http.ListenAndServe(p, api.MakeHandler(repo, tc, ac, "influxdb-reader"))
errs <- http.ListenAndServe(p, api.MakeHandler(repo, tc, ac, svcName, logger))
}
+3 -2
View File
@@ -34,6 +34,7 @@ import (
)
const (
svcName = "mongodb-reader"
defLogLevel = "error"
defPort = "8180"
defDB = "mainflux"
@@ -269,9 +270,9 @@ func startHTTPServer(repo readers.MessageRepository, tc mainflux.ThingsServiceCl
if cfg.serverCert != "" || cfg.serverKey != "" {
logger.Info(fmt.Sprintf("Mongo reader service started using https on port %s with cert %s key %s",
cfg.port, cfg.serverCert, cfg.serverKey))
errs <- http.ListenAndServeTLS(p, cfg.serverCert, cfg.serverKey, api.MakeHandler(repo, tc, ac, "mongodb-reader"))
errs <- http.ListenAndServeTLS(p, cfg.serverCert, cfg.serverKey, api.MakeHandler(repo, tc, ac, svcName, logger))
return
}
logger.Info(fmt.Sprintf("Mongo reader service started, exposed port %s", cfg.port))
errs <- http.ListenAndServe(p, api.MakeHandler(repo, tc, ac, "mongodb-reader"))
errs <- http.ListenAndServe(p, api.MakeHandler(repo, tc, ac, svcName, logger))
}
+1 -1
View File
@@ -219,5 +219,5 @@ func newRouteMapRepositoy(client *r.Client, prefix string, logger logger.Logger)
func startHTTPServer(svc opcua.Service, cfg config, logger logger.Logger, errs chan error) {
p := fmt.Sprintf(":%s", cfg.httpPort)
logger.Info(fmt.Sprintf("opcua-adapter service started, exposed port %s", cfg.httpPort))
errs <- http.ListenAndServe(p, api.MakeHandler(svc))
errs <- http.ListenAndServe(p, api.MakeHandler(svc, logger))
}
+1 -1
View File
@@ -281,5 +281,5 @@ func newService(db *sqlx.DB, logger logger.Logger) readers.MessageRepository {
func startHTTPServer(repo readers.MessageRepository, tc mainflux.ThingsServiceClient, ac mainflux.AuthServiceClient, port string, logger logger.Logger, errs chan error) {
p := fmt.Sprintf(":%s", port)
logger.Info(fmt.Sprintf("Postgres reader service started, exposed port %s", port))
errs <- http.ListenAndServe(p, api.MakeHandler(repo, tc, ac, svcName))
errs <- http.ListenAndServe(p, api.MakeHandler(repo, tc, ac, svcName, logger))
}
+2 -2
View File
@@ -126,11 +126,11 @@ func startHTTPServer(svc provision.Service, cfg provision.Config, logger logger.
if cfg.Server.ServerCert != "" || cfg.Server.ServerKey != "" {
logger.Info(fmt.Sprintf("Provision service started using https on port %s with cert %s key %s",
cfg.Server.HTTPPort, cfg.Server.ServerCert, cfg.Server.ServerKey))
errs <- http.ListenAndServeTLS(p, cfg.Server.ServerCert, cfg.Server.ServerKey, api.MakeHandler(svc))
errs <- http.ListenAndServeTLS(p, cfg.Server.ServerCert, cfg.Server.ServerKey, api.MakeHandler(svc, logger))
return
}
logger.Info(fmt.Sprintf("Provision service started using http on port %s", cfg.Server.HTTPPort))
errs <- http.ListenAndServe(p, api.MakeHandler(svc))
errs <- http.ListenAndServe(p, api.MakeHandler(svc, logger))
}
func loadConfigFromFile(file string) (provision.Config, error) {
+2 -2
View File
@@ -327,9 +327,9 @@ func startHTTPServer(tracer opentracing.Tracer, svc notifiers.Service, port stri
p := fmt.Sprintf(":%s", port)
if certFile != "" || keyFile != "" {
logger.Info(fmt.Sprintf("SMPP notifier service started using https, cert %s key %s, exposed port %s", certFile, keyFile, port))
errs <- http.ListenAndServeTLS(p, certFile, keyFile, api.MakeHandler(svc, tracer))
errs <- http.ListenAndServeTLS(p, certFile, keyFile, api.MakeHandler(svc, tracer, logger))
} else {
logger.Info(fmt.Sprintf("SMPP notifier service started using http, exposed port %s", port))
errs <- http.ListenAndServe(p, api.MakeHandler(svc, tracer))
errs <- http.ListenAndServe(p, api.MakeHandler(svc, tracer, logger))
}
}
+2 -2
View File
@@ -314,9 +314,9 @@ func startHTTPServer(tracer opentracing.Tracer, svc notifiers.Service, port stri
p := fmt.Sprintf(":%s", port)
if certFile != "" || keyFile != "" {
logger.Info(fmt.Sprintf("SMTP notifier service started using https, cert %s key %s, exposed port %s", certFile, keyFile, port))
errs <- http.ListenAndServeTLS(p, certFile, keyFile, api.MakeHandler(svc, tracer))
errs <- http.ListenAndServeTLS(p, certFile, keyFile, api.MakeHandler(svc, tracer, logger))
} else {
logger.Info(fmt.Sprintf("SMTP notifier service started using http, exposed port %s", port))
errs <- http.ListenAndServe(p, api.MakeHandler(svc, tracer))
errs <- http.ListenAndServe(p, api.MakeHandler(svc, tracer, logger))
}
}
+2 -2
View File
@@ -157,8 +157,8 @@ func main() {
svc := newService(auth, dbTracer, cacheTracer, db, cacheClient, esClient, logger)
errs := make(chan error, 2)
go startHTTPServer(thhttpapi.MakeHandler(thingsTracer, svc), cfg.httpPort, cfg, logger, errs)
go startHTTPServer(authhttpapi.MakeHandler(thingsTracer, svc), cfg.authHTTPPort, cfg, logger, errs)
go startHTTPServer(thhttpapi.MakeHandler(thingsTracer, svc, logger), cfg.httpPort, cfg, logger, errs)
go startHTTPServer(authhttpapi.MakeHandler(thingsTracer, svc, logger), cfg.authHTTPPort, cfg, logger, errs)
go startGRPCServer(svc, thingsTracer, cfg, logger, errs)
go func() {
+1 -1
View File
@@ -267,5 +267,5 @@ func newService(db *sqlx.DB, logger logger.Logger) readers.MessageRepository {
func startHTTPServer(repo readers.MessageRepository, tc mainflux.ThingsServiceClient, ac mainflux.AuthServiceClient, port string, logger logger.Logger, errs chan error) {
p := fmt.Sprintf(":%s", port)
logger.Info(fmt.Sprintf("Timescale reader service started, exposed port %s", port))
errs <- http.ListenAndServe(p, api.MakeHandler(repo, tc, ac, svcName))
errs <- http.ListenAndServe(p, api.MakeHandler(repo, tc, ac, svcName, logger))
}
+1 -1
View File
@@ -139,7 +139,7 @@ func main() {
tracer, closer := initJaeger("twins", cfg.jaegerURL, logger)
defer closer.Close()
errs := make(chan error, 2)
go startHTTPServer(twapi.MakeHandler(tracer, svc), cfg.httpPort, cfg, logger, errs)
go startHTTPServer(twapi.MakeHandler(tracer, svc, logger), cfg.httpPort, cfg, logger, errs)
go func() {
c := make(chan os.Signal)
+2 -2
View File
@@ -415,9 +415,9 @@ func startHTTPServer(tracer opentracing.Tracer, svc users.Service, port string,
p := fmt.Sprintf(":%s", port)
if certFile != "" || keyFile != "" {
logger.Info(fmt.Sprintf("Users service started using https, cert %s key %s, exposed port %s", certFile, keyFile, port))
errs <- http.ListenAndServeTLS(p, certFile, keyFile, api.MakeHandler(svc, tracer))
errs <- http.ListenAndServeTLS(p, certFile, keyFile, api.MakeHandler(svc, tracer, logger))
} else {
logger.Info(fmt.Sprintf("Users service started using http, exposed port %s", port))
errs <- http.ListenAndServe(p, api.MakeHandler(svc, tracer))
errs <- http.ListenAndServe(p, api.MakeHandler(svc, tracer, logger))
}
}
BIN
View File
Binary file not shown.
+13 -10
View File
@@ -17,7 +17,8 @@ import (
notifiers "github.com/mainflux/mainflux/consumers/notifiers"
httpapi "github.com/mainflux/mainflux/consumers/notifiers/api"
"github.com/mainflux/mainflux/consumers/notifiers/mocks"
"github.com/mainflux/mainflux/internal/httputil"
"github.com/mainflux/mainflux/internal/apiutil"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/mainflux/mainflux/pkg/uuid"
"github.com/opentracing/opentracing-go/mocktracer"
@@ -36,9 +37,10 @@ const (
)
var (
notFoundRes = toJSON(httputil.ErrorRes{Err: errors.ErrNotFound.Error()})
unauthRes = toJSON(httputil.ErrorRes{Err: errors.ErrAuthentication.Error()})
invalidRes = toJSON(httputil.ErrorRes{Err: errors.ErrInvalidQueryParams.Error()})
notFoundRes = toJSON(apiutil.ErrorRes{Err: errors.ErrNotFound.Error()})
unauthRes = toJSON(apiutil.ErrorRes{Err: errors.ErrAuthentication.Error()})
invalidRes = toJSON(apiutil.ErrorRes{Err: errors.ErrInvalidQueryParams.Error()})
missingTokRes = toJSON(apiutil.ErrorRes{Err: apiutil.ErrBearerToken.Error()})
)
type testRequest struct {
@@ -56,7 +58,7 @@ func (tr testRequest) make() (*http.Response, error) {
return nil, err
}
if tr.token != "" {
req.Header.Set("Authorization", httputil.BearerPrefix+tr.token)
req.Header.Set("Authorization", apiutil.BearerPrefix+tr.token)
}
if tr.contentType != "" {
req.Header.Set("Content-Type", tr.contentType)
@@ -74,7 +76,8 @@ func newService(tokens map[string]string) notifiers.Service {
}
func newServer(svc notifiers.Service) *httptest.Server {
mux := httpapi.MakeHandler(svc, mocktracer.New())
logger := logger.NewMock()
mux := httpapi.MakeHandler(svc, mocktracer.New(), logger)
return httptest.NewServer(mux)
}
@@ -242,7 +245,7 @@ func TestView(t *testing.T) {
id: id,
auth: "",
status: http.StatusUnauthorized,
res: unauthRes,
res: missingTokRes,
},
}
@@ -362,7 +365,7 @@ func TestList(t *testing.T) {
desc: "list with empty auth token",
auth: "",
status: http.StatusUnauthorized,
res: unauthRes,
res: missingTokRes,
},
}
@@ -418,7 +421,7 @@ func TestRemove(t *testing.T) {
desc: "remove empty id",
id: "",
auth: token,
status: http.StatusNotFound,
status: http.StatusBadRequest,
},
{
desc: "view with invalid auth token",
@@ -432,7 +435,7 @@ func TestRemove(t *testing.T) {
id: id,
auth: "",
status: http.StatusUnauthorized,
res: unauthRes,
res: missingTokRes,
},
}
+7 -14
View File
@@ -3,14 +3,7 @@
package api
import (
"github.com/mainflux/mainflux/pkg/errors"
)
var (
errInvalidTopic = errors.New("invalid Subscription topic")
errInvalidContact = errors.New("invalid Subscription contact")
)
import "github.com/mainflux/mainflux/internal/apiutil"
type createSubReq struct {
token string
@@ -20,13 +13,13 @@ type createSubReq struct {
func (req createSubReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
if req.Topic == "" {
return errInvalidTopic
return apiutil.ErrInvalidTopic
}
if req.Contact == "" {
return errInvalidContact
return apiutil.ErrInvalidContact
}
return nil
}
@@ -38,10 +31,10 @@ type subReq struct {
func (req subReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
if req.id == "" {
return errors.ErrNotFound
return apiutil.ErrMissingID
}
return nil
}
@@ -56,7 +49,7 @@ type listSubsReq struct {
func (req listSubsReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
return nil
}
+28 -30
View File
@@ -14,18 +14,27 @@ import (
"github.com/go-zoo/bone"
"github.com/mainflux/mainflux"
notifiers "github.com/mainflux/mainflux/consumers/notifiers"
"github.com/mainflux/mainflux/internal/httputil"
"github.com/mainflux/mainflux/internal/apiutil"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
opentracing "github.com/opentracing/opentracing-go"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
const contentType = "application/json"
const (
contentType = "application/json"
offsetKey = "offset"
limitKey = "limit"
topicKey = "topic"
contactKey = "contact"
defOffset = 0
defLimit = 20
)
// MakeHandler returns a HTTP handler for API endpoints.
func MakeHandler(svc notifiers.Service, tracer opentracing.Tracer) http.Handler {
func MakeHandler(svc notifiers.Service, tracer opentracing.Tracer, logger logger.Logger) http.Handler {
opts := []kithttp.ServerOption{
kithttp.ServerErrorEncoder(encodeError),
kithttp.ServerErrorEncoder(apiutil.LoggingErrorEncoder(logger, encodeError)),
}
mux := bone.New()
@@ -68,56 +77,43 @@ func decodeCreate(_ context.Context, r *http.Request) (interface{}, error) {
if !strings.Contains(r.Header.Get("Content-Type"), contentType) {
return nil, errors.ErrUnsupportedContentType
}
var req createSubReq
req := createSubReq{token: apiutil.ExtractBearerToken(r)}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return nil, errors.Wrap(errors.ErrMalformedEntity, err)
}
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req.token = t
return req, nil
}
func decodeSubscription(_ context.Context, r *http.Request) (interface{}, error) {
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req := subReq{
id: bone.GetValue(r, "id"),
token: t,
token: apiutil.ExtractBearerToken(r),
}
return req, nil
}
func decodeList(_ context.Context, r *http.Request) (interface{}, error) {
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req := listSubsReq{
token: t,
}
vals := bone.GetQuery(r, "topic")
req := listSubsReq{token: apiutil.ExtractBearerToken(r)}
vals := bone.GetQuery(r, topicKey)
if len(vals) > 0 {
req.topic = vals[0]
}
vals = bone.GetQuery(r, "contact")
vals = bone.GetQuery(r, contactKey)
if len(vals) > 0 {
req.contact = vals[0]
}
offset, err := httputil.ReadUintQuery(r, "offset", 0)
offset, err := apiutil.ReadUintQuery(r, offsetKey, defOffset)
if err != nil {
return listSubsReq{}, err
}
req.offset = uint(offset)
limit, err := httputil.ReadUintQuery(r, "limit", 20)
limit, err := apiutil.ReadUintQuery(r, limitKey, defLimit)
if err != nil {
return listSubsReq{}, err
}
@@ -145,13 +141,15 @@ func encodeResponse(_ context.Context, w http.ResponseWriter, response interface
func encodeError(_ context.Context, err error, w http.ResponseWriter) {
switch {
case errors.Contains(err, errors.ErrMalformedEntity),
errors.Contains(err, errInvalidContact),
errors.Contains(err, errInvalidTopic),
err == apiutil.ErrInvalidContact,
err == apiutil.ErrInvalidTopic,
err == apiutil.ErrMissingID,
errors.Contains(err, errors.ErrInvalidQueryParams):
w.WriteHeader(http.StatusBadRequest)
case errors.Contains(err, errors.ErrNotFound):
w.WriteHeader(http.StatusNotFound)
case errors.Contains(err, errors.ErrAuthentication):
case errors.Contains(err, errors.ErrAuthentication),
err == apiutil.ErrBearerToken:
w.WriteHeader(http.StatusUnauthorized)
case errors.Contains(err, errors.ErrConflict):
w.WriteHeader(http.StatusConflict)
@@ -169,7 +167,7 @@ func encodeError(_ context.Context, err error, w http.ResponseWriter) {
if errorVal, ok := err.(errors.Error); ok {
w.Header().Set("Content-Type", contentType)
if err := json.NewEncoder(w).Encode(httputil.ErrorRes{Err: errorVal.Msg()}); err != nil {
if err := json.NewEncoder(w).Encode(apiutil.ErrorRes{Err: errorVal.Msg()}); err != nil {
w.WriteHeader(http.StatusInternalServerError)
}
}
+5 -3
View File
@@ -17,7 +17,8 @@ import (
adapter "github.com/mainflux/mainflux/http"
"github.com/mainflux/mainflux/http/api"
"github.com/mainflux/mainflux/http/mocks"
"github.com/mainflux/mainflux/internal/httputil"
"github.com/mainflux/mainflux/internal/apiutil"
"github.com/mainflux/mainflux/logger"
"github.com/stretchr/testify/assert"
)
@@ -27,7 +28,8 @@ func newService(cc mainflux.ThingsServiceClient) adapter.Service {
}
func newHTTPServer(svc adapter.Service) *httptest.Server {
mux := api.MakeHandler(svc, mocktracer.New())
logger := logger.NewMock()
mux := api.MakeHandler(svc, mocktracer.New(), logger)
return httptest.NewServer(mux)
}
@@ -48,7 +50,7 @@ func (tr testRequest) make() (*http.Response, error) {
}
if tr.token != "" {
req.Header.Set("Authorization", httputil.BearerPrefix+tr.token)
req.Header.Set("Authorization", apiutil.BearerPrefix+tr.token)
}
if tr.basicAuth && tr.token != "" {
req.SetBasicAuth("", tr.token)
+2 -2
View File
@@ -4,7 +4,7 @@
package api
import (
"github.com/mainflux/mainflux/pkg/errors"
"github.com/mainflux/mainflux/internal/apiutil"
"github.com/mainflux/mainflux/pkg/messaging"
)
@@ -15,7 +15,7 @@ type publishReq struct {
func (req publishReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
return nil
+7 -8
View File
@@ -18,7 +18,8 @@ import (
"github.com/go-zoo/bone"
"github.com/mainflux/mainflux"
adapter "github.com/mainflux/mainflux/http"
"github.com/mainflux/mainflux/internal/httputil"
"github.com/mainflux/mainflux/internal/apiutil"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/mainflux/mainflux/pkg/messaging"
opentracing "github.com/opentracing/opentracing-go"
@@ -39,7 +40,7 @@ var (
var channelPartRegExp = regexp.MustCompile(`^/channels/([\w\-]+)/messages(/[^?]*)?(\?.*)?$`)
// MakeHandler returns a HTTP handler for API endpoints.
func MakeHandler(svc adapter.Service, tracer opentracing.Tracer) http.Handler {
func MakeHandler(svc adapter.Service, tracer opentracing.Tracer, logger logger.Logger) http.Handler {
opts := []kithttp.ServerOption{
kithttp.ServerErrorEncoder(encodeError),
}
@@ -115,10 +116,7 @@ func decodeRequest(ctx context.Context, r *http.Request) (interface{}, error) {
case ok:
token = pass
case !ok:
token, err = httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
token = apiutil.ExtractBearerToken(r)
}
payload, err := ioutil.ReadAll(r.Body)
@@ -148,7 +146,8 @@ func encodeResponse(_ context.Context, w http.ResponseWriter, response interface
func encodeError(_ context.Context, err error, w http.ResponseWriter) {
switch {
case errors.Contains(err, errors.ErrAuthentication):
case errors.Contains(err, errors.ErrAuthentication),
err == apiutil.ErrBearerToken:
w.WriteHeader(http.StatusUnauthorized)
case errors.Contains(err, errors.ErrAuthorization):
w.WriteHeader(http.StatusForbidden)
@@ -178,7 +177,7 @@ func encodeError(_ context.Context, err error, w http.ResponseWriter) {
if errorVal, ok := err.(errors.Error); ok {
w.Header().Set("Content-Type", contentType)
if err := json.NewEncoder(w).Encode(httputil.ErrorRes{Err: errorVal.Msg()}); err != nil {
if err := json.NewEncoder(w).Encode(apiutil.ErrorRes{Err: errorVal.Msg()}); err != nil {
w.WriteHeader(http.StatusInternalServerError)
}
}
+95
View File
@@ -0,0 +1,95 @@
// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
package apiutil
import "github.com/mainflux/mainflux/pkg/errors"
// Errors defined in this file are used by the LoggingErrorEncoder decorator
// to distinguish and log API request validation errors and avoid that service
// errors are logged twice.
var (
// ErrBearerToken indicates missing or invalid bearer user token.
ErrBearerToken = errors.New("missing or invalid bearer user token")
// ErrBearerKey indicates missing or invalid bearer entity key.
ErrBearerKey = errors.New("missing or invalid bearer entity key")
// ErrMissingID indicates missing entity ID.
ErrMissingID = errors.New("missing entity id")
// ErrInvalidAuthKey indicates invalid auth key.
ErrInvalidAuthKey = errors.New("invalid auth key")
// ErrInvalidIDFormat indicates an invalid ID format.
ErrInvalidIDFormat = errors.New("invalid id format provided")
// ErrNameSize indicates that name size exceeds the max.
ErrNameSize = errors.New("invalid name size")
// ErrLimitSize indicates that an invalid limit.
ErrLimitSize = errors.New("invalid limit size")
// ErrOffsetSize indicates an invalid offset.
ErrOffsetSize = errors.New("invalid offset size")
// ErrInvalidOrder indicates an invalid list order.
ErrInvalidOrder = errors.New("invalid list order provided")
// ErrInvalidDirection indicates an invalid list direction.
ErrInvalidDirection = errors.New("invalid list direction provided")
// ErrEmptyList indicates that entity data is empty.
ErrEmptyList = errors.New("empty list provided")
// ErrMalformedPolicy indicates that policies are malformed.
ErrMalformedPolicy = errors.New("falmormed policy")
// ErrMissingPolicySub indicates that policies are subject.
ErrMissingPolicySub = errors.New("falmormed policy subject")
// ErrMissingPolicyObj indicates missing policies object.
ErrMissingPolicyObj = errors.New("falmormed policy object")
// ErrMissingPolicyAct indicates missing policies action.
ErrMissingPolicyAct = errors.New("falmormed policy action")
// ErrMissingCertData indicates missing cert data (ttl, key_type or key_bits).
ErrMissingCertData = errors.New("missing certificate data")
// ErrInvalidTopic indicates an invalid subscription topic.
ErrInvalidTopic = errors.New("invalid Subscription topic")
// ErrInvalidContact indicates an invalid subscription contract.
ErrInvalidContact = errors.New("invalid Subscription contact")
// ErrMissingEmail indicates missing email.
ErrMissingEmail = errors.New("missing email")
// ErrMissingHost indicates missing host.
ErrMissingHost = errors.New("missing host")
// ErrMissingPass indicates missing password.
ErrMissingPass = errors.New("missing password")
// ErrMissingConfPass indicates missing conf password.
ErrMissingConfPass = errors.New("missing conf password")
// ErrInvalidResetPass indicates an invalid reset password.
ErrInvalidResetPass = errors.New("invalid reset password")
// ErrInvalidComparator indicates an invalid comparator.
ErrInvalidComparator = errors.New("invalid comparator")
// ErrMissingMemberType indicates missing group member type.
ErrMissingMemberType = errors.New("missing group member type")
// ErrInvalidAPIKey indicates an invalid API key type.
ErrInvalidAPIKey = errors.New("invalid api key type")
// ErrMaxLevelExceeded indicates an invalid group level.
ErrMaxLevelExceeded = errors.New("invalid group level (should be lower than 5)")
// ErrBootstrapState indicates an invalid boostrap state.
ErrBootstrapState = errors.New("invalid bootstrap state")
)
@@ -1,7 +1,7 @@
// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
package httputil
package apiutil
// ErrorRes represents the HTTP error response body.
type ErrorRes struct {
+23
View File
@@ -0,0 +1,23 @@
// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
package apiutil
import (
"net/http"
"strings"
)
// BearerPrefix represents the token prefix for Bearer authentication scheme.
const BearerPrefix = "Bearer "
// ExtractBearerToken returns value of the bearer token. If there is no bearer token - an empty value is returned.
func ExtractBearerToken(r *http.Request) string {
token := r.Header.Get("Authorization")
if !strings.HasPrefix(token, BearerPrefix) {
return ""
}
return strings.TrimPrefix(token, BearerPrefix)
}
@@ -1,17 +1,59 @@
// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
package httputil
package apiutil
import (
"context"
"encoding/json"
"net/http"
"strconv"
kithttp "github.com/go-kit/kit/transport/http"
"github.com/go-zoo/bone"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
)
// LoggingErrorEncoder is a go-kit error encoder logging decorator.
func LoggingErrorEncoder(logger logger.Logger, enc kithttp.ErrorEncoder) kithttp.ErrorEncoder {
return func(ctx context.Context, err error, w http.ResponseWriter) {
switch err {
case ErrBearerToken,
ErrMissingID,
ErrBearerKey,
ErrInvalidAuthKey,
ErrInvalidIDFormat,
ErrNameSize,
ErrLimitSize,
ErrOffsetSize,
ErrInvalidOrder,
ErrInvalidDirection,
ErrEmptyList,
ErrMalformedPolicy,
ErrMissingPolicySub,
ErrMissingPolicyObj,
ErrMissingPolicyAct,
ErrMissingCertData,
ErrInvalidTopic,
ErrInvalidContact,
ErrMissingEmail,
ErrMissingHost,
ErrMissingPass,
ErrMissingConfPass,
ErrInvalidResetPass,
ErrInvalidComparator,
ErrMissingMemberType,
ErrInvalidAPIKey,
ErrMaxLevelExceeded,
ErrBootstrapState:
logger.Error(err.Error())
}
enc(ctx, err, w)
}
}
// ReadUintQuery reads the value of uint64 http query parameters for a given key
func ReadUintQuery(r *http.Request, key string, def uint64) (uint64, error) {
vals := bone.GetQuery(r, key)
-25
View File
@@ -1,25 +0,0 @@
// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
package httputil
import (
"net/http"
"strings"
"github.com/mainflux/mainflux/pkg/errors"
)
// BearerPrefix represents the token prefix for Bearer authentication scheme.
const BearerPrefix = "Bearer "
// ExtractAuthToken reads the value of request Authorization and removes the Bearer substring or returns error if it does not exist
func ExtractAuthToken(r *http.Request) (string, error) {
token := r.Header.Get("Authorization")
if !strings.HasPrefix(token, BearerPrefix) {
return token, errors.ErrAuthentication
}
return strings.TrimPrefix(token, BearerPrefix), nil
}
-32
View File
@@ -1,32 +0,0 @@
// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
package httputil
import (
"context"
"errors"
"net/http"
kithttp "github.com/go-kit/kit/transport/http"
"github.com/mainflux/mainflux/logger"
)
var (
// ErrMissingToken indicates missing user token.
ErrMissingToken = errors.New("missing user token")
// ErrMissingID indicates missing entity ID.
ErrMissingID = errors.New("missing entity id")
)
// Middleware is an ErrorEncoder middleware
type Middleware func(kithttp.ErrorEncoder) kithttp.ErrorEncoder
// LoggingErrorEncoder is a go-kit error encoder logging decorator.
func LoggingErrorEncoder(logger logger.Logger, enc kithttp.ErrorEncoder) kithttp.ErrorEncoder {
return func(ctx context.Context, err error, w http.ResponseWriter) {
logger.Error(err.Error())
enc(ctx, err, w)
}
}
+1
View File
@@ -19,6 +19,7 @@ const (
Debug
)
// ErrInvalidLogLevel indicates an unrecognized log level.
var ErrInvalidLogLevel = errors.New("unrecognized log level")
// Level represents severity level while logging.
+2 -1
View File
@@ -5,9 +5,10 @@ package logger
import (
"fmt"
"github.com/go-kit/kit/log"
"io"
"time"
"github.com/go-kit/kit/log"
)
// Logger specifies logging API.
+29
View File
@@ -0,0 +1,29 @@
// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
package logger
var _ Logger = (*loggerMock)(nil)
type loggerMock struct{}
// NewMock returns wrapped go kit logger mock.
func NewMock() Logger {
return &loggerMock{}
}
func (l loggerMock) Debug(msg string) {
return
}
func (l loggerMock) Info(msg string) {
return
}
func (l loggerMock) Warn(msg string) {
return
}
func (l loggerMock) Error(msg string) {
return
}
+2 -2
View File
@@ -3,7 +3,7 @@
package api
import "github.com/mainflux/mainflux/pkg/errors"
import "github.com/mainflux/mainflux/internal/apiutil"
type browseReq struct {
ServerURI string
@@ -13,7 +13,7 @@ type browseReq struct {
func (req *browseReq) validate() error {
if req.ServerURI == "" {
return errors.ErrMalformedEntity
return apiutil.ErrMissingID
}
return nil
+10 -8
View File
@@ -11,7 +11,8 @@ import (
kithttp "github.com/go-kit/kit/transport/http"
"github.com/go-zoo/bone"
"github.com/mainflux/mainflux"
"github.com/mainflux/mainflux/internal/httputil"
"github.com/mainflux/mainflux/internal/apiutil"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/opcua"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/prometheus/client_golang/prometheus/promhttp"
@@ -29,9 +30,9 @@ const (
)
// MakeHandler returns a HTTP handler for API endpoints.
func MakeHandler(svc opcua.Service) http.Handler {
func MakeHandler(svc opcua.Service, logger logger.Logger) http.Handler {
opts := []kithttp.ServerOption{
kithttp.ServerErrorEncoder(encodeError),
kithttp.ServerErrorEncoder(apiutil.LoggingErrorEncoder(logger, encodeError)),
}
r := bone.New()
@@ -50,17 +51,17 @@ func MakeHandler(svc opcua.Service) http.Handler {
}
func decodeBrowse(_ context.Context, r *http.Request) (interface{}, error) {
s, err := httputil.ReadStringQuery(r, serverParam, "")
s, err := apiutil.ReadStringQuery(r, serverParam, "")
if err != nil {
return nil, err
}
n, err := httputil.ReadStringQuery(r, namespaceParam, "")
n, err := apiutil.ReadStringQuery(r, namespaceParam, "")
if err != nil {
return nil, err
}
i, err := httputil.ReadStringQuery(r, identifierParam, "")
i, err := apiutil.ReadStringQuery(r, identifierParam, "")
if err != nil {
return nil, err
}
@@ -100,7 +101,8 @@ func encodeResponse(_ context.Context, w http.ResponseWriter, response interface
func encodeError(_ context.Context, err error, w http.ResponseWriter) {
switch {
case errors.Contains(err, errors.ErrInvalidQueryParams),
errors.Contains(err, errors.ErrMalformedEntity):
errors.Contains(err, errors.ErrMalformedEntity),
err == apiutil.ErrMissingID:
w.WriteHeader(http.StatusBadRequest)
default:
@@ -109,7 +111,7 @@ func encodeError(_ context.Context, err error, w http.ResponseWriter) {
if errorVal, ok := err.(errors.Error); ok {
w.Header().Set("Content-Type", contentType)
if err := json.NewEncoder(w).Encode(httputil.ErrorRes{Err: errorVal.Msg()}); err != nil {
if err := json.NewEncoder(w).Encode(apiutil.ErrorRes{Err: errorVal.Msg()}); err != nil {
w.WriteHeader(http.StatusInternalServerError)
}
}
+5 -5
View File
@@ -27,7 +27,7 @@ func TestCreateChannel(t *testing.T) {
ts := newThingsServer(svc)
defer ts.Close()
chWrongExtID := sdk.Channel{ID: "b0aa-000000000001", Name: "1", Metadata:metadata}
chWrongExtID := sdk.Channel{ID: "b0aa-000000000001", Name: "1", Metadata: metadata}
sdkConf := sdk.Config{
ThingsURL: ts.URL,
@@ -73,14 +73,14 @@ func TestCreateChannel(t *testing.T) {
empty: false,
},
{
desc: "create a new channel with external UUID",
desc: "create a new channel with external UUID",
channel: ch2,
token: token,
err: nil,
empty: false,
},
{
desc: "create a new channel with wrong external UUID",
desc: "create a new channel with wrong external UUID",
channel: chWrongExtID,
token: token,
err: createError(sdk.ErrFailedCreation, http.StatusBadRequest),
@@ -269,8 +269,8 @@ func TestChannels(t *testing.T) {
token: token,
offset: 0,
limit: 0,
err: nil,
response: channels[0:10],
err: createError(sdk.ErrFailedFetch, http.StatusBadRequest),
response: nil,
},
{
desc: "get a list of channels with limit greater than max",
+3 -1
View File
@@ -13,6 +13,7 @@ import (
adapter "github.com/mainflux/mainflux/http"
"github.com/mainflux/mainflux/http/api"
"github.com/mainflux/mainflux/http/mocks"
"github.com/mainflux/mainflux/logger"
sdk "github.com/mainflux/mainflux/pkg/sdk/go"
"github.com/opentracing/opentracing-go/mocktracer"
"github.com/stretchr/testify/assert"
@@ -24,7 +25,8 @@ func newMessageService(cc mainflux.ThingsServiceClient) adapter.Service {
}
func newMessageServer(svc adapter.Service) *httptest.Server {
mux := api.MakeHandler(svc, mocktracer.New())
logger := logger.NewMock()
mux := api.MakeHandler(svc, mocktracer.New(), logger)
return httptest.NewServer(mux)
}
+2 -2
View File
@@ -10,7 +10,7 @@ import (
"time"
"github.com/mainflux/mainflux"
"github.com/mainflux/mainflux/internal/httputil"
"github.com/mainflux/mainflux/internal/apiutil"
)
const (
@@ -328,7 +328,7 @@ func NewSDK(conf Config) SDK {
func (sdk mfSDK) sendRequest(req *http.Request, token, contentType string) (*http.Response, error) {
if token != "" {
req.Header.Set("Authorization", httputil.BearerPrefix+token)
req.Header.Set("Authorization", apiutil.BearerPrefix+token)
}
if contentType != "" {
+5 -3
View File
@@ -9,6 +9,7 @@ import (
"net/http/httptest"
"testing"
"github.com/mainflux/mainflux/logger"
sdk "github.com/mainflux/mainflux/pkg/sdk/go"
"github.com/mainflux/mainflux/pkg/uuid"
"github.com/mainflux/mainflux/things"
@@ -55,7 +56,8 @@ func newThingsService(tokens map[string]string) things.Service {
}
func newThingsServer(svc things.Service) *httptest.Server {
mux := httpapi.MakeHandler(mocktracer.New(), svc)
logger := logger.NewMock()
mux := httpapi.MakeHandler(mocktracer.New(), svc, logger)
return httptest.NewServer(mux)
}
@@ -316,8 +318,8 @@ func TestThings(t *testing.T) {
token: token,
offset: 0,
limit: 0,
err: nil,
response: things[0:10],
err: createError(sdk.ErrFailedFetch, http.StatusBadRequest),
response: nil,
},
{
desc: "get a list of things with limit greater than max",
+3 -1
View File
@@ -12,6 +12,7 @@ import (
"testing"
"github.com/mainflux/mainflux"
"github.com/mainflux/mainflux/logger"
sdk "github.com/mainflux/mainflux/pkg/sdk/go"
"github.com/mainflux/mainflux/pkg/uuid"
"github.com/mainflux/mainflux/users"
@@ -46,7 +47,8 @@ func newUserService() users.Service {
}
func newUserServer(svc users.Service) *httptest.Server {
mux := api.MakeHandler(svc, mocktracer.New())
logger := logger.NewMock()
mux := api.MakeHandler(svc, mocktracer.New(), logger)
return httptest.NewServer(mux)
}
+9 -4
View File
@@ -1,6 +1,6 @@
package api
import "github.com/mainflux/mainflux/pkg/errors"
import "github.com/mainflux/mainflux/internal/apiutil"
type provisionReq struct {
token string
@@ -10,9 +10,14 @@ type provisionReq struct {
}
func (req provisionReq) validate() error {
if req.ExternalID == "" || req.ExternalKey == "" {
return errors.ErrMalformedEntity
if req.ExternalID == "" {
return apiutil.ErrMissingID
}
if req.ExternalKey == "" {
return apiutil.ErrBearerKey
}
return nil
}
@@ -22,7 +27,7 @@ type mappingReq struct {
func (req mappingReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
return nil
}
+2 -1
View File
@@ -4,6 +4,7 @@ import (
"fmt"
"testing"
"github.com/mainflux/mainflux/internal/apiutil"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/stretchr/testify/assert"
)
@@ -21,7 +22,7 @@ func TestValidate(t *testing.T) {
err: nil,
},
"external id for device empty": {
err: errors.ErrMalformedEntity,
err: apiutil.ErrMissingID,
},
}
+15 -17
View File
@@ -8,7 +8,8 @@ import (
kithttp "github.com/go-kit/kit/transport/http"
"github.com/go-zoo/bone"
"github.com/mainflux/mainflux"
"github.com/mainflux/mainflux/internal/httputil"
"github.com/mainflux/mainflux/internal/apiutil"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/mainflux/mainflux/provision"
"github.com/prometheus/client_golang/prometheus/promhttp"
@@ -19,10 +20,10 @@ const (
)
// MakeHandler returns a HTTP handler for API endpoints.
func MakeHandler(svc provision.Service) http.Handler {
func MakeHandler(svc provision.Service, logger logger.Logger) http.Handler {
opts := []kithttp.ServerOption{
kithttp.ServerErrorEncoder(encodeError),
kithttp.ServerErrorEncoder(apiutil.LoggingErrorEncoder(logger, encodeError)),
}
r := bone.New()
@@ -69,11 +70,8 @@ func decodeProvisionRequest(_ context.Context, r *http.Request) (interface{}, er
if r.Header.Get("Content-Type") != contentType {
return nil, errors.ErrUnsupportedContentType
}
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req := provisionReq{token: t}
req := provisionReq{token: apiutil.ExtractBearerToken(r)}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return nil, err
}
@@ -85,25 +83,25 @@ func decodeMappingRequest(_ context.Context, r *http.Request) (interface{}, erro
if r.Header.Get("Content-Type") != contentType {
return nil, errors.ErrUnsupportedContentType
}
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req := mappingReq{token: t}
req := mappingReq{token: apiutil.ExtractBearerToken(r)}
return req, nil
}
func encodeError(_ context.Context, err error, w http.ResponseWriter) {
switch {
case errors.Contains(err, errors.ErrAuthentication),
err == apiutil.ErrBearerToken:
w.WriteHeader(http.StatusUnauthorized)
case errors.Contains(err, errors.ErrUnsupportedContentType):
w.WriteHeader(http.StatusUnsupportedMediaType)
case errors.Contains(err, errors.ErrMalformedEntity):
case errors.Contains(err, errors.ErrMalformedEntity),
err == apiutil.ErrMissingID,
err == apiutil.ErrBearerKey:
w.WriteHeader(http.StatusBadRequest)
case errors.Contains(err, errors.ErrConflict):
w.WriteHeader(http.StatusConflict)
case errors.Contains(err, errors.ErrAuthentication):
w.WriteHeader(http.StatusUnauthorized)
default:
w.WriteHeader(http.StatusInternalServerError)
@@ -111,7 +109,7 @@ func encodeError(_ context.Context, err error, w http.ResponseWriter) {
if errorVal, ok := err.(errors.Error); ok {
w.Header().Set("Content-Type", contentType)
if err := json.NewEncoder(w).Encode(httputil.ErrorRes{Err: errorVal.Msg()}); err != nil {
if err := json.NewEncoder(w).Encode(apiutil.ErrorRes{Err: errorVal.Msg()}); err != nil {
w.WriteHeader(http.StatusInternalServerError)
}
}
+4 -3
View File
@@ -13,7 +13,7 @@ import (
"time"
"github.com/mainflux/mainflux"
"github.com/mainflux/mainflux/internal/httputil"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/transformers/senml"
"github.com/mainflux/mainflux/pkg/uuid"
"github.com/mainflux/mainflux/readers"
@@ -49,7 +49,8 @@ var (
)
func newServer(repo readers.MessageRepository, tc mainflux.ThingsServiceClient, ac mainflux.AuthServiceClient) *httptest.Server {
mux := api.MakeHandler(repo, tc, ac, svcName)
logger := logger.NewMock()
mux := api.MakeHandler(repo, tc, ac, svcName, logger)
return httptest.NewServer(mux)
}
@@ -67,7 +68,7 @@ func (tr testRequest) make() (*http.Response, error) {
return nil, err
}
if tr.token != "" {
req.Header.Set("Authorization", httputil.BearerPrefix+tr.token)
req.Header.Set("Authorization", tr.token)
}
return tr.client.Do(req)
+15 -6
View File
@@ -4,10 +4,12 @@
package api
import (
"github.com/mainflux/mainflux/pkg/errors"
"github.com/mainflux/mainflux/internal/apiutil"
"github.com/mainflux/mainflux/readers"
)
const maxLimitSize = 1000
type apiReq interface {
validate() error
}
@@ -20,21 +22,28 @@ type listMessagesReq struct {
func (req listMessagesReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
if req.chanID == "" {
return errors.ErrMalformedEntity
return apiutil.ErrMissingID
}
if req.pageMeta.Limit < 1 || req.pageMeta.Offset < 0 {
return errors.ErrInvalidQueryParams
if req.pageMeta.Limit < 1 || req.pageMeta.Limit > maxLimitSize {
return apiutil.ErrLimitSize
}
if req.pageMeta.Offset < 0 {
return apiutil.ErrOffsetSize
}
if req.pageMeta.Comparator != "" &&
req.pageMeta.Comparator != readers.EqualKey &&
req.pageMeta.Comparator != readers.LowerThanKey &&
req.pageMeta.Comparator != readers.LowerThanEqualKey &&
req.pageMeta.Comparator != readers.GreaterThanKey &&
req.pageMeta.Comparator != readers.GreaterThanEqualKey {
return errors.ErrInvalidQueryParams
return apiutil.ErrInvalidComparator
}
return nil
+26 -26
View File
@@ -12,7 +12,8 @@ import (
kithttp "github.com/go-kit/kit/transport/http"
"github.com/go-zoo/bone"
"github.com/mainflux/mainflux"
"github.com/mainflux/mainflux/internal/httputil"
"github.com/mainflux/mainflux/internal/apiutil"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/mainflux/mainflux/readers"
"github.com/prometheus/client_golang/prometheus/promhttp"
@@ -51,7 +52,7 @@ var (
)
// MakeHandler returns a HTTP handler for API endpoints.
func MakeHandler(svc readers.MessageRepository, tc mainflux.ThingsServiceClient, ac mainflux.AuthServiceClient, svcName string) http.Handler {
func MakeHandler(svc readers.MessageRepository, tc mainflux.ThingsServiceClient, ac mainflux.AuthServiceClient, svcName string, logger logger.Logger) http.Handler {
thingsAuth = tc
usersAuth = ac
@@ -74,79 +75,74 @@ func MakeHandler(svc readers.MessageRepository, tc mainflux.ThingsServiceClient,
}
func decodeList(ctx context.Context, r *http.Request) (interface{}, error) {
offset, err := httputil.ReadUintQuery(r, offsetKey, defOffset)
offset, err := apiutil.ReadUintQuery(r, offsetKey, defOffset)
if err != nil {
return nil, err
}
limit, err := httputil.ReadUintQuery(r, limitKey, defLimit)
limit, err := apiutil.ReadUintQuery(r, limitKey, defLimit)
if err != nil {
return nil, err
}
format, err := httputil.ReadStringQuery(r, formatKey, defFormat)
format, err := apiutil.ReadStringQuery(r, formatKey, defFormat)
if err != nil {
return nil, err
}
subtopic, err := httputil.ReadStringQuery(r, subtopicKey, "")
subtopic, err := apiutil.ReadStringQuery(r, subtopicKey, "")
if err != nil {
return nil, err
}
publisher, err := httputil.ReadStringQuery(r, publisherKey, "")
publisher, err := apiutil.ReadStringQuery(r, publisherKey, "")
if err != nil {
return nil, err
}
protocol, err := httputil.ReadStringQuery(r, protocolKey, "")
protocol, err := apiutil.ReadStringQuery(r, protocolKey, "")
if err != nil {
return nil, err
}
name, err := httputil.ReadStringQuery(r, nameKey, "")
name, err := apiutil.ReadStringQuery(r, nameKey, "")
if err != nil {
return nil, err
}
v, err := httputil.ReadFloatQuery(r, valueKey, 0)
v, err := apiutil.ReadFloatQuery(r, valueKey, 0)
if err != nil {
return nil, err
}
comparator, err := httputil.ReadStringQuery(r, comparatorKey, "")
comparator, err := apiutil.ReadStringQuery(r, comparatorKey, "")
if err != nil {
return nil, err
}
vs, err := httputil.ReadStringQuery(r, stringValueKey, "")
vs, err := apiutil.ReadStringQuery(r, stringValueKey, "")
if err != nil {
return nil, err
}
vd, err := httputil.ReadStringQuery(r, dataValueKey, "")
vd, err := apiutil.ReadStringQuery(r, dataValueKey, "")
if err != nil {
return nil, err
}
from, err := httputil.ReadFloatQuery(r, fromKey, 0)
from, err := apiutil.ReadFloatQuery(r, fromKey, 0)
if err != nil {
return nil, err
}
to, err := httputil.ReadFloatQuery(r, toKey, 0)
if err != nil {
return nil, err
}
t, err := httputil.ExtractAuthToken(r)
to, err := apiutil.ReadFloatQuery(r, toKey, 0)
if err != nil {
return nil, err
}
req := listMessagesReq{
chanID: bone.GetValue(r, "chanID"),
token: t,
token: r.Header.Get("Authorization"),
pageMeta: readers.PageMetadata{
Offset: offset,
Limit: limit,
@@ -164,7 +160,7 @@ func decodeList(ctx context.Context, r *http.Request) (interface{}, error) {
},
}
vb, err := httputil.ReadBoolQuery(r, boolValueKey, false)
vb, err := apiutil.ReadBoolQuery(r, boolValueKey, false)
if err != nil && err != errors.ErrNotFoundParam {
return nil, err
}
@@ -197,11 +193,15 @@ func encodeError(_ context.Context, err error, w http.ResponseWriter) {
switch {
case errors.Contains(err, nil):
case errors.Contains(err, errors.ErrInvalidQueryParams),
errors.Contains(err, errors.ErrMalformedEntity):
errors.Contains(err, errors.ErrMalformedEntity),
err == apiutil.ErrMissingID,
err == apiutil.ErrLimitSize,
err == apiutil.ErrOffsetSize,
err == apiutil.ErrInvalidComparator:
w.WriteHeader(http.StatusBadRequest)
case errors.Contains(err, errors.ErrAuthentication):
case errors.Contains(err, errors.ErrAuthentication),
err == apiutil.ErrBearerToken:
w.WriteHeader(http.StatusUnauthorized)
case errors.Contains(err, readers.ErrReadMessages):
w.WriteHeader(http.StatusInternalServerError)
@@ -211,7 +211,7 @@ func encodeError(_ context.Context, err error, w http.ResponseWriter) {
if errorVal, ok := err.(errors.Error); ok {
w.Header().Set("Content-Type", contentType)
if err := json.NewEncoder(w).Encode(httputil.ErrorRes{Err: errorVal.Msg()}); err != nil {
if err := json.NewEncoder(w).Encode(apiutil.ErrorRes{Err: errorVal.Msg()}); err != nil {
w.WriteHeader(http.StatusInternalServerError)
}
}
+2 -2
View File
@@ -71,7 +71,7 @@ func (client grpcClient) CanAccessByKey(ctx context.Context, req *mainflux.Acces
ctx, cancel := context.WithTimeout(ctx, client.timeout)
defer cancel()
ar := AccessByKeyReq{
ar := accessByKeyReq{
thingKey: req.GetToken(),
chanID: req.GetChanID(),
}
@@ -120,7 +120,7 @@ func (client grpcClient) Identify(ctx context.Context, req *mainflux.Token, _ ..
}
func encodeCanAccessByKeyRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
req := grpcReq.(AccessByKeyReq)
req := grpcReq.(accessByKeyReq)
return &mainflux.AccessByKeyReq{Token: req.thingKey, ChanID: req.chanID}, nil
}
+1 -1
View File
@@ -12,7 +12,7 @@ import (
func canAccessEndpoint(svc things.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
req := request.(AccessByKeyReq)
req := request.(accessByKeyReq)
if err := req.validate(); err != nil {
return nil, err
}
+12 -8
View File
@@ -3,16 +3,20 @@
package grpc
import "github.com/mainflux/mainflux/pkg/errors"
import "github.com/mainflux/mainflux/internal/apiutil"
type AccessByKeyReq struct {
type accessByKeyReq struct {
thingKey string
chanID string
}
func (req AccessByKeyReq) validate() error {
if req.chanID == "" || req.thingKey == "" {
return errors.ErrMalformedEntity
func (req accessByKeyReq) validate() error {
if req.chanID == "" {
return apiutil.ErrMissingID
}
if req.thingKey == "" {
return apiutil.ErrBearerKey
}
return nil
@@ -25,7 +29,7 @@ type accessByIDReq struct {
func (req accessByIDReq) validate() error {
if req.thingID == "" || req.chanID == "" {
return errors.ErrMalformedEntity
return apiutil.ErrMissingID
}
return nil
@@ -38,7 +42,7 @@ type channelOwnerReq struct {
func (req channelOwnerReq) validate() error {
if req.owner == "" || req.chanID == "" {
return errors.ErrMalformedEntity
return apiutil.ErrMissingID
}
return nil
@@ -50,7 +54,7 @@ type identifyReq struct {
func (req identifyReq) validate() error {
if req.key == "" {
return errors.ErrMalformedEntity
return apiutil.ErrBearerKey
}
return nil
+5 -2
View File
@@ -10,6 +10,7 @@ import (
kitgrpc "github.com/go-kit/kit/transport/grpc"
"github.com/golang/protobuf/ptypes/empty"
"github.com/mainflux/mainflux"
"github.com/mainflux/mainflux/internal/apiutil"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/mainflux/mainflux/things"
opentracing "github.com/opentracing/opentracing-go"
@@ -90,7 +91,7 @@ func (gs *grpcServer) Identify(ctx context.Context, req *mainflux.Token) (*mainf
func decodeCanAccessByKeyRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
req := grpcReq.(*mainflux.AccessByKeyReq)
return AccessByKeyReq{thingKey: req.GetToken(), chanID: req.GetChanID()}, nil
return accessByKeyReq{thingKey: req.GetToken(), chanID: req.GetChanID()}, nil
}
func decodeCanAccessByIDRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
@@ -122,7 +123,9 @@ func encodeError(err error) error {
switch err {
case nil:
return nil
case errors.ErrMalformedEntity:
case errors.ErrMalformedEntity,
apiutil.ErrMissingID,
apiutil.ErrBearerKey:
return status.Error(codes.InvalidArgument, "received invalid can access request")
case errors.ErrAuthentication:
return status.Error(codes.Unauthenticated, "missing or invalid credentials provided")
+3 -1
View File
@@ -15,6 +15,7 @@ import (
"github.com/opentracing/opentracing-go/mocktracer"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/uuid"
"github.com/mainflux/mainflux/things"
httpapi "github.com/mainflux/mainflux/things/api/auth/http"
@@ -79,7 +80,8 @@ func newService(tokens map[string]string) things.Service {
}
func newServer(svc things.Service) *httptest.Server {
mux := httpapi.MakeHandler(mocktracer.New(), svc)
logger := logger.NewMock()
mux := httpapi.MakeHandler(mocktracer.New(), svc, logger)
return httptest.NewServer(mux)
}
+5 -5
View File
@@ -3,7 +3,7 @@
package http
import "github.com/mainflux/mainflux/pkg/errors"
import "github.com/mainflux/mainflux/internal/apiutil"
type identifyReq struct {
Token string `json:"token"`
@@ -11,7 +11,7 @@ type identifyReq struct {
func (req identifyReq) validate() error {
if req.Token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
return nil
@@ -24,11 +24,11 @@ type canAccessByKeyReq struct {
func (req canAccessByKeyReq) validate() error {
if req.Token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
if req.chanID == "" {
return errors.ErrMalformedEntity
return apiutil.ErrMissingID
}
return nil
@@ -41,7 +41,7 @@ type canAccessByIDReq struct {
func (req canAccessByIDReq) validate() error {
if req.ThingID == "" || req.chanID == "" {
return errors.ErrMalformedEntity
return apiutil.ErrMissingID
}
return nil
+9 -6
View File
@@ -13,7 +13,8 @@ import (
kithttp "github.com/go-kit/kit/transport/http"
"github.com/go-zoo/bone"
"github.com/mainflux/mainflux"
"github.com/mainflux/mainflux/internal/httputil"
"github.com/mainflux/mainflux/internal/apiutil"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/mainflux/mainflux/things"
opentracing "github.com/opentracing/opentracing-go"
@@ -22,9 +23,9 @@ import (
const contentType = "application/json"
// MakeHandler returns a HTTP handler for auth API endpoints.
func MakeHandler(tracer opentracing.Tracer, svc things.Service) http.Handler {
func MakeHandler(tracer opentracing.Tracer, svc things.Service, logger logger.Logger) http.Handler {
opts := []kithttp.ServerOption{
kithttp.ServerErrorEncoder(encodeError),
kithttp.ServerErrorEncoder(apiutil.LoggingErrorEncoder(logger, encodeError)),
}
r := bone.New()
@@ -114,7 +115,8 @@ func encodeResponse(_ context.Context, w http.ResponseWriter, response interface
func encodeError(_ context.Context, err error, w http.ResponseWriter) {
switch {
case errors.Contains(err, errors.ErrAuthentication):
case err == apiutil.ErrBearerToken,
errors.Contains(err, errors.ErrAuthentication):
w.WriteHeader(http.StatusUnauthorized)
case errors.Contains(err, errors.ErrNotFound):
w.WriteHeader(http.StatusNotFound)
@@ -122,7 +124,8 @@ func encodeError(_ context.Context, err error, w http.ResponseWriter) {
w.WriteHeader(http.StatusForbidden)
case errors.Contains(err, errors.ErrUnsupportedContentType):
w.WriteHeader(http.StatusUnsupportedMediaType)
case errors.Contains(err, errors.ErrMalformedEntity):
case errors.Contains(err, errors.ErrMalformedEntity),
err == apiutil.ErrMissingID:
w.WriteHeader(http.StatusBadRequest)
default:
w.WriteHeader(http.StatusInternalServerError)
@@ -130,7 +133,7 @@ func encodeError(_ context.Context, err error, w http.ResponseWriter) {
if errorVal, ok := err.(errors.Error); ok {
w.Header().Set("Content-Type", contentType)
if err := json.NewEncoder(w).Encode(httputil.ErrorRes{Err: errorVal.Msg()}); err != nil {
if err := json.NewEncoder(w).Encode(apiutil.ErrorRes{Err: errorVal.Msg()}); err != nil {
w.WriteHeader(http.StatusInternalServerError)
}
}
+17 -14
View File
@@ -16,7 +16,8 @@ import (
"testing"
"time"
"github.com/mainflux/mainflux/internal/httputil"
"github.com/mainflux/mainflux/internal/apiutil"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/mainflux/mainflux/pkg/uuid"
"github.com/mainflux/mainflux/things"
@@ -51,9 +52,10 @@ var (
Metadata: map[string]interface{}{"test": "data"},
}
invalidName = strings.Repeat("m", maxNameSize+1)
notFoundRes = toJSON(httputil.ErrorRes{Err: errors.ErrNotFound.Error()})
unauthzRes = toJSON(httputil.ErrorRes{Err: errors.ErrAuthorization.Error()})
unauthRes = toJSON(httputil.ErrorRes{Err: errors.ErrAuthentication.Error()})
notFoundRes = toJSON(apiutil.ErrorRes{Err: errors.ErrNotFound.Error()})
unauthzRes = toJSON(apiutil.ErrorRes{Err: errors.ErrAuthorization.Error()})
unauthRes = toJSON(apiutil.ErrorRes{Err: errors.ErrAuthentication.Error()})
missingTokRes = toJSON(apiutil.ErrorRes{Err: apiutil.ErrBearerToken.Error()})
searchThingReq = things.PageMetadata{
Limit: 5,
Offset: 0,
@@ -75,7 +77,7 @@ func (tr testRequest) make() (*http.Response, error) {
return nil, err
}
if tr.token != "" {
req.Header.Set("Authorization", httputil.BearerPrefix+tr.token)
req.Header.Set("Authorization", apiutil.BearerPrefix+tr.token)
}
if tr.contentType != "" {
req.Header.Set("Content-Type", tr.contentType)
@@ -99,7 +101,8 @@ func newService(tokens map[string]string) things.Service {
}
func newServer(svc things.Service) *httptest.Server {
mux := httpapi.MakeHandler(mocktracer.New(), svc)
logger := logger.NewMock()
mux := httpapi.MakeHandler(mocktracer.New(), svc, logger)
return httptest.NewServer(mux)
}
@@ -734,7 +737,7 @@ func TestViewThing(t *testing.T) {
id: th.ID,
auth: "",
status: http.StatusUnauthorized,
res: unauthRes,
res: missingTokRes,
},
{
desc: "view thing by passing invalid id",
@@ -857,9 +860,9 @@ func TestListThings(t *testing.T) {
{
desc: "get a list of things with zero limit and offset 1",
auth: token,
status: http.StatusOK,
status: http.StatusBadRequest,
url: fmt.Sprintf("%s?offset=%d&limit=%d", thingURL, 1, 0),
res: data[1:11],
res: nil,
},
{
desc: "get a list of things without offset",
@@ -1087,9 +1090,9 @@ func TestSearchThings(t *testing.T) {
{
desc: "search things with zero limit",
auth: token,
status: http.StatusOK,
status: http.StatusBadRequest,
req: zeroLimitData,
res: data[0:10],
res: nil,
},
{
desc: "search things without offset",
@@ -1778,7 +1781,7 @@ func TestViewChannel(t *testing.T) {
id: sch.ID,
auth: "",
status: http.StatusUnauthorized,
res: unauthRes,
res: missingTokRes,
},
{
desc: "view channel with invalid id",
@@ -1907,9 +1910,9 @@ func TestListChannels(t *testing.T) {
{
desc: "get a list of channels with zero limit and offset 1",
auth: token,
status: http.StatusOK,
status: http.StatusBadRequest,
url: fmt.Sprintf("%s?offset=%d&limit=%d", channelURL, 1, 0),
res: channels[1:11],
res: nil,
},
{
desc: "get a list of channels with no offset provided",
+81 -70
View File
@@ -5,7 +5,7 @@ package http
import (
"github.com/gofrs/uuid"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/mainflux/mainflux/internal/apiutil"
"github.com/mainflux/mainflux/things"
)
@@ -32,7 +32,7 @@ type createThingReq struct {
func validateUUID(extID string) (err error) {
id, err := uuid.FromString(extID)
if id.String() != extID || err != nil {
return errors.ErrMalformedEntity
return apiutil.ErrInvalidIDFormat
}
return nil
@@ -40,15 +40,16 @@ func validateUUID(extID string) (err error) {
func (req createThingReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
}
if req.ID != "" && validateUUID(req.ID) != nil {
return errors.ErrMalformedEntity
return apiutil.ErrBearerToken
}
if len(req.Name) > maxNameSize {
return errors.ErrMalformedEntity
return apiutil.ErrNameSize
}
// Do the validation only if request contains ID
if req.ID != "" {
return validateUUID(req.ID)
}
return nil
@@ -61,20 +62,22 @@ type createThingsReq struct {
func (req createThingsReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
if len(req.Things) <= 0 {
return errors.ErrMalformedEntity
return apiutil.ErrEmptyList
}
for _, thing := range req.Things {
if thing.ID != "" && validateUUID(thing.ID) != nil {
return errors.ErrMalformedEntity
if thing.ID != "" {
if err := validateUUID(thing.ID); err != nil {
return err
}
}
if len(thing.Name) > maxNameSize {
return errors.ErrMalformedEntity
return apiutil.ErrNameSize
}
}
@@ -90,15 +93,20 @@ type shareThingReq struct {
func (req shareThingReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
if req.thingID == "" || len(req.UserIDs) == 0 || len(req.Policies) == 0 {
return errors.ErrMalformedEntity
if req.thingID == "" || len(req.UserIDs) == 0 {
return apiutil.ErrMissingID
}
if len(req.Policies) == 0 {
return apiutil.ErrEmptyList
}
for _, p := range req.Policies {
if p != readPolicy && p != writePolicy && p != deletePolicy {
return errors.ErrMalformedEntity
return apiutil.ErrMalformedPolicy
}
}
return nil
@@ -113,15 +121,15 @@ type updateThingReq struct {
func (req updateThingReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
if req.id == "" {
return errors.ErrMalformedEntity
return apiutil.ErrMissingID
}
if len(req.Name) > maxNameSize {
return errors.ErrMalformedEntity
return apiutil.ErrNameSize
}
return nil
@@ -135,11 +143,15 @@ type updateKeyReq struct {
func (req updateKeyReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
if req.id == "" || req.Key == "" {
return errors.ErrMalformedEntity
if req.id == "" {
return apiutil.ErrMissingID
}
if req.Key == "" {
return apiutil.ErrBearerKey
}
return nil
@@ -154,15 +166,16 @@ type createChannelReq struct {
func (req createChannelReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
}
if req.ID != "" && validateUUID(req.ID) != nil {
return errors.ErrMalformedEntity
return apiutil.ErrBearerToken
}
if len(req.Name) > maxNameSize {
return errors.ErrMalformedEntity
return apiutil.ErrNameSize
}
// Do the validation only if request contains ID
if req.ID != "" {
return validateUUID(req.ID)
}
return nil
@@ -175,20 +188,22 @@ type createChannelsReq struct {
func (req createChannelsReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
if len(req.Channels) <= 0 {
return errors.ErrMalformedEntity
return apiutil.ErrEmptyList
}
for _, channel := range req.Channels {
if channel.ID != "" && validateUUID(channel.ID) != nil {
return errors.ErrMalformedEntity
if channel.ID != "" {
if err := validateUUID(channel.ID); err != nil {
return err
}
}
if len(channel.Name) > maxNameSize {
return errors.ErrMalformedEntity
return apiutil.ErrNameSize
}
}
@@ -204,15 +219,15 @@ type updateChannelReq struct {
func (req updateChannelReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
if req.id == "" {
return errors.ErrMalformedEntity
return apiutil.ErrMissingID
}
if len(req.Name) > maxNameSize {
return errors.ErrMalformedEntity
return apiutil.ErrNameSize
}
return nil
@@ -225,11 +240,11 @@ type viewResourceReq struct {
func (req viewResourceReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
if req.id == "" {
return errors.ErrMalformedEntity
return apiutil.ErrMissingID
}
return nil
@@ -242,29 +257,25 @@ type listResourcesReq struct {
func (req *listResourcesReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
if req.pageMetadata.Limit == 0 {
req.pageMetadata.Limit = defLimit
}
if req.pageMetadata.Limit > maxLimitSize {
return errors.ErrMalformedEntity
if req.pageMetadata.Limit > maxLimitSize || req.pageMetadata.Limit < 1 {
return apiutil.ErrLimitSize
}
if len(req.pageMetadata.Name) > maxNameSize {
return errors.ErrMalformedEntity
return apiutil.ErrNameSize
}
if req.pageMetadata.Order != "" &&
req.pageMetadata.Order != nameOrder && req.pageMetadata.Order != idOrder {
return errors.ErrMalformedEntity
return apiutil.ErrInvalidOrder
}
if req.pageMetadata.Dir != "" &&
req.pageMetadata.Dir != ascDir && req.pageMetadata.Dir != descDir {
return errors.ErrMalformedEntity
return apiutil.ErrInvalidDirection
}
return nil
@@ -278,25 +289,25 @@ type listByConnectionReq struct {
func (req listByConnectionReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
if req.id == "" {
return errors.ErrMalformedEntity
return apiutil.ErrMissingID
}
if req.pageMetadata.Limit == 0 || req.pageMetadata.Limit > maxLimitSize {
return errors.ErrMalformedEntity
if req.pageMetadata.Limit > maxLimitSize || req.pageMetadata.Limit < 1 {
return apiutil.ErrLimitSize
}
if req.pageMetadata.Order != "" &&
req.pageMetadata.Order != nameOrder && req.pageMetadata.Order != idOrder {
return errors.ErrMalformedEntity
return apiutil.ErrInvalidOrder
}
if req.pageMetadata.Dir != "" &&
req.pageMetadata.Dir != ascDir && req.pageMetadata.Dir != descDir {
return errors.ErrMalformedEntity
return apiutil.ErrInvalidDirection
}
return nil
@@ -310,11 +321,11 @@ type connectThingReq struct {
func (req connectThingReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
if req.chanID == "" || req.thingID == "" {
return errors.ErrMalformedEntity
return apiutil.ErrMissingID
}
return nil
@@ -328,21 +339,21 @@ type connectReq struct {
func (req connectReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
if len(req.ChannelIDs) == 0 || len(req.ThingIDs) == 0 {
return errors.ErrMalformedEntity
return apiutil.ErrEmptyList
}
for _, chID := range req.ChannelIDs {
if chID == "" {
return errors.ErrMalformedEntity
return apiutil.ErrMissingID
}
}
for _, thingID := range req.ThingIDs {
if thingID == "" {
return errors.ErrMalformedEntity
return apiutil.ErrMissingID
}
}
@@ -357,29 +368,29 @@ type listThingsGroupReq struct {
func (req listThingsGroupReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
if req.groupID == "" {
return errors.ErrMalformedEntity
return apiutil.ErrMissingID
}
if req.pageMetadata.Limit == 0 || req.pageMetadata.Limit > maxLimitSize {
return errors.ErrMalformedEntity
if req.pageMetadata.Limit > maxLimitSize || req.pageMetadata.Limit < 1 {
return apiutil.ErrLimitSize
}
if len(req.pageMetadata.Name) > maxNameSize {
return errors.ErrMalformedEntity
return apiutil.ErrNameSize
}
if req.pageMetadata.Order != "" &&
req.pageMetadata.Order != "name" && req.pageMetadata.Order != "id" {
return errors.ErrMalformedEntity
req.pageMetadata.Order != nameOrder && req.pageMetadata.Order != idOrder {
return apiutil.ErrInvalidOrder
}
if req.pageMetadata.Dir != "" &&
req.pageMetadata.Dir != "asc" && req.pageMetadata.Dir != "desc" {
return errors.ErrMalformedEntity
req.pageMetadata.Dir != ascDir && req.pageMetadata.Dir != descDir {
return apiutil.ErrInvalidDirection
}
return nil
+47 -113
View File
@@ -13,7 +13,8 @@ import (
kithttp "github.com/go-kit/kit/transport/http"
"github.com/go-zoo/bone"
"github.com/mainflux/mainflux"
"github.com/mainflux/mainflux/internal/httputil"
"github.com/mainflux/mainflux/internal/apiutil"
log "github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/mainflux/mainflux/pkg/uuid"
"github.com/mainflux/mainflux/things"
@@ -36,9 +37,9 @@ const (
)
// MakeHandler returns a HTTP handler for API endpoints.
func MakeHandler(tracer opentracing.Tracer, svc things.Service) http.Handler {
func MakeHandler(tracer opentracing.Tracer, svc things.Service, logger log.Logger) http.Handler {
opts := []kithttp.ServerOption{
kithttp.ServerErrorEncoder(encodeError),
kithttp.ServerErrorEncoder(apiutil.LoggingErrorEncoder(logger, encodeError)),
}
r := bone.New()
@@ -208,13 +209,7 @@ func decodeThingCreation(_ context.Context, r *http.Request) (interface{}, error
return nil, errors.ErrUnsupportedContentType
}
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req := createThingReq{token: t}
req := createThingReq{token: apiutil.ExtractBearerToken(r)}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return nil, errors.Wrap(errors.ErrMalformedEntity, err)
}
@@ -227,12 +222,7 @@ func decodeThingsCreation(_ context.Context, r *http.Request) (interface{}, erro
return nil, errors.ErrUnsupportedContentType
}
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req := createThingsReq{token: t}
req := createThingsReq{token: apiutil.ExtractBearerToken(r)}
if err := json.NewDecoder(r.Body).Decode(&req.Things); err != nil {
return nil, errors.Wrap(errors.ErrMalformedEntity, err)
}
@@ -245,13 +235,8 @@ func decodeShareThing(ctx context.Context, r *http.Request) (interface{}, error)
return nil, errors.ErrUnsupportedContentType
}
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req := shareThingReq{
token: t,
token: apiutil.ExtractBearerToken(r),
thingID: bone.GetValue(r, "id"),
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
@@ -266,13 +251,8 @@ func decodeThingUpdate(_ context.Context, r *http.Request) (interface{}, error)
return nil, errors.ErrUnsupportedContentType
}
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req := updateThingReq{
token: t,
token: apiutil.ExtractBearerToken(r),
id: bone.GetValue(r, "id"),
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
@@ -287,13 +267,8 @@ func decodeKeyUpdate(_ context.Context, r *http.Request) (interface{}, error) {
return nil, errors.ErrUnsupportedContentType
}
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req := updateKeyReq{
token: t,
token: apiutil.ExtractBearerToken(r),
id: bone.GetValue(r, "id"),
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
@@ -308,12 +283,7 @@ func decodeChannelCreation(_ context.Context, r *http.Request) (interface{}, err
return nil, errors.ErrUnsupportedContentType
}
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req := createChannelReq{token: t}
req := createChannelReq{token: apiutil.ExtractBearerToken(r)}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return nil, errors.Wrap(errors.ErrMalformedEntity, err)
}
@@ -326,13 +296,7 @@ func decodeChannelsCreation(_ context.Context, r *http.Request) (interface{}, er
return nil, errors.ErrUnsupportedContentType
}
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req := createChannelsReq{token: t}
req := createChannelsReq{token: apiutil.ExtractBearerToken(r)}
if err := json.NewDecoder(r.Body).Decode(&req.Channels); err != nil {
return nil, errors.Wrap(errors.ErrMalformedEntity, err)
}
@@ -345,13 +309,8 @@ func decodeChannelUpdate(_ context.Context, r *http.Request) (interface{}, error
return nil, errors.ErrUnsupportedContentType
}
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req := updateChannelReq{
token: t,
token: apiutil.ExtractBearerToken(r),
id: bone.GetValue(r, "id"),
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
@@ -362,13 +321,8 @@ func decodeChannelUpdate(_ context.Context, r *http.Request) (interface{}, error
}
func decodeView(_ context.Context, r *http.Request) (interface{}, error) {
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req := viewResourceReq{
token: t,
token: apiutil.ExtractBearerToken(r),
id: bone.GetValue(r, "id"),
}
@@ -376,47 +330,42 @@ func decodeView(_ context.Context, r *http.Request) (interface{}, error) {
}
func decodeList(_ context.Context, r *http.Request) (interface{}, error) {
o, err := httputil.ReadUintQuery(r, offsetKey, defOffset)
o, err := apiutil.ReadUintQuery(r, offsetKey, defOffset)
if err != nil {
return nil, err
}
l, err := httputil.ReadUintQuery(r, limitKey, defLimit)
l, err := apiutil.ReadUintQuery(r, limitKey, defLimit)
if err != nil {
return nil, err
}
n, err := httputil.ReadStringQuery(r, nameKey, "")
n, err := apiutil.ReadStringQuery(r, nameKey, "")
if err != nil {
return nil, err
}
or, err := httputil.ReadStringQuery(r, orderKey, "")
or, err := apiutil.ReadStringQuery(r, orderKey, "")
if err != nil {
return nil, err
}
d, err := httputil.ReadStringQuery(r, dirKey, "")
d, err := apiutil.ReadStringQuery(r, dirKey, "")
if err != nil {
return nil, err
}
m, err := httputil.ReadMetadataQuery(r, metadataKey, nil)
m, err := apiutil.ReadMetadataQuery(r, metadataKey, nil)
if err != nil {
return nil, err
}
shared, err := httputil.ReadBoolQuery(r, sharedKey, false)
if err != nil {
return nil, err
}
t, err := httputil.ExtractAuthToken(r)
shared, err := apiutil.ReadBoolQuery(r, sharedKey, false)
if err != nil {
return nil, err
}
req := listResourcesReq{
token: t,
token: apiutil.ExtractBearerToken(r),
pageMetadata: things.PageMetadata{
Offset: o,
Limit: l,
@@ -432,12 +381,7 @@ func decodeList(_ context.Context, r *http.Request) (interface{}, error) {
}
func decodeListByMetadata(_ context.Context, r *http.Request) (interface{}, error) {
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req := listResourcesReq{token: t}
req := listResourcesReq{token: apiutil.ExtractBearerToken(r)}
if err := json.NewDecoder(r.Body).Decode(&req.pageMetadata); err != nil {
return nil, errors.Wrap(errors.ErrMalformedEntity, err)
}
@@ -446,38 +390,33 @@ func decodeListByMetadata(_ context.Context, r *http.Request) (interface{}, erro
}
func decodeListByConnection(_ context.Context, r *http.Request) (interface{}, error) {
o, err := httputil.ReadUintQuery(r, offsetKey, defOffset)
o, err := apiutil.ReadUintQuery(r, offsetKey, defOffset)
if err != nil {
return nil, err
}
l, err := httputil.ReadUintQuery(r, limitKey, defLimit)
l, err := apiutil.ReadUintQuery(r, limitKey, defLimit)
if err != nil {
return nil, err
}
c, err := httputil.ReadBoolQuery(r, disconnKey, false)
c, err := apiutil.ReadBoolQuery(r, disconnKey, false)
if err != nil {
return nil, err
}
or, err := httputil.ReadStringQuery(r, orderKey, "")
or, err := apiutil.ReadStringQuery(r, orderKey, "")
if err != nil {
return nil, err
}
d, err := httputil.ReadStringQuery(r, dirKey, "")
if err != nil {
return nil, err
}
t, err := httputil.ExtractAuthToken(r)
d, err := apiutil.ReadStringQuery(r, dirKey, "")
if err != nil {
return nil, err
}
req := listByConnectionReq{
token: t,
token: apiutil.ExtractBearerToken(r),
id: bone.GetValue(r, "id"),
pageMetadata: things.PageMetadata{
Offset: o,
@@ -492,13 +431,8 @@ func decodeListByConnection(_ context.Context, r *http.Request) (interface{}, er
}
func decodeConnectThing(_ context.Context, r *http.Request) (interface{}, error) {
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req := connectThingReq{
token: t,
token: apiutil.ExtractBearerToken(r),
chanID: bone.GetValue(r, "chanId"),
thingID: bone.GetValue(r, "thingId"),
}
@@ -511,12 +445,7 @@ func decodeConnectList(_ context.Context, r *http.Request) (interface{}, error)
return nil, errors.ErrUnsupportedContentType
}
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req := connectReq{token: t}
req := connectReq{token: apiutil.ExtractBearerToken(r)}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return nil, errors.Wrap(errors.ErrMalformedEntity, err)
}
@@ -525,28 +454,23 @@ func decodeConnectList(_ context.Context, r *http.Request) (interface{}, error)
}
func decodeListMembersRequest(_ context.Context, r *http.Request) (interface{}, error) {
o, err := httputil.ReadUintQuery(r, offsetKey, defOffset)
o, err := apiutil.ReadUintQuery(r, offsetKey, defOffset)
if err != nil {
return nil, err
}
l, err := httputil.ReadUintQuery(r, limitKey, defLimit)
l, err := apiutil.ReadUintQuery(r, limitKey, defLimit)
if err != nil {
return nil, err
}
m, err := httputil.ReadMetadataQuery(r, metadataKey, nil)
if err != nil {
return nil, err
}
t, err := httputil.ExtractAuthToken(r)
m, err := apiutil.ReadMetadataQuery(r, metadataKey, nil)
if err != nil {
return nil, err
}
req := listThingsGroupReq{
token: t,
token: apiutil.ExtractBearerToken(r),
groupID: bone.GetValue(r, "groupId"),
pageMetadata: things.PageMetadata{
Offset: o,
@@ -577,14 +501,24 @@ func encodeResponse(_ context.Context, w http.ResponseWriter, response interface
func encodeError(_ context.Context, err error, w http.ResponseWriter) {
switch {
case errors.Contains(err, errors.ErrAuthentication):
case errors.Contains(err, errors.ErrAuthentication),
err == apiutil.ErrBearerToken:
w.WriteHeader(http.StatusUnauthorized)
case errors.Contains(err, errors.ErrAuthorization):
w.WriteHeader(http.StatusForbidden)
case errors.Contains(err, errors.ErrUnsupportedContentType):
w.WriteHeader(http.StatusUnsupportedMediaType)
case errors.Contains(err, errors.ErrInvalidQueryParams),
errors.Contains(err, errors.ErrMalformedEntity):
errors.Contains(err, errors.ErrMalformedEntity),
err == apiutil.ErrNameSize,
err == apiutil.ErrEmptyList,
err == apiutil.ErrMissingID,
err == apiutil.ErrMalformedPolicy,
err == apiutil.ErrBearerKey,
err == apiutil.ErrLimitSize,
err == apiutil.ErrInvalidOrder,
err == apiutil.ErrInvalidDirection,
err == apiutil.ErrInvalidIDFormat:
w.WriteHeader(http.StatusBadRequest)
case errors.Contains(err, errors.ErrNotFound):
w.WriteHeader(http.StatusNotFound)
@@ -608,7 +542,7 @@ func encodeError(_ context.Context, err error, w http.ResponseWriter) {
if errorVal, ok := err.(errors.Error); ok {
w.Header().Set("Content-Type", contentType)
if err := json.NewEncoder(w).Encode(httputil.ErrorRes{Err: errorVal.Msg()}); err != nil {
if err := json.NewEncoder(w).Encode(apiutil.ErrorRes{Err: errorVal.Msg()}); err != nil {
w.WriteHeader(http.StatusInternalServerError)
}
}
+5 -3
View File
@@ -14,7 +14,8 @@ import (
"strings"
"testing"
"github.com/mainflux/mainflux/internal/httputil"
"github.com/mainflux/mainflux/internal/apiutil"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/twins"
httpapi "github.com/mainflux/mainflux/twins/api/http"
"github.com/mainflux/mainflux/twins/mocks"
@@ -76,7 +77,7 @@ func (tr testRequest) make() (*http.Response, error) {
return nil, err
}
if tr.token != "" {
req.Header.Set("Authorization", httputil.BearerPrefix+tr.token)
req.Header.Set("Authorization", apiutil.BearerPrefix+tr.token)
}
if tr.contentType != "" {
req.Header.Set("Content-Type", tr.contentType)
@@ -85,7 +86,8 @@ func (tr testRequest) make() (*http.Response, error) {
}
func newServer(svc twins.Service) *httptest.Server {
mux := httpapi.MakeHandler(mocktracer.New(), svc)
logger := logger.NewMock()
mux := httpapi.MakeHandler(mocktracer.New(), svc, logger)
return httptest.NewServer(mux)
}
+15 -15
View File
@@ -4,7 +4,7 @@
package http
import (
"github.com/mainflux/mainflux/pkg/errors"
"github.com/mainflux/mainflux/internal/apiutil"
"github.com/mainflux/mainflux/twins"
)
@@ -26,11 +26,11 @@ type addTwinReq struct {
func (req addTwinReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
if len(req.Name) > maxNameSize {
return errors.ErrMalformedEntity
return apiutil.ErrNameSize
}
return nil
@@ -46,15 +46,15 @@ type updateTwinReq struct {
func (req updateTwinReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
if req.id == "" {
return errors.ErrMalformedEntity
return apiutil.ErrMissingID
}
if len(req.Name) > maxNameSize {
return errors.ErrMalformedEntity
return apiutil.ErrNameSize
}
return nil
@@ -67,11 +67,11 @@ type viewTwinReq struct {
func (req viewTwinReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
if req.id == "" {
return errors.ErrMalformedEntity
return apiutil.ErrMissingID
}
return nil
@@ -87,15 +87,15 @@ type listReq struct {
func (req *listReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
if req.limit == 0 || req.limit > maxLimitSize {
return errors.ErrMalformedEntity
if req.limit < 1 || req.limit > maxLimitSize {
return apiutil.ErrLimitSize
}
if len(req.name) > maxNameSize {
return errors.ErrMalformedEntity
return apiutil.ErrNameSize
}
return nil
@@ -110,15 +110,15 @@ type listStatesReq struct {
func (req *listStatesReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
if req.id == "" {
return errors.ErrMalformedEntity
return apiutil.ErrMissingID
}
if req.limit == 0 || req.limit > maxLimitSize {
return errors.ErrMalformedEntity
return apiutil.ErrLimitSize
}
return nil
+22 -37
View File
@@ -13,7 +13,8 @@ import (
kithttp "github.com/go-kit/kit/transport/http"
"github.com/go-zoo/bone"
"github.com/mainflux/mainflux"
"github.com/mainflux/mainflux/internal/httputil"
"github.com/mainflux/mainflux/internal/apiutil"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/mainflux/mainflux/twins"
opentracing "github.com/opentracing/opentracing-go"
@@ -31,9 +32,9 @@ const (
)
// MakeHandler returns a HTTP handler for API endpoints.
func MakeHandler(tracer opentracing.Tracer, svc twins.Service) http.Handler {
func MakeHandler(tracer opentracing.Tracer, svc twins.Service, logger logger.Logger) http.Handler {
opts := []kithttp.ServerOption{
kithttp.ServerErrorEncoder(encodeError),
kithttp.ServerErrorEncoder(apiutil.LoggingErrorEncoder(logger, encodeError)),
}
r := bone.New()
@@ -91,11 +92,7 @@ func decodeTwinCreation(_ context.Context, r *http.Request) (interface{}, error)
return nil, errors.ErrUnsupportedContentType
}
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req := addTwinReq{token: t}
req := addTwinReq{token: apiutil.ExtractBearerToken(r)}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return nil, errors.Wrap(errors.ErrMalformedEntity, err)
}
@@ -108,12 +105,8 @@ func decodeTwinUpdate(_ context.Context, r *http.Request) (interface{}, error) {
return nil, errors.ErrUnsupportedContentType
}
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req := updateTwinReq{
token: t,
token: apiutil.ExtractBearerToken(r),
id: bone.GetValue(r, "id"),
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
@@ -124,12 +117,8 @@ func decodeTwinUpdate(_ context.Context, r *http.Request) (interface{}, error) {
}
func decodeView(_ context.Context, r *http.Request) (interface{}, error) {
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req := viewTwinReq{
token: t,
token: apiutil.ExtractBearerToken(r),
id: bone.GetValue(r, "id"),
}
@@ -137,32 +126,28 @@ func decodeView(_ context.Context, r *http.Request) (interface{}, error) {
}
func decodeList(_ context.Context, r *http.Request) (interface{}, error) {
l, err := httputil.ReadUintQuery(r, limitKey, defLimit)
l, err := apiutil.ReadUintQuery(r, limitKey, defLimit)
if err != nil {
return nil, err
}
o, err := httputil.ReadUintQuery(r, offsetKey, defOffset)
o, err := apiutil.ReadUintQuery(r, offsetKey, defOffset)
if err != nil {
return nil, err
}
n, err := httputil.ReadStringQuery(r, nameKey, "")
n, err := apiutil.ReadStringQuery(r, nameKey, "")
if err != nil {
return nil, err
}
m, err := httputil.ReadMetadataQuery(r, metadataKey, nil)
m, err := apiutil.ReadMetadataQuery(r, metadataKey, nil)
if err != nil {
return nil, err
}
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req := listReq{
token: t,
token: apiutil.ExtractBearerToken(r),
limit: l,
offset: o,
name: n,
@@ -173,22 +158,18 @@ func decodeList(_ context.Context, r *http.Request) (interface{}, error) {
}
func decodeListStates(_ context.Context, r *http.Request) (interface{}, error) {
l, err := httputil.ReadUintQuery(r, limitKey, defLimit)
l, err := apiutil.ReadUintQuery(r, limitKey, defLimit)
if err != nil {
return nil, err
}
o, err := httputil.ReadUintQuery(r, offsetKey, defOffset)
o, err := apiutil.ReadUintQuery(r, offsetKey, defOffset)
if err != nil {
return nil, err
}
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req := listStatesReq{
token: t,
token: apiutil.ExtractBearerToken(r),
limit: l,
offset: o,
id: bone.GetValue(r, "id"),
@@ -217,13 +198,17 @@ func encodeResponse(_ context.Context, w http.ResponseWriter, response interface
func encodeError(_ context.Context, err error, w http.ResponseWriter) {
switch {
case errors.Contains(err, errors.ErrAuthentication):
case errors.Contains(err, errors.ErrAuthentication),
err == apiutil.ErrBearerToken:
w.WriteHeader(http.StatusUnauthorized)
case errors.Contains(err, errors.ErrInvalidQueryParams):
w.WriteHeader(http.StatusBadRequest)
case errors.Contains(err, errors.ErrUnsupportedContentType):
w.WriteHeader(http.StatusUnsupportedMediaType)
case errors.Contains(err, errors.ErrMalformedEntity):
case errors.Contains(err, errors.ErrMalformedEntity),
err == apiutil.ErrMissingID,
err == apiutil.ErrNameSize,
err == apiutil.ErrLimitSize:
w.WriteHeader(http.StatusBadRequest)
case errors.Contains(err, errors.ErrNotFound):
w.WriteHeader(http.StatusNotFound)
@@ -242,7 +227,7 @@ func encodeError(_ context.Context, err error, w http.ResponseWriter) {
if errorVal, ok := err.(errors.Error); ok {
w.Header().Set("Content-Type", contentType)
if err := json.NewEncoder(w).Encode(httputil.ErrorRes{Err: errorVal.Msg()}); err != nil {
if err := json.NewEncoder(w).Encode(apiutil.ErrorRes{Err: errorVal.Msg()}); err != nil {
w.WriteHeader(http.StatusInternalServerError)
}
}
+1 -1
View File
@@ -150,7 +150,7 @@ func passwordChangeEndpoint(svc users.Service) endpoint.Endpoint {
return nil, err
}
res := passwChangeRes{}
if err := svc.ChangePassword(ctx, req.Token, req.Password, req.OldPassword); err != nil {
if err := svc.ChangePassword(ctx, req.token, req.Password, req.OldPassword); err != nil {
return nil, err
}
return res, nil
+26 -17
View File
@@ -16,7 +16,8 @@ import (
"testing"
"github.com/mainflux/mainflux"
"github.com/mainflux/mainflux/internal/httputil"
"github.com/mainflux/mainflux/internal/apiutil"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/mainflux/mainflux/pkg/uuid"
"github.com/mainflux/mainflux/users"
@@ -39,14 +40,18 @@ const (
)
var (
user = users.User{Email: validEmail, Password: validPass}
notFoundRes = toJSON(httputil.ErrorRes{Err: errors.ErrNotFound.Error()})
unauthRes = toJSON(httputil.ErrorRes{Err: errors.ErrAuthentication.Error()})
malformedRes = toJSON(httputil.ErrorRes{Err: errors.ErrMalformedEntity.Error()})
weakPassword = toJSON(httputil.ErrorRes{Err: users.ErrPasswordFormat.Error()})
unsupportedRes = toJSON(httputil.ErrorRes{Err: errors.ErrUnsupportedContentType.Error()})
failDecodeRes = toJSON(httputil.ErrorRes{Err: errors.ErrMalformedEntity.Error()})
passRegex = regexp.MustCompile("^.{8,}$")
user = users.User{Email: validEmail, Password: validPass}
notFoundRes = toJSON(apiutil.ErrorRes{Err: errors.ErrNotFound.Error()})
unauthRes = toJSON(apiutil.ErrorRes{Err: errors.ErrAuthentication.Error()})
malformedRes = toJSON(apiutil.ErrorRes{Err: errors.ErrMalformedEntity.Error()})
weakPassword = toJSON(apiutil.ErrorRes{Err: users.ErrPasswordFormat.Error()})
unsupportedRes = toJSON(apiutil.ErrorRes{Err: errors.ErrUnsupportedContentType.Error()})
missingTokRes = toJSON(apiutil.ErrorRes{Err: apiutil.ErrBearerToken.Error()})
missingEmailRes = toJSON(apiutil.ErrorRes{Err: apiutil.ErrMissingEmail.Error()})
missingPassRes = toJSON(apiutil.ErrorRes{Err: apiutil.ErrMissingPass.Error()})
invalidRestPassRes = toJSON(apiutil.ErrorRes{Err: apiutil.ErrInvalidResetPass.Error()})
failDecodeRes = toJSON(apiutil.ErrorRes{Err: errors.ErrMalformedEntity.Error()})
passRegex = regexp.MustCompile("^.{8,}$")
)
type testRequest struct {
@@ -64,7 +69,7 @@ func (tr testRequest) make() (*http.Response, error) {
return nil, err
}
if tr.token != "" {
req.Header.Set("Authorization", httputil.BearerPrefix+tr.token)
req.Header.Set("Authorization", apiutil.BearerPrefix+tr.token)
}
if tr.contentType != "" {
req.Header.Set("Content-Type", tr.contentType)
@@ -89,7 +94,8 @@ func newService() users.Service {
}
func newServer(svc users.Service) *httptest.Server {
mux := api.MakeHandler(svc, mocktracer.New())
logger := logger.NewMock()
mux := api.MakeHandler(svc, mocktracer.New(), logger)
return httptest.NewServer(mux)
}
@@ -109,6 +115,8 @@ func TestRegister(t *testing.T) {
invalidData := toJSON(users.User{Email: invalidEmail, Password: validPass})
invalidPasswordData := toJSON(users.User{Email: validEmail, Password: invalidPass})
invalidFieldData := fmt.Sprintf(`{"email": "%s", "pass": "%s"}`, user.Email, user.Password)
emptyEmailData := `{"email": ""}`
emptyHostData := fmt.Sprintf(`{"email": "%s"}`, user.Email)
mockAuthzDB := map[string][]mocks.SubjectSet{}
mockAuthzDB[user.Email] = append(mockAuthzDB[user.Email], mocks.SubjectSet{Object: authoritiesObjKey, Relation: memberRelationKey})
@@ -131,7 +139,8 @@ func TestRegister(t *testing.T) {
{"register new user with unauthenticated access", userNew, contentType, http.StatusUnauthorized, "wrong"},
{"register existing user with unauthenticated access", data, contentType, http.StatusUnauthorized, "wrong"},
{"register user with invalid request format", "{", contentType, http.StatusBadRequest, token},
{"register user with empty JSON request", "{}", contentType, http.StatusBadRequest, token},
{"register user with empty email request", emptyEmailData, contentType, http.StatusBadRequest, token},
{"register user with empty host request", emptyHostData, contentType, http.StatusBadRequest, token},
{"register user with empty request", "", contentType, http.StatusBadRequest, token},
{"register user with invalid field name", invalidFieldData, contentType, http.StatusBadRequest, token},
{"register user with missing content type", data, "", http.StatusUnsupportedMediaType, token},
@@ -299,7 +308,7 @@ func TestPasswordResetRequest(t *testing.T) {
{"password reset request with valid email", data, contentType, http.StatusCreated, expectedExisting},
{"password reset request with invalid email", nonexistentData, contentType, http.StatusNotFound, notFoundRes},
{"password reset request with invalid request format", "{", contentType, http.StatusBadRequest, malformedRes},
{"password reset request with empty JSON request", "{}", contentType, http.StatusBadRequest, malformedRes},
{"password reset request with empty email request", "{}", contentType, http.StatusBadRequest, missingEmailRes},
{"password reset request with empty request", "", contentType, http.StatusBadRequest, malformedRes},
{"password reset request with missing content type", data, "", http.StatusUnsupportedMediaType, unsupportedRes},
}
@@ -374,9 +383,9 @@ func TestPasswordReset(t *testing.T) {
}{
{"password reset with valid token", reqExisting, contentType, http.StatusCreated, "{}", token},
{"password reset with invalid token", reqNoExist, contentType, http.StatusUnauthorized, unauthRes, token},
{"password reset with confirm password not matching", reqPassNoMatch, contentType, http.StatusBadRequest, malformedRes, token},
{"password reset with confirm password not matching", reqPassNoMatch, contentType, http.StatusBadRequest, invalidRestPassRes, token},
{"password reset request with invalid request format", "{", contentType, http.StatusBadRequest, malformedRes, token},
{"password reset request with empty JSON request", "{}", contentType, http.StatusBadRequest, malformedRes, token},
{"password reset request with empty JSON request", "{}", contentType, http.StatusBadRequest, missingPassRes, token},
{"password reset request with empty request", "", contentType, http.StatusBadRequest, malformedRes, token},
{"password reset request with missing content type", reqExisting, "", http.StatusUnsupportedMediaType, unsupportedRes, token},
{"password reset with weak password", reqPassWeak, contentType, http.StatusBadRequest, weakPassword, token},
@@ -447,10 +456,10 @@ func TestPasswordChange(t *testing.T) {
tok string
}{
{"password change with valid token", dataResExisting, contentType, http.StatusCreated, "{}", token},
{"password change with invalid token", reqNoExist, contentType, http.StatusUnauthorized, unauthRes, ""},
{"password change with empty token", reqNoExist, contentType, http.StatusUnauthorized, missingTokRes, ""},
{"password change with invalid old password", reqWrongPass, contentType, http.StatusUnauthorized, unauthRes, token},
{"password change with invalid new password", reqWeakPass, contentType, http.StatusBadRequest, weakPassword, token},
{"password change with empty JSON request", "{}", contentType, http.StatusBadRequest, malformedRes, token},
{"password change with empty JSON request", "{}", contentType, http.StatusBadRequest, missingPassRes, token},
{"password change empty request", "", contentType, http.StatusBadRequest, malformedRes, token},
{"password change missing content type", dataResExisting, "", http.StatusUnsupportedMediaType, unsupportedRes, token},
}
+28 -16
View File
@@ -4,7 +4,7 @@
package api
import (
"github.com/mainflux/mainflux/pkg/errors"
"github.com/mainflux/mainflux/internal/apiutil"
"github.com/mainflux/mainflux/users"
)
@@ -32,7 +32,7 @@ type viewUserReq struct {
func (req viewUserReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
return nil
}
@@ -47,7 +47,7 @@ type listUsersReq struct {
func (req listUsersReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
return nil
}
@@ -59,7 +59,7 @@ type updateUserReq struct {
func (req updateUserReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
return nil
}
@@ -70,9 +70,14 @@ type passwResetReq struct {
}
func (req passwResetReq) validate() error {
if req.Email == "" || req.Host == "" {
return errors.ErrMalformedEntity
if req.Email == "" {
return apiutil.ErrMissingEmail
}
if req.Host == "" {
return apiutil.ErrMissingHost
}
return nil
}
@@ -83,30 +88,37 @@ type resetTokenReq struct {
}
func (req resetTokenReq) validate() error {
if req.Password == "" || req.ConfPass == "" {
return errors.ErrMalformedEntity
if req.Password == "" {
return apiutil.ErrMissingPass
}
if req.ConfPass == "" {
return apiutil.ErrMissingConfPass
}
if req.Token == "" {
return users.ErrMissingResetToken
return apiutil.ErrBearerToken
}
if req.Password != req.ConfPass {
return errors.ErrMalformedEntity
return apiutil.ErrInvalidResetPass
}
return nil
}
type passwChangeReq struct {
Token string `json:"token"`
token string
Password string `json:"password"`
OldPassword string `json:"old_password"`
}
func (req passwChangeReq) validate() error {
if req.Token == "" {
return errors.ErrAuthentication
if req.token == "" {
return apiutil.ErrBearerToken
}
if req.OldPassword == "" {
return errors.ErrMalformedEntity
return apiutil.ErrMissingPass
}
return nil
}
@@ -121,11 +133,11 @@ type listMemberGroupReq struct {
func (req listMemberGroupReq) validate() error {
if req.token == "" {
return errors.ErrAuthentication
return apiutil.ErrBearerToken
}
if req.groupID == "" {
return errors.ErrMalformedEntity
return apiutil.ErrMissingID
}
return nil
+30 -55
View File
@@ -13,7 +13,8 @@ import (
kithttp "github.com/go-kit/kit/transport/http"
"github.com/go-zoo/bone"
"github.com/mainflux/mainflux"
"github.com/mainflux/mainflux/internal/httputil"
"github.com/mainflux/mainflux/internal/apiutil"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
"github.com/mainflux/mainflux/pkg/uuid"
"github.com/mainflux/mainflux/users"
@@ -32,9 +33,9 @@ const (
)
// MakeHandler returns a HTTP handler for API endpoints.
func MakeHandler(svc users.Service, tracer opentracing.Tracer) http.Handler {
func MakeHandler(svc users.Service, tracer opentracing.Tracer, logger logger.Logger) http.Handler {
opts := []kithttp.ServerOption{
kithttp.ServerErrorEncoder(encodeError),
kithttp.ServerErrorEncoder(apiutil.LoggingErrorEncoder(logger, encodeError)),
}
mux := bone.New()
@@ -116,55 +117,43 @@ func MakeHandler(svc users.Service, tracer opentracing.Tracer) http.Handler {
}
func decodeViewUser(_ context.Context, r *http.Request) (interface{}, error) {
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req := viewUserReq{
token: t,
token: apiutil.ExtractBearerToken(r),
userID: bone.GetValue(r, "userID"),
}
return req, nil
}
func decodeViewProfile(_ context.Context, r *http.Request) (interface{}, error) {
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req := viewUserReq{
token: t,
}
req := viewUserReq{token: apiutil.ExtractBearerToken(r)}
return req, nil
}
func decodeListUsers(_ context.Context, r *http.Request) (interface{}, error) {
o, err := httputil.ReadUintQuery(r, offsetKey, defOffset)
o, err := apiutil.ReadUintQuery(r, offsetKey, defOffset)
if err != nil {
return nil, err
}
l, err := httputil.ReadUintQuery(r, limitKey, defLimit)
l, err := apiutil.ReadUintQuery(r, limitKey, defLimit)
if err != nil {
return nil, err
}
e, err := httputil.ReadStringQuery(r, emailKey, "")
e, err := apiutil.ReadStringQuery(r, emailKey, "")
if err != nil {
return nil, err
}
m, err := httputil.ReadMetadataQuery(r, metadataKey, nil)
m, err := apiutil.ReadMetadataQuery(r, metadataKey, nil)
if err != nil {
return nil, err
}
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req := listUsersReq{
token: t,
token: apiutil.ExtractBearerToken(r),
offset: o,
limit: l,
email: e,
@@ -174,16 +163,11 @@ func decodeListUsers(_ context.Context, r *http.Request) (interface{}, error) {
}
func decodeUpdateUser(_ context.Context, r *http.Request) (interface{}, error) {
var req updateUserReq
req := updateUserReq{token: apiutil.ExtractBearerToken(r)}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return nil, errors.Wrap(errors.ErrMalformedEntity, err)
}
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req.token = t
return req, nil
}
@@ -205,11 +189,6 @@ func decodeCreateUserReq(_ context.Context, r *http.Request) (interface{}, error
return nil, errors.ErrUnsupportedContentType
}
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
var user users.User
if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
return nil, errors.Wrap(errors.ErrMalformedEntity, err)
@@ -217,7 +196,7 @@ func decodeCreateUserReq(_ context.Context, r *http.Request) (interface{}, error
req := createUserReq{
user: user,
token: t,
token: apiutil.ExtractBearerToken(r),
}
return req, nil
@@ -256,42 +235,32 @@ func decodePasswordChange(_ context.Context, r *http.Request) (interface{}, erro
return nil, errors.ErrUnsupportedContentType
}
var req passwChangeReq
req := passwChangeReq{token: apiutil.ExtractBearerToken(r)}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return nil, errors.Wrap(errors.ErrMalformedEntity, err)
}
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req.Token = t
return req, nil
}
func decodeListMembersRequest(_ context.Context, r *http.Request) (interface{}, error) {
o, err := httputil.ReadUintQuery(r, offsetKey, defOffset)
o, err := apiutil.ReadUintQuery(r, offsetKey, defOffset)
if err != nil {
return nil, err
}
l, err := httputil.ReadUintQuery(r, limitKey, defLimit)
l, err := apiutil.ReadUintQuery(r, limitKey, defLimit)
if err != nil {
return nil, err
}
m, err := httputil.ReadMetadataQuery(r, metadataKey, nil)
m, err := apiutil.ReadMetadataQuery(r, metadataKey, nil)
if err != nil {
return nil, err
}
t, err := httputil.ExtractAuthToken(r)
if err != nil {
return nil, err
}
req := listMemberGroupReq{
token: t,
token: apiutil.ExtractBearerToken(r),
groupID: bone.GetValue(r, "groupId"),
offset: o,
limit: l,
@@ -320,10 +289,15 @@ func encodeError(_ context.Context, err error, w http.ResponseWriter) {
switch {
case errors.Contains(err, errors.ErrInvalidQueryParams),
errors.Contains(err, errors.ErrMalformedEntity),
errors.Contains(err, users.ErrPasswordFormat):
errors.Contains(err, users.ErrPasswordFormat),
err == apiutil.ErrMissingEmail,
err == apiutil.ErrMissingHost,
err == apiutil.ErrMissingPass,
err == apiutil.ErrMissingConfPass,
err == apiutil.ErrInvalidResetPass:
w.WriteHeader(http.StatusBadRequest)
case errors.Contains(err, errors.ErrAuthentication),
errors.Contains(err, users.ErrRecoveryToken):
err == apiutil.ErrBearerToken:
w.WriteHeader(http.StatusUnauthorized)
case errors.Contains(err, errors.ErrAuthorization):
w.WriteHeader(http.StatusForbidden)
@@ -335,7 +309,8 @@ func encodeError(_ context.Context, err error, w http.ResponseWriter) {
case errors.Contains(err, errors.ErrNotFound):
w.WriteHeader(http.StatusNotFound)
case errors.Contains(err, uuid.ErrGeneratingID):
case errors.Contains(err, uuid.ErrGeneratingID),
errors.Contains(err, users.ErrRecoveryToken):
w.WriteHeader(http.StatusInternalServerError)
case errors.Contains(err, errors.ErrCreateEntity),
@@ -350,7 +325,7 @@ func encodeError(_ context.Context, err error, w http.ResponseWriter) {
if errorVal, ok := err.(errors.Error); ok {
w.Header().Set("Content-Type", contentType)
if err := json.NewEncoder(w).Encode(httputil.ErrorRes{Err: errorVal.Msg()}); err != nil {
if err := json.NewEncoder(w).Encode(apiutil.ErrorRes{Err: errorVal.Msg()}); err != nil {
w.WriteHeader(http.StatusInternalServerError)
}
}