From 73b5fd52508c745d7d2751b6330eeeaa2be17386 Mon Sep 17 00:00:00 2001 From: kevin olson Date: Sun, 31 Mar 2024 21:31:07 -0500 Subject: [PATCH 1/5] =?UTF-8?q?=F0=9F=9A=A7=20web=20auth=20progress?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 7 +- go.sum | 14 ++ pkg/cmd/auth/auth.go | 5 +- pkg/cmd/auth/login/login.go | 27 ++-- pkg/cmd/auth/login/token/token.go | 40 ++++++ pkg/cmd/auth/login/web/web.go | 131 ++++++++++++++++++ pkg/cmd/auth/status/status.go | 2 +- .../auth/login/interact.go => login/login.go} | 29 +--- 8 files changed, 206 insertions(+), 49 deletions(-) create mode 100644 pkg/cmd/auth/login/token/token.go create mode 100644 pkg/cmd/auth/login/web/web.go rename pkg/{cmd/auth/login/interact.go => login/login.go} (76%) diff --git a/go.mod b/go.mod index 6c8a3b6..ad9a13e 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ module github.com/vulncheck-oss/cli go 1.21.5 -// replace github.com/vulncheck-oss/sdk => /Users/k/vc/oss/sdk +replace github.com/vulncheck-oss/sdk => /Users/k/vc/oss/sdk require ( github.com/MakeNowJust/heredoc/v2 v2.0.1 @@ -24,8 +24,11 @@ require ( github.com/catppuccin/go v0.2.0 // indirect github.com/charmbracelet/harmonica v0.2.0 // indirect github.com/containerd/console v1.0.4 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dlclark/regexp2 v1.11.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/gomarkdown/markdown v0.0.0-20210208175418-bda154fe17d8 // indirect + github.com/google/uuid v1.4.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect @@ -38,7 +41,9 @@ require ( github.com/muesli/cancelreader v0.2.2 // indirect github.com/muesli/reflow v0.3.0 // indirect github.com/muesli/termenv v0.15.2 // indirect + github.com/octoper/go-ray v0.1.5 // indirect github.com/pelletier/go-toml/v2 v2.2.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect diff --git a/go.sum b/go.sum index 436fddc..083fb98 100644 --- a/go.sum +++ b/go.sum @@ -12,6 +12,7 @@ github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= +github.com/bradleyjkemp/cupaloy/v2 v2.6.0/go.mod h1:bm7JXdkRd4BHJk9HpwqAI8BoAY1lps46Enkdqw6aRX0= github.com/catppuccin/go v0.2.0 h1:ktBeIrIP42b/8FGiScP9sgrWOss3lw0Z5SktRoithGA= github.com/catppuccin/go v0.2.0/go.mod h1:8IHJuMGaUUjQM82qBrGNBv7LFq6JI3NnQCF6MOlZjpc= github.com/charmbracelet/bubbles v0.18.0 h1:PYv1A036luoBGroX6VWjQIE9Syf2Wby2oOl/39KLfy0= @@ -39,8 +40,13 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/gomarkdown/markdown v0.0.0-20210208175418-bda154fe17d8 h1:nWU6p08f1VgIalT6iZyqXi4o5cZsz4X6qa87nusfcsc= +github.com/gomarkdown/markdown v0.0.0-20210208175418-bda154fe17d8/go.mod h1:aii0r/K0ZnHv7G0KF7xy1v0A7s2Ljrb5byB7MO5p6TU= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= +github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= @@ -72,8 +78,12 @@ github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo= github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8= +github.com/octoper/go-ray v0.1.5 h1:tTN+4HptuzSnw60E0wM71wegKsy8wYhnQ2THjMvXBGQ= +github.com/octoper/go-ray v0.1.5/go.mod h1:Y1I9cUEZ4oD94H0/M+xwHhvGVbFu1o/dW3fDrknELk8= github.com/pelletier/go-toml/v2 v2.2.0 h1:QLgLl2yMN7N+ruc31VynXs1vhMZa7CeHHejIeBAsoHo= github.com/pelletier/go-toml/v2 v2.2.0/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -101,9 +111,12 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= @@ -115,6 +128,7 @@ github.com/vulncheck-oss/sdk v1.2.5 h1:gJgUm+dojHTC9fUSl/doq9IGS5QqtH5BGCDgTkcIj github.com/vulncheck-oss/sdk v1.2.5/go.mod h1:ufLXRGtv47jpjt2B7FcwUXhexX7F4lj4LaXl3ZyNiKA= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +golang.org/dl v0.0.0-20190829154251-82a15e2f2ead/go.mod h1:IUMfjQLJQd4UTqG1Z90tenwKoCX93Gn3MAQJMOSBsDQ= golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 h1:aAcj0Da7eBAtrTp03QXWvm88pSyOt+UgdZw2BFZ+lEw= golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ= golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= diff --git a/pkg/cmd/auth/auth.go b/pkg/cmd/auth/auth.go index 640e946..42dfd13 100644 --- a/pkg/cmd/auth/auth.go +++ b/pkg/cmd/auth/auth.go @@ -2,7 +2,8 @@ package auth import ( "github.com/spf13/cobra" - "github.com/vulncheck-oss/cli/pkg/cmd/auth/login" + + cmdLogin "github.com/vulncheck-oss/cli/pkg/cmd/auth/login" "github.com/vulncheck-oss/cli/pkg/cmd/auth/logout" "github.com/vulncheck-oss/cli/pkg/cmd/auth/status" "github.com/vulncheck-oss/cli/pkg/i18n" @@ -18,7 +19,7 @@ func Command() *cobra.Command { session.DisableAuthCheck(cmd) - cmd.AddCommand(login.Command()) + cmd.AddCommand(cmdLogin.Command()) cmd.AddCommand(status.Command()) cmd.AddCommand(logout.Command()) diff --git a/pkg/cmd/auth/login/login.go b/pkg/cmd/auth/login/login.go index 5816282..981f326 100644 --- a/pkg/cmd/auth/login/login.go +++ b/pkg/cmd/auth/login/login.go @@ -2,8 +2,11 @@ package login import ( "github.com/spf13/cobra" + "github.com/vulncheck-oss/cli/pkg/cmd/auth/login/token" + "github.com/vulncheck-oss/cli/pkg/cmd/auth/login/web" "github.com/vulncheck-oss/cli/pkg/config" "github.com/vulncheck-oss/cli/pkg/i18n" + pkgLogin "github.com/vulncheck-oss/cli/pkg/login" "github.com/vulncheck-oss/cli/pkg/session" "github.com/vulncheck-oss/cli/pkg/ui" ) @@ -27,12 +30,12 @@ func Command() *cobra.Command { } if config.HasConfig() && config.HasToken() { - if err := existingToken(); err != nil { + if err := pkgLogin.ExistingToken(); err != nil { return err } } - choice, err := chooseAuthMethod() + choice, err := pkgLogin.ChooseAuthMethod() if err != nil { return err @@ -40,30 +43,16 @@ func Command() *cobra.Command { switch choice { case "token": - return cmdToken(cmd, args) + return token.CmdToken(cmd, args) case "web": - return ui.Error("Command currently under construction") + return web.CmdWeb(cmd, args) default: return ui.Error("Invalid choice") } }, } - token := &cobra.Command{ - Use: "token", - Short: i18n.C.AuthLoginToken, - RunE: cmdToken, - } - - web := &cobra.Command{ - Use: "web", - Short: i18n.C.AuthLoginWeb, - RunE: func(cmd *cobra.Command, args []string) error { - return ui.Error("web login is not yet implemented") - }, - } - - cmd.AddCommand(web, token) + cmd.AddCommand(web.Command(), token.Command()) session.DisableAuthCheck(cmd) return cmd diff --git a/pkg/cmd/auth/login/token/token.go b/pkg/cmd/auth/login/token/token.go new file mode 100644 index 0000000..322a886 --- /dev/null +++ b/pkg/cmd/auth/login/token/token.go @@ -0,0 +1,40 @@ +package token + +import ( + "github.com/charmbracelet/huh" + "github.com/spf13/cobra" + "github.com/vulncheck-oss/cli/pkg/config" + "github.com/vulncheck-oss/cli/pkg/i18n" + "github.com/vulncheck-oss/cli/pkg/login" + "github.com/vulncheck-oss/cli/pkg/ui" +) + +func Command() *cobra.Command { + return &cobra.Command{ + Use: "token", + Short: i18n.C.AuthLoginToken, + RunE: CmdToken, + } +} + +func CmdToken(cmd *cobra.Command, args []string) error { + + var token string + + input := huh. + NewInput(). + Title("Enter your authentication token"). + Password(true). + Placeholder("vulncheck_******************"). + Value(&token) + + if err := input.Run(); err != nil { + return ui.Error("Token verification failed: %v", err) + } + + if !config.ValidToken(token) { + return ui.Error("Invalid token specified") + } + + return login.SaveToken(token) +} diff --git a/pkg/cmd/auth/login/web/web.go b/pkg/cmd/auth/login/web/web.go new file mode 100644 index 0000000..c335d22 --- /dev/null +++ b/pkg/cmd/auth/login/web/web.go @@ -0,0 +1,131 @@ +package web + +import ( + "encoding/json" + "fmt" + "github.com/charmbracelet/huh/spinner" + "github.com/pkg/browser" + "github.com/spf13/cobra" + "github.com/vulncheck-oss/cli/pkg/config" + "github.com/vulncheck-oss/cli/pkg/environment" + "github.com/vulncheck-oss/cli/pkg/i18n" + "github.com/vulncheck-oss/cli/pkg/login" + "github.com/vulncheck-oss/cli/pkg/session" + "github.com/vulncheck-oss/cli/pkg/ui" + "os/exec" + "runtime" + "strings" + "time" +) + +/** +step 1. generate an inquiry. +step 2. prompt the user to visit the inquiry URL. +step 3. loop and sleep waiting for an inquiry response. +*/ + +type Inquiry struct { + Hash string + Token string + Name string + IP string + Agent string + Location string + Coordinate string + CreatedAt string `json:"created_at"` + UpdatedAt string `json:"updated_at"` +} + +type InquiryResponse struct { + Benchmark float64 `json:"_benchmark"` + Message string `json:"message"` + Data Inquiry `json:"data"` +} + +type InquiryPingResponse struct { + Benchmark float64 `json:"_benchmark"` + Data Inquiry `json:"data"` +} + +func Command() *cobra.Command { + return &cobra.Command{ + Use: "web", + Short: i18n.C.AuthLoginWeb, + RunE: CmdWeb, + } +} + +func CmdWeb(cmd *cobra.Command, args []string) error { + var responseJSON *InquiryResponse + response, err := session.Connect(config.Token()).Form("name", GetName()).Request("POST", "/inquiry") + if err != nil { + return err + } + defer response.Body.Close() + _ = json.NewDecoder(response.Body).Decode(&responseJSON) + + ui.Info("Attempting to launch vulncheck.com in your browser...") + if err := browser.OpenURL(fmt.Sprintf("%s/inquiry/%s", environment.Env.WEB, responseJSON.Data.Hash)); err != nil { + return err + } + + var errorResponse error + var pingResponse *InquiryPingResponse + + _ = spinner.New(). + Style(ui.Pantone). + Title(" Awaiting Verification...").Action(func() { + + ticker := time.NewTicker(2 * time.Second) + defer ticker.Stop() + + timeout := time.After(30 * time.Second) + + for { + select { + case <-ticker.C: + var responsePing *InquiryPingResponse + response, err := session.Connect(config.Token()).Request("GET", fmt.Sprintf("/inquiry/ping/%s", responseJSON.Data.Hash)) + if err != nil { + errorResponse = err + return + } + defer response.Body.Close() + _ = json.NewDecoder(response.Body).Decode(&responsePing) + if config.ValidToken(responsePing.Data.Token) { + pingResponse = responsePing + return + } + case <-timeout: + return + } + } + + }).Run() + + if errorResponse != nil { + return errorResponse + } + + if pingResponse != nil { + return login.SaveToken(pingResponse.Data.Token) + } + return nil +} + +// GetName returns the ComputerName and/or hostname of the machine +func GetName() string { + var out []byte + var err error + + if strings.HasPrefix(runtime.GOOS, "darwin") { + out, err = exec.Command("scutil", "--get", "ComputerName").Output() + } else { + out, err = exec.Command("hostname").Output() + } + if err != nil { + return "" + } + + return strings.TrimSpace(string(out)) +} diff --git a/pkg/cmd/auth/status/status.go b/pkg/cmd/auth/status/status.go index 49b0390..6029808 100644 --- a/pkg/cmd/auth/status/status.go +++ b/pkg/cmd/auth/status/status.go @@ -3,9 +3,9 @@ package status import ( "fmt" "github.com/spf13/cobra" - "github.com/vulncheck-oss/cli/pkg/cmd/auth/login" "github.com/vulncheck-oss/cli/pkg/config" "github.com/vulncheck-oss/cli/pkg/i18n" + "github.com/vulncheck-oss/cli/pkg/login" "github.com/vulncheck-oss/cli/pkg/session" ) diff --git a/pkg/cmd/auth/login/interact.go b/pkg/login/login.go similarity index 76% rename from pkg/cmd/auth/login/interact.go rename to pkg/login/login.go index ef3c1e9..42de6f9 100644 --- a/pkg/cmd/auth/login/interact.go +++ b/pkg/login/login.go @@ -4,14 +4,13 @@ import ( "fmt" "github.com/charmbracelet/huh" "github.com/charmbracelet/huh/spinner" - "github.com/spf13/cobra" "github.com/vulncheck-oss/cli/pkg/config" "github.com/vulncheck-oss/cli/pkg/session" "github.com/vulncheck-oss/cli/pkg/ui" "github.com/vulncheck-oss/sdk" ) -func chooseAuthMethod() (string, error) { +func ChooseAuthMethod() (string, error) { var choice string form := huh.NewForm( @@ -33,13 +32,13 @@ func chooseAuthMethod() (string, error) { return choice, nil } -func existingToken() error { +func ExistingToken() error { logoutChoice := true confirm := huh.NewForm(huh.NewGroup(huh.NewConfirm(). Title("You currently have a token saved. Do you want to invalidate it first?"). Affirmative("Yes"). Negative("No"). - Value(&logoutChoice))).WithTheme(huh.ThemeDracula()) + Value(&logoutChoice))).WithTheme(huh.ThemeCatppuccin()) confirm.Run() if logoutChoice { @@ -61,28 +60,6 @@ func existingToken() error { return nil } -func cmdToken(cmd *cobra.Command, args []string) error { - - var token string - - input := huh. - NewInput(). - Title("Enter your authentication token"). - Password(true). - Placeholder("vulncheck_******************"). - Value(&token) - - if err := input.Run(); err != nil { - return ui.Error("Token verification failed: %v", err) - } - - if !config.ValidToken(token) { - return ui.Error("Invalid token specified") - } - - return SaveToken(token) -} - func SaveToken(token string) error { var res *sdk.UserResponse From 1522007c4b4590ab074e03a54f644f82ee7e11b1 Mon Sep 17 00:00:00 2001 From: kevin olson Date: Wed, 3 Apr 2024 14:09:14 -0500 Subject: [PATCH 2/5] =?UTF-8?q?=E2=9C=A8=20more=20json,=20examples,=20and?= =?UTF-8?q?=20i18n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/cmd/backup/backup.go | 19 ++++++++++++++++++- pkg/cmd/cpe/cpe.go | 25 ++++++++++++++++++++++--- pkg/cmd/purl/purl.go | 24 +++++++++++++++++++++--- pkg/i18n/en_US.go | 4 +++- pkg/i18n/i18n.go | 2 ++ pkg/ui/ui.go | 11 +++++++++++ 6 files changed, 77 insertions(+), 8 deletions(-) diff --git a/pkg/cmd/backup/backup.go b/pkg/cmd/backup/backup.go index 4398e2b..9ce12c5 100644 --- a/pkg/cmd/backup/backup.go +++ b/pkg/cmd/backup/backup.go @@ -12,6 +12,10 @@ import ( "time" ) +type UrlOptions struct { + Json bool +} + func Command() *cobra.Command { cmd := &cobra.Command{ @@ -19,6 +23,10 @@ func Command() *cobra.Command { Short: i18n.C.BackupShort, } + opts := &UrlOptions{ + Json: false, + } + cmdUrl := &cobra.Command{ Use: "url ", Short: i18n.C.BackupUrlShort, @@ -30,10 +38,19 @@ func Command() *cobra.Command { if err != nil { return err } - ui.Json(response.GetData()[0]) + if opts.Json { + ui.Json(response.GetData()[0]) + return nil + } + + ui.Stat("Filename", response.GetData()[0].Filename) + ui.Stat("SHA256", response.GetData()[0].Sha256) + ui.Stat("Date Added", response.GetData()[0].DateAdded) + ui.Stat("URL", response.GetData()[0].URL) return nil }, } + cmdUrl.Flags().BoolVarP(&opts.Json, "json", "j", false, "Output as JSON") cmdDownload := &cobra.Command{ Use: "download ", diff --git a/pkg/cmd/cpe/cpe.go b/pkg/cmd/cpe/cpe.go index 353e5e2..07a9304 100644 --- a/pkg/cmd/cpe/cpe.go +++ b/pkg/cmd/cpe/cpe.go @@ -9,10 +9,20 @@ import ( "github.com/vulncheck-oss/cli/pkg/ui" ) +type Options struct { + Json bool +} + func Command() *cobra.Command { - return &cobra.Command{ - Use: "cpe ", - Short: i18n.C.CpeShort, + + opts := &Options{ + Json: false, + } + + cmd := &cobra.Command{ + Use: "cpe ", + Short: i18n.C.CpeShort, + Example: fmt.Sprintf(i18n.C.CpeExample, "cpe:2.3:a:sap:businessobjects_business_intelligence_platform:4.2:-:*"), RunE: func(cmd *cobra.Command, args []string) error { if len(args) != 1 { return ui.Error(i18n.C.ErrorCpeSchemeRequired) @@ -21,6 +31,11 @@ func Command() *cobra.Command { if err != nil { return err } + + if opts.Json { + ui.Json(response.GetData()) + return nil + } cves := response.GetData() if err := ui.CpeMeta(response.CpeMeta()); err != nil { return err @@ -34,4 +49,8 @@ func Command() *cobra.Command { return nil }, } + + cmd.Flags().BoolVarP(&opts.Json, "json", "j", false, "Output as JSON") + + return cmd } diff --git a/pkg/cmd/purl/purl.go b/pkg/cmd/purl/purl.go index 23d4757..64b23e8 100644 --- a/pkg/cmd/purl/purl.go +++ b/pkg/cmd/purl/purl.go @@ -9,10 +9,19 @@ import ( "github.com/vulncheck-oss/cli/pkg/ui" ) +type Options struct { + Json bool +} + func Command() *cobra.Command { - return &cobra.Command{ - Use: "purl ", - Short: i18n.C.PurlShort, + opts := &Options{ + Json: false, + } + + cmd := &cobra.Command{ + Use: "purl ", + Short: i18n.C.PurlShort, + Example: fmt.Sprintf(i18n.C.PurlExample, "pkg:hackage/aeson@0.3.2.8"), RunE: func(cmd *cobra.Command, args []string) error { if len(args) != 1 { return ui.Error(i18n.C.ErrorPurlSchemeRequired) @@ -21,6 +30,11 @@ func Command() *cobra.Command { if err != nil { return err } + + if opts.Json { + ui.Json(response.GetData()) + return nil + } cves := response.Cves() if err := ui.PurlMeta(response.PurlMeta()); err != nil { return err @@ -34,4 +48,8 @@ func Command() *cobra.Command { return nil }, } + + cmd.Flags().BoolVarP(&opts.Json, "json", "j", false, "Output as JSON") + + return cmd } diff --git a/pkg/i18n/en_US.go b/pkg/i18n/en_US.go index 479c0d4..3e11d3c 100644 --- a/pkg/i18n/en_US.go +++ b/pkg/i18n/en_US.go @@ -65,10 +65,12 @@ var En = Copy{ BackupDownloadComplete: "Backup downloaded successfully", CpeShort: "Look up a specified cpe for any related CVEs", + CpeExample: "vc cpe \"%s\"", CpeNoCves: "No CVEs were found for cpe %s", CpeCvesFound: "%d CVEs were found for cpe %s", - PurlShort: "Look up a specified PURL for any CVES or vulnerabilities", + PurlShort: "Look up a specified PURL for any CVES or vulnerabilities", + PurlExample: "vc purl \"%s\"", PurlNoCves: "No CVEs were found for purl %s", PurlCvesFound: "%d CVEs were found for purl %s", diff --git a/pkg/i18n/i18n.go b/pkg/i18n/i18n.go index 93d98b1..47a4b60 100644 --- a/pkg/i18n/i18n.go +++ b/pkg/i18n/i18n.go @@ -44,10 +44,12 @@ type Copy struct { BackupDownloadComplete string CpeShort string + CpeExample string CpeNoCves string CpeCvesFound string PurlShort string + PurlExample string PurlNoCves string PurlCvesFound string diff --git a/pkg/ui/ui.go b/pkg/ui/ui.go index 2482d18..accd89a 100644 --- a/pkg/ui/ui.go +++ b/pkg/ui/ui.go @@ -7,9 +7,11 @@ import ( ) var format = "%s %s\n" +var statFormat = "%s %s: %s\n" var Pantone = lipgloss.NewStyle().Foreground(lipgloss.Color("#6667ab")) var White = lipgloss.NewStyle().Foreground(lipgloss.Color("#ffffff")) +var Gray = lipgloss.NewStyle().Foreground(lipgloss.Color("#dddddd")) var Emerald = lipgloss.NewStyle().Foreground(lipgloss.Color("#34d399")) var Red = lipgloss.NewStyle().Foreground(lipgloss.Color("#ff0000")) @@ -29,6 +31,15 @@ func Info(str string) { ) } +func Stat(label string, value string) { + fmt.Printf( + statFormat, + Pantone.Render("i"), + Gray.Render(label), + White.Render(value), + ) +} + func Danger(str string) error { return fmt.Errorf( format, From 202d9f36514e45940c5effd46f6b5c6938bc179b Mon Sep 17 00:00:00 2001 From: kevin olson Date: Wed, 3 Apr 2024 16:06:54 -0500 Subject: [PATCH 3/5] =?UTF-8?q?=F0=9F=94=92=200600=20for=20config=20perms?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/config/config.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/config/config.go b/pkg/config/config.go index 2e5f9a7..51ab296 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -52,6 +52,7 @@ func saveConfig(config *Config) error { } viper.AddConfigPath(dir) viper.SetConfigName("vc") + viper.SetConfigPermissions(0600) viper.SetConfigType("yaml") viper.Set("Token", config.Token) return viper.WriteConfigAs(fmt.Sprintf("%s/vc.yaml", dir)) From 65343a8eec739230c8496a8052f18a7f7909da49 Mon Sep 17 00:00:00 2001 From: kevin olson Date: Wed, 3 Apr 2024 16:13:02 -0500 Subject: [PATCH 4/5] :lint: lint cleanup --- Makefile | 3 +++ pkg/cmd/backup/backup.go | 4 ++++ pkg/cmd/root/root.go | 9 --------- pkg/cmd/root/root_test.go | 4 +--- pkg/config/config.go | 6 +----- pkg/i18n/i18n.go | 2 -- pkg/login/login.go | 4 +++- pkg/ui/table.go | 4 +++- 8 files changed, 15 insertions(+), 21 deletions(-) diff --git a/Makefile b/Makefile index 8862c69..103f36b 100644 --- a/Makefile +++ b/Makefile @@ -27,3 +27,6 @@ test: update: go get -u ./... && go mod tidy + +lint: + @golangci-lint run diff --git a/pkg/cmd/backup/backup.go b/pkg/cmd/backup/backup.go index 9ce12c5..53b2fc8 100644 --- a/pkg/cmd/backup/backup.go +++ b/pkg/cmd/backup/backup.go @@ -66,6 +66,10 @@ func Command() *cobra.Command { file, err := extractFile(response.GetData()[0].URL) + if err != nil { + return err + } + date := parseDate(response.GetData()[0].DateAdded) ui.Info(fmt.Sprintf(i18n.C.BackupDownloadInfo, args[0], date)) diff --git a/pkg/cmd/root/root.go b/pkg/cmd/root/root.go index 2bf11b6..b62aca8 100644 --- a/pkg/cmd/root/root.go +++ b/pkg/cmd/root/root.go @@ -27,15 +27,6 @@ type AuthError struct { err error } -type exitCode int - -const ( - exitOK exitCode = 0 - exitError exitCode = 1 - exitCancel exitCode = 2 - exitAuthError exitCode = 3 -) - func (ae *AuthError) Error() string { return ae.err.Error() } diff --git a/pkg/cmd/root/root_test.go b/pkg/cmd/root/root_test.go index 35e7fef..2ddcc22 100644 --- a/pkg/cmd/root/root_test.go +++ b/pkg/cmd/root/root_test.go @@ -106,9 +106,7 @@ func setRootActual(args ...string) (*bytes.Buffer, *cobra.Command) { root.SetOut(actual) root.SetErr(actual) var argsArray []string - for _, arg := range args { - argsArray = append(argsArray, arg) - } + argsArray = append(argsArray, args...) root.SetArgs(argsArray) return actual, root } diff --git a/pkg/config/config.go b/pkg/config/config.go index 51ab296..0f59206 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -73,12 +73,8 @@ func configDir() (string, error) { } func HasConfig() bool { - _, err := loadConfig() - if err != nil { - return false - } - return true + return err == nil } func Token() string { diff --git a/pkg/i18n/i18n.go b/pkg/i18n/i18n.go index 47a4b60..12eb316 100644 --- a/pkg/i18n/i18n.go +++ b/pkg/i18n/i18n.go @@ -1,7 +1,5 @@ package i18n -var lang = "en_US" - type Copy struct { AboutInfo string InteractiveOnly string diff --git a/pkg/login/login.go b/pkg/login/login.go index 42de6f9..5e0ad77 100644 --- a/pkg/login/login.go +++ b/pkg/login/login.go @@ -39,7 +39,9 @@ func ExistingToken() error { Affirmative("Yes"). Negative("No"). Value(&logoutChoice))).WithTheme(huh.ThemeCatppuccin()) - confirm.Run() + if err := confirm.Run(); err != nil { + return err + } if logoutChoice { if _, err := session.InvalidateToken(config.Token()); err != nil { diff --git a/pkg/ui/table.go b/pkg/ui/table.go index 0627df3..af1f585 100644 --- a/pkg/ui/table.go +++ b/pkg/ui/table.go @@ -36,7 +36,9 @@ func (m tableModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case "q", "ctrl+c": return m, tea.Quit case "enter": - m.action(m.table.SelectedRow()[0]) + if err := m.action(m.table.SelectedRow()[0]); err != nil { + return m, tea.Quit + } return m, tea.Quit /* return m, tea.Batch( From b493334033ee169b264d3ba650312828c62d7cd9 Mon Sep 17 00:00:00 2001 From: kevin olson Date: Wed, 3 Apr 2024 16:27:26 -0500 Subject: [PATCH 5/5] =?UTF-8?q?=F0=9F=9A=A7=20dep=20cleanup?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 10 +++------- go.sum | 16 ++-------------- 2 files changed, 5 insertions(+), 21 deletions(-) diff --git a/go.mod b/go.mod index ad9a13e..03aba9f 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ module github.com/vulncheck-oss/cli go 1.21.5 -replace github.com/vulncheck-oss/sdk => /Users/k/vc/oss/sdk +// replace github.com/vulncheck-oss/sdk => /Users/k/vc/oss/sdk require ( github.com/MakeNowJust/heredoc/v2 v2.0.1 @@ -12,9 +12,10 @@ require ( github.com/charmbracelet/huh v0.3.0 github.com/charmbracelet/huh/spinner v0.0.0-20240328185852-590ecabc34b9 github.com/charmbracelet/lipgloss v0.10.0 + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c github.com/spf13/cobra v1.8.0 github.com/spf13/viper v1.18.2 - github.com/vulncheck-oss/sdk v1.2.5 + github.com/vulncheck-oss/sdk v1.2.6 golang.org/x/term v0.18.0 ) @@ -24,11 +25,8 @@ require ( github.com/catppuccin/go v0.2.0 // indirect github.com/charmbracelet/harmonica v0.2.0 // indirect github.com/containerd/console v1.0.4 // indirect - github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dlclark/regexp2 v1.11.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect - github.com/gomarkdown/markdown v0.0.0-20210208175418-bda154fe17d8 // indirect - github.com/google/uuid v1.4.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect @@ -41,9 +39,7 @@ require ( github.com/muesli/cancelreader v0.2.2 // indirect github.com/muesli/reflow v0.3.0 // indirect github.com/muesli/termenv v0.15.2 // indirect - github.com/octoper/go-ray v0.1.5 // indirect github.com/pelletier/go-toml/v2 v2.2.0 // indirect - github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect diff --git a/go.sum b/go.sum index 083fb98..e42a879 100644 --- a/go.sum +++ b/go.sum @@ -12,7 +12,6 @@ github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= -github.com/bradleyjkemp/cupaloy/v2 v2.6.0/go.mod h1:bm7JXdkRd4BHJk9HpwqAI8BoAY1lps46Enkdqw6aRX0= github.com/catppuccin/go v0.2.0 h1:ktBeIrIP42b/8FGiScP9sgrWOss3lw0Z5SktRoithGA= github.com/catppuccin/go v0.2.0/go.mod h1:8IHJuMGaUUjQM82qBrGNBv7LFq6JI3NnQCF6MOlZjpc= github.com/charmbracelet/bubbles v0.18.0 h1:PYv1A036luoBGroX6VWjQIE9Syf2Wby2oOl/39KLfy0= @@ -40,13 +39,8 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= -github.com/gomarkdown/markdown v0.0.0-20210208175418-bda154fe17d8 h1:nWU6p08f1VgIalT6iZyqXi4o5cZsz4X6qa87nusfcsc= -github.com/gomarkdown/markdown v0.0.0-20210208175418-bda154fe17d8/go.mod h1:aii0r/K0ZnHv7G0KF7xy1v0A7s2Ljrb5byB7MO5p6TU= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= -github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= @@ -78,8 +72,6 @@ github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo= github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8= -github.com/octoper/go-ray v0.1.5 h1:tTN+4HptuzSnw60E0wM71wegKsy8wYhnQ2THjMvXBGQ= -github.com/octoper/go-ray v0.1.5/go.mod h1:Y1I9cUEZ4oD94H0/M+xwHhvGVbFu1o/dW3fDrknELk8= github.com/pelletier/go-toml/v2 v2.2.0 h1:QLgLl2yMN7N+ruc31VynXs1vhMZa7CeHHejIeBAsoHo= github.com/pelletier/go-toml/v2 v2.2.0/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= @@ -111,12 +103,9 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= @@ -124,11 +113,10 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= -github.com/vulncheck-oss/sdk v1.2.5 h1:gJgUm+dojHTC9fUSl/doq9IGS5QqtH5BGCDgTkcIjU8= -github.com/vulncheck-oss/sdk v1.2.5/go.mod h1:ufLXRGtv47jpjt2B7FcwUXhexX7F4lj4LaXl3ZyNiKA= +github.com/vulncheck-oss/sdk v1.2.6 h1:5KVRqHs7nnQ9mJNeEUEDwZq7E2V9oGrre0XGBlwG/Ao= +github.com/vulncheck-oss/sdk v1.2.6/go.mod h1:ufLXRGtv47jpjt2B7FcwUXhexX7F4lj4LaXl3ZyNiKA= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -golang.org/dl v0.0.0-20190829154251-82a15e2f2ead/go.mod h1:IUMfjQLJQd4UTqG1Z90tenwKoCX93Gn3MAQJMOSBsDQ= golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 h1:aAcj0Da7eBAtrTp03QXWvm88pSyOt+UgdZw2BFZ+lEw= golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ= golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=