forked from gopasspw/gopass
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
18 changed files
with
311 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package action | ||
|
||
import ( | ||
"context" | ||
"os" | ||
"path/filepath" | ||
|
||
"github.com/justwatchcom/gopass/pkg/config" | ||
"github.com/justwatchcom/gopass/pkg/fsutil" | ||
"github.com/justwatchcom/gopass/pkg/out" | ||
"github.com/urfave/cli" | ||
) | ||
|
||
// Fsck checks the store integrity | ||
func (s *Action) Fsck(ctx context.Context, c *cli.Context) error { | ||
// make sure config is in the right place | ||
// we may have loaded it from one of the fallback locations | ||
if err := s.cfg.Save(); err != nil { | ||
return ExitError(ctx, ExitConfig, err, "failed to save config: %s", err) | ||
} | ||
// clean up any previous config locations | ||
oldCfg := filepath.Join(config.Homedir(), ".gopass.yml") | ||
if fsutil.IsFile(oldCfg) { | ||
if err := os.Remove(oldCfg); err != nil { | ||
out.Red(ctx, "Failed to remove old gopass config %s: %s", oldCfg, err) | ||
} | ||
} | ||
|
||
if err := s.Store.Fsck(ctx, c.Args().Get(0)); err != nil { | ||
return ExitError(ctx, ExitFsck, err, "fsck found errors: %s", err) | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -35,4 +35,5 @@ type Storage interface { | |
|
||
Name() string | ||
Version() semver.Version | ||
Fsck(context.Context) error | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package fs | ||
|
||
import ( | ||
"context" | ||
"os" | ||
"path/filepath" | ||
"syscall" | ||
|
||
"github.com/justwatchcom/gopass/pkg/fsutil" | ||
"github.com/justwatchcom/gopass/pkg/out" | ||
) | ||
|
||
// Fsck checks the storage integrity | ||
func (s *Store) Fsck(ctx context.Context) error { | ||
entries, err := s.List(ctx, "") | ||
if err != nil { | ||
return err | ||
} | ||
dirs := make(map[string]struct{}, len(entries)) | ||
for _, entry := range entries { | ||
filename := filepath.Join(s.path, entry) | ||
dirs[filepath.Dir(filename)] = struct{}{} | ||
|
||
if err := s.fsckCheckFile(ctx, filename); err != nil { | ||
return err | ||
} | ||
} | ||
|
||
for dir := range dirs { | ||
if err := s.fsckCheckDir(ctx, dir); err != nil { | ||
return err | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func (s *Store) fsckCheckFile(ctx context.Context, filename string) error { | ||
fi, err := os.Stat(filename) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if fi.Mode().Perm()&0177 == 0 { | ||
return nil | ||
} | ||
|
||
out.Yellow(ctx, "Permissions too wide: %s (%s)", filename, fi.Mode().String()) | ||
|
||
np := uint32(fi.Mode().Perm() & 0600) | ||
out.Green(ctx, "Fixing permissions on %s from %s to %s", filename, fi.Mode().Perm().String(), os.FileMode(np).Perm().String()) | ||
if err := syscall.Chmod(filename, np); err != nil { | ||
out.Red(ctx, "Failed to set permissions for %s to rw-------: %s", filename, err) | ||
} | ||
return nil | ||
} | ||
|
||
func (s *Store) fsckCheckDir(ctx context.Context, dirname string) error { | ||
fi, err := os.Stat(dirname) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// check if any group or other perms are set, | ||
// i.e. check for perms other than rwx------ | ||
if fi.Mode().Perm()&077 != 0 { | ||
out.Yellow(ctx, "Permissions too wide %s on dir %s", fi.Mode().Perm().String(), dirname) | ||
|
||
np := uint32(fi.Mode().Perm() & 0700) | ||
out.Green(ctx, "Fixing permissions from %s to %s", fi.Mode().Perm().String(), os.FileMode(np).Perm().String()) | ||
if err := syscall.Chmod(dirname, np); err != nil { | ||
out.Red(ctx, "Failed to set permissions for %s to rwx------: %s", dirname, err) | ||
} | ||
} | ||
// check for empty folders | ||
isEmpty, err := fsutil.IsEmptyDir(dirname) | ||
if err != nil { | ||
return err | ||
} | ||
if isEmpty { | ||
out.Red(ctx, "WARNING: Folder %s is empty", dirname) | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package root | ||
|
||
import ( | ||
"context" | ||
"strings" | ||
|
||
"github.com/pkg/errors" | ||
) | ||
|
||
// Fsck checks all stores/entries matching the given prefix | ||
func (s *Store) Fsck(ctx context.Context, path string) error { | ||
for alias, sub := range s.mounts { | ||
if sub == nil { | ||
continue | ||
} | ||
if path != "" && !strings.HasPrefix(path, alias+"/") { | ||
continue | ||
} | ||
if err := sub.Fsck(ctx, strings.TrimPrefix(path, alias+"/")); err != nil { | ||
return errors.Wrapf(err, "fsck failed on sub store %s: %s", alias, err) | ||
} | ||
} | ||
if err := s.store.Fsck(ctx, path); err != nil { | ||
return errors.Wrapf(err, "fsck failed on root store: %s", err) | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
package sub | ||
|
||
import ( | ||
"context" | ||
"sort" | ||
|
||
"github.com/justwatchcom/gopass/pkg/out" | ||
"github.com/pkg/errors" | ||
) | ||
|
||
// Fsck checks all entries matching the given prefix | ||
func (s *Store) Fsck(ctx context.Context, path string) error { | ||
// first let the storage backend check itself | ||
if err := s.storage.Fsck(ctx); err != nil { | ||
return errors.Wrapf(err, "storage backend found errors: %s", err) | ||
} | ||
|
||
// then we'll make sure all the secrets are readable by us and every | ||
// valid recipient | ||
names, err := s.List(ctx, path) | ||
if err != nil { | ||
return errors.Wrapf(err, "failed to list entries: %s", err) | ||
} | ||
sort.Strings(names) | ||
for _, name := range names { | ||
if err := s.fsckCheckEntry(ctx, name); err != nil { | ||
return errors.Wrapf(err, "failed to check %s: %s", name, err) | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (s *Store) fsckCheckEntry(ctx context.Context, name string) error { | ||
// make sure we can actually decode this secret | ||
// if this fails there is no way we could fix this | ||
_, err := s.Get(ctx, name) | ||
if err != nil { | ||
return errors.Wrapf(err, "failed to decode secret %s: %s", name, err) | ||
} | ||
|
||
// now compare the recipients this secret was encoded for and fix it if | ||
// if doesn't match | ||
ciphertext, err := s.storage.Get(ctx, s.passfile(name)) | ||
if err != nil { | ||
return err | ||
} | ||
itemRecps, err := s.crypto.RecipientIDs(ctx, ciphertext) | ||
if err != nil { | ||
return err | ||
} | ||
perItemStoreRecps, err := s.GetRecipients(ctx, name) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// check itemRecps matches storeRecps | ||
missing, extra := compareStringSlices(perItemStoreRecps, itemRecps) | ||
if len(missing) > 0 { | ||
out.Red(ctx, "Missing recipients on %s: %+v", name, missing) | ||
} | ||
if len(extra) > 0 { | ||
out.Red(ctx, "Extra recipients on %s: %+v", name, extra) | ||
} | ||
if len(missing) > 0 || len(extra) > 0 { | ||
sec, err := s.Get(ctx, name) | ||
if err != nil { | ||
return err | ||
} | ||
if err := s.Set(WithReason(ctx, "fsck fix recipients"), name, sec); err != nil { | ||
return err | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func compareStringSlices(want, have []string) ([]string, []string) { | ||
missing := []string{} | ||
extra := []string{} | ||
|
||
wantMap := make(map[string]struct{}, len(want)) | ||
haveMap := make(map[string]struct{}, len(have)) | ||
|
||
for _, w := range want { | ||
wantMap[w] = struct{}{} | ||
} | ||
for _, h := range have { | ||
haveMap[h] = struct{}{} | ||
} | ||
|
||
for k := range wantMap { | ||
if _, found := haveMap[k]; !found { | ||
missing = append(missing, k) | ||
} | ||
} | ||
for k := range haveMap { | ||
if _, found := wantMap[k]; !found { | ||
extra = append(extra, k) | ||
} | ||
} | ||
|
||
return missing, extra | ||
} |
Oops, something went wrong.