Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


SSL Prompter.sys.mjs   Sprache: unbekannt

 
/* 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";

// This is redefined below, for strange and unfortunate reasons.
import { PromptUtils } from "resource://gre/modules/PromptUtils.sys.mjs";
import { BrowserUtils } from "resource://gre/modules/BrowserUtils.sys.mjs";

const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
  ClipboardContextMenu: "resource://gre/modules/ClipboardContextMenu.sys.mjs",
});

const {
  MODAL_TYPE_TAB,
  MODAL_TYPE_CONTENT,
  MODAL_TYPE_WINDOW,
  MODAL_TYPE_INTERNAL_WINDOW,
} = Ci.nsIPrompt;

const COMMON_DIALOG = "chrome://global/content/commonDialog.xhtml";
const SELECT_DIALOG = "chrome://global/content/selectDialog.xhtml";

export function Prompter() {
  // Note that EmbedPrompter clones this implementation.
}

/**
 * Implements nsIPromptService and nsIPromptFactory
 * @class Prompter
 */
Prompter.prototype = {
  classID: Components.ID("{1c978d25-b37f-43a8-a2d6-0c7a239ead87}"),
  QueryInterface: ChromeUtils.generateQI([
    "nsIPromptFactory",
    "nsIPromptService",
  ]),

  /* ----------  private members  ---------- */

  pickPrompter(options) {
    return new ModalPrompter(options);
  },

  /* ----------  nsIPromptFactory  ---------- */

  getPrompt(domWin, iid) {
    // This is still kind of dumb; the C++ code delegated to login manager
    // here, which in turn calls back into us via nsIPromptService.
    if (iid.equals(Ci.nsIAuthPrompt2) || iid.equals(Ci.nsIAuthPrompt)) {
      try {
        let pwmgr = Cc[
          "@mozilla.org/passwordmanager/authpromptfactory;1"
        ].getService(Ci.nsIPromptFactory);
        return pwmgr.getPrompt(domWin, iid);
      } catch (e) {
        console.error("nsPrompter: Delegation to password manager failed: ", e);
      }
    }

    let p = new ModalPrompter({ domWin });
    p.QueryInterface(iid);
    return p;
  },

  /* ----------  nsIPromptService  ---------- */

  /**
   * Puts up an alert dialog with an OK button.
   * @param {mozIDOMWindowProxy} domWin - The parent window or null.
   * @param {String} title - Text to appear in the title of the dialog.
   * @param {String} text - Text to appear in the body of the dialog.
   */
  alert(domWin, title, text) {
    let p = this.pickPrompter({ domWin });
    p.alert(title, text);
  },

  /**
   * Puts up an alert dialog with an OK button.
   * @param {BrowsingContext} browsingContext - The browsing context the
   *        prompt should be opened for.
   * @param {Number} modalType - The modal type of the prompt.
   *        nsIPromptService.<MODAL_TYPE_WINDOW|MODAL_TYPE_TAB|MODAL_TYPE_CONTENT>
   * @param {String} title - Text to appear in the title of the dialog.
   * @param {String} text - Text to appear in the body of the dialog.
   */
  alertBC(browsingContext, modalType, ...promptArgs) {
    let p = this.pickPrompter({ browsingContext, modalType });
    p.alert(...promptArgs);
  },

  /**
   * Puts up an alert dialog with an OK button.
   *
   * @param {BrowsingContext} browsingContext - The browsing context the
   *        prompt should be opened for.
   * @param {Number} modalType - The modal type of the prompt.
   *        nsIPromptService.<MODAL_TYPE_WINDOW|MODAL_TYPE_TAB|MODAL_TYPE_CONTENT>
   * @param {String} title - Text to appear in the title of the dialog.
   * @param {String} text - Text to appear in the body of the dialog.
   * @returns {Promise} A promise which resolves when the prompt is dismissed.
   */
  asyncAlert(browsingContext, modalType, ...promptArgs) {
    let p = this.pickPrompter({ browsingContext, modalType, async: true });
    return p.alert(...promptArgs);
  },

  /**
   * Puts up an alert dialog with an OK button and a labeled checkbox.
   * @param {mozIDOMWindowProxy} domWin - The parent window or null.
   * @param {String} title - Text to appear in the title of the dialog.
   * @param {String} text - Text to appear in the body of the dialog.
   * @param {String} checkLabel - Text to appear with the checkbox.
   * @param {Object} checkValue - Contains the initial checked state of the
   *        checkbox when this method is called and the final checked state
   *        after this method returns.
   */
  alertCheck(domWin, title, text, checkLabel, checkValue) {
    let p = this.pickPrompter({ domWin });
    p.alertCheck(title, text, checkLabel, checkValue);
  },

  /**
   * Puts up an alert dialog with an OK button and a labeled checkbox.
   * @param {BrowsingContext} browsingContext - The browsing context the
   *        prompt should be opened for.
   * @param {Number} modalType - The modal type of the prompt.
   *        nsIPromptService.<MODAL_TYPE_WINDOW|MODAL_TYPE_TAB|MODAL_TYPE_CONTENT>
   * @param {String} title - Text to appear in the title of the dialog.
   * @param {String} text - Text to appear in the body of the dialog.
   * @param {String} checkLabel - Text to appear with the checkbox.
   * @param {Object} checkValue - Contains the initial checked state of the
   *        checkbox when this method is called and the final checked state
   *        after this method returns.
   */
  alertCheckBC(browsingContext, modalType, ...promptArgs) {
    let p = this.pickPrompter({ browsingContext, modalType });
    p.alertCheck(...promptArgs);
  },

  /**
   * Puts up an alert dialog with an OK button and a labeled checkbox.
   * @param {BrowsingContext} browsingContext - The browsing context the
   *        prompt should be opened for.
   * @param {Number} modalType - The modal type of the prompt.
   *        nsIPromptService.<MODAL_TYPE_WINDOW|MODAL_TYPE_TAB|MODAL_TYPE_CONTENT>
   * @param {String} title - Text to appear in the title of the dialog.
   * @param {String} text - Text to appear in the body of the dialog.
   * @param {String} checkLabel - Text to appear with the checkbox.
   * @param {Boolean} checkValue - The initial checked state of the checkbox.
   * @returns {Promise<nsIPropertyBag<{ checked: Boolean }>>}
   *          A promise which resolves when the prompt is dismissed.
   */
  asyncAlertCheck(browsingContext, modalType, ...promptArgs) {
    let p = this.pickPrompter({ browsingContext, modalType, async: true });
    return p.alertCheck(...promptArgs);
  },

  /**
   * Puts up a dialog with OK and Cancel buttons.
   * @param {mozIDOMWindowProxy} domWin - The parent window or null.
   * @param {String} title - Text to appear in the title of the dialog.
   * @param {String} text - Text to appear in the body of the dialog.
   * @returns {Boolean} true for OK, false for Cancel.
   */
  confirm(domWin, title, text) {
    let p = this.pickPrompter({ domWin });
    return p.confirm(title, text);
  },

  /**
   * Puts up a dialog with OK and Cancel buttons.
   * @param {BrowsingContext} browsingContext - The browsing context the
   *        prompt should be opened for.
   * @param {Number} modalType - The modal type of the prompt.
   *        nsIPromptService.<MODAL_TYPE_WINDOW|MODAL_TYPE_TAB|MODAL_TYPE_CONTENT>
   * @param {String} title - Text to appear in the title of the dialog.
   * @param {String} text - Text to appear in the body of the dialog.
   * @returns {Boolean} true for OK, false for Cancel.
   */
  confirmBC(browsingContext, modalType, ...promptArgs) {
    let p = this.pickPrompter({ browsingContext, modalType });
    return p.confirm(...promptArgs);
  },

  /**
   * Puts up a dialog with OK and Cancel buttons.
   * @param {BrowsingContext} browsingContext - The browsing context the
   *        prompt should be opened for.
   * @param {Number} modalType - The modal type of the prompt.
   *        nsIPromptService.<MODAL_TYPE_WINDOW|MODAL_TYPE_TAB|MODAL_TYPE_CONTENT>
   * @param {String} title - Text to appear in the title of the dialog.
   * @param {String} text - Text to appear in the body of the dialog.
   * @returns {Promise<nsIPropertyBag<{ ok: Boolean }>>}
   *          A promise which resolves when the prompt is dismissed.
   */
  asyncConfirm(browsingContext, modalType, ...promptArgs) {
    let p = this.pickPrompter({ browsingContext, modalType, async: true });
    return p.confirm(...promptArgs);
  },

  /**
   * Puts up a dialog with OK and Cancel buttons and a labeled checkbox.
   * @param {mozIDOMWindowProxy} domWin - The parent window or null.
   * @param {String} title - Text to appear in the title of the dialog.
   * @param {String} text - Text to appear in the body of the dialog.
   * @param {String} checkLabel - Text to appear with the checkbox.
   * @param {Object} checkValue - Contains the initial checked state of the
   *        checkbox when this method is called and the final checked state
   *        after this method returns.
   */
  confirmCheck(domWin, title, text, checkLabel, checkValue) {
    let p = this.pickPrompter({ domWin });
    return p.confirmCheck(title, text, checkLabel, checkValue);
  },

  /**
   * Puts up a dialog with OK and Cancel buttons and a labeled checkbox.
   * @param {BrowsingContext} browsingContext - The browsing context the
   *        prompt should be opened for.
   * @param {Number} modalType - The modal type of the prompt.
   *        nsIPromptService.<MODAL_TYPE_WINDOW|MODAL_TYPE_TAB|MODAL_TYPE_CONTENT>
   * @param {String} title - Text to appear in the title of the dialog.
   * @param {String} text - Text to appear in the body of the dialog.
   * @param {String} checkLabel - Text to appear with the checkbox.
   * @param {Object} checkValue - Contains the initial checked state of the
   *        checkbox when this method is called and the final checked state
   *        after this method returns.
   * @returns {Boolean} true for OK, false for Cancel
   */
  confirmCheckBC(browsingContext, modalType, ...promptArgs) {
    let p = this.pickPrompter({ browsingContext, modalType });
    return p.confirmCheck(...promptArgs);
  },

  /**
   * Puts up a dialog with OK and Cancel buttons and a labeled checkbox.
   * @param {BrowsingContext} browsingContext - The browsing context the
   *        prompt should be opened for.
   * @param {Number} modalType - The modal type of the prompt.
   *        nsIPromptService.<MODAL_TYPE_WINDOW|MODAL_TYPE_TAB|MODAL_TYPE_CONTENT>
   * @param {String} title - Text to appear in the title of the dialog.
   * @param {String} text - Text to appear in the body of the dialog.
   * @param {String} checkLabel - Text to appear with the checkbox.
   * @param {Boolean} checkValue - The initial checked state of the checkbox.
   * @returns {Promise<nsIPropertyBag<{ ok: Boolean, checked: Boolean }>>}
   *          A promise which resolves when the prompt is dismissed.
   */
  asyncConfirmCheck(browsingContext, modalType, ...promptArgs) {
    let p = this.pickPrompter({ browsingContext, modalType, async: true });
    return p.confirmCheck(...promptArgs);
  },

  /**
   * Puts up a dialog with up to 3 buttons and an optional, labeled checkbox.
   *
   * Buttons are numbered 0 - 2. Button 0 is the default button unless one of
   * the Button Default Flags is specified.
   *
   * A button may use a predefined title, specified by one of the Button Title
   * Flags values.  Each title value can be multiplied by a position value to
   * assign the title to a particular button.  If BUTTON_TITLE_IS_STRING is
   * used for a button, the string parameter for that button will be used.  If
   * the value for a button position is zero, the button will not be shown.
   *
   * In general, flags is constructed per the following example:
   *
   * flags = (BUTTON_POS_0) * (BUTTON_TITLE_AAA) +
   *         (BUTTON_POS_1) * (BUTTON_TITLE_BBB) +
   *         BUTTON_POS_1_DEFAULT;
   *
   * where "AAA" and "BBB" correspond to one of the button titles.
   *
   * @param {mozIDOMWindowProxy} domWin - The parent window or null.
   * @param {String} title - Text to appear in the title of the dialog.
   * @param {String} text - Text to appear in the body of the dialog.
   * @param {Number} flags - A combination of Button Flags.
   * @param {String} button0 - Used when button 0 uses TITLE_IS_STRING.
   * @param {String} button1 - Used when button 1 uses TITLE_IS_STRING.
   * @param {String} button2 - Used when button 2 uses TITLE_IS_STRING.
   * @param {String} checkLabel - Text to appear with the checkbox.
   *        Null if no checkbox.
   * @param {Object} checkValue - Contains the initial checked state of the
   *        checkbox when this method
   *        is called and the final checked state after this method returns.
   * @returns {Number} The index of the button pressed.
   */
  confirmEx(
    domWin,
    title,
    text,
    flags,
    button0,
    button1,
    button2,
    checkLabel,
    checkValue
  ) {
    let p = this.pickPrompter({ domWin });
    return p.confirmEx(
      title,
      text,
      flags,
      button0,
      button1,
      button2,
      checkLabel,
      checkValue
    );
  },

  /**
   * Puts up a dialog with up to 3 buttons and an optional, labeled checkbox.
   * @param {BrowsingContext} browsingContext - The browsing context the
   *        prompt should be opened for.
   * @param {Number} modalType - The modal type of the prompt.
   *        nsIPromptService.<MODAL_TYPE_WINDOW|MODAL_TYPE_TAB|MODAL_TYPE_CONTENT>
   * @param {String} title - Text to appear in the title of the dialog.
   * @param {String} text - Text to appear in the body of the dialog.
   * @param {Number} flags - A combination of Button Flags.
   * @param {String} button0 - Used when button 0 uses TITLE_IS_STRING.
   * @param {String} button1 - Used when button 1 uses TITLE_IS_STRING.
   * @param {String} button2 - Used when button 2 uses TITLE_IS_STRING.
   * @param {String} checkLabel - Text to appear with the checkbox.
   *        Null if no checkbox.
   * @param {Object} checkValue - Contains the initial checked state of the
   *        checkbox when this method is called and the final checked state
   *        after this method returns.
   * @returns {Number} The index of the button pressed.
   */
  confirmExBC(browsingContext, modalType, ...promptArgs) {
    let p = this.pickPrompter({ browsingContext, modalType });
    return p.confirmEx(...promptArgs);
  },

  /**
   * Puts up a dialog with up to 3 buttons and an optional, labeled checkbox.
   * @param {BrowsingContext} browsingContext - The browsing context the
   *        prompt should be opened for.
   * @param {Number} modalType - The modal type of the prompt.
   *        nsIPromptService.<MODAL_TYPE_WINDOW|MODAL_TYPE_TAB|MODAL_TYPE_CONTENT>
   * @param {String} title - Text to appear in the title of the dialog.
   * @param {String} text - Text to appear in the body of the dialog.
   * @param {Number} flags - A combination of Button Flags.
   * @param {String} button0 - Used when button 0 uses TITLE_IS_STRING.
   * @param {String} button1 - Used when button 1 uses TITLE_IS_STRING.
   * @param {String} button2 - Used when button 2 uses TITLE_IS_STRING.
   * @param {String} checkLabel - Text to appear with the checkbox.
   *        Null if no checkbox.
   * @param {Boolean} checkValue - The initial checked state of the checkbox.
   * @param {Object} [extraArgs] - Extra arguments for the prompt metadata.
   * @returns {Promise<nsIPropertyBag<{ buttonNumClicked: Number, checked: Boolean, isExtra1Secondary: Boolean }>>}
   */
  asyncConfirmEx(browsingContext, modalType, ...promptArgs) {
    let p = this.pickPrompter({ browsingContext, modalType, async: true });
    return p.confirmEx(...promptArgs);
  },

  /**
   * Puts up a dialog with an edit field and an optional, labeled checkbox.
   * @param {mozIDOMWindowProxy} domWin - The parent window or null.
   * @param {String} title - Text to appear in the title of the dialog.
   * @param {String} text - Text to appear in the body of the dialog.
   * @param {Object} value - Contains the default value for the dialog field
   *        when this method is called (null value is ok).  Upon return, if
   *        the user pressed OK, then this parameter contains a newly
   *        allocated string value.
   *        Otherwise, the parameter's value is unmodified.
   * @param {String} checkLabel - Text to appear with the checkbox.
   *        If null, check box will not be shown.
   * @param {Object} checkValue - Contains the initial checked state of the
   *        checkbox when this method is called and the final checked state
   *        after this method returns.
   * @returns {Boolean} true for OK, false for Cancel.
   */
  prompt(domWin, title, text, value, checkLabel, checkValue) {
    let p = this.pickPrompter({ domWin });
    return p.nsIPrompt_prompt(title, text, value, checkLabel, checkValue);
  },

  /**
   * Puts up a dialog with an edit field and an optional, labeled checkbox.
   * @param {BrowsingContext} browsingContext - The browsing context the
   *        prompt should be opened for.
   * @param {Number} modalType - The modal type of the prompt.
   *        nsIPromptService.<MODAL_TYPE_WINDOW|MODAL_TYPE_TAB|MODAL_TYPE_CONTENT>
   * @param {String} title - Text to appear in the title of the dialog.
   * @param {String} text - Text to appear in the body of the dialog.
   * @param {Object} value - Contains the default value for the dialog field
   *        when this method is called (null value is ok).  Upon return, if
   *        the user pressed OK, then this parameter contains a newly
   *        allocated string value.
   *        Otherwise, the parameter's value is unmodified.
   * @param {String} checkLabel - Text to appear with the checkbox.
   *        If null, check box will not be shown.
   * @param {Object} checkValue - Contains the initial checked state of the
   *        checkbox when this method is called and the final checked state
   *        after this method returns.
   * @returns {Boolean} true for OK, false for Cancel.
   */
  promptBC(browsingContext, modalType, ...promptArgs) {
    let p = this.pickPrompter({ browsingContext, modalType });
    return p.nsIPrompt_prompt(...promptArgs);
  },

  /**
   * Puts up a dialog with an edit field and an optional, labeled checkbox.
   * @param {BrowsingContext} browsingContext - The browsing context the
   *        prompt should be opened for.
   * @param {Number} modalType - The modal type of the prompt.
   *        nsIPromptService.<MODAL_TYPE_WINDOW|MODAL_TYPE_TAB|MODAL_TYPE_CONTENT>
   * @param {String} title - Text to appear in the title of the dialog.
   * @param {String} text - Text to appear in the body of the dialog.
   * @param {String} value - The default value for the dialog text field.
   * @param {String} checkLabel - Text to appear with the checkbox.
   *        If null, check box will not be shown.
   * @param {Boolean} checkValue - The initial checked state of the checkbox.
   * @returns {Promise<nsIPropertyBag<{ ok: Boolean, checked: Boolean, value: String }>>}
   *          A promise which resolves when the prompt is dismissed.
   */
  asyncPrompt(browsingContext, modalType, ...promptArgs) {
    let p = this.pickPrompter({ browsingContext, modalType, async: true });
    return p.nsIPrompt_prompt(...promptArgs);
  },

  /**
   * Puts up a dialog with an edit field and a password field.
   * @param {mozIDOMWindowProxy} domWin - The parent window or null.
   * @param {String} title - Text to appear in the title of the dialog.
   * @param {String} text - Text to appear in the body of the dialog.
   * @param {Object} user - Contains the default value for the username
   *        field when this method is called (null value is ok).
   *        Upon return, if the user pressed OK, then this parameter contains
   *        a newly allocated string value. Otherwise, the parameter's value
   *        is unmodified.
   * @param {Object} pass - Contains the default value for the password field
   *        when this method is called (null value is ok). Upon return, if the
   *        user pressed OK, this parameter contains a newly allocated string
   *        value. Otherwise, the parameter's value is unmodified.
   * @returns {Boolean} true for OK, false for Cancel.
   */
  promptUsernameAndPassword(domWin, title, text, user, pass) {
    let p = this.pickPrompter({ domWin });
    return p.nsIPrompt_promptUsernameAndPassword(null, title, text, user, pass);
  },

  /**
   * Puts up a dialog with an edit field and a password field.
   * @param {BrowsingContext} browsingContext - The browsing context the
   *        prompt should be opened for.
   * @param {Number} modalType - The modal type of the prompt.
   *        nsIPromptService.<MODAL_TYPE_WINDOW|MODAL_TYPE_TAB|MODAL_TYPE_CONTENT>
   * @param {String} title - Text to appear in the title of the dialog.
   * @param {String} text - Text to appear in the body of the dialog.
   * @param {Object} user - Contains the default value for the username
   *        field when this method is called (null value is ok).
   *        Upon return, if the user pressed OK, then this parameter contains
   *        a newly allocated string value. Otherwise, the parameter's value
   *        is unmodified.
   * @param {Object} pass - Contains the default value for the password field
   *        when this method is called (null value is ok). Upon return, if the
   *        user pressed OK, this parameter contains a newly allocated string
   *        value. Otherwise, the parameter's value is unmodified.
   * @returns {Boolean} true for OK, false for Cancel.
   */
  promptUsernameAndPasswordBC(browsingContext, modalType, ...promptArgs) {
    let p = this.pickPrompter({ browsingContext, modalType });
    return p.nsIPrompt_promptUsernameAndPassword(null, ...promptArgs);
  },

  /**
   * Puts up a dialog with an edit field and a password field.
   * @param {BrowsingContext} browsingContext - The browsing context the
   *        prompt should be opened for.
   * @param {Number} modalType - The modal type of the prompt.
   *        nsIPromptService.<MODAL_TYPE_WINDOW|MODAL_TYPE_TAB|MODAL_TYPE_CONTENT>
   * @param {String} title - Text to appear in the title of the dialog.
   * @param {String} text - Text to appear in the body of the dialog.
   * @param {String} user - Default value for the username field.
   * @param {String} pass - Contains the default value for the password field.
   * @returns {Promise<nsIPropertyBag<{ ok: Boolean, user: String, pass: String }>>}
   *          A promise which resolves when the prompt is dismissed.
   */
  asyncPromptUsernameAndPassword(browsingContext, modalType, ...promptArgs) {
    let p = this.pickPrompter({ browsingContext, modalType, async: true });
    return p.nsIPrompt_promptUsernameAndPassword(null, ...promptArgs);
  },

  /**
   * Puts up a dialog with a password field.
   * @param {mozIDOMWindowProxy} domWin - The parent window or null.
   * @param {String} title - Text to appear in the title of the dialog.
   * @param {String} text - Text to appear in the body of the dialog.
   * @param {Object} pass - Contains the default value for the password field
   *        when this method is called (null value is ok). Upon return, if the
   *        user pressed OK, this parameter contains a newly allocated string
   *        value. Otherwise, the parameter's value is unmodified.
   * @returns {Boolean} true for OK, false for Cancel.
   */
  promptPassword(domWin, title, text, pass) {
    let p = this.pickPrompter({ domWin });
    return p.nsIPrompt_promptPassword(
      null, // no channel.
      title,
      text,
      pass
    );
  },

  /**
   * Puts up a dialog with a password field.
   * @param {BrowsingContext} browsingContext - The browsing context the
   *        prompt should be opened for.
   * @param {Number} modalType - The modal type of the prompt.
   *        nsIPromptService.<MODAL_TYPE_WINDOW|MODAL_TYPE_TAB|MODAL_TYPE_CONTENT>
   * @param {String} title - Text to appear in the title of the dialog.
   * @param {String} text - Text to appear in the body of the dialog.
   * @param {Object} pass - Contains the default value for the password field
   *        when this method is called (null value is ok). Upon return, if the
   *        user pressed OK, this parameter contains a newly allocated string
   *        value. Otherwise, the parameter's value is unmodified.
   * @returns {Boolean} true for OK, false for Cancel.
   */
  promptPasswordBC(browsingContext, modalType, ...promptArgs) {
    let p = this.pickPrompter({ browsingContext, modalType });
    return p.nsIPrompt_promptPassword(null, ...promptArgs);
  },

  /**
   * Puts up a dialog with a password field.
   * @param {BrowsingContext} browsingContext - The browsing context the
   *        prompt should be opened for.
   * @param {Number} modalType - The modal type of the prompt.
   *        nsIPromptService.<MODAL_TYPE_WINDOW|MODAL_TYPE_TAB|MODAL_TYPE_CONTENT>
   * @param {String} title - Text to appear in the title of the dialog.
   * @param {String} text - Text to appear in the body of the dialog.
   * @param {String} pass - Contains the default value for the password field.
   * @returns {Promise<nsIPropertyBag<{ ok: Boolean, pass: String }>>}
   *          A promise which resolves when the prompt is dismissed.
   */
  asyncPromptPassword(browsingContext, modalType, ...promptArgs) {
    let p = this.pickPrompter({ browsingContext, modalType, async: true });
    return p.nsIPrompt_promptPassword(null, ...promptArgs);
  },

  /**
   * Puts up a dialog box which has a list box of strings from which the user
   * may make a single selection.
   * @param {mozIDOMWindowProxy} domWin - The parent window or null.
   * @param {String} title - Text to appear in the title of the dialog.
   * @param {String} text - Text to appear in the body of the dialog.
   * @param {String[]} list - The list of strings to display.
   * @param {Object} selected - Contains the index of the selected item in the
   *        list when this method returns true.
   * @returns {Boolean} true for OK, false for Cancel.
   */
  select(domWin, title, text, list, selected) {
    let p = this.pickPrompter({ domWin });
    return p.select(title, text, list, selected);
  },

  /**
   * Puts up a dialog box which has a list box of strings from which the user
   * may make a single selection.
   * @param {BrowsingContext} browsingContext - The browsing context the
   *        prompt should be opened for.
   * @param {Number} modalType - The modal type of the prompt.
   *        nsIPromptService.<MODAL_TYPE_WINDOW|MODAL_TYPE_TAB|MODAL_TYPE_CONTENT>
   * @param {String} title - Text to appear in the title of the dialog.
   * @param {String} text - Text to appear in the body of the dialog.
   * @param {String[]} list - The list of strings to display.
   * @param {Object} selected - Contains the index of the selected item in the
   *        list when this method returns true.
   * @returns {Boolean} true for OK, false for Cancel.
   */
  selectBC(browsingContext, modalType, ...promptArgs) {
    let p = this.pickPrompter({ browsingContext, modalType });
    return p.select(...promptArgs);
  },

  /**
   * Puts up a dialog box which has a list box of strings from which the user
   * may make a single selection.
   * @param {BrowsingContext} browsingContext - The browsing context the
   *        prompt should be opened for.
   * @param {Number} modalType - The modal type of the prompt.
   *        nsIPromptService.<MODAL_TYPE_WINDOW|MODAL_TYPE_TAB|MODAL_TYPE_CONTENT>
   * @param {String} title - Text to appear in the title of the dialog.
   * @param {String} text - Text to appear in the body of the dialog.
   * @param {String[]} list - The list of strings to display.
   * @returns {Promise<nsIPropertyBag<{ selected: Number, ok: Boolean  }>>}
   *          A promise which resolves when the prompt is dismissed.
   */
  asyncSelect(browsingContext, modalType, ...promptArgs) {
    let p = this.pickPrompter({ browsingContext, modalType, async: true });
    return p.select(...promptArgs);
  },

  /**
   * Requests a username and a password. Shows a dialog with username and
   * password field, depending on flags also a domain field.
   * @param {mozIDOMWindowProxy} domWin - The parent window or null.
   * @param {nsIChannel} channel - The channel that requires authentication.
   * @param {Number} level - Security level of the credential transmission.
   *        Any of nsIAuthPrompt2.<LEVEL_NONE|LEVEL_PW_ENCRYPTED|LEVEL_SECURE>
   * @param {nsIAuthInformation} authInfo - Authentication information object.
   * @returns {Boolean}
   *          true: Authentication can proceed using the values
   *          in the authInfo object.
   *          false: Authentication should be cancelled, usually because the
   *          user did not provide username/password.
   */
  promptAuth(domWin, channel, level, authInfo) {
    let p = this.pickPrompter({ domWin });
    return p.promptAuth(channel, level, authInfo);
  },

  /**
   * Requests a username and a password. Shows a dialog with username and
   * password field, depending on flags also a domain field.
   * @param {BrowsingContext} browsingContext - The browsing context the
   *        prompt should be opened for.
   * @param {Number} modalType - The modal type of the prompt.
   *        nsIPromptService.<MODAL_TYPE_WINDOW|MODAL_TYPE_TAB|MODAL_TYPE_CONTENT>
   * @param {nsIChannel} channel - The channel that requires authentication.
   * @param {Number} level - Security level of the credential transmission.
   *        Any of nsIAuthPrompt2.<LEVEL_NONE|LEVEL_PW_ENCRYPTED|LEVEL_SECURE>
   * @param {nsIAuthInformation} authInfo - Authentication information object.
   * @returns {Boolean}
   *          true: Authentication can proceed using the values
   *          in the authInfo object.
   *          false: Authentication should be cancelled, usually because the
   *          user did not provide username/password.
   */
  promptAuthBC(browsingContext, modalType, ...promptArgs) {
    let p = this.pickPrompter({ browsingContext, modalType });
    return p.promptAuth(...promptArgs);
  },

  /**
   * Requests a username and a password. Shows a dialog with username and
   * password field, depending on flags also a domain field.
   * @param {BrowsingContext} browsingContext - The browsing context the
   *        prompt should be opened for.
   * @param {Number} modalType - The modal type of the prompt.
   *        nsIPromptService.<MODAL_TYPE_WINDOW|MODAL_TYPE_TAB|MODAL_TYPE_CONTENT>
   * @param {nsIChannel} channel - The channel that requires authentication.
   * @param {Number} level - Security level of the credential transmission.
   *        Any of nsIAuthPrompt2.<LEVEL_NONE|LEVEL_PW_ENCRYPTED|LEVEL_SECURE>
   * @param {nsIAuthInformation} authInfo - Authentication information object.
   * @returns {Promise<nsIPropertyBag<{ ok: Boolean }>>}
   *          A promise which resolves when the prompt is dismissed.
   */
  asyncPromptAuth(browsingContext, modalType, ...promptArgs) {
    let p = this.pickPrompter({ browsingContext, modalType, async: true });
    return p.promptAuth(...promptArgs);
  },

  /**
   * Displays a contextmenu to get user confirmation for clipboard read. Only
   * one context menu can be opened at a time.
   *
   * @param {WindowContext} windowContext - The window context that initiates
   *        the clipboard operation.
   * @returns {Promise<nsIPropertyBag<{ ok: Boolean }>>}
   *          A promise which resolves when the contextmenu is dismissed.
   */
  confirmUserPaste() {
    return lazy.ClipboardContextMenu.confirmUserPaste(...arguments);
  },
};

// Common utils not specific to a particular prompter style.
var InternalPromptUtils = {
  getLocalizedString(key, formatArgs) {
    if (formatArgs) {
      return this.strBundle.formatStringFromName(key, formatArgs);
    }
    return this.strBundle.GetStringFromName(key);
  },

  confirmExHelper(flags, button0, button1, button2) {
    const BUTTON_DEFAULT_MASK = 0x03000000;
    let defaultButtonNum = (flags & BUTTON_DEFAULT_MASK) >> 24;
    let isDelayEnabled = flags & Ci.nsIPrompt.BUTTON_DELAY_ENABLE;

    // Sanity check: If the flags indicate there should be no button0 then flags
    // must contain BUTTON_NONE (notably, it must include BUTTON_NONE_ENABLE_BIT).
    let allowNoButtons =
      (flags & Ci.nsIPromptService.BUTTON_NONE) ==
      Ci.nsIPromptService.BUTTON_NONE;
    const NO_BUTTON0 =
      Ci.nsIPrompt.BUTTON_POS_0 * Ci.nsIPrompt.BUTTON_TITLE_IS_STRING;
    if (!allowNoButtons && !button0 && (flags & NO_BUTTON0) == NO_BUTTON0) {
      throw new Error(
        `Request for modal prompt with no buttons requires flags to be ` +
          `BUTTON_NONE.  Got ${flags}`
      );
    }
    if (allowNoButtons && (button0 || button1 || button2)) {
      throw new Error(
        `Request for modal prompt with no buttons requires button names to be ` +
          `null.  Got ${button0}, ${button1}, ${button2}`
      );
    }

    // Flags can be used to select a specific pre-defined button label or
    // a caller-supplied string (button0/button1/button2). If no flags are
    // set for a button, then the button won't be shown.
    let argText = [button0, button1, button2];
    let buttonLabels = [null, null, null];
    for (let i = 0; i < 3; i++) {
      let buttonLabel;
      switch (flags & 0xff) {
        case Ci.nsIPrompt.BUTTON_TITLE_OK:
          buttonLabel = this.getLocalizedString("OK");
          break;
        case Ci.nsIPrompt.BUTTON_TITLE_CANCEL:
          buttonLabel = this.getLocalizedString("Cancel");
          break;
        case Ci.nsIPrompt.BUTTON_TITLE_YES:
          buttonLabel = this.getLocalizedString("Yes");
          break;
        case Ci.nsIPrompt.BUTTON_TITLE_NO:
          buttonLabel = this.getLocalizedString("No");
          break;
        case Ci.nsIPrompt.BUTTON_TITLE_SAVE:
          buttonLabel = this.getLocalizedString("Save");
          break;
        case Ci.nsIPrompt.BUTTON_TITLE_DONT_SAVE:
          buttonLabel = this.getLocalizedString("DontSave");
          break;
        case Ci.nsIPrompt.BUTTON_TITLE_REVERT:
          buttonLabel = this.getLocalizedString("Revert");
          break;
        case Ci.nsIPrompt.BUTTON_TITLE_IS_STRING:
          buttonLabel = argText[i];
          break;
      }
      if (buttonLabel) {
        buttonLabels[i] = buttonLabel;
      }
      flags >>= 8;
    }

    return [
      buttonLabels[0],
      buttonLabels[1],
      buttonLabels[2],
      defaultButtonNum,
      isDelayEnabled,
      allowNoButtons,
    ];
  },

  getAuthInfo(authInfo) {
    let username, password;

    let flags = authInfo.flags;
    if (flags & Ci.nsIAuthInformation.NEED_DOMAIN && authInfo.domain) {
      username = authInfo.domain + "\\" + authInfo.username;
    } else {
      username = authInfo.username;
    }

    password = authInfo.password;

    return [username, password];
  },

  setAuthInfo(authInfo, username, password) {
    let flags = authInfo.flags;
    if (flags & Ci.nsIAuthInformation.NEED_DOMAIN) {
      // Domain is separated from username by a backslash
      let idx = username.indexOf("\\");
      if (idx == -1) {
        authInfo.username = username;
      } else {
        authInfo.domain = username.substring(0, idx);
        authInfo.username = username.substring(idx + 1);
      }
    } else {
      authInfo.username = username;
    }
    authInfo.password = password;
  },

  /**
   * Strip out things like userPass and path for display.
   */
  getFormattedHostname(uri) {
    return uri.scheme + "://" + uri.hostPort;
  },

  // Note: there's a similar implementation in the login manager.
  getAuthTarget(aChannel, aAuthInfo) {
    let displayHost, realm;

    // If our proxy is demanding authentication, don't use the
    // channel's actual destination.
    if (aAuthInfo.flags & Ci.nsIAuthInformation.AUTH_PROXY) {
      if (!(aChannel instanceof Ci.nsIProxiedChannel)) {
        throw new Error("proxy auth needs nsIProxiedChannel");
      }

      let info = aChannel.proxyInfo;
      if (!info) {
        throw new Error("proxy auth needs nsIProxyInfo");
      }

      // Proxies don't have a scheme, but we'll use "moz-proxy://"
      // so that it's more obvious what the login is for.
      let idnService = Cc["@mozilla.org/network/idn-service;1"].getService(
        Ci.nsIIDNService
      );
      displayHost =
        "moz-proxy://" +
        idnService.convertUTF8toACE(info.host) +
        ":" +
        info.port;
      realm = aAuthInfo.realm;
      if (!realm) {
        realm = displayHost;
      }

      return { realm, displayHost };
    }

    displayHost = this.getFormattedHostname(aChannel.URI);
    let displayHostOnly = aChannel.URI.hostPort;

    // If a HTTP WWW-Authenticate header specified a realm, that value
    // will be available here. If it wasn't set or wasn't HTTP, we'll use
    // the formatted hostname instead.
    realm = aAuthInfo.realm;
    if (!realm) {
      realm = displayHost;
    }

    return { realm, displayHostOnly, displayHost };
  },

  makeAuthMessage(prompt, channel, authInfo) {
    if (prompt.modalType != MODAL_TYPE_TAB) {
      return this._legacyMakeAuthMessage(channel, authInfo);
    }

    let isProxy = authInfo.flags & Ci.nsIAuthInformation.AUTH_PROXY;
    let isPassOnly = authInfo.flags & Ci.nsIAuthInformation.ONLY_PASSWORD;
    let isCrossOrig =
      authInfo.flags & Ci.nsIAuthInformation.CROSS_ORIGIN_SUB_RESOURCE;
    let username = authInfo.username;

    // We use the realm and displayHost only for proxy auth,
    // and the displayHostOnly (hostPort) only for x-origin auth prompts.
    // Otherwise we rely on the title of the dialog displaying the correct
    // title.
    let { displayHost, realm, displayHostOnly } = this.getAuthTarget(
      channel,
      authInfo
    );

    if (isProxy) {
      // The realm is server-controlled. Trim it if it's very long, to
      // avoid the dialog becoming unusable.
      // For background, see https://bugzilla.mozilla.org/show_bug.cgi?id=244273
      if (realm.length > 150) {
        realm = realm.substring(0, 150);
        // Append "..." (or localized equivalent).
        realm += this.ellipsis;
      }

      return this.getLocalizedString("EnterLoginForProxy3", [
        realm,
        displayHost,
      ]);
    }
    if (isPassOnly) {
      return this.getLocalizedString("EnterPasswordOnlyFor", [username]);
    }
    if (isCrossOrig) {
      return this.getLocalizedString("EnterCredentialsCrossOrigin", [
        displayHostOnly,
      ]);
    }
    return this.getLocalizedString("EnterCredentials");
  },

  _legacyMakeAuthMessage(channel, authInfo) {
    let isProxy = authInfo.flags & Ci.nsIAuthInformation.AUTH_PROXY;
    let isPassOnly = authInfo.flags & Ci.nsIAuthInformation.ONLY_PASSWORD;
    let isCrossOrig =
      authInfo.flags & Ci.nsIAuthInformation.CROSS_ORIGIN_SUB_RESOURCE;

    let username = authInfo.username;
    let { displayHost, realm } = this.getAuthTarget(channel, authInfo);

    // Suppress "the site says: $realm" when we synthesized a missing realm.
    if (!authInfo.realm && !isProxy) {
      realm = "";
    }

    // The realm is server-controlled. Trim it if it's very long, to
    // avoid the dialog becoming unusable.
    // For background, see https://bugzilla.mozilla.org/show_bug.cgi?id=244273
    if (realm.length > 150) {
      realm = realm.substring(0, 150);
      // Append "..." (or localized equivalent).
      realm += this.ellipsis;
    }

    let text;
    if (isProxy) {
      text = this.getLocalizedString("EnterLoginForProxy3", [
        realm,
        displayHost,
      ]);
    } else if (isPassOnly) {
      text = this.getLocalizedString("EnterPasswordFor", [
        username,
        displayHost,
      ]);
    } else if (isCrossOrig) {
      text = this.getLocalizedString("EnterUserPasswordForCrossOrigin2", [
        displayHost,
      ]);
    } else if (!realm) {
      text = this.getLocalizedString("EnterUserPasswordFor2", [displayHost]);
    } else {
      text = this.getLocalizedString("EnterLoginForRealm3", [
        realm,
        displayHost,
      ]);
    }

    return text;
  },

  getBrandFullName() {
    return this.brandBundle.GetStringFromName("brandFullName");
  },
};

