mirror of
https://github.com/gopasspw/gopass.git
synced 2025-12-08 19:24:54 +00:00
* [bugfix] Bring back audit summary This PR brings back the audit summary view and displays only that by default. This restores the old behaviour before we refactored the audit implementation. The new view is still available with the new --full flag. Fixes #2816 Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org> * Fix tests. Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org> * Fix integration test Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org> --------- Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>
140 lines
3.4 KiB
Go
140 lines
3.4 KiB
Go
package action
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/gopasspw/gopass/internal/action/exit"
|
|
"github.com/gopasspw/gopass/internal/audit"
|
|
"github.com/gopasspw/gopass/internal/out"
|
|
"github.com/gopasspw/gopass/internal/tree"
|
|
"github.com/gopasspw/gopass/pkg/ctxutil"
|
|
"github.com/gopasspw/gopass/pkg/debug"
|
|
"github.com/gopasspw/gopass/pkg/fsutil"
|
|
"github.com/urfave/cli/v2"
|
|
)
|
|
|
|
// Audit validates passwords against common flaws.
|
|
func (s *Action) Audit(c *cli.Context) error {
|
|
ctx := ctxutil.WithGlobalFlags(c)
|
|
|
|
_ = s.rem.Reset("audit")
|
|
out.Print(ctx, "Auditing passwords for common flaws ...")
|
|
|
|
t, err := s.Store.Tree(ctx)
|
|
if err != nil {
|
|
return exit.Error(exit.List, err, "failed to get store tree: %s", err)
|
|
}
|
|
|
|
if filter := c.Args().First(); filter != "" {
|
|
subtree, err := t.FindFolder(filter)
|
|
if err != nil {
|
|
return exit.Error(exit.Unknown, err, "failed to find subtree: %s", err)
|
|
}
|
|
debug.Log("subtree for %q: %+v", filter, subtree)
|
|
t = subtree
|
|
}
|
|
|
|
list := t.List(tree.INF)
|
|
|
|
if len(list) < 1 {
|
|
out.Printf(ctx, "No secrets found")
|
|
|
|
return nil
|
|
}
|
|
|
|
var excludes string
|
|
st := s.Store.Storage(ctx, c.Args().First())
|
|
if buf, err := st.Get(ctx, ".gopass-audit-ignore"); err == nil && buf != nil {
|
|
excludes = string(buf)
|
|
}
|
|
nList := audit.FilterExcludes(excludes, list)
|
|
if len(nList) < len(list) {
|
|
out.Warningf(ctx, "Excluding %d secrets based on .gopass-audit-ignore", len(list)-len(nList))
|
|
}
|
|
|
|
a := audit.New(c.Context, s.Store)
|
|
r, err := a.Batch(ctx, nList)
|
|
if err != nil {
|
|
return exit.Error(exit.Unknown, err, "failed to audit password store: %s", err)
|
|
}
|
|
|
|
if p := c.String("template"); p != "" && fsutil.IsFile(p) {
|
|
r.Template = p
|
|
}
|
|
|
|
switch c.String("format") {
|
|
case "html":
|
|
return saveReport(ctx, r.RenderHTML, c.String("output-file"), "html")
|
|
case "csv":
|
|
return saveReport(ctx, r.RenderCSV, c.String("output-file"), "csv")
|
|
default:
|
|
var err error
|
|
if c.Bool("full") {
|
|
debug.Log("Printing full report")
|
|
err = r.PrintResults(ctx)
|
|
}
|
|
if c.Bool("summary") {
|
|
debug.Log("Printing summary")
|
|
|
|
nerr := r.PrintSummary(ctx)
|
|
// do not overwrite err if it is already set
|
|
if err == nil {
|
|
err = nerr
|
|
}
|
|
}
|
|
if !c.Bool("full") && !c.Bool("summary") {
|
|
out.Warning(ctx, "No output format specified. Use `--full` or `--summary` to specify.")
|
|
}
|
|
|
|
return err
|
|
}
|
|
}
|
|
|
|
func saveReport(ctx context.Context, f func(io.Writer) error, path, suffix string) error {
|
|
if path == "" {
|
|
out.Noticef(ctx, "No output filename given. Will use a random file name. Use `--output-file` to specify.")
|
|
}
|
|
|
|
fn, err := writeReport(f, path)
|
|
if err != nil {
|
|
return exit.Error(exit.Unknown, err, "failed to write report to %s: %s", fn, err)
|
|
}
|
|
|
|
if !strings.HasSuffix(fn, "."+suffix) {
|
|
nfn := fn + "." + suffix
|
|
if err := os.Rename(fn, fn+"."+suffix); err != nil {
|
|
return exit.Error(exit.IO, err, "failed to rename report to %s: %s", nfn, err)
|
|
}
|
|
fn = nfn
|
|
}
|
|
|
|
out.Noticef(ctx, "Wrote report to %s", fn)
|
|
|
|
return nil
|
|
}
|
|
|
|
func writeReport(f func(io.Writer) error, path string) (string, error) {
|
|
fh, err := openReport(path)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
defer fh.Close() //nolint:errcheck
|
|
|
|
if err := f(fh); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return fh.Name(), nil
|
|
}
|
|
|
|
func openReport(path string) (*os.File, error) {
|
|
if path == "" {
|
|
return os.CreateTemp("", "gopass-report")
|
|
}
|
|
|
|
return os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o600)
|
|
}
|