From 0aa43c683ebcd5e51188b230e82302a0e64f0bb2 Mon Sep 17 00:00:00 2001 From: Erik Johnson Date: Thu, 3 May 2018 08:41:05 -0500 Subject: [PATCH 1/2] Return user paths relative to effective user's homedir Since `os.path.expanduser()` is used to expand the `~` to the home directory, paths which use `~` will always return a path relative to the home directory of the user under which the python process is running. However, if the euid has been changed, this means that these paths will be incorrect, leading to problems when the non-privleged user tries to write to these paths. This commit fixes that issue by attempting to get the username matching the euid, and using that username (e.g. `~user/.cache`) when invoking `os.path.expanduser()`. --- appdirs.py | 77 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 54 insertions(+), 23 deletions(-) diff --git a/appdirs.py b/appdirs.py index f7f8359..374b69e 100644 --- a/appdirs.py +++ b/appdirs.py @@ -20,6 +20,11 @@ import sys import os +try: + import pwd +except ImportError: + pwd = None + PY3 = sys.version_info[0] == 3 if PY3: @@ -41,6 +46,12 @@ system = sys.platform +def _effective_user(): + try: + return pwd.getpwuid(os.geteuid()).pw_name + except Exception: + return '' + def user_data_dir(appname=None, appauthor=None, version=None, roaming=False): r"""Return full path to the user-specific data dir for this application. @@ -84,14 +95,21 @@ def user_data_dir(appname=None, appauthor=None, version=None, roaming=False): path = os.path.join(path, appauthor, appname) else: path = os.path.join(path, appname) - elif system == 'darwin': - path = os.path.expanduser('~/Library/Application Support/') - if appname: - path = os.path.join(path, appname) else: - path = os.getenv('XDG_DATA_HOME', os.path.expanduser("~/.local/share")) - if appname: - path = os.path.join(path, appname) + user = _effective_user() + if system == 'darwin': + path = os.path.expanduser( + '~{0}/Library/Application Support/'.format(user) + ) + if appname: + path = os.path.join(path, appname) + else: + path = os.getenv( + 'XDG_DATA_HOME', + os.path.expanduser('~{0}/.local/share'.format(user)) + ) + if appname: + path = os.path.join(path, appname) if appname and version: path = os.path.join(path, version) return path @@ -194,14 +212,19 @@ def user_config_dir(appname=None, appauthor=None, version=None, roaming=False): """ if system == "win32": path = user_data_dir(appname, appauthor, None, roaming) - elif system == 'darwin': - path = os.path.expanduser('~/Library/Preferences/') - if appname: - path = os.path.join(path, appname) else: - path = os.getenv('XDG_CONFIG_HOME', os.path.expanduser("~/.config")) - if appname: - path = os.path.join(path, appname) + user = _effective_user() + if system == 'darwin': + path = os.path.expanduser('~{0}/Library/Preferences/'.format(user)) + if appname: + path = os.path.join(path, appname) + else: + path = os.getenv( + 'XDG_CONFIG_HOME', + os.path.expanduser('~{0}/.config'.format(user)) + ) + if appname: + path = os.path.join(path, appname) if appname and version: path = os.path.join(path, version) return path @@ -306,14 +329,19 @@ def user_cache_dir(appname=None, appauthor=None, version=None, opinion=True): path = os.path.join(path, appname) if opinion: path = os.path.join(path, "Cache") - elif system == 'darwin': - path = os.path.expanduser('~/Library/Caches') - if appname: - path = os.path.join(path, appname) else: - path = os.getenv('XDG_CACHE_HOME', os.path.expanduser('~/.cache')) - if appname: - path = os.path.join(path, appname) + user = _effective_user() + if system == 'darwin': + path = os.path.expanduser('~{0}/Library/Caches'.format(user)) + if appname: + path = os.path.join(path, appname) + else: + path = os.getenv( + 'XDG_CACHE_HOME', + os.path.expanduser('~{0}/.cache'.format(user)) + ) + if appname: + path = os.path.join(path, appname) if appname and version: path = os.path.join(path, version) return path @@ -353,7 +381,10 @@ def user_state_dir(appname=None, appauthor=None, version=None, roaming=False): if system in ["win32", "darwin"]: path = user_data_dir(appname, appauthor, None, roaming) else: - path = os.getenv('XDG_STATE_HOME', os.path.expanduser("~/.local/state")) + path = os.getenv( + 'XDG_STATE_HOME', + os.path.expanduser('~{0}/.local/state'.format(_effective_user())) + ) if appname: path = os.path.join(path, appname) if appname and version: @@ -395,7 +426,7 @@ def user_log_dir(appname=None, appauthor=None, version=None, opinion=True): """ if system == "darwin": path = os.path.join( - os.path.expanduser('~/Library/Logs'), + os.path.expanduser('~{0}/Library/Logs'.format(_effective_user())), appname) elif system == "win32": path = user_data_dir(appname, appauthor, version) From 1fd0b1943d3aeacb0c7d451d8c15ccce65b6ea61 Mon Sep 17 00:00:00 2001 From: Erik Johnson Date: Mon, 7 May 2018 08:50:58 -0500 Subject: [PATCH 2/2] Recommended style changes --- appdirs.py | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/appdirs.py b/appdirs.py index 374b69e..b2a44bf 100644 --- a/appdirs.py +++ b/appdirs.py @@ -46,13 +46,6 @@ system = sys.platform -def _effective_user(): - try: - return pwd.getpwuid(os.geteuid()).pw_name - except Exception: - return '' - - def user_data_dir(appname=None, appauthor=None, version=None, roaming=False): r"""Return full path to the user-specific data dir for this application. @@ -96,17 +89,18 @@ def user_data_dir(appname=None, appauthor=None, version=None, roaming=False): else: path = os.path.join(path, appname) else: - user = _effective_user() if system == 'darwin': path = os.path.expanduser( - '~{0}/Library/Application Support/'.format(user) + '~{0}/Library/Application Support/'.format(_effective_user()) ) if appname: path = os.path.join(path, appname) else: path = os.getenv( 'XDG_DATA_HOME', - os.path.expanduser('~{0}/.local/share'.format(user)) + os.path.expanduser( + '~{0}/.local/share'.format(_effective_user()) + ) ) if appname: path = os.path.join(path, appname) @@ -213,15 +207,16 @@ def user_config_dir(appname=None, appauthor=None, version=None, roaming=False): if system == "win32": path = user_data_dir(appname, appauthor, None, roaming) else: - user = _effective_user() if system == 'darwin': - path = os.path.expanduser('~{0}/Library/Preferences/'.format(user)) + path = os.path.expanduser( + '~{0}/Library/Preferences/'.format(_effective_user()) + ) if appname: path = os.path.join(path, appname) else: path = os.getenv( 'XDG_CONFIG_HOME', - os.path.expanduser('~{0}/.config'.format(user)) + os.path.expanduser('~{0}/.config'.format(_effective_user())) ) if appname: path = os.path.join(path, appname) @@ -330,15 +325,16 @@ def user_cache_dir(appname=None, appauthor=None, version=None, opinion=True): if opinion: path = os.path.join(path, "Cache") else: - user = _effective_user() if system == 'darwin': - path = os.path.expanduser('~{0}/Library/Caches'.format(user)) + path = os.path.expanduser( + '~{0}/Library/Caches'.format(_effective_user()) + ) if appname: path = os.path.join(path, appname) else: path = os.getenv( 'XDG_CACHE_HOME', - os.path.expanduser('~{0}/.cache'.format(user)) + os.path.expanduser('~{0}/.cache'.format(_effective_user())) ) if appname: path = os.path.join(path, appname) @@ -427,7 +423,8 @@ def user_log_dir(appname=None, appauthor=None, version=None, opinion=True): if system == "darwin": path = os.path.join( os.path.expanduser('~{0}/Library/Logs'.format(_effective_user())), - appname) + appname + ) elif system == "win32": path = user_data_dir(appname, appauthor, version) version = False @@ -491,6 +488,13 @@ def user_log_dir(self): #---- internal support stuff +def _effective_user(): + try: + return pwd.getpwuid(os.geteuid()).pw_name + except Exception: + return '' + + def _get_win_folder_from_registry(csidl_name): """This is a fallback technique at best. I'm not sure if using the registry for this guarantees us the correct answer for all CSIDL_*