From 9a16e20fa9055dc07ef590b9a8c1459937da6999 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Wed, 18 Feb 2026 16:48:09 -0800 Subject: [PATCH] letsencrypt: When copying certificate reset the umask reliably - When there is an error writing to certificate files, the umask is not reset properly. Fix this my using umask context manager from action utils. This could be core reason behind: #2564. Tests: - Changing the domain name creates the file /var/lib/quassel/quasselCert.pem with the proper permissions of 0o600. If in Quassel app's Let's Encrypt component the certificate file path is changed, then two files are created on domain name change. Private key is created with 0o600 permissions and certificate file is created with 0o644 permissions. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/modules/letsencrypt/privileged.py | 26 +++++++++++------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/plinth/modules/letsencrypt/privileged.py b/plinth/modules/letsencrypt/privileged.py index f96184cf2..6c673f2f8 100644 --- a/plinth/modules/letsencrypt/privileged.py +++ b/plinth/modules/letsencrypt/privileged.py @@ -160,21 +160,19 @@ def copy_certificate(managing_app: str, source_private_key: str, certificate_path.parent.mkdir(mode=0o755, parents=True, exist_ok=True) # Private key is only accessible to the user owner - old_mask = os.umask(0o177) - shutil.copyfile(source_private_key_path, private_key_path) + with action_utils.umask(0o177): + shutil.copyfile(source_private_key_path, private_key_path) - if certificate_path != private_key_path: - # Certificate is only writable by the user owner - os.umask(0o133) - shutil.copyfile(source_certificate_path, certificate_path) - else: - # If private key and certificate are the same file, append one after - # the other. - source_certificate_bytes = source_certificate_path.read_bytes() - with private_key_path.open(mode='a+b') as file_handle: - file_handle.write(source_certificate_bytes) - - os.umask(old_mask) + if certificate_path != private_key_path: + # Certificate is only writable by the user owner + with action_utils.umask(0o133): + shutil.copyfile(source_certificate_path, certificate_path) + else: + # If private key and certificate are the same file, append one + # after the other. + source_certificate_bytes = source_certificate_path.read_bytes() + with private_key_path.open(mode='a+b') as file_handle: + file_handle.write(source_certificate_bytes) shutil.chown(certificate_path, user=user_owner, group=group_owner) shutil.chown(private_key_path, user=user_owner, group=group_owner)