From bdeb032fbaca171646d417e7754692de2a4c1516 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Wed, 3 Aug 2022 13:52:02 +0530 Subject: [PATCH] refactor: use separate config key for encryption (#17720) --- frappe/commands/site.py | 8 +++---- frappe/patches.txt | 3 ++- .../patches/v14_0/different_encryption_key.py | 16 ++++++++++++++ frappe/utils/backups.py | 21 ++++++++++++++++--- 4 files changed, 40 insertions(+), 8 deletions(-) create mode 100644 frappe/patches/v14_0/different_encryption_key.py diff --git a/frappe/commands/site.py b/frappe/commands/site.py index e3c7de32a3..ab599be121 100644 --- a/frappe/commands/site.py +++ b/frappe/commands/site.py @@ -142,7 +142,7 @@ def restore( is_partial, validate_database_sql, ) - from frappe.utils.backups import Backup + from frappe.utils.backups import Backup, get_or_generate_backup_encryption_key _backup = Backup(sql_file_path) @@ -171,7 +171,7 @@ def restore( else: click.secho("Encrypted backup file detected. Decrypting using site config.", fg="yellow") - encryption_key = frappe.get_site_config().encryption_key + encryption_key = get_or_generate_backup_encryption_key() _backup.backup_decryption(encryption_key) # Rollback on unsuccessful decryrption @@ -268,7 +268,7 @@ def restore( @pass_context def partial_restore(context, sql_file_path, verbose, encryption_key=None): from frappe.installer import extract_sql_from_archive, partial_restore - from frappe.utils.backups import Backup + from frappe.utils.backups import Backup, get_or_generate_backup_encryption_key if not os.path.exists(sql_file_path): print("Invalid path", sql_file_path) @@ -304,7 +304,7 @@ def partial_restore(context, sql_file_path, verbose, encryption_key=None): else: click.secho("Encrypted backup file detected. Decrypting using site config.", fg="yellow") - key = frappe.get_site_config().encryption_key + key = get_or_generate_backup_encryption_key() _backup.backup_decryption(key) diff --git a/frappe/patches.txt b/frappe/patches.txt index 0dce4b9f71..2f6ebd334a 100644 --- a/frappe/patches.txt +++ b/frappe/patches.txt @@ -208,4 +208,5 @@ frappe.patches.v14_0.update_auto_account_deletion_duration frappe.patches.v14_0.update_integration_request frappe.patches.v14_0.set_document_expiry_default frappe.patches.v14_0.delete_data_migration_tool -frappe.patches.v14_0.set_suspend_email_queue_default \ No newline at end of file +frappe.patches.v14_0.set_suspend_email_queue_default +frappe.patches.v14_0.different_encryption_key diff --git a/frappe/patches/v14_0/different_encryption_key.py b/frappe/patches/v14_0/different_encryption_key.py new file mode 100644 index 0000000000..3b80e15a73 --- /dev/null +++ b/frappe/patches/v14_0/different_encryption_key.py @@ -0,0 +1,16 @@ +import pathlib + +import frappe +from frappe.installer import update_site_config +from frappe.utils.backups import BACKUP_ENCRYPTION_CONFIG_KEY, get_backup_path + + +def execute(): + if frappe.conf.get(BACKUP_ENCRYPTION_CONFIG_KEY): + return + + backup_path = pathlib.Path(get_backup_path()) + encrypted_backups_present = bool(list(backup_path.glob("*-enc*"))) + + if encrypted_backups_present: + update_site_config(BACKUP_ENCRYPTION_CONFIG_KEY, frappe.local.conf.encryption_key) diff --git a/frappe/utils/backups.py b/frappe/utils/backups.py index f5e13c0873..b5722def4f 100644 --- a/frappe/utils/backups.py +++ b/frappe/utils/backups.py @@ -11,12 +11,12 @@ from shutil import which # imports - third party imports import click +from cryptography.fernet import Fernet # imports - module imports import frappe from frappe import conf from frappe.utils import cint, get_file_size, get_url, now, now_datetime -from frappe.utils.password import get_encryption_key # backup variable for backwards compatibility verbose = False @@ -24,6 +24,8 @@ compress = False _verbose = verbose base_tables = ["__Auth", "__global_search", "__UserSettings"] +BACKUP_ENCRYPTION_CONFIG_KEY = "backup_encryption_key" + class BackupGenerator: """ @@ -230,7 +232,7 @@ class BackupGenerator: cmd_string = "gpg --yes --passphrase {passphrase} --pinentry-mode loopback -c {filelocation}" try: command = cmd_string.format( - passphrase=get_encryption_key(), + passphrase=get_or_generate_backup_encryption_key(), filelocation=path, ) @@ -628,7 +630,20 @@ def get_backup_path(): @frappe.whitelist() def get_backup_encryption_key(): frappe.only_for("System Manager") - return frappe.conf.encryption_key + return frappe.conf.get(BACKUP_ENCRYPTION_CONFIG_KEY) + + +def get_or_generate_backup_encryption_key(): + from frappe.installer import update_site_config + + key = frappe.conf.get(BACKUP_ENCRYPTION_CONFIG_KEY) + if key: + return key + + key = Fernet.generate_key().decode() + update_site_config(BACKUP_ENCRYPTION_CONFIG_KEY, key) + + return key class Backup: