forked from borgmatic-collective/borgmatic
Compare commits
7 Commits
5cea1e1b72
...
issue1047
| Author | SHA1 | Date | |
|---|---|---|---|
| 248999c23e | |||
| 4e55547235 | |||
| 96ec66de79 | |||
| 7a0c56878b | |||
| 92ebc77597 | |||
| 863c954144 | |||
| f7e4d38762 |
@@ -2683,6 +2683,20 @@ properties:
|
||||
description: |
|
||||
Command to use instead of "keepassxc-cli".
|
||||
example: /usr/local/bin/keepassxc-cli
|
||||
key_file:
|
||||
type: string
|
||||
description: |
|
||||
Path to a key file for unlocking the KeePassXC database.
|
||||
example: /path/to/keyfile
|
||||
yubikey:
|
||||
type: string
|
||||
description: |
|
||||
YubiKey slot and optional serial number used to access the KeePassXC database.
|
||||
Format: "<slot[:serial]>", where:
|
||||
- <slot> is the YubiKey slot number (e.g., `1` or `2`).
|
||||
- <serial> (optional) is the YubiKey's serial number (e.g., `1:7370001`).
|
||||
example: "1:7370001"
|
||||
|
||||
description: |
|
||||
Configuration for integration with the KeePassXC password manager.
|
||||
default_actions:
|
||||
|
||||
@@ -11,34 +11,31 @@ def load_credential(hook_config, config, credential_parameters):
|
||||
'''
|
||||
Given the hook configuration dict, the configuration dict, and a credential parameters tuple
|
||||
containing a KeePassXC database path and an attribute name to load, run keepassxc-cli to fetch
|
||||
the corresponidng KeePassXC credential and return it.
|
||||
the corresponding KeePassXC credential and return it.
|
||||
|
||||
Raise ValueError if keepassxc-cli can't retrieve the credential.
|
||||
'''
|
||||
try:
|
||||
(database_path, attribute_name) = credential_parameters
|
||||
except ValueError:
|
||||
path_and_name = ' '.join(credential_parameters)
|
||||
|
||||
raise ValueError(
|
||||
f'Cannot load credential with invalid KeePassXC database path and attribute name: "{path_and_name}"'
|
||||
)
|
||||
raise ValueError( f'Invalid KeePassXC credential parameters: {credential_parameters}')
|
||||
|
||||
expanded_database_path = os.path.expanduser(database_path)
|
||||
|
||||
if not os.path.exists(expanded_database_path):
|
||||
raise ValueError(
|
||||
f'Cannot load credential because KeePassXC database path does not exist: {database_path}'
|
||||
)
|
||||
|
||||
return borgmatic.execute.execute_command_and_capture_output(
|
||||
raise ValueError( f'KeePassXC database path does not exist: {database_path}')
|
||||
|
||||
|
||||
# Build the keepassxc-cli command
|
||||
command = (
|
||||
tuple(shlex.split((hook_config or {}).get('keepassxc_cli_command', 'keepassxc-cli')))
|
||||
+ (
|
||||
'show',
|
||||
'--show-protected',
|
||||
'--attributes',
|
||||
'Password',
|
||||
expanded_database_path,
|
||||
attribute_name,
|
||||
)
|
||||
).rstrip(os.linesep)
|
||||
+ ('show', '--show-protected', '--attributes', 'Password')
|
||||
+ (('--key-file', hook_config['key_file']) if 'key_file' in hook_config else ())
|
||||
+ (('--yubikey', hook_config['yubikey']) if 'yubikey' in hook_config else ())
|
||||
+ (expanded_database_path, attribute_name) # Ensure database & entry are last
|
||||
)
|
||||
|
||||
try:
|
||||
return borgmatic.execute.execute_command_and_capture_output(command).rstrip(os.linesep)
|
||||
except Exception as e:
|
||||
raise ValueError(f'Failed to retrieve credential: {e}')
|
||||
|
||||
@@ -116,3 +116,104 @@ def test_load_credential_with_expanded_directory_with_present_database_fetches_p
|
||||
)
|
||||
== 'password'
|
||||
)
|
||||
|
||||
|
||||
def test_load_credential_with_key_file():
|
||||
flexmock(module.os.path).should_receive('expanduser').with_args('database.kdbx').and_return(
|
||||
'database.kdbx'
|
||||
)
|
||||
flexmock(module.os.path).should_receive('exists').and_return(True)
|
||||
flexmock(module.borgmatic.execute).should_receive(
|
||||
'execute_command_and_capture_output'
|
||||
).with_args(
|
||||
(
|
||||
'keepassxc-cli',
|
||||
'show',
|
||||
'--show-protected',
|
||||
'--attributes',
|
||||
'Password',
|
||||
'--key-file',
|
||||
'/path/to/keyfile',
|
||||
'database.kdbx',
|
||||
'mypassword',
|
||||
)
|
||||
).and_return(
|
||||
'password'
|
||||
).once()
|
||||
|
||||
assert (
|
||||
module.load_credential(
|
||||
hook_config={'key_file': '/path/to/keyfile'},
|
||||
config={},
|
||||
credential_parameters=('database.kdbx', 'mypassword'),
|
||||
)
|
||||
== 'password'
|
||||
)
|
||||
|
||||
|
||||
def test_load_credential_with_yubikey():
|
||||
flexmock(module.os.path).should_receive('expanduser').with_args('database.kdbx').and_return(
|
||||
'database.kdbx'
|
||||
)
|
||||
flexmock(module.os.path).should_receive('exists').and_return(True)
|
||||
flexmock(module.borgmatic.execute).should_receive(
|
||||
'execute_command_and_capture_output'
|
||||
).with_args(
|
||||
(
|
||||
'keepassxc-cli',
|
||||
'show',
|
||||
'--show-protected',
|
||||
'--attributes',
|
||||
'Password',
|
||||
'--yubikey',
|
||||
'1:7370001',
|
||||
'database.kdbx',
|
||||
'mypassword',
|
||||
)
|
||||
).and_return(
|
||||
'password'
|
||||
).once()
|
||||
|
||||
assert (
|
||||
module.load_credential(
|
||||
hook_config={'yubikey': '1:7370001'},
|
||||
config={},
|
||||
credential_parameters=('database.kdbx', 'mypassword'),
|
||||
)
|
||||
== 'password'
|
||||
)
|
||||
|
||||
|
||||
def test_load_credential_with_key_file_and_yubikey():
|
||||
flexmock(module.os.path).should_receive('expanduser').with_args('database.kdbx').and_return(
|
||||
'database.kdbx'
|
||||
)
|
||||
flexmock(module.os.path).should_receive('exists').and_return(True)
|
||||
flexmock(module.borgmatic.execute).should_receive(
|
||||
'execute_command_and_capture_output'
|
||||
).with_args(
|
||||
(
|
||||
'keepassxc-cli',
|
||||
'show',
|
||||
'--show-protected',
|
||||
'--attributes',
|
||||
'Password',
|
||||
'--key-file',
|
||||
'/path/to/keyfile',
|
||||
'--yubikey',
|
||||
'2',
|
||||
'database.kdbx',
|
||||
'mypassword',
|
||||
)
|
||||
).and_return(
|
||||
'password'
|
||||
).once()
|
||||
|
||||
assert (
|
||||
module.load_credential(
|
||||
hook_config={'key_file': '/path/to/keyfile', 'yubikey': '2'},
|
||||
config={},
|
||||
credential_parameters=('database.kdbx', 'mypassword'),
|
||||
)
|
||||
== 'password'
|
||||
)
|
||||
Reference in New Issue
Block a user