Google requires OAuth for calendar access; app passwords stopped working for CalDAV, CardDAV and IMAP in March 2025, so there is no simpler path to offer. - Authorisation code flow over a loopback redirect, which is what Google supports for desktop clients now the copy-paste flow is gone, with PKCE so an intercepted code is useless without the verifier. Only the refresh token is persisted, 0600, in the state directory. - An expired grant is reported as itself: a consent screen still in Testing has its refresh tokens expired after 7 days, and "run calcalist google login" is more use than Google's bare invalid_grant. - doctor reports whether each Google endpoint is still authorised, since an installation that worked last week can stop with nothing having changed here. A webcal URL may now come from a command instead of the config. Google's secret iCal address grants read access to a whole calendar to anyone holding it, so writing it into a file described as portable and secret-free was a contradiction. Fixed a serious defect in the first draft of this module: random_token used fs::read on /dev/urandom, which reads to end of file. /dev/urandom has no end, so it allocated until the machine ran out of memory — it took the editor down with it. It now reads exactly 32 bytes, and a randomness failure is fatal rather than falling back to the clock, since a guessable state or PKCE verifier defeats the point of having them. Verified end to end against a live Posteo CalDAV calendar: pimsync validated the generated config against the real server, 58 events from a public feed were mirrored and pushed, and a second run was a no-op. 97 tests. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
23 lines
551 B
TOML
23 lines
551 B
TOML
[package]
|
|
name = "calcalist"
|
|
version = "0.1.0"
|
|
edition = "2024"
|
|
rust-version = "1.97"
|
|
description = "Aggregate and sync events between CalDAV, Google Calendar and iCal feeds"
|
|
publish = false
|
|
|
|
[dependencies]
|
|
blake3 = "1.8"
|
|
clap = { version = "4.6", features = ["derive"] }
|
|
serde = { version = "1.0", features = ["derive"] }
|
|
serde_json = "1.0"
|
|
sha2 = "0.11"
|
|
thiserror = "2.0"
|
|
toml = "1.1"
|
|
ureq = { version = "3.4", default-features = false, features = ["json", "rustls", "gzip"] }
|
|
|
|
[dev-dependencies]
|
|
tempfile = "3"
|
|
|
|
[lints.rust]
|
|
unsafe_code = "forbid"
|