55 "crypto/aes"
66 "crypto/cipher"
77 "crypto/rand"
8+ "encoding/binary"
89 "errors"
910 "fmt"
1011 "io"
@@ -50,7 +51,8 @@ func NewOnDiskStore(path string, pass []byte, opt ...Option) (Store, error) {
5051 return store , nil
5152}
5253
53- const BlockSize = 64 * 4096
54+ const blockSize = 64 * 4096
55+ const storeVersion = uint32 (1 )
5456
5557func (c * onDiskStore ) Set (messageID imap.InternalMessageID , in io.Reader ) error {
5658 if err := os .MkdirAll (c .path , 0o700 ); err != nil {
@@ -76,6 +78,12 @@ func (c *onDiskStore) Set(messageID imap.InternalMessageID, in io.Reader) error
7678
7779 defer file .Close ()
7880
81+ if written , err := file .Write (storeHeaderBytes ); err != nil {
82+ return err
83+ } else if written != len (storeHeaderBytes ) {
84+ return fmt .Errorf ("failed to write store header to file" )
85+ }
86+
7987 reader , writer := io .Pipe ()
8088 defer writer .Close ()
8189
@@ -91,9 +99,9 @@ func (c *onDiskStore) Set(messageID imap.InternalMessageID, in io.Reader) error
9199 }()
92100
93101 encryptionOverhead := c .gcm .Overhead ()
94- encryptedBlockSized := getEncryptedBlockSize (c .gcm , BlockSize )
102+ encryptedBlockSized := getEncryptedBlockSize (c .gcm , blockSize )
95103
96- compressedBlock := make ([]byte , BlockSize )
104+ compressedBlock := make ([]byte , blockSize )
97105 encryptedBlock := make ([]byte , encryptedBlockSized )
98106
99107 // Write nonce to file.
@@ -103,8 +111,8 @@ func (c *onDiskStore) Set(messageID imap.InternalMessageID, in io.Reader) error
103111
104112 // Write encrypted blocks.
105113 for {
106- // Read at least BlockSize from the compressor.
107- bytesRead , err := io .ReadAtLeast (reader , compressedBlock , BlockSize )
114+ // Read at least blockSize from the compressor.
115+ bytesRead , err := io .ReadAtLeast (reader , compressedBlock , blockSize )
108116 if err != nil {
109117 if errors .Is (err , io .EOF ) {
110118 break
@@ -144,8 +152,17 @@ func (c *onDiskStore) Get(messageID imap.InternalMessageID) ([]byte, error) {
144152
145153 var fileSize int64
146154
155+ header := make ([]byte , len (storeHeaderBytes ))
156+ if _ , err := io .ReadFull (file , header ); err != nil {
157+ return nil , err
158+ }
159+
160+ if ! bytes .Equal (header , storeHeaderBytes ) {
161+ return nil , fmt .Errorf ("file is not a valid store file" )
162+ }
163+
147164 if stat , err := file .Stat (); err == nil {
148- fileSize = stat .Size ()
165+ fileSize = stat .Size () - int64 ( len ( storeHeaderBytes ))
149166 }
150167
151168 nonce := make ([]byte , c .gcm .NonceSize ())
@@ -158,13 +175,13 @@ func (c *onDiskStore) Get(messageID imap.InternalMessageID) ([]byte, error) {
158175 reader , writer := io .Pipe ()
159176
160177 encryptionOverhead := c .gcm .Overhead ()
161- encryptedBlockSize := getEncryptedBlockSize (c .gcm , BlockSize )
178+ encryptedBlockSize := getEncryptedBlockSize (c .gcm , blockSize )
162179
163180 go func () {
164181 defer writer .Close ()
165182
166183 readBuffer := make ([]byte , encryptedBlockSize )
167- decryptBuffer := make ([]byte , BlockSize )
184+ decryptBuffer := make ([]byte , blockSize )
168185 totalBytesRead := 0
169186
170187 for {
@@ -282,3 +299,15 @@ func (*OnDiskStoreBuilder) Delete(path, userID string) error {
282299func getEncryptedBlockSize (aead cipher.AEAD , blockSize int ) int {
283300 return blockSize + aead .Overhead ()
284301}
302+
303+ func makeGluonHeaderBytes () []byte {
304+ const StoreHeaderID = "GLUON-CACHE"
305+
306+ version := make ([]byte , 4 )
307+
308+ binary .LittleEndian .PutUint32 (version , storeVersion )
309+
310+ return append ([]byte (StoreHeaderID ), version ... )
311+ }
312+
313+ var storeHeaderBytes = makeGluonHeaderBytes ()
0 commit comments