Bug 1786310 - Offboard the main/public-suffix-list Remote Settings collection r=valentin,Gijs,necko-reviewers,firefox-desktop-core-reviewers

Reverts the work done in:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1563226
- https://bugzilla.mozilla.org/show_bug.cgi?id=1582647
- https://bugzilla.mozilla.org/show_bug.cgi?id=1563246

Differential Revision: https://phabricator.services.mozilla.com/D234356
This commit is contained in:
Mathieu Leplatre
2025-01-17 11:47:30 +00:00
parent 8e209660aa
commit 24dad11c20
13 changed files with 7 additions and 478 deletions

View File

@@ -77,8 +77,6 @@ ChromeUtils.defineESModuleGetters(lazy, {
PluginManager: "resource:///actors/PluginParent.sys.mjs",
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs",
ProcessHangMonitor: "resource:///modules/ProcessHangMonitor.sys.mjs",
PublicSuffixList:
"resource://gre/modules/netwerk-dns/PublicSuffixList.sys.mjs",
QuickSuggest: "resource:///modules/QuickSuggest.sys.mjs",
RFPHelper: "resource://gre/modules/RFPHelper.sys.mjs",
RemoteSecuritySettings:
@@ -3265,10 +3263,6 @@ BrowserGlue.prototype = {
this._addBreachesSyncHandler();
}.bind(this),
function PublicSuffixListInit() {
lazy.PublicSuffixList.init();
},
function RemoteSecuritySettingsInit() {
lazy.RemoteSecuritySettings.init();
},

View File

@@ -3095,12 +3095,6 @@ pref("network.tcp.keepalive.idle_time", 600); // seconds; 10 mins
pref("network.tcp.keepalive.probe_count", 4);
#endif
// This pref controls if we send the "public-suffix-list-updated" notification
// from PublicSuffixList.onUpdate() - Doing so would cause the PSL graph to
// be updated while Firefox is running which may cause principals to have an
// inconsistent state. See bug 1582647 comment 30
pref("network.psl.onUpdate_notify", false);
#ifdef MOZ_WIDGET_GTK
pref("widget.disable-workspace-management", false);
#endif

View File

@@ -1,104 +0,0 @@
/* 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/. */
import { RemoteSettings } from "resource://services-settings/remote-settings.sys.mjs";
const FileUtils = ChromeUtils.importESModule(
"resource://gre/modules/FileUtils.sys.mjs"
).FileUtils;
const RECORD_ID = "tld-dafsa";
const SIGNAL = "public-suffix-list-updated";
export const PublicSuffixList = {
CLIENT: RemoteSettings("public-suffix-list"),
init() {
// Only initialize once.
if (this._initialized) {
return;
}
this._initialized = true;
this.CLIENT.on("sync", this.onUpdate.bind(this));
/* We have a single record for this collection. Let's see if we already have it locally.
* Note that on startup, we don't need to synchronize immediately on new profiles.
*/
this.CLIENT.get({ syncIfEmpty: false, filters: { id: RECORD_ID } })
.then(async records => {
if (records.length == 1) {
// Get the downloaded file URI (most likely to be a no-op here, since file will exist).
const fileURI = await this.CLIENT.attachments.downloadToDisk(
records[0]
);
// Send a signal so that the C++ code loads the updated list on startup.
this.notifyUpdate(fileURI);
}
})
.catch(err => console.error(err));
},
/**
* This method returns the path to the file based on the file uri received
* Example:
* On windows "file://C:/Users/AppData/main/public-suffix-list/dafsa.bin"
* will be converted to "C:\\Users\\main\\public-suffix-list\\dafsa.bin
*
* On macOS/linux "file:///home/main/public-suffix-list/dafsa.bin"
* will be converted to "/home/main/public-suffix-list/dafsa.bin"
*/
getFilePath(fileURI) {
const uri = Services.io.newURI(fileURI);
const file = uri.QueryInterface(Ci.nsIFileURL).file;
return file.path;
},
notifyUpdate(fileURI) {
if (!Services.prefs.getBoolPref("network.psl.onUpdate_notify", false)) {
// Updating the PSL while Firefox is running could cause principals to
// have a different base domain before/after the update.
// See bug 1582647 comment 30
return;
}
const filePath = this.getFilePath(fileURI);
const nsifile = new FileUtils.File(filePath);
/* Send a signal to be read by the C++, the method
* ::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData)
* at netwerk/dns/nsEffectiveTLDService.cpp
*/
Services.obs.notifyObservers(
nsifile, // aSubject
SIGNAL, // aTopic
filePath // aData
);
},
async onUpdate({ data: { created, updated, deleted } }) {
// In theory, this will never happen, we will never delete the record.
if (deleted.length == 1) {
await this.CLIENT.attachments.deleteFromDisk(deleted[0]);
}
// Handle creation and update the same way
const changed = created.concat(updated.map(u => u.new));
/* In theory, we should never have more than one record. And if we receive
* this event, it's because the single record was updated.
*/
if (changed.length != 1) {
console.warn("Unsupported sync event for Public Suffix List");
return;
}
// Download the updated file.
let fileURI;
try {
fileURI = await this.CLIENT.attachments.downloadToDisk(changed[0]);
} catch (err) {
console.error(err);
return;
}
// Notify the C++ part to reload it from disk.
this.notifyUpdate(fileURI);
},
};

View File

@@ -7,8 +7,6 @@
with Files("**"):
BUG_COMPONENT = ("Core", "Networking: DNS")
DIRS += ["tests"]
XPIDL_SOURCES += [
"nsIDNSAdditionalInfo.idl",
"nsIDNSByTypeRecord.idl",
@@ -24,10 +22,6 @@ XPIDL_SOURCES += [
XPIDL_MODULE = "necko_dns"
EXTRA_JS_MODULES["netwerk-dns"] += [
"PublicSuffixList.sys.mjs",
]
XPCSHELL_TESTS_MANIFESTS += ["tests/unit/xpcshell.toml"]
EXPORTS += [

View File

@@ -21,7 +21,6 @@
#include "nsCRT.h"
#include "nsEffectiveTLDService.h"
#include "nsIFile.h"
#include "nsIObserverService.h"
#include "nsIURI.h"
#include "nsNetCID.h"
#include "nsNetUtil.h"
@@ -38,21 +37,16 @@ namespace etld_dafsa {
using namespace mozilla;
NS_IMPL_ISUPPORTS(nsEffectiveTLDService, nsIEffectiveTLDService,
nsIMemoryReporter, nsIObserver)
nsIMemoryReporter)
// ----------------------------------------------------------------------
static nsEffectiveTLDService* gService = nullptr;
nsEffectiveTLDService::nsEffectiveTLDService()
: mGraphLock("nsEffectiveTLDService::mGraph") {
mGraph.emplace(etld_dafsa::kDafsa);
}
nsEffectiveTLDService::nsEffectiveTLDService() : mGraph(etld_dafsa::kDafsa) {}
nsresult nsEffectiveTLDService::Init() {
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
obs->AddObserver(this, "public-suffix-list-updated", false);
if (gService) {
return NS_ERROR_ALREADY_INITIALIZED;
@@ -64,39 +58,6 @@ nsresult nsEffectiveTLDService::Init() {
return NS_OK;
}
NS_IMETHODIMP nsEffectiveTLDService::Observe(nsISupports* aSubject,
const char* aTopic,
const char16_t* aData) {
/**
* Signal sent from netwerk/dns/PublicSuffixList.sys.mjs
* aSubject is the nsIFile object for dafsa.bin
* aData is the absolute path to the dafsa.bin file (not used)
*/
if (aSubject && (nsCRT::strcmp(aTopic, "public-suffix-list-updated") == 0)) {
nsCOMPtr<nsIFile> mDafsaBinFile(do_QueryInterface(aSubject));
NS_ENSURE_TRUE(mDafsaBinFile, NS_ERROR_ILLEGAL_VALUE);
AutoWriteLock lock(mGraphLock);
// Reset mGraph with kDafsa in case reassigning to mDafsaMap fails
mGraph.reset();
mGraph.emplace(etld_dafsa::kDafsa);
mDafsaMap.reset();
mMruTable.Clear();
MOZ_TRY(mDafsaMap.init(mDafsaBinFile));
size_t size = mDafsaMap.size();
const uint8_t* remoteDafsaPtr = mDafsaMap.get<uint8_t>().get();
auto remoteDafsa = mozilla::Span(remoteDafsaPtr, size);
mGraph.reset();
mGraph.emplace(remoteDafsa);
}
return NS_OK;
}
nsEffectiveTLDService::~nsEffectiveTLDService() {
UnregisterWeakMemoryReporter(this);
gService = nullptr;
@@ -399,12 +360,9 @@ nsresult nsEffectiveTLDService::GetBaseDomainInternal(
return NS_ERROR_INVALID_ARG;
}
int result;
{
AutoReadLock lock(mGraphLock);
// Perform the lookup.
result = mGraph->Lookup(Substring(currDomain, end));
}
// Perform the lookup.
const int result = mGraph.Lookup(Substring(currDomain, end));
if (result != Dafsa::kKeyNotFound) {
hasKnownPublicSuffix = true;
if (result == kWildcardRule && prevDomain) {
@@ -537,8 +495,6 @@ nsEffectiveTLDService::HasKnownPublicSuffixFromHost(const nsACString& aHostname,
hostname.Truncate(hostname.Length() - 1);
}
AutoReadLock lock(mGraphLock);
// Check if we can find a suffix on the PSL. Start with the top level domain
// (for example "com" in "example.com"). If that isn't on the PSL, continue to
// add domain segments from the end (for example for "example.co.za", "za" is
@@ -551,7 +507,7 @@ nsEffectiveTLDService::HasKnownPublicSuffixFromHost(const nsACString& aHostname,
const nsACString& suffix = Substring(
hostname, dotBeforeSuffix == kNotFound ? 0 : dotBeforeSuffix + 1);
if (mGraph->Lookup(suffix) != Dafsa::kKeyNotFound) {
if (mGraph.Lookup(suffix) != Dafsa::kKeyNotFound) {
*aResult = true;
return NS_OK;
}

View File

@@ -19,19 +19,16 @@
#include "nsCOMPtr.h"
#include "nsHashKeys.h"
#include "nsIMemoryReporter.h"
#include "nsIObserver.h"
#include "nsString.h"
class nsIIDNService;
class nsEffectiveTLDService final : public nsIEffectiveTLDService,
public nsIObserver,
public nsIMemoryReporter {
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIEFFECTIVETLDSERVICE
NS_DECL_NSIMEMORYREPORTER
NS_DECL_NSIOBSERVER
nsEffectiveTLDService();
nsresult Init();
@@ -47,13 +44,7 @@ class nsEffectiveTLDService final : public nsIEffectiveTLDService,
~nsEffectiveTLDService();
// The DAFSA provides a compact encoding of the rather large eTLD list.
mozilla::Maybe<mozilla::Dafsa> mGraph MOZ_GUARDED_BY(mGraphLock);
// Memory map used for a new updated dafsa
mozilla::loader::AutoMemMap mDafsaMap MOZ_GUARDED_BY(mGraphLock);
// Lock for mGraph and mDafsaMap
mozilla::RWLock mGraphLock;
mozilla::Dafsa mGraph;
// Note that the cache entries here can record entries that were cached
// successfully or unsuccessfully. mResult must be checked before using an

View File

@@ -1,7 +0,0 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
DIRS += ["unit"]

View File

@@ -1,57 +0,0 @@
// 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 https://mozilla.org/MPL/2.0/.
// This is a fake suffix list created only for the purposes of testing,
// The real PSL is rather large thus this file is kept small by cutting out most of the suffixes
// The Original list can be found at https://publicsuffix.org/list/public_suffix_list.dat,
// Learn more about the PSL at https://publicsuffix.org.
// .xpcshelltest is the fake domain created specifically for the the tests while
// the others are ripped from the real list, serving as examples.
// This fake public suffix list was used to create the binary file fake_remote_dafsa.bin
// The binary is built at compile time and can be found at
// obj-dir/_tests/xpcshell/netwerk/dns/tests/unit/data/
// The list created with help of netwerk/dns/prepare_tlds.py and xpcom/ds/tools/make_dafsa.py
// The build directive for the binary is at moz.build at netwerk/dns/tests/unit/data/
// ===BEGIN ICANN DOMAINS===
// xpcshelltest : Used in tests
xpcshelltest
website.xpcshelltest
com.xpcshelltest
edu.xpcshelltest
gov.xpcshelltest
net.xpcshelltest
mil.xpcshelltest
org.xpcshelltest
// ac : https://en.wikipedia.org/wiki/.ac
ac
coc.ac
com.ac
edu.ac
gov.ac
net.ac
mil.ac
org.ac
// bj : https://en.wikipedia.org/wiki/.bj
bj
asso.bj
barreau.bj
gouv.bj
// bm : http://www.bermudanic.bm/dnr-text.txt
bm
com.bm
edu.bm
gov.bm
net.bm
org.bm

View File

@@ -1,14 +0,0 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
GeneratedFile(
"fake_remote_dafsa.bin",
script="../../../prepare_tlds.py",
inputs=["fake_public_suffix_list.dat"],
flags=["bin"],
)
TEST_HARNESS_FILES.xpcshell.netwerk.dns.tests.unit.data += ["!fake_remote_dafsa.bin"]

View File

@@ -1,7 +0,0 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
DIRS += ["data"]

View File

@@ -1,174 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* https://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const { PublicSuffixList } = ChromeUtils.importESModule(
"resource://gre/modules/netwerk-dns/PublicSuffixList.sys.mjs"
);
const { TestUtils } = ChromeUtils.importESModule(
"resource://testing-common/TestUtils.sys.mjs"
);
const CLIENT = PublicSuffixList.CLIENT;
const SIGNAL = "public-suffix-list-updated";
const PAYLOAD_UPDATED_RECORDS = {
current: [{ id: "tld-dafsa", "commit-hash": "current-commit-hash" }],
created: [],
updated: [
{
old: { id: "tld-dafsa", "commit-hash": "current-commit-hash" },
new: { id: "tld-dafsa", "commit-hash": "new-commit-hash" },
},
],
deleted: [],
};
const PAYLOAD_CREATED_RECORDS = {
current: [],
created: [
{
id: "tld-dafsa",
"commit-hash": "new-commit-hash",
attachment: {},
},
],
updated: [],
deleted: [],
};
const PAYLOAD_UPDATED_AND_CREATED_RECORDS = {
current: [{ id: "tld-dafsa", "commit-hash": "current-commit-hash" }],
created: [{ id: "tld-dafsa", "commit-hash": "another-commit-hash" }],
updated: [
{
old: { id: "tld-dafsa", "commit-hash": "current-commit-hash" },
new: { id: "tld-dafsa", "commit-hash": "new-commit-hash" },
},
],
deleted: [],
};
const fakeDafsaBinFile = do_get_file("data/fake_remote_dafsa.bin");
const mockedFilePath = fakeDafsaBinFile.path;
function setup() {
Services.prefs.setBoolPref("network.psl.onUpdate_notify", true);
}
setup();
registerCleanupFunction(() => {
Services.prefs.clearUserPref("network.psl.onUpdate_notify");
});
/**
* downloadToDiskCalled is used by mockDownloadToDisk() and resetMockDownloadToDisk()
* to keep track weather CLIENT.attachments.download is called or not
* downloadToDiskBackup will help restore CLIENT.attachments.download to original definition
* notifyUpdateBackup will help restore PublicSuffixList.notifyUpdate to original definition
*/
let downloadToDiskCalled = false;
const downloadToDiskBackup = CLIENT.attachments.downloadToDisk;
// returns a fake fileURI and sends a signal with filePath and no nsifile
function mockDownloadToDisk() {
downloadToDiskCalled = false;
CLIENT.attachments.downloadToDisk = async () => {
downloadToDiskCalled = true;
return `file://${mockedFilePath}`; // Create a fake file URI
};
}
// resetMockDownloadToDisk() must be run at the end of the test that uses mockDownloadToDisk()
const resetMockDownloadToDisk = () => {
CLIENT.attachments.downloadToDisk = downloadToDiskBackup;
};
add_task(async () => {
info("File path sent when record is in DB.");
await CLIENT.db.clear(); // Make sure there's no record initially
await CLIENT.db.create({
id: "tld-dafsa",
"commit-hash": "fake-commit-hash",
attachment: {},
});
mockDownloadToDisk();
const promiseSignal = TestUtils.topicObserved(SIGNAL);
await PublicSuffixList.init();
const observed = await promiseSignal;
Assert.equal(
observed[1],
mockedFilePath,
"File path sent when record is in DB."
);
await CLIENT.db.clear(); // Clean up the mockDownloaded record
resetMockDownloadToDisk();
});
add_task(async () => {
info("File path sent when record updated.");
mockDownloadToDisk();
const promiseSignal = TestUtils.topicObserved(SIGNAL);
await PublicSuffixList.init();
await CLIENT.emit("sync", { data: PAYLOAD_UPDATED_RECORDS });
const observed = await promiseSignal;
Assert.equal(
observed[1],
mockedFilePath,
"File path sent when record updated."
);
resetMockDownloadToDisk();
});
add_task(async () => {
info("Attachment downloaded when record created.");
mockDownloadToDisk();
await PublicSuffixList.init();
await CLIENT.emit("sync", { data: PAYLOAD_CREATED_RECORDS });
Assert.equal(
downloadToDiskCalled,
true,
"Attachment downloaded when record created."
);
resetMockDownloadToDisk();
});
add_task(async () => {
info("Attachment downloaded when record updated.");
mockDownloadToDisk();
await PublicSuffixList.init();
await CLIENT.emit("sync", { data: PAYLOAD_UPDATED_RECORDS });
Assert.equal(
downloadToDiskCalled,
true,
"Attachment downloaded when record updated."
);
resetMockDownloadToDisk();
});
add_task(async () => {
info("No download when more than one record is changed.");
mockDownloadToDisk();
await PublicSuffixList.init();
await CLIENT.emit("sync", { data: PAYLOAD_UPDATED_AND_CREATED_RECORDS });
Assert.equal(
downloadToDiskCalled,
false,
"No download when more than one record is changed."
);
resetMockDownloadToDisk();
});

View File

@@ -1,32 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* https://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const SIGNAL = "public-suffix-list-updated";
add_task(async () => {
info("Before fake dafsa reload.");
let suffix = Services.eTLD.getPublicSuffixFromHost("website.xpcshelltest");
Assert.equal(
suffix,
"xpcshelltest",
"Fake Suffix does not exist in current PSL."
);
});
add_task(async () => {
info("After fake dafsa reload.");
// reload the PSL with fake data containing .xpcshelltest
const fakeDafsaFile = do_get_file("data/fake_remote_dafsa.bin");
Services.obs.notifyObservers(fakeDafsaFile, SIGNAL, fakeDafsaFile.path);
let suffix = Services.eTLD.getPublicSuffixFromHost("website.xpcshelltest");
Assert.equal(
suffix,
"website.xpcshelltest",
"Fake Suffix now exists in PSL after DAFSA reload."
);
});

View File

@@ -7,11 +7,6 @@ support-files = [
"!/services/common/tests/unit/head_helpers.js",
]
["test_PublicSuffixList.js"]
tags = "remote-settings"
["test_nsEffectiveTLDService_Reload_DAFSA.js"]
["test_nsEffectiveTLDService_getKnownPublicSuffix.js"]
["test_nsEffectiveTLDService_getSite.js"]