// Copyright 2014 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/update_client/utils.h" #include #include #include #include #include #include #include "base/callback.h" #include "base/containers/cxx20_erase.h" #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/files/memory_mapped_file.h" #include "base/json/json_file_value_serializer.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_piece.h" #include "base/strings/string_util.h" #include "base/values.h" #include "components/crx_file/id_util.h" #include "components/update_client/component.h" #include "components/update_client/configurator.h" #include "components/update_client/network.h" #include "components/update_client/update_client.h" #include "components/update_client/update_client_errors.h" #include "crypto/secure_hash.h" #include "crypto/sha2.h" #include "url/gurl.h" namespace update_client { bool HasDiffUpdate(const Component& component) { return !component.crx_diffurls().empty(); } bool IsHttpServerError(int status_code) { return 500 <= status_code && status_code < 600; } bool DeleteFileAndEmptyParentDirectory(const base::FilePath& filepath) { if (!base::DeleteFile(filepath)) return false; const base::FilePath dirname(filepath.DirName()); if (!base::IsDirectoryEmpty(dirname)) return true; return base::DeleteFile(dirname); } std::string GetCrxComponentID(const CrxComponent& component) { return component.app_id.empty() ? GetCrxIdFromPublicKeyHash(component.pk_hash) : component.app_id; } std::string GetCrxIdFromPublicKeyHash(const std::vector& pk_hash) { const std::string result = crx_file::id_util::GenerateIdFromHash(&pk_hash[0], pk_hash.size()); DCHECK(crx_file::id_util::IdIsValid(result)); return result; } bool VerifyFileHash256(const base::FilePath& filepath, const std::string& expected_hash_str) { std::vector expected_hash; if (!base::HexStringToBytes(expected_hash_str, &expected_hash) || expected_hash.size() != crypto::kSHA256Length) { return false; } std::unique_ptr hasher( crypto::SecureHash::Create(crypto::SecureHash::SHA256)); int64_t file_size = 0; if (!base::GetFileSize(filepath, &file_size)) return false; if (file_size > 0) { base::MemoryMappedFile mmfile; if (!mmfile.Initialize(filepath)) return false; hasher->Update(mmfile.data(), mmfile.length()); } uint8_t actual_hash[crypto::kSHA256Length] = {0}; hasher->Finish(actual_hash, sizeof(actual_hash)); return memcmp(actual_hash, &expected_hash[0], sizeof(actual_hash)) == 0; } bool IsValidBrand(const std::string& brand) { const size_t kMaxBrandSize = 4; if (!brand.empty() && brand.size() != kMaxBrandSize) return false; return std::find_if_not(brand.begin(), brand.end(), [](char ch) { return base::IsAsciiAlpha(ch); }) == brand.end(); } // Helper function. // Returns true if |part| matches the expression // ^[a-zA-Z0-9]{min_length,max_length}$ bool IsValidInstallerAttributePart(const std::string& part, const std::string& special_chars, size_t min_length, size_t max_length) { if (part.size() < min_length || part.size() > max_length) return false; return std::find_if_not(part.begin(), part.end(), [&special_chars](char ch) { if (base::IsAsciiAlpha(ch) || base::IsAsciiDigit(ch)) return true; for (auto c : special_chars) { if (c == ch) return true; } return false; }) == part.end(); } // Returns true if the |name| parameter matches ^[-_a-zA-Z0-9]{1,256}$ . bool IsValidInstallerAttributeName(const std::string& name) { return IsValidInstallerAttributePart(name, "-_", 1, 256); } // Returns true if the |value| parameter matches ^[-.,;+_=$a-zA-Z0-9]{0,256}$ . bool IsValidInstallerAttributeValue(const std::string& value) { return IsValidInstallerAttributePart(value, "-.,;+_=$", 0, 256); } bool IsValidInstallerAttribute(const InstallerAttribute& attr) { return IsValidInstallerAttributeName(attr.first) && IsValidInstallerAttributeValue(attr.second); } void RemoveUnsecureUrls(std::vector* urls) { DCHECK(urls); base::EraseIf(*urls, [](const GURL& url) { return !url.SchemeIsCryptographic(); }); } CrxInstaller::Result InstallFunctionWrapper( base::OnceCallback callback) { return CrxInstaller::Result(std::move(callback).Run() ? InstallError::NONE : InstallError::GENERIC_ERROR); } // TODO(cpu): add a specific attribute check to a component json that the // extension unpacker will reject, so that a component cannot be installed // as an extension. base::Value ReadManifest(const base::FilePath& unpack_path) { base::FilePath manifest = unpack_path.Append(FILE_PATH_LITERAL("manifest.json")); if (!base::PathExists(manifest)) return base::Value(); JSONFileValueDeserializer deserializer(manifest); std::string error; std::unique_ptr root = deserializer.Deserialize(nullptr, &error); if (!root) return base::Value(); return base::Value::FromUniquePtrValue(std::move(root)); } } // namespace update_client