Bug 1915672 - Add Telemetry for OSAuth for Formautofill and about:logins. r=dimi,mtigley,settings-reviewers,firefox-desktop-core-reviewers ,joschmidt
Differential Revision: https://phabricator.services.mozilla.com/D232339
This commit is contained in:
@@ -3160,6 +3160,21 @@ BrowserGlue.prototype = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: "OS Authentication telemetry",
|
||||||
|
task: () => {
|
||||||
|
const osAuthForCc = lazy.FormAutofillUtils.getOSAuthEnabled(
|
||||||
|
lazy.FormAutofillUtils.AUTOFILL_CREDITCARDS_REAUTH_PREF
|
||||||
|
);
|
||||||
|
const osAuthForPw = lazy.LoginHelper.getOSAuthEnabled(
|
||||||
|
lazy.LoginHelper.OS_AUTH_FOR_PASSWORDS_PREF
|
||||||
|
);
|
||||||
|
|
||||||
|
Glean.formautofill.osAuthEnabled.set(osAuthForCc);
|
||||||
|
Glean.pwmgr.osAuthEnabled.set(osAuthForPw);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
name: "browser-startup-idle-tasks-finished",
|
name: "browser-startup-idle-tasks-finished",
|
||||||
task: () => {
|
task: () => {
|
||||||
|
|||||||
@@ -121,13 +121,17 @@ export class AboutLoginsChild extends JSWindowActorChild {
|
|||||||
* @param resolve Callback that is called with result of authentication.
|
* @param resolve Callback that is called with result of authentication.
|
||||||
* @param messageId The string ID that corresponds to a string stored in aboutLogins.ftl.
|
* @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.
|
* This string will be displayed only when the OS auth dialog is used.
|
||||||
|
* @param reason The reason for requesting reauthentication, used for telemetry.
|
||||||
*/
|
*/
|
||||||
async promptForPrimaryPassword(resolve, messageId) {
|
async promptForPrimaryPassword(resolve, messageId, reason) {
|
||||||
gPrimaryPasswordPromise = {
|
gPrimaryPasswordPromise = {
|
||||||
resolve,
|
resolve,
|
||||||
};
|
};
|
||||||
|
|
||||||
that.sendAsyncMessage("AboutLogins:PrimaryPasswordRequest", messageId);
|
that.sendAsyncMessage("AboutLogins:PrimaryPasswordRequest", {
|
||||||
|
messageId,
|
||||||
|
reason,
|
||||||
|
});
|
||||||
|
|
||||||
return gPrimaryPasswordPromise;
|
return gPrimaryPasswordPromise;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -131,7 +131,10 @@ export class AboutLoginsParent extends JSWindowActorParent {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "AboutLogins:PrimaryPasswordRequest": {
|
case "AboutLogins:PrimaryPasswordRequest": {
|
||||||
await this.#primaryPasswordRequest(message.data);
|
await this.#primaryPasswordRequest(
|
||||||
|
message.data.messageId,
|
||||||
|
message.data.reason
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "AboutLogins:Subscribe": {
|
case "AboutLogins:Subscribe": {
|
||||||
@@ -245,7 +248,7 @@ export class AboutLoginsParent extends JSWindowActorParent {
|
|||||||
this.#ownerGlobal.openPreferences("privacy-logins");
|
this.#ownerGlobal.openPreferences("privacy-logins");
|
||||||
}
|
}
|
||||||
|
|
||||||
async #primaryPasswordRequest(messageId) {
|
async #primaryPasswordRequest(messageId, reason) {
|
||||||
if (!messageId) {
|
if (!messageId) {
|
||||||
throw new Error("AboutLogins:PrimaryPasswordRequest: no messageId.");
|
throw new Error("AboutLogins:PrimaryPasswordRequest: no messageId.");
|
||||||
}
|
}
|
||||||
@@ -277,7 +280,8 @@ export class AboutLoginsParent extends JSWindowActorParent {
|
|||||||
isOSAuthEnabled,
|
isOSAuthEnabled,
|
||||||
AboutLogins._authExpirationTime,
|
AboutLogins._authExpirationTime,
|
||||||
messageText.value,
|
messageText.value,
|
||||||
captionText.value
|
captionText.value,
|
||||||
|
reason
|
||||||
);
|
);
|
||||||
this.sendAsyncMessage("AboutLogins:PrimaryPasswordResponse", {
|
this.sendAsyncMessage("AboutLogins:PrimaryPasswordResponse", {
|
||||||
result: isAuthorized,
|
result: isAuthorized,
|
||||||
@@ -394,12 +398,14 @@ export class AboutLoginsParent extends JSWindowActorParent {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let reason = "export_logins";
|
||||||
let { isAuthorized, telemetryEvent } = await lazy.LoginHelper.requestReauth(
|
let { isAuthorized, telemetryEvent } = await lazy.LoginHelper.requestReauth(
|
||||||
this.browsingContext.embedderElement,
|
this.browsingContext.embedderElement,
|
||||||
true,
|
true,
|
||||||
null, // Prompt regardless of a recent prompt
|
null, // Prompt regardless of a recent prompt
|
||||||
messageText.value,
|
messageText.value,
|
||||||
captionText.value
|
captionText.value,
|
||||||
|
reason
|
||||||
);
|
);
|
||||||
|
|
||||||
let { name, extra = {}, value = null } = telemetryEvent;
|
let { name, extra = {}, value = null } = telemetryEvent;
|
||||||
|
|||||||
@@ -51,9 +51,13 @@ export function setKeyboardAccessForNonDialogElements(enableKeyboardAccess) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function promptForPrimaryPassword(messageId) {
|
export function promptForPrimaryPassword(messageId, reason) {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
window.AboutLoginsUtils.promptForPrimaryPassword(resolve, messageId);
|
window.AboutLoginsUtils.promptForPrimaryPassword(
|
||||||
|
resolve,
|
||||||
|
messageId,
|
||||||
|
reason
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -422,9 +422,11 @@ export default class LoginItem extends HTMLElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// We prompt for the primary password when entering edit mode already.
|
// We prompt for the primary password when entering edit mode already.
|
||||||
|
const reason = "reveal_logins";
|
||||||
if (this._revealCheckbox.checked && !this.dataset.editing) {
|
if (this._revealCheckbox.checked && !this.dataset.editing) {
|
||||||
let primaryPasswordAuth = await promptForPrimaryPassword(
|
let primaryPasswordAuth = await promptForPrimaryPassword(
|
||||||
"about-logins-reveal-password-os-auth-dialog-message"
|
"about-logins-reveal-password-os-auth-dialog-message",
|
||||||
|
reason
|
||||||
);
|
);
|
||||||
if (!primaryPasswordAuth) {
|
if (!primaryPasswordAuth) {
|
||||||
this._revealCheckbox.checked = false;
|
this._revealCheckbox.checked = false;
|
||||||
@@ -468,8 +470,10 @@ export default class LoginItem extends HTMLElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async handleCopyPasswordClick({ currentTarget }) {
|
async handleCopyPasswordClick({ currentTarget }) {
|
||||||
|
let reason = "copy_logins";
|
||||||
let primaryPasswordAuth = await promptForPrimaryPassword(
|
let primaryPasswordAuth = await promptForPrimaryPassword(
|
||||||
"about-logins-copy-password-os-auth-dialog-message"
|
"about-logins-copy-password-os-auth-dialog-message",
|
||||||
|
reason
|
||||||
);
|
);
|
||||||
if (!primaryPasswordAuth) {
|
if (!primaryPasswordAuth) {
|
||||||
return;
|
return;
|
||||||
@@ -547,8 +551,10 @@ export default class LoginItem extends HTMLElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async handleEditEvent() {
|
async handleEditEvent() {
|
||||||
|
let reason = "edit_logins";
|
||||||
let primaryPasswordAuth = await promptForPrimaryPassword(
|
let primaryPasswordAuth = await promptForPrimaryPassword(
|
||||||
"about-logins-edit-login-os-auth-dialog-message2"
|
"about-logins-edit-login-os-auth-dialog-message2",
|
||||||
|
reason
|
||||||
);
|
);
|
||||||
if (!primaryPasswordAuth) {
|
if (!primaryPasswordAuth) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ Object.defineProperty(window, "AboutLoginsUtils", {
|
|||||||
setFocus(element) {
|
setFocus(element) {
|
||||||
return element.focus();
|
return element.focus();
|
||||||
},
|
},
|
||||||
async promptForPrimaryPassword(resolve, _messageId) {
|
async promptForPrimaryPassword(resolve, _messageId, _reason) {
|
||||||
resolve(true);
|
resolve(true);
|
||||||
},
|
},
|
||||||
doLoginsMatch(login1, login2) {
|
doLoginsMatch(login1, login2) {
|
||||||
|
|||||||
@@ -2984,12 +2984,23 @@ var gPrivacyPane = {
|
|||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
let win = Services.wm.getMostRecentBrowserWindow();
|
let win = Services.wm.getMostRecentBrowserWindow();
|
||||||
|
|
||||||
|
// Note on Glean collection: because OSKeyStore.ensureLoggedIn() is not wrapped in
|
||||||
|
// verifyOSAuth(), it will be documenting "success" for unsupported platforms
|
||||||
|
// and won't record "fail_error", only "fail_user_canceled"
|
||||||
let loggedIn = await OSKeyStore.ensureLoggedIn(
|
let loggedIn = await OSKeyStore.ensureLoggedIn(
|
||||||
messageText.value,
|
messageText.value,
|
||||||
captionText.value,
|
captionText.value,
|
||||||
win,
|
win,
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const result = loggedIn.authenticated ? "success" : "fail_user_canceled";
|
||||||
|
Glean.pwmgr.promptShownOsReauth.record({
|
||||||
|
trigger: "toggle_pref_primary_password",
|
||||||
|
result,
|
||||||
|
});
|
||||||
|
|
||||||
if (!loggedIn.authenticated) {
|
if (!loggedIn.authenticated) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -3091,10 +3102,20 @@ var gPrivacyPane = {
|
|||||||
osReauthCheckbox.ownerGlobal.docShell.chromeEventHandler.ownerGlobal;
|
osReauthCheckbox.ownerGlobal.docShell.chromeEventHandler.ownerGlobal;
|
||||||
|
|
||||||
// Calling OSKeyStore.ensureLoggedIn() instead of LoginHelper.verifyOSAuth()
|
// Calling OSKeyStore.ensureLoggedIn() instead of LoginHelper.verifyOSAuth()
|
||||||
// since we want to authenticate user each time this stting is changed.
|
// since we want to authenticate user each time this setting is changed.
|
||||||
|
|
||||||
|
// Note on Glean collection: because OSKeyStore.ensureLoggedIn() is not wrapped in
|
||||||
|
// verifyOSAuth(), it will be documenting "success" for unsupported platforms
|
||||||
|
// and won't record "fail_error", only "fail_user_canceled"
|
||||||
let isAuthorized = (
|
let isAuthorized = (
|
||||||
await OSKeyStore.ensureLoggedIn(messageText, captionText, win, false)
|
await OSKeyStore.ensureLoggedIn(messageText, captionText, win, false)
|
||||||
).authenticated;
|
).authenticated;
|
||||||
|
|
||||||
|
Glean.pwmgr.promptShownOsReauth.record({
|
||||||
|
trigger: "toggle_pref_os_auth",
|
||||||
|
result: isAuthorized ? "success" : "fail_user_canceled",
|
||||||
|
});
|
||||||
|
|
||||||
if (!isAuthorized) {
|
if (!isAuthorized) {
|
||||||
osReauthCheckbox.checked = !osReauthCheckbox.checked;
|
osReauthCheckbox.checked = !osReauthCheckbox.checked;
|
||||||
return;
|
return;
|
||||||
@@ -3105,6 +3126,10 @@ var gPrivacyPane = {
|
|||||||
LoginHelper.OS_AUTH_FOR_PASSWORDS_PREF,
|
LoginHelper.OS_AUTH_FOR_PASSWORDS_PREF,
|
||||||
osReauthCheckbox.checked
|
osReauthCheckbox.checked
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Glean.pwmgr.requireOsReauthToggle.record({
|
||||||
|
toggle_state: osReauthCheckbox.checked,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
_initOSAuthentication() {
|
_initOSAuthentication() {
|
||||||
|
|||||||
@@ -378,15 +378,28 @@ export class ManageCreditCards extends ManageRecords {
|
|||||||
"autofill-edit-payment-method-os-prompt-windows",
|
"autofill-edit-payment-method-os-prompt-windows",
|
||||||
"autofill-edit-payment-method-os-prompt-other"
|
"autofill-edit-payment-method-os-prompt-other"
|
||||||
);
|
);
|
||||||
|
let verified;
|
||||||
const verified = await lazy.FormAutofillUtils.verifyUserOSAuth(
|
let result;
|
||||||
|
try {
|
||||||
|
verified = await lazy.FormAutofillUtils.verifyUserOSAuth(
|
||||||
FormAutofill.AUTOFILL_CREDITCARDS_REAUTH_PREF,
|
FormAutofill.AUTOFILL_CREDITCARDS_REAUTH_PREF,
|
||||||
promptMessage
|
promptMessage
|
||||||
);
|
);
|
||||||
|
result = verified ? "success" : "fail_user_canceled";
|
||||||
|
} catch (ex) {
|
||||||
|
result = "fail_error";
|
||||||
|
throw ex;
|
||||||
|
} finally {
|
||||||
|
Glean.formautofill.promptShownOsReauth.record({
|
||||||
|
trigger: "edit",
|
||||||
|
result,
|
||||||
|
});
|
||||||
|
}
|
||||||
if (!verified) {
|
if (!verified) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let decryptedCCNumObj = {};
|
let decryptedCCNumObj = {};
|
||||||
if (creditCard && creditCard["cc-number-encrypted"]) {
|
if (creditCard && creditCard["cc-number-encrypted"]) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -335,8 +335,13 @@ FormAutofillPreferences.prototype = {
|
|||||||
"autofill-creditcard-os-auth-dialog-caption"
|
"autofill-creditcard-os-auth-dialog-caption"
|
||||||
);
|
);
|
||||||
let win = target.ownerGlobal.docShell.chromeEventHandler.ownerGlobal;
|
let win = target.ownerGlobal.docShell.chromeEventHandler.ownerGlobal;
|
||||||
|
|
||||||
// Calling OSKeyStore.ensureLoggedIn() instead of FormAutofillUtils.verifyOSAuth()
|
// Calling OSKeyStore.ensureLoggedIn() instead of FormAutofillUtils.verifyOSAuth()
|
||||||
// since we want to authenticate user each time this stting is changed.
|
// since we want to authenticate user each time this setting is changed.
|
||||||
|
|
||||||
|
// Note on Glean collection: because OSKeyStore.ensureLoggedIn() is not wrapped in
|
||||||
|
// verifyOSAuth(), it will be documenting "success" for unsupported platforms
|
||||||
|
// and won't record "fail_error", only "fail_user_canceled"
|
||||||
let isAuthorized = (
|
let isAuthorized = (
|
||||||
await lazy.OSKeyStore.ensureLoggedIn(
|
await lazy.OSKeyStore.ensureLoggedIn(
|
||||||
messageText,
|
messageText,
|
||||||
@@ -345,6 +350,11 @@ FormAutofillPreferences.prototype = {
|
|||||||
false
|
false
|
||||||
)
|
)
|
||||||
).authenticated;
|
).authenticated;
|
||||||
|
Glean.formautofill.promptShownOsReauth.record({
|
||||||
|
trigger: "toggle_pref_os_auth",
|
||||||
|
result: isAuthorized ? "success" : "fail_user_canceled",
|
||||||
|
});
|
||||||
|
|
||||||
if (!isAuthorized) {
|
if (!isAuthorized) {
|
||||||
target.checked = !target.checked;
|
target.checked = !target.checked;
|
||||||
break;
|
break;
|
||||||
@@ -355,6 +365,9 @@ FormAutofillPreferences.prototype = {
|
|||||||
AUTOFILL_CREDITCARDS_REAUTH_PREF,
|
AUTOFILL_CREDITCARDS_REAUTH_PREF,
|
||||||
target.checked
|
target.checked
|
||||||
);
|
);
|
||||||
|
Glean.formautofill.requireOsReauthToggle.record({
|
||||||
|
toggle_state: target.checked,
|
||||||
|
});
|
||||||
} else if (target == this.refs.savedAddressesBtn) {
|
} else if (target == this.refs.savedAddressesBtn) {
|
||||||
target.ownerGlobal.gSubDialog.open(MANAGE_ADDRESSES_URL);
|
target.ownerGlobal.gSubDialog.open(MANAGE_ADDRESSES_URL);
|
||||||
} else if (target == this.refs.savedCreditCardsBtn) {
|
} else if (target == this.refs.savedCreditCardsBtn) {
|
||||||
|
|||||||
@@ -342,6 +342,69 @@ formautofill:
|
|||||||
expires: never
|
expires: never
|
||||||
telemetry_mirror: FORMAUTOFILL_AVAILABILITY
|
telemetry_mirror: FORMAUTOFILL_AVAILABILITY
|
||||||
|
|
||||||
|
prompt_shown_os_reauth:
|
||||||
|
type: event
|
||||||
|
description: >
|
||||||
|
Captures the method of user interaction initiating the prompt and the result of the prompt.
|
||||||
|
Possible triggers include:
|
||||||
|
"autofill" when a user attempts to autofill a payment method.
|
||||||
|
"edit" when a user edits a login in about:preferences
|
||||||
|
"toggle_pref_os_auth" when a user toggles "Autofill / Require device sign in" in about:preferences
|
||||||
|
Possible results include:
|
||||||
|
"success" should be used when the user is shown the OS Auth prompt and successfully authenticates.
|
||||||
|
"fail_user_canceled" should be used when the user cancels the authentication prompt. The user may or may not have provided an incorrect password before cancelling.
|
||||||
|
"fail_error" should be used when an unexpected exception is encountered.
|
||||||
|
bugs:
|
||||||
|
- https://bugzilla.mozilla.org/show_bug.cgi?id=1915672
|
||||||
|
data_reviews:
|
||||||
|
- https://bugzilla.mozilla.org/show_bug.cgi?id=1915672
|
||||||
|
notification_emails:
|
||||||
|
- autofill@lists.mozilla.org
|
||||||
|
- passwords-dev@mozilla.org
|
||||||
|
expires: never
|
||||||
|
extra_keys:
|
||||||
|
trigger:
|
||||||
|
description: >
|
||||||
|
Which user interaction triggered the event.
|
||||||
|
type: string
|
||||||
|
result:
|
||||||
|
description: >
|
||||||
|
The result of the OS Authentication.
|
||||||
|
type: string
|
||||||
|
|
||||||
|
require_os_reauth_toggle:
|
||||||
|
type: event
|
||||||
|
description: >
|
||||||
|
Toggle states include:
|
||||||
|
True means the OS Auth preference is enabled.
|
||||||
|
False means it is disabled.
|
||||||
|
bugs:
|
||||||
|
- https://bugzilla.mozilla.org/show_bug.cgi?id=1915672
|
||||||
|
data_reviews:
|
||||||
|
- https://bugzilla.mozilla.org/show_bug.cgi?id=1915672
|
||||||
|
notification_emails:
|
||||||
|
- autofill@lists.mozilla.org
|
||||||
|
- passwords-dev@mozilla.org
|
||||||
|
expires: never
|
||||||
|
extra_keys:
|
||||||
|
toggle_state:
|
||||||
|
description: >
|
||||||
|
The toggle state after the event.
|
||||||
|
type: boolean
|
||||||
|
|
||||||
|
os_auth_enabled:
|
||||||
|
type: boolean
|
||||||
|
description: >
|
||||||
|
Check at startup whether OS Authentication has been enabled for credit cards.
|
||||||
|
bugs:
|
||||||
|
- https://bugzilla.mozilla.org/show_bug.cgi?id=1915672
|
||||||
|
data_reviews:
|
||||||
|
- https://bugzilla.mozilla.org/show_bug.cgi?id=1915672
|
||||||
|
notification_emails:
|
||||||
|
- autofill@lists.mozilla.org
|
||||||
|
- passwords-dev@mozilla.org
|
||||||
|
expires: never
|
||||||
|
|
||||||
address:
|
address:
|
||||||
show_capture_doorhanger:
|
show_capture_doorhanger:
|
||||||
type: event
|
type: event
|
||||||
|
|||||||
@@ -606,16 +606,27 @@ export class FormAutofillCreditCardSection extends FormAutofillSection {
|
|||||||
"autofill-use-payment-method-os-prompt-windows",
|
"autofill-use-payment-method-os-prompt-windows",
|
||||||
"autofill-use-payment-method-os-prompt-other"
|
"autofill-use-payment-method-os-prompt-other"
|
||||||
);
|
);
|
||||||
const decrypted = await this.getDecryptedString(
|
let decrypted;
|
||||||
|
let result;
|
||||||
|
try {
|
||||||
|
decrypted = await this.getDecryptedString(
|
||||||
profile["cc-number-encrypted"],
|
profile["cc-number-encrypted"],
|
||||||
promptMessage
|
promptMessage
|
||||||
);
|
);
|
||||||
|
result = decrypted ? "success" : "fail_user_canceled";
|
||||||
|
} catch (ex) {
|
||||||
|
result = "fail_error";
|
||||||
|
throw ex;
|
||||||
|
} finally {
|
||||||
|
Glean.formautofill.promptShownOsReauth.record({
|
||||||
|
trigger: "autofill",
|
||||||
|
result,
|
||||||
|
});
|
||||||
|
}
|
||||||
if (!decrypted) {
|
if (!decrypted) {
|
||||||
// Early return if the decrypted is empty or undefined
|
// Early return if the decrypted is empty or undefined
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
profile["cc-number"] = decrypted;
|
profile["cc-number"] = decrypted;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -1599,13 +1599,15 @@ export const LoginHelper = {
|
|||||||
* @param expirationTime Optional timestamp indicating next required re-authentication
|
* @param expirationTime Optional timestamp indicating next required re-authentication
|
||||||
* @param messageText Formatted and localized string to be displayed when the OS auth dialog is used.
|
* @param messageText Formatted and localized string to be displayed when the OS auth dialog is used.
|
||||||
* @param captionText Formatted and localized string to be displayed when the OS auth dialog is used.
|
* @param captionText Formatted and localized string to be displayed when the OS auth dialog is used.
|
||||||
|
* @param reason The reason for requesting reauthentication, used for telemetry.
|
||||||
*/
|
*/
|
||||||
async requestReauth(
|
async requestReauth(
|
||||||
browser,
|
browser,
|
||||||
OSReauthEnabled,
|
OSReauthEnabled,
|
||||||
expirationTime,
|
expirationTime,
|
||||||
messageText,
|
messageText,
|
||||||
captionText
|
captionText,
|
||||||
|
reason
|
||||||
) {
|
) {
|
||||||
let isAuthorized = false;
|
let isAuthorized = false;
|
||||||
let telemetryEvent;
|
let telemetryEvent;
|
||||||
@@ -1644,13 +1646,25 @@ export const LoginHelper = {
|
|||||||
}
|
}
|
||||||
// Use the OS auth dialog if there is no primary password
|
// Use the OS auth dialog if there is no primary password
|
||||||
if (!token.hasPassword && OSReauthEnabled) {
|
if (!token.hasPassword && OSReauthEnabled) {
|
||||||
let isAuthorized = await this.verifyUserOSAuth(
|
let result;
|
||||||
|
try {
|
||||||
|
isAuthorized = await this.verifyUserOSAuth(
|
||||||
OS_AUTH_FOR_PASSWORDS_PREF,
|
OS_AUTH_FOR_PASSWORDS_PREF,
|
||||||
messageText,
|
messageText,
|
||||||
captionText,
|
captionText,
|
||||||
browser.ownerGlobal,
|
browser.ownerGlobal,
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
result = isAuthorized ? "success" : "fail_user_canceled";
|
||||||
|
} catch (ex) {
|
||||||
|
result = "fail_error";
|
||||||
|
throw ex;
|
||||||
|
} finally {
|
||||||
|
Glean.pwmgr.promptShownOsReauth.record({
|
||||||
|
trigger: reason,
|
||||||
|
result,
|
||||||
|
});
|
||||||
|
}
|
||||||
let value = lazy.OSKeyStore.canReauth()
|
let value = lazy.OSKeyStore.canReauth()
|
||||||
? "success"
|
? "success"
|
||||||
: "success_unsupported_platform";
|
: "success_unsupported_platform";
|
||||||
|
|||||||
@@ -377,6 +377,78 @@ pwmgr:
|
|||||||
extra_keys: *pwmgr_reauthenticate_extra
|
extra_keys: *pwmgr_reauthenticate_extra
|
||||||
telemetry_mirror: Pwmgr_Reauthenticate_OsAuth
|
telemetry_mirror: Pwmgr_Reauthenticate_OsAuth
|
||||||
|
|
||||||
|
prompt_shown_os_reauth:
|
||||||
|
type: event
|
||||||
|
description: >
|
||||||
|
Captures the method of user interaction initiating the prompt and the result of the prompt.
|
||||||
|
Possible triggers include:
|
||||||
|
"copy_logins" when a user copies a password in about:logins
|
||||||
|
"copy_cpm" when a user copies a password in contextual password manager
|
||||||
|
"edit_logins" when a user edits a login in about:logins
|
||||||
|
"edit_cpm" when a user edits a login in contextual password manager
|
||||||
|
"export_logins" when a user exports all passwords in about:logins
|
||||||
|
"export_cpm" when a user exports all passwords in contextual password manager
|
||||||
|
"reveal_logins" when a user reveals a password a login in about:logins
|
||||||
|
"reveal_cpm" when a user reveals a password a login in contextual password manager
|
||||||
|
"toggle_pref_primary_password" when a user toggles "Use a Primary Password" in about:preferences
|
||||||
|
"toggle_pref_os_auth" when a user toggles "Passwords / Require device sign in" in about:preferences
|
||||||
|
Possible results include:
|
||||||
|
"success" should be used when the user is shown the OS Auth prompt and successfully authenticates.
|
||||||
|
"fail_user_canceled" should be used when the user cancels the authentication prompt. The user may or may not have provided an incorrect password before cancelling.
|
||||||
|
"fail_error" should be used when an unexpected exception is encountered.
|
||||||
|
bugs:
|
||||||
|
- https://bugzilla.mozilla.org/show_bug.cgi?id=1915672
|
||||||
|
data_reviews:
|
||||||
|
- https://bugzilla.mozilla.org/show_bug.cgi?id=1915672
|
||||||
|
notification_emails:
|
||||||
|
- autofill@lists.mozilla.org
|
||||||
|
- passwords-dev@mozilla.org
|
||||||
|
expires: never
|
||||||
|
extra_keys:
|
||||||
|
trigger:
|
||||||
|
description: >
|
||||||
|
Which user interaction triggered the event.
|
||||||
|
type: string
|
||||||
|
result:
|
||||||
|
description: >
|
||||||
|
The result of the OS Authentication.
|
||||||
|
type: string
|
||||||
|
|
||||||
|
require_os_reauth_toggle:
|
||||||
|
type: event
|
||||||
|
description: >
|
||||||
|
Captures the state of the toggle after the change was made.
|
||||||
|
Toggle states include:
|
||||||
|
True means the OS Auth preference is enabeled.
|
||||||
|
False means it is disabled.
|
||||||
|
bugs:
|
||||||
|
- https://bugzilla.mozilla.org/show_bug.cgi?id=1915672
|
||||||
|
data_reviews:
|
||||||
|
- https://bugzilla.mozilla.org/show_bug.cgi?id=1915672
|
||||||
|
notification_emails:
|
||||||
|
- autofill@lists.mozilla.org
|
||||||
|
- passwords-dev@mozilla.org
|
||||||
|
expires: never
|
||||||
|
extra_keys:
|
||||||
|
toggle_state:
|
||||||
|
description: >
|
||||||
|
The toggle state after the event.
|
||||||
|
type: boolean
|
||||||
|
|
||||||
|
os_auth_enabled:
|
||||||
|
type: boolean
|
||||||
|
description: >
|
||||||
|
Check at startup whether OS Authentication has been enabled for passwords.
|
||||||
|
bugs:
|
||||||
|
- https://bugzilla.mozilla.org/show_bug.cgi?id=1915672
|
||||||
|
data_reviews:
|
||||||
|
- https://bugzilla.mozilla.org/show_bug.cgi?id=1915672
|
||||||
|
notification_emails:
|
||||||
|
- autofill@lists.mozilla.org
|
||||||
|
- passwords-dev@mozilla.org
|
||||||
|
expires: never
|
||||||
|
|
||||||
|
|
||||||
open_management_aboutprotections:
|
open_management_aboutprotections:
|
||||||
type: event
|
type: event
|
||||||
description: >
|
description: >
|
||||||
|
|||||||
@@ -197,12 +197,21 @@ export class MegalistViewModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async #promptForReauth(command) {
|
async #promptForReauth(command) {
|
||||||
|
// used for recording telemetry
|
||||||
|
const reasonMap = {
|
||||||
|
Copy: "copy_cpm",
|
||||||
|
Reveal: "reveal_cpm",
|
||||||
|
Edit: "edit_cpm",
|
||||||
|
};
|
||||||
|
const reason = reasonMap[command.id];
|
||||||
|
|
||||||
const { isAuthorized } = await lazy.LoginHelper.requestReauth(
|
const { isAuthorized } = await lazy.LoginHelper.requestReauth(
|
||||||
lazy.BrowserWindowTracker.getTopWindow().gBrowser,
|
lazy.BrowserWindowTracker.getTopWindow().gBrowser,
|
||||||
this.getOSAuthEnabled(),
|
this.getOSAuthEnabled(),
|
||||||
this.#authExpirationTime,
|
this.#authExpirationTime,
|
||||||
command.OSAuthPromptMessage,
|
command.OSAuthPromptMessage,
|
||||||
command.OSAuthCaptionMessage
|
command.OSAuthCaptionMessage,
|
||||||
|
reason
|
||||||
);
|
);
|
||||||
|
|
||||||
if (isAuthorized) {
|
if (isAuthorized) {
|
||||||
|
|||||||
@@ -519,12 +519,14 @@ export class LoginDataSource extends DataSourceBase {
|
|||||||
LoginHelper.OS_AUTH_FOR_PASSWORDS_PREF
|
LoginHelper.OS_AUTH_FOR_PASSWORDS_PREF
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const reason = "export_cpm";
|
||||||
let { isAuthorized, telemetryEvent } = await LoginHelper.requestReauth(
|
let { isAuthorized, telemetryEvent } = await LoginHelper.requestReauth(
|
||||||
browsingContext,
|
browsingContext,
|
||||||
isOSAuthEnabled,
|
isOSAuthEnabled,
|
||||||
null, // Prompt regardless of a recent prompt
|
null, // Prompt regardless of a recent prompt
|
||||||
this.#exportPasswordsStrings.OSReauthMessage,
|
this.#exportPasswordsStrings.OSReauthMessage,
|
||||||
this.#exportPasswordsStrings.OSAuthDialogCaption
|
this.#exportPasswordsStrings.OSAuthDialogCaption,
|
||||||
|
reason
|
||||||
);
|
);
|
||||||
|
|
||||||
let { name, extra = {}, value = null } = telemetryEvent;
|
let { name, extra = {}, value = null } = telemetryEvent;
|
||||||
|
|||||||
Reference in New Issue
Block a user