KeePass support
This commit is contained in:
parent
1f28ee3622
commit
ff2cddbf65
@ -88,3 +88,11 @@ This configures [`keyringer`](https://0xacab.org/rhatto/keyringer) (based on GPG
|
|||||||
|
|
||||||
`keyringer` need a "keyring" to search in, and you can (optionally) specify a folder to be
|
`keyringer` need a "keyring" to search in, and you can (optionally) specify a folder to be
|
||||||
prefixed to the password names created from the realm.
|
prefixed to the password names created from the realm.
|
||||||
|
|
||||||
|
#### keepass
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
keepass: /home/me/mypasswords.kdbx
|
||||||
|
```
|
||||||
|
|
||||||
|
This configures KeePass as password manager; it will prompt for your master password every time.
|
||||||
|
@ -22,6 +22,11 @@ dependencies = [
|
|||||||
"PyYAML",
|
"PyYAML",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[project.optional-dependencies]
|
||||||
|
keepass = [
|
||||||
|
"pykeepass",
|
||||||
|
]
|
||||||
|
|
||||||
[project.scripts]
|
[project.scripts]
|
||||||
ldaptool = "ldaptool._main:main"
|
ldaptool = "ldaptool._main:main"
|
||||||
|
|
||||||
@ -46,5 +51,6 @@ module = [
|
|||||||
"ldap",
|
"ldap",
|
||||||
"ldap.dn",
|
"ldap.dn",
|
||||||
"ldap.controls.libldap",
|
"ldap.controls.libldap",
|
||||||
|
"pykeepass",
|
||||||
]
|
]
|
||||||
ignore_missing_imports = true
|
ignore_missing_imports = true
|
||||||
|
@ -2,6 +2,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import abc
|
import abc
|
||||||
import dataclasses
|
import dataclasses
|
||||||
|
import getpass
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
import shlex
|
import shlex
|
||||||
@ -122,6 +123,34 @@ class Keyringer(PasswordManager):
|
|||||||
return result.stdout.strip()
|
return result.stdout.strip()
|
||||||
|
|
||||||
|
|
||||||
|
@dataclasses.dataclass
|
||||||
|
class Keepass(PasswordManager):
|
||||||
|
database: str
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def load(data: typing.Any) -> Keepass:
|
||||||
|
try:
|
||||||
|
import pykeepass # make sure dependency is present during config loading
|
||||||
|
|
||||||
|
assert pykeepass # so it isn't unused...
|
||||||
|
except ImportError:
|
||||||
|
raise Exception(
|
||||||
|
"Missing (optional) dependency for keepass support - please install (python package for) pykeepass"
|
||||||
|
)
|
||||||
|
assert isinstance(
|
||||||
|
data, str
|
||||||
|
), "keepass integration expects a single string as configuration with the database location"
|
||||||
|
return Keepass(database=data)
|
||||||
|
|
||||||
|
def get_password(self, password_name: str) -> str:
|
||||||
|
import pykeepass # already made sure it is avaiable above
|
||||||
|
|
||||||
|
password = getpass.getpass(f"KeePass password for database {self.database}: ")
|
||||||
|
kp = pykeepass.PyKeePass(self.database, password=password)
|
||||||
|
entry = kp.find_entries(username=password_name, first=True)
|
||||||
|
return entry.password # type: ignore
|
||||||
|
|
||||||
|
|
||||||
@dataclasses.dataclass
|
@dataclasses.dataclass
|
||||||
class PasswordScript(PasswordManager):
|
class PasswordScript(PasswordManager):
|
||||||
command: list[str]
|
command: list[str]
|
||||||
@ -173,6 +202,10 @@ class Config:
|
|||||||
if password_manager:
|
if password_manager:
|
||||||
raise ValueError("Can only set a single password manager")
|
raise ValueError("Can only set a single password manager")
|
||||||
password_manager = Keyringer.load(data.pop("keyringer"))
|
password_manager = Keyringer.load(data.pop("keyringer"))
|
||||||
|
if "keepass" in data:
|
||||||
|
if password_manager:
|
||||||
|
raise ValueError("Can only set a single password manager")
|
||||||
|
password_manager = Keepass.load(data.pop("keepass"))
|
||||||
if "password-script" in data:
|
if "password-script" in data:
|
||||||
if password_manager:
|
if password_manager:
|
||||||
raise ValueError("Can only set a single password manager")
|
raise ValueError("Can only set a single password manager")
|
||||||
@ -189,6 +222,5 @@ class Config:
|
|||||||
raise RuntimeError("Can't get password without acccount - should use kerberos instead")
|
raise RuntimeError("Can't get password without acccount - should use kerberos instead")
|
||||||
if self.password_manager:
|
if self.password_manager:
|
||||||
return self.password_manager.get_password(realm.password_name)
|
return self.password_manager.get_password(realm.password_name)
|
||||||
import getpass
|
|
||||||
|
|
||||||
return getpass.getpass(f"Enter password for {realm.password_name}: ")
|
return getpass.getpass(f"Enter password for {realm.password_name}: ")
|
||||||
|
Loading…
Reference in New Issue
Block a user