diff --git a/.gitignore b/.gitignore index 98d8a5a..6c3d6ce 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,23 @@ -logs +# Python +__pycache__/ +*.py[cod] +*.egg-info/ +*.egg +dist/ +build/ + +# Virtual environments +.venv/ + +# IDE +.idea/ +.vscode/ +*.swp +*.swo + +# OS +.DS_Store +Thumbs.db + +# Honker +logs/ diff --git a/config.sample.yaml b/config.sample.yaml new file mode 100644 index 0000000..7ea6603 --- /dev/null +++ b/config.sample.yaml @@ -0,0 +1,12 @@ +# Honker configuration +# Copy this file to ~/.config/honker/config.yaml and edit to suit your setup. + +# The Signal account number honker will use +account: "+15551234567" + +# Contacts that are allowed to interact with honker +trusted_contacts: + - name: "Alice" + number: "+15559876543" + - name: "Bob" + number: "+15551112222" diff --git a/src/honker/__pycache__/__init__.cpython-312.pyc b/src/honker/__pycache__/__init__.cpython-312.pyc deleted file mode 100644 index 468013e..0000000 Binary files a/src/honker/__pycache__/__init__.cpython-312.pyc and /dev/null differ diff --git a/src/honker/__pycache__/config.cpython-312.pyc b/src/honker/__pycache__/config.cpython-312.pyc deleted file mode 100644 index 743d918..0000000 Binary files a/src/honker/__pycache__/config.cpython-312.pyc and /dev/null differ diff --git a/src/honker/__pycache__/main.cpython-312.pyc b/src/honker/__pycache__/main.cpython-312.pyc deleted file mode 100644 index 611b8da..0000000 Binary files a/src/honker/__pycache__/main.cpython-312.pyc and /dev/null differ diff --git a/src/honker/__pycache__/processes.cpython-312.pyc b/src/honker/__pycache__/processes.cpython-312.pyc deleted file mode 100644 index 977ee47..0000000 Binary files a/src/honker/__pycache__/processes.cpython-312.pyc and /dev/null differ diff --git a/src/honker/config.py b/src/honker/config.py index b28c85a..4767b5a 100644 --- a/src/honker/config.py +++ b/src/honker/config.py @@ -1,4 +1,4 @@ -import os +from dataclasses import dataclass, field from pathlib import Path import yaml @@ -7,12 +7,49 @@ DEFAULT_CONFIG_PATH = Path.home() / ".config" / "honker" / "config.yaml" DEFAULT_SIGNAL_SOCKET_PATH = Path.home() / ".local" / "share" / "honker" / "signal-cli.sock" -def load_config(path: Path | None = None) -> dict: +@dataclass +class Contact: + name: str + number: str + + +@dataclass +class Config: + account: str + trusted_contacts: list[Contact] = field(default_factory=list) + + def is_trusted(self, number: str) -> bool: + """Check whether a phone number belongs to a trusted contact.""" + return any(c.number == number for c in self.trusted_contacts) + + def contact_by_number(self, number: str) -> Contact | None: + """Look up a trusted contact by phone number.""" + return next((c for c in self.trusted_contacts if c.number == number), None) + + +def load_config(path: Path | None = None) -> Config: """Load configuration from ~/.config/honker/config.yaml""" config_path = path or DEFAULT_CONFIG_PATH if not config_path.exists(): - return {} + raise FileNotFoundError( + f"Config file not found: {config_path}\n" + "Create it with at least:\n" + " account: +1234567890\n" + " trusted_contacts:\n" + ' - name: "Alice"\n' + " number: +1234567890" + ) with open(config_path) as f: - return yaml.safe_load(f) or {} + raw = yaml.safe_load(f) or {} + + if "account" not in raw: + raise ValueError("Config is missing required field: account") + + contacts = [ + Contact(name=c["name"], number=c["number"]) + for c in raw.get("trusted_contacts", []) + ] + + return Config(account=raw["account"], trusted_contacts=contacts) diff --git a/src/honker/main.py b/src/honker/main.py index 34237d3..0cd8109 100644 --- a/src/honker/main.py +++ b/src/honker/main.py @@ -13,6 +13,13 @@ log = logging.getLogger(__name__) def parse_args() -> argparse.Namespace: parser = argparse.ArgumentParser(description="Honker – Signal ↔ Goose ACP bridge") + parser.add_argument( + "--config", + metavar="FILE", + type=Path, + default=None, + help="Path to config file (default: ~/.config/honker/config.yaml)", + ) parser.add_argument( "--debug", metavar="DIR", @@ -31,8 +38,9 @@ def main() -> None: format="%(asctime)s [%(name)s] %(levelname)s: %(message)s", ) - config = load_config() - log.info("Honker starting up") + config = load_config(path=args.config) + log.info("Honker starting up (account=%s, %d trusted contacts)", + config.account, len(config.trusted_contacts)) if args.debug: log.debug("Debug mode enabled — process logs will be written to %s", args.debug)