142 lines
4 KiB
JavaScript
142 lines
4 KiB
JavaScript
/* 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/. */
|
|
|
|
const lazy = {};
|
|
|
|
ChromeUtils.defineESModuleGetters(lazy, {
|
|
RemoteSettings: "resource://services-settings/remote-settings.sys.mjs",
|
|
});
|
|
|
|
const COLLECTION_NAME = "partitioning-exempt-urls";
|
|
const PREF_NAME = "privacy.restrict3rdpartystorage.skip_list";
|
|
|
|
class Feature {
|
|
constructor() {
|
|
this.prefName = PREF_NAME;
|
|
this.observers = new Set();
|
|
this.prefValue = [];
|
|
this.remoteEntries = [];
|
|
|
|
if (this.prefName) {
|
|
let prefValue = Services.prefs.getStringPref(this.prefName, null);
|
|
this.prefValue = prefValue ? prefValue.split(";") : [];
|
|
Services.prefs.addObserver(this.prefName, this);
|
|
}
|
|
}
|
|
|
|
async addAndRunObserver(observer) {
|
|
this.observers.add(observer);
|
|
this.notifyObservers(observer);
|
|
}
|
|
|
|
removeObserver(observer) {
|
|
this.observers.delete(observer);
|
|
}
|
|
|
|
observe(subject, topic, data) {
|
|
if (topic != "nsPref:changed" || data != this.prefName) {
|
|
console.error(`Unexpected event ${topic} with ${data}`);
|
|
return;
|
|
}
|
|
|
|
let prefValue = Services.prefs.getStringPref(this.prefName, null);
|
|
this.prefValue = prefValue ? prefValue.split(";") : [];
|
|
this.notifyObservers();
|
|
}
|
|
|
|
onRemoteSettingsUpdate(entries) {
|
|
this.remoteEntries = [];
|
|
|
|
for (let entry of entries) {
|
|
this.remoteEntries.push(
|
|
`${entry.firstPartyOrigin},${entry.thirdPartyOrigin}`
|
|
);
|
|
}
|
|
}
|
|
|
|
notifyObservers(observer = null) {
|
|
let entries = this.prefValue.concat(this.remoteEntries);
|
|
let entriesAsString = entries.join(";").toLowerCase();
|
|
if (observer) {
|
|
observer.onExceptionListUpdate(entriesAsString);
|
|
} else {
|
|
for (let obs of this.observers) {
|
|
obs.onExceptionListUpdate(entriesAsString);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
export function PartitioningExceptionListService() {}
|
|
|
|
PartitioningExceptionListService.prototype = {
|
|
classID: Components.ID("{ab94809d-33f0-4f28-af38-01efbd3baf22}"),
|
|
QueryInterface: ChromeUtils.generateQI([
|
|
"nsIPartitioningExceptionListService",
|
|
]),
|
|
|
|
_initialized: false,
|
|
|
|
async lazyInit() {
|
|
if (this._initialized) {
|
|
return;
|
|
}
|
|
|
|
this.feature = new Feature();
|
|
|
|
let rs = lazy.RemoteSettings(COLLECTION_NAME);
|
|
rs.on("sync", event => {
|
|
let {
|
|
data: { current },
|
|
} = event;
|
|
this.onUpdateEntries(current);
|
|
});
|
|
|
|
this._initialized = true;
|
|
|
|
let entries;
|
|
// If the remote settings list hasn't been populated yet we have to make sure
|
|
// to do it before firing the first notification.
|
|
// This has to be run after _initialized is set because we'll be
|
|
// blocked while getting entries from RemoteSetting, and we don't want
|
|
// LazyInit is executed again.
|
|
try {
|
|
// The data will be initially available from the local DB (via a
|
|
// resource:// URI).
|
|
entries = await rs.get();
|
|
} catch (e) {}
|
|
|
|
// RemoteSettings.get() could return null, ensure passing a list to
|
|
// onUpdateEntries.
|
|
this.onUpdateEntries(entries || []);
|
|
},
|
|
|
|
onUpdateEntries(entries) {
|
|
if (!this.feature) {
|
|
return;
|
|
}
|
|
this.feature.onRemoteSettingsUpdate(entries);
|
|
this.feature.notifyObservers();
|
|
},
|
|
|
|
registerAndRunExceptionListObserver(observer) {
|
|
// We don't await this; the caller is C++ and won't await this function,
|
|
// and because we prevent re-entering into this method, once it's been
|
|
// called once any subsequent calls will early-return anyway - so
|
|
// awaiting that would be meaningless. Instead, `Feature` implementations
|
|
// make sure not to call into observers until they have data, and we
|
|
// make sure to let feature instances know whether we have data
|
|
// immediately.
|
|
this.lazyInit();
|
|
|
|
this.feature.addAndRunObserver(observer);
|
|
},
|
|
|
|
unregisterExceptionListObserver(observer) {
|
|
if (!this.feature) {
|
|
return;
|
|
}
|
|
this.feature.removeObserver(observer);
|
|
},
|
|
};
|