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  }