diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index ac62b2b6a5..d14f554491 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -47,7 +47,7 @@ }, { "ImportPath": "github.com/endophage/gotuf", - "Rev": "429e2920d26a5703bb9cbdeaf893d3b79d6b2085" + "Rev": "36214c0646639c7f94b3151df15dc417a67a9406" }, { "ImportPath": "github.com/go-sql-driver/mysql", diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/tuf.go b/Godeps/_workspace/src/github.com/endophage/gotuf/tuf.go index 860e405ae7..efca615620 100644 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/tuf.go +++ b/Godeps/_workspace/src/github.com/endophage/gotuf/tuf.go @@ -387,6 +387,19 @@ func (tr *TufRepo) AddTargets(role string, targets data.Files) (data.Files, erro return nil, nil } +func (tr *TufRepo) RemoveTargets(role string, targets ...string) error { + t, ok := tr.Targets[role] + if !ok { + return errors.ErrInvalidRole{role} + } + + for _, path := range targets { + delete(t.Signed.Targets, path) + } + t.Dirty = true + return nil +} + func (tr *TufRepo) UpdateSnapshot(role string, s *data.Signed) error { jsonData, err := json.Marshal(s) if err != nil { diff --git a/cmd/notary/main.go b/cmd/notary/main.go index ff87f83a0b..9924cfe99c 100644 --- a/cmd/notary/main.go +++ b/cmd/notary/main.go @@ -24,9 +24,11 @@ const privDir string = configPath + "private/" const tufDir string = configPath + "tuf/" var caStore trustmanager.X509Store +var rawOutput bool func init() { logrus.SetLevel(logrus.ErrorLevel) + logrus.SetOutput(os.Stderr) // Retrieve current user to get home directory usr, err := user.Current() if err != nil { @@ -93,11 +95,13 @@ func main() { NotaryCmd.AddCommand(cmdKeys) NotaryCmd.AddCommand(cmdTufInit) NotaryCmd.AddCommand(cmdTufList) + cmdTufList.Flags().BoolVarP(&rawOutput, "raw", "", false, "Instructs notary list to output a non-pretty printed version of the targets list. Useful if you need to parse the list.") NotaryCmd.AddCommand(cmdTufAdd) NotaryCmd.AddCommand(cmdTufRemove) NotaryCmd.AddCommand(cmdTufPublish) cmdTufPublish.Flags().StringVarP(&remoteTrustServer, "remote", "r", "", "Remote trust server location") NotaryCmd.AddCommand(cmdTufLookup) + cmdTufLookup.Flags().BoolVarP(&rawOutput, "raw", "", false, "Instructs notary lookup to output a non-pretty printed version of the targets list. Useful if you need to parse the list.") cmdTufLookup.Flags().StringVarP(&remoteTrustServer, "remote", "r", "", "Remote trust server location") NotaryCmd.Execute() diff --git a/cmd/notary/tuf.go b/cmd/notary/tuf.go index 6823c3e8a1..01f573cbf2 100644 --- a/cmd/notary/tuf.go +++ b/cmd/notary/tuf.go @@ -9,6 +9,7 @@ import ( "path" "path/filepath" + "github.com/Sirupsen/logrus" "github.com/endophage/gotuf" "github.com/endophage/gotuf/client" "github.com/endophage/gotuf/data" @@ -76,64 +77,20 @@ func tufAdd(cmd *cobra.Command, args []string) { signer := signed.NewSigner(NewCryptoService(gun)) repo := tuf.NewTufRepo(kdb, signer) - filestore, err := store.NewFilesystemStore( - path.Join(viper.GetString("tufDir"), gun), - "metadata", - "json", - "targets", - ) - b, err := ioutil.ReadFile(targetPath) if err != nil { fatalf(err.Error()) } - rootJSON, err := filestore.GetMeta("root", 0) - if err != nil { - fatalf(err.Error()) - } - root := &data.Signed{} - err = json.Unmarshal(rootJSON, root) - if err != nil { - fatalf(err.Error()) - } - repo.SetRoot(root) - targetsJSON, err := filestore.GetMeta("targets", 0) - if err != nil { - fatalf(err.Error()) - } - targets := &data.Signed{} - err = json.Unmarshal(targetsJSON, targets) - if err != nil { - fatalf(err.Error()) - } - repo.SetTargets("targets", targets) - snapshotJSON, err := filestore.GetMeta("snapshot", 0) - if err != nil { - fatalf(err.Error()) - } - snapshot := &data.Signed{} - err = json.Unmarshal(snapshotJSON, snapshot) - if err != nil { - fatalf(err.Error()) - } - repo.SetSnapshot(snapshot) - timestampJSON, err := filestore.GetMeta("timestamp", 0) - if err != nil { - fatalf(err.Error()) - } - timestamp := &data.Signed{} - err = json.Unmarshal(timestampJSON, timestamp) - if err != nil { - fatalf(err.Error()) - } - repo.SetTimestamp(timestamp) + filestore := bootstrapRepo(gun, repo) + fmt.Println("Generating metadata for target") meta, err := data.NewFileMeta(bytes.NewBuffer(b)) if err != nil { fatalf(err.Error()) } + fmt.Printf("Adding target \"%s\" with sha256 \"%s\" and size %s bytes.\n", targetName, meta.Hashes["sha256"], meta.Length) _, err = repo.AddTargets("targets", data.Files{targetName: meta}) if err != nil { fatalf(err.Error()) @@ -206,37 +163,24 @@ func tufList(cmd *cobra.Command, args []string) { "json", "", ) - rootJSON, err := remote.GetMeta("root", 5<<20) + c, err := bootstrapClient(remote, repo, kdb) if err != nil { - fmt.Println("Couldn't get initial root") - fatalf(err.Error()) + return } - root := &data.Signed{} - err = json.Unmarshal(rootJSON, root) - if err != nil { - fmt.Println("Couldn't parse initial root") - fatalf(err.Error()) - } - // TODO: Validate the root file against the key store - err = repo.SetRoot(root) - if err != nil { - fmt.Println("Error setting root") - fatalf(err.Error()) - } - - c := client.NewClient( - repo, - remote, - kdb, - ) - err = c.Update() if err != nil { - fmt.Println("Update failed") - fatalf(err.Error()) + logrus.Error("Error updating client: ", err.Error()) + return } - for name, meta := range repo.Targets["targets"].Signed.Targets { - fmt.Println(name, " ", meta.Hashes["sha256"], " ", meta.Length) + + if rawOutput { + for name, meta := range repo.Targets["targets"].Signed.Targets { + fmt.Println(name, " ", meta.Hashes["sha256"], " ", meta.Length) + } + } else { + for name, meta := range repo.Targets["targets"].Signed.Targets { + fmt.Println(name, " ", meta.Hashes["sha256"], " ", meta.Length) + } } } @@ -256,49 +200,35 @@ func tufLookup(cmd *cobra.Command, args []string) { "json", "", ) - rootJSON, err := remote.GetMeta("root", 5<<20) + c, err := bootstrapClient(remote, repo, kdb) if err != nil { - fmt.Println("Couldn't get initial root") - fatalf(err.Error()) + return } - root := &data.Signed{} - err = json.Unmarshal(rootJSON, root) - if err != nil { - fmt.Println("Couldn't parse initial root") - fatalf(err.Error()) - } - // TODO: Validate the root file against the key store - err = repo.SetRoot(root) - if err != nil { - fmt.Println("Error setting root") - fatalf(err.Error()) - } - - c := client.NewClient( - repo, - remote, - kdb, - ) - err = c.Update() if err != nil { - fmt.Println("Update failed") - fatalf(err.Error()) + logrus.Error("Error updating client: ", err.Error()) + return } meta := c.TargetMeta(targetName) if meta == nil { + logrus.Infof("Target %s not found in %s.", targetName, gun) return } - fmt.Println(targetName, fmt.Sprintf("sha256:%s", meta.Hashes["sha256"]), meta.Length) + if rawOutput { + fmt.Println(targetName, fmt.Sprintf("sha256:%s", meta.Hashes["sha256"]), meta.Length) + } else { + fmt.Println(targetName, fmt.Sprintf("sha256:%s", meta.Hashes["sha256"]), meta.Length) + } } func tufPublish(cmd *cobra.Command, args []string) { if len(args) < 1 { cmd.Usage() - fatalf("must specify a GUN") + fatalf("Must specify a GUN") } gun := args[0] + fmt.Println("Pushing changes to ", gun, ".") remote, err := store.NewHTTPStore( "https://vetinari:4443/v2/"+gun+"/_trust/tuf/", @@ -312,6 +242,9 @@ func tufPublish(cmd *cobra.Command, args []string) { "json", "targets", ) + if err != nil { + fatalf(err.Error()) + } root, err := filestore.GetMeta("root", 0) if err != nil { @@ -349,23 +282,38 @@ func tufPublish(cmd *cobra.Command, args []string) { } func tufRemove(cmd *cobra.Command, args []string) { - if len(args) < 1 { + if len(args) < 2 { cmd.Usage() - fatalf("must specify a GUN") + fatalf("must specify a GUN and target name") } + gun := args[0] + targetName := args[1] + kdb := keys.NewDB() + signer := signed.NewSigner(NewCryptoService(gun)) + repo := tuf.NewTufRepo(kdb, signer) + + fmt.Println("Removing target ", targetName, " from ", gun) + + filestore := bootstrapRepo(gun, repo) + + err := repo.RemoveTargets("targets", targetName) + if err != nil { + fatalf(err.Error()) + } + + saveRepo(repo, filestore) } func saveRepo(repo *tuf.TufRepo, filestore store.MetadataStore) error { + fmt.Println("Saving changes to TUF Repository.") signedRoot, err := repo.SignRoot(data.DefaultExpires("root")) if err != nil { return err } - fmt.Println("Marshalling root") rootJSON, _ := json.Marshal(signedRoot) filestore.SetMeta("root", rootJSON) for r, _ := range repo.Targets { - fmt.Println("Marshalling ", r) signedTargets, err := repo.SignTargets(r, data.DefaultExpires("targets")) if err != nil { return err @@ -380,7 +328,6 @@ func saveRepo(repo *tuf.TufRepo, filestore store.MetadataStore) error { if err != nil { return err } - fmt.Println("Marshalling snapshot") snapshotJSON, _ := json.Marshal(signedSnapshot) filestore.SetMeta("snapshot", snapshotJSON) @@ -388,8 +335,84 @@ func saveRepo(repo *tuf.TufRepo, filestore store.MetadataStore) error { if err != nil { return err } - fmt.Println("Marshalling timestamp") timestampJSON, _ := json.Marshal(signedTimestamp) filestore.SetMeta("timestamp", timestampJSON) return nil } + +func bootstrapClient(remote store.RemoteStore, repo *tuf.TufRepo, kdb *keys.KeyDB) (*client.Client, error) { + rootJSON, err := remote.GetMeta("root", 5<<20) + if err != nil { + return nil, err + } + root := &data.Signed{} + err = json.Unmarshal(rootJSON, root) + if err != nil { + return nil, err + } + // TODO: Validate the root file against the key store + err = repo.SetRoot(root) + if err != nil { + return nil, err + } + return client.NewClient( + repo, + remote, + kdb, + ), nil +} + +func bootstrapRepo(gun string, repo *tuf.TufRepo) store.MetadataStore { + filestore, err := store.NewFilesystemStore( + path.Join(viper.GetString("tufDir"), gun), + "metadata", + "json", + "targets", + ) + if err != nil { + fatalf(err.Error()) + } + + fmt.Println("Loading TUF Repository.") + rootJSON, err := filestore.GetMeta("root", 0) + if err != nil { + fatalf(err.Error()) + } + root := &data.Signed{} + err = json.Unmarshal(rootJSON, root) + if err != nil { + fatalf(err.Error()) + } + repo.SetRoot(root) + targetsJSON, err := filestore.GetMeta("targets", 0) + if err != nil { + fatalf(err.Error()) + } + targets := &data.Signed{} + err = json.Unmarshal(targetsJSON, targets) + if err != nil { + fatalf(err.Error()) + } + repo.SetTargets("targets", targets) + snapshotJSON, err := filestore.GetMeta("snapshot", 0) + if err != nil { + fatalf(err.Error()) + } + snapshot := &data.Signed{} + err = json.Unmarshal(snapshotJSON, snapshot) + if err != nil { + fatalf(err.Error()) + } + repo.SetSnapshot(snapshot) + timestampJSON, err := filestore.GetMeta("timestamp", 0) + if err != nil { + fatalf(err.Error()) + } + timestamp := &data.Signed{} + err = json.Unmarshal(timestampJSON, timestamp) + if err != nil { + fatalf(err.Error()) + } + repo.SetTimestamp(timestamp) + return filestore +} diff --git a/server/handlers/default.go b/server/handlers/default.go index 5a922f9310..5d7bdade31 100644 --- a/server/handlers/default.go +++ b/server/handlers/default.go @@ -53,7 +53,7 @@ func UpdateHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) } } vars := mux.Vars(r) - qdn := vars["imageName"] + gun := vars["imageName"] tufRole := vars["tufRole"] input, err := ioutil.ReadAll(r.Body) if err != nil { @@ -73,7 +73,7 @@ func UpdateHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) } } version := meta.Signed.Version - err = store.UpdateCurrent(qdn, tufRole, version, input) + err = store.UpdateCurrent(gun, tufRole, version, input) if err != nil { return &errors.HTTPError{ HTTPStatus: http.StatusInternalServerError, @@ -96,11 +96,12 @@ func GetHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) *er } } vars := mux.Vars(r) - qdn := vars["imageName"] + gun := vars["imageName"] tufRole := vars["tufRole"] - data, err := store.GetCurrent(qdn, tufRole) + data, err := store.GetCurrent(gun, tufRole) logrus.Debug("JSON: ", string(data)) if err != nil { + logrus.Errorf("[Vetinari] 500 GET repository: %s, role: %s", gun, tufRole) return &errors.HTTPError{ HTTPStatus: http.StatusInternalServerError, Code: 9999, @@ -108,6 +109,7 @@ func GetHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) *er } } if data == nil { + logrus.Errorf("[Vetinari] 404 GET repository: %s, role: %s", gun, tufRole) return &errors.HTTPError{ HTTPStatus: http.StatusNotFound, Code: 9999,