tor-browser

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

web-reference.sys.mjs (8671B)


      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 file,
      3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 const lazy = {};
      6 
      7 ChromeUtils.defineESModuleGetters(lazy, {
      8  assert: "chrome://remote/content/shared/webdriver/Assert.sys.mjs",
      9  dom: "chrome://remote/content/shared/DOM.sys.mjs",
     10  error: "chrome://remote/content/shared/webdriver/Errors.sys.mjs",
     11  generateUUID: "chrome://remote/content/shared/UUID.sys.mjs",
     12  pprint: "chrome://remote/content/shared/Format.sys.mjs",
     13 });
     14 
     15 /**
     16 * A web reference is an abstraction used to identify an element when
     17 * it is transported via the protocol, between remote- and local ends.
     18 *
     19 * In Marionette this abstraction can represent DOM elements,
     20 * WindowProxies, and XUL elements.
     21 */
     22 export class WebReference {
     23  /**
     24   * @param {string} uuid
     25   *     Identifier that must be unique across all browsing contexts
     26   *     for the contract to be upheld.
     27   */
     28  constructor(uuid) {
     29    this.uuid = lazy.assert.string(
     30      uuid,
     31      lazy.pprint`Expected "uuid" to be a string, got ${uuid}`
     32    );
     33  }
     34 
     35  /**
     36   * Performs an equality check between this web element and
     37   * <var>other</var>.
     38   *
     39   * @param {WebReference} other
     40   *     Web element to compare with this.
     41   *
     42   * @returns {boolean}
     43   *     True if this and <var>other</var> are the same.  False
     44   *     otherwise.
     45   */
     46  is(other) {
     47    return other instanceof WebReference && this.uuid === other.uuid;
     48  }
     49 
     50  toString() {
     51    return `[object ${this.constructor.name} uuid=${this.uuid}]`;
     52  }
     53 
     54  /**
     55   * Returns a new {@link WebReference} reference for a DOM or XUL element,
     56   * <code>WindowProxy</code>, or <code>ShadowRoot</code>.
     57   *
     58   * @param {(Element|ShadowRoot|WindowProxy|MockXULElement)} node
     59   *     Node to construct a web element reference for.
     60   * @param {string=} uuid
     61   *     Optional unique identifier of the WebReference if already known.
     62   *     If not defined a new unique identifier will be created.
     63   *
     64   * @returns {WebReference}
     65   *     Web reference for <var>node</var>.
     66   *
     67   * @throws {InvalidArgumentError}
     68   *     If <var>node</var> is neither a <code>WindowProxy</code>,
     69   *     DOM or XUL element, or <code>ShadowRoot</code>.
     70   */
     71  static from(node, uuid) {
     72    if (uuid === undefined) {
     73      uuid = lazy.generateUUID();
     74    }
     75 
     76    if (lazy.dom.isShadowRoot(node) && !lazy.dom.isInPrivilegedDocument(node)) {
     77      // When we support Chrome Shadowroots we will need to
     78      // do a check here of shadowroot.host being in a privileged document
     79      // See Bug 1743541
     80      return new ShadowRoot(uuid);
     81    } else if (lazy.dom.isElement(node)) {
     82      return new WebElement(uuid);
     83    } else if (lazy.dom.isDOMWindow(node)) {
     84      if (node.parent === node) {
     85        return new WebWindow(uuid);
     86      }
     87      return new WebFrame(uuid);
     88    }
     89 
     90    throw new lazy.error.InvalidArgumentError(
     91      "Expected DOM window/element " + lazy.pprint`or XUL element, got: ${node}`
     92    );
     93  }
     94 
     95  /**
     96   * Unmarshals a JSON Object to one of {@link ShadowRoot}, {@link WebElement},
     97   * {@link WebFrame}, or {@link WebWindow}.
     98   *
     99   * @param {Record<string, string>} json
    100   *     Web reference, which is supposed to be a JSON Object
    101   *     where the key is one of the {@link WebReference} concrete
    102   *     classes' UUID identifiers.
    103   *
    104   * @returns {WebReference}
    105   *     Web reference for the JSON object.
    106   *
    107   * @throws {InvalidArgumentError}
    108   *     If <var>json</var> is not a web reference.
    109   */
    110  static fromJSON(json) {
    111    lazy.assert.object(
    112      json,
    113      lazy.pprint`Expected web reference to be an object, got ${json}`
    114    );
    115    if (json instanceof WebReference) {
    116      return json;
    117    }
    118    let keys = Object.keys(json);
    119 
    120    for (let key of keys) {
    121      switch (key) {
    122        case ShadowRoot.Identifier:
    123          return ShadowRoot.fromJSON(json);
    124 
    125        case WebElement.Identifier:
    126          return WebElement.fromJSON(json);
    127 
    128        case WebFrame.Identifier:
    129          return WebFrame.fromJSON(json);
    130 
    131        case WebWindow.Identifier:
    132          return WebWindow.fromJSON(json);
    133      }
    134    }
    135 
    136    throw new lazy.error.InvalidArgumentError(
    137      lazy.pprint`Expected web reference, got: ${json}`
    138    );
    139  }
    140 
    141  /**
    142   * Checks if <var>obj<var> is a {@link WebReference} reference.
    143   *
    144   * @param {Record<string, string>} obj
    145   *     Object that represents a {@link WebReference}.
    146   *
    147   * @returns {boolean}
    148   *     True if <var>obj</var> is a {@link WebReference}, false otherwise.
    149   */
    150  static isReference(obj) {
    151    if (Object.prototype.toString.call(obj) != "[object Object]") {
    152      return false;
    153    }
    154 
    155    if (
    156      ShadowRoot.Identifier in obj ||
    157      WebElement.Identifier in obj ||
    158      WebFrame.Identifier in obj ||
    159      WebWindow.Identifier in obj
    160    ) {
    161      return true;
    162    }
    163    return false;
    164  }
    165 }
    166 
    167 /**
    168 * Shadow Root elements are represented as shadow root references when they are
    169 * transported over the wire protocol
    170 */
    171 export class ShadowRoot extends WebReference {
    172  toJSON() {
    173    return { [ShadowRoot.Identifier]: this.uuid };
    174  }
    175 
    176  static fromJSON(json) {
    177    const { Identifier } = ShadowRoot;
    178 
    179    if (!(Identifier in json)) {
    180      throw new lazy.error.InvalidArgumentError(
    181        lazy.pprint`Expected shadow root reference, got: ${json}`
    182      );
    183    }
    184 
    185    let uuid = json[Identifier];
    186    return new ShadowRoot(uuid);
    187  }
    188 
    189  /**
    190   * Constructs a {@link ShadowRoot} from a string <var>uuid</var>.
    191   *
    192   * This whole function is a workaround for the fact that clients
    193   * to Marionette occasionally pass <code>{id: <uuid>}</code> JSON
    194   * Objects instead of shadow root representations.
    195   *
    196   * @param {string} uuid
    197   *     UUID to be associated with the web reference.
    198   *
    199   * @returns {ShadowRoot}
    200   *     The shadow root reference.
    201   *
    202   * @throws {InvalidArgumentError}
    203   *     If <var>uuid</var> is not a string.
    204   */
    205  static fromUUID(uuid) {
    206    lazy.assert.string(
    207      uuid,
    208      lazy.pprint`Expected "uuid" to be a string, got: ${uuid}`
    209    );
    210 
    211    return new ShadowRoot(uuid);
    212  }
    213 }
    214 
    215 ShadowRoot.Identifier = "shadow-6066-11e4-a52e-4f735466cecf";
    216 
    217 /**
    218 * DOM elements are represented as web elements when they are
    219 * transported over the wire protocol.
    220 */
    221 export class WebElement extends WebReference {
    222  toJSON() {
    223    return { [WebElement.Identifier]: this.uuid };
    224  }
    225 
    226  static fromJSON(json) {
    227    const { Identifier } = WebElement;
    228 
    229    if (!(Identifier in json)) {
    230      throw new lazy.error.InvalidArgumentError(
    231        lazy.pprint`Expected web element reference, got: ${json}`
    232      );
    233    }
    234 
    235    let uuid = json[Identifier];
    236    return new WebElement(uuid);
    237  }
    238 
    239  /**
    240   * Constructs a {@link WebElement} from a string <var>uuid</var>.
    241   *
    242   * This whole function is a workaround for the fact that clients
    243   * to Marionette occasionally pass <code>{id: <uuid>}</code> JSON
    244   * Objects instead of web element representations.
    245   *
    246   * @param {string} uuid
    247   *     UUID to be associated with the web reference.
    248   *
    249   * @returns {WebElement}
    250   *     The web element reference.
    251   *
    252   * @throws {InvalidArgumentError}
    253   *     If <var>uuid</var> is not a string.
    254   */
    255  static fromUUID(uuid) {
    256    return new WebElement(uuid);
    257  }
    258 }
    259 
    260 WebElement.Identifier = "element-6066-11e4-a52e-4f735466cecf";
    261 
    262 /**
    263 * Nested browsing contexts, such as the <code>WindowProxy</code>
    264 * associated with <tt>&lt;frame&gt;</tt> and <tt>&lt;iframe&gt;</tt>,
    265 * are represented as web frames over the wire protocol.
    266 */
    267 export class WebFrame extends WebReference {
    268  toJSON() {
    269    return { [WebFrame.Identifier]: this.uuid };
    270  }
    271 
    272  static fromJSON(json) {
    273    if (!(WebFrame.Identifier in json)) {
    274      throw new lazy.error.InvalidArgumentError(
    275        lazy.pprint`Expected web frame reference, got: ${json}`
    276      );
    277    }
    278    let uuid = json[WebFrame.Identifier];
    279    return new WebFrame(uuid);
    280  }
    281 }
    282 
    283 WebFrame.Identifier = "frame-075b-4da1-b6ba-e579c2d3230a";
    284 
    285 /**
    286 * Top-level browsing contexts, such as <code>WindowProxy</code>
    287 * whose <code>opener</code> is null, are represented as web windows
    288 * over the wire protocol.
    289 */
    290 export class WebWindow extends WebReference {
    291  toJSON() {
    292    return { [WebWindow.Identifier]: this.uuid };
    293  }
    294 
    295  static fromJSON(json) {
    296    if (!(WebWindow.Identifier in json)) {
    297      throw new lazy.error.InvalidArgumentError(
    298        lazy.pprint`Expected web window reference, got: ${json}`
    299      );
    300    }
    301    let uuid = json[WebWindow.Identifier];
    302    return new WebWindow(uuid);
    303  }
    304 }
    305 
    306 WebWindow.Identifier = "window-fcc6-11e5-b4f8-330a88ab9d7f";