forked from mirrors/gecko-dev
317 lines
8.8 KiB
JavaScript
317 lines
8.8 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/. */
|
|
|
|
import { LoginHelper } from "resource://gre/modules/LoginHelper.sys.mjs";
|
|
|
|
import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
|
|
|
|
const lazy = {};
|
|
|
|
XPCOMUtils.defineLazyServiceGetter(
|
|
lazy,
|
|
"ClipboardHelper",
|
|
"@mozilla.org/widget/clipboardhelper;1",
|
|
"nsIClipboardHelper"
|
|
);
|
|
|
|
const TELEMETRY_EVENT_CATEGORY = "pwmgr";
|
|
const TELEMETRY_MIN_MS_BETWEEN_OPEN_MANAGEMENT = 5000;
|
|
|
|
let gLastOpenManagementBrowserId = null;
|
|
let gLastOpenManagementEventTime = Number.NEGATIVE_INFINITY;
|
|
let gPrimaryPasswordPromise;
|
|
|
|
function recordTelemetryEvent(event) {
|
|
try {
|
|
let { method, object, extra = {}, value = null } = event;
|
|
Services.telemetry.recordEvent(
|
|
TELEMETRY_EVENT_CATEGORY,
|
|
method,
|
|
object,
|
|
value,
|
|
extra
|
|
);
|
|
} catch (ex) {
|
|
console.error("AboutLoginsChild: error recording telemetry event:", ex);
|
|
}
|
|
}
|
|
|
|
export class AboutLoginsChild extends JSWindowActorChild {
|
|
handleEvent(event) {
|
|
switch (event.type) {
|
|
case "AboutLoginsInit": {
|
|
this.#aboutLoginsInit();
|
|
break;
|
|
}
|
|
case "AboutLoginsImportReportInit": {
|
|
this.#aboutLoginsImportReportInit();
|
|
break;
|
|
}
|
|
case "AboutLoginsCopyLoginDetail": {
|
|
this.#aboutLoginsCopyLoginDetail(event.detail);
|
|
break;
|
|
}
|
|
case "AboutLoginsCreateLogin": {
|
|
this.#aboutLoginsCreateLogin(event.detail);
|
|
break;
|
|
}
|
|
case "AboutLoginsDeleteLogin": {
|
|
this.#aboutLoginsDeleteLogin(event.detail);
|
|
break;
|
|
}
|
|
case "AboutLoginsExportPasswords": {
|
|
this.#aboutLoginsExportPasswords();
|
|
break;
|
|
}
|
|
case "AboutLoginsGetHelp": {
|
|
this.#aboutLoginsGetHelp();
|
|
break;
|
|
}
|
|
case "AboutLoginsImportFromBrowser": {
|
|
this.#aboutLoginsImportFromBrowser();
|
|
break;
|
|
}
|
|
case "AboutLoginsImportFromFile": {
|
|
this.#aboutLoginsImportFromFile();
|
|
break;
|
|
}
|
|
case "AboutLoginsOpenPreferences": {
|
|
this.#aboutLoginsOpenPreferences();
|
|
break;
|
|
}
|
|
case "AboutLoginsRecordTelemetryEvent": {
|
|
this.#aboutLoginsRecordTelemetryEvent(event);
|
|
break;
|
|
}
|
|
case "AboutLoginsRemoveAllLogins": {
|
|
this.#aboutLoginsRemoveAllLogins();
|
|
break;
|
|
}
|
|
case "AboutLoginsSortChanged": {
|
|
this.#aboutLoginsSortChanged(event.detail);
|
|
break;
|
|
}
|
|
case "AboutLoginsSyncEnable": {
|
|
this.#aboutLoginsSyncEnable();
|
|
break;
|
|
}
|
|
case "AboutLoginsSyncOptions": {
|
|
this.#aboutLoginsSyncOptions();
|
|
break;
|
|
}
|
|
case "AboutLoginsUpdateLogin": {
|
|
this.#aboutLoginsUpdateLogin(event.detail);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
#aboutLoginsInit() {
|
|
this.sendAsyncMessage("AboutLogins:Subscribe");
|
|
|
|
let win = this.browsingContext.window;
|
|
let waivedContent = Cu.waiveXrays(win);
|
|
let that = this;
|
|
let AboutLoginsUtils = {
|
|
doLoginsMatch(loginA, loginB) {
|
|
return LoginHelper.doLoginsMatch(loginA, loginB, {});
|
|
},
|
|
getLoginOrigin(uriString) {
|
|
return LoginHelper.getLoginOrigin(uriString);
|
|
},
|
|
setFocus(element) {
|
|
Services.focus.setFocus(element, Services.focus.FLAG_BYKEY);
|
|
},
|
|
/**
|
|
* Shows the Primary Password prompt if enabled, or the
|
|
* OS auth dialog otherwise.
|
|
* @param resolve Callback that is called with result of authentication.
|
|
* @param messageId The string ID that corresponds to a string stored in aboutLogins.ftl.
|
|
* This string will be displayed only when the OS auth dialog is used.
|
|
*/
|
|
async promptForPrimaryPassword(resolve, messageId) {
|
|
gPrimaryPasswordPromise = {
|
|
resolve,
|
|
};
|
|
|
|
that.sendAsyncMessage("AboutLogins:PrimaryPasswordRequest", messageId);
|
|
|
|
return gPrimaryPasswordPromise;
|
|
},
|
|
fileImportEnabled: Services.prefs.getBoolPref(
|
|
"signon.management.page.fileImport.enabled"
|
|
),
|
|
// Default to enabled just in case a search is attempted before we get a response.
|
|
primaryPasswordEnabled: true,
|
|
passwordRevealVisible: true,
|
|
};
|
|
waivedContent.AboutLoginsUtils = Cu.cloneInto(
|
|
AboutLoginsUtils,
|
|
waivedContent,
|
|
{
|
|
cloneFunctions: true,
|
|
}
|
|
);
|
|
}
|
|
|
|
#aboutLoginsImportReportInit() {
|
|
this.sendAsyncMessage("AboutLogins:ImportReportInit");
|
|
}
|
|
|
|
#aboutLoginsCopyLoginDetail(detail) {
|
|
lazy.ClipboardHelper.copyString(
|
|
detail,
|
|
this.windowContext,
|
|
lazy.ClipboardHelper.Sensitive
|
|
);
|
|
}
|
|
|
|
#aboutLoginsCreateLogin(login) {
|
|
this.sendAsyncMessage("AboutLogins:CreateLogin", {
|
|
login,
|
|
});
|
|
}
|
|
|
|
#aboutLoginsDeleteLogin(login) {
|
|
this.sendAsyncMessage("AboutLogins:DeleteLogin", {
|
|
login,
|
|
});
|
|
}
|
|
|
|
#aboutLoginsExportPasswords() {
|
|
this.sendAsyncMessage("AboutLogins:ExportPasswords");
|
|
}
|
|
|
|
#aboutLoginsGetHelp() {
|
|
this.sendAsyncMessage("AboutLogins:GetHelp");
|
|
}
|
|
|
|
#aboutLoginsImportFromBrowser() {
|
|
this.sendAsyncMessage("AboutLogins:ImportFromBrowser");
|
|
recordTelemetryEvent({
|
|
object: "import_from_browser",
|
|
method: "mgmt_menu_item_used",
|
|
});
|
|
}
|
|
|
|
#aboutLoginsImportFromFile() {
|
|
this.sendAsyncMessage("AboutLogins:ImportFromFile");
|
|
recordTelemetryEvent({
|
|
object: "import_from_csv",
|
|
method: "mgmt_menu_item_used",
|
|
});
|
|
}
|
|
|
|
#aboutLoginsOpenPreferences() {
|
|
this.sendAsyncMessage("AboutLogins:OpenPreferences");
|
|
recordTelemetryEvent({
|
|
object: "preferences",
|
|
method: "mgmt_menu_item_used",
|
|
});
|
|
}
|
|
|
|
#aboutLoginsRecordTelemetryEvent(event) {
|
|
let { method } = event.detail;
|
|
|
|
if (method == "open_management") {
|
|
let { docShell } = this.browsingContext;
|
|
// Compare to the last time open_management was recorded for the same
|
|
// outerWindowID to not double-count them due to a redirect to remove
|
|
// the entryPoint query param (since replaceState isn't allowed for
|
|
// about:). Don't use performance.now for the tab since you can't
|
|
// compare that number between different tabs and this JSM is shared.
|
|
let now = docShell.now();
|
|
if (
|
|
this.browsingContext.browserId == gLastOpenManagementBrowserId &&
|
|
now - gLastOpenManagementEventTime <
|
|
TELEMETRY_MIN_MS_BETWEEN_OPEN_MANAGEMENT
|
|
) {
|
|
return;
|
|
}
|
|
gLastOpenManagementEventTime = now;
|
|
gLastOpenManagementBrowserId = this.browsingContext.browserId;
|
|
}
|
|
recordTelemetryEvent(event.detail);
|
|
}
|
|
|
|
#aboutLoginsRemoveAllLogins() {
|
|
this.sendAsyncMessage("AboutLogins:RemoveAllLogins");
|
|
}
|
|
|
|
#aboutLoginsSortChanged(detail) {
|
|
this.sendAsyncMessage("AboutLogins:SortChanged", detail);
|
|
}
|
|
|
|
#aboutLoginsSyncEnable() {
|
|
this.sendAsyncMessage("AboutLogins:SyncEnable");
|
|
}
|
|
|
|
#aboutLoginsSyncOptions() {
|
|
this.sendAsyncMessage("AboutLogins:SyncOptions");
|
|
}
|
|
|
|
#aboutLoginsUpdateLogin(login) {
|
|
this.sendAsyncMessage("AboutLogins:UpdateLogin", {
|
|
login,
|
|
});
|
|
}
|
|
|
|
receiveMessage(message) {
|
|
switch (message.name) {
|
|
case "AboutLogins:ImportReportData":
|
|
this.#importReportData(message.data);
|
|
break;
|
|
case "AboutLogins:PrimaryPasswordResponse":
|
|
this.#primaryPasswordResponse(message.data);
|
|
break;
|
|
case "AboutLogins:RemaskPassword":
|
|
this.#remaskPassword(message.data);
|
|
break;
|
|
case "AboutLogins:Setup":
|
|
this.#setup(message.data);
|
|
break;
|
|
default:
|
|
this.#passMessageDataToContent(message);
|
|
}
|
|
}
|
|
|
|
#importReportData(data) {
|
|
this.sendToContent("ImportReportData", data);
|
|
}
|
|
|
|
#primaryPasswordResponse(data) {
|
|
if (gPrimaryPasswordPromise) {
|
|
gPrimaryPasswordPromise.resolve(data.result);
|
|
recordTelemetryEvent(data.telemetryEvent);
|
|
}
|
|
}
|
|
|
|
#remaskPassword(data) {
|
|
this.sendToContent("RemaskPassword", data);
|
|
}
|
|
|
|
#setup(data) {
|
|
let utils = Cu.waiveXrays(this.browsingContext.window).AboutLoginsUtils;
|
|
utils.primaryPasswordEnabled = data.primaryPasswordEnabled;
|
|
utils.passwordRevealVisible = data.passwordRevealVisible;
|
|
utils.importVisible = data.importVisible;
|
|
utils.supportBaseURL = Services.urlFormatter.formatURLPref(
|
|
"app.support.baseURL"
|
|
);
|
|
this.sendToContent("Setup", data);
|
|
}
|
|
|
|
#passMessageDataToContent(message) {
|
|
this.sendToContent(message.name.replace("AboutLogins:", ""), message.data);
|
|
}
|
|
|
|
sendToContent(messageType, detail) {
|
|
let win = this.document.defaultView;
|
|
let message = Object.assign({ messageType }, { value: detail });
|
|
let event = new win.CustomEvent("AboutLoginsChromeToContent", {
|
|
detail: Cu.cloneInto(message, win),
|
|
});
|
|
win.dispatchEvent(event);
|
|
}
|
|
}
|