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 }