NOISSUE - Change Share Client To Be AddPolicy (#1825)
* Change Share Client To Be AddPolicy Signed-off-by: rodneyosodo <blackd0t@protonmail.com> * Remove from API endpoint as it is a duplicate of Signed-off-by: rodneyosodo <blackd0t@protonmail.com> * Fix typo Signed-off-by: rodneyosodo <blackd0t@protonmail.com> --------- Signed-off-by: rodneyosodo <blackd0t@protonmail.com>
This commit is contained in:
parent
2673b34c6a
commit
fce91bb652
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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")
|
||||
}
|
|
@ -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")
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -215,23 +215,23 @@ var cmdThings = []cobra.Command{
|
|||
},
|
||||
},
|
||||
{
|
||||
Use: "share <thing_id> <group_id> <user_id> <allowed_actions> <user_auth_token>",
|
||||
Use: "share <channel_id> <user_id> <allowed_actions> <user_auth_token>",
|
||||
Short: "Share thing with a user",
|
||||
Long: "Share thing with a user\n" +
|
||||
"Usage:\n" +
|
||||
"\tmainflux-cli things share <thing_id> <group_id> <user_id> '[\"c_list\", \"c_delete\"]' $USERTOKEN\n",
|
||||
"\tmainflux-cli things share <channel_id> <user_id> '[\"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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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"`
|
||||
|
|
|
@ -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.
|
||||
//
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)))
|
||||
|
|
Loading…
Reference in New Issue