Google Auto Backup of the age-encrypted blob, passphrase-gated restore
Per request: re-enable allowBackup but scope it to ONE file via include-rules — files/gbackup/latest.json.age, an age-encrypted export written only while a backup passphrase is set (never plaintext to Google; DB/prefs stay excluded). On a new device the OS restores the blob, the Today screen detects an empty DB + present blob and offers 'Gjenopprett' — which demands the passphrase typed, since the Keystore key never migrates. Clearing the passphrase deletes the blob. scrypt work factor dropped 18→15: age's desktop default needs a 256 MiB working set and OOM-crashed on-device (found the hard way); 15 = 32 MiB, still real brute-force cost, and largeHeap covers decrypting foreign files made at 18. Verified by instrumented round-trip tests (write → empty DB → restore; wrong passphrase keeps DB empty; cleared passphrase removes blob) — UI automation couldn't drive the multi-field dialog reliably, so the proof lives in the test instead. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
96ac8ea108
commit
c9ee76387f
11 changed files with 264 additions and 24 deletions
|
|
@ -164,12 +164,29 @@ fun BackupSettingsScreen(nav: Nav) {
|
|||
settings.s3AccessKey = accessKey.trim().ifBlank { null }
|
||||
settings.s3SecretKey = secretKey.trim().ifBlank { null }
|
||||
settings.autoBackupPassphrase = autoPassphrase.ifBlank { null }
|
||||
// Write/remove the Google Auto Backup blob right away so the
|
||||
// protection state matches the setting immediately.
|
||||
scope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
BackupManager(context).writeCloudBlob()
|
||||
} catch (e: Exception) {
|
||||
withContext(Dispatchers.Main) { toast("Kunne ikke skrive Google-kopi: ${e.message}") }
|
||||
}
|
||||
}
|
||||
toast("Lagret")
|
||||
},
|
||||
enabled = !passphraseMismatch,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
) { Text("Lagre backupinnstillinger") }
|
||||
|
||||
Text(
|
||||
"Google-sikkerhetskopi: når passordfrase er satt, legges en kryptert kopi i " +
|
||||
"Googles enhetsbackup. Gjenoppretting på ny enhet krever at frasen tastes " +
|
||||
"inn — den følger aldri med. Uten frase sendes ingenting til Google.",
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
|
||||
OutlinedButton(
|
||||
onClick = {
|
||||
scope.launch(Dispatchers.IO) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue