github.com/hoffie/larasync@v0.0.0-20151025221940-0384d2bddcef/repository/nibStore.go (about) 1 package repository 2 3 import ( 4 "bytes" 5 "errors" 6 "io" 7 "io/ioutil" 8 9 "github.com/hoffie/larasync/helpers/crypto" 10 "github.com/hoffie/larasync/repository/content" 11 "github.com/hoffie/larasync/repository/nib" 12 ) 13 14 // NIBStore handles the interaction with NIBs in a specific 15 // repository. 16 type NIBStore struct { 17 storage content.Storage 18 keys *KeyStore 19 transactionManager *TransactionManager 20 } 21 22 // newNibStore generates the NIBStore with the passed backend, repository, 23 // and transactionManager. 24 func newNIBStore(storage content.Storage, 25 keys *KeyStore, 26 transactionManager *TransactionManager, 27 ) *NIBStore { 28 return &NIBStore{ 29 storage: storage, 30 keys: keys, 31 transactionManager: transactionManager, 32 } 33 } 34 35 // Get returns the NIB of the given id. 36 func (s *NIBStore) Get(id string) (*nib.NIB, error) { 37 pubKey, err := s.keys.SigningPublicKey() 38 if err != nil { 39 return nil, err 40 } 41 42 data, err := s.GetBytes(id) 43 if err != nil { 44 return nil, err 45 } 46 47 buffer := bytes.NewReader(data) 48 signatureReader, err := crypto.NewVerifyingReader( 49 pubKey, 50 buffer, 51 ) 52 if err != nil { 53 return nil, err 54 } 55 56 n := nib.NIB{} 57 _, err = n.ReadFrom(signatureReader) 58 if err != nil { 59 return nil, err 60 } 61 62 if !signatureReader.VerifyAfterRead() { 63 return nil, ErrSignatureVerification 64 } 65 66 return &n, nil 67 } 68 69 // GetBytes returns the Byte representation of the 70 // given NIB ID. 71 func (s *NIBStore) GetBytes(id string) ([]byte, error) { 72 reader, err := s.getReader(id) 73 if err != nil { 74 return []byte{}, err 75 } 76 defer reader.Close() 77 return ioutil.ReadAll(reader) 78 } 79 80 // GetReader returns the Reader which stores the bytes 81 // of the given NIB ID. 82 func (s *NIBStore) getReader(id string) (io.ReadCloser, error) { 83 return s.storage.Get(id) 84 } 85 86 func (s *NIBStore) getFromTransactions(transactions []*Transaction) <-chan *nib.NIB { 87 nibChannel := make(chan *nib.NIB, 100) 88 89 go func() { 90 errorOccured := false 91 for nibID := range nibUUIDsFromTransactions(transactions) { 92 nib, err := s.Get(nibID) 93 if err != nil { 94 errorOccured = true 95 } 96 if !errorOccured { 97 nibChannel <- nib 98 } 99 } 100 close(nibChannel) 101 }() 102 103 return nibChannel 104 } 105 106 func (s *NIBStore) getByteRepresentationsFromTransactions(transactions []*Transaction) <-chan []byte { 107 nibChannel := make(chan []byte, 100) 108 go func() { 109 for nibID := range nibUUIDsFromTransactions(transactions) { 110 data, err := s.GetBytes(nibID) 111 if err != nil { 112 break 113 } 114 nibChannel <- data 115 } 116 close(nibChannel) 117 }() 118 return nibChannel 119 } 120 121 // GetAll returns all NIBs which have been commited to the store. 122 func (s *NIBStore) GetAll() (<-chan *nib.NIB, error) { 123 transactions, err := s.transactionManager.All() 124 if err != nil { 125 return nil, err 126 } 127 128 return s.getFromTransactions(transactions), nil 129 } 130 131 // GetAllBytes returns all signed NIB byte representations of the NIBs 132 // in the repository. 133 func (s *NIBStore) GetAllBytes() (<-chan []byte, error) { 134 transactions, err := s.transactionManager.All() 135 if err != nil { 136 return nil, err 137 } 138 139 return s.getByteRepresentationsFromTransactions(transactions), nil 140 } 141 142 // GetFrom returns all NIBs added added after the given transaction id. 143 func (s *NIBStore) GetFrom(transactionID int64) (<-chan *nib.NIB, error) { 144 transactions, err := s.transactionManager.From(transactionID) 145 if err != nil { 146 return nil, err 147 } 148 149 return s.getFromTransactions(transactions), nil 150 } 151 152 // GetBytesFrom returns all signed byte representations for all NIBs 153 // changed since the given transactionID were added. 154 func (s *NIBStore) GetBytesFrom(transactionID int64) (<-chan []byte, error) { 155 transactions, err := s.transactionManager.From(transactionID) 156 if err != nil { 157 return nil, err 158 } 159 160 return s.getByteRepresentationsFromTransactions(transactions), nil 161 } 162 163 // Add adds the given NIB to the store. 164 func (s *NIBStore) Add(nib *nib.NIB) error { 165 if nib.ID == "" { 166 return errors.New("empty nib ID") 167 } 168 169 buf := &bytes.Buffer{} 170 _, err := nib.WriteTo(buf) 171 if err != nil { 172 return err 173 } 174 175 return s.writeBytes(nib.ID, buf.Bytes()) 176 } 177 178 // writeBytes signs and adds the bytes for the given NIB ID. 179 func (s *NIBStore) writeBytes(id string, data []byte) error { 180 key, err := s.keys.SigningPrivateKey() 181 182 if err != nil { 183 return err 184 } 185 186 buf := &bytes.Buffer{} 187 188 sw := crypto.NewSigningWriter(key, buf) 189 _, err = sw.Write(data) 190 if err != nil { 191 return err 192 } 193 err = sw.Finalize() 194 if err != nil { 195 return err 196 } 197 198 return s.AddContent(id, buf) 199 } 200 201 // Creates a transaction with the given ID as NIB and Transaction id. 202 func (s *NIBStore) createTransaction(id string) *Transaction { 203 return &Transaction{ 204 NIBIDs: []string{id}, 205 } 206 } 207 208 // AddContent adds the byte data of a NIB with the passed ID in the 209 // storage backend. 210 func (s *NIBStore) AddContent(id string, reader io.Reader) error { 211 transaction := s.createTransaction(id) 212 213 err := s.storage.Set(id, reader) 214 if err != nil { 215 return err 216 } 217 return s.transactionManager.Add(transaction) 218 } 219 220 // Exists returns if there is a NIB with 221 // the given ID in the store. 222 func (s *NIBStore) Exists(id string) bool { 223 return s.storage.Exists(id) 224 } 225 226 // VerifyAndParseBytes verifies the correctness of the given 227 // data in the reader and returns the parsed nib. 228 func (s *NIBStore) VerifyAndParseBytes(data []byte) (*nib.NIB, error) { 229 pubKey, err := s.keys.SigningPublicKey() 230 if err != nil { 231 return nil, err 232 } 233 234 signatureReader, err := crypto.NewVerifyingReader( 235 pubKey, 236 bytes.NewReader(data), 237 ) 238 if err != nil { 239 return nil, err 240 } 241 242 // reading into a temporary buffer first requires memory, 243 // but this way we avoid parsing NIBs before actually verifying 244 // their signature; do not change this without further 245 // consideration. 246 buf, err := ioutil.ReadAll(signatureReader) 247 if err != nil { 248 return nil, err 249 } 250 251 if !signatureReader.VerifyAfterRead() { 252 return nil, ErrSignatureVerification 253 } 254 255 n := &nib.NIB{} 256 _, err = n.ReadFrom(bytes.NewReader(buf)) 257 if err != nil { 258 return nil, ErrUnMarshalling 259 } 260 261 return n, nil 262 }