mirror of
https://github.com/home-assistant/core.git
synced 2026-09-27 01:46:11 -04:00
Write the backup store with private=True so the backup password is not world-readable (#182259)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -14,7 +14,7 @@ if TYPE_CHECKING:
|
||||
STORE_DELAY_SAVE = 30
|
||||
STORAGE_KEY = DOMAIN
|
||||
STORAGE_VERSION = 1
|
||||
STORAGE_VERSION_MINOR = 7
|
||||
STORAGE_VERSION_MINOR = 8
|
||||
|
||||
|
||||
class StoredBackupData(TypedDict):
|
||||
@@ -39,6 +39,8 @@ class _BackupStore(Store[StoredBackupData]):
|
||||
STORAGE_KEY,
|
||||
max_readable_version=self._MAX_READABLE_VERSION,
|
||||
minor_version=STORAGE_VERSION_MINOR,
|
||||
# The store persists the automatic backup password in plaintext.
|
||||
private=True,
|
||||
)
|
||||
|
||||
@override
|
||||
@@ -85,6 +87,9 @@ class _BackupStore(Store[StoredBackupData]):
|
||||
for backup in data["backups"]:
|
||||
backup["failed_addons"] = []
|
||||
backup["failed_folders"] = []
|
||||
# Version 1.8 does not change the data. The minor version was bumped
|
||||
# so that stores written before the store was made private are
|
||||
# rewritten once, with mode 0600, on the first load.
|
||||
|
||||
# Note: We allow reading data with major version 2 in which the unused key
|
||||
# data["config"]["schedule"]["state"] will be removed. The bump to 2 is
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
}),
|
||||
}),
|
||||
'key': 'backup',
|
||||
'minor_version': 7,
|
||||
'minor_version': 8,
|
||||
'version': 1,
|
||||
})
|
||||
# ---
|
||||
@@ -93,7 +93,7 @@
|
||||
}),
|
||||
}),
|
||||
'key': 'backup',
|
||||
'minor_version': 7,
|
||||
'minor_version': 8,
|
||||
'version': 1,
|
||||
})
|
||||
# ---
|
||||
@@ -142,7 +142,7 @@
|
||||
}),
|
||||
}),
|
||||
'key': 'backup',
|
||||
'minor_version': 7,
|
||||
'minor_version': 8,
|
||||
'version': 1,
|
||||
})
|
||||
# ---
|
||||
@@ -191,7 +191,7 @@
|
||||
}),
|
||||
}),
|
||||
'key': 'backup',
|
||||
'minor_version': 7,
|
||||
'minor_version': 8,
|
||||
'version': 1,
|
||||
})
|
||||
# ---
|
||||
@@ -250,7 +250,7 @@
|
||||
}),
|
||||
}),
|
||||
'key': 'backup',
|
||||
'minor_version': 7,
|
||||
'minor_version': 8,
|
||||
'version': 1,
|
||||
})
|
||||
# ---
|
||||
@@ -309,7 +309,7 @@
|
||||
}),
|
||||
}),
|
||||
'key': 'backup',
|
||||
'minor_version': 7,
|
||||
'minor_version': 8,
|
||||
'version': 1,
|
||||
})
|
||||
# ---
|
||||
@@ -362,7 +362,7 @@
|
||||
}),
|
||||
}),
|
||||
'key': 'backup',
|
||||
'minor_version': 7,
|
||||
'minor_version': 8,
|
||||
'version': 1,
|
||||
})
|
||||
# ---
|
||||
@@ -415,7 +415,7 @@
|
||||
}),
|
||||
}),
|
||||
'key': 'backup',
|
||||
'minor_version': 7,
|
||||
'minor_version': 8,
|
||||
'version': 1,
|
||||
})
|
||||
# ---
|
||||
@@ -468,7 +468,7 @@
|
||||
}),
|
||||
}),
|
||||
'key': 'backup',
|
||||
'minor_version': 7,
|
||||
'minor_version': 8,
|
||||
'version': 1,
|
||||
})
|
||||
# ---
|
||||
@@ -521,7 +521,7 @@
|
||||
}),
|
||||
}),
|
||||
'key': 'backup',
|
||||
'minor_version': 7,
|
||||
'minor_version': 8,
|
||||
'version': 1,
|
||||
})
|
||||
# ---
|
||||
@@ -577,7 +577,7 @@
|
||||
}),
|
||||
}),
|
||||
'key': 'backup',
|
||||
'minor_version': 7,
|
||||
'minor_version': 8,
|
||||
'version': 1,
|
||||
})
|
||||
# ---
|
||||
@@ -633,7 +633,7 @@
|
||||
}),
|
||||
}),
|
||||
'key': 'backup',
|
||||
'minor_version': 7,
|
||||
'minor_version': 8,
|
||||
'version': 1,
|
||||
})
|
||||
# ---
|
||||
@@ -695,7 +695,7 @@
|
||||
}),
|
||||
}),
|
||||
'key': 'backup',
|
||||
'minor_version': 7,
|
||||
'minor_version': 8,
|
||||
'version': 1,
|
||||
})
|
||||
# ---
|
||||
@@ -757,7 +757,131 @@
|
||||
}),
|
||||
}),
|
||||
'key': 'backup',
|
||||
'minor_version': 7,
|
||||
'minor_version': 8,
|
||||
'version': 1,
|
||||
})
|
||||
# ---
|
||||
# name: test_store_migration[store_data7]
|
||||
dict({
|
||||
'data': dict({
|
||||
'backups': list([
|
||||
dict({
|
||||
'backup_id': 'abc123',
|
||||
'failed_addons': list([
|
||||
dict({
|
||||
'name': 'Test add-on',
|
||||
'slug': 'test_addon',
|
||||
'version': '1.0.0',
|
||||
}),
|
||||
]),
|
||||
'failed_agent_ids': list([
|
||||
'test.remote',
|
||||
]),
|
||||
'failed_folders': list([
|
||||
'ssl',
|
||||
]),
|
||||
}),
|
||||
]),
|
||||
'config': dict({
|
||||
'agents': dict({
|
||||
'test.remote': dict({
|
||||
'protected': True,
|
||||
'retention': dict({
|
||||
'copies': None,
|
||||
'days': None,
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
'automatic_backups_configured': True,
|
||||
'create_backup': dict({
|
||||
'agent_ids': list([
|
||||
]),
|
||||
'include_addons': None,
|
||||
'include_all_addons': False,
|
||||
'include_database': True,
|
||||
'include_folders': None,
|
||||
'name': None,
|
||||
'password': 'hunter2',
|
||||
}),
|
||||
'last_attempted_automatic_backup': None,
|
||||
'last_completed_automatic_backup': None,
|
||||
'retention': dict({
|
||||
'copies': None,
|
||||
'days': None,
|
||||
}),
|
||||
'schedule': dict({
|
||||
'days': list([
|
||||
]),
|
||||
'recurrence': 'never',
|
||||
'state': 'never',
|
||||
'time': None,
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
'key': 'backup',
|
||||
'minor_version': 8,
|
||||
'version': 1,
|
||||
})
|
||||
# ---
|
||||
# name: test_store_migration[store_data7].1
|
||||
dict({
|
||||
'data': dict({
|
||||
'backups': list([
|
||||
dict({
|
||||
'backup_id': 'abc123',
|
||||
'failed_addons': list([
|
||||
dict({
|
||||
'name': 'Test add-on',
|
||||
'slug': 'test_addon',
|
||||
'version': '1.0.0',
|
||||
}),
|
||||
]),
|
||||
'failed_agent_ids': list([
|
||||
'test.remote',
|
||||
]),
|
||||
'failed_folders': list([
|
||||
'ssl',
|
||||
]),
|
||||
}),
|
||||
]),
|
||||
'config': dict({
|
||||
'agents': dict({
|
||||
'test.remote': dict({
|
||||
'protected': True,
|
||||
'retention': dict({
|
||||
'copies': None,
|
||||
'days': None,
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
'automatic_backups_configured': True,
|
||||
'create_backup': dict({
|
||||
'agent_ids': list([
|
||||
'test-agent',
|
||||
]),
|
||||
'include_addons': None,
|
||||
'include_all_addons': False,
|
||||
'include_database': True,
|
||||
'include_folders': None,
|
||||
'name': None,
|
||||
'password': 'hunter2',
|
||||
}),
|
||||
'last_attempted_automatic_backup': None,
|
||||
'last_completed_automatic_backup': None,
|
||||
'retention': dict({
|
||||
'copies': None,
|
||||
'days': None,
|
||||
}),
|
||||
'schedule': dict({
|
||||
'days': list([
|
||||
]),
|
||||
'recurrence': 'never',
|
||||
'time': None,
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
'key': 'backup',
|
||||
'minor_version': 8,
|
||||
'version': 1,
|
||||
})
|
||||
# ---
|
||||
|
||||
@@ -1330,7 +1330,7 @@
|
||||
}),
|
||||
}),
|
||||
'key': 'backup',
|
||||
'minor_version': 7,
|
||||
'minor_version': 8,
|
||||
'version': 1,
|
||||
})
|
||||
# ---
|
||||
@@ -1446,7 +1446,7 @@
|
||||
}),
|
||||
}),
|
||||
'key': 'backup',
|
||||
'minor_version': 7,
|
||||
'minor_version': 8,
|
||||
'version': 1,
|
||||
})
|
||||
# ---
|
||||
@@ -1562,7 +1562,7 @@
|
||||
}),
|
||||
}),
|
||||
'key': 'backup',
|
||||
'minor_version': 7,
|
||||
'minor_version': 8,
|
||||
'version': 1,
|
||||
})
|
||||
# ---
|
||||
@@ -1692,7 +1692,7 @@
|
||||
}),
|
||||
}),
|
||||
'key': 'backup',
|
||||
'minor_version': 7,
|
||||
'minor_version': 8,
|
||||
'version': 1,
|
||||
})
|
||||
# ---
|
||||
@@ -1969,7 +1969,7 @@
|
||||
}),
|
||||
}),
|
||||
'key': 'backup',
|
||||
'minor_version': 7,
|
||||
'minor_version': 8,
|
||||
'version': 1,
|
||||
})
|
||||
# ---
|
||||
@@ -2083,7 +2083,7 @@
|
||||
}),
|
||||
}),
|
||||
'key': 'backup',
|
||||
'minor_version': 7,
|
||||
'minor_version': 8,
|
||||
'version': 1,
|
||||
})
|
||||
# ---
|
||||
@@ -2197,7 +2197,7 @@
|
||||
}),
|
||||
}),
|
||||
'key': 'backup',
|
||||
'minor_version': 7,
|
||||
'minor_version': 8,
|
||||
'version': 1,
|
||||
})
|
||||
# ---
|
||||
@@ -2313,7 +2313,7 @@
|
||||
}),
|
||||
}),
|
||||
'key': 'backup',
|
||||
'minor_version': 7,
|
||||
'minor_version': 8,
|
||||
'version': 1,
|
||||
})
|
||||
# ---
|
||||
@@ -2431,7 +2431,7 @@
|
||||
}),
|
||||
}),
|
||||
'key': 'backup',
|
||||
'minor_version': 7,
|
||||
'minor_version': 8,
|
||||
'version': 1,
|
||||
})
|
||||
# ---
|
||||
@@ -2547,7 +2547,7 @@
|
||||
}),
|
||||
}),
|
||||
'key': 'backup',
|
||||
'minor_version': 7,
|
||||
'minor_version': 8,
|
||||
'version': 1,
|
||||
})
|
||||
# ---
|
||||
@@ -2667,7 +2667,7 @@
|
||||
}),
|
||||
}),
|
||||
'key': 'backup',
|
||||
'minor_version': 7,
|
||||
'minor_version': 8,
|
||||
'version': 1,
|
||||
})
|
||||
# ---
|
||||
@@ -2791,7 +2791,7 @@
|
||||
}),
|
||||
}),
|
||||
'key': 'backup',
|
||||
'minor_version': 7,
|
||||
'minor_version': 8,
|
||||
'version': 1,
|
||||
})
|
||||
# ---
|
||||
@@ -2907,7 +2907,7 @@
|
||||
}),
|
||||
}),
|
||||
'key': 'backup',
|
||||
'minor_version': 7,
|
||||
'minor_version': 8,
|
||||
'version': 1,
|
||||
})
|
||||
# ---
|
||||
@@ -3023,7 +3023,7 @@
|
||||
}),
|
||||
}),
|
||||
'key': 'backup',
|
||||
'minor_version': 7,
|
||||
'minor_version': 8,
|
||||
'version': 1,
|
||||
})
|
||||
# ---
|
||||
@@ -3139,7 +3139,7 @@
|
||||
}),
|
||||
}),
|
||||
'key': 'backup',
|
||||
'minor_version': 7,
|
||||
'minor_version': 8,
|
||||
'version': 1,
|
||||
})
|
||||
# ---
|
||||
@@ -3255,7 +3255,7 @@
|
||||
}),
|
||||
}),
|
||||
'key': 'backup',
|
||||
'minor_version': 7,
|
||||
'minor_version': 8,
|
||||
'version': 1,
|
||||
})
|
||||
# ---
|
||||
|
||||
@@ -302,6 +302,57 @@ def mock_delay_save() -> Generator[None]:
|
||||
"minor_version": 7,
|
||||
"version": 1,
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"backups": [
|
||||
{
|
||||
"backup_id": "abc123",
|
||||
"failed_addons": [
|
||||
{
|
||||
"name": "Test add-on",
|
||||
"slug": "test_addon",
|
||||
"version": "1.0.0",
|
||||
}
|
||||
],
|
||||
"failed_agent_ids": ["test.remote"],
|
||||
"failed_folders": ["ssl"],
|
||||
}
|
||||
],
|
||||
"config": {
|
||||
"agents": {
|
||||
"test.remote": {
|
||||
"protected": True,
|
||||
"retention": {"copies": None, "days": None},
|
||||
}
|
||||
},
|
||||
"automatic_backups_configured": True,
|
||||
"create_backup": {
|
||||
"agent_ids": [],
|
||||
"include_addons": None,
|
||||
"include_all_addons": False,
|
||||
"include_database": True,
|
||||
"include_folders": None,
|
||||
"name": None,
|
||||
"password": "hunter2",
|
||||
},
|
||||
"last_attempted_automatic_backup": None,
|
||||
"last_completed_automatic_backup": None,
|
||||
"retention": {
|
||||
"copies": None,
|
||||
"days": None,
|
||||
},
|
||||
"schedule": {
|
||||
"days": [],
|
||||
"recurrence": "never",
|
||||
"state": "never",
|
||||
"time": None,
|
||||
},
|
||||
},
|
||||
},
|
||||
"key": DOMAIN,
|
||||
"minor_version": 8,
|
||||
"version": 1,
|
||||
},
|
||||
],
|
||||
)
|
||||
async def test_store_migration(
|
||||
|
||||
Reference in New Issue
Block a user