def _get_parms_for_page(self): user_root = self.getUserDB().get_root_dir(self.getUsername()) user_root_b = encode_s(user_root) user_repos = self.getUserDB().get_repos(self.getUsername()) repoList = [] for user_repo in user_repos: try: # Get reference to a repo object repo_obj = librdiff.RdiffRepo(user_root_b, encode_s(user_repo)) path = repo_obj.path name = repo_obj.display_name in_progress = repo_obj.in_progress last_backup_date = repo_obj.last_backup_date failed = False except librdiff.FileError: logging.exception("invalid user path %s" % user_repo) path = encode_s(user_repo) name = user_repo in_progress = False last_backup_date = 0 failed = True repoList.append({"path": path, "name": name, "last_backup_date": last_backup_date, 'in_progress': in_progress, 'failed': failed}) return {"repos": repoList}
def check_user_exists(l, r): if len(r) != 1: raise ValueError("user [%s] not found" % username) # Bind using the user credentials. Throws an exception in case of # error. l.simple_bind_s(r[0][0], encode_s(old_password)) l.passwd_s(r[0][0], encode_s(old_password), encode_s(password)) l.unbind_s() logger.info("password for user [%s] is updated in LDAP" % username)
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''' assert isinstance(path_b, str) # Add a ending slash (/) to avoid matching wrong repo. Ref #56 path_b = path_b.strip(b'/') + b'/' # NOTE: a blank path is allowed, since the user root directory might be # a repository. logger.debug("check user access to path [%s]" % decode_s(path_b, 'replace')) # Get reference to user repos user_repos = self.app.currentuser.repos # Check if any of the repos matches the given path. user_repos_matches = [ encode_s(user_repo).strip(b'/') for user_repo in user_repos if path_b.startswith(encode_s(user_repo).strip(b'/') + b'/')] if not user_repos_matches: # No repo matches logger.error("user doesn't have access to [%s]" % decode_s(path_b, 'replace')) raise librdiff.AccessDeniedError repo_b = user_repos_matches[0] # Get reference to user_root user_root_b = encode_s(self.app.currentuser.root_dir) # Check path vs real path value full_path_b = os.path.join(user_root_b, path_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.warn("access is denied [%s] vs [%s]" % ( decode_s(full_path_b, 'replace'), decode_s(real_path_b, 'replace'))) raise librdiff.AccessDeniedError # Get reference to the repository (this ensure the repository does # exists and is valid.) repo_obj = librdiff.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""" assert isinstance(path_b, str) path_b = path_b.strip(b"/") + b"/" # NOTE: a blank path is allowed, since the user root directory might be # a repository. logger.debug("check user access to path [%s]" % decode_s(path_b, "replace")) # Get reference to user repos user_repos = self.getUserDB().get_repos(self.getUsername()) # Check if any of the repos matches the given path. user_repos_matches = filter(lambda x: path_b.startswith(encode_s(x).strip(b"/") + b"/"), user_repos) if not user_repos_matches: # No repo matches logger.error("user doesn't have access to [%s]" % decode_s(path_b, "replace")) raise librdiff.AccessDeniedError repo_b = encode_s(user_repos_matches[0]).strip(b"/") # Get reference to user_root user_root = self.getUserDB().get_root_dir(self.getUsername()) user_root_b = encode_s(user_root) # Check path vs real path value full_path_b = os.path.join(user_root_b, path_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.warn( "access is denied [%s] vs [%s]" % (decode_s(full_path_b, "replace"), decode_s(real_path_b, "replace")) ) raise librdiff.AccessDeniedError # Get reference to the repository (this ensure the repository does # exists and is valid.) repo_obj = librdiff.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 restore(self, name, restore_date, use_zip): """Used to restore the given file located in this path.""" assert isinstance(name, str) assert isinstance(restore_date, rdw_helpers.rdwTime) name = name.lstrip(b"/") # Determine the file name to be restore (from rdiff-backup # point of view). file_to_restore = os.path.join(self.full_path, name) file_to_restore = self.repo.unquote(file_to_restore) # Convert the date into epoch. date_epoch = str(restore_date.getSeconds()) # Define a location where to restore the data if name == b"" and self.path == b"": filename = b"root" if self.path != b"": filename = os.path.basename(self.path) if name != b"": filename = name # Generate a temporary location used to restore data. tempdir = rdw_helpers.encode_s(rdw_config.get_config("tempdir", default=None)) output = os.path.join(tempfile.mkdtemp(dir=tempdir), filename) # Execute rdiff-backup to restore the data. logger.info(b"execute rdiff-backup --restore-as-of=%s '%s' '%s'" % (date_epoch, file_to_restore, output)) results = self._execute( b"rdiff-backup", b"--restore-as-of=" + date_epoch, file_to_restore, output) # Check the result if results['exitCode'] != 0 or not os.access(output, os.F_OK): error = results['stderr'] if not error: error = '''rdiff-backup claimed success, but did not restore anything. This indicates a bug in rdiffweb. Please report this to a developer.''' raise UnknownError('unable to restore!\n' + error) # The path restored is a directory and need to be archived using zip # or tar if os.path.isdir(output): output_dir = output try: if use_zip: output = output_dir + ZIP_SUFFIX self._recursiveZipDir(output_dir, output) else: output = output_dir + TARGZ_SUFFIX self._recursiveTarDir(output_dir, output) finally: rdw_helpers.remove_dir(output_dir) # Return the location of the file to be restored return output
def _hashPassword(self, password): # At this point the password should be unicode. We converted it into # system encoding. password_b = encode_s(password) import sha hasher = sha.new() hasher.update(password_b) return decode_s(hasher.hexdigest())
def get_config_str(self, key, default=""): """ A convenience method which coerces the key to an str. """ try: return rdw_helpers.encode_s(self.get_config(key, default)) except: return default
def _get_parms_for_page(self): """ Build the params for the locations templates. """ # Get user's locations. user_root = self.app.currentuser.root_dir user_root_b = encode_s(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_b, encode_s(user_repo)) path = repo_obj.path name = repo_obj.display_name in_progress = repo_obj.in_progress last_backup_date = repo_obj.last_backup_date failed = False except librdiff.FileError: logging.exception("invalid user path %s" % user_repo) path = encode_s(user_repo) name = user_repo in_progress = False last_backup_date = 0 failed = True # Create an entry to represent the repository repos.append({ "path": path, "name": name, "last_backup_date": last_backup_date, 'in_progress': in_progress, 'failed': failed }) params = { "repos": repos, "templates_before_content": list(), } # Add plugins params. self.app.plugins.run( lambda x: x.locations_update_params(params), rdw_plugin.ILocationsPagePlugin.CATEGORY) # Return the complete list of params. return params
def _execute(self, username, function): assert isinstance(username, unicode) """Reusable method to run LDAP operation.""" # try STARTLS if configured if self.tls: ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) # Check LDAP credential only. l = ldap.initialize(self.uri) # Set v2 or v3 if self.version == 2: l.protocol_version = ldap.VERSION2 else: l.protocol_version = ldap.VERSION3 try: # Bind to the LDAP server logger.debug("binding to ldap server {}".format(self.uri)) l.simple_bind_s(self.bind_dn, self.bind_password) # Search the LDAP server search_filter = "(&{}({}={}))".format( self.filter, self.attribute, username) logger.info("search ldap server: {}/{}?{}?{}?{}".format( self.uri, self.base_dn, self.attribute, self.scope, search_filter)) r = l.search_s(encode_s(self.base_dn), self.scope, encode_s(search_filter)) # Execute operation return function(l, r) except ldap.LDAPError as e: l.unbind_s() if isinstance(e.message, dict) and 'desc' in e.message: raise ValueError(e.message['desc']) else: raise ValueError(e.message['info'])
def check_crendential(l, r): # Check results if len(r) != 1: logger.warn("user [%s] not found in LDAP" % username) return False # Bind using the user credentials. Throws an exception in case of # error. l.simple_bind_s(r[0][0], encode_s(password)) l.unbind_s() logger.info("user [%s] found in LDAP" % username) return True
def __str__(self): return rdw_helpers.encode_s(unicode(self))
def _getUserMessages(self, repos, includeSuccess, includeFailure, earliest_date, latest_date): user_root = self.app.userdb.get_user_root(self.app.currentuser.username) user_root_b = encode_s(user_root) repoErrors = [] allBackups = [] for repo in repos: # Get binary representation of the repo repo_b = encode_s(repo) if isinstance(repo, unicode) else repo repo_b = repo_b.lstrip(b"/") try: repo_obj = librdiff.RdiffRepo(user_root_b, repo_b) backups = repo_obj.get_history_entries(-1, earliest_date, latest_date) allBackups += [{"repo_path": repo_obj.path, "repo_name": repo_obj.display_name, "date": backup.date, "size": backup.size, "errors": backup.errors} for backup in backups] except librdiff.FileError as e: repoErrors.append( {"repo_path": repo_b, "repo_name": decode_s(repo_b, 'replace'), "error": unicode(e)}) allBackups.sort(lambda x, y: cmp(y["date"], x["date"])) failedBackups = filter(lambda x: x["errors"], allBackups) # group successful backups by day successfulBackups = filter(lambda x: not x["errors"], allBackups) if successfulBackups: lastSuccessDate = successfulBackups[0]["date"] successfulBackups = rdw_helpers.groupby( successfulBackups, lambda x: x["date"].getLocalDaysSinceEpoch()) userMessages = [] # generate failure messages if includeFailure: for job in failedBackups: date = job["date"] job.update( {"is_success": False, "date": date, "repoErrors": [], "backups": [], "repo_path": job["repo_path"], "repo_name": job["repo_name"]}) userMessages.append(job) # generate success messages (publish date is most recent backup date) if includeSuccess: for day in successfulBackups.keys(): date = successfulBackups[day][0]["date"] # include repository errors in most recent entry if date == lastSuccessDate: repoErrorsForMsg = repoErrors else: repoErrorsForMsg = [] userMessages.append( {"is_success": True, "date": date, "repoErrors": repoErrorsForMsg, "backups": successfulBackups[day]}) # sort messages by date userMessages.sort(lambda x, y: cmp(y["date"], x["date"])) return userMessages