v1.18.0: contacts, socket activation, reconnect overhaul - #28
Merged
Merged
Conversation
Only open outbound TCP on discovery for paired devices, active pairing mode, or explicit 'kcd pair <id>' intent (one-shot dial + on-demand pair request via last-seen discovery address). Discovered strangers are still recorded as UNPAIRED (new-device default, with UNKNOWN migration) but never dialled. '--connected' and clipboard/findmyphone auto-pick now mean paired+connected; client docs require state==PAIRED for auto-select.
…ped names pair_listen now only reports the candidate instead of auto-accepting, so stale requests can no longer pair silently. 'kcd pair' asks Accept [y/N] (default reject); -y/--yes keeps headless usage working. Some senders transmit non-ASCII names as decimal byte escapes; decode them to real UTF-8 on receipt, truncate runewise, and migrate stored names on daemon load.
An unpaired stranger gets one ephemeral TCP dial per unpaired era so the identity exchange makes both sides visible, closed again on the next sighting while still unpaired. No timers or polling: a marker suppresses re-dials, pairing mode and explicit pair intent bypass, unpair/reject re-arms, and broadcast stop drops leftover unpaired connections. kcd pair listen also retries past the daemon 60s timeout until Ctrl+C.
Liveness stays on the CONNECTED column; the flag now hides only unpaired strangers instead of offline paired phones.
Add Report() accessor on the connectivity plugin, emit a cached connectivity.update in the watch initial-state dump, and add a kcd connectivity [--json] [device-id] query path (IPC command, daemon route, client method) rendering per-SIM signal bars.
Add a state.snapshot event on watch connect covering all known devices with cached battery/media/signal so clients boot from one connection. Expose posAnchorMs on NowPlaying for drift-free position math and flag in-flight album art with artPending plus an empty URL instead of an unloadable kdeconnect:/ URI. Enrich devices --json via an IPC-only DeviceSummary (disk shape unchanged) and add --json to battery, volume list, sftp info/volumes with fish completions. this is basically to make it easier for external clients
last_seen is stamped at connect time and discovery sightings skip connected devices, so the raw stamp goes stale for the whole session and clients show "Xm ago" for a live phone. SummarizeDevice now reports now for connected devices; stored stamp, prune, and devices.json semantics untouched.
Paired sightings no longer trust unauthenticated discovery for dial targets or names; redial LastIP:LastPort with per-device throttle. Clamp discovery ports, throttle ephemeral dials, extend pair intent past the one-shot trigger, and strip control/shell chars from names.
receiveAlbumArt could complete after a track change and publish the old cover against the new track. Guard the attribution on matching art URL and player; bytes stay cached for the new track's own request.
Bound MMS attachment streams with LimitReader and a 50MB cap. Restrict notification IDs to filename-safe characters and confine icon cache paths to the cache dir. Pass -- to notify-send and wtype so remote text can't be misparsed as flags, and harden SMS attachment filenames.
…ecutable auto-open Strict user/host/port/path validation for the sshfs argv so remote values can't be reinterpreted as ssh options. Only http/https URLs reach xdg-open; anything else is logged and skipped. Never auto-open executable file types (auto_open stays off by default).
Side-channel TLS used the same trust-any-cert profile as the main link but never checked who presented it, so any holder of a cert could feed bytes to a receiver or pull files from a sender. Pin each transfer to the peer fingerprint snapshot at request time: receivers abort before writing, senders abort before streaming. Unpinned (unpaired) devices log a warning and proceed as before.
…-only flags Bare pair --yes accepted the first device that asked, stranger or not. Add --expected-fingerprint to pin the exact peer cert and --known-only to restrict candidates to previously recorded devices; anything else is rejected while listening continues. Print a warning when --yes runs unconstrained. The listen result now carries the candidate fingerprint.
A fresh device published charge 0 / charging false, indistinguishable from a genuine 0% reading — and at steady charge no later packet ever corrected it. Track first-receipt per device and leave the battery object out of summaries, the watch bootstrap dump, and the battery query (which now fails closed) until then. Summaries carry batteryAgeMs so clients can apply staleness rules.
… activation The daemon adopts a systemd-passed IPC listener (LISTEN_FDS, stdlib only) when configured with the default socket path, so any client command — including watch — summons a stopped daemon instead of retrying against an absent socket. Custom socket paths and non-systemd systems keep the self-bind path. The socket unit owns the runtime directory (declaring it in both units made service stops delete the socket file) with mode 0600, and the installer enables the socket instead of the always-on service.
LastIP/LastPort lived only in memory, so every daemon restart left paired auto-dial with nothing to dial — reconnect waited entirely on the phone connecting inbound while we advertise nothing. Store the target in the device state file (validated on load; the file is user-editable) and restore it at startup. Pure state, no new timers.
On hearing a paired phone, kcd redialed the remembered LastIP and ignored the fresh source address in the sighting — so a phone that roamed to a new DHCP address triggered dials to the dead old one while the proof of its new address sat in the packet. Dial the sighted ip:port (throttled as before); whoever answers must still present the paired certificate or setup fails, so spoofed sightings cost a dial, never a session. LastIP stays the fallback for silent peers via the backoff loop.
A sighting from an address other than the failing target proves the old backoff was aimed at a dead address, so later cycles restart at the floor. Same-address sightings leave the counter alone, preserving flap protection for a dying peer. No new timers — pure counter state.
…le broadcasting mDNS registration lived inside the UDP broadcast loop, which is stopped by default — so a quiet daemon was invisible to phones on both discovery channels. Registration is responder-only (no idle timers), so it now runs from daemon startup at negligible cost while UDP broadcast keeps its on-demand lifecycle.
Run the UDP broadcaster while any paired device is disconnected so roamed or restarted phones can find us back; fully stopped otherwise, so connected steady state keeps zero timers. Starts are reference-counted per owner, so reconnect needs and kcd pair neither start nor stop each other's loop. Driven by connect/disconnect events plus a startup sync — no polling.
Request UID/timestamp lists, fetch vCards for new or changed contacts, and cache per-device .vcf files plus an index sidecar. Syncs trigger on connect and via kcd contacts sync; kcd contacts list reads the cache (empty when never synced — unknown, never zero). Unpairing wipes the cached address book. Defensive handling throughout: UIDs are filename-sanitized and confined, empty UID lists never wipe the cache, response sizes are capped, string and numeric timestamps both parse, display fields are stripped of control characters, cache files are 0600, and the update event carries counts only.
Add packaging/kcd-pkg.socket (distro variant without the graphical-session tie-in) and include both socket units in the tarballs, deb/rpm contents, and AUR package body. kcd-pkg.service no longer declares RuntimeDirectory=kcd so stopping the service can't tear the socket out from under the socket unit; the daemon self-creates the dir in non-socket mode. Drop the AUR post-install hook (packaging/kcd-bin.install); post-install enablement is documented in the README and release notes instead. Point deb/rpm postinstall and the uninstall script at kcd.socket, and document the one-command wake (paired phones reconnect on their own afterwards). Also fix the Hyprland keybind snippet for the Lua config format (hl.bind) and correct stale constructor signatures in AGENTS.md.
Handle spawns sendDesktopNotification in a goroutine, so the fake's calls slice was written off-test-goroutine while TestNotifySendEndsOptions read it directly (and argFor read it unlocked). Guard argFor with the existing mutex, add a locked lastCall snapshot, and poll it via waitFor instead of a fixed sleep.
goreleaser check fails on the deprecated property and CI gates on it. The verified hint is cosmetic; removing it changes nothing about the published cask.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Highlights
kcd contacts), counts-only watch events, per-device opt-in, wiped on unpair. (Phonebook/Contacts? #27 )kcd.socket), zero idle cost; old always-on service still supported.LastIP/LastPort), dial sighted address for pairs, roam-aware backoff reset, mDNS advertised for daemon lifetime, UDP broadcast while a pair is offline.--expected-fingerprint,--known-only).Validation
CGO_ENABLED=0 go test -p 1 -count=1 ./...green,golangci-lint0 issues, static binary verified.goreleaser release --snapshotsucceeds withkcd.socketconfirmed in tarballs, deb, rpm, and rendered AUR PKGBUILD.