before cleanup

This commit is contained in:
2026-09-08 16:32:02 +02:00
parent 7c70221723
commit 5642424697
4 changed files with 185 additions and 50 deletions

View File

@@ -50,7 +50,7 @@ all:
musicmouse: musicmouse:
squeezelite_name: MusicMouse squeezelite_name: MusicMouse
shairport_name: MusicMouse shairport_name: MusicMouse
alsa_card_name: 1 alsa_card_name: sndrpihifiberry
hifiberry_overlay: hifiberry-dacplus hifiberry_overlay: hifiberry-dacplus
sensor_room_name: Kinderzimmer sensor_room_name: Kinderzimmer
sensor_room_name_ascii: kinderzimmer sensor_room_name_ascii: kinderzimmer

View File

@@ -1,63 +1,191 @@
# Copy this to ".ansible/plugins/lookup" # Copy this file to ~/.ansible/plugins/lookup/keepass.py
#
# Prerequisites:
# pip install keepassxc-proxy-client
#
# KeePassXC setup:
# Tools > Settings > Browser Integration > Enable browser integration
# The plugin will prompt you to approve the association in KeePassXC on first run.
# Association credentials are saved to ~/.keepassxc_ansible_assoc (override with
# env var KEEPASSXC_ASSOC_FILE).
#
# Usage:
# {{ lookup('keepass', 'https://example.com', 'password') }}
# {{ lookup('keepass', 'https://example.com', 'username') }}
# {{ lookup('keepass', 'https://example.com') }} # defaults to password
#
# Terms:
# terms[0] URL (or title) to search for — matched against KeePassXC entries
# terms[1] Attribute to return: username / user / password / pass / passwd
# Defaults to 'password' if omitted.
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import json
import os
from ansible.errors import AnsibleError from ansible.errors import AnsibleError
from ansible.plugins.lookup import LookupBase from ansible.plugins.lookup import LookupBase
from keepasshttplib import keepasshttplib, encrypter
import requests
DOCUMENTATION = """ DOCUMENTATION = r"""
lookup: keepass lookup: keepass
author: Martin Bauer <bauer_martin@gmx.de> short_description: Fetch credentials from KeePassXC via the browser proxy protocol
version_added: '0.2'
short_description: fetch data from KeePass over KeePassHTTP
description: description:
- This lookup returns a username or password queried by the URL of the keepass entry - Connects to a running KeePassXC instance over its browser-integration Unix socket
(or Windows named pipe) and retrieves credentials for a given URL.
- On first use the plugin associates itself with KeePassXC; you will see an
approval dialog in KeePassXC. The association is saved to disk so subsequent
runs are silent.
options: options:
_terms: _terms:
description: description:
- first is the URL to search for - First term is the URL (or entry title URL) to look up.
- second is a property name of the entry, e.g. username or password - Second term (optional) is the attribute to return.
required: True Accepted values are username, user, password, pass, passwd.
Defaults to password.
required: true
notes: notes:
- https://github.com/viczem/ansible-keepass - KeePassXC must be running with Browser Integration enabled.
- Requires the Python package keepassxc-proxy-client.
example:
- "{{ lookup('keepass', 'urlOfEntry', 'password') }}"
""" """
EXAMPLES = r"""
- name: Get password for an entry
debug:
msg: "{{ lookup('keepass', 'https://example.com') }}"
- name: Get username for an entry
debug:
msg: "{{ lookup('keepass', 'https://example.com', 'username') }}"
- name: Set pi account password from KeePassXC
user:
name: pi
password: "{{ lookup('keepass', 'default_rpi_password') | password_hash('sha512') }}"
"""
ASSOC_FILE_ENV = "KEEPASSXC_ASSOC_FILE"
ASSOC_FILE_DEFAULT = os.path.expanduser("~/.keepassxc_ansible_assoc")
ASSOC_NAME = "ansible-keepassxc"
USERNAME_ATTRS = {"username", "user"}
PASSWORD_ATTRS = {"password", "pass", "passwd"}
def _get_assoc_file():
return os.environ.get(ASSOC_FILE_ENV, ASSOC_FILE_DEFAULT)
def _load_assoc(connection):
"""Load a previously saved association from disk into *connection*. Returns True on success."""
path = _get_assoc_file()
if not os.path.exists(path):
return False
try:
with open(path, "r") as fh:
data = json.load(fh)
connection.load_associate(data["name"], bytes(data["public_key"]))
return True
except (KeyError, ValueError, OSError):
return False
def _save_assoc(connection):
"""Persist the current association to disk."""
path = _get_assoc_file()
assoc_id, public_key = connection.dump_associate()
data = {"name": assoc_id, "public_key": list(public_key)}
with open(path, "w") as fh:
json.dump(data, fh)
os.chmod(path, 0o600)
def _connect():
"""Return an authenticated, test-verified Connection to KeePassXC."""
try:
from keepassxc_proxy_client.protocol import Connection, ResponseUnsuccesfulException
except ImportError:
raise AnsibleError(
"keepassxc-proxy-client is not installed. "
"Run: pip install keepassxc-proxy-client"
)
conn = Connection()
try:
conn.connect()
except Exception as exc:
raise AnsibleError(
"Cannot connect to KeePassXC. Is it running with Browser Integration enabled? "
"Error: {}".format(exc)
)
conn.change_public_keys()
# Try to reuse an existing association
if _load_assoc(conn):
try:
conn.test_associate(trigger_unlock=True)
return conn # existing association is still valid
except Exception:
pass # fall through and re-associate
# First run (or stale association) — ask KeePassXC to authorise us
try:
conn.associate()
except Exception as exc:
raise AnsibleError(
"KeePassXC association failed. "
"Please approve the request in the KeePassXC dialog. "
"Error: {}".format(exc)
)
try:
conn.test_associate(trigger_unlock=True)
except Exception as exc:
raise AnsibleError("KeePassXC association test failed: {}".format(exc))
_save_assoc(conn)
return conn
class LookupModule(LookupBase): class LookupModule(LookupBase):
def __init__(self, *args, **kwargs):
super(LookupModule, self).__init__(*args, **kwargs)
self.k = keepasshttplib.Keepasshttplib()
def run(self, terms, variables=None, **kwargs): def run(self, terms, variables=None, **kwargs):
if not terms or len(terms) > 2: if not terms or len(terms) > 2:
raise AnsibleError('Keepass wrong request format') raise AnsibleError(
if len(terms) == 1: "keepass lookup expects 1 or 2 arguments: "
entry_path, entry_attr = terms[0], 'password' "lookup('keepass', '<url>', '<attribute>')"
else: )
entry_path, entry_attr = terms[0], terms[1]
url = terms[0]
#if not self._test_connection(): attr = terms[1].lower() if len(terms) == 2 else "password"
# raise AnsibleError('Keepass is closed!')
try: if attr not in USERNAME_ATTRS | PASSWORD_ATTRS:
auth = self.k.get_credentials(entry_path) raise AnsibleError(
except Exception as e: "keepass: unsupported attribute '{}'. "
raise AnsibleError('Keepass error obtaining entry {}: {}'.format(entry_path, e)) "Use one of: username, user, password, pass, passwd".format(attr)
if auth: )
if entry_attr not in ('username', 'user', 'pass', 'passwd', 'password'):
raise AnsibleError("Keepass wrong entry") conn = _connect()
ret = auth[0] if entry_attr.startswith('user') else auth[1]
return [ret]
def _test_connection(self):
key = self.k.get_key_from_keyring()
if key is None:
key = encrypter.generate_key()
id_ = self.k.get_id_from_keyring()
try: try:
return self.k.test_associate(key, id_) entries = conn.get_logins(url)
except requests.exceptions.ConnectionError as e: except Exception as exc:
raise AnsibleError('Keepass Connection Error: {}'.format(e)) raise AnsibleError(
"keepass: failed to retrieve logins for '{}': {}".format(url, exc)
)
if not entries:
raise AnsibleError(
"keepass: no entries found in KeePassXC for URL '{}'".format(url)
)
# Return the first matching entry (KeePassXC already filters by URL)
entry = entries[0]
if attr in USERNAME_ATTRS:
return [entry.get("login", "")]
else:
return [entry.get("password", "")]

