github.com/decred/politeia@v1.4.0/politeiad/backendv2/tstorebe/tstore/extradata.go (about)

     1  // Copyright (c) 2020-2021 The Decred developers
     2  // Use of this source code is governed by an ISC
     3  // license that can be found in the LICENSE file.
     4  
     5  package tstore
     6  
     7  import (
     8  	"encoding/json"
     9  
    10  	backend "github.com/decred/politeia/politeiad/backendv2"
    11  	"github.com/google/uuid"
    12  )
    13  
    14  const (
    15  	// keyPrefixEncrypted is prefixed onto key-value store keys if the
    16  	// data is encrypted. We do this so that when a record is made
    17  	// public we can save the plain text record content blobs using the
    18  	// same keys, but without the prefix. Using a new key for the plain
    19  	// text blobs would not work since we cannot append a new leaf onto
    20  	// the tlog without getting a duplicate leaf error.
    21  	keyPrefixEncrypted = "e_"
    22  )
    23  
    24  // extraData is the data that is stored in the log leaf ExtraData field. It is
    25  // saved as a JSON encoded byte slice. The JSON keys have been abbreviated to
    26  // minimize the size of a trillian log leaf.
    27  type extraData struct {
    28  	// Key contains the key-value store key. If this blob is part of an
    29  	// unvetted record the key will need to be prefixed with the
    30  	// keyPrefixEncrypted in order to retrieve the blob from the kv
    31  	// store. Use the extraData.storeKey() method to retrieve the key.
    32  	// Do NOT reference this key directly.
    33  	Key string `json:"k"`
    34  
    35  	// Desc contains the blob entry data descriptor.
    36  	Desc string `json:"d"`
    37  
    38  	// State indicates the record state of the blob that this leaf
    39  	// corresponds to. Unvetted blobs encrypted prior to being saved
    40  	// to the store. When retrieving unvetted blobs from the kv store
    41  	// the keyPrefixEncrypted prefix must be added to the Key field.
    42  	// State will not be populated for anchor records.
    43  	State backend.StateT `json:"s,omitempty"`
    44  }
    45  
    46  // storeKey returns the kv store key for the blob. If the blob is part of an
    47  // unvetted record it will be saved as an encrypted blob in the kv store and
    48  // the key is prefixed with keyPrefixEncrypted.
    49  func (e *extraData) storeKey() string {
    50  	if e.State == backend.StateUnvetted {
    51  		return keyPrefixEncrypted + e.Key
    52  	}
    53  	return e.Key
    54  }
    55  
    56  // storeKeyNoPrefix returns the kv store key without any encryption prefix,
    57  // even if the leaf corresponds to a unvetted blob.
    58  func (e *extraData) storeKeyNoPrefix() string {
    59  	return e.Key
    60  }
    61  
    62  // extraDataEncode encodes prepares an extraData using the provided arguments
    63  // then returns the JSON encoded byte slice.
    64  func extraDataEncode(key, desc string, state backend.StateT) ([]byte, error) {
    65  	// The encryption prefix is stripped from the key if one exists.
    66  	ed := extraData{
    67  		Key:   storeKeyCleaned(key),
    68  		Desc:  desc,
    69  		State: state,
    70  	}
    71  	b, err := json.Marshal(ed)
    72  	if err != nil {
    73  		return nil, err
    74  	}
    75  	return b, nil
    76  }
    77  
    78  // extraDataDecode decodes a JSON byte slice into a extraData.
    79  func extraDataDecode(b []byte) (*extraData, error) {
    80  	var ed extraData
    81  	err := json.Unmarshal(b, &ed)
    82  	if err != nil {
    83  		return nil, err
    84  	}
    85  	return &ed, nil
    86  }
    87  
    88  // storeKeyNew returns a new key for the key-value store. If the data is
    89  // encrypted the key is prefixed.
    90  func storeKeyNew(encrypt bool) string {
    91  	k := uuid.New().String()
    92  	if encrypt {
    93  		k = keyPrefixEncrypted + k
    94  	}
    95  	return k
    96  }
    97  
    98  // storeKeyCleaned strips the key-value store key of the encryption prefix if
    99  // one is present.
   100  func storeKeyCleaned(key string) string {
   101  	// A uuid string is 36 bytes. Return the last 36 bytes of the
   102  	// string. This will strip the prefix if it exists.
   103  	return key[len(key)-36:]
   104  }