ChromeUtils.defineLazyGetter(InternalPromptUtils, "strBundle", function () {
  let bundle = Services.strings.createBundle(
    "chrome://global/locale/commonDialogs.properties"
  );
  if (!bundle) {
    throw new Error("String bundle for Prompter not present!");
  }
  return bundle;
});

ChromeUtils.defineLazyGetter(InternalPromptUtils, "brandBundle", function () {
  let bundle = Services.strings.createBundle(
    "chrome://branding/locale/brand.properties"
  );
  if (!bundle) {
    throw new Error("String bundle for branding not present!");
  }
  return bundle;
});

ChromeUtils.defineLazyGetter(InternalPromptUtils, "ellipsis", function () {
  let ellipsis = "\u2026";
  try {
    ellipsis = Services.prefs.getComplexValue(
      "intl.ellipsis",
      Ci.nsIPrefLocalizedString
    ).data;
  } catch (e) {}
  return ellipsis;
});

class ModalPrompter {
  constructor({
    browsingContext = null,
    domWin = null,
    modalType = null,
    async = false,
  }) {
    if (browsingContext && domWin) {
      throw new Error("Pass either browsingContext or domWin");
    }

    if (domWin) {
      // We have a domWin, get the associated browsing context
      this.browsingContext = BrowsingContext.getFromWindow(domWin);
    } else {
      this.browsingContext = browsingContext;
    }

    if (
      domWin &&
      (!modalType || modalType == MODAL_TYPE_WINDOW) &&
      !this.browsingContext?.isContent &&
      this.browsingContext?.associatedWindow?.gDialogBox
    ) {
      modalType = MODAL_TYPE_INTERNAL_WINDOW;
    }

    // Use given modal type or fallback to default
    this.modalType = modalType || ModalPrompter.defaultModalType;

    this.async = async;

    this.QueryInterface = ChromeUtils.generateQI([
      "nsIPrompt",
      "nsIAuthPrompt",
      "nsIAuthPrompt2",
      "nsIWritablePropertyBag2",
    ]);
  }

  set modalType(modalType) {
    // Setting modal type window is always allowed
    if (modalType == MODAL_TYPE_WINDOW) {
      this._modalType = modalType;
      return;
    }

    // For content prompts for non-content windows, use window prompts:
    if (modalType == MODAL_TYPE_CONTENT && !this.browsingContext?.isContent) {
      this._modalType = MODAL_TYPE_WINDOW;
      return;
    }

    // We can't use content / tab prompts if we don't have a suitable parent.
    if (
      !this.browsingContext?.isContent &&
      modalType != MODAL_TYPE_INTERNAL_WINDOW
    ) {
      // Only show this error if we're not about to fall back again and show a different one.
      if (this.browsingContext?.associatedWindow?.gDialogBox) {
        console.error(
          "Prompter: Browser not available. Falling back to internal window prompt."
        );
      }
      modalType = MODAL_TYPE_INTERNAL_WINDOW;
    }

    if (
      modalType == MODAL_TYPE_INTERNAL_WINDOW &&
      (this.browsingContext?.isContent ||
        !this.browsingContext?.associatedWindow?.gDialogBox)
    ) {
      console.error(
        "Prompter: internal dialogs not available in this context. Falling back to window prompt."
      );
      modalType = MODAL_TYPE_WINDOW;
    }

    this._modalType = modalType;
  }

