summaryrefslogtreecommitdiffstats
path: root/toolkit/components/passwordmgr/LoginRelatedRealms.sys.mjs
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/passwordmgr/LoginRelatedRealms.sys.mjs')
-rw-r--r--toolkit/components/passwordmgr/LoginRelatedRealms.sys.mjs110
1 files changed, 110 insertions, 0 deletions
diff --git a/toolkit/components/passwordmgr/LoginRelatedRealms.sys.mjs b/toolkit/components/passwordmgr/LoginRelatedRealms.sys.mjs
new file mode 100644
index 0000000000..bcfd675b4b
--- /dev/null
+++ b/toolkit/components/passwordmgr/LoginRelatedRealms.sys.mjs
@@ -0,0 +1,110 @@
+/* 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 { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
+
+const lazy = {};
+
+ChromeUtils.defineESModuleGetters(lazy, {
+ LoginHelper: "resource://gre/modules/LoginHelper.sys.mjs",
+ RemoteSettings: "resource://services-settings/remote-settings.sys.mjs",
+});
+
+XPCOMUtils.defineLazyGetter(lazy, "log", () => {
+ let logger = lazy.LoginHelper.createLogger("LoginRelatedRealms");
+ return logger;
+});
+
+export class LoginRelatedRealmsParent extends JSWindowActorParent {
+ /**
+ * @type RemoteSettingsClient
+ *
+ * @memberof LoginRelatedRealmsParent
+ */
+ _sharedCredentialsClient = null;
+ /**
+ * @type string[][]
+ *
+ * @memberof LoginRelatedRealmsParent
+ */
+ _relatedDomainsList = [[]];
+
+ /**
+ * Handles the Remote Settings sync event
+ *
+ * @param {Object} aEvent
+ * @param {Array} aEvent.current Records that are currently in the collection after the sync event
+ * @param {Array} aEvent.created Records that were created
+ * @param {Array} aEvent.updated Records that were updated
+ * @param {Array} aEvent.deleted Records that were deleted
+ * @memberof LoginRelatedRealmsParent
+ */
+ onRemoteSettingsSync(aEvent) {
+ let {
+ data: { current },
+ } = aEvent;
+ this._relatedDomainsList = current;
+ }
+
+ async getSharedCredentialsCollection() {
+ if (!this._sharedCredentialsClient) {
+ this._sharedCredentialsClient = lazy.RemoteSettings(
+ lazy.LoginHelper.relatedRealmsCollection
+ );
+ this._sharedCredentialsClient.on("sync", event =>
+ this.onRemoteSettingsSync(event)
+ );
+ this._relatedDomainsList = await this._sharedCredentialsClient.get();
+ }
+ return this._relatedDomainsList;
+ }
+
+ /**
+ * Determine if there are any related realms of this `formOrigin` using the related realms collection
+ * @param {string} formOrigin A form origin
+ * @return {string[]} filteredRealms An array of domains related to the `formOrigin`
+ * @async
+ * @memberof LoginRelatedRealmsParent
+ */
+ async findRelatedRealms(formOrigin) {
+ try {
+ let formOriginURI = Services.io.newURI(formOrigin);
+ let originDomain = formOriginURI.host;
+ let [{ relatedRealms } = {}] =
+ await this.getSharedCredentialsCollection();
+ if (!relatedRealms) {
+ return [];
+ }
+ let filterOriginIndex;
+ let shouldInclude = false;
+ let filteredRealms = relatedRealms.filter(_realms => {
+ for (let relatedOrigin of _realms) {
+ // We can't have an origin that matches multiple entries in our related realms collection
+ // so we exit the loop early
+ if (shouldInclude) {
+ return false;
+ }
+ if (Services.eTLD.hasRootDomain(originDomain, relatedOrigin)) {
+ shouldInclude = true;
+ break;
+ }
+ }
+ return shouldInclude;
+ });
+ // * Filtered realms is a nested array due to its structure in Remote Settings
+ filteredRealms = filteredRealms.flat();
+
+ filterOriginIndex = filteredRealms.indexOf(originDomain);
+ // Removing the current formOrigin match if it exists in the related realms
+ // so that we don't return duplicates when we search for logins
+ if (filterOriginIndex !== -1) {
+ filteredRealms.splice(filterOriginIndex, 1);
+ }
+ return filteredRealms;
+ } catch (e) {
+ lazy.log.error(e);
+ return [];
+ }
+ }
+}