diff --git a/web/pgadmin/misc/file_manager/__init__.py b/web/pgadmin/misc/file_manager/__init__.py index 4d8f2c51..6177b195 100644 --- a/web/pgadmin/misc/file_manager/__init__.py +++ b/web/pgadmin/misc/file_manager/__init__.py @@ -16,6 +16,7 @@ import string import sys import time from sys import platform as _platform +import config import simplejson as json from flask import render_template, Response, session, request as req, url_for @@ -246,12 +247,12 @@ class Filemanager(object): { 'Error': gettext('No permission to operate on \ specified path.'), - 'Code': -1 + 'Code': 0 } ) self.dir = get_storage_directory() - if (self.dir is not None and isinstance(self.dir, list)): + if self.dir is not None and isinstance(self.dir, list): self.dir = "" @staticmethod @@ -391,11 +392,11 @@ class Filemanager(object): bitmask >>= 1 if (drive_name != '' and drive_name is not None and drive_name in drives): - return "{0}{1}".format(drive_name, ':/') + return u"{0}{1}".format(drive_name, ':') else: return drives # return drives if no argument is passed except Exception: - return ['C:/'] + return ['C:'] else: return '/' @@ -408,12 +409,24 @@ class Filemanager(object): path = unquote(path) if hasattr(str, 'decode'): path = unquote(path).encode('utf-8').decode('utf-8') + + try: + Filemanager.check_access_permission(dir, path) + except Exception as e: + err_msg = "Error: {0}".format(str(e)) + files = { + 'Code': 0, + 'Error': err_msg + } + return files + files = {} - if (_platform == "win32" and path == '/') and dir is None: + if (_platform == "win32" and (path == '/' or path == '\\'))\ + and dir is None: drives = Filemanager._get_drives() for drive in drives: protected = 0 - path = file_name = "{0}:/".format(drive) + path = file_name = u"{0}:".format(drive) try: drive_size = getDriveSize(path) drive_size_in_units = sizeof_fmt(drive_size) @@ -452,7 +465,7 @@ class Filemanager(object): system_path = os.path.join(os.path.join(orig_path, f)) # continue if file/folder is hidden - if (is_folder_hidden(system_path) or f.startswith('.')): + if is_folder_hidden(system_path) or f.startswith('.'): continue if hasattr(str, 'decode'): @@ -473,7 +486,7 @@ class Filemanager(object): if files_only == 'true': continue file_extension = str('dir') - user_path = "{0}/".format(user_path) + user_path = u"{0}/".format(user_path) else: # filter files based on file_type if file_type is not None and file_type != "*": @@ -502,10 +515,55 @@ class Filemanager(object): err_msg = "Error: {0}".format(e) files = { 'Code': 0, - 'err_msg': err_msg + 'Error': err_msg } return files + @staticmethod + def check_access_permission(dir, path): + if dir is None: + dir = "" + orig_path = Filemanager.get_abs_path(dir, path) + + # This translates path with relative path notations like ./ and ../ to + # absolute path. + orig_path = os.path.abspath(orig_path) + + # Do not allow user to access outside his storage dir in server mode. + if config.SERVER_MODE is True and not orig_path.startswith(dir): + raise Exception( + gettext(u"Access denied ({})".format(orig_path))) + return True + + @staticmethod + def get_abs_path(dir, path): + + if path.startswith('\\\\'): + return u"{}".format(path) + + if path == '/' or path == '\\': + if _platform == 'win32': + if dir.endswith('\\'): + return u"{}".format(dir) + else: + return u"{}{}".format(dir, '\\') + else: + if dir.endswith('/'): + return u"{}".format(dir) + else: + return u"{}{}".format(dir, '/') + + if dir.endswith('/') or dir.endswith('\\'): + if path.startswith('/') or path.startswith('\\'): + return u"{}{}".format(dir[:-1], path) + else: + return u"{}{}".format(dir, path) + else: + if path.startswith('/') or path.startswith('\\'): + return u"{}{}".format(dir, path) + else: + return u"{}/{}".format(dir, path) + def validate_request(self, capability): """ It validates the capability with the capabilities @@ -525,13 +583,35 @@ class Filemanager(object): if self.dir is None: self.dir = "" orig_path = u"{0}{1}".format(self.dir, path) + + try: + Filemanager.check_access_permission(self.dir, path) + except Exception as e: + thefile = { + 'Filename': split_path(path)[-1], + 'FileType': '', + 'Path': path, + 'Error': gettext("Error: {0}".format(str(e))), + 'Code': 0, + 'Info': '', + 'Properties': { + 'Date Created': '', + 'Date Modified': '', + 'Width': '', + 'Height': '', + 'Size': '' + } + } + return thefile + user_dir = path thefile = { 'Filename': split_path(orig_path)[-1], - 'File Type': '', + 'FileType': '', 'Path': user_dir, 'Error': '', - 'Code': 0, + 'Code': 1, + 'Info': '', 'Properties': { 'Date Created': '', 'Date Modified': '', @@ -542,13 +622,16 @@ class Filemanager(object): } if not path_exists(orig_path): - thefile['Error'] = gettext('File does not exist.') - return (encode_json(thefile), None, 'application/json') - - if split_path(user_dir)[-1] == '/': - thefile['File Type'] = 'Directory' + thefile['Error'] = gettext("'{}' file does not exist.".format( + split_path(orig_path)[-1])) + thefile['Code'] = -1 + return thefile + + if split_path(user_dir)[-1] == '/'\ + or os.path.isfile(orig_path) is False: + thefile['FileType'] = 'Directory' else: - thefile['File Type'] = splitext(user_dir) + thefile['FileType'] = splitext(user_dir) created = time.ctime(os.path.getctime(orig_path)) modified = time.ctime(os.path.getmtime(orig_path)) @@ -575,10 +658,21 @@ class Filemanager(object): if not self.validate_request('rename'): return { 'Error': gettext('Not allowed'), - 'Code': 1 + 'Code': 0 } dir = self.dir if self.dir is not None else '' + + try: + Filemanager.check_access_permission(dir, old) + Filemanager.check_access_permission(dir, new) + except Exception as e: + res = { + 'Error': gettext("Error: {0}".format(str(e))), + 'Code': 0 + } + return res + # check if it's dir if old[-1] == '/': old = old[:-1] @@ -593,7 +687,6 @@ class Filemanager(object): if not path[-1] == '/': path += '/' - # newname = encode_urlpath(new) newname = new if hasattr(str, 'decode'): newname = new.encode('utf-8').decode('utf-8') @@ -607,8 +700,8 @@ class Filemanager(object): code = 1 try: os.rename(oldpath_sys, newpath_sys) - code = 0 except Exception as e: + code = 0 error_msg = "{0} {1}".format( gettext('There was an error renaming the file:'), str(e)) @@ -631,23 +724,31 @@ class Filemanager(object): if not self.validate_request('delete'): return { 'Error': gettext('Not allowed'), - 'Code': 1 + 'Code': 0 } dir = self.dir if self.dir is not None else '' path = path.encode('utf-8').decode('utf-8') if hasattr(str, 'decode') else path orig_path = u"{0}{1}".format(dir, path) + try: + Filemanager.check_access_permission(dir, path) + except Exception as e: + res = { + 'Error': gettext("Error: {0}".format(str(e))), + 'Code': 0 + } + return res + err_msg = '' code = 1 try: if os.path.isdir(orig_path): os.rmdir(orig_path) - code = 0 else: os.remove(orig_path) - code = 0 except Exception as e: + code = 0 err_msg = "Error: {0}".format(e.strerror) result = { @@ -665,7 +766,7 @@ class Filemanager(object): if not self.validate_request('upload'): return { 'Error': gettext('Not allowed'), - 'Code': 1 + 'Code': 0 } dir = self.dir if self.dir is not None else '' @@ -680,14 +781,23 @@ class Filemanager(object): path = req.form.get('currentpath').encode('utf-8').decode('utf-8') file_name = file_obj.filename.encode('utf-8').decode('utf-8') orig_path = u"{0}{1}".format(dir, path) - newName = u'{0}{1}'.format(orig_path, file_name) + newName = u"{0}{1}".format(orig_path, file_name) with open(newName, 'wb') as f: f.write(file_obj.read()) - code = 0 except Exception as e: + code = 0 err_msg = "Error: {0}".format(e.strerror) + try: + Filemanager.check_access_permission(dir, path) + except Exception as e: + res = { + 'Error': gettext("Error: {0}".format(str(e))), + 'Code': 0 + } + return res + result = { 'Path': path, 'Name': newName, @@ -707,17 +817,21 @@ class Filemanager(object): name = unquote(name) path = unquote(path) if hasattr(str, 'decode'): - name = unquote(name).encode('utf-8') - path = unquote(path).encode('utf-8') + name = name.encode('utf-8').decode('utf-8') + path = path.encode('utf-8').decode('utf-8') try: - orig_path = "{0}{1}".format(dir, path) - newName = '{0}{1}'.format(orig_path, name) - if os.path.exists(newName): + orig_path = u"{0}{1}".format(dir, path) + Filemanager.check_access_permission(dir, u"{}{}".format(path, name)) + + newName = u"{0}{1}".format(orig_path, name) + if not os.path.exists(newName): code = 0 - else: - code = 1 except Exception as e: - err_msg = "Error: {0}".format(e.strerror) + code = 0 + if hasattr(e, 'strerror'): + err_msg = "Error: {0}".format(e.strerror) + else: + err_msg = "Error: {0}".format(str(e)) result = { 'Path': path, @@ -754,7 +868,7 @@ class Filemanager(object): if not self.validate_request('create'): return { 'Error': gettext('Not allowed'), - 'Code': 1 + 'Code': 0 } dir = self.dir if self.dir is not None else '' @@ -762,6 +876,16 @@ class Filemanager(object): if hasattr(str, 'decode'): newName = name.encode('utf-8') + try: + Filemanager.check_access_permission(dir, u"{}{}".format( + path, newName)) + except Exception as e: + res = { + 'Error': gettext("Error: {0}".format(str(e))), + 'Code': 0 + } + return res + if dir != "": if hasattr(str, 'decode'): newPath = dir + '/' + path + newName.decode('utf-8') + '/' @@ -778,15 +902,15 @@ class Filemanager(object): if not path_exists(newPath): try: os.mkdir(newPath) - code = 0 except Exception as e: + code = 0 err_msg = "Error: {0}".format(e.strerror) else: newPath, newName = self.getNewName(dir, path, newName) try: os.mkdir(newPath) - code = 0 except Exception as e: + code = 0 err_msg = "Error: {0}".format(e.strerror) result = { @@ -805,15 +929,25 @@ class Filemanager(object): if not self.validate_request('download'): return { 'Error': gettext('Not allowed'), - 'Code': 1 + 'Code': 0 } dir = self.dir if self.dir is not None else '' + if hasattr(str, 'decode'): path = path.encode('utf-8') orig_path = u"{0}{1}".format(dir, path.decode('utf-8')) else: - orig_path = "{0}{1}".format(dir, path) + orig_path = u"{0}{1}".format(dir, path) + + try: + Filemanager.check_access_permission(dir, u"{}{}".format( + path, path)) + except Exception as e: + resp = Response(gettext("Error: {0}".format(str(e)))) + resp.headers['Content-Disposition'] = 'attachment; filename=' + name + return resp + name = path.split('/')[-1] content = open(orig_path, 'rb') resp = Response(content) diff --git a/web/pgadmin/misc/file_manager/static/css/file_manager.css b/web/pgadmin/misc/file_manager/static/css/file_manager.css index ea502ac9..56d9c389 100755 --- a/web/pgadmin/misc/file_manager/static/css/file_manager.css +++ b/web/pgadmin/misc/file_manager/static/css/file_manager.css @@ -15,19 +15,17 @@ top: 35px; } -#uploader h1 { +#uploader .input-path { font-size: 14px; margin: 0; - margin-left: 5px; padding: 0; display: block; float: left; text-align: left; - line-height:1.9em; - max-width: 367px; + line-height:1.6em; + width: calc(100% - 72px); text-overflow: ellipsis; overflow: hidden; - color: #999; } #uploader h1 b { diff --git a/web/pgadmin/misc/file_manager/templates/file_manager/index.html b/web/pgadmin/misc/file_manager/templates/file_manager/index.html index 197386fc..992fe5d2 100755 --- a/web/pgadmin/misc/file_manager/templates/file_manager/index.html +++ b/web/pgadmin/misc/file_manager/templates/file_manager/index.html @@ -5,13 +5,14 @@