Previously `gopass version` would always print an upgrade notice
when build from source even if there were no newer releases.
Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>
* 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>
This change adds GoDoc comments to many of the public symbols in the
`pkg/` directory. It also includes various improvements to the
documentation in `README.md` and other markdown files in the `docs/`
directory.
This is a partial documentation effort, as requested by the user, to
get a pull request submitted quickly.
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
* feat: Clone remote on init
When a remote is provided to the init command, try to clone it first.
If the cloned repository is not empty, use it as the password store.
Otherwise, initialize a new password store.
* feat: Clone remote on setup
When a remote is provided to the setup command, try to clone it first.
If the cloned repository is not empty, use it as the password store.
Otherwise, initialize a new password store.
* [fix] Remove init during clone
When we clone a repo we never want to initialize it automatically.
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>
* feat: Add regression test for issue #2571
This commit adds a regression test for issue #2571. The issue describes a scenario where `gopass sync` incorrectly removes public keys for sub-stores under certain conditions.
The new integration test in `tests/sync_test.go` reproduces the steps outlined in the GitHub issue to ensure that the public key is not deleted after running `gopass sync`.
* [fix] Fix lint errors
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>
* feat(age): Add unlock command to age agent
This change introduces a proper lock/unlock mechanism for the age agent.
The issue was that after locking the agent with `gopass age lock`, there was no way to unlock it without restarting the agent. This made the lock command mostly useless.
This change introduces a new `unlock` command for the agent and a `locked` state.
- The `lock` command now sets a `locked` flag to `true` in addition to clearing identities.
- The `decrypt` function in the agent now checks this `locked` flag and returns an error if the agent is locked.
- When the gopass client receives the "agent is locked" error, it will ask the user for their passphrase, reload the identities, and send them to the agent.
- A new `gopass age agent unlock` CLI command is added to trigger this new functionality.
- The `gopass age agent status` command is enhanced to report whether the agent is locked.
- The old top-level `gopass age lock` command is hidden, and a new `gopass age agent lock` command is introduced for consistency.
Fixes#3242
* feat(age): Add unlock command to age agent
This change introduces a proper lock/unlock mechanism for the age agent.
The issue was that after locking the agent with `gopass age lock`, there was no way to unlock it without restarting the agent. This made the lock command mostly useless.
This change introduces a new `unlock` command for the agent and a `locked` state.
- The `lock` command now sets a `locked` flag to `true` in addition to clearing identities.
- The `decrypt` function in the agent now checks this `locked` flag and returns an error if the agent is locked.
- When the gopass client receives the "agent is locked" error, it will ask the user for their passphrase, reload the identities, and send them to the agent.
- A new `gopass age agent unlock` CLI command is added to trigger this new functionality.
- The `gopass age agent status` command is enhanced to report whether the agent is locked.
- The old top-level `gopass age lock` command is hidden, and a new `gopass age agent lock` command is introduced for consistency.
I have also addressed the PR comment about the import alias. I have removed the alias and used a dot import instead to avoid the name collision.
Fixes#3242
* feat(age): Add unlock command to age agent
This change introduces a proper lock/unlock mechanism for the age agent.
The issue was that after locking the agent with `gopass age lock`, there was no way to unlock it without restarting the agent. This made the lock command mostly useless.
This change introduces a new `unlock` command for the agent and a `locked` state.
- The `lock` command now sets a `locked` flag to `true` in addition to clearing identities.
- The `decrypt` function in the agent now checks this `locked` flag and returns an error if the agent is locked.
- When the gopass client receives the "agent is locked" error, it will ask the user for their passphrase, reload the identities, and send them to the agent.
- A new `gopass age agent unlock` CLI command is added to trigger this new functionality.
- The `gopass age agent status` command is enhanced to report whether the agent is locked.
- The old top-level `gopass age lock` command is hidden, and a new `gopass age agent lock` command is introduced for consistency.
To avoid name collisions with the imported `filippo.io/age` package, the local `age` package has been renamed to `agecrypto`.
Fixes#3242
* feat(age): Add auto-lock feature to age agent
This change introduces an auto-lock feature for the age agent. The agent will now automatically lock itself after a configurable period of inactivity.
This change also includes the initial fix for issue #3242, which introduced a proper lock/unlock mechanism for the age agent.
- A new config option `age.agent-timeout` is added to specify the inactivity timeout in seconds.
- The agent now has a timer that is reset on every successful decryption operation.
- If the timer expires, the agent locks itself.
- A new `set-timeout` command is added to the agent protocol to configure the timeout.
- The gopass client sends the timeout to the agent when it starts or when it unlocks the agent.
- A new test `TestAgentAutoLock` is added to verify the new functionality.
To avoid name collisions with the imported `filippo.io/age` package, the local `age` package has been renamed to `agecrypto`.
Fixes#3242
* [fix] Fix lint issues
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>
The move implementation would always try to commit, even if the caller
did set this to false.
Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>
The reorg command was only listing top-level folders, which made it
difficult to move secrets in bulk. This change modifies the reorg
command to list all secrets recursively, one per line, with their full
name. This is achieved by changing the maxDepth parameter of the
Store.List call to -1, which signifies an infinite depth.
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
This change improves the usability of the `gopass mounts add` command by making the `alias` argument optional.
If the `alias` is not provided, it is automatically derived from the base name of the provided path. This makes the command more intuitive to use, as users can now simply provide the path to the store they want to mount.
The help text for the command has also been updated to reflect this new usage pattern.
Fixes#2952
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
When using `gopass edit` with the fuzzy match feature the recipients
check might incorrectly target the root store when the actual secret
would be in a mount (and might have correct recpients).
Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>
* feat: add reorg command for bulk secret reorganization
This commit introduces the `gopass reorg` command, which allows for bulk reorganization of secrets within a password store.
The command works by listing secrets in a temporary file, which the user can then edit in their default editor. After the editor is closed, gopass calculates the necessary moves, shows a diff for confirmation, and then executes the moves as a single commit.
This feature addresses issue #1866, providing a more efficient way to manage large password stores.
* feat: add reorg command for bulk secret reorganization
This commit introduces the `gopass reorg` command, which allows for bulk reorganization of secrets within a password store.
The command works by listing secrets in a temporary file, which the user can then edit in their default editor. After the editor is closed, gopass calculates the necessary moves, shows a diff for confirmation, and then executes the moves as a single commit.
This feature addresses issue #1866, providing a more efficient way to manage large password stores.
* feat: add reorg command for bulk secret reorganization
This commit introduces the `gopass reorg` command, which allows for bulk reorganization of secrets within a password store.
The command works by listing secrets in a temporary file, which the user can then edit in their default editor. After the editor is closed, gopass calculates the necessary moves, shows a diff for confirmation, and then executes the moves as a single commit.
This feature addresses issue #1866, providing a more efficient way to manage large password stores.
* feat: add reorg command for bulk secret reorganization
This commit introduces the `gopass reorg` command, which allows for bulk reorganization of secrets within a password store.
The command works by listing secrets in a temporary file, which the user can then edit in their default editor. After the editor is closed, gopass calculates the necessary moves, shows a diff for confirmation, and then executes the moves as a single commit.
This feature addresses issue #1866, providing a more efficient way to manage large password stores.
---------
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
* fix(gpg): Opportunistic key comparison on import
When importing keys gopass was already checking if the key was already present.
However, GPG is very flexible in which kind of key IDs it accepts. So it could happen that gopass would ask to import a key that is already present in the keyring, but referenced by a different ID.
This change makes the check more robust by checking the key's fingerprint before asking for import. If a key with the same fingerprint is already present, the import is skipped.
* fix(gpg): Opportunistic key comparison on import
When importing keys gopass was already checking if the key was already present.
However, GPG is very flexible in which kind of key IDs it accepts. So it could happen that gopass would ask to import a key that is already present in the keyring, but referenced by a different ID.
This change makes the check more robust by checking the key's fingerprint before asking for import. If a key with the same fingerprint is already present, the import is skipped.
---------
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
* feat: Allow to customize commit messages
This change introduces the ability for users to customize the commit
message when performing actions that modify the secret store.
It adds two new flags to the `edit`, `insert`, `generate`, `copy`,
`move`, and `delete` commands:
- `--commit-message` (`-m`): to specify the commit message directly.
- `--interactive-commit` (`-i`): to open an editor for the commit
message.
The default behavior of using a pre-defined commit message is
preserved.
* fix: Use correct commit message from context
This change fixes a bug where the commit message from the context was
not being used correctly in the `delete` function.
---------
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
The handling of the `core.exportkeys` configuration setting was
inconsistent across the application.
In `internal/store/leaf/recipients.go`, the value was read using
`config.AsBoolWithDefault(..., true)`. This was introduced as a fix
for #2848 to ensure that public keys were exported by default, even
in substores.
However, other parts of the code, such as `internal/action/sync.go`,
used `config.AsBool(...)`. This resulted in different behaviors
depending on the gopass command being executed. For a substore without
the `core.exportkeys` key explicitly set, modifying recipients would
default to `true`, while a `gopass sync` would default to `false`.
This inconsistency is the likely cause of the user's report in issue
#3227 about the default value changing.
This change harmonizes the behavior by using `config.AsBool` in
`recipients.go`, making it consistent with the rest of the codebase
and the recommendation in AGENTS.md to use the `config.Bool` helper
(which uses `AsBool`).
While this may re-introduce the issue that #2848 aimed to solve (where
substores default to not exporting keys), it fixes the immediate problem
of inconsistent behavior. The root cause appears to be in how substores
inherit configuration, which should be addressed separately.
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
* This change introduces an agent for the age backend to cache passphrases for age identities.
The agent is a long-running process that listens on a Unix domain socket. Gopass communicates with the agent to request decryption of secrets. The agent caches the passphrases for the identities and performs the decryption, so the passphrases never leave the agent process. This addresses the security concerns with the initial implementation.
The agent can be controlled with the following commands:
- `gopass age agent`: starts the agent in the foreground.
- `gopass age lock`: locks the agent, clearing all cached passphrases.
The age backend will automatically start the agent if it's not already running and the `age.agent-enabled` configuration option is set to `true` (the default).
This change includes:
- The implementation of the age agent in `internal/backend/crypto/age/agent/`.
- Modifications to the age backend to communicate with the agent.
- A new configuration option `age.agent-enabled`.
- Unit tests for the agent.
- Updated documentation for the age backend.
The integration test for this feature (`TestAgeAgent`) is currently failing. The issue is that the test environment is non-interactive, and the code path for initializing a new age store requires a password for the identity keyring, which triggers a `pinentry` call that fails without a TTY. I have tried several approaches to work around this, including setting the `GOPASS_PASSWORD` environment variable and providing a custom pinentry script, but none have been successful so far. The core implementation of the agent is believed to be correct, but the integration test needs further work to run in a non-interactive environment.
* This change introduces an agent for the age backend to cache passphrases for age identities.
The agent is a long-running process that listens on a Unix domain socket. Gopass communicates with the agent to request decryption of secrets. The agent caches the passphrases for the identities and performs the decryption, so the passphrases never leave the agent process. This addresses the security concerns with the initial implementation.
The agent can be controlled with the following commands:
- `gopass age agent`: starts the agent in the foreground.
- `gopass age lock`: locks the agent, clearing all cached passphrases.
The age backend will automatically start the agent if it's not already running and the `age.agent-enabled` configuration option is set to `true` (the default).
This change includes:
- The implementation of the age agent in `internal/backend/crypto/age/agent/`.
- Modifications to the age backend to communicate with the agent.
- A new configuration option `age.agent-enabled`.
- Unit tests for the agent.
- Updated documentation for the age backend.
* This change introduces an agent for the age backend to cache passphrases for age identities.
The agent is a long-running process that listens on a Unix domain socket. Gopass communicates with the agent to request decryption of secrets. The agent caches the passphrases for the identities and performs the decryption, so the passphrases never leave the agent process. This addresses the security concerns with the initial implementation.
The agent can be controlled with the following commands:
- `gopass age agent`: starts the agent in the foreground.
- `gopass age lock`: locks the agent, clearing all cached passphrases.
The age backend will automatically start the agent if it's not already running and the `age.agent-enabled` configuration option is set to `true` (the default).
This change includes:
- The implementation of the age agent in `internal/backend/crypto/age/agent/`.
- Modifications to the age backend to communicate with the agent.
- A new configuration option `age.agent-enabled`.
- Unit tests for the agent.
- Updated documentation for the age backend.
* This change introduces an agent for the age backend to cache passphrases for age identities.
The agent is a long-running process that listens on a Unix domain socket. Gopass communicates with the agent to request decryption of secrets. The agent caches the passphrases for the identities and performs the decryption, so the passphrases never leave the agent process. This addresses the security concerns with the initial implementation.
The agent can be controlled with the following commands:
- `gopass age agent`: starts the agent in the foreground.
- `gopass age lock`: locks the agent, clearing all cached passphrases.
The age backend will automatically start the agent if it's not already running and the `age.agent-enabled` configuration option is set to `true` (the default).
This change includes:
- The implementation of the age agent in `internal/backend/crypto/age/agent/`.
- Modifications to the age backend to communicate with the agent.
- A new configuration option `age.agent-enabled`.
- Unit tests for the agent.
- Updated documentation for the age backend.
* Fix some test failures and add more logging.
Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>
* Fix lint error
Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>
* [fix] Fix integration tests
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>
When cleaning up the public keys in the .public-keys directory, we were
previously only considering the top-level .gpg-id file. This could lead
to the removal of public keys that were still in use in sub-stores.
This commit fixes this by changing the `idFiles` function to correctly
find all .gpg-id files in the store, including nested ones.
It also introduces a new `AllRecipients` function that gathers all
recipients from the main store and all sub-stores by using the corrected
`idFiles` logic.
The `UpdateExportedPublicKeys` function is refactored to use
`AllRecipients` to get the complete list of recipients, removing the need
to pass them as an argument. All call sites of `UpdateExportedPublicKeys`
are updated accordingly.
Finally, the logic for finding extra keys to remove is extracted into a
standalone `extraKeys` function, and a new unit test `TestExtraKeys` is
added to verify its behavior.
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
* fix(store): Correctly handle moves within mounts
When moving a secret within a mounted store, the destination path was not
correctly stripped of the mount prefix. This lead to the creation of an
unnecessary subdirectory with the name of the mount.
This commit fixes this issue by ensuring the destination path is correctly
handled in the `directMove` function.
Fixes#3164
* fix(store): Correctly handle moves within mounts
When moving a secret within a mounted store, the destination path was not
correctly stripped of the mount prefix. This lead to the creation of an
unnecessary subdirectory with the name of the mount.
This commit fixes this issue by ensuring the destination path is correctly
handled in the `directMove` function.
Fixes#3164
---------
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
This commit adds a new experimental storage backend for the Jujutsu
VCS. It currently is a wrapper around Git and does not add too much
value by itself, but provides an interface that is supposed to be
more stable than git and might eventually evolve to support a
custom storage backend as well. Also I want to test it.
Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>
We have some strange test failures on Windows and I can not identify any
root cause in this repo. It does look like either a Go or a GHA Windows
builder regression and I currently don't have the resources to properly
debug those. If you care about Windows, please help. Otherwise I have
to turn these off for now to unblock PR which are perfectly find on
other platforms.
Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>
this fix will skip confirmation input when using gopass recipient add
--force
fixes#3172
Signed-off-by: Tommi2Day <tommi2day@tommi2day.net>
Co-authored-by: Tommi2Day <tommi2day@tommi2day.net>
* feat: handle referencing in passwords
Signed-off-by: Parham Alvani <parham.alvani@gmail.com>
* feat: use seq over slice to improve performance
Signed-off-by: Parham Alvani <parham.alvani@gmail.com>
* feat: handle error during reference following
Signed-off-by: Parham Alvani <parham.alvani@gmail.com>
* feat: provide a flag for not following references
Signed-off-by: Parham Alvani <parham.alvani@gmail.com>
* feat: disable ref following on edit and remove the flag
Signed-off-by: Parham Alvani <parham.alvani@gmail.com>
* feat: provide a configuration for follow-references
Signed-off-by: Parham Alvani <parham.alvani@gmail.com>
* fix: correct configuration tests
Signed-off-by: Parham Alvani <parham.alvani@gmail.com>
* fix: correct tests and document the new flag
Signed-off-by: Parham Alvani <parham.alvani@gmail.com>
* fix: correct integration test
Signed-off-by: Parham Alvani <parham.alvani@gmail.com>
* fix: correct tests
Signed-off-by: Parham Alvani <parham.alvani@gmail.com>
---------
Signed-off-by: Parham Alvani <parham.alvani@gmail.com>
Mostly to remind myself how those are supposed to operate
and document it for my future self.
The lookup part is a little bit error prone, i.e. if the rules for
these domains change the test will break. But I promise to take
care of that once that happens for the first time.
Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>
This change fixes a bug with the generatePasswordForRule() function,
so that users who have provided initial values that are within the
bounds of the domain's rule are not prompted for the length, and rejects
all invalid length values by recursively prompting the user for a valid
length.
Signed-off-by: sudoforge <no-reply@sudoforge.com>
When the `--edit` (`-e`) flag is provided, a user has already opted in
to edit the entry after password generation. This change removes the
redundant confirmation prompt in order to streamline this workflow.
Signed-off-by: sudoforge <no-reply@sudoforge.com>
Hard-coding paths to binaries like `/bin/<foo>` fails on platforms like
NixOS, which do not follow the typical directory hierarchy found on
Linux distributions. Using `/usr/bin/env cat` is much more portable,
however, it delegates path searching to the shell environment, which
**can** be a cause for concern in domains with high security
requirements.
Signed-off-by: sudoforge <no-reply@sudoforge.com>
This change makes the `gopass create` workflow pick up the config
settings for pwgen the same way as the `gopass generate` workflows
do. This allows more flexibility and users to override the defaults
used in the create wizard.
Fixes#3141
Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>
* add gitconfig extension from include
feature for #2458
RELEASE_NOTES=[FEATURE] Add support for gitconfig include
Signed-off-by: Sergei Suslov <sergey.suslov.nsk@gmail.com>
* use t.Setenv instead of os.Setenv, comment log
RELEASE_NOTES=n/a
Signed-off-by: Sergei Suslov <sergey.suslov.nsk@gmail.com>
* [fix] Fix writing merged configs
We must not write the content of the merged config to the base config.
Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>
* [chore] Classify license
Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>
* [fix] Fix lint issues and one test
Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>
* [fix] Fix one failing test on Windows as a workaround
Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>
* [fix] Ignore two tests on windows
Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>
---------
Signed-off-by: Sergei Suslov <sergey.suslov.nsk@gmail.com>
Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>
Co-authored-by: Sergei Suslov <sergey.suslov.nsk@gmail.com>
* [feat] Replace clipboard library to support wl-copy args
This change should allow us to protect sensitive content
from being captured in some clipboard managers on KDE.
Fixes#2611
Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>
* [chore] Update clipboard dep
Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>
* [fix] Update clipboard
Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>
---------
Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>
* [fix] Fix test regressions
This change fixes some tests that did start to fail at some point.
I can't tell for sure when they broke (didn't bisect) and if that
breakage is isolated to my system or not. But I need to fix them
anyway.
Fixes#3115
Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>
* Add missing files.
Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>
* Fix test failure
Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>
* Fix one more version test
Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>
---------
Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>
This change removes the extraneous colon from the commit message in the
event that no HeadMessage is set on the current context.
Signed-off-by: sudoforge <no-reply@sudoforge.com>