View File

@@ -10,6 +10,7 @@ import json
from datetime import datetime from datetime import datetime
import os import os
import time import time
import subprocess
# ------------------- Config ---------------------------------------------------------------- # ------------------- Config ----------------------------------------------------------------
@@ -78,6 +79,12 @@ async def ble_scan():
await stop_event.wait() await stop_event.wait()
except Exception as e: except Exception as e:
print("Error", e) print("Error", e)
try:
subprocess.run(["hciconfig", "hci0", "reset"], check=True)
except Exception as reset_err:
print(f"Reset failed: {reset_err}")
await asyncio.sleep(3)
print("Starting again") print("Starting again")
@@ -94,4 +101,4 @@ if __name__ == "__main__":
os.system(f"hciconfig {restart_interface} up") os.system(f"hciconfig {restart_interface} up")
time.sleep(3) time.sleep(3)
print("Done") print("Done")
asyncio.run(main()) asyncio.run(main())

View File

@@ -47,7 +47,7 @@
user: user:
name: pi name: pi
update_password: always update_password: always
password: "{{ lookup('keepass', 'default_rpi_password') | password_hash('sha512') }}" password: "{{ lookup('keepass', 'ansible://default_rpi_password') | password_hash('sha512') }}"
- name: Install Packages (vim, git, basic python stuff) - name: Install Packages (vim, git, basic python stuff)
apt: apt:
name: name: