File 0001-Ensure-that-the-authenticated-users-cant-access-each-other-directories.patch of Package pgadmin4.33332
From 8b236e7bc8238a2b90ae1524eef2ce120f53ad9d Mon Sep 17 00:00:00 2001
From: Aditya Toshniwal <aditya.toshniwal@enterprisedb.com>
Date: Fri, 13 Jan 2023 12:29:21 +0530
Subject: [PATCH] Ensure that the authenticated users can't access each other's
directories and files by providing relative paths. #5734
Rebased by Antonio Larrosa <alarrosa@suse.com> for pgAdmin 4.30
---
web/pgadmin/tools/backup/__init__.py | 41 ++--------
web/pgadmin/tools/import_export/__init__.py | 36 ++-------
.../tools/import_export_servers/__init__.py | 13 +++-
web/pgadmin/tools/restore/__init__.py | 30 ++------
web/pgadmin/utils/__init__.py | 75 ++++++++++++-------
web/yarn.lock | 8 +-
6 files changed, 77 insertions(+), 126 deletions(-)
diff --git a/web/pgadmin/tools/backup/__init__.py b/web/pgadmin/tools/backup/__init__.py
index 0a0567d072..6b27b38aeb 100644
--- a/web/pgadmin/tools/backup/__init__.py
+++ b/web/pgadmin/tools/backup/__init__.py
@@ -19,8 +19,9 @@
from flask_security import login_required, current_user
from pgadmin.misc.bgprocess.processes import BatchProcess, IProcessDesc
from pgadmin.utils import PgAdminModule, get_storage_directory, html, \
#- fs_short_path, document_dir, does_utility_exist, get_server
- fs_short_path, document_dir, does_utility_exist
-from pgadmin.utils.ajax import make_json_response, bad_request
#+ fs_short_path, document_dir, does_utility_exist, get_server, \
+ fs_short_path, document_dir, does_utility_exist, \
+ filename_with_file_manager_path
+from pgadmin.utils.ajax import make_json_response, bad_request, unauthorized
from config import PG_DEFAULT_DRIVER
# from pgadmin.model import Server, SharedServer
from pgadmin.model import Server
@@ -189,40 +190,6 @@ def script():
)
-def filename_with_file_manager_path(_file, create_file=True):
- """
- Args:
- file: File name returned from client file manager
- create_file: Set flag to False when file creation doesn't required
- Returns:
- Filename to use for backup with full path taken from preference
- """
- # Set file manager directory from preference
- storage_dir = get_storage_directory()
- if storage_dir:
- _file = os.path.join(storage_dir, _file.lstrip('/').lstrip('\\'))
- elif not os.path.isabs(_file):
- _file = os.path.join(document_dir(), _file)
-
- def short_filepath():
- short_path = fs_short_path(_file)
- # fs_short_path() function may return empty path on Windows
- # if directory doesn't exists. In that case we strip the last path
- # component and get the short path.
- if os.name == 'nt' and short_path == '':
- base_name = os.path.basename(_file)
- dir_name = os.path.dirname(_file)
- short_path = fs_short_path(dir_name) + '\\' + base_name
- return short_path
-
- if create_file:
- # Touch the file to get the short path of the file on windows.
- with open(_file, 'a'):
- return short_filepath()
-
- return short_filepath()
-
-
def _get_args_params_values(data, conn, backup_obj_type, backup_file, server,
manager):
"""
@@ -367,6 +334,8 @@ def create_backup_objects_job(sid):
try:
backup_file = filename_with_file_manager_path(
data['file'], (data.get('format', '') != 'directory'))
+ except PermissionError as e:
+ return unauthorized(errormsg=str(e))
except Exception as e:
return bad_request(errormsg=str(e))
diff --git a/web/pgadmin/tools/import_export/__init__.py b/web/pgadmin/tools/import_export/__init__.py
index db1e0d2622..6308f9dbfd 100644
--- a/web/pgadmin/tools/import_export/__init__.py
+++ b/web/pgadmin/tools/import_export/__init__.py
@@ -17,8 +17,9 @@
from flask_security import login_required, current_user
from pgadmin.misc.bgprocess.processes import BatchProcess, IProcessDesc
from pgadmin.utils import PgAdminModule, get_storage_directory, html, \
- fs_short_path, document_dir, IS_WIN, does_utility_exist
-from pgadmin.utils.ajax import make_json_response, bad_request
+ fs_short_path, document_dir, IS_WIN, does_utility_exist, \
+ filename_with_file_manager_path
+from pgadmin.utils.ajax import make_json_response, bad_request, unauthorized
from config import PG_DEFAULT_DRIVER
from pgadmin.model import Server
@@ -145,33 +146,6 @@ def script():
)
-def filename_with_file_manager_path(_file, _present=False):
- """
- Args:
- file: File name returned from client file manager
-
- Returns:
- Filename to use for backup with full path taken from preference
- """
- # Set file manager directory from preference
- storage_dir = get_storage_directory()
-
- if storage_dir:
- _file = os.path.join(storage_dir, _file.lstrip('/').lstrip('\\'))
- elif not os.path.isabs(_file):
- _file = os.path.join(document_dir(), _file)
-
- if not _present:
- # Touch the file to get the short path of the file on windows.
- with open(_file, 'a'):
- return fs_short_path(_file)
- else:
- if not os.path.isfile(_file):
- return None
-
- return fs_short_path(_file)
-
-
def _get_ignored_column_list(data, driver, conn):
"""
Get list of ignored columns for import/export.
@@ -297,7 +271,9 @@ def create_import_export_job(sid):
if 'filename' in data:
try:
_file = filename_with_file_manager_path(
- data['filename'], data['is_import'])
+ data['filename'], not data['is_import'])
+ except PermissionError as e:
+ return unauthorized(errormsg=str(e))
except Exception as e:
return bad_request(errormsg=str(e))
#diff --git a/web/pgadmin/tools/import_export_servers/__init__.py b/web/pgadmin/tools/import_export_servers/__init__.py
#index 755507774c..91ec2ac62a 100644
#--- a/web/pgadmin/tools/import_export_servers/__init__.py
#+++ b/web/pgadmin/tools/import_export_servers/__init__.py
#@@ -20,10 +20,11 @@
# from pgadmin.utils import PgAdminModule
# from pgadmin.utils.ajax import bad_request
# from pgadmin.utils.constants import MIMETYPE_APP_JS
#-from pgadmin.utils.ajax import make_json_response, internal_server_error
#+from pgadmin.utils.ajax import make_json_response, internal_server_error, \
#+ unauthorized
# from pgadmin.model import ServerGroup, Server
# from pgadmin.utils import clear_database_servers, dump_database_servers,\
#- load_database_servers, validate_json_data
#+ load_database_servers, validate_json_data, filename_with_file_manager_path
# from urllib.parse import unquote
# from pgadmin.utils.paths import get_storage_directory
#
#@@ -118,6 +119,14 @@ def load_servers():
#
# # retrieve storage directory path
# storage_manager_path = get_storage_directory()
#+
#+ try:
#+ file_path = filename_with_file_manager_path(file_path)
#+ except PermissionError as e:
#+ return unauthorized(errormsg=str(e))
#+ except Exception as e:
#+ return bad_request(errormsg=str(e))
#+
# if storage_manager_path:
# # generate full path of file
# file_path = os.path.join(
diff --git a/web/pgadmin/tools/restore/__init__.py b/web/pgadmin/tools/restore/__init__.py
index 0a242bf847..fc2cb998fb 100644
--- a/web/pgadmin/tools/restore/__init__.py
+++ b/web/pgadmin/tools/restore/__init__.py
@@ -18,8 +18,10 @@
from flask_security import login_required, current_user
from pgadmin.misc.bgprocess.processes import BatchProcess, IProcessDesc
from pgadmin.utils import PgAdminModule, get_storage_directory, html, \
#- fs_short_path, document_dir, does_utility_exist, get_server
- fs_short_path, document_dir, does_utility_exist
-from pgadmin.utils.ajax import make_json_response, bad_request
#+ fs_short_path, document_dir, does_utility_exist, get_server, \
+ fs_short_path, document_dir, does_utility_exist, \
+ filename_with_file_manager_path
+from pgadmin.utils.ajax import make_json_response, bad_request, \
+ internal_server_error
from config import PG_DEFAULT_DRIVER
# from pgadmin.model import Server, SharedServer
from pgadmin.model import Server
@@ -129,28 +131,6 @@ def script():
)
-def filename_with_file_manager_path(_file):
- """
- Args:
- file: File name returned from client file manager
-
- Returns:
- Filename to use for backup with full path taken from preference
- """
- # Set file manager directory from preference
- storage_dir = get_storage_directory()
-
- if storage_dir:
- _file = os.path.join(storage_dir, _file.lstrip('/').lstrip('\\'))
- elif not os.path.isabs(_file):
- _file = os.path.join(document_dir(), _file)
-
- if not os.path.isfile(_file) and not os.path.exists(_file):
- return None
-
- return fs_short_path(_file)
-
-
def _get_create_req_data():
"""
Get data from request for create restore job.
@@ -164,7 +144,7 @@ def _get_create_req_data():
try:
_file = filename_with_file_manager_path(data['file'])
except Exception as e:
- return True, bad_request(errormsg=str(e)), data
+ return True, internal_server_error(errormsg=str(e)), data, None
if _file is None:
return True, make_json_response(
diff --git a/web/pgadmin/utils/__init__.py b/web/pgadmin/utils/__init__.py
index dbca361652..cd86c022fa 100644
--- a/web/pgadmin/utils/__init__.py
+++ b/web/pgadmin/utils/__init__.py
@@ -260,6 +260,45 @@ def get_complete_file_path(file, validate=True):
# return file
return file if os.path.isfile(file) else None
+def filename_with_file_manager_path(_file, create_file=False,
+ skip_permission_check=False):
+ """
+ Args:
+ file: File name returned from client file manager
+ create_file: Set flag to False when file creation doesn't required
+ Returns:
+ Filename to use for backup with full path taken from preference
+ """
+ # Set file manager directory from preference
+ storage_dir = get_storage_directory()
+
+ from pgadmin.misc.file_manager import Filemanager
+ Filemanager.check_access_permission(
+ storage_dir, _file, skip_permission_check)
+ if storage_dir:
+ _file = os.path.join(storage_dir, _file.lstrip('/').lstrip('\\'))
+ elif not os.path.isabs(_file):
+ _file = os.path.join(document_dir(), _file)
+
+ def short_filepath():
+ short_path = fs_short_path(_file)
+ # fs_short_path() function may return empty path on Windows
+ # if directory doesn't exists. In that case we strip the last path
+ # component and get the short path.
+ if os.name == 'nt' and short_path == '':
+ base_name = os.path.basename(_file)
+ dir_name = os.path.dirname(_file)
+ short_path = fs_short_path(dir_name) + '\\' + base_name
+ return short_path
+
+ if create_file:
+ # Touch the file to get the short path of the file on windows.
+ with open(_file, 'a'):
+ return short_filepath()
+
+ return short_filepath()
+
+
def does_utility_exist(file):
"""
This function will check the utility file exists on given path.
#@@ -434,27 +473,12 @@ def dump_database_servers(output_file, selected_servers,
#
# object_dict["Servers"] = server_dict
#
#- # retrieve storage directory path
#- storage_manager_path = None
#- if not from_setup:
#- storage_manager_path = get_storage_directory(user)
#-
#- # generate full path of file
#- file_path = unquote(output_file)
#-
#- from pgadmin.misc.file_manager import Filemanager
# try:
#- Filemanager.check_access_permission(storage_manager_path, file_path,
#- from_setup)
#+ file_path = filename_with_file_manager_path(
#+ unquote(output_file), skip_permission_check=from_setup)
# except Exception as e:
# return _handle_error(str(e), from_setup)
#
#- if storage_manager_path is not None:
#- file_path = os.path.join(
#- storage_manager_path,
#- file_path.lstrip('/').lstrip('\\')
#- )
#-
# # write to file
# file_content = json.dumps(object_dict, indent=4)
# error_str = "Error: {0}"
#@@ -548,19 +572,12 @@ def load_database_servers(input_file, selected_servers,
# if user is None:
# return False, USER_NOT_FOUND % load_user
#
#- # retrieve storage directory path
#- storage_manager_path = None
#- if not from_setup:
#- storage_manager_path = get_storage_directory(user)
#-
# # generate full path of file
#- file_path = unquote(input_file)
#- if storage_manager_path:
#- # generate full path of file
#- file_path = os.path.join(
#- storage_manager_path,
#- file_path.lstrip('/').lstrip('\\')
#- )
#+ try:
#+ file_path = filename_with_file_manager_path(
#+ unquote(input_file), skip_permission_check=from_setup)
#+ except Exception as e:
#+ return _handle_error(str(e), from_setup)
#
# try:
# with open(file_path) as f:
diff --git a/web/yarn.lock b/web/yarn.lock
index 96d52e5a29..df20a984a8 100644
--- a/web/yarn.lock
+++ b/web/yarn.lock
#@@ -8517,9 +8517,9 @@ react-checkbox-tree@^1.7.2:
# nanoid "^3.0.0"
# prop-types "^15.5.8"
#
#-"react-data-grid@git+https://github.com/EnterpriseDB/react-data-grid.git/#200d2f5e02de694e3e9ffbe177c279bc40240fb8":
#+"react-data-grid@git+https://github.com/pgadmin-org/react-data-grid.git/#200d2f5e02de694e3e9ffbe177c279bc40240fb8":
# version "7.0.0-beta.14"
#- resolved "git+https://github.com/EnterpriseDB/react-data-grid.git/#200d2f5e02de694e3e9ffbe177c279bc40240fb8"
#+ resolved "git+https://github.com/pgadmin-org/react-data-grid.git/#200d2f5e02de694e3e9ffbe177c279bc40240fb8"
# dependencies:
# clsx "^1.1.1"
#
@@ -10337,9 +10337,9 @@ watchpack@^2.4.0:
# glob-to-regexp "^0.4.1"
# graceful-fs "^4.1.2"
chokidar "^3.4.1"
watchpack-chokidar2 "^2.0.1"
#-"webcabin-docker@git+https://github.com/EnterpriseDB/wcDocker/#3df8aac825ee2892f4d824de273b779cc6dbcad8":
#+"webcabin-docker@git+https://github.com/pgadmin-org/wcdocker/#3df8aac825ee2892f4d824de273b779cc6dbcad8":
-"webcabin-docker@git+https://github.com/EnterpriseDB/wcDocker/#c4a3398b89588408dc705895675bce7bd7660d36":
+"webcabin-docker@git+https://github.com/pgadmin-org/wcDocker/#c4a3398b89588408dc705895675bce7bd7660d36":
# version "2.2.5"
version "2.2.4-dev"
#- resolved "git+https://github.com/EnterpriseDB/wcDocker/#3df8aac825ee2892f4d824de273b779cc6dbcad8"
#+ resolved "git+https://github.com/pgadmin-org/wcdocker/#3df8aac825ee2892f4d824de273b779cc6dbcad8"
- resolved "git+https://github.com/EnterpriseDB/wcDocker/#c4a3398b89588408dc705895675bce7bd7660d36"
+ resolved "git+https://github.com/pgadmin-org/wcDocker/#c4a3398b89588408dc705895675bce7bd7660d36"
dependencies:
"@fortawesome/fontawesome-free" "^5.14.0"
FileSaver "^0.10.0"