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)