Exemple #1
0
 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)
Exemple #2
0
 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)
Exemple #3
0
    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)
Exemple #4
0
    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)
Exemple #5
0
    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)
Exemple #6
0
    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)
Exemple #7
0
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''
Exemple #8
0
    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()
Exemple #9
0
    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()
Exemple #10
0
    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)
Exemple #11
0
    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)
Exemple #12
0
    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[:]
Exemple #13
0
    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
Exemple #14
0
    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
Exemple #15
0
    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)
Exemple #16
0
def _getpwnam(user):
    assert isinstance(user, str)
    if PY3:
        return pwd.getpwnam(user)
    else:
        return pwd.getpwnam(encodefilename(user))
Exemple #17
0
    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)