// GetOrCreateTimestamp returns the current timestamp for the gun. This may mean // a new timestamp is generated either because none exists, or because the current // one has expired. Once generated, the timestamp is saved in the store. // Additionally, if we had to generate a new snapshot for this timestamp, // it is also saved in the store func GetOrCreateTimestamp(gun string, store storage.MetaStore, cryptoService signed.CryptoService) ( *time.Time, []byte, error) { updates := []storage.MetaUpdate{} lastModified, timestampJSON, err := store.GetCurrent(gun, data.CanonicalTimestampRole) if err != nil { logrus.Debug("error retrieving timestamp: ", err.Error()) return nil, nil, err } prev := &data.SignedTimestamp{} if err := json.Unmarshal(timestampJSON, prev); err != nil { logrus.Error("Failed to unmarshal existing timestamp") return nil, nil, err } snapChecksums, err := prev.GetSnapshot() if err != nil || snapChecksums == nil { return nil, nil, err } snapshotSha256Bytes, ok := snapChecksums.Hashes[notary.SHA256] if !ok { return nil, nil, data.ErrMissingMeta{Role: data.CanonicalSnapshotRole} } snapshotSha256Hex := hex.EncodeToString(snapshotSha256Bytes[:]) snapshotTime, snapshot, err := snapshot.GetOrCreateSnapshot(gun, snapshotSha256Hex, store, cryptoService) if err != nil { logrus.Debug("Previous timestamp, but no valid snapshot for GUN ", gun) return nil, nil, err } snapshotRole := &data.SignedSnapshot{} if err := json.Unmarshal(snapshot, snapshotRole); err != nil { logrus.Error("Failed to unmarshal retrieved snapshot") return nil, nil, err } // If the snapshot was generated, we should write it with the timestamp if snapshotTime == nil { updates = append(updates, storage.MetaUpdate{Role: data.CanonicalSnapshotRole, Version: snapshotRole.Signed.Version, Data: snapshot}) } if !timestampExpired(prev) && !snapshotExpired(prev, snapshot) { return lastModified, timestampJSON, nil } tsUpdate, err := createTimestamp(gun, prev, snapshot, store, cryptoService) if err != nil { logrus.Error("Failed to create a new timestamp") return nil, nil, err } updates = append(updates, *tsUpdate) c := time.Now() // Write the timestamp, and potentially snapshot if err = store.UpdateMany(gun, updates); err != nil { return nil, nil, err } return &c, tsUpdate.Data, 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, w io.Writer, store storage.MetaStore, gun, role string) error { cryptoServiceVal := ctx.Value("cryptoService") cryptoService, ok := cryptoServiceVal.(signed.CryptoService) if !ok { return errors.ErrNoCryptoService.WithDetail(nil) } var ( out []byte err error ) switch role { case data.CanonicalSnapshotRole: out, err = snapshot.GetOrCreateSnapshot(gun, store, cryptoService) case data.CanonicalTimestampRole: out, err = timestamp.GetOrCreateTimestamp(gun, store, cryptoService) } if err != nil { switch err.(type) { case *storage.ErrNoKey, storage.ErrNotFound: return errors.ErrMetadataNotFound.WithDetail(err) default: return errors.ErrUnknown.WithDetail(err) } } w.Write(out) return nil }
// GetOrCreateTimestamp returns the current timestamp for the gun. This may mean // a new timestamp is generated either because none exists, or because the current // one has expired. Once generated, the timestamp is saved in the store. func GetOrCreateTimestamp(gun string, store storage.MetaStore, cryptoService signed.CryptoService) ([]byte, error) { snapshot, err := snapshot.GetOrCreateSnapshot(gun, store, cryptoService) if err != nil { return nil, err } d, err := store.GetCurrent(gun, "timestamp") if err != nil { if _, ok := err.(storage.ErrNotFound); !ok { logrus.Error("error retrieving timestamp: ", err.Error()) return nil, err } logrus.Debug("No timestamp found, will proceed to create first timestamp") } ts := &data.SignedTimestamp{} if d != nil { err := json.Unmarshal(d, ts) if err != nil { logrus.Error("Failed to unmarshal existing timestamp") return nil, err } if !timestampExpired(ts) && !snapshotExpired(ts, snapshot) { return d, nil } } sgnd, version, err := CreateTimestamp(gun, ts, snapshot, store, cryptoService) if err != nil { logrus.Error("Failed to create a new timestamp") return nil, err } out, err := json.Marshal(sgnd) if err != nil { logrus.Error("Failed to marshal new timestamp") return nil, err } err = store.UpdateCurrent(gun, storage.MetaUpdate{Role: "timestamp", Version: version, Data: out}) if err != nil { return nil, err } return out, nil }
// getTimestampHandler returns a timestamp.json given a GUN func getSnapshot(ctx context.Context, w http.ResponseWriter, logger ctxu.Logger, store storage.MetaStore, gun string) error { cryptoServiceVal := ctx.Value("cryptoService") cryptoService, ok := cryptoServiceVal.(signed.CryptoService) if !ok { return errors.ErrNoCryptoService.WithDetail(nil) } out, err := snapshot.GetOrCreateSnapshot(gun, store, cryptoService) if err != nil { switch err.(type) { case *storage.ErrNoKey, storage.ErrNotFound: logger.Error("404 GET snapshot") return errors.ErrMetadataNotFound.WithDetail(nil) default: logger.Error("500 GET snapshot") return errors.ErrUnknown.WithDetail(err) } } logger.Debug("200 GET snapshot") w.Write(out) return nil }