Restore latest backup straight from the bucket

Settings gains 'Gjenopprett siste backup fra bøtta': lists the bucket
(classic query-less ListObjects — an empty canonical query sidesteps a
whole class of SigV4 encoding mismatches; keys filtered client-side),
picks the lexicographically newest timestamped key, downloads, then
runs the existing import path (format auto-detect, passphrase prompt,
replace-all, alarm re-arm). Closes the circle: after a device loss,
recovery is in-app instead of laptop + age -d. parseListKeys is pure
and unit-tested; first ListObjects page only (1000 keys), which the
bucket's lifecycle expiration keeps us far below.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Ole-Morten Duesund 2026-06-11 17:51:13 +02:00
commit 90eb15ca0b
4 changed files with 109 additions and 1 deletions

View file

@ -48,6 +48,19 @@ class BackupManager(private val context: Context) {
return file.medications.size
}
/**
* Newest backup object in the bucket, or null when none exist. Keys embed
* a UTC timestamp, so the lexicographically last key is the newest.
*/
suspend fun fetchLatestBackup(): Pair<String, ByteArray>? {
val settings = SettingsStore(context)
val s3 = checkNotNull(settings.s3Client()) { "Backup er ikke konfigurert" }
val key = s3.listAllKeys()
.filter { it.startsWith("meddetsamme/backup-") }
.maxOrNull() ?: return null
return key to s3.get(key)
}
/**
* Unattended backup S3. Encrypts with the STORED passphrase if one is
* configured (protects against bucket compromise only see SettingsStore),