  get modalType() {
    return this._modalType;
  }

  /* ---------- internal methods ---------- */

  /**
   * Synchronous wrapper around {@link ModalPrompter#openPrompt}
   * @param {Object} args Prompt arguments. When prompt has been closed, they are updated to reflect the result state.
   */
  openPromptSync(args) {
    let closed = false;
    this.openPrompt(args)
      .then(returnedArgs => {
        if (returnedArgs) {
          for (let key in returnedArgs) {
            args[key] = returnedArgs[key];
          }
        }
      })
      .finally(() => {
        closed = true;
      });
    Services.tm.spinEventLoopUntilOrQuit(
      "prompts/Prompter.sys.mjs:openPromptSync",
      () => closed
    );
  }

  async openPrompt(args) {
    if (!this.browsingContext) {
      // We don't have a browsing context, fallback to a window prompt.
      args.modalType = MODAL_TYPE_WINDOW;
      this.openWindowPrompt(null, args);
      return args;
    }

    if (this._modalType == MODAL_TYPE_INTERNAL_WINDOW) {
      await this.openInternalWindowPrompt(
        this.browsingContext.associatedWindow,
        args
      );
      return args;
    }

    // Select prompts are not part of CommonDialog
    // and thus not supported as tab or content prompts yet. See Bug 1622817.
    // Once they are integrated this override should be removed.
    if (args.promptType == "select" && this.modalType !== MODAL_TYPE_WINDOW) {
      console.error(
        "Prompter: 'select' prompts do not support tab/content prompting. Falling back to window prompt."
      );
      args.modalType = MODAL_TYPE_WINDOW;
    } else {
      args.modalType = this.modalType;
    }

    const IS_CONTENT =
      Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT;

    let actor;
    try {
      if (IS_CONTENT) {
        // When in the content, get the PromptChild actor.
        actor =
          this.browsingContext.window.windowGlobalChild.getActor("Prompt");
      } else {
        // When in the parent, get the PromptParent actor.
        actor = this.browsingContext.currentWindowGlobal.getActor("Prompt");
      }
    } catch (_) {
      // We can't get the prompt actor, fallback to window prompt.
      let parentWin;
      // If given a chrome BC we can try to get its window
      if (!this.browsingContext.isContent && this.browsingContext.window) {
        parentWin = this.browsingContext.window;
      } else {
        // Try to get the window which is the browsers parent
        parentWin = this.browsingContext.top?.embedderElement?.ownerGlobal;
      }
      this.openWindowPrompt(parentWin, args);
      return args;
    }

    /* For prompts with a channel, we want to show the origin requesting
     * authentication. This is different from the prompt principal,
     * which is based on the document loaded in the browsing context over
     * which the prompt appears. So if page foo.com loads bar.com, and the
     * latter asks for auth, we want that bar.com's origin, not foo.com.
     * To avoid confusion, we use different properties
     * (authOrigin / promptPrincipal) to track this information.
     */
    if (args.channel) {
      try {
        // Bug 1767292: Display scheme if it is HTTP, otherwise omit it.
        args.authOrigin = BrowserUtils.formatURIForDisplay(args.channel.URI, {
          showInsecureHTTP: true,
        });
      } catch (ex) {
        args.authOrigin = args.channel.URI.prePath;
      }
      args.isInsecureAuth = args.channel.URI.schemeIs("http");
      // whether we are going to prompt the user for their credentials for a different base domain.
      // When true, auth prompt spoofing protection mechanisms will be triggered (see bug 791594).
      args.isTopLevelCrossDomainAuth = false;
      // We don't support auth prompt spoofing protections for sub resources and window prompts
      if (
        args.modalType == MODAL_TYPE_TAB &&
        args.channel.loadInfo.isTopLevelLoad
      ) {
        // check if this is a request from a third party
        try {
          args.isTopLevelCrossDomainAuth =
            this.browsingContext.currentWindowGlobal?.documentPrincipal?.isThirdPartyURI(
              args.channel.URI
            );
        } catch (e) {
          // isThirdPartyURI failes for about:/blob/data URIs
          console.warn("nsPrompter: isThirdPartyURI failed: " + e);
        }
      }
    } else {
      args.promptPrincipal =
        this.browsingContext.window?.document.nodePrincipal;
    }
    if (IS_CONTENT) {
      let docShell = this.browsingContext.docShell;
      let inPermitUnload = docShell?.docViewer?.inPermitUnload;
      args.inPermitUnload = inPermitUnload;
      let eventDetail = Cu.cloneInto(
        {
          tabPrompt: this.modalType != MODAL_TYPE_WINDOW,
          inPermitUnload,
        },
        this.browsingContext.window
      );
      PromptUtils.fireDialogEvent(
        this.browsingContext.window,
        "DOMWillOpenModalDialog",
        null,
        eventDetail
      );

      // Put content window in the modal state while the prompt is open.
      let windowUtils = this.browsingContext.window?.windowUtils;
      if (windowUtils) {
        windowUtils.enterModalState();
      }
    } else if (args.inPermitUnload) {
      args.promptPrincipal =
        this.browsingContext.currentWindowGlobal.documentPrincipal;
    }

    // It is technically possible for multiple prompts to be sent from a single
    // BrowsingContext. See bug 1266353. We use a randomly generated UUID to
    // differentiate between the different prompts.
    let id = "id" + Services.uuid.generateUUID().toString();

    args._remoteId = args.promptID ?? id;

    let returnedArgs;
    try {
      if (IS_CONTENT) {
        // If we're in the content process, send a message to the PromptParent
        // window actor.
        returnedArgs = await actor.sendQuery("Prompt:Open", args);
      } else {
        // If we're in the parent process we already have the parent actor.
        // We can call its message handler directly.
        returnedArgs = await actor.receiveMessage({
          name: "Prompt:Open",
          data: args,
        });
      }

      if (returnedArgs?.promptAborted) {
        throw Components.Exception(
          "prompt aborted by user",
          Cr.NS_ERROR_NOT_AVAILABLE
        );
      }
    } finally {
      if (IS_CONTENT) {
        let windowUtils = this.browsingContext.window?.windowUtils;
        if (windowUtils) {
          windowUtils.leaveModalState();
        }
        PromptUtils.fireDialogEvent(
          this.browsingContext.window,
          "DOMModalDialogClosed"
        );
      }
    }
    return returnedArgs;
  }

