1package blobstore
2
3import (
4	"os"
5
6	boshcrypto "github.com/cloudfoundry/bosh-utils/crypto"
7	bosherr "github.com/cloudfoundry/bosh-utils/errors"
8	boshsys "github.com/cloudfoundry/bosh-utils/system"
9)
10
11type digestVerifiableBlobstore struct {
12	blobstore        Blobstore
13	fs               boshsys.FileSystem
14	createAlgorithms []boshcrypto.Algorithm
15}
16
17func NewDigestVerifiableBlobstore(blobstore Blobstore, fs boshsys.FileSystem, createAlgorithms []boshcrypto.Algorithm) DigestBlobstore {
18	return digestVerifiableBlobstore{
19		blobstore:        blobstore,
20		fs:               fs,
21		createAlgorithms: createAlgorithms,
22	}
23}
24
25func (b digestVerifiableBlobstore) Get(blobID string, digest boshcrypto.Digest) (string, error) {
26	fileName, err := b.blobstore.Get(blobID)
27	if err != nil {
28		return "", bosherr.WrapError(err, "Getting blob from inner blobstore")
29	}
30
31	file, err := b.fs.OpenFile(fileName, os.O_RDONLY, 0)
32	if err != nil {
33		return "", err
34	}
35
36	defer file.Close()
37
38	err = digest.Verify(file)
39	if err != nil {
40		return "", bosherr.WrapErrorf(err, "Checking downloaded blob '%s'", blobID)
41	}
42
43	return fileName, nil
44}
45
46func (b digestVerifiableBlobstore) Delete(blobId string) error {
47	return b.blobstore.Delete(blobId)
48}
49
50func (b digestVerifiableBlobstore) CleanUp(fileName string) error {
51	return b.blobstore.CleanUp(fileName)
52}
53
54func (b digestVerifiableBlobstore) Create(fileName string) (string, boshcrypto.MultipleDigest, error) {
55	multipleDigest, err := b.createDigest(fileName)
56	if err != nil {
57		return "", boshcrypto.MultipleDigest{}, err
58	}
59
60	blobID, err := b.blobstore.Create(fileName)
61	return blobID, multipleDigest, err
62}
63
64func (b digestVerifiableBlobstore) Validate() error {
65	return b.blobstore.Validate()
66}
67
68func (b digestVerifiableBlobstore) createDigest(fileName string) (boshcrypto.MultipleDigest, error) {
69	digests := []boshcrypto.Digest{}
70	for _, algo := range b.createAlgorithms {
71		digest, err := b.computeDigest(algo, fileName)
72		if err != nil {
73			return boshcrypto.MultipleDigest{}, err
74		}
75		digests = append(digests, digest)
76	}
77	return boshcrypto.MustNewMultipleDigest(digests...), nil
78}
79
80func (b digestVerifiableBlobstore) computeDigest(algo boshcrypto.Algorithm, fileName string) (boshcrypto.Digest, error) {
81	file, err := b.fs.OpenFile(fileName, os.O_RDONLY, 0)
82	if err != nil {
83		return boshcrypto.MultipleDigest{}, err
84	}
85
86	defer file.Close()
87
88	return algo.CreateDigest(file)
89}
90