github.com/ethersphere/bee/v2@v2.2.0/pkg/accesscontrol/mock/controller.go (about) 1 // Copyright 2020 The Swarm Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package mock provides a mock implementation for the 6 // access control functionalities. 7 // 8 //nolint:ireturn 9 package mock 10 11 import ( 12 "context" 13 "crypto/ecdsa" 14 "encoding/hex" 15 "fmt" 16 "time" 17 18 "github.com/ethersphere/bee/v2/pkg/accesscontrol" 19 "github.com/ethersphere/bee/v2/pkg/crypto" 20 "github.com/ethersphere/bee/v2/pkg/encryption" 21 "github.com/ethersphere/bee/v2/pkg/file" 22 "github.com/ethersphere/bee/v2/pkg/file/loadsave" 23 "github.com/ethersphere/bee/v2/pkg/file/pipeline" 24 "github.com/ethersphere/bee/v2/pkg/file/pipeline/builder" 25 "github.com/ethersphere/bee/v2/pkg/file/redundancy" 26 "github.com/ethersphere/bee/v2/pkg/storage" 27 mockstorer "github.com/ethersphere/bee/v2/pkg/storer/mock" 28 "github.com/ethersphere/bee/v2/pkg/swarm" 29 "golang.org/x/crypto/sha3" 30 ) 31 32 type mockController struct { 33 historyMap map[string]accesscontrol.History 34 refMap map[string]swarm.Address 35 acceptAll bool 36 publisher string 37 encrypter encryption.Interface 38 ls file.LoadSaver 39 } 40 41 type optionFunc func(*mockController) 42 43 // Option is an option passed to a mock accesscontrol Controller. 44 type Option interface { 45 apply(*mockController) 46 } 47 48 func (f optionFunc) apply(r *mockController) { f(r) } 49 50 // New creates a new mock accesscontrol Controller. 51 func New(o ...Option) accesscontrol.Controller { 52 storer := mockstorer.New() 53 m := &mockController{ 54 historyMap: make(map[string]accesscontrol.History), 55 refMap: make(map[string]swarm.Address), 56 publisher: "", 57 encrypter: encryption.New(encryption.Key("b6ee086390c280eeb9824c331a4427596f0c8510d5564bc1b6168d0059a46e2b"), 0, 0, sha3.NewLegacyKeccak256), 58 ls: loadsave.New(storer.ChunkStore(), storer.Cache(), requestPipelineFactory(context.Background(), storer.Cache(), false, redundancy.NONE)), 59 } 60 for _, v := range o { 61 v.apply(m) 62 } 63 64 return m 65 } 66 67 // WithAcceptAll sets the mock to return fixed references on every call to DownloadHandler. 68 func WithAcceptAll() Option { 69 return optionFunc(func(m *mockController) { m.acceptAll = true }) 70 } 71 72 // WithHistory sets the mock to use the given history reference. 73 func WithHistory(h accesscontrol.History, ref string) Option { 74 return optionFunc(func(m *mockController) { 75 m.historyMap = map[string]accesscontrol.History{ref: h} 76 }) 77 } 78 79 // WithPublisher sets the mock to use the given reference as the publisher address. 80 func WithPublisher(ref string) Option { 81 return optionFunc(func(m *mockController) { 82 m.publisher = ref 83 m.encrypter = encryption.New(encryption.Key(ref), 0, 0, sha3.NewLegacyKeccak256) 84 }) 85 } 86 87 func (m *mockController) DownloadHandler(ctx context.Context, ls file.LoadSaver, encryptedRef swarm.Address, publisher *ecdsa.PublicKey, historyRootHash swarm.Address, timestamp int64) (swarm.Address, error) { 88 if m.acceptAll { 89 return swarm.ParseHexAddress("36e6c1bbdfee6ac21485d5f970479fd1df458d36df9ef4e8179708ed46da557f") 90 } 91 92 publicKeyBytes := crypto.EncodeSecp256k1PublicKey(publisher) 93 p := hex.EncodeToString(publicKeyBytes) 94 if m.publisher != "" && m.publisher != p { 95 return swarm.ZeroAddress, accesscontrol.ErrInvalidPublicKey 96 } 97 98 h, exists := m.historyMap[historyRootHash.String()] 99 if !exists { 100 return swarm.ZeroAddress, accesscontrol.ErrNotFound 101 } 102 entry, err := h.Lookup(ctx, timestamp) 103 if err != nil { 104 return swarm.ZeroAddress, err 105 } 106 kvsRef := entry.Reference() 107 if kvsRef.IsZero() { 108 return swarm.ZeroAddress, err 109 } 110 return m.refMap[encryptedRef.String()], nil 111 } 112 113 func (m *mockController) UploadHandler(ctx context.Context, ls file.LoadSaver, reference swarm.Address, publisher *ecdsa.PublicKey, historyRootHash swarm.Address) (swarm.Address, swarm.Address, swarm.Address, error) { 114 historyRef, _ := swarm.ParseHexAddress("67bdf80a9bbea8eca9c8480e43fdceb485d2d74d5708e45144b8c4adacd13d9c") 115 kvsRef, _ := swarm.ParseHexAddress("3339613565613837623134316665343461613630396333333237656364383934") 116 if m.acceptAll { 117 encryptedRef, _ := swarm.ParseHexAddress("fc4e9fe978991257b897d987bc4ff13058b66ef45a53189a0b4fe84bb3346396") 118 return kvsRef, historyRef, encryptedRef, nil 119 } 120 var ( 121 h accesscontrol.History 122 exists bool 123 ) 124 125 publicKeyBytes := crypto.EncodeSecp256k1PublicKey(publisher) 126 p := hex.EncodeToString(publicKeyBytes) 127 if m.publisher != "" && m.publisher != p { 128 return swarm.ZeroAddress, swarm.ZeroAddress, swarm.ZeroAddress, accesscontrol.ErrInvalidPublicKey 129 } 130 131 now := time.Now().Unix() 132 if !historyRootHash.IsZero() { 133 historyRef = historyRootHash 134 h, exists = m.historyMap[historyRef.String()] 135 if !exists { 136 return swarm.ZeroAddress, swarm.ZeroAddress, swarm.ZeroAddress, accesscontrol.ErrNotFound 137 } 138 entry, err := h.Lookup(ctx, now) 139 if err != nil { 140 return swarm.ZeroAddress, swarm.ZeroAddress, swarm.ZeroAddress, err 141 } 142 kvsRef := entry.Reference() 143 if kvsRef.IsZero() { 144 return swarm.ZeroAddress, swarm.ZeroAddress, swarm.ZeroAddress, fmt.Errorf("kvs not found") 145 } 146 } else { 147 h, _ = accesscontrol.NewHistory(m.ls) 148 _ = h.Add(ctx, kvsRef, &now, nil) 149 historyRef, _ = h.Store(ctx) 150 m.historyMap[historyRef.String()] = h 151 } 152 153 encryptedRef, _ := m.encrypter.Encrypt(reference.Bytes()) 154 m.refMap[(hex.EncodeToString(encryptedRef))] = reference 155 return kvsRef, historyRef, swarm.NewAddress(encryptedRef), nil 156 } 157 158 func (m *mockController) Close() error { 159 return nil 160 } 161 162 func (m *mockController) UpdateHandler(_ context.Context, ls file.LoadSaver, gls file.LoadSaver, encryptedglref swarm.Address, historyref swarm.Address, publisher *ecdsa.PublicKey, addList []*ecdsa.PublicKey, removeList []*ecdsa.PublicKey) (swarm.Address, swarm.Address, swarm.Address, swarm.Address, error) { 163 if historyref.Equal(swarm.EmptyAddress) || encryptedglref.Equal(swarm.EmptyAddress) { 164 return swarm.ZeroAddress, swarm.ZeroAddress, swarm.ZeroAddress, swarm.ZeroAddress, accesscontrol.ErrNotFound 165 } 166 historyRef, _ := swarm.ParseHexAddress("67bdf80a9bbea8eca9c8480e43fdceb485d2d74d5708e45144b8c4adacd13d9c") 167 glRef, _ := swarm.ParseHexAddress("3339613565613837623134316665343461613630396333333237656364383934") 168 eglRef, _ := swarm.ParseHexAddress("fc4e9fe978991257b897d987bc4ff13058b66ef45a53189a0b4fe84bb3346396") 169 actref, _ := swarm.ParseHexAddress("39a5ea87b141fe44aa609c3327ecd896c0e2122897f5f4bbacf74db1033c5559") 170 return glRef, eglRef, historyRef, actref, nil 171 } 172 173 func (m *mockController) Get(ctx context.Context, ls file.LoadSaver, publisher *ecdsa.PublicKey, encryptedglref swarm.Address) ([]*ecdsa.PublicKey, error) { 174 if m.publisher == "" { 175 return nil, fmt.Errorf("granteelist not found") 176 } 177 keys := []string{ 178 "a786dd84b61485de12146fd9c4c02d87e8fd95f0542765cb7fc3d2e428c0bcfa", 179 "b786dd84b61485de12146fd9c4c02d87e8fd95f0542765cb7fc3d2e428c0bcfb", 180 "c786dd84b61485de12146fd9c4c02d87e8fd95f0542765cb7fc3d2e428c0bcfc", 181 } 182 pubkeys := make([]*ecdsa.PublicKey, 0, len(keys)) 183 for i := range keys { 184 data, err := hex.DecodeString(keys[i]) 185 if err != nil { 186 panic(err) 187 } 188 189 privKey, err := crypto.DecodeSecp256k1PrivateKey(data) 190 pubKey := privKey.PublicKey 191 if err != nil { 192 panic(err) 193 } 194 pubkeys = append(pubkeys, &pubKey) 195 } 196 return pubkeys, nil 197 } 198 199 func requestPipelineFactory(ctx context.Context, s storage.Putter, encrypt bool, rLevel redundancy.Level) func() pipeline.Interface { 200 return func() pipeline.Interface { 201 return builder.NewPipelineBuilder(ctx, s, encrypt, rLevel) 202 } 203 } 204 205 var _ accesscontrol.Controller = (*mockController)(nil)