forked from notaryproject/notary
-
Notifications
You must be signed in to change notification settings - Fork 0
/
tuf_store.go
129 lines (117 loc) · 4.59 KB
/
tuf_store.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package storage
import (
"encoding/hex"
"fmt"
"time"
"github.com/docker/go/canonical/json"
"github.com/theupdateframework/notary"
"github.com/theupdateframework/notary/storage"
"github.com/theupdateframework/notary/tuf/data"
)
// TUFMetaStorage wraps a MetaStore in order to walk the TUF tree for GetCurrent in a consistent manner,
// by always starting from a current timestamp and then looking up other data by hash
type TUFMetaStorage struct {
MetaStore
// cached metadata by checksum
cachedMeta map[string]*storedMeta
}
// NewTUFMetaStorage instantiates a TUFMetaStorage instance
func NewTUFMetaStorage(m MetaStore) *TUFMetaStorage {
return &TUFMetaStorage{
MetaStore: m,
cachedMeta: make(map[string]*storedMeta),
}
}
type storedMeta struct {
data []byte
createupdate *time.Time
}
// GetCurrent gets a specific TUF record, by walking from the current Timestamp to other metadata by checksum
func (tms TUFMetaStorage) GetCurrent(gun data.GUN, tufRole data.RoleName) (*time.Time, []byte, error) {
timestampTime, timestampJSON, err := tms.MetaStore.GetCurrent(gun, data.CanonicalTimestampRole)
if err != nil {
return nil, nil, err
}
// If we wanted data for the timestamp role, we're done here
if tufRole == data.CanonicalTimestampRole {
return timestampTime, timestampJSON, nil
}
// If we want to lookup another role, walk to it via current timestamp --> snapshot by checksum --> desired role
timestampMeta := &data.SignedTimestamp{}
if err := json.Unmarshal(timestampJSON, timestampMeta); err != nil {
return nil, nil, fmt.Errorf("could not parse current timestamp")
}
snapshotChecksums, err := timestampMeta.GetSnapshot()
if err != nil || snapshotChecksums == nil {
return nil, nil, fmt.Errorf("could not retrieve latest snapshot checksum")
}
snapshotSHA256Bytes, ok := snapshotChecksums.Hashes[notary.SHA256]
if !ok {
return nil, nil, fmt.Errorf("could not retrieve latest snapshot sha256")
}
snapshotSHA256Hex := hex.EncodeToString(snapshotSHA256Bytes[:])
// Check the cache if we have our snapshot data
var snapshotTime *time.Time
var snapshotJSON []byte
if cachedSnapshotData, ok := tms.cachedMeta[snapshotSHA256Hex]; ok {
snapshotTime = cachedSnapshotData.createupdate
snapshotJSON = cachedSnapshotData.data
} else {
// Get the snapshot from the underlying store by checksum if it isn't cached yet
snapshotTime, snapshotJSON, err = tms.GetChecksum(gun, data.CanonicalSnapshotRole, snapshotSHA256Hex)
if err != nil {
return nil, nil, err
}
// cache for subsequent lookups
tms.cachedMeta[snapshotSHA256Hex] = &storedMeta{data: snapshotJSON, createupdate: snapshotTime}
}
// If we wanted data for the snapshot role, we're done here
if tufRole == data.CanonicalSnapshotRole {
return snapshotTime, snapshotJSON, nil
}
// If it's a different role, we should have the checksum in snapshot metadata, and we can use it to GetChecksum()
snapshotMeta := &data.SignedSnapshot{}
if err := json.Unmarshal(snapshotJSON, snapshotMeta); err != nil {
return nil, nil, fmt.Errorf("could not parse current snapshot")
}
roleMeta, err := snapshotMeta.GetMeta(tufRole)
if err != nil {
return nil, nil, err
}
roleSHA256Bytes, ok := roleMeta.Hashes[notary.SHA256]
if !ok {
return nil, nil, fmt.Errorf("could not retrieve latest %s sha256", tufRole)
}
roleSHA256Hex := hex.EncodeToString(roleSHA256Bytes[:])
// check if we can retrieve this data from cache
if cachedRoleData, ok := tms.cachedMeta[roleSHA256Hex]; ok {
return cachedRoleData.createupdate, cachedRoleData.data, nil
}
roleTime, roleJSON, err := tms.MetaStore.GetChecksum(gun, tufRole, roleSHA256Hex)
if err != nil {
return nil, nil, err
}
// cache for subsequent lookups
tms.cachedMeta[roleSHA256Hex] = &storedMeta{data: roleJSON, createupdate: roleTime}
return roleTime, roleJSON, nil
}
// GetChecksum gets a specific TUF record by checksum, also checking the internal cache
func (tms TUFMetaStorage) GetChecksum(gun data.GUN, tufRole data.RoleName, checksum string) (*time.Time, []byte, error) {
if cachedRoleData, ok := tms.cachedMeta[checksum]; ok {
return cachedRoleData.createupdate, cachedRoleData.data, nil
}
roleTime, roleJSON, err := tms.MetaStore.GetChecksum(gun, tufRole, checksum)
if err != nil {
return nil, nil, err
}
// cache for subsequent lookups
tms.cachedMeta[checksum] = &storedMeta{data: roleJSON, createupdate: roleTime}
return roleTime, roleJSON, nil
}
// Bootstrap the store with tables if possible
func (tms TUFMetaStorage) Bootstrap() error {
if s, ok := tms.MetaStore.(storage.Bootstrapper); ok {
return s.Bootstrap()
}
return fmt.Errorf("store does not support bootstrapping")
}