Files

73 lines
1.8 KiB
Go

package cipher
import (
"bytes"
"context"
"sync"
"testing"
"github.com/google/uuid"
"github.com/warmbly/warmbly/internal/infrastructure/encryptedkeys"
)
// raceStore reports no DEK on the first read and then holds the one a concurrent caller stored.
type raceStore struct {
mu sync.Mutex
reads int
blob string
puts []string
}
func (s *raceStore) Put(_ context.Context, _ uuid.UUID, b string) error {
s.mu.Lock()
defer s.mu.Unlock()
s.puts = append(s.puts, b)
if s.blob != "" {
return encryptedkeys.ErrAlreadyExists
}
s.blob = b
return nil
}
func (s *raceStore) Get(_ context.Context, _ uuid.UUID) (string, error) {
s.mu.Lock()
defer s.mu.Unlock()
s.reads++
if s.reads == 1 {
return "", nil
}
return s.blob, nil
}
func (s *raceStore) Delete(context.Context, uuid.UUID) error { return nil }
func (s *raceStore) Name() string { return "race" }
type fakeKMS struct{ keys map[string][]byte }
func (k *fakeKMS) GenerateDataKey(context.Context) ([]byte, string, error) {
return bytes.Repeat([]byte{2}, 32), "loser-blob", nil
}
func (k *fakeKMS) GetDecryptedKey(_ context.Context, b string) ([]byte, error) {
return k.keys[b], nil
}
func (k *fakeKMS) Name() string { return "fake" }
func TestCipherAdoptsDEKStoredByConcurrentCreator(t *testing.T) {
winner := bytes.Repeat([]byte{1}, 32)
store := &raceStore{blob: "winner-blob"}
svc := &cipherService{encryptedKeys: store, kms: &fakeKMS{keys: map[string][]byte{"winner-blob": winner}}}
c, err := svc.Cipher(context.Background(), uuid.New())
if err != nil {
t.Fatalf("Cipher: %v", err)
}
if !bytes.Equal(c.plainDEK, winner) {
t.Fatal("cipher did not adopt the stored DEK")
}
if store.blob != "winner-blob" {
t.Fatalf("stored DEK was replaced: %q", store.blob)
}
}