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"
openSUSE Build Service is sponsored by