github.com/cs3org/reva/v2@v2.27.7/pkg/publicshare/manager/memory/memory.go (about)

     1  // Copyright 2018-2021 CERN
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  //
    15  // In applying this license, CERN does not waive the privileges and immunities
    16  // granted to it by virtue of its status as an Intergovernmental Organization
    17  // or submit itself to any jurisdiction.
    18  
    19  package memory
    20  
    21  import (
    22  	"context"
    23  	"encoding/json"
    24  	"errors"
    25  	"fmt"
    26  	"math/rand"
    27  	"sync"
    28  	"time"
    29  
    30  	user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
    31  	link "github.com/cs3org/go-cs3apis/cs3/sharing/link/v1beta1"
    32  	provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
    33  	typespb "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
    34  	"github.com/cs3org/reva/v2/pkg/appctx"
    35  	"github.com/cs3org/reva/v2/pkg/errtypes"
    36  	"github.com/cs3org/reva/v2/pkg/publicshare"
    37  	"github.com/cs3org/reva/v2/pkg/publicshare/manager/registry"
    38  	"github.com/cs3org/reva/v2/pkg/utils"
    39  )
    40  
    41  func init() {
    42  	registry.Register("memory", New)
    43  }
    44  
    45  // New returns a new memory manager.
    46  func New(c map[string]interface{}) (publicshare.Manager, error) {
    47  	return &manager{
    48  		shares: sync.Map{},
    49  	}, nil
    50  }
    51  
    52  type manager struct {
    53  	shares sync.Map
    54  }
    55  
    56  var (
    57  	passwordProtected bool
    58  )
    59  
    60  // CreatePublicShare adds a new entry to manager.shares
    61  func (m *manager) CreatePublicShare(ctx context.Context, u *user.User, rInfo *provider.ResourceInfo, g *link.Grant) (*link.PublicShare, error) {
    62  	id := &link.PublicShareId{
    63  		OpaqueId: randString(15),
    64  	}
    65  
    66  	tkn := randString(15)
    67  	now := uint64(time.Now().Unix())
    68  
    69  	displayName, ok := rInfo.ArbitraryMetadata.Metadata["name"]
    70  	if !ok {
    71  		displayName = tkn
    72  	}
    73  
    74  	if g.Password != "" {
    75  		passwordProtected = true
    76  	}
    77  
    78  	createdAt := &typespb.Timestamp{
    79  		Seconds: now,
    80  		Nanos:   uint32(now % 1000000000),
    81  	}
    82  
    83  	modifiedAt := &typespb.Timestamp{
    84  		Seconds: now,
    85  		Nanos:   uint32(now % 1000000000),
    86  	}
    87  
    88  	s := link.PublicShare{
    89  		Id:                id,
    90  		Owner:             rInfo.GetOwner(),
    91  		Creator:           u.Id,
    92  		ResourceId:        rInfo.Id,
    93  		Token:             tkn,
    94  		Permissions:       g.Permissions,
    95  		Ctime:             createdAt,
    96  		Mtime:             modifiedAt,
    97  		PasswordProtected: passwordProtected,
    98  		Expiration:        g.Expiration,
    99  		DisplayName:       displayName,
   100  	}
   101  
   102  	m.shares.Store(s.Token, &s)
   103  	return &s, nil
   104  }
   105  
   106  // UpdatePublicShare updates the expiration date, permissions and Mtime
   107  func (m *manager) UpdatePublicShare(ctx context.Context, u *user.User, req *link.UpdatePublicShareRequest) (*link.PublicShare, error) {
   108  	log := appctx.GetLogger(ctx)
   109  	share, err := m.GetPublicShare(ctx, u, req.Ref, false)
   110  	if err != nil {
   111  		return nil, errors.New("ref does not exist")
   112  	}
   113  
   114  	token := share.GetToken()
   115  
   116  	switch req.GetUpdate().GetType() {
   117  	case link.UpdatePublicShareRequest_Update_TYPE_DISPLAYNAME:
   118  		log.Debug().Str("memory", "update display name").Msgf("from: `%v` to `%v`", share.DisplayName, req.Update.GetDisplayName())
   119  		share.DisplayName = req.Update.GetDisplayName()
   120  	case link.UpdatePublicShareRequest_Update_TYPE_PERMISSIONS:
   121  		old, _ := json.Marshal(share.Permissions)
   122  		new, _ := json.Marshal(req.Update.GetGrant().Permissions)
   123  		log.Debug().Str("memory", "update grants").Msgf("from: `%v`\nto\n`%v`", old, new)
   124  		share.Permissions = req.Update.GetGrant().GetPermissions()
   125  	case link.UpdatePublicShareRequest_Update_TYPE_EXPIRATION:
   126  		old, _ := json.Marshal(share.Expiration)
   127  		new, _ := json.Marshal(req.Update.GetGrant().Expiration)
   128  		log.Debug().Str("memory", "update expiration").Msgf("from: `%v`\nto\n`%v`", old, new)
   129  		share.Expiration = req.Update.GetGrant().Expiration
   130  	case link.UpdatePublicShareRequest_Update_TYPE_PASSWORD:
   131  		// TODO(refs) Do public shares need Grants? Struct is defined, just not used. Fill this once it's done.
   132  		fallthrough
   133  	default:
   134  		return nil, fmt.Errorf("invalid update type: %v", req.GetUpdate().GetType())
   135  	}
   136  
   137  	// share.Expiration = g.Expiration
   138  	share.Mtime = &typespb.Timestamp{
   139  		Seconds: uint64(time.Now().Unix()),
   140  		Nanos:   uint32(time.Now().Unix() % 1000000000),
   141  	}
   142  
   143  	m.shares.Store(token, share)
   144  
   145  	return share, nil
   146  }
   147  
   148  func (m *manager) GetPublicShare(ctx context.Context, u *user.User, ref *link.PublicShareReference, sign bool) (share *link.PublicShare, err error) {
   149  	// TODO(refs) return an error if the share is expired.
   150  
   151  	// Attempt to fetch public share by token
   152  	if ref.GetToken() != "" {
   153  		share, err = m.GetPublicShareByToken(ctx, ref.GetToken(), &link.PublicShareAuthentication{}, sign)
   154  		if err != nil {
   155  			return nil, errors.New("no shares found by token")
   156  		}
   157  	}
   158  
   159  	// Attempt to fetch public share by Id
   160  	if ref.GetId() != nil {
   161  		share, err = m.getPublicShareByTokenID(ctx, ref.GetId())
   162  		if err != nil {
   163  			return nil, errors.New("no shares found by id")
   164  		}
   165  	}
   166  
   167  	return
   168  }
   169  
   170  func (m *manager) ListPublicShares(ctx context.Context, u *user.User, filters []*link.ListPublicSharesRequest_Filter, sign bool) ([]*link.PublicShare, error) {
   171  	// TODO(refs) filter out expired shares
   172  	shares := []*link.PublicShare{}
   173  	m.shares.Range(func(k, v interface{}) bool {
   174  		s := v.(*link.PublicShare)
   175  		if len(filters) == 0 {
   176  			shares = append(shares, s)
   177  		} else {
   178  			for _, f := range filters {
   179  				if f.Type == link.ListPublicSharesRequest_Filter_TYPE_RESOURCE_ID {
   180  					if utils.ResourceIDEqual(s.ResourceId, f.GetResourceId()) {
   181  						shares = append(shares, s)
   182  					}
   183  				}
   184  			}
   185  		}
   186  		return true
   187  	})
   188  
   189  	return shares, nil
   190  }
   191  
   192  func (m *manager) RevokePublicShare(ctx context.Context, u *user.User, ref *link.PublicShareReference) error {
   193  	// check whether the reference exists
   194  	switch {
   195  	case ref.GetId() != nil && ref.GetId().OpaqueId != "":
   196  		s, err := m.getPublicShareByTokenID(ctx, ref.GetId())
   197  		if err != nil {
   198  			return errors.New("reference does not exist")
   199  		}
   200  		m.shares.Delete(s.Token)
   201  	case ref.GetToken() != "":
   202  		if _, err := m.GetPublicShareByToken(ctx, ref.GetToken(), &link.PublicShareAuthentication{}, false); err != nil {
   203  			return errors.New("reference does not exist")
   204  		}
   205  		m.shares.Delete(ref.GetToken())
   206  	default:
   207  		return errors.New("reference does not exist")
   208  	}
   209  	return nil
   210  }
   211  
   212  func (m *manager) GetPublicShareByToken(ctx context.Context, token string, auth *link.PublicShareAuthentication, sign bool) (*link.PublicShare, error) {
   213  	if ps, ok := m.shares.Load(token); ok {
   214  		return ps.(*link.PublicShare), nil
   215  	}
   216  	return nil, errtypes.NotFound("invalid token")
   217  }
   218  
   219  func randString(n int) string {
   220  	var l = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
   221  	b := make([]rune, n)
   222  	for i := range b {
   223  		b[i] = l[rand.Intn(len(l))]
   224  	}
   225  	return string(b)
   226  }
   227  
   228  func (m *manager) getPublicShareByTokenID(ctx context.Context, targetID *link.PublicShareId) (*link.PublicShare, error) {
   229  	var found *link.PublicShare
   230  	m.shares.Range(func(k, v interface{}) bool {
   231  		id := v.(*link.PublicShare).GetId()
   232  		if targetID.String() == id.String() {
   233  			found = v.(*link.PublicShare)
   234  		}
   235  		return true
   236  	})
   237  
   238  	if found != nil {
   239  		return found, nil
   240  	}
   241  	return nil, errors.New("resource not found")
   242  }