diff --git a/certs/certs.go b/certs/certs.go index 9b0a63fb..e8b4e17a 100644 --- a/certs/certs.go +++ b/certs/certs.go @@ -8,7 +8,6 @@ import ( "crypto/tls" "crypto/x509" "encoding/pem" - "io/ioutil" "os" "github.com/mainflux/mainflux/pkg/errors" @@ -62,7 +61,7 @@ func LoadCertificates(caPath, caKeyPath string) (tls.Certificate, *x509.Certific return tlsCert, &x509.Certificate{}, err } - b, err := ioutil.ReadFile(caPath) + b, err := os.ReadFile(caPath) if err != nil { return tlsCert, &x509.Certificate{}, err } diff --git a/certs/mocks/channels.go b/certs/mocks/channels.go new file mode 100644 index 00000000..fb2439da --- /dev/null +++ b/certs/mocks/channels.go @@ -0,0 +1,109 @@ +// Copyright (c) Mainflux +// SPDX-License-Identifier: Apache-2.0 + +package mocks + +import ( + "context" + "strconv" + "sync" + + mfclients "github.com/mainflux/mainflux/pkg/clients" + "github.com/mainflux/mainflux/pkg/errors" + mfgroups "github.com/mainflux/mainflux/pkg/groups" + "github.com/mainflux/mainflux/things/groups" + upolicies "github.com/mainflux/mainflux/users/policies" +) + +var _ groups.Service = (*mainfluxChannels)(nil) + +type mainfluxChannels struct { + mu sync.Mutex + counter uint64 + channels map[string]mfgroups.Group + auth upolicies.AuthServiceClient +} + +// NewChannelsService returns Mainflux Channels service mock. +// Only methods used by SDK are mocked. +func NewChannelsService(channels map[string]mfgroups.Group, auth upolicies.AuthServiceClient) groups.Service { + return &mainfluxChannels{ + channels: channels, + auth: auth, + } +} + +func (svc *mainfluxChannels) CreateGroups(ctx context.Context, token string, chs ...mfgroups.Group) ([]mfgroups.Group, error) { + svc.mu.Lock() + defer svc.mu.Unlock() + + userID, err := svc.auth.Identify(ctx, &upolicies.Token{Value: token}) + if err != nil { + return []mfgroups.Group{}, errors.ErrAuthentication + } + for i := range chs { + svc.counter++ + chs[i].Owner = userID.GetId() + chs[i].ID = strconv.FormatUint(svc.counter, 10) + svc.channels[chs[i].ID] = chs[i] + } + + return chs, nil +} + +func (svc *mainfluxChannels) ViewGroup(_ context.Context, owner, id string) (mfgroups.Group, error) { + if c, ok := svc.channels[id]; ok { + return c, nil + } + return mfgroups.Group{}, errors.ErrNotFound +} + +func (svc *mainfluxChannels) ListGroups(context.Context, string, mfgroups.GroupsPage) (mfgroups.GroupsPage, error) { + panic("not implemented") +} + +func (svc *mainfluxChannels) ListMemberships(context.Context, string, string, mfgroups.GroupsPage) (mfgroups.MembershipsPage, error) { + panic("not implemented") +} + +func (svc *mainfluxChannels) UpdateGroup(context.Context, string, mfgroups.Group) (mfgroups.Group, error) { + panic("not implemented") +} + +func (svc *mainfluxChannels) EnableGroup(ctx context.Context, token, id string) (mfgroups.Group, error) { + svc.mu.Lock() + defer svc.mu.Unlock() + + userID, err := svc.auth.Identify(ctx, &upolicies.Token{Value: token}) + if err != nil { + return mfgroups.Group{}, errors.ErrAuthentication + } + + if t, ok := svc.channels[id]; !ok || t.Owner != userID.GetId() { + return mfgroups.Group{}, errors.ErrNotFound + } + if t, ok := svc.channels[id]; ok && t.Owner == userID.GetId() { + t.Status = mfclients.EnabledStatus + return t, nil + } + return mfgroups.Group{}, nil +} + +func (svc *mainfluxChannels) DisableGroup(ctx context.Context, token, id string) (mfgroups.Group, error) { + svc.mu.Lock() + defer svc.mu.Unlock() + + userID, err := svc.auth.Identify(ctx, &upolicies.Token{Value: token}) + if err != nil { + return mfgroups.Group{}, errors.ErrAuthentication + } + + if t, ok := svc.channels[id]; !ok || t.Owner != userID.GetId() { + return mfgroups.Group{}, errors.ErrNotFound + } + if t, ok := svc.channels[id]; ok && t.Owner == userID.GetId() { + t.Status = mfclients.DisabledStatus + return t, nil + } + return mfgroups.Group{}, nil +} diff --git a/certs/mocks/policies.go b/certs/mocks/policies.go new file mode 100644 index 00000000..99e93c90 --- /dev/null +++ b/certs/mocks/policies.go @@ -0,0 +1,71 @@ +// Copyright (c) Mainflux +// SPDX-License-Identifier: Apache-2.0 + +package mocks + +import ( + "context" + "fmt" + "sync" + + "github.com/mainflux/mainflux/pkg/errors" + tpolicies "github.com/mainflux/mainflux/things/policies" + upolicies "github.com/mainflux/mainflux/users/policies" +) + +var _ tpolicies.Service = (*mainfluxPolicies)(nil) + +type mainfluxPolicies struct { + mu sync.Mutex + auth upolicies.AuthServiceClient + connections map[string]tpolicies.Policy +} + +// NewPoliciesService returns Mainflux Things Policies service mock. +// Only methods used by SDK are mocked. +func NewPoliciesService(auth upolicies.AuthServiceClient) tpolicies.Service { + return &mainfluxPolicies{ + auth: auth, + connections: make(map[string]tpolicies.Policy), + } +} + +func (svc *mainfluxPolicies) AddPolicy(ctx context.Context, token string, p tpolicies.Policy) (tpolicies.Policy, error) { + svc.mu.Lock() + defer svc.mu.Unlock() + + if _, err := svc.auth.Identify(ctx, &upolicies.Token{Value: token}); err != nil { + return tpolicies.Policy{}, errors.ErrAuthentication + } + svc.connections[fmt.Sprintf("%s:%s", p.Subject, p.Object)] = p + + return p, nil +} + +func (svc *mainfluxPolicies) DeletePolicy(ctx context.Context, token string, p tpolicies.Policy) error { + svc.mu.Lock() + defer svc.mu.Unlock() + + if _, err := svc.auth.Identify(context.Background(), &upolicies.Token{Value: token}); err != nil { + return errors.ErrAuthentication + } + + for _, pol := range svc.connections { + if pol.Subject == p.Subject && pol.Object == p.Object { + delete(svc.connections, fmt.Sprintf("%s:%s", p.Subject, p.Object)) + } + } + return nil +} + +func (svc *mainfluxPolicies) UpdatePolicy(context.Context, string, tpolicies.Policy) (tpolicies.Policy, error) { + panic("not implemented") +} + +func (svc *mainfluxPolicies) Authorize(context.Context, tpolicies.AccessRequest) (tpolicies.Policy, error) { + panic("not implemented") +} + +func (svc *mainfluxPolicies) ListPolicies(context.Context, string, tpolicies.Page) (tpolicies.PolicyPage, error) { + panic("not implemented") +} diff --git a/certs/mocks/things.go b/certs/mocks/things.go new file mode 100644 index 00000000..e8ccb2f7 --- /dev/null +++ b/certs/mocks/things.go @@ -0,0 +1,139 @@ +// Copyright (c) Mainflux +// SPDX-License-Identifier: Apache-2.0 + +package mocks + +import ( + "context" + "strconv" + "sync" + + mfclients "github.com/mainflux/mainflux/pkg/clients" + "github.com/mainflux/mainflux/pkg/errors" + "github.com/mainflux/mainflux/things/clients" + upolicies "github.com/mainflux/mainflux/users/policies" +) + +var _ clients.Service = (*mainfluxThings)(nil) + +type mainfluxThings struct { + mu sync.Mutex + counter uint64 + things map[string]mfclients.Client + auth upolicies.AuthServiceClient +} + +// NewThingsService returns Mainflux Things service mock. +// Only methods used by SDK are mocked. +func NewThingsService(things map[string]mfclients.Client, auth upolicies.AuthServiceClient) clients.Service { + return &mainfluxThings{ + things: things, + auth: auth, + } +} + +func (svc *mainfluxThings) CreateThings(_ context.Context, owner string, ths ...mfclients.Client) ([]mfclients.Client, error) { + svc.mu.Lock() + defer svc.mu.Unlock() + + userID, err := svc.auth.Identify(context.Background(), &upolicies.Token{Value: owner}) + if err != nil { + return []mfclients.Client{}, errors.ErrAuthentication + } + for i := range ths { + svc.counter++ + ths[i].Owner = userID.GetId() + ths[i].ID = strconv.FormatUint(svc.counter, 10) + ths[i].Credentials.Secret = ths[i].ID + svc.things[ths[i].ID] = ths[i] + } + + return ths, nil +} + +func (svc *mainfluxThings) ViewClient(_ context.Context, owner, id string) (mfclients.Client, error) { + svc.mu.Lock() + defer svc.mu.Unlock() + + userID, err := svc.auth.Identify(context.Background(), &upolicies.Token{Value: owner}) + if err != nil { + return mfclients.Client{}, errors.ErrAuthentication + } + + if t, ok := svc.things[id]; ok && t.Owner == userID.GetId() { + return t, nil + + } + + return mfclients.Client{}, errors.ErrNotFound +} + +func (svc *mainfluxThings) EnableClient(ctx context.Context, token, id string) (mfclients.Client, error) { + svc.mu.Lock() + defer svc.mu.Unlock() + + userID, err := svc.auth.Identify(context.Background(), &upolicies.Token{Value: token}) + if err != nil { + return mfclients.Client{}, errors.ErrAuthentication + } + + if t, ok := svc.things[id]; !ok || t.Owner != userID.GetId() { + return mfclients.Client{}, errors.ErrNotFound + } + if t, ok := svc.things[id]; ok && t.Owner == userID.GetId() { + t.Status = mfclients.EnabledStatus + return t, nil + } + return mfclients.Client{}, nil +} + +func (svc *mainfluxThings) DisableClient(ctx context.Context, token, id string) (mfclients.Client, error) { + svc.mu.Lock() + defer svc.mu.Unlock() + + userID, err := svc.auth.Identify(context.Background(), &upolicies.Token{Value: token}) + if err != nil { + return mfclients.Client{}, errors.ErrAuthentication + } + + if t, ok := svc.things[id]; !ok || t.Owner != userID.GetId() { + return mfclients.Client{}, errors.ErrNotFound + } + if t, ok := svc.things[id]; ok && t.Owner == userID.GetId() { + t.Status = mfclients.DisabledStatus + return t, nil + } + return mfclients.Client{}, nil +} + +func (svc *mainfluxThings) UpdateClient(context.Context, string, mfclients.Client) (mfclients.Client, error) { + panic("not implemented") +} + +func (svc *mainfluxThings) UpdateClientSecret(context.Context, string, string, string) (mfclients.Client, error) { + panic("not implemented") +} + +func (svc *mainfluxThings) UpdateClientOwner(context.Context, string, mfclients.Client) (mfclients.Client, error) { + panic("not implemented") +} + +func (svc *mainfluxThings) UpdateClientTags(context.Context, string, mfclients.Client) (mfclients.Client, error) { + panic("not implemented") +} + +func (svc *mainfluxThings) ListClients(context.Context, string, mfclients.Page) (mfclients.ClientsPage, error) { + panic("not implemented") +} + +func (svc *mainfluxThings) ListClientsByGroup(context.Context, string, string, mfclients.Page) (mfclients.MembersPage, error) { + panic("not implemented") +} + +func (svc *mainfluxThings) Identify(context.Context, string) (string, error) { + panic("not implemented") +} + +func (svc *mainfluxThings) ShareClient(ctx context.Context, token, userID, groupID, thingID string, actions []string) error { + panic("not implemented") +} diff --git a/certs/service_test.go b/certs/service_test.go index 31583994..4ec889aa 100644 --- a/certs/service_test.go +++ b/certs/service_test.go @@ -23,7 +23,7 @@ import ( "github.com/mainflux/mainflux/things/clients" httpapi "github.com/mainflux/mainflux/things/clients/api" thmocks "github.com/mainflux/mainflux/things/clients/mocks" - "github.com/mainflux/mainflux/users/policies" + upolicies "github.com/mainflux/mainflux/users/policies" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -47,6 +47,7 @@ const ( func newService(tokens map[string]string) (certs.Service, error) { ac := bsmocks.NewAuthClient(map[string]string{token: email}) + server := newThingsServer(newThingsService(ac)) policies := []thmocks.MockSubjectSet{{Object: "token", Relation: clients.AdminRelationKey}} @@ -74,7 +75,7 @@ func newService(tokens map[string]string) (certs.Service, error) { return certs.New(auth, repo, sdk, pki), nil } -func newThingsService(auth policies.AuthServiceClient) clients.Service { +func newThingsService(auth upolicies.AuthServiceClient) clients.Service { ths := make(map[string]mfclients.Client, thingsNum) for i := 0; i < thingsNum; i++ { id := strconv.Itoa(i + 1) diff --git a/cli/things.go b/cli/things.go index 9e2a4fff..d28e03f8 100644 --- a/cli/things.go +++ b/cli/things.go @@ -215,23 +215,23 @@ var cmdThings = []cobra.Command{ }, }, { - Use: "share ", + Use: "share ", Short: "Share thing with a user", Long: "Share thing with a user\n" + "Usage:\n" + - "\tmainflux-cli things share '[\"c_list\", \"c_delete\"]' $USERTOKEN\n", + "\tmainflux-cli things share '[\"c_list\", \"c_delete\"]' $USERTOKEN\n", Run: func(cmd *cobra.Command, args []string) { - if len(args) != 5 { + if len(args) != 4 { logUsage(cmd.Use) return } var actions []string - if err := json.Unmarshal([]byte(args[3]), &actions); err != nil { + if err := json.Unmarshal([]byte(args[2]), &actions); err != nil { logError(err) return } - err := sdk.ShareThing(args[0], args[1], args[2], actions, args[4]) + err := sdk.ShareThing(args[0], args[1], actions, args[3]) if err != nil { logError(err) return diff --git a/pkg/messaging/mqtt/pubsub_test.go b/pkg/messaging/mqtt/pubsub_test.go index 5c9c7bda..3043234d 100644 --- a/pkg/messaging/mqtt/pubsub_test.go +++ b/pkg/messaging/mqtt/pubsub_test.go @@ -39,7 +39,7 @@ func TestPublisher(t *testing.T) { client, err := newClient(address, "clientID1", brokerTimeout) assert.Nil(t, err, fmt.Sprintf("got unexpected error: %s", err)) - token := client.Subscribe(topic, qos, func(c mqtt.Client, m mqtt.Message) { + token := client.Subscribe(topic, qos, func(_ mqtt.Client, m mqtt.Message) { msgChan <- m.Payload() }) if ok := token.WaitTimeout(tokenTimeout); !ok { @@ -47,7 +47,7 @@ func TestPublisher(t *testing.T) { } assert.Nil(t, token.Error(), fmt.Sprintf("got unexpected error: %s", token.Error())) - token = client.Subscribe(fmt.Sprintf("%s.%s", topic, subtopic), qos, func(c mqtt.Client, m mqtt.Message) { + token = client.Subscribe(fmt.Sprintf("%s.%s", topic, subtopic), qos, func(_ mqtt.Client, m mqtt.Message) { msgChan <- m.Payload() }) if ok := token.WaitTimeout(tokenTimeout); !ok { diff --git a/pkg/sdk/go/requests.go b/pkg/sdk/go/requests.go index 3431ade5..e03daa5e 100644 --- a/pkg/sdk/go/requests.go +++ b/pkg/sdk/go/requests.go @@ -38,12 +38,6 @@ type tokenReq struct { Secret string `json:"secret"` } -type shareThingReq struct { - GroupID string `json:"group_id"` - UserID string `json:"user_id"` - Actions []string `json:"actions"` -} - type canAccessReq struct { ClientSecret string `json:"secret"` GroupID string `json:"group_id"` diff --git a/pkg/sdk/go/sdk.go b/pkg/sdk/go/sdk.go index 4ad5373a..c3a4e3f5 100644 --- a/pkg/sdk/go/sdk.go +++ b/pkg/sdk/go/sdk.go @@ -370,12 +370,17 @@ type SDK interface { // fmt.Println(id) IdentifyThing(key string) (string, errors.SDKError) - // ShareThing shares thing with other user. + // ShareThing shares thing with other user. It assumes that you have + // already created a group and added things to it. It also assumes that + // you have required policy to share a thing with the specified user. + // + // The `ShareThing` method calls the `Connect` method with the + // subject as `userID` rather than `thingID`. // // example: - // err := sdk.ShareThing("thingID", "groupID", "userID", []string{"c_list", "c_delete"}, "token") + // err := sdk.ShareThing("channelID", "userID", []string{"c_list", "c_delete"}, "token") // fmt.Println(err) - ShareThing(thingID, groupID, userID string, actions []string, token string) errors.SDKError + ShareThing(channelID, userID string, actions []string, token string) errors.SDKError // CreateGroup creates new group and returns its id. // diff --git a/pkg/sdk/go/things.go b/pkg/sdk/go/things.go index 7aa2eb61..b819c1d8 100644 --- a/pkg/sdk/go/things.go +++ b/pkg/sdk/go/things.go @@ -250,18 +250,12 @@ func (sdk mfSDK) IdentifyThing(key string) (string, errors.SDKError) { return i.ID, nil } -func (sdk mfSDK) ShareThing(thingID, groupID, userID string, actions []string, token string) errors.SDKError { - sreq := shareThingReq{GroupID: groupID, UserID: userID, Actions: actions} - data, err := json.Marshal(sreq) - if err != nil { - return errors.NewSDKError(err) +func (sdk mfSDK) ShareThing(groupID, userID string, actions []string, token string) errors.SDKError { + policy := ConnectionIDs{ + ChannelIDs: []string{groupID}, + ThingIDs: []string{userID}, + Actions: actions, } - url := fmt.Sprintf("%s/%s/%s/%s", sdk.thingsURL, thingsEndpoint, thingID, shareEndpoint) - _, _, sdkerr := sdk.processRequest(http.MethodPost, url, token, string(CTJSON), data, http.StatusOK) - if sdkerr != nil { - return sdkerr - } - - return nil + return sdk.Connect(policy, token) } diff --git a/pkg/sdk/go/things_test.go b/pkg/sdk/go/things_test.go index 67844a51..beefff8d 100644 --- a/pkg/sdk/go/things_test.go +++ b/pkg/sdk/go/things_test.go @@ -1383,7 +1383,6 @@ func TestShareThing(t *testing.T) { cases := []struct { desc string - thingID string groupID string userID string token string @@ -1391,7 +1390,6 @@ func TestShareThing(t *testing.T) { }{ { desc: "share thing with valid token", - thingID: generateUUID(t), groupID: generateUUID(t), userID: generateUUID(t), token: adminToken, @@ -1399,7 +1397,6 @@ func TestShareThing(t *testing.T) { }, { desc: "share thing with invalid token", - thingID: generateUUID(t), groupID: generateUUID(t), userID: generateUUID(t), token: invalidToken, @@ -1412,7 +1409,7 @@ func TestShareThing(t *testing.T) { repoCall1 := pRepo.On("EvaluateThingAccess", mock.Anything, mock.Anything).Return(policies.Policy{}, nil) repoCall3 := pRepo.On("Retrieve", mock.Anything, mock.Anything).Return(policies.PolicyPage{}, nil) repoCall4 := pRepo.On("Save", mock.Anything, mock.Anything).Return(policies.Policy{}, nil) - err := mfsdk.ShareThing(tc.thingID, tc.groupID, tc.userID, []string{"c_list", "c_delete"}, tc.token) + err := mfsdk.ShareThing(tc.groupID, tc.userID, []string{"c_list", "c_delete"}, tc.token) assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected error %s, got %s", tc.desc, tc.err, err)) if tc.err == nil { ok := repoCall4.Parent.AssertCalled(t, "Save", mock.Anything, mock.Anything) diff --git a/things/clients/api/endpoints.go b/things/clients/api/endpoints.go index 25301783..e7863a18 100644 --- a/things/clients/api/endpoints.go +++ b/things/clients/api/endpoints.go @@ -159,19 +159,6 @@ func updateClientTagsEndpoint(svc clients.Service) endpoint.Endpoint { } } -func shareClientEndpoint(svc clients.Service) endpoint.Endpoint { - return func(ctx context.Context, request interface{}) (interface{}, error) { - req := request.(shareClientReq) - if err := req.validate(); err != nil { - return nil, err - } - if err := svc.ShareClient(ctx, req.token, req.UserID, req.GroupID, req.clientID, req.Actions); err != nil { - return nil, err - } - return shareClientRes{}, nil - } -} - func updateClientSecretEndpoint(svc clients.Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(updateClientCredentialsReq) diff --git a/things/clients/api/logging.go b/things/clients/api/logging.go index 0f1a1a48..f43c641f 100644 --- a/things/clients/api/logging.go +++ b/things/clients/api/logging.go @@ -144,18 +144,6 @@ func (lm *loggingMiddleware) ListClientsByGroup(ctx context.Context, token, chan return lm.svc.ListClientsByGroup(ctx, token, channelID, cp) } -func (lm *loggingMiddleware) ShareClient(ctx context.Context, token, userID, groupID, thingID string, actions []string) (err error) { - defer func(begin time.Time) { - message := fmt.Sprintf("Method share_thing for thing with id %s using token %s took %s to complete", thingID, token, time.Since(begin)) - if err != nil { - lm.logger.Warn(fmt.Sprintf("%s with error: %s.", message, err)) - return - } - lm.logger.Info(fmt.Sprintf("%s without errors.", message)) - }(time.Now()) - return lm.svc.ShareClient(ctx, token, userID, groupID, thingID, actions) -} - func (lm *loggingMiddleware) Identify(ctx context.Context, key string) (id string, err error) { defer func(begin time.Time) { message := fmt.Sprintf("Method identify for thing with id %s and key %s took %s to complete", id, key, time.Since(begin)) diff --git a/things/clients/api/metrics.go b/things/clients/api/metrics.go index 60e26bcc..0ffb6cca 100644 --- a/things/clients/api/metrics.go +++ b/things/clients/api/metrics.go @@ -69,14 +69,6 @@ func (ms *metricsMiddleware) UpdateClientTags(ctx context.Context, token string, return ms.svc.UpdateClientTags(ctx, token, client) } -func (ms *metricsMiddleware) ShareClient(ctx context.Context, token, userID, groupID, thingID string, actions []string) error { - defer func(begin time.Time) { - ms.counter.With("method", "share_thing").Add(1) - ms.latency.With("method", "share_thing").Observe(time.Since(begin).Seconds()) - }(time.Now()) - return ms.svc.ShareClient(ctx, token, userID, groupID, thingID, actions) -} - func (ms *metricsMiddleware) UpdateClientSecret(ctx context.Context, token, oldSecret, newSecret string) (mfclients.Client, error) { defer func(begin time.Time) { ms.counter.With("method", "update_thing_secret").Add(1) diff --git a/things/clients/api/requests.go b/things/clients/api/requests.go index b800647b..b3a09f9b 100644 --- a/things/clients/api/requests.go +++ b/things/clients/api/requests.go @@ -208,27 +208,3 @@ func (req changeClientStatusReq) validate() error { } return nil } - -type shareClientReq struct { - token string - clientID string - GroupID string `json:"group_id"` - UserID string `json:"user_id"` - Actions []string `json:"actions"` -} - -func (req shareClientReq) validate() error { - if req.token == "" { - return apiutil.ErrBearerToken - } - - if req.clientID == "" || req.GroupID == "" || req.UserID == "" { - return apiutil.ErrMissingID - } - - if len(req.Actions) == 0 { - return apiutil.ErrEmptyList - } - - return nil -} diff --git a/things/clients/api/responses.go b/things/clients/api/responses.go index 2e530b34..f35eab30 100644 --- a/things/clients/api/responses.go +++ b/things/clients/api/responses.go @@ -18,7 +18,6 @@ var ( _ mainflux.Response = (*clientsPageRes)(nil) _ mainflux.Response = (*viewMembersRes)(nil) _ mainflux.Response = (*memberPageRes)(nil) - _ mainflux.Response = (*shareClientRes)(nil) ) type pageRes struct { @@ -151,17 +150,3 @@ func (res deleteClientRes) Headers() map[string]string { func (res deleteClientRes) Empty() bool { return false } - -type shareClientRes struct{} - -func (res shareClientRes) Code() int { - return http.StatusOK -} - -func (res shareClientRes) Headers() map[string]string { - return map[string]string{} -} - -func (res shareClientRes) Empty() bool { - return false -} diff --git a/things/clients/api/transport.go b/things/clients/api/transport.go index 19bd091e..76a3143c 100644 --- a/things/clients/api/transport.go +++ b/things/clients/api/transport.go @@ -77,13 +77,6 @@ func MakeHandler(svc clients.Service, mux *bone.Mux, logger mflog.Logger) http.H opts..., )) - mux.Post("/things/:thingID/share", kithttp.NewServer( - otelkit.EndpointMiddleware(otelkit.WithOperation("share_thing"))(shareClientEndpoint(svc)), - decodeShareClient, - api.EncodeResponse, - opts..., - )) - mux.Patch("/things/:thingID/secret", kithttp.NewServer( otelkit.EndpointMiddleware(otelkit.WithOperation("update_thing_secret"))(updateClientSecretEndpoint(svc)), decodeUpdateClientCredentials, @@ -126,22 +119,6 @@ func decodeViewClient(_ context.Context, r *http.Request) (interface{}, error) { return req, nil } -func decodeShareClient(_ context.Context, r *http.Request) (interface{}, error) { - if !strings.Contains(r.Header.Get("Content-Type"), api.ContentType) { - return nil, errors.ErrUnsupportedContentType - } - - req := shareClientReq{ - token: apiutil.ExtractBearerToken(r), - clientID: bone.GetValue(r, "thingID"), - } - if err := json.NewDecoder(r.Body).Decode(&req); err != nil { - return nil, errors.Wrap(errors.ErrMalformedEntity, err) - } - - return req, nil -} - func decodeListClients(_ context.Context, r *http.Request) (interface{}, error) { var sid, oid string s, err := apiutil.ReadStringQuery(r, api.StatusKey, api.DefClientStatus) diff --git a/things/clients/clients.go b/things/clients/clients.go index 52d1a7b8..9e11c7e5 100644 --- a/things/clients/clients.go +++ b/things/clients/clients.go @@ -45,11 +45,6 @@ type Service interface { // DisableClient logically disables the client identified with the provided ID DisableClient(ctx context.Context, token, id string) (clients.Client, error) - // ShareClient gives actions associated with the thing to the given user IDs. - // The requester user identified by the token has to have a "write" relation - // on the thing in order to share the thing. - ShareClient(ctx context.Context, token, userID, groupID, thingID string, actions []string) error - // Identify returns thing ID for given thing key. Identify(ctx context.Context, key string) (string, error) } diff --git a/things/clients/redis/events.go b/things/clients/redis/events.go index d02bf535..dc6767ac 100644 --- a/things/clients/redis/events.go +++ b/things/clients/redis/events.go @@ -17,7 +17,6 @@ const ( clientCreate = clientPrefix + "create" clientUpdate = clientPrefix + "update" clientRemove = clientPrefix + "remove" - clientShare = clientPrefix + "share" clientView = clientPrefix + "view" clientList = clientPrefix + "list" clientListByGroup = clientPrefix + "list_by_group" @@ -32,7 +31,6 @@ var ( _ event = (*createClientEvent)(nil) _ event = (*updateClientEvent)(nil) _ event = (*removeClientEvent)(nil) - _ event = (*shareClientEvent)(nil) _ event = (*viewClientEvent)(nil) _ event = (*listClientEvent)(nil) _ event = (*listClientByGroupEvent)(nil) @@ -136,23 +134,6 @@ func (rce removeClientEvent) Encode() (map[string]interface{}, error) { }, nil } -type shareClientEvent struct { - thingID string - actions string - userID string - groupID string -} - -func (sce shareClientEvent) Encode() (map[string]interface{}, error) { - return map[string]interface{}{ - "operation": clientShare, - "thing_id": sce.thingID, - "actions": sce.actions, - "user_id": sce.userID, - "group_id": sce.groupID, - }, nil -} - type viewClientEvent struct { mfclients.Client } diff --git a/things/clients/redis/streams.go b/things/clients/redis/streams.go index a42b3884..e59c8ac0 100644 --- a/things/clients/redis/streams.go +++ b/things/clients/redis/streams.go @@ -5,8 +5,6 @@ package redis import ( "context" - "fmt" - "strings" "github.com/go-redis/redis/v8" mfclients "github.com/mainflux/mainflux/pkg/clients" @@ -116,32 +114,6 @@ func (es eventStore) update(ctx context.Context, operation string, cli mfclients return cli, nil } -func (es eventStore) ShareClient(ctx context.Context, token, userID, groupID, thingID string, actions []string) error { - if err := es.svc.ShareClient(ctx, token, userID, groupID, thingID, actions); err != nil { - return err - } - event := shareClientEvent{ - thingID: thingID, - userID: userID, - groupID: groupID, - actions: fmt.Sprintf("[%s]", strings.Join(actions, ",")), - } - values, err := event.Encode() - if err != nil { - return err - } - record := &redis.XAddArgs{ - Stream: streamID, - MaxLenApprox: streamLen, - Values: values, - } - if err := es.client.XAdd(ctx, record).Err(); err != nil { - return err - } - - return nil -} - func (es eventStore) ViewClient(ctx context.Context, token, id string) (mfclients.Client, error) { cli, err := es.svc.ViewClient(ctx, token, id) if err != nil { diff --git a/things/clients/service.go b/things/clients/service.go index 817c35f4..c4133d7b 100644 --- a/things/clients/service.go +++ b/things/clients/service.go @@ -4,7 +4,6 @@ package clients import ( "context" - "fmt" "time" "github.com/mainflux/mainflux" @@ -280,36 +279,6 @@ func (svc service) Identify(ctx context.Context, key string) (string, error) { return client.ID, nil } -// ShareClient shares a thing with a user. -// We assume the user has already created the things anf group. -func (svc service) ShareClient(ctx context.Context, token, userID, groupID, thingID string, actions []string) error { - id, err := svc.identify(ctx, token) - if err != nil { - return err - } - - areq := tpolicies.AccessRequest{Subject: id, Object: groupID, Action: addRelationKey, Entity: groupEntityType} - if _, err := svc.policies.Authorize(ctx, areq); err != nil { - return fmt.Errorf("cannot share things using group %s to user %s: %s", groupID, userID, err) - } - - areq = tpolicies.AccessRequest{Subject: id, Object: thingID, Action: addRelationKey, Entity: clientEntityType} - if _, err := svc.policies.Authorize(ctx, areq); err != nil { - return fmt.Errorf("cannot share thing %s with user %s: %s", thingID, userID, err) - } - - policy := tpolicies.Policy{ - Subject: userID, - Object: groupID, - Actions: actions, - } - if _, err = svc.policies.AddPolicy(ctx, token, policy); err != nil { - return err - } - - return nil -} - func (svc service) identify(ctx context.Context, token string) (string, error) { req := &upolicies.Token{Value: token} res, err := svc.uauth.Identify(ctx, req) diff --git a/things/clients/tracing/tracing.go b/things/clients/tracing/tracing.go index b3c7692f..9454746c 100644 --- a/things/clients/tracing/tracing.go +++ b/things/clients/tracing/tracing.go @@ -110,19 +110,6 @@ func (tm *tracingMiddleware) ListClientsByGroup(ctx context.Context, token, grou } -// ShareClient traces the "ShareClient" operation of the wrapped policies.Service. -func (tm *tracingMiddleware) ShareClient(ctx context.Context, token, userID, groupID, thingID string, actions []string) error { - ctx, span := tm.tracer.Start(ctx, "svc_share_client", trace.WithAttributes( - attribute.String("userID", userID), - attribute.String("groupID", groupID), - attribute.String("thingID", thingID), - attribute.StringSlice("actions", actions), - )) - defer span.End() - - return tm.svc.ShareClient(ctx, token, userID, groupID, thingID, actions) -} - // ListMemberships traces the "ListMemberships" operation of the wrapped policies.Service. func (tm *tracingMiddleware) Identify(ctx context.Context, key string) (string, error) { ctx, span := tm.tracer.Start(ctx, "svc_identify", trace.WithAttributes(attribute.String("key", key)))