tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

GeckoViewPrompterParent.sys.mjs (4787B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 import { GeckoViewActorParent } from "resource://gre/modules/GeckoViewActorParent.sys.mjs";
      6 
      7 const DIALOGS = [
      8  "alert",
      9  "alertCheck",
     10  "confirm",
     11  "confirmCheck",
     12  "prompt",
     13  "promptCheck",
     14 ];
     15 
     16 export class GeckoViewPrompterParent extends GeckoViewActorParent {
     17  constructor() {
     18    super();
     19    this._prompts = new Map();
     20  }
     21 
     22  get rootActor() {
     23    return this.browsingContext.top.currentWindowGlobal.getActor(
     24      "GeckoViewPrompter"
     25    );
     26  }
     27 
     28  registerPrompt(promptId, promptType, actor) {
     29    return this._prompts.set(
     30      promptId,
     31      new RemotePrompt(promptId, promptType, actor)
     32    );
     33  }
     34 
     35  unregisterPrompt(promptId) {
     36    this._prompts.delete(promptId);
     37  }
     38 
     39  notifyPromptShow(promptId) {
     40    // ToDo: Bug 1761480 - GeckoView can send additional prompts to Marionette
     41    if (this._prompts.get(promptId).isDialog) {
     42      Services.obs.notifyObservers({ id: promptId }, "geckoview-prompt-show");
     43    }
     44  }
     45 
     46  getPrompts() {
     47    const self = this;
     48    const prompts = [];
     49    // Marionette expects this event to be fired from the parent
     50    const createDialogClosedEvent = detail =>
     51      new CustomEvent("DOMModalDialogClosed", {
     52        cancelable: true,
     53        bubbles: true,
     54        detail,
     55      });
     56 
     57    for (const [, prompt] of this._prompts) {
     58      // Adding only WebDriver compliant dialogs to the window
     59      if (prompt.isDialog) {
     60        prompts.push({
     61          args: {
     62            modalType: "GeckoViewPrompter",
     63            promptType: prompt.type,
     64            isDialog: prompt.isDialog,
     65          },
     66          getPromptId() {
     67            return prompt.id;
     68          },
     69          setInputText(text) {
     70            prompt.inputText = text;
     71            prompt.setInputText(text);
     72          },
     73          async getPromptText() {
     74            return prompt.getPromptText();
     75          },
     76          async getInputText() {
     77            return prompt.getInputText();
     78          },
     79          acceptPrompt() {
     80            prompt.acceptPrompt();
     81            self.window.dispatchEvent(
     82              createDialogClosedEvent({
     83                areLeaving: true,
     84                promptType: prompt.type,
     85                value: prompt.inputText,
     86              })
     87            );
     88          },
     89          dismissPrompt() {
     90            prompt.dismissPrompt();
     91            self.window.dispatchEvent(
     92              createDialogClosedEvent({
     93                areLeaving: false,
     94                promptType: prompt.type,
     95              })
     96            );
     97          },
     98        });
     99      }
    100    }
    101    return prompts;
    102  }
    103 
    104  /**
    105   * Handles the message coming from GeckoViewPrompterChild.
    106   *
    107   * @param   {string} message.name The subject of the message.
    108   * @param   {object} message.data The data of the message.
    109   */
    110  // eslint-disable-next-line consistent-return
    111  async receiveMessage({ name, data }) {
    112    switch (name) {
    113      case "RegisterPrompt": {
    114        this.rootActor.registerPrompt(data.id, data.promptType, this);
    115        break;
    116      }
    117      case "UnregisterPrompt": {
    118        this.rootActor.unregisterPrompt(data.id);
    119        break;
    120      }
    121      case "NotifyPromptShow": {
    122        this.rootActor.notifyPromptShow(data.id);
    123        break;
    124      }
    125      case "GeckoView:Prompt:Dismiss": {
    126        return this.eventDispatcher.sendRequest({
    127          ...data,
    128          type: "GeckoView:Prompt:Dismiss",
    129        });
    130      }
    131      case "GeckoView:Prompt:Update": {
    132        return this.eventDispatcher.sendRequest({
    133          ...data,
    134          type: "GeckoView:Prompt:Update",
    135        });
    136      }
    137      case "GeckoView:Prompt": {
    138        return this.eventDispatcher.sendRequestForResult({
    139          ...data,
    140          type: "GeckoView:Prompt",
    141        });
    142      }
    143      default: {
    144        return super.receiveMessage({ name, data });
    145      }
    146    }
    147  }
    148 }
    149 
    150 class RemotePrompt {
    151  constructor(id, type, actor) {
    152    this.id = id;
    153    this.type = type;
    154    this.actor = actor;
    155  }
    156 
    157  // Checks if the prompt conforms to a WebDriver simple dialog.
    158  get isDialog() {
    159    return DIALOGS.includes(this.type);
    160  }
    161 
    162  getPromptText() {
    163    return this.actor.sendQuery("GetPromptText", {
    164      id: this.id,
    165    });
    166  }
    167 
    168  getInputText() {
    169    return this.actor.sendQuery("GetInputText", {
    170      id: this.id,
    171    });
    172  }
    173 
    174  setInputText(inputText) {
    175    this.actor.sendAsyncMessage("SetInputText", {
    176      id: this.id,
    177      text: inputText,
    178    });
    179  }
    180 
    181  acceptPrompt() {
    182    this.actor.sendAsyncMessage("AcceptPrompt", {
    183      id: this.id,
    184    });
    185  }
    186 
    187  dismissPrompt() {
    188    this.actor.sendAsyncMessage("DismissPrompt", {
    189      id: this.id,
    190    });
    191  }
    192 }