  /**
   * Open a window modal prompt
   *
   * There's an implied contract that says modal prompts should still work when
   * no "parent" window is passed for the dialog (eg, the "Master Password"
   * dialog does this).  These prompts must be shown even if there are *no*
   * visible windows at all.
   * We try and find a window to use as the parent, but don't consider if that
   * is visible before showing the prompt. parentWindow may still be null if
   * there are _no_ windows open.
   * @param {Window} [parentWindow] - The parent window for the prompt, may be
   *        null.
   * @param {Object} args - Prompt options and return values.
   */
  openWindowPrompt(parentWindow = null, args) {
    let uri = args.promptType == "select" ? SELECT_DIALOG : COMMON_DIALOG;
    let propBag = PromptUtils.objectToPropBag(args);
    Services.ww.openWindow(
      parentWindow || Services.ww.activeWindow,
      uri,
      "_blank",
      "centerscreen,chrome,modal,titlebar",
      propBag
    );
    PromptUtils.propBagToObject(propBag, args);
  }

  async openInternalWindowPrompt(parentWindow, args) {
    if (!parentWindow?.gDialogBox) {
      this.openWindowPrompt(parentWindow, args);
      return;
    }
    let propBag = PromptUtils.objectToPropBag(args);
    propBag.setProperty("async", this.async);
    let uri = args.promptType == "select" ? SELECT_DIALOG : COMMON_DIALOG;
    await parentWindow.gDialogBox.open(uri, propBag);
    propBag.deleteProperty("async");
    PromptUtils.propBagToObject(propBag, args);
  }

