mirror of
https://github.com/rclone/rclone.git
synced 2026-05-13 02:44:21 -04:00
Add read-only iCloud Photos support to the existing iclouddrive backend via `service = photos` config option. Also includes auth improvements on top of #9209's SRP authentication. **Photos features:** - 3-level hierarchy: libraries (Personal + Shared Photo Library) → albums → photos/videos - server-side smart albums (All Photos, Videos, Favorites, Screenshots, Live, Bursts, Panoramas, Slo-mo, Time-lapse, Portrait, Long Exposure, Animated, Hidden, Recently Deleted) - User-created albums and nested album folders - Live Photo `.MOV` companions as first-class entries - Edited photo versions (`-edited` suffix) and RAW alternatives - Duplicate filename dedup for camera counter wrap collisions - Parallel cold listing for large albums - Delta sync via CloudKit `changes/zone` - warm listings near-instant from disk cache - Disk cache (libraries, albums, photos) with atomic writes for crash safety - `ChangeNotify` support for FUSE mounts via `changes/zone` polling - `ListR` support for `--fast-list` and recursive operations - `--metadata` support - width, height, added-time, favorite, hidden - Fresh download URLs per file - no stale URL failures on long copies - FUSE mount documentation with recommended flags **Auth improvements over #9209:** - SMS 2FA fallback for users without trusted Apple devices - Explicit push notification request - fixes iOS/macOS 26.4+ where 409 no longer auto-pushes - Thread safety for concurrent FUSE callers (mutexes on session and client state) - Session endpoint caching - skips ~5s `/validate` round-trip on warm start - `Disconnect` support - clears auth state + disk cache - PCS cookie support for Advanced Data Protection accounts, including trusted-device approval for PCS cookies Built on @coughlanio's Photos PoC (Closes #8734) and @mikegillan's SRP auth (#9209). Fixes #7982 Co-authored-by: Chris Coughlan <chris@coughlan.io>
41 lines
1.2 KiB
Go
41 lines
1.2 KiB
Go
package api
|
|
|
|
import (
|
|
"net/http"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestExtractHeadersMergesCookies(t *testing.T) {
|
|
s := NewSession()
|
|
s.Cookies = []*http.Cookie{{Name: "existing", Value: "old"}}
|
|
|
|
resp := &http.Response{Header: make(http.Header)}
|
|
resp.Header.Add("Set-Cookie", (&http.Cookie{Name: "existing", Value: "new"}).String())
|
|
resp.Header.Add("Set-Cookie", (&http.Cookie{Name: "fresh", Value: "value"}).String())
|
|
resp.Header.Set("X-Apple-Session-Token", "session-token")
|
|
|
|
s.extractHeaders(resp)
|
|
|
|
require.Len(t, s.Cookies, 2)
|
|
assert.Equal(t, "new", s.Cookies[0].Value)
|
|
assert.Equal(t, "fresh", s.Cookies[1].Name)
|
|
assert.Equal(t, "session-token", s.SessionToken)
|
|
}
|
|
|
|
func TestExtractHeadersDeletesEmptyCookies(t *testing.T) {
|
|
s := NewSession()
|
|
s.Cookies = []*http.Cookie{{Name: "X-APPLE-WEBAUTH-HSA-LOGIN", Value: "stale"}, {Name: "keep", Value: "value"}}
|
|
|
|
resp := &http.Response{Header: make(http.Header)}
|
|
resp.Header.Add("Set-Cookie", (&http.Cookie{Name: "X-APPLE-WEBAUTH-HSA-LOGIN", Value: ""}).String())
|
|
|
|
s.extractHeaders(resp)
|
|
|
|
require.Len(t, s.Cookies, 1)
|
|
assert.Equal(t, "keep", s.Cookies[0].Name)
|
|
assert.Equal(t, "keep=value", s.GetCookieString())
|
|
}
|