def get_repo(self, name): """ Return the repository identified as `name`. `name` may be a bytes string or unicode string. """ assert isinstance(name, str) or isinstance(name, bytes) if isinstance(name, str): name = encodefilename(name) name = normpath(name) for r in self._db.get_repos(self._username): if name == normpath(encodefilename(r)): return RepoObject(self._db, self._username, r) raise KeyError(name)
def __init__(self, user_root, path, encoding=FS_ENCODING): if isinstance(user_root, str): user_root = encodefilename(user_root) if isinstance(path, str): path = encodefilename(path) assert isinstance(user_root, bytes) assert isinstance(path, bytes) self._encoding = encodings.search_function(encoding) assert self._encoding self.path = path.strip(b"/") self.full_path = os.path.realpath(os.path.join(user_root, self.path)) # The location of rdiff-backup-data directory. self._data_path = os.path.join(self.full_path, RDIFF_BACKUP_DATA) assert isinstance(self._data_path, bytes) self._increment_path = os.path.join(self._data_path, INCREMENTS)
def get_path(self, path): """Return a new instance of DirEntry to represent the given path.""" if isinstance(path, str): path = encodefilename(path) path = os.path.normpath(path.strip(b"/")) # Get if the path request is the root path. if path == b'.': return DirEntry(self, b'', True, []) # Remove access to rdiff-backup-data directory. if path.startswith(RDIFF_BACKUP_DATA): raise DoesNotExistError(path) # Resolve symlink to make sure we do not leave the repo # and to break symlink loops. p = os.path.realpath(os.path.join(self.full_path, path)) if not p.startswith(self.full_path): raise SymLinkAccessDeniedError(path) path = os.path.relpath(p, self.full_path) # Check if path exists or has increment. If not raise an exception. exists = os.path.exists(p) fn = os.path.basename(p) increments = [ e for e in self._get_increment_entries(os.path.dirname(path)) if e.filename == fn ] if not exists and not increments: logger.error("path [%r] doesn't exists", path) raise DoesNotExistError(path) # Create a directory entry. return DirEntry(self, path, exists, increments)
def validate_user_path(self, path_b): ''' Takes a path relative to the user's root dir and validates that it is valid and within the user's root. Uses bytes path to avoid any data lost in encoding/decoding. ''' assert isinstance(path_b, bytes) # Add a ending slash (/) to avoid matching wrong repo. Ref #56 path_b = normpath(path_b) # NOTE: a blank path is allowed, since the user root directory might be # a repository. logger.debug("checking user access to path %r", path_b) # Get reference to user repos (as bytes) user_repos = [ normpath(encodefilename(r)) for r in self.app.currentuser.repos] # Check if any of the repos matches the given path. repo_b = next(( user_repo for user_repo in user_repos if path_b.startswith(user_repo)), None) if repo_b is None: # No repo matches logger.error("user doesn't have access to [%r]", path_b) raise DoesNotExistError(path_b) # Get reference to user_root user_root_b = encodefilename(self.app.currentuser.user_root) # Get reference to the repository (this ensure the repository does # exists and is valid.) repo_obj = RdiffRepo(user_root_b, repo_b) # Get reference to the path. path_b = path_b[len(repo_b):] path_obj = repo_obj.get_path(path_b) return (repo_obj, path_obj)
def validate_user_path(self, path_b): ''' Takes a path relative to the user's root dir and validates that it is valid and within the user's root. Uses bytes path to avoid any data lost in encoding/decoding. ''' assert isinstance(path_b, bytes) # Add a ending slash (/) to avoid matching wrong repo. Ref #56 path_b = normpath(path_b) # NOTE: a blank path is allowed, since the user root directory might be # a repository. logger.debug("checking user access to path %r", path_b) # Get reference to user repos (as bytes) user_repos = [ normpath(encodefilename(r)) for r in self.app.currentuser.repos ] # Check if any of the repos matches the given path. repo_b = next( (user_repo for user_repo in user_repos if path_b.startswith(user_repo)), None) if repo_b is None: # No repo matches logger.error("user doesn't have access to [%r]", path_b) raise DoesNotExistError(path_b) # Get reference to user_root user_root_b = encodefilename(self.app.currentuser.user_root) # Get reference to the repository (this ensure the repository does # exists and is valid.) repo_obj = RdiffRepo(user_root_b, repo_b) # Get reference to the path. path_b = path_b[len(repo_b):] path_obj = repo_obj.get_path(path_b) return (repo_obj, path_obj)
def split_path(path): "Split the given path into <username> / <path>" # First part is the username assert path if isinstance(path, str): path = encodefilename(path) path = path.strip(b'/') if b'/' in path: username, path = path.split(b'/', 1) return username.decode('utf-8'), path else: return path.decode('utf-8'), b''
def __init__(self, user_root, path): if isinstance(user_root, str): user_root = encodefilename(user_root) if isinstance(path, str): path = encodefilename(path) assert isinstance(user_root, bytes) assert isinstance(path, bytes) self._encoding = encodings.search_function(FS_ENCODING) assert self._encoding self.path = path.strip(b"/") self.full_path = os.path.realpath(os.path.join(user_root, self.path)) # The location of rdiff-backup-data directory. self._data_path = os.path.join(self.full_path, RDIFF_BACKUP_DATA) assert isinstance(self._data_path, bytes) self._increment_path = os.path.join(self._data_path, INCREMENTS) self._hint_file = os.path.join(self._data_path, RDIFFWEB_CONF) # Check if the object is valid. self._check() # Check if the repository has hint for rdiffweb. self._load_hints()
def __init__(self, user_root, path): if isinstance(user_root, str): user_root = encodefilename(user_root) if isinstance(path, str): path = encodefilename(path) assert isinstance(user_root, bytes) assert isinstance(path, bytes) self.encoding = encodings.search_function(FS_ENCODING) assert self.encoding self.user_root = user_root.rstrip(b"/") self.path = path.strip(b"/") self.repo_root = os.path.join(self.user_root, self.path) self.root_path = RdiffPath(weakref.proxy(self)) # The location of rdiff-backup-data directory. self.data_path = os.path.join(self.repo_root, RDIFF_BACKUP_DATA) assert isinstance(self.data_path, bytes) # Check if the object is valid. self._check() # Check if the repository has hint for rdiffweb. self._load_hints()
def get_repo(self, name): """ Return the repository identified as `name`. `name` may be a bytes string or unicode string. """ username, name = split_path(name) # Check if user has permissions to access this path if username != self._username and not self.is_admin: raise AccessDeniedError(name) name = normpath(name) for r in self._db.get_repos(username): if name == normpath(encodefilename(r)): user_obj = self if username == self._username else UserObject( self._userdb, self._db, username) return RepoObject(user_obj, r) raise DoesNotExistError(name)
def get_repo_path(self, path): """ Return a the repository identified by the given `path`. """ username, path = split_path(path) # Check if user has permissions to access this path if username != self._username and not self.is_admin: raise AccessDeniedError(path) path = normpath(path) for r in self._db.get_repos(username): repo = normpath(encodefilename(r)) if path.startswith(repo): user_obj = self if username == self._username else UserObject( self._userdb, self._db, username) repo_obj = RepoObject(user_obj, r) path_obj = repo_obj.get_path(path[len(repo):]) return (repo_obj, path_obj) raise DoesNotExistError(path)
def update_repos(self): """ Refresh the users repositories. """ def _onerror(error): logger.error('error updating user [%s] repos' % self.username, exc_info=1) user_root = encodefilename(self.user_root) for root, dirs, unused_files in os.walk(user_root, _onerror): for name in dirs: if name == b'rdiff-backup-data': repopath = os.path.relpath(root, start=user_root) # Handle special scenario when the repo is the user_root repopath = b'' if repopath == b'.' else repopath try: self.get_repo(repopath) except DoesNotExistError: self.add_repo(repopath) if root.count(SEP) - user_root.count(SEP) >= MAX_DEPTH: del dirs[:]
def _get_parms_for_page(self): """ Build the params for the locations templates. """ # Get user's locations. user_root = self.app.currentuser.user_root user_repos = self.app.currentuser.repos repos = [] for user_repo in user_repos: try: # Get reference to a repo object repo_obj = librdiff.RdiffRepo(user_root, user_repo) path = repo_obj.path name = repo_obj.display_name status = repo_obj.status last_backup_date = repo_obj.last_backup_date except librdiff.FileError: logger.exception("invalid user path %s" % user_repo) path = encodefilename(user_repo.strip('/')) name = user_repo.strip('/') status = ( 'failed', _('The repository cannot be found or is badly damaged.')) last_backup_date = 0 # Create an entry to represent the repository repos.append({ "path": path, "name_split": name.strip('/').split('/'), "last_backup_date": last_backup_date, 'status': status, }) params = { "repos": repos, "templates_before_content": list(), } # Return the complete list of params. return params
def _get_parms_for_page(self): """ Build the params for the locations templates. """ # Get user's locations. user_root = self.app.currentuser.user_root user_repos = self.app.currentuser.repos repos = [] for user_repo in user_repos: try: # Get reference to a repo object repo_obj = librdiff.RdiffRepo(user_root, user_repo) path = repo_obj.path name = repo_obj.display_name status = repo_obj.status last_backup_date = repo_obj.last_backup_date except librdiff.FileError: logger.exception("invalid user path %s" % user_repo) path = encodefilename(user_repo.strip('/')) name = user_repo.strip('/') status = ('failed', _('The repository cannot be found or is badly damaged.')) last_backup_date = 0 # Create an entry to represent the repository repos.append({ "path": path, "name_split": name.strip('/').split('/'), "last_backup_date": last_backup_date, 'status': status, }) params = { "repos": repos, "templates_before_content": list(), } # Return the complete list of params. return params
def validate_user_path(self, path_b): ''' Takes a path relative to the user's root dir and validates that it is valid and within the user's root. Uses bytes path to avoid any data lost in encoding/decoding. ''' assert isinstance(path_b, bytes) # Add a ending slash (/) to avoid matching wrong repo. Ref #56 path_b = normpath(path_b) # NOTE: a blank path is allowed, since the user root directory might be # a repository. logger.debug("checking user access to path %r", path_b) # Get reference to user repos (as bytes) user_repos = [ normpath(encodefilename(r)) for r in self.app.currentuser.repos] # Check if any of the repos matches the given path. repo_b = next(( user_repo for user_repo in user_repos if path_b.startswith(user_repo)), None) if repo_b is None: # No repo matches logger.error("user doesn't have access to [%r]", path_b) raise cherrypy.HTTPError(404) # Get reference to user_root user_root_b = encodefilename(self.app.currentuser.user_root) # Check path vs real path value full_path_b = os.path.join(user_root_b, path_b.lstrip(b'/')).rstrip(b"/") real_path_b = os.path.realpath(full_path_b).rstrip(b"/") if full_path_b != real_path_b: # We can safely assume the realpath contains a symbolic link. If # the symbolic link is valid, we display the content of the "real" # path. if real_path_b.startswith(os.path.join(user_root_b, repo_b)): path_b = os.path.relpath(real_path_b, user_root_b) else: logger.warning("access is denied [%r] vs [%r]", full_path_b, real_path_b) raise cherrypy.HTTPError(404) try: # Get reference to the repository (this ensure the repository does # exists and is valid.) repo_obj = RdiffRepo(user_root_b, repo_b) # Get reference to the path. path_b = path_b[len(repo_b):] path_obj = repo_obj.get_path(path_b) return (repo_obj, path_obj) except AccessDeniedError as e: logger.warning("access is denied", exc_info=1) raise cherrypy.HTTPError(404) except DoesNotExistError as e: logger.warning("doesn't exists", exc_info=1) raise cherrypy.HTTPError(404)
def _getpwnam(user): assert isinstance(user, str) if PY3: return pwd.getpwnam(user) else: return pwd.getpwnam(encodefilename(user))
def validate_user_path(self, path_b): ''' Takes a path relative to the user's root dir and validates that it is valid and within the user's root. Uses bytes path to avoid any data lost in encoding/decoding. ''' assert isinstance(path_b, bytes) # Add a ending slash (/) to avoid matching wrong repo. Ref #56 path_b = normpath(path_b) # NOTE: a blank path is allowed, since the user root directory might be # a repository. logger.debug("checking user access to path %r", path_b) # Get reference to user repos (as bytes) user_repos = [ normpath(encodefilename(r)) for r in self.app.currentuser.repos ] # Check if any of the repos matches the given path. repo_b = next( (user_repo for user_repo in user_repos if path_b.startswith(user_repo)), None) if repo_b is None: # No repo matches logger.error("user doesn't have access to [%r]", path_b) raise cherrypy.HTTPError(404) # Get reference to user_root user_root_b = encodefilename(self.app.currentuser.user_root) # Check path vs real path value full_path_b = os.path.join(user_root_b, path_b.lstrip(b'/')).rstrip(b"/") real_path_b = os.path.realpath(full_path_b).rstrip(b"/") if full_path_b != real_path_b: # We can safely assume the realpath contains a symbolic link. If # the symbolic link is valid, we display the content of the "real" # path. if real_path_b.startswith(os.path.join(user_root_b, repo_b)): path_b = os.path.relpath(real_path_b, user_root_b) else: logger.warning("access is denied [%r] vs [%r]", full_path_b, real_path_b) raise cherrypy.HTTPError(404) try: # Get reference to the repository (this ensure the repository does # exists and is valid.) repo_obj = RdiffRepo(user_root_b, repo_b) # Get reference to the path. path_b = path_b[len(repo_b):] path_obj = repo_obj.get_path(path_b) return (repo_obj, path_obj) except AccessDeniedError as e: logger.warning("access is denied", exc_info=1) raise cherrypy.HTTPError(404) except DoesNotExistError as e: logger.warning("doesn't exists", exc_info=1) raise cherrypy.HTTPError(404)