[Config] Prevent symlinked config files being overwritten

If a user keeps the deluge config file under source control and symlinks
to the config files in deluge config dir then when deluge saves config
files it will replace the symlink with actual file.

Using realpath will resolve these symlinks and file will be updated in
the correct location.

Use a temporary file for new config new before moving it to the
resolved location.

Co-authored-by: Calum Lind <calumlind+deluge@gmail.com>
This commit is contained in:
Phil Hudson 2018-10-11 21:58:08 +00:00 committed by Calum Lind
parent 3645feb486
commit c01679de1f
1 changed files with 11 additions and 4 deletions

View File

@ -47,6 +47,7 @@ import os
import shutil
from codecs import getwriter
from io import open
from tempfile import NamedTemporaryFile
import six.moves.cPickle as pickle
@ -475,8 +476,11 @@ class Config(object):
# Save the new config and make sure it's written to disk
try:
log.debug('Saving new config file %s', filename + '.new')
with open(filename + '.new', 'wb') as _file:
with NamedTemporaryFile(
prefix=os.path.basename(filename) + '.', delete=False
) as _file:
filename_tmp = _file.name
log.debug('Saving new config file %s', filename_tmp)
json.dump(self.__version, getwriter('utf8')(_file), **JSON_FORMAT)
json.dump(self.__config, getwriter('utf8')(_file), **JSON_FORMAT)
_file.flush()
@ -485,6 +489,9 @@ class Config(object):
log.error('Error writing new config file: %s', ex)
return False
# Resolve symlinked config files before backing up and saving.
filename = os.path.realpath(filename)
# Make a backup of the old config
try:
log.debug('Backing up old config file to %s.bak', filename)
@ -495,8 +502,8 @@ class Config(object):
# The new config file has been written successfully, so let's move it over
# the existing one.
try:
log.debug('Moving new config file %s to %s..', filename + '.new', filename)
shutil.move(filename + '.new', filename)
log.debug('Moving new config file %s to %s', filename_tmp, filename)
shutil.move(filename_tmp, filename)
except IOError as ex:
log.error('Error moving new config file: %s', ex)
return False