diff --git a/browser/base/content/navigator-toolbox.inc.xhtml b/browser/base/content/navigator-toolbox.inc.xhtml
index d3c7e777bd05..774d01f56096 100644
--- a/browser/base/content/navigator-toolbox.inc.xhtml
+++ b/browser/base/content/navigator-toolbox.inc.xhtml
@@ -306,7 +306,7 @@
+ data-l10n-id="identity-credential-urlbar-anchor"/>
diff --git a/browser/base/content/popup-notifications.inc b/browser/base/content/popup-notifications.inc
index 87e30754ed37..c073388d51b1 100644
--- a/browser/base/content/popup-notifications.inc
+++ b/browser/base/content/popup-notifications.inc
@@ -172,13 +172,18 @@
-
+
+
+
+
+
+
diff --git a/browser/components/credentialmanager/identityCredentialNotification.ftl b/browser/components/credentialmanager/identityCredentialNotification.ftl
index efdb12913084..ef45dddf02ea 100644
--- a/browser/components/credentialmanager/identityCredentialNotification.ftl
+++ b/browser/components/credentialmanager/identityCredentialNotification.ftl
@@ -4,13 +4,22 @@
## Credential panel
## $host (String): the hostname of the site that is being displayed.
+## $provider (String): the hostname of another website you are using to log in to the site being displayed
-credential-header-providers = Sign in to { $host }.
-credential-header-accounts = Pick a { $host } account.
+identity-credential-header-providers = Sign in to { $host }
+identity-credential-header-accounts = Pick a { $host } account
# Identity providers are websites you use to log into another website, for example: Google when you Log in with Google.
-credential-description-provider-explanation = These are the identity providers that would like to help you log in.
-credential-description-account-explanation = Picking an account here shares that identity with { $host }.
-urlbar-identity-credential-anchor =
+identity-credential-description-provider-explanation = These are the identity providers that would like to help you log in.
+identity-credential-description-account-explanation = Picking an account here shares that identity with { $host }.
+identity-credential-urlbar-anchor =
.tooltiptext = Open federated login panel
-credential-cancel-label = Cancel
-credential-cancel-accesskey = C
+identity-credential-cancel-button =
+ .label = Cancel
+ .accesskey = C
+identity-credential-accept-button =
+ .label = Okay
+ .accesskey = O
+identity-credential-policy-title = Legal information
+identity-credential-policy-description = Logging into { $host } with an account from { $provider } is controlled by these legal policies. This is optional and you can cancel this and try to log in again using another method.
+identity-credential-privacy-policy = Privacy Policy
+identity-credential-terms-of-service = Terms of Service
diff --git a/dom/webidl/IdentityCredential.webidl b/dom/webidl/IdentityCredential.webidl
index 23a9fc03ccaa..3a57f3e82ba6 100644
--- a/dom/webidl/IdentityCredential.webidl
+++ b/dom/webidl/IdentityCredential.webidl
@@ -72,6 +72,7 @@ dictionary IdentityAccountList {
};
// https://fedidcg.github.io/FedCM/#idp-api-client-id-metadata-endpoint
+[GenerateInit, GenerateConversionToJS]
dictionary IdentityClientMetadata {
USVString privacy_policy_url;
USVString terms_of_service_url;
diff --git a/toolkit/components/credentialmanagement/IdentityCredentialPromptService.sys.mjs b/toolkit/components/credentialmanagement/IdentityCredentialPromptService.sys.mjs
index 0bf924b9c7f1..3557f911e1e0 100644
--- a/toolkit/components/credentialmanagement/IdentityCredentialPromptService.sys.mjs
+++ b/toolkit/components/credentialmanagement/IdentityCredentialPromptService.sys.mjs
@@ -63,15 +63,17 @@ export class IdentityCredentialPromptService {
true
);
let headerMessage = localization.formatValueSync(
- "credential-header-providers",
+ "identity-credential-header-providers",
{
host: "<>",
}
);
- let cancelLabel = localization.formatValueSync("credential-cancel-label");
- let cancelKey = localization.formatValueSync(
- "credential-cancel-accesskey"
- );
+ let [cancel] = localization.formatMessagesSync([
+ { id: "identity-credential-cancel-button" },
+ ]);
+
+ let cancelLabel = cancel.attributes.find(x => x.name == "label").value;
+ let cancelKey = cancel.attributes.find(x => x.name == "accesskey").value;
// Build the choices into the panel
let listBox = browser.ownerDocument.getElementById(
@@ -123,6 +125,9 @@ export class IdentityCredentialPromptService {
browser.ownerDocument.getElementById(
"identity-credential-provider"
).hidden = false;
+ browser.ownerDocument.getElementById(
+ "identity-credential-policy"
+ ).hidden = true;
browser.ownerDocument.getElementById(
"identity-credential-account"
).hidden = true;
@@ -138,6 +143,131 @@ export class IdentityCredentialPromptService {
});
}
+ /**
+ * Ask the user, using a PopupNotification, to approve or disapprove of the policies of the Identity Provider.
+ * @param {BrowsingContext} browsingContext - The BrowsingContext of the document requesting an identity credential via navigator.credentials.get()
+ * @param {IdentityProvider} identityProvider - The Identity Provider that the user has selected to use
+ * @param {IdentityCredentialMetadata} identityCredentialMetadata - The metadata displayed to the user
+ * @returns {Promise} A boolean representing the user's acceptance of the metadata.
+ */
+ showPolicyPrompt(
+ browsingContext,
+ identityProvider,
+ identityCredentialMetadata
+ ) {
+ // For testing only.
+ if (lazy.SELECT_FIRST_IN_UI_LISTS) {
+ return Promise.resolve(true);
+ }
+ if (
+ !identityCredentialMetadata ||
+ (!identityCredentialMetadata.privacy_policy_url &&
+ !identityCredentialMetadata.terms_of_service_url)
+ ) {
+ return Promise.resolve(true);
+ }
+ return new Promise(function(resolve, reject) {
+ let browser = browsingContext.top.embedderElement;
+ if (!browser) {
+ reject();
+ return;
+ }
+
+ let providerURI = new URL(identityProvider.configURL);
+ let providerDisplayDomain = lazy.IDNService.convertToDisplayIDN(
+ providerURI.host,
+ {}
+ );
+ let currentBaseDomain =
+ browsingContext.currentWindowContext.documentPrincipal.baseDomain;
+ // Localize the description
+ // Bug 1797154 - Convert localization calls to use the async formatValues.
+ let localization = new Localization(
+ ["preview/identityCredentialNotification.ftl"],
+ true
+ );
+ let descriptionMessage = localization.formatValueSync(
+ "identity-credential-policy-description",
+ {
+ host: currentBaseDomain,
+ provider: providerDisplayDomain,
+ }
+ );
+ let [accept, cancel] = localization.formatMessagesSync([
+ { id: "identity-credential-accept-button" },
+ { id: "identity-credential-cancel-button" },
+ ]);
+
+ let cancelLabel = cancel.attributes.find(x => x.name == "label").value;
+ let cancelKey = cancel.attributes.find(x => x.name == "accesskey").value;
+ let acceptLabel = accept.attributes.find(x => x.name == "label").value;
+ let acceptKey = accept.attributes.find(x => x.name == "accesskey").value;
+ let title = localization.formatValueSync(
+ "identity-credential-policy-title"
+ );
+
+ // Populate the content of the policy panel
+ let description = browser.ownerDocument.getElementById(
+ "identity-credential-policy-explanation"
+ );
+ description.textContent = descriptionMessage;
+ let privacyPolicyAnchor = browser.ownerDocument.getElementById(
+ "identity-credential-privacy-policy"
+ );
+ privacyPolicyAnchor.hidden = true;
+ if (identityCredentialMetadata.privacy_policy_url) {
+ privacyPolicyAnchor.href =
+ identityCredentialMetadata.privacy_policy_url;
+ privacyPolicyAnchor.hidden = false;
+ }
+ let termsOfServiceAnchor = browser.ownerDocument.getElementById(
+ "identity-credential-terms-of-service"
+ );
+ termsOfServiceAnchor.hidden = true;
+ if (identityCredentialMetadata.terms_of_service_url) {
+ termsOfServiceAnchor.href =
+ identityCredentialMetadata.terms_of_service_url;
+ termsOfServiceAnchor.hidden = false;
+ }
+
+ // Construct the necessary arguments for notification behavior
+ let options = {};
+ let mainAction = {
+ label: acceptLabel,
+ accessKey: acceptKey,
+ callback(event) {
+ resolve(true);
+ },
+ };
+ let secondaryActions = [
+ {
+ label: cancelLabel,
+ accessKey: cancelKey,
+ callback(event) {
+ resolve(false);
+ },
+ },
+ ];
+
+ // Show the popup
+ let ownerDocument = browser.ownerDocument;
+ ownerDocument.getElementById(
+ "identity-credential-provider"
+ ).hidden = true;
+ ownerDocument.getElementById("identity-credential-policy").hidden = false;
+ ownerDocument.getElementById("identity-credential-account").hidden = true;
+ browser.ownerGlobal.PopupNotifications.show(
+ browser,
+ "identity-credential",
+ title,
+ "identity-credential-notification-icon",
+ mainAction,
+ secondaryActions,
+ options
+ );
+ });
+ }
+
/**
* Ask the user, using a PopupNotification, to select an account from a provided list.
* @param {BrowsingContext} browsingContext - The BrowsingContext of the document requesting an identity credential via navigator.credentials.get()
@@ -165,21 +295,23 @@ export class IdentityCredentialPromptService {
true
);
let headerMessage = localization.formatValueSync(
- "credential-header-accounts",
+ "identity-credential-header-accounts",
{
host: "<>",
}
);
let descriptionMessage = localization.formatValueSync(
- "credential-description-account-explanation",
+ "identity-credential-description-account-explanation",
{
host: currentOrigin,
}
);
- let cancelLabel = localization.formatValueSync("credential-cancel-label");
- let cancelKey = localization.formatValueSync(
- "credential-cancel-accesskey"
- );
+ let [cancel] = localization.formatMessagesSync([
+ { id: "identity-credential-cancel-button" },
+ ]);
+
+ let cancelLabel = cancel.attributes.find(x => x.name == "label").value;
+ let cancelKey = cancel.attributes.find(x => x.name == "accesskey").value;
// Add the description text
browser.ownerDocument.getElementById(
@@ -228,6 +360,9 @@ export class IdentityCredentialPromptService {
browser.ownerDocument.getElementById(
"identity-credential-provider"
).hidden = true;
+ browser.ownerDocument.getElementById(
+ "identity-credential-policy"
+ ).hidden = true;
browser.ownerDocument.getElementById(
"identity-credential-account"
).hidden = false;
diff --git a/toolkit/components/credentialmanagement/nsIIdentityCredentialPromptService.idl b/toolkit/components/credentialmanagement/nsIIdentityCredentialPromptService.idl
index 27b0a4718f64..483689c93377 100644
--- a/toolkit/components/credentialmanagement/nsIIdentityCredentialPromptService.idl
+++ b/toolkit/components/credentialmanagement/nsIIdentityCredentialPromptService.idl
@@ -11,6 +11,9 @@ interface nsIIdentityCredentialPromptService : nsISupports {
// Display to the user an interface to choose from among the identity providers listed
// Resolves with one of the elements of the list.
Promise showProviderPrompt(in BrowsingContext browsingContext, in jsval identityProviders);
+ // Display to the user an interface to approve (or disapprove) of the terms of service for
+ // the identity provider when used on the current site.
+ Promise showPolicyPrompt(in BrowsingContext browsingContext, in jsval identityProvider, in jsval identityClientMetadata);
// Display to the user an interface to choose from among the accounts listed.
// Resolves with one of the elements of the list.
Promise showAccountListPrompt(in BrowsingContext browsingContext, in jsval accountList);