123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654 |
- /* -*- Mode: C++; tab-width: 2; 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/. */
- #include "CertBlocklist.h"
- #include "mozilla/Base64.h"
- #include "mozilla/Casting.h"
- #include "mozilla/Logging.h"
- #include "mozilla/Preferences.h"
- #include "mozilla/Unused.h"
- #include "nsAppDirectoryServiceDefs.h"
- #include "nsCRTGlue.h"
- #include "nsDirectoryServiceUtils.h"
- #include "nsICryptoHash.h"
- #include "nsIFileStreams.h"
- #include "nsILineInputStream.h"
- #include "nsISafeOutputStream.h"
- #include "nsIX509Cert.h"
- #include "nsNetCID.h"
- #include "nsNetUtil.h"
- #include "nsTHashtable.h"
- #include "nsThreadUtils.h"
- #include "pkix/Input.h"
- #include "prtime.h"
- NS_IMPL_ISUPPORTS(CertBlocklist, nsICertBlocklist)
- using namespace mozilla;
- using namespace mozilla::pkix;
- #define PREF_BACKGROUND_UPDATE_TIMER "app.update.lastUpdateTime.blocklist-background-update-timer"
- #define PREF_BLOCKLIST_ONECRL_CHECKED "services.blocklist.onecrl.checked"
- #define PREF_MAX_STALENESS_IN_SECONDS "security.onecrl.maximum_staleness_in_seconds"
- static LazyLogModule gCertBlockPRLog("CertBlock");
- uint32_t CertBlocklist::sLastBlocklistUpdate = 0U;
- uint32_t CertBlocklist::sMaxStaleness = 0U;
- CertBlocklistItem::CertBlocklistItem(const uint8_t* DNData,
- size_t DNLength,
- const uint8_t* otherData,
- size_t otherLength,
- CertBlocklistItemMechanism itemMechanism)
- : mIsCurrent(false)
- , mItemMechanism(itemMechanism)
- {
- mDNData = new uint8_t[DNLength];
- memcpy(mDNData, DNData, DNLength);
- mDNLength = DNLength;
- mOtherData = new uint8_t[otherLength];
- memcpy(mOtherData, otherData, otherLength);
- mOtherLength = otherLength;
- }
- CertBlocklistItem::CertBlocklistItem(const CertBlocklistItem& aItem)
- {
- mDNLength = aItem.mDNLength;
- mDNData = new uint8_t[mDNLength];
- memcpy(mDNData, aItem.mDNData, mDNLength);
- mOtherLength = aItem.mOtherLength;
- mOtherData = new uint8_t[mOtherLength];
- memcpy(mOtherData, aItem.mOtherData, mOtherLength);
- mItemMechanism = aItem.mItemMechanism;
- mIsCurrent = aItem.mIsCurrent;
- }
- CertBlocklistItem::~CertBlocklistItem()
- {
- delete[] mDNData;
- delete[] mOtherData;
- }
- nsresult
- CertBlocklistItem::ToBase64(nsACString& b64DNOut, nsACString& b64OtherOut)
- {
- nsDependentCSubstring DNString(BitwiseCast<char*, uint8_t*>(mDNData),
- mDNLength);
- nsDependentCSubstring otherString(BitwiseCast<char*, uint8_t*>(mOtherData),
- mOtherLength);
- nsresult rv = Base64Encode(DNString, b64DNOut);
- if (NS_FAILED(rv)) {
- return rv;
- }
- rv = Base64Encode(otherString, b64OtherOut);
- return rv;
- }
- bool
- CertBlocklistItem::operator==(const CertBlocklistItem& aItem) const
- {
- if (aItem.mItemMechanism != mItemMechanism) {
- return false;
- }
- if (aItem.mDNLength != mDNLength ||
- aItem.mOtherLength != mOtherLength) {
- return false;
- }
- return memcmp(aItem.mDNData, mDNData, mDNLength) == 0 &&
- memcmp(aItem.mOtherData, mOtherData, mOtherLength) == 0;
- }
- uint32_t
- CertBlocklistItem::Hash() const
- {
- uint32_t hash;
- // there's no requirement for a serial to be as large as the size of the hash
- // key; if it's smaller, fall back to the first octet (otherwise, the last
- // four)
- if (mItemMechanism == BlockByIssuerAndSerial &&
- mOtherLength >= sizeof(hash)) {
- memcpy(&hash, mOtherData + mOtherLength - sizeof(hash), sizeof(hash));
- } else {
- hash = *mOtherData;
- }
- return hash;
- }
- CertBlocklist::CertBlocklist()
- : mMutex("CertBlocklist::mMutex")
- , mModified(false)
- , mBackingFileIsInitialized(false)
- , mBackingFile(nullptr)
- {
- }
- CertBlocklist::~CertBlocklist()
- {
- Preferences::UnregisterCallback(CertBlocklist::PreferenceChanged,
- PREF_BACKGROUND_UPDATE_TIMER,
- this);
- Preferences::UnregisterCallback(CertBlocklist::PreferenceChanged,
- PREF_MAX_STALENESS_IN_SECONDS,
- this);
- Preferences::UnregisterCallback(CertBlocklist::PreferenceChanged,
- PREF_BLOCKLIST_ONECRL_CHECKED,
- this);
- }
- nsresult
- CertBlocklist::Init()
- {
- MOZ_LOG(gCertBlockPRLog, LogLevel::Debug, ("CertBlocklist::Init"));
- // Init must be on main thread for getting the profile directory
- if (!NS_IsMainThread()) {
- MOZ_LOG(gCertBlockPRLog, LogLevel::Debug,
- ("CertBlocklist::Init - called off main thread"));
- return NS_ERROR_NOT_SAME_THREAD;
- }
- // Register preference callbacks
- nsresult rv =
- Preferences::RegisterCallbackAndCall(CertBlocklist::PreferenceChanged,
- PREF_BACKGROUND_UPDATE_TIMER,
- this);
- if (NS_FAILED(rv)) {
- return rv;
- }
- rv = Preferences::RegisterCallbackAndCall(CertBlocklist::PreferenceChanged,
- PREF_MAX_STALENESS_IN_SECONDS,
- this);
- if (NS_FAILED(rv)) {
- return rv;
- }
- rv = Preferences::RegisterCallbackAndCall(CertBlocklist::PreferenceChanged,
- PREF_BLOCKLIST_ONECRL_CHECKED,
- this);
- if (NS_FAILED(rv)) {
- return rv;
- }
- // Get the profile directory
- rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
- getter_AddRefs(mBackingFile));
- if (NS_FAILED(rv) || !mBackingFile) {
- MOZ_LOG(gCertBlockPRLog, LogLevel::Debug,
- ("CertBlocklist::Init - couldn't get profile dir"));
- // Since we're returning NS_OK here, set mBackingFile to a safe value.
- // (We need initialization to succeed and CertBlocklist to be in a
- // well-defined state if the profile directory doesn't exist.)
- mBackingFile = nullptr;
- return NS_OK;
- }
- rv = mBackingFile->Append(NS_LITERAL_STRING("revocations.txt"));
- if (NS_FAILED(rv)) {
- return rv;
- }
- nsAutoCString path;
- rv = mBackingFile->GetNativePath(path);
- if (NS_FAILED(rv)) {
- return rv;
- }
- MOZ_LOG(gCertBlockPRLog, LogLevel::Debug,
- ("CertBlocklist::Init certList path: %s", path.get()));
- return NS_OK;
- }
- nsresult
- CertBlocklist::EnsureBackingFileInitialized(MutexAutoLock& lock)
- {
- MOZ_LOG(gCertBlockPRLog, LogLevel::Debug,
- ("CertBlocklist::EnsureBackingFileInitialized"));
- if (mBackingFileIsInitialized || !mBackingFile) {
- return NS_OK;
- }
- MOZ_LOG(gCertBlockPRLog, LogLevel::Debug,
- ("CertBlocklist::EnsureBackingFileInitialized - not initialized"));
- bool exists = false;
- nsresult rv = mBackingFile->Exists(&exists);
- if (NS_FAILED(rv)) {
- return rv;
- }
- if (!exists) {
- MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
- ("CertBlocklist::EnsureBackingFileInitialized no revocations file"));
- return NS_OK;
- }
- // Load the revocations file into the cert blocklist
- nsCOMPtr<nsIFileInputStream> fileStream(
- do_CreateInstance(NS_LOCALFILEINPUTSTREAM_CONTRACTID, &rv));
- if (NS_FAILED(rv)) {
- return rv;
- }
- rv = fileStream->Init(mBackingFile, -1, -1, false);
- if (NS_FAILED(rv)) {
- return rv;
- }
- nsCOMPtr<nsILineInputStream> lineStream(do_QueryInterface(fileStream, &rv));
- nsAutoCString line;
- nsAutoCString DN;
- nsAutoCString other;
- CertBlocklistItemMechanism mechanism;
- // read in the revocations file. The file format is as follows: each line
- // contains a comment, base64 encoded DER for a DN, base64 encoded DER for a
- // serial number or a Base64 encoded SHA256 hash of a public key. Comment
- // lines start with '#', serial number lines, ' ' (a space), public key hashes
- // with '\t' (a tab) and anything else is assumed to be a DN.
- bool more = true;
- do {
- rv = lineStream->ReadLine(line, &more);
- if (NS_FAILED(rv)) {
- break;
- }
- // ignore comments and empty lines
- if (line.IsEmpty() || line.First() == '#') {
- continue;
- }
- if (line.First() != ' ' && line.First() != '\t') {
- DN = line;
- continue;
- }
- other = line;
- if (line.First() == ' ') {
- mechanism = BlockByIssuerAndSerial;
- } else {
- mechanism = BlockBySubjectAndPubKey;
- }
- other.Trim(" \t", true, false, false);
- // Serial numbers and public key hashes 'belong' to the last DN line seen;
- // if no DN has been seen, the serial number or public key hash is ignored.
- if (DN.IsEmpty() || other.IsEmpty()) {
- continue;
- }
- MOZ_LOG(gCertBlockPRLog, LogLevel::Debug,
- ("CertBlocklist::EnsureBackingFileInitialized adding: %s %s",
- DN.get(), other.get()));
- MOZ_LOG(gCertBlockPRLog, LogLevel::Debug,
- ("CertBlocklist::EnsureBackingFileInitialized - pre-decode"));
- rv = AddRevokedCertInternal(DN, other, mechanism, CertOldFromLocalCache,
- lock);
- if (NS_FAILED(rv)) {
- // we warn here, rather than abandoning, since we need to
- // ensure that as many items as possible are read
- MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
- ("CertBlocklist::EnsureBackingFileInitialized adding revoked cert "
- "failed"));
- }
- } while (more);
- mBackingFileIsInitialized = true;
- return NS_OK;
- }
- NS_IMETHODIMP
- CertBlocklist::RevokeCertBySubjectAndPubKey(const char* aSubject,
- const char* aPubKeyHash)
- {
- MOZ_LOG(gCertBlockPRLog, LogLevel::Debug,
- ("CertBlocklist::RevokeCertBySubjectAndPubKey - subject is: %s and pubKeyHash: %s",
- aSubject, aPubKeyHash));
- MutexAutoLock lock(mMutex);
- return AddRevokedCertInternal(nsDependentCString(aSubject),
- nsDependentCString(aPubKeyHash),
- BlockBySubjectAndPubKey,
- CertNewFromBlocklist, lock);
- }
- NS_IMETHODIMP
- CertBlocklist::RevokeCertByIssuerAndSerial(const char* aIssuer,
- const char* aSerialNumber)
- {
- MOZ_LOG(gCertBlockPRLog, LogLevel::Debug,
- ("CertBlocklist::RevokeCertByIssuerAndSerial - issuer is: %s and serial: %s",
- aIssuer, aSerialNumber));
- MutexAutoLock lock(mMutex);
- return AddRevokedCertInternal(nsDependentCString(aIssuer),
- nsDependentCString(aSerialNumber),
- BlockByIssuerAndSerial,
- CertNewFromBlocklist, lock);
- }
- nsresult
- CertBlocklist::AddRevokedCertInternal(const nsACString& aEncodedDN,
- const nsACString& aEncodedOther,
- CertBlocklistItemMechanism aMechanism,
- CertBlocklistItemState aItemState,
- MutexAutoLock& /*proofOfLock*/)
- {
- nsCString decodedDN;
- nsCString decodedOther;
- nsresult rv = Base64Decode(aEncodedDN, decodedDN);
- if (NS_FAILED(rv)) {
- return rv;
- }
- rv = Base64Decode(aEncodedOther, decodedOther);
- if (NS_FAILED(rv)) {
- return rv;
- }
- CertBlocklistItem item(
- BitwiseCast<const uint8_t*, const char*>(decodedDN.get()),
- decodedDN.Length(),
- BitwiseCast<const uint8_t*, const char*>(decodedOther.get()),
- decodedOther.Length(),
- aMechanism);
- if (aItemState == CertNewFromBlocklist) {
- // We want SaveEntries to be a no-op if no new entries are added.
- nsGenericHashKey<CertBlocklistItem>* entry = mBlocklist.GetEntry(item);
- if (!entry) {
- mModified = true;
- } else {
- // Ensure that any existing item is replaced by a fresh one so we can
- // use mIsCurrent to decide which entries to write out.
- mBlocklist.RemoveEntry(entry);
- }
- item.mIsCurrent = true;
- }
- mBlocklist.PutEntry(item);
- return NS_OK;
- }
- // Write a line for a given string in the output stream
- nsresult
- WriteLine(nsIOutputStream* outputStream, const nsACString& string)
- {
- nsAutoCString line(string);
- line.Append('\n');
- const char* data = line.get();
- uint32_t length = line.Length();
- nsresult rv = NS_OK;
- while (NS_SUCCEEDED(rv) && length) {
- uint32_t bytesWritten = 0;
- rv = outputStream->Write(data, length, &bytesWritten);
- if (NS_FAILED(rv)) {
- return rv;
- }
- // if no data is written, something is wrong
- if (!bytesWritten) {
- return NS_ERROR_FAILURE;
- }
- length -= bytesWritten;
- data += bytesWritten;
- }
- return rv;
- }
- // void saveEntries();
- // Store the blockist in a text file containing base64 encoded issuers and
- // serial numbers.
- //
- // Each item is stored on a separate line; each issuer is followed by its
- // revoked serial numbers, indented by one space.
- //
- // lines starting with a # character are ignored
- NS_IMETHODIMP
- CertBlocklist::SaveEntries()
- {
- MOZ_LOG(gCertBlockPRLog, LogLevel::Debug,
- ("CertBlocklist::SaveEntries - not initialized"));
- MutexAutoLock lock(mMutex);
- if (!mModified) {
- return NS_OK;
- }
- nsresult rv = EnsureBackingFileInitialized(lock);
- if (NS_FAILED(rv)) {
- return rv;
- }
- if (!mBackingFile) {
- // We allow this to succeed with no profile directory for tests
- MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
- ("CertBlocklist::SaveEntries no file in profile to write to"));
- return NS_OK;
- }
- // Data needed for writing blocklist items out to the revocations file
- IssuerTable issuerTable;
- BlocklistStringSet issuers;
- nsCOMPtr<nsIOutputStream> outputStream;
- rv = NS_NewAtomicFileOutputStream(getter_AddRefs(outputStream),
- mBackingFile, -1, -1, 0);
- if (NS_FAILED(rv)) {
- return rv;
- }
- rv = WriteLine(outputStream,
- NS_LITERAL_CSTRING("# Auto generated contents. Do not edit."));
- if (NS_FAILED(rv)) {
- return rv;
- }
- // Sort blocklist items into lists of serials for each issuer
- for (auto iter = mBlocklist.Iter(); !iter.Done(); iter.Next()) {
- CertBlocklistItem item = iter.Get()->GetKey();
- if (!item.mIsCurrent) {
- continue;
- }
- nsAutoCString encDN;
- nsAutoCString encOther;
- nsresult rv = item.ToBase64(encDN, encOther);
- if (NS_FAILED(rv)) {
- MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
- ("CertBlocklist::SaveEntries writing revocation data failed"));
- return NS_ERROR_FAILURE;
- }
- // If it's a subject / public key block, write it straight out
- if (item.mItemMechanism == BlockBySubjectAndPubKey) {
- WriteLine(outputStream, encDN);
- WriteLine(outputStream, NS_LITERAL_CSTRING("\t") + encOther);
- continue;
- }
- // Otherwise, we have to group entries by issuer
- issuers.PutEntry(encDN);
- BlocklistStringSet* issuerSet = issuerTable.Get(encDN);
- if (!issuerSet) {
- issuerSet = new BlocklistStringSet();
- issuerTable.Put(encDN, issuerSet);
- }
- issuerSet->PutEntry(encOther);
- }
- for (auto iter = issuers.Iter(); !iter.Done(); iter.Next()) {
- nsCStringHashKey* hashKey = iter.Get();
- nsAutoPtr<BlocklistStringSet> issuerSet;
- issuerTable.RemoveAndForget(hashKey->GetKey(), issuerSet);
- nsresult rv = WriteLine(outputStream, hashKey->GetKey());
- if (NS_FAILED(rv)) {
- break;
- }
- // Write serial data to the output stream
- for (auto iter = issuerSet->Iter(); !iter.Done(); iter.Next()) {
- nsresult rv = WriteLine(outputStream,
- NS_LITERAL_CSTRING(" ") + iter.Get()->GetKey());
- if (NS_FAILED(rv)) {
- MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
- ("CertBlocklist::SaveEntries writing revocation data failed"));
- return NS_ERROR_FAILURE;
- }
- }
- }
- nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(outputStream);
- NS_ASSERTION(safeStream, "expected a safe output stream!");
- if (!safeStream) {
- return NS_ERROR_FAILURE;
- }
- rv = safeStream->Finish();
- if (NS_FAILED(rv)) {
- MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
- ("CertBlocklist::SaveEntries saving revocation data failed"));
- return rv;
- }
- mModified = false;
- return NS_OK;
- }
- NS_IMETHODIMP
- CertBlocklist::IsCertRevoked(const uint8_t* aIssuer,
- uint32_t aIssuerLength,
- const uint8_t* aSerial,
- uint32_t aSerialLength,
- const uint8_t* aSubject,
- uint32_t aSubjectLength,
- const uint8_t* aPubKey,
- uint32_t aPubKeyLength,
- bool* _retval)
- {
- MutexAutoLock lock(mMutex);
- MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
- ("CertBlocklist::IsCertRevoked?"));
- nsresult rv = EnsureBackingFileInitialized(lock);
- if (NS_FAILED(rv)) {
- return rv;
- }
- Input issuer;
- Input serial;
- if (issuer.Init(aIssuer, aIssuerLength) != Success) {
- return NS_ERROR_FAILURE;
- }
- if (serial.Init(aSerial, aSerialLength) != Success) {
- return NS_ERROR_FAILURE;
- }
- CertBlocklistItem issuerSerial(aIssuer, aIssuerLength, aSerial, aSerialLength,
- BlockByIssuerAndSerial);
- nsAutoCString encDN;
- nsAutoCString encOther;
- issuerSerial.ToBase64(encDN, encOther);
- if (NS_FAILED(rv)) {
- return rv;
- }
- MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
- ("CertBlocklist::IsCertRevoked issuer %s - serial %s",
- encDN.get(), encOther.get()));
- *_retval = mBlocklist.Contains(issuerSerial);
- if (*_retval) {
- MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
- ("certblocklist::IsCertRevoked found by issuer / serial"));
- return NS_OK;
- }
- nsCOMPtr<nsICryptoHash> crypto;
- crypto = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv);
- rv = crypto->Init(nsICryptoHash::SHA256);
- if (NS_FAILED(rv)) {
- return rv;
- }
- rv = crypto->Update(aPubKey, aPubKeyLength);
- if (NS_FAILED(rv)) {
- return rv;
- }
- nsCString hashString;
- rv = crypto->Finish(false, hashString);
- if (NS_FAILED(rv)) {
- return rv;
- }
- CertBlocklistItem subjectPubKey(
- aSubject,
- static_cast<size_t>(aSubjectLength),
- BitwiseCast<const uint8_t*, const char*>(hashString.get()),
- hashString.Length(),
- BlockBySubjectAndPubKey);
- rv = subjectPubKey.ToBase64(encDN, encOther);
- if (NS_FAILED(rv)) {
- return rv;
- }
- MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
- ("CertBlocklist::IsCertRevoked subject %s - pubKey hash %s",
- encDN.get(), encOther.get()));
- *_retval = mBlocklist.Contains(subjectPubKey);
- MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
- ("CertBlocklist::IsCertRevoked by subject / pubkey? %s",
- *_retval ? "true" : "false"));
- return NS_OK;
- }
- NS_IMETHODIMP
- CertBlocklist::IsBlocklistFresh(bool* _retval)
- {
- MutexAutoLock lock(mMutex);
- *_retval = false;
- uint32_t now = uint32_t(PR_Now() / PR_USEC_PER_SEC);
- uint32_t lastUpdate = sLastBlocklistUpdate;
- MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
- ("CertBlocklist::IsBlocklistFresh lastUpdate is %i",
- lastUpdate));
- if (now > lastUpdate) {
- int64_t interval = now - lastUpdate;
- MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
- ("CertBlocklist::IsBlocklistFresh we're after the last BlocklistUpdate "
- "interval is %i, staleness %u", interval, sMaxStaleness));
- *_retval = sMaxStaleness > interval;
- }
- MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
- ("CertBlocklist::IsBlocklistFresh ? %s", *_retval ? "true" : "false"));
- return NS_OK;
- }
- /* static */
- void
- CertBlocklist::PreferenceChanged(const char* aPref, void* aClosure)
- {
- auto blocklist = static_cast<CertBlocklist*>(aClosure);
- MutexAutoLock lock(blocklist->mMutex);
- MOZ_LOG(gCertBlockPRLog, LogLevel::Warning,
- ("CertBlocklist::PreferenceChanged %s changed", aPref));
- if (strcmp(aPref, PREF_BACKGROUND_UPDATE_TIMER) == 0) {
- sLastBlocklistUpdate = Preferences::GetUint(PREF_BACKGROUND_UPDATE_TIMER,
- uint32_t(0));
- } else if (strcmp(aPref, PREF_MAX_STALENESS_IN_SECONDS) == 0) {
- sMaxStaleness = Preferences::GetUint(PREF_MAX_STALENESS_IN_SECONDS,
- uint32_t(0));
- }
- }
|