func getRole(ctx context.Context, store storage.MetaStore, gun, role, checksum string) (*time.Time, []byte, error) { var ( lastModified *time.Time out []byte err error ) if checksum == "" { // the timestamp and snapshot might be server signed so are // handled specially switch role { case data.CanonicalTimestampRole, data.CanonicalSnapshotRole: return getMaybeServerSigned(ctx, store, gun, role) } lastModified, out, err = store.GetCurrent(gun, role) } else { lastModified, out, err = store.GetChecksum(gun, role, checksum) } if err != nil { if _, ok := err.(storage.ErrNotFound); ok { return nil, nil, errors.ErrMetadataNotFound.WithDetail(err) } return nil, nil, errors.ErrUnknown.WithDetail(err) } if out == nil { return nil, nil, errors.ErrMetadataNotFound.WithDetail(nil) } return lastModified, out, nil }
// getMaybeServerSigned writes the current snapshot or timestamp (based on the // role passed) to the provided writer or returns an error. In retrieving // the timestamp and snapshot, based on the keys held by the server, a new one // might be generated and signed due to expiry of the previous one or updates // to other roles. func getMaybeServerSigned(ctx context.Context, store storage.MetaStore, gun, role string) (*time.Time, []byte, error) { cryptoServiceVal := ctx.Value(notary.CtxKeyCryptoSvc) cryptoService, ok := cryptoServiceVal.(signed.CryptoService) if !ok { return nil, nil, errors.ErrNoCryptoService.WithDetail(nil) } var ( lastModified *time.Time out []byte err error ) if role != data.CanonicalTimestampRole && role != data.CanonicalSnapshotRole { return nil, nil, fmt.Errorf("role %s cannot be server signed", role) } lastModified, out, err = timestamp.GetOrCreateTimestamp(gun, store, cryptoService) if err != nil { switch err.(type) { case *storage.ErrNoKey, storage.ErrNotFound: return nil, nil, errors.ErrMetadataNotFound.WithDetail(err) default: return nil, nil, errors.ErrUnknown.WithDetail(err) } } // If we wanted the snapshot, get it by checksum from the timestamp data if role == data.CanonicalSnapshotRole { ts := new(data.SignedTimestamp) if err := json.Unmarshal(out, ts); err != nil { return nil, nil, err } snapshotChecksums, err := ts.GetSnapshot() if err != nil || snapshotChecksums == nil { return nil, nil, fmt.Errorf("could not retrieve latest snapshot checksum") } if snapshotSHA256Bytes, ok := snapshotChecksums.Hashes[notary.SHA256]; ok { snapshotSHA256Hex := hex.EncodeToString(snapshotSHA256Bytes[:]) return store.GetChecksum(gun, role, snapshotSHA256Hex) } return nil, nil, fmt.Errorf("could not retrieve sha256 snapshot checksum") } return lastModified, out, nil }
// GetOrCreateSnapshot either returns the existing latest snapshot, or uses // whatever the most recent snapshot is to generate the next one, only updating // the expiry time and version. Note that this function does not write generated // snapshots to the underlying data store, and will either return the latest snapshot time // or nil as the time modified func GetOrCreateSnapshot(gun, checksum string, store storage.MetaStore, cryptoService signed.CryptoService) ( *time.Time, []byte, error) { lastModified, currentJSON, err := store.GetChecksum(gun, data.CanonicalSnapshotRole, checksum) if err != nil { return nil, nil, err } prev := new(data.SignedSnapshot) if err := json.Unmarshal(currentJSON, prev); err != nil { logrus.Error("Failed to unmarshal existing snapshot for GUN ", gun) return nil, nil, err } if !snapshotExpired(prev) { return lastModified, currentJSON, nil } builder := tuf.NewRepoBuilder(gun, cryptoService, trustpinning.TrustPinConfig{}) // load the current root to ensure we use the correct snapshot key. _, rootJSON, err := store.GetCurrent(gun, data.CanonicalRootRole) if err != nil { logrus.Debug("Previous snapshot, but no root for GUN ", gun) return nil, nil, err } if err := builder.Load(data.CanonicalRootRole, rootJSON, 1, false); err != nil { logrus.Debug("Could not load valid previous root for GUN ", gun) return nil, nil, err } meta, _, err := builder.GenerateSnapshot(prev) if err != nil { return nil, nil, err } return nil, meta, nil }