blob: 18bc800c144bb9cfab6c8c7238f67449f34dbf6a [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/offline_pages/core/archive_validator.h"
#include <vector>
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "crypto/secure_hash.h"
#include "crypto/sha2.h"
#if defined(OS_ANDROID)
#include "base/android/content_uri_utils.h"
#endif
namespace offline_pages {
ArchiveValidator::ArchiveValidator() {
secure_hash_ = crypto::SecureHash::Create(crypto::SecureHash::SHA256);
}
ArchiveValidator::~ArchiveValidator() = default;
void ArchiveValidator::Update(const char* input, size_t len) {
secure_hash_->Update(input, len);
}
std::string ArchiveValidator::Finish() {
std::string digest(crypto::kSHA256Length, 0);
secure_hash_->Finish(&(digest[0]), digest.size());
return digest;
}
// static
std::string ArchiveValidator::ComputeDigest(const base::FilePath& file_path) {
std::pair<int64_t, std::string> result = GetSizeAndComputeDigest(file_path);
return result.second;
}
// static
std::pair<int64_t, std::string> ArchiveValidator::GetSizeAndComputeDigest(
const base::FilePath& file_path) {
base::File file;
#if defined(OS_ANDROID)
if (file_path.IsContentUri()) {
file = base::OpenContentUriForRead(file_path);
} else {
#endif // defined(OS_ANDROID)
file.Initialize(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
#if defined(OS_ANDROID)
}
#endif // defined(OS_ANDROID)
if (!file.IsValid())
return std::make_pair(0LL, std::string());
ArchiveValidator archive_validator;
const int kMaxBufferSize = 1024;
std::vector<char> buffer(kMaxBufferSize);
int64_t total_read = 0LL;
int bytes_read;
do {
bytes_read = file.ReadAtCurrentPos(buffer.data(), kMaxBufferSize);
if (bytes_read > 0) {
total_read += bytes_read;
archive_validator.Update(buffer.data(), bytes_read);
}
} while (bytes_read > 0);
if (bytes_read < 0)
return std::make_pair(0LL, std::string());
return std::make_pair(total_read, archive_validator.Finish());
}
// static
bool ArchiveValidator::ValidateFile(const base::FilePath& file_path,
int64_t expected_file_size,
const std::string& expected_digest) {
int64_t actual_file_size;
if (!base::GetFileSize(file_path, &actual_file_size))
return false;
if (expected_file_size != actual_file_size)
return false;
std::string actual_digest = ComputeDigest(file_path);
return expected_digest == actual_digest;
}
} // namespace offline_pages