Commit Graph

13 Commits

Author SHA1 Message Date
michael
24237cbf8b refactor(daemon): AppState delegates to storage modules; dbus tests use tempdir
Lands plan tasks 2.15 (AppState refactor with StorageConfig + open()) and 2.16
(dbus.rs tests switched to tempdir-backed AppState; storage errors threaded
through D-Bus methods as Failed). Bundled because the AppState surface change
forces dbus.rs adjustments in the same commit.

- daemon/src/state.rs: AppState::open(StorageConfig) replaces with_fixtures().
  StorageConfig.from_env_or_defaults() reads AUTHFORGE_POLICY_DIR /
  _PENDING_DIR / _USERDB env vars (defaults: /etc/authforge/policy.d,
  /var/lib/authforge/pending, /var/lib/authforge/users.db). State delegates
  list/add/remove credentials to CredsPathResolver + CredentialsStore picked
  per-call from current Policy; pending and userdb operate independently.
- daemon/src/main.rs: opens state via env-driven config; reuses cfg.policy_dir
  for the watcher to keep one source of truth.
- daemon/src/dbus.rs: every write method maps StateError to fdo::Error::Failed.
  p2p_pair seeds 00-test.conf with [storage] backend = central pointing into
  the tempdir so credential writes don't try to touch /home/<user>/...
  (alice/bob/carol aren't real accounts in tests).
- Renamed: list_credentials_returns_fixture_for_alice ->
  list_credentials_after_enroll. Removed: with_fixtures().
- .gitignore: add .claude/ so leftover Phase 1 worktree state isn't committed.

Test count: 26/26 daemon tests green (was 17). Common: 13/13. Clippy + fmt clean.
2026-04-27 06:44:07 -07:00
michael
90f7a0f4fc feat(daemon): storage::userdb sqlite cache for enrollment registry 2026-04-27 06:29:36 -07:00
michael
eb3362c81c feat(daemon): storage::credentials parser, CRUD, and per-user vs central path
Lands plan tasks 2.10 (pam_u2f line format parser via CredEntry::from_line/
to_line, credId extraction), 2.11 (CredentialsStore add/remove/list with
idempotent add-by-credId), and 2.12 (CredsPathResolver dispatching central vs
per-user paths). Bundled because the three pieces compose into one storage
boundary.

CredEntry treats post-username chunks as opaque blobs split on ':', preserving
pam_u2f's full record on round-trip. credId = first comma-separated field of a
blob. add() is idempotent on credId match (Phase 3 may decide to refresh
publicKey on re-enroll; out of scope here).

Path resolution: Central -> Storage.central_path verbatim. PerUser -> getpwnam
via nix, with a /home/<user>/... fallback if NSS errors (CI users, distro
quirks); pam_u2f does the real lookup at auth time, so the fallback only
matters for write-on-enroll where the user does exist.

7 tests added; clippy + fmt clean.
2026-04-27 06:29:00 -07:00
michael
dd766e3077 feat(daemon): storage::pending JSON read/write/clear with path-traversal guards 2026-04-27 06:27:30 -07:00
michael
ea70386c2f feat(daemon): storage::policy + PolicyChanged signal + inotify watcher
Lands plan tasks 2.6 (PolicyStore wraps load_from_dir / save_local), 2.7
(PolicyChanged D-Bus signal on the AuthForge interface), and 2.8 (notify-based
inotify watcher in main.rs that emits the signal on any change in the policy.d
directory). Bundled because watcher → emit signal → wraps PolicyStore is one
data flow.

- daemon/src/storage/{mod,policy}.rs — PolicyStore::{load,save,watch}; watch
  returns a (RecommendedWatcher, watch::Receiver) so the caller keeps the
  watcher alive.
- daemon/src/dbus.rs — adds #[zbus(signal)] policy_changed; integration test
  via p2p connection asserts the signal arrives within 2s.
- daemon/src/main.rs — spawns a task that ticks PolicyChanged on every
  rx.changed(), keyed off AUTHFORGE_POLICY_DIR env var (default
  /etc/authforge/policy.d). Watcher leaked via std::mem::forget; daemon
  lifetime = process lifetime.

Test count: 17/17 daemon (was 14) + 13/13 common.
2026-04-27 06:26:49 -07:00
michael
dc2c4b02cb refactor(common): move Policy types from types.rs into policy.rs 2026-04-27 06:22:54 -07:00
michael
57c97b492c chore: add notify + rusqlite + futures-util for Phase 2 storage layer 2026-04-27 06:18:13 -07:00
michael
c26d6ae896 feat(daemon): D-Bus interface with all 9 stub methods + system-bus wiring
Bundles plan tasks 1.8 (read methods), 1.9 (EnrollOwn/RemoveOwn with polkit
gate), 1.10 (EnrollOther, SetPolicy, pending, recovery-code), and 1.11
(main.rs system-bus registration) — they land together because Polkit::System
is only constructed by main.rs, so splitting them mid-implementation would
require dead_code allows that immediately reverse.

Adds:
- daemon/src/dbus.rs — AuthForge struct + #[zbus::interface] impl with all 9
  methods. Reads (ListCredentials, GetPolicy) are unauthenticated; writes call
  authz() which dispatches to polkit. Includes 9 integration tests via a
  tokio::net::UnixStream::pair p2p connection — no system bus needed for tests.
- daemon/src/main.rs — connects to system bus, picks Polkit::system or
  Polkit::permissive based on AUTHFORGE_POLKIT_BYPASS env var, registers the
  AuthForge interface at /io/dangerousthings/AuthForge, requests well-known
  name io.dangerousthings.AuthForge, then parks forever.
- daemon/src/polkit.rs — drop dead_code allows now that System is wired.
- daemon/src/state.rs — gate has_pending() behind cfg(test); production reads
  go through the on-disk file in later phases, not this in-memory cache.
- common/src/types.rs (formatting only via rustfmt).

Tests: 14/14 daemon tests pass (4 state, 1 polkit, 9 dbus). 7/7 common tests
pass. cargo clippy --workspace --all-targets -D warnings clean. cargo fmt
clean.
2026-04-26 23:04:59 -07:00
michael
df22358051 feat(daemon): add polkit authorizer with permissive + system modes 2026-04-26 20:49:21 -07:00
michael
0dec2a1236 feat(daemon): add AppState with fixture-backed in-memory store 2026-04-26 20:48:56 -07:00
michael
c78ad0dc29 chore: add daemon deps for D-Bus interface and tests 2026-04-26 20:47:46 -07:00
michael
f50c7b2e82 Rename project: ubuntu-fido -> authforge
Renames the package and all artifacts to authforge to drop the
distro-specific prefix, since the roadmap targets Ubuntu + Debian +
KDE + eventually Fedora (option C in the design).

- deb packages: authforge, authforge-{daemon,pam,cli,gui,gnome-integration}
- binaries: authforged, authforgectl, authforge (GUI)
- D-Bus name: io.dangerousthings.AuthForge
- PAM module: pam_authforge_pending.so
- Paths: /etc/authforge/, /var/lib/authforge/, /usr/share/pam-configs/authforge
- PPA: ppa:dangerousthings/authforge

Filesystem path /home/work/VSCodeProjects/ubuntu_fido/ left as-is for
historical reference; can rename later via git mv at the dir level.

Verified: cargo build/test/clippy/fmt clean, pam builds, gui builds,
all 5 debs produced.
2026-04-26 16:53:11 -07:00
michael
e3ab53c3c6 Add daemon crate skeleton 2026-04-26 14:31:06 -07:00