mirror of
https://github.com/gopasspw/gopass.git
synced 2026-05-30 11:18:48 +02:00
882d06e001
* feat: Add cryptfs storage backend for filename encryption This commit introduces a new storage backend called `cryptfs`. This backend encrypts the filenames of secrets to enhance privacy while maintaining compatibility with existing VCS backends like Git. Key features: - For each secret, a cryptographically secure hash (SHA-256) of its name is generated and used as the filename for the underlying storage. - A mapping from the original secret name to the hashed filename is maintained in an encrypted file (`.gopass-mapping.age`) within the repository. - The mapping file is encrypted using the `age` encryption backend, with recipients read from the store's `.age-recipients` file. - The `cryptfs` backend is implemented as a wrapper around any existing storage backend (e.g., `gitfs`, `fs`), which can be configured by the user. - The backend is registered with gopass and can be enabled by setting `storage: cryptfs` in the store's configuration. This implementation addresses issue #2634. * [fix] Fix lint errors Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org> * [chore] Fix the remaining tests and add some docs. Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org> --------- Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org> Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> Co-authored-by: Dominik Schulz <dominik.schulz@gauner.org>
112 lines
2.4 KiB
Go
112 lines
2.4 KiB
Go
package cryptfs
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/gopasspw/gopass/internal/backend"
|
|
"github.com/gopasspw/gopass/internal/config"
|
|
"github.com/gopasspw/gopass/internal/out"
|
|
"github.com/gopasspw/gopass/pkg/debug"
|
|
"github.com/gopasspw/gopass/pkg/fsutil"
|
|
)
|
|
|
|
func init() {
|
|
backend.StorageRegistry.Register(backend.CryptFS, "cryptfs", &loader{})
|
|
}
|
|
|
|
type loader struct{}
|
|
|
|
// New returns a new cryptfs storage backend.
|
|
func (l *loader) New(ctx context.Context, path string) (backend.Storage, error) {
|
|
subID, err := getSubStorage(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
sub, err := backend.NewStorage(ctx, subID, path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return newCrypt(ctx, sub)
|
|
}
|
|
|
|
// Init initializes a new cryptfs storage backend.
|
|
func (l *loader) Init(ctx context.Context, path string) (backend.Storage, error) {
|
|
subID, err := getSubStorage(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
sub, err := backend.InitStorage(ctx, subID, path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
debug.Log("Initialized sub storage %s at %s", subID, path)
|
|
|
|
c, err := newCrypt(ctx, sub)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if err := c.saveMappings(ctx); err != nil {
|
|
out.Warningf(ctx, "Failed to save initial mapping: %s", err)
|
|
}
|
|
|
|
return c, nil
|
|
}
|
|
|
|
// Handles returns true if this backend handles the given path.
|
|
func (l *loader) Handles(ctx context.Context, path string) error {
|
|
if fsutil.IsFile(path + "/" + mappingFile) {
|
|
return nil
|
|
}
|
|
|
|
return fmt.Errorf("no mapping file found")
|
|
}
|
|
|
|
// String returns the name of this backend.
|
|
func (l *loader) String() string {
|
|
return name
|
|
}
|
|
|
|
// Priority returns the priority of this backend.
|
|
func (l *loader) Priority() int {
|
|
return 7
|
|
}
|
|
|
|
// Clone clones an existing repository and initializes the cryptfs backend.
|
|
func (l *loader) Clone(ctx context.Context, repo, path string) (backend.Storage, error) {
|
|
subID, err := getSubStorage(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
subLoader, err := backend.StorageRegistry.Get(subID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
sub, err := subLoader.Clone(ctx, repo, path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return newCrypt(ctx, sub)
|
|
}
|
|
|
|
func getSubStorage(ctx context.Context) (backend.StorageBackend, error) {
|
|
subStoreName := config.String(ctx, "cryptfs.substorage")
|
|
if subStoreName == "" {
|
|
subStoreName = "gitfs"
|
|
}
|
|
|
|
id, err := backend.StorageRegistry.Backend(subStoreName)
|
|
if err != nil {
|
|
debug.Log("Failed to get backend ID for %q: %s", subStoreName, err)
|
|
}
|
|
|
|
return id, err
|
|
}
|