github.com/ethersphere/bee/v2@v2.2.0/pkg/accesscontrol/grantee.go (about) 1 // Copyright 2024 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 accesscontrol 6 7 import ( 8 "context" 9 "crypto/ecdsa" 10 "crypto/elliptic" 11 "errors" 12 "fmt" 13 14 "github.com/btcsuite/btcd/btcec/v2" 15 "github.com/ethersphere/bee/v2/pkg/file" 16 "github.com/ethersphere/bee/v2/pkg/swarm" 17 ) 18 19 const ( 20 publicKeyLen = 65 21 ) 22 23 var ( 24 // ErrNothingToRemove indicates that the remove list is empty. 25 ErrNothingToRemove = errors.New("nothing to remove") 26 // ErrNoGranteeFound indicates that the grantee list is empty. 27 ErrNoGranteeFound = errors.New("no grantee found") 28 // ErrNothingToAdd indicates that the add list is empty. 29 ErrNothingToAdd = errors.New("nothing to add") 30 ) 31 32 // GranteeList manages a list of public keys. 33 type GranteeList interface { 34 // Add adds a list of public keys to the grantee list. It filters out duplicates. 35 Add(addList []*ecdsa.PublicKey) error 36 // Remove removes a list of public keys from the grantee list, if there is any. 37 Remove(removeList []*ecdsa.PublicKey) error 38 // Get simply returns the list of public keys. 39 Get() []*ecdsa.PublicKey 40 // Save saves the grantee list to the underlying storage and returns the reference. 41 Save(ctx context.Context) (swarm.Address, error) 42 } 43 44 // GranteeListStruct represents a list of grantee public keys. 45 type GranteeListStruct struct { 46 grantees []*ecdsa.PublicKey 47 loadSave file.LoadSaver 48 } 49 50 var _ GranteeList = (*GranteeListStruct)(nil) 51 52 // Get simply returns the list of public keys. 53 func (g *GranteeListStruct) Get() []*ecdsa.PublicKey { 54 return g.grantees 55 } 56 57 // Add adds a list of public keys to the grantee list. It filters out duplicates. 58 func (g *GranteeListStruct) Add(addList []*ecdsa.PublicKey) error { 59 if len(addList) == 0 { 60 return ErrNothingToAdd 61 } 62 filteredList := make([]*ecdsa.PublicKey, 0, len(addList)) 63 for _, addkey := range addList { 64 add := true 65 for _, granteekey := range g.grantees { 66 if granteekey.Equal(addkey) { 67 add = false 68 break 69 } 70 } 71 for _, filteredkey := range filteredList { 72 if filteredkey.Equal(addkey) { 73 add = false 74 break 75 } 76 } 77 if add { 78 filteredList = append(filteredList, addkey) 79 } 80 } 81 g.grantees = append(g.grantees, filteredList...) 82 83 return nil 84 } 85 86 // Save saves the grantee list to the underlying storage and returns the reference. 87 func (g *GranteeListStruct) Save(ctx context.Context) (swarm.Address, error) { 88 data := serialize(g.grantees) 89 refBytes, err := g.loadSave.Save(ctx, data) 90 if err != nil { 91 return swarm.ZeroAddress, fmt.Errorf("grantee save error: %w", err) 92 } 93 94 return swarm.NewAddress(refBytes), nil 95 } 96 97 // Remove removes a list of public keys from the grantee list, if there is any. 98 func (g *GranteeListStruct) Remove(keysToRemove []*ecdsa.PublicKey) error { 99 if len(keysToRemove) == 0 { 100 return ErrNothingToRemove 101 } 102 103 if len(g.grantees) == 0 { 104 return ErrNoGranteeFound 105 } 106 grantees := g.grantees 107 108 for _, remove := range keysToRemove { 109 for i := 0; i < len(grantees); i++ { 110 if grantees[i].Equal(remove) { 111 grantees[i] = grantees[len(grantees)-1] 112 grantees = grantees[:len(grantees)-1] 113 } 114 } 115 } 116 g.grantees = grantees 117 118 return nil 119 } 120 121 // NewGranteeList creates a new (and empty) grantee list. 122 func NewGranteeList(ls file.LoadSaver) *GranteeListStruct { 123 return &GranteeListStruct{ 124 grantees: []*ecdsa.PublicKey{}, 125 loadSave: ls, 126 } 127 } 128 129 // NewGranteeListReference loads an existing grantee list. 130 func NewGranteeListReference(ctx context.Context, ls file.LoadSaver, reference swarm.Address) (*GranteeListStruct, error) { 131 data, err := ls.Load(ctx, reference.Bytes()) 132 if err != nil { 133 return nil, fmt.Errorf("failed to load grantee list reference, %w", err) 134 } 135 grantees := deserialize(data) 136 137 return &GranteeListStruct{ 138 grantees: grantees, 139 loadSave: ls, 140 }, nil 141 } 142 143 func serialize(publicKeys []*ecdsa.PublicKey) []byte { 144 b := make([]byte, 0, len(publicKeys)*publicKeyLen) 145 for _, key := range publicKeys { 146 b = append(b, serializePublicKey(key)...) 147 } 148 return b 149 } 150 151 func serializePublicKey(pub *ecdsa.PublicKey) []byte { 152 return elliptic.Marshal(pub.Curve, pub.X, pub.Y) 153 } 154 155 func deserialize(data []byte) []*ecdsa.PublicKey { 156 if len(data) == 0 { 157 return []*ecdsa.PublicKey{} 158 } 159 160 p := make([]*ecdsa.PublicKey, 0, len(data)/publicKeyLen) 161 for i := 0; i < len(data); i += publicKeyLen { 162 pubKey := deserializeBytes(data[i : i+publicKeyLen]) 163 if pubKey == nil { 164 return []*ecdsa.PublicKey{} 165 } 166 p = append(p, pubKey) 167 } 168 return p 169 } 170 171 func deserializeBytes(data []byte) *ecdsa.PublicKey { 172 key, err := btcec.ParsePubKey(data) 173 if err != nil { 174 return nil 175 } 176 return key.ToECDSA() 177 }