tor-browser

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

UrlbarProviderClipboard.sys.mjs (4203B)


      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 {
      6  UrlbarProvider,
      7  UrlbarUtils,
      8 } from "moz-src:///browser/components/urlbar/UrlbarUtils.sys.mjs";
      9 
     10 const lazy = {};
     11 
     12 ChromeUtils.defineESModuleGetters(lazy, {
     13  UrlbarResult: "moz-src:///browser/components/urlbar/UrlbarResult.sys.mjs",
     14  UrlbarPrefs: "moz-src:///browser/components/urlbar/UrlbarPrefs.sys.mjs",
     15  UrlUtils: "resource://gre/modules/UrlUtils.sys.mjs",
     16 });
     17 
     18 const RESULT_MENU_COMMANDS = {
     19  DISMISS: "dismiss",
     20 };
     21 export const CLIPBOARD_IMPRESSION_LIMIT = 2;
     22 
     23 /**
     24 * A provider that returns a suggested url to the user based
     25 * on a valid URL stored in the clipboard.
     26 */
     27 export class UrlbarProviderClipboard extends UrlbarProvider {
     28  #previousClipboard = {
     29    value: "",
     30    impressionsLeft: CLIPBOARD_IMPRESSION_LIMIT,
     31  };
     32 
     33  constructor() {
     34    super();
     35  }
     36 
     37  /**
     38   * @returns {Values<typeof UrlbarUtils.PROVIDER_TYPE>}
     39   */
     40  get type() {
     41    return UrlbarUtils.PROVIDER_TYPE.PROFILE;
     42  }
     43 
     44  setPreviousClipboardValue(newValue) {
     45    this.#previousClipboard.value = newValue;
     46  }
     47 
     48  async isActive(queryContext, controller) {
     49    // Return clipboard results only for empty searches.
     50    if (
     51      !lazy.UrlbarPrefs.get("clipboard.featureGate") ||
     52      !lazy.UrlbarPrefs.get("suggest.clipboard") ||
     53      queryContext.searchString ||
     54      queryContext.searchMode
     55    ) {
     56      return false;
     57    }
     58    let textFromClipboard = controller.browserWindow.readFromClipboard();
     59 
     60    // Check for spaces in clipboard text to avoid suggesting
     61    // clipboard content including both a url and the following text.
     62    if (
     63      !textFromClipboard ||
     64      textFromClipboard.length > 2048 ||
     65      lazy.UrlUtils.REGEXP_SPACES.test(textFromClipboard)
     66    ) {
     67      return false;
     68    }
     69    textFromClipboard =
     70      controller.input.sanitizeTextFromClipboard(textFromClipboard);
     71    const validUrl = this.#validUrl(textFromClipboard);
     72    if (!validUrl) {
     73      return false;
     74    }
     75 
     76    if (this.#previousClipboard.value === validUrl) {
     77      if (this.#previousClipboard.impressionsLeft <= 0) {
     78        return false;
     79      }
     80    } else {
     81      this.#previousClipboard = {
     82        value: validUrl,
     83        impressionsLeft: CLIPBOARD_IMPRESSION_LIMIT,
     84      };
     85    }
     86 
     87    return true;
     88  }
     89 
     90  #validUrl(clipboardVal) {
     91    let givenUrl = URL.parse(clipboardVal);
     92    if (!givenUrl) {
     93      // Not a valid URI.
     94      return null;
     95    }
     96 
     97    if (givenUrl.protocol == "http:" || givenUrl.protocol == "https:") {
     98      return givenUrl.href;
     99    }
    100 
    101    return null;
    102  }
    103 
    104  getPriority() {
    105    // Zero-prefix suggestions have the same priority as top sites.
    106    return 1;
    107  }
    108 
    109  /**
    110   * Starts querying.
    111   *
    112   * @param {UrlbarQueryContext} queryContext
    113   * @param {(provider: UrlbarProvider, result: UrlbarResult) => void} addCallback
    114   *   Callback invoked by the provider to add a new result.
    115   */
    116  async startQuery(queryContext, addCallback) {
    117    // If the query was started, isActive should have cached a url already.
    118    let result = new lazy.UrlbarResult({
    119      type: UrlbarUtils.RESULT_TYPE.URL,
    120      source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
    121      payload: {
    122        title: UrlbarUtils.prepareUrlForDisplay(this.#previousClipboard.value, {
    123          trimURL: false,
    124        }),
    125        url: this.#previousClipboard.value,
    126        icon: "chrome://global/skin/icons/clipboard.svg",
    127        isBlockable: true,
    128      },
    129    });
    130 
    131    addCallback(this, result);
    132  }
    133 
    134  onEngagement(queryContext, controller, details) {
    135    this.#previousClipboard.impressionsLeft = 0; // User has picked the suggested clipboard result
    136    // Handle commands.
    137    this.#handlePossibleCommand(
    138      controller.view,
    139      details.result,
    140      details.selType
    141    );
    142  }
    143 
    144  onImpression() {
    145    this.#previousClipboard.impressionsLeft--;
    146  }
    147 
    148  #handlePossibleCommand(view, result, selType) {
    149    switch (selType) {
    150      case RESULT_MENU_COMMANDS.DISMISS:
    151        view.controller.removeResult(result);
    152        this.#previousClipboard.impressionsLeft = 0;
    153        break;
    154    }
    155  }
    156 }