From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- toolkit/components/url-classifier/Entries.h | 347 ++++++++++++++++++++++++++++ 1 file changed, 347 insertions(+) create mode 100644 toolkit/components/url-classifier/Entries.h (limited to 'toolkit/components/url-classifier/Entries.h') diff --git a/toolkit/components/url-classifier/Entries.h b/toolkit/components/url-classifier/Entries.h new file mode 100644 index 0000000000..713867c2b7 --- /dev/null +++ b/toolkit/components/url-classifier/Entries.h @@ -0,0 +1,347 @@ +//* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// This header file defines the storage types of the actual safebrowsing +// chunk data, which may be either 32-bit hashes or complete 256-bit hashes. +// Chunk numbers are represented in ChunkSet.h. + +#ifndef SBEntries_h__ +#define SBEntries_h__ + +#include "nsTArray.h" +#include "nsString.h" +#include "nsICryptoHash.h" +#include "nsNetUtil.h" +#include "nsIOutputStream.h" +#include "nsClassHashtable.h" +#include "nsComponentManagerUtils.h" +#include "nsTHashMap.h" +#include "plbase64.h" + +namespace mozilla { +namespace safebrowsing { + +#define PREFIX_SIZE 4 +#define COMPLETE_SIZE 32 + +// This is the struct that contains 4-byte hash prefixes. +template +struct SafebrowsingHash { + static_assert(S >= 4, "The SafebrowsingHash should be at least 4 bytes."); + + static const uint32_t sHashSize = S; + typedef SafebrowsingHash self_type; + uint8_t buf[S]; + + nsresult FromPlaintext(const nsACString& aPlainText) { + // From the protocol doc: + // Each entry in the chunk is composed + // of the SHA 256 hash of a suffix/prefix expression. + nsresult rv; + nsCOMPtr hash = + do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + rv = hash->Init(nsICryptoHash::SHA256); + NS_ENSURE_SUCCESS(rv, rv); + + rv = hash->Update( + reinterpret_cast(aPlainText.BeginReading()), + aPlainText.Length()); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoCString hashed; + rv = hash->Finish(false, hashed); + NS_ENSURE_SUCCESS(rv, rv); + + NS_ASSERTION(hashed.Length() >= sHashSize, + "not enough characters in the hash"); + + memcpy(buf, hashed.BeginReading(), sHashSize); + + return NS_OK; + } + + void Assign(const nsACString& aStr) { + NS_ASSERTION(aStr.Length() >= sHashSize, + "string must be at least sHashSize characters long"); + memcpy(buf, aStr.BeginReading(), sHashSize); + } + + int Compare(const self_type& aOther) const { + return Comparator::Compare(buf, aOther.buf); + } + + bool operator==(const self_type& aOther) const { + return Comparator::Compare(buf, aOther.buf) == 0; + } + + bool operator!=(const self_type& aOther) const { + return Comparator::Compare(buf, aOther.buf) != 0; + } + + bool operator<(const self_type& aOther) const { + return Comparator::Compare(buf, aOther.buf) < 0; + } + + void ToString(nsACString& aStr) const { + // Base64 represents 6-bits data as 8-bits output. + uint32_t len = ((sHashSize + 2) / 3) * 4; + + aStr.SetLength(len); + PL_Base64Encode((char*)buf, sHashSize, aStr.BeginWriting()); + MOZ_ASSERT(aStr.BeginReading()[len] == '\0'); + } + + nsCString ToString() const { + nsAutoCString str; + ToString(str); + return std::move(str); + } + + void ToHexString(nsACString& aStr) const { + static const char* const lut = "0123456789ABCDEF"; + // 32 bytes is the longest hash + size_t len = 32; + + aStr.SetCapacity(2 * len); + for (size_t i = 0; i < len; ++i) { + const char c = static_cast(buf[i]); + aStr.Append(lut[(c >> 4) & 0x0F]); + aStr.Append(lut[c & 15]); + } + } + + uint32_t ToUint32() const { + uint32_t n; + memcpy(&n, buf, sizeof(n)); + return n; + } + void FromUint32(uint32_t aHash) { memcpy(buf, &aHash, sizeof(aHash)); } +}; + +class PrefixComparator { + public: + static int Compare(const uint8_t* a, const uint8_t* b) { + uint32_t first; + memcpy(&first, a, sizeof(uint32_t)); + + uint32_t second; + memcpy(&second, b, sizeof(uint32_t)); + + if (first > second) { + return 1; + } else if (first == second) { + return 0; + } else { + return -1; + } + } +}; +// Use this for 4-byte hashes +typedef SafebrowsingHash Prefix; +typedef nsTArray PrefixArray; + +class CompletionComparator { + public: + static int Compare(const uint8_t* a, const uint8_t* b) { + return memcmp(a, b, COMPLETE_SIZE); + } +}; +// Use this for 32-byte hashes +typedef SafebrowsingHash Completion; +typedef nsTArray CompletionArray; + +struct AddPrefix { + // The truncated hash. + Prefix prefix; + // The chunk number to which it belongs. + uint32_t addChunk; + + AddPrefix() : addChunk(0) {} + + // Returns the chunk number. + uint32_t Chunk() const { return addChunk; } + const Prefix& PrefixHash() const { return prefix; } + + template + int Compare(const T& other) const { + int cmp = prefix.Compare(other.PrefixHash()); + if (cmp != 0) { + return cmp; + } + return addChunk - other.addChunk; + } +}; + +struct AddComplete { + Completion complete; + uint32_t addChunk; + + AddComplete() : addChunk(0) {} + + uint32_t Chunk() const { return addChunk; } + // The 4-byte prefix of the sha256 hash. + uint32_t ToUint32() const { return complete.ToUint32(); } + // The 32-byte sha256 hash. + const Completion& CompleteHash() const { return complete; } + + template + int Compare(const T& other) const { + int cmp = complete.Compare(other.CompleteHash()); + if (cmp != 0) { + return cmp; + } + return addChunk - other.addChunk; + } + + bool operator!=(const AddComplete& aOther) const { + if (addChunk != aOther.addChunk) { + return true; + } + return complete != aOther.complete; + } +}; + +struct SubPrefix { + // The hash to subtract. + Prefix prefix; + // The chunk number of the add chunk to which the hash belonged. + uint32_t addChunk; + // The chunk number of this sub chunk. + uint32_t subChunk; + + SubPrefix() : addChunk(0), subChunk(0) {} + + uint32_t Chunk() const { return subChunk; } + uint32_t AddChunk() const { return addChunk; } + const Prefix& PrefixHash() const { return prefix; } + + template + // Returns 0 if and only if the chunks are the same in every way. + int Compare(const T& aOther) const { + int cmp = prefix.Compare(aOther.PrefixHash()); + if (cmp != 0) return cmp; + if (addChunk != aOther.addChunk) return addChunk - aOther.addChunk; + return subChunk - aOther.subChunk; + } + + template + int CompareAlt(const T& aOther) const { + Prefix other; + other.FromUint32(aOther.ToUint32()); + int cmp = prefix.Compare(other); + if (cmp != 0) return cmp; + return addChunk - aOther.addChunk; + } +}; + +struct SubComplete { + Completion complete; + uint32_t addChunk; + uint32_t subChunk; + + SubComplete() : addChunk(0), subChunk(0) {} + + uint32_t Chunk() const { return subChunk; } + uint32_t AddChunk() const { return addChunk; } + const Completion& CompleteHash() const { return complete; } + // The 4-byte prefix of the sha256 hash. + uint32_t ToUint32() const { return complete.ToUint32(); } + + int Compare(const SubComplete& aOther) const { + int cmp = complete.Compare(aOther.complete); + if (cmp != 0) return cmp; + if (addChunk != aOther.addChunk) return addChunk - aOther.addChunk; + return subChunk - aOther.subChunk; + } +}; + +typedef FallibleTArray AddPrefixArray; +typedef FallibleTArray AddCompleteArray; +typedef FallibleTArray SubPrefixArray; +typedef FallibleTArray SubCompleteArray; +typedef FallibleTArray MissPrefixArray; + +/** + * Sort an array of store entries. + */ +template +void EntrySort(nsTArray_Impl& aArray) { + aArray.Sort([](const T& aA, const T& aB) { return aA.Compare(aB); }); +} + +template +nsresult ReadTArray(nsIInputStream* aStream, nsTArray_Impl* aArray, + uint32_t aNumElements) { + if (!aArray->SetLength(aNumElements, fallible)) return NS_ERROR_OUT_OF_MEMORY; + + void* buffer = aArray->Elements(); + nsresult rv = + NS_ReadInputStreamToBuffer(aStream, &buffer, (aNumElements * sizeof(T))); + NS_ENSURE_SUCCESS(rv, rv); + return NS_OK; +} + +template +nsresult WriteTArray(nsIOutputStream* aStream, + nsTArray_Impl& aArray) { + uint32_t written; + return aStream->Write(reinterpret_cast(aArray.Elements()), + aArray.Length() * sizeof(T), &written); +} + +typedef nsClassHashtable PrefixStringMap; + +typedef nsTHashMap TableFreshnessMap; + +typedef nsCStringHashKey FullHashString; + +typedef nsTHashMap FullHashExpiryCache; + +struct CachedFullHashResponse { + int64_t negativeCacheExpirySec; + + // Map contains all matches found in Fullhash response, this field might be + // empty. + FullHashExpiryCache fullHashes; + + CachedFullHashResponse& operator=(const CachedFullHashResponse& aOther) { + negativeCacheExpirySec = aOther.negativeCacheExpirySec; + + fullHashes = aOther.fullHashes.Clone(); + + return *this; + } + + bool operator==(const CachedFullHashResponse& aOther) const { + if (negativeCacheExpirySec != aOther.negativeCacheExpirySec || + fullHashes.Count() != aOther.fullHashes.Count()) { + return false; + } + for (const auto& entry : fullHashes) { + if (entry.GetData() != aOther.fullHashes.Get(entry.GetKey())) { + return false; + } + } + return true; + } +}; + +typedef nsClassHashtable + FullHashResponseMap; + +template +void CopyClassHashTable(const T& aSource, T& aDestination) { + for (const auto& entry : aSource) { + auto value = aDestination.GetOrInsertNew(entry.GetKey()); + *value = *(entry.GetData()); + } +} + +} // namespace safebrowsing +} // namespace mozilla + +#endif // SBEntries_h__ -- cgit v1.2.3