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 }