diff options
Diffstat (limited to 'netwerk/dns/PublicSuffixList.jsm')
-rw-r--r-- | netwerk/dns/PublicSuffixList.jsm | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/netwerk/dns/PublicSuffixList.jsm b/netwerk/dns/PublicSuffixList.jsm new file mode 100644 index 0000000000..1759053fc4 --- /dev/null +++ b/netwerk/dns/PublicSuffixList.jsm @@ -0,0 +1,108 @@ +/* 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/. */ +"use strict"; + +const { RemoteSettings } = ChromeUtils.import( + "resource://services-settings/remote-settings.js" +); +const FileUtils = ChromeUtils.importESModule( + "resource://gre/modules/FileUtils.sys.mjs" +).FileUtils; + +const EXPORTED_SYMBOLS = ["PublicSuffixList"]; + +const RECORD_ID = "tld-dafsa"; +const SIGNAL = "public-suffix-list-updated"; + +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); + }, +}; |