blob: 9cdeccfbc03f19ee7769975b2292e9fb84d06942 [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/utility/safe_browsing/archive_analyzer.h"
#include "base/feature_list.h"
#include "build/build_config.h"
#include "build/buildflag.h"
#include "chrome/common/safe_browsing/archive_analyzer_results.h"
#include "chrome/utility/safe_browsing/rar_analyzer.h"
#include "chrome/utility/safe_browsing/seven_zip_analyzer.h"
#include "chrome/utility/safe_browsing/zip_analyzer.h"
#include "components/safe_browsing/content/common/proto/download_file_types.pb.h"
#include "components/safe_browsing/core/common/features.h"
#if BUILDFLAG(IS_MAC)
#include "chrome/utility/safe_browsing/mac/dmg_analyzer.h"
#endif
namespace safe_browsing {
// static
std::unique_ptr<ArchiveAnalyzer> ArchiveAnalyzer::CreateForArchiveType(
DownloadFileType_InspectionType file_type) {
if (file_type == DownloadFileType::RAR) {
return std::make_unique<RarAnalyzer>();
} else if (file_type == DownloadFileType::ZIP) {
return std::make_unique<ZipAnalyzer>();
} else if (file_type == DownloadFileType::SEVEN_ZIP) {
return std::make_unique<SevenZipAnalyzer>();
}
#if BUILDFLAG(IS_MAC)
if (file_type == DownloadFileType::DMG) {
return std::make_unique<dmg::DMGAnalyzer>();
}
#endif
return nullptr;
}
ArchiveAnalyzer::ArchiveAnalyzer() = default;
ArchiveAnalyzer::~ArchiveAnalyzer() = default;
void ArchiveAnalyzer::Analyze(
base::File archive_file,
base::FilePath relative_path,
const std::optional<std::string>& password,
FinishedAnalysisCallback finished_analysis_callback,
GetTempFileCallback get_temp_file_callback,
ArchiveAnalyzerResults* results) {
archive_file_ = std::move(archive_file);
root_path_ = relative_path;
password_ = password;
finished_analysis_callback_ = std::move(finished_analysis_callback);
get_temp_file_callback_ = std::move(get_temp_file_callback);
results_ = results;
Init();
}
void ArchiveAnalyzer::SetResultsForTesting(ArchiveAnalyzerResults* results) {
results_ = results;
}
void ArchiveAnalyzer::SetFinishedCallbackForTesting(
FinishedAnalysisCallback callback) {
finished_analysis_callback_ = std::move(callback);
}
base::File& ArchiveAnalyzer::GetArchiveFile() {
return archive_file_;
}
void ArchiveAnalyzer::GetTempFile(
base::OnceCallback<void(base::File)> callback) {
get_temp_file_callback_.Run(std::move(callback));
}
const base::FilePath& ArchiveAnalyzer::GetRootPath() const {
return root_path_;
}
bool ArchiveAnalyzer::UpdateResultsForEntry(base::File entry,
base::FilePath path,
int file_length,
bool is_encrypted,
bool is_directory,
bool contents_valid) {
if (base::FeatureList::IsEnabled(kNestedArchives) && !is_encrypted) {
nested_analyzer_ = ArchiveAnalyzer::CreateForArchiveType(GetFileType(path));
if (nested_analyzer_) {
nested_analyzer_->Analyze(
entry.Duplicate(), path, password(),
base::BindOnce(&ArchiveAnalyzer::NestedAnalysisFinished, GetWeakPtr(),
entry.Duplicate(), path, file_length),
get_temp_file_callback_, results_);
return false;
}
}
if (is_directory) {
results_->directory_count++;
} else {
results_->file_count++;
}
UpdateArchiveAnalyzerResultsWithFile(path, &entry, file_length, is_encrypted,
is_directory, contents_valid, results_);
return true;
}
void ArchiveAnalyzer::InitComplete(ArchiveAnalysisResult result) {
if (result != ArchiveAnalysisResult::kValid) {
results_->success = false;
results_->analysis_result = result;
std::move(finished_analysis_callback_).Run();
return;
}
results_->success = true;
results_->analysis_result = ArchiveAnalysisResult::kValid;
if (ResumeExtraction()) {
std::move(finished_analysis_callback_).Run();
}
}
void ArchiveAnalyzer::NestedAnalysisFinished(base::File entry,
base::FilePath path,
int entry_size) {
// `results_->success` will contain the latest analyzer's success
// status and can be used to determine if the nester archive unpacked
// successfully.
if (!results_->success) {
results_->has_archive = true;
results_->file_count++;
results_->archived_archive_filenames.push_back(path.BaseName());
ClientDownloadRequest::ArchivedBinary* archived_archive =
results_->archived_binary.Add();
archived_archive->set_download_type(ClientDownloadRequest::ARCHIVE);
archived_archive->set_is_encrypted(false);
archived_archive->set_is_archive(true);
SetNameForContainedFile(path, archived_archive);
SetLengthAndDigestForContainedFile(&entry, entry_size, archived_archive);
}
if (ResumeExtraction()) {
std::move(finished_analysis_callback_).Run();
}
}
} // namespace safe_browsing