  /**
   * Calls async prompt method and optionally runs promise chained task on
   * result data. Converts result data to nsIPropertyBag.
   * @param {Object} args - Prompt arguments.
   * @param {Function} [task] - Function which is called with the modified
   *  prompt args object once the prompt has been closed. Must return a
   *  result object for the prompt caller.
   * @returns {Promise<nsIPropertyBag>} - Resolves with a property bag holding the
   * prompt result properties. Resolves once prompt has been closed.
   */
  async openPromptAsync(args, task) {
    let result = await this.openPrompt(args);
    // If task is not defined, the prompt method does not return
    // anything. In this case we can resolve without value.
    if (!task) {
      return undefined;
    }
    // Convert task result to nsIPropertyBag and resolve
    let taskResult = task(result);
    if (!(taskResult instanceof Object)) {
      throw new Error("task must return object");
    }
    return PromptUtils.objectToPropBag(taskResult);
  }

  /*
   * ---------- interface disambiguation ----------
   *
   * nsIPrompt and nsIAuthPrompt share 3 method names with slightly
   * different arguments. All but prompt() have the same number of
   * arguments, so look at the arg types to figure out how we're being
   * called. :-(
   */
  prompt() {
    // also, the nsIPrompt flavor has 5 args instead of 6.
    if (typeof arguments[2] == "object") {
      return this.nsIPrompt_prompt.apply(this, arguments);
    }
    return this.nsIAuthPrompt_prompt.apply(this, arguments);
  }

  promptUsernameAndPassword() {
    // Both have 6 args, so use types.
    if (typeof arguments[2] == "object") {
      // Add the null channel:
      let args = Array.from(arguments);
      args.unshift(null);
      return this.nsIPrompt_promptUsernameAndPassword.apply(this, args);
    }
    return this.nsIAuthPrompt_promptUsernameAndPassword.apply(this, arguments);
  }

  promptPassword() {
    // Both have 5 args, so use types.
    if (typeof arguments[2] == "object") {
      // Add the null channel:
      let args = Array.from(arguments);
      args.unshift(null);
      return this.nsIPrompt_promptPassword.apply(this, args);
    }
    return this.nsIAuthPrompt_promptPassword.apply(this, arguments);
  }

  /* ----------  nsIPrompt  ---------- */

  alert(title, text) {
    if (!title) {
      title = InternalPromptUtils.getLocalizedString("Alert");
    }

    let args = {
      promptType: "alert",
      title,
      text,
    };

    if (this.async) {
      return this.openPromptAsync(args);
    }

    return this.openPromptSync(args);
  }

  alertCheck(title, text, checkLabel, checkValue) {
    if (!title) {
      title = InternalPromptUtils.getLocalizedString("Alert");
    }

    // For sync calls checkValue is an XPCOM inout. XPCOM wraps primitves in
    // objects for call by reference.
    // The async version of this method uses call by value.
    let checked = this.async ? checkValue : checkValue.value;

    let args = {
      promptType: "alertCheck",
      title,
      text,
      checkLabel,
      checked,
    };

    if (this.async) {
      return this.openPromptAsync(args, result => ({
        checked: result.checked,
      }));
    }

    this.openPromptSync(args);
    checkValue.value = args.checked;
    return undefined;
  }

  confirm(title, text) {
    if (!title) {
      title = InternalPromptUtils.getLocalizedString("Confirm");
    }

    let args = {
      promptType: "confirm",
      title,
      text,
      ok: false,
    };

    if (this.async) {
      return this.openPromptAsync(args, result => ({ ok: result.ok }));
    }

    this.openPromptSync(args);
    return args.ok;
  }

  confirmCheck(title, text, checkLabel, checkValue) {
    if (!title) {
      title = InternalPromptUtils.getLocalizedString("ConfirmCheck");
    }

    let checked = this.async ? checkValue : checkValue.value;

    let args = {
      promptType: "confirmCheck",
      title,
      text,
      checkLabel,
      checked,
      ok: false,
    };

    if (this.async) {
      return this.openPromptAsync(args, result => ({
        // Checkbox state always returned, even if cancel clicked.
        checked: result.checked,
        // Did user click Ok or Cancel?
        ok: result.ok,
      }));
    }

    this.openPromptSync(args);
    checkValue.value = args.checked;
    return args.ok;
  }

  confirmEx(
    title,
    text,
    flags,
    button0,
    button1,
    button2,
    checkLabel,
    checkValue,
    extraArgs = {}
  ) {
    if (!title) {
      title = InternalPromptUtils.getLocalizedString("Confirm");
    }

    let args = {
      promptType: "confirmEx",
      title,
      text,
      checkLabel,
      checked: this.async ? checkValue : checkValue.value,
      ok: false,
      buttonNumClicked: 1,
      ...extraArgs,
    };

    let [
      label0,
      label1,
      label2,
      defaultButtonNum,
      isDelayEnabled,
      allowNoButtons,
    ] = InternalPromptUtils.confirmExHelper(flags, button0, button1, button2);

    args.defaultButtonNum = defaultButtonNum;
    args.enableDelay = isDelayEnabled;
    args.allowNoButtons = allowNoButtons;

    if (label0) {
      args.button0Label = label0;
      if (label1) {
        args.button1Label = label1;
        if (label2) {
          args.button2Label = label2;
        }
      }
    }

    if (flags & Ci.nsIPrompt.BUTTON_POS_1_IS_SECONDARY) {
      args.isExtra1Secondary = true;
    }

    if (flags & Ci.nsIPrompt.SHOW_SPINNER) {
      args.headerIconCSSValue = "url('chrome://global/skin/icons/loading.svg')";
    }

    if (this.async) {
      return this.openPromptAsync(args, result => ({
        checked: !!result.checked,
        buttonNumClicked: result.buttonNumClicked,
        isExtra1Secondary: result.isExtra1Secondary,
      }));
    }

    this.openPromptSync(args);
    checkValue.value = args.checked;
    return args.buttonNumClicked;
  }

  nsIPrompt_prompt(title, text, value, checkLabel, checkValue) {
    if (!title) {
      title = InternalPromptUtils.getLocalizedString("Prompt");
    }

    let args = {
      promptType: "prompt",
      title,
      text,
      value: this.async ? value : value.value,
      checkLabel,
      checked: this.async ? checkValue : checkValue.value,
      ok: false,
    };

    if (this.async) {
      return this.openPromptAsync(args, result => ({
        checked: !!result.checked,
        value: result.value,
        ok: result.ok,
      }));
    }

    this.openPromptSync(args);

    // Did user click Ok or Cancel?
    let ok = args.ok;
    if (ok) {
      checkValue.value = args.checked;
      value.value = args.value;
    }

    return ok;
  }

  nsIPrompt_promptUsernameAndPassword(channel, title, text, user, pass) {
    if (!title) {
      title = InternalPromptUtils.getLocalizedString(
        "PromptUsernameAndPassword3",
        [InternalPromptUtils.getBrandFullName()]
      );
    }

    let args = {
      channel,
      promptType: "promptUserAndPass",
      title,
      text,
      user: this.async ? user : user.value,
      pass: this.async ? pass : pass.value,
      button0Label: InternalPromptUtils.getLocalizedString("SignIn"),
      ok: false,
    };

    if (this.async) {
      return this.openPromptAsync(args, result => ({
        user: result.user,
        pass: result.pass,
        ok: result.ok,
      }));
    }

    this.openPromptSync(args);

    // Did user click Ok or Cancel?
    let ok = args.ok;
    if (ok) {
      user.value = args.user;
      pass.value = args.pass;
    }

    return ok;
  }

  nsIPrompt_promptPassword(channel, title, text, pass) {
    if (!title) {
      title = InternalPromptUtils.getLocalizedString("PromptPassword3", [
        InternalPromptUtils.getBrandFullName(),
      ]);
    }

    let args = {
      channel,
      promptType: "promptPassword",
      title,
      text,
      pass: this.async ? pass : pass.value,
      button0Label: InternalPromptUtils.getLocalizedString("SignIn"),
      ok: false,
    };

    if (this.async) {
      return this.openPromptAsync(args, result => ({
        pass: result.pass,
        ok: result.ok,
      }));
    }

    this.openPromptSync(args);

    // Did user click Ok or Cancel?
    let ok = args.ok;
    if (ok) {
      pass.value = args.pass;
    }

    return ok;
  }

  select(title, text, list, selected) {
    if (!title) {
      title = InternalPromptUtils.getLocalizedString("Select");
    }

    let args = {
      promptType: "select",
      title,
      text,
      list,
      selected: -1,
      ok: false,
    };

    if (this.async) {
      return this.openPromptAsync(args, result => ({
        selected: result.selected,
        ok: result.ok,
      }));
    }

    this.openPromptSync(args);

    // Did user click Ok or Cancel?
    let ok = args.ok;
    if (ok) {
      selected.value = args.selected;
    }

    return ok;
  }

  /* ----------  nsIAuthPrompt  ---------- */

  nsIAuthPrompt_prompt(
    title,
    text,
    passwordRealm,
    savePassword,
    defaultText,
    result
  ) {
    // The passwordRealm and savePassword args were ignored by nsPrompt.cpp
    if (defaultText) {
      result.value = defaultText;
    }
    return this.nsIPrompt_prompt(title, text, result, null, {});
  }

  nsIAuthPrompt_promptUsernameAndPassword(
    title,
    text,
    passwordRealm,
    savePassword,
    user,
    pass
  ) {
    // The passwordRealm and savePassword args were ignored by nsPrompt.cpp
    return this.nsIPrompt_promptUsernameAndPassword(
      null,
      title,
      text,
      user,
      pass
    );
  }

  nsIAuthPrompt_promptPassword(title, text, passwordRealm, savePassword, pass) {
    // The passwordRealm and savePassword args were ignored by nsPrompt.cpp,
    // and we don't have a channel here.
    return this.nsIPrompt_promptPassword(null, title, text, pass);
  }

  /* ----------  nsIAuthPrompt2  ---------- */

  promptAuth(channel, level, authInfo) {
    let message = InternalPromptUtils.makeAuthMessage(this, channel, authInfo);

    let [username, password] = InternalPromptUtils.getAuthInfo(authInfo);

    let userParam = this.async ? username : { value: username };
    let passParam = this.async ? password : { value: password };

    let result;
    if (authInfo.flags & Ci.nsIAuthInformation.ONLY_PASSWORD) {
      result = this.nsIPrompt_promptPassword(channel, null, message, passParam);
    } else {
      result = this.nsIPrompt_promptUsernameAndPassword(
        channel,
        null,
        message,
        userParam,
        passParam
      );
    }

    // For the async case result is an nsIPropertyBag with prompt results.
    if (this.async) {
      return result.then(bag => {
        let ok = bag.getProperty("ok");
        if (ok) {
          InternalPromptUtils.setAuthInfo(
            authInfo,
            bag.getProperty("user"),
            bag.getProperty("pass")
          );
        }
        return ok;
      });
    }

    // For the sync case result is the "ok" boolean which indicates whether
    // the user has confirmed the dialog.
    if (result) {
      InternalPromptUtils.setAuthInfo(
        authInfo,
        userParam.value,
        passParam.value
      );
    }
    return result;
  }

  asyncPromptAuth() {
    // Nothing calls this directly; netwerk ends up going through
    // nsIPromptService::GetPrompt, which delegates to login manager.
    // Login manger handles the async bits itself, and only calls out
    // promptAuth, never asyncPromptAuth.
    //
    // Bug 565582 will change this.
    throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED);
  }

  /* ----------  nsIWritablePropertyBag2 ---------- */
  // Legacy way to set modal type when prompting via nsIPrompt.
  // Please prompt via nsIPromptService. This will be removed in the future.
  setPropertyAsUint32(name, value) {
    if (name == "modalType") {
      this.modalType = value;
    } else {
      throw Components.Exception("", Cr.NS_ERROR_ILLEGAL_VALUE);
    }
  }
}

XPCOMUtils.defineLazyPreferenceGetter(
  ModalPrompter,
  "defaultModalType",
  "prompts.defaultModalType",
  MODAL_TYPE_WINDOW
);

export function AuthPromptAdapterFactory() {}
AuthPromptAdapterFactory.prototype = {
  classID: Components.ID("{6e134924-6c3a-4d86-81ac-69432dd971dc}"),
  QueryInterface: ChromeUtils.generateQI(["nsIAuthPromptAdapterFactory"]),

  /* ----------  nsIAuthPromptAdapterFactory ---------- */

  createAdapter(oldPrompter) {
    return new AuthPromptAdapter(oldPrompter);
  },
};

// Takes an nsIAuthPrompt implementation, wraps it with a nsIAuthPrompt2 shell.
function AuthPromptAdapter(oldPrompter) {
  this.oldPrompter = oldPrompter;
}
AuthPromptAdapter.prototype = {
  QueryInterface: ChromeUtils.generateQI(["nsIAuthPrompt2"]),
  oldPrompter: null,

  /* ----------  nsIAuthPrompt2 ---------- */

  promptAuth(channel, level, authInfo) {
    let message = InternalPromptUtils.makeAuthMessage(
      this.oldPrompter,
      channel,
      authInfo
    );

    let [username, password] = InternalPromptUtils.getAuthInfo(authInfo);
    let userParam = { value: username };
    let passParam = { value: password };

    let { displayHost, realm } = InternalPromptUtils.getAuthTarget(
      channel,
      authInfo
    );
    let authTarget = displayHost + " (" + realm + ")";

    let ok;
    if (authInfo.flags & Ci.nsIAuthInformation.ONLY_PASSWORD) {
      ok = this.oldPrompter.promptPassword(
        null,
        message,
        authTarget,
        Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY,
        passParam
      );
    } else {
      ok = this.oldPrompter.promptUsernameAndPassword(
        null,
        message,
        authTarget,
        Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY,
        userParam,
        passParam
      );
    }

    if (ok) {
--> --------------------

--> maximum size reached

--> --------------------

[ Verzeichnis aufwärts0.45unsichere Verbindung  Übersetzung europäischer Sprachen durch Browser  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge