Commit cbb6af14 authored by henry's avatar henry
Browse files

fixup! Bug 40209: Implement Basic Crypto Safety

Bug 42702: Read clipboard in parent actor rather than child.
parent 40f8455d
Loading
Loading
Loading
Loading
+10 −45
Original line number Diff line number Diff line
@@ -5,12 +5,14 @@
 * 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 { Bech32Decode } from "resource://gre/modules/Bech32Decode.sys.mjs";

import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";

const lazy = {};

ChromeUtils.defineESModuleGetters(lazy, {
  setTimeout: "resource://gre/modules/Timer.sys.mjs",
});

XPCOMUtils.defineLazyPreferenceGetter(
  lazy,
  "isCryptoSafetyEnabled",
@@ -18,43 +20,6 @@ XPCOMUtils.defineLazyPreferenceGetter(
  true // Defaults to true.
);

function looksLikeCryptoAddress(s) {
  // P2PKH and P2SH addresses
  // https://stackoverflow.com/a/24205650
  const bitcoinAddr = /^[13][a-km-zA-HJ-NP-Z1-9]{25,39}$/;
  if (bitcoinAddr.test(s)) {
    return true;
  }

  // Bech32 addresses
  if (Bech32Decode(s) !== null) {
    return true;
  }

  // regular addresses
  const etherAddr = /^0x[a-fA-F0-9]{40}$/;
  if (etherAddr.test(s)) {
    return true;
  }

  // t-addresses
  // https://www.reddit.com/r/zec/comments/8mxj6x/simple_regex_to_validate_a_zcash_tz_address/dzr62p5/
  const zcashAddr = /^t1[a-zA-Z0-9]{33}$/;
  if (zcashAddr.test(s)) {
    return true;
  }

  // Standard, Integrated, and 256-bit Integrated addresses
  // https://monero.stackexchange.com/a/10627
  const moneroAddr =
    /^4(?:[0-9AB]|[1-9A-HJ-NP-Za-km-z]{12}(?:[1-9A-HJ-NP-Za-km-z]{30})?)[1-9A-HJ-NP-Za-km-z]{93}$/;
  if (moneroAddr.test(s)) {
    return true;
  }

  return false;
}

export class CryptoSafetyChild extends JSWindowActorChild {
  handleEvent(event) {
    if (
@@ -70,13 +35,13 @@ export class CryptoSafetyChild extends JSWindowActorChild {
      return;
    }

    this.contentWindow.navigator.clipboard.readText().then(clipText => {
      const selection = clipText.replace(/\s+/g, "");
      if (!looksLikeCryptoAddress(selection)) {
        return;
      }
    // We send a message to the parent to inspect the clipboard content.
    // NOTE: We wait until next cycle to allow the event to propagate and fill
    // the clipboard before being read.
    // NOTE: Using navigator.clipboard.readText fails with Wayland. See
    // tor-browser#42702.
    lazy.setTimeout(() => {
      this.sendAsyncMessage("CryptoSafety:CopiedText", {
        selection,
        host: this.document.documentURIObject.host,
      });
    });
+56 −1
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@ const lazy = {};

ChromeUtils.defineESModuleGetters(lazy, {
  TorDomainIsolator: "resource://gre/modules/TorDomainIsolator.sys.mjs",
  Bech32Decode: "resource://gre/modules/Bech32Decode.sys.mjs",
});

ChromeUtils.defineLazyGetter(lazy, "CryptoStrings", function () {
@@ -24,6 +25,43 @@ XPCOMUtils.defineLazyPreferenceGetter(
  true // Defaults to true.
);

function looksLikeCryptoAddress(s) {
  // P2PKH and P2SH addresses
  // https://stackoverflow.com/a/24205650
  const bitcoinAddr = /^[13][a-km-zA-HJ-NP-Z1-9]{25,39}$/;
  if (bitcoinAddr.test(s)) {
    return true;
  }

  // Bech32 addresses
  if (lazy.Bech32Decode(s) !== null) {
    return true;
  }

  // regular addresses
  const etherAddr = /^0x[a-fA-F0-9]{40}$/;
  if (etherAddr.test(s)) {
    return true;
  }

  // t-addresses
  // https://www.reddit.com/r/zec/comments/8mxj6x/simple_regex_to_validate_a_zcash_tz_address/dzr62p5/
  const zcashAddr = /^t1[a-zA-Z0-9]{33}$/;
  if (zcashAddr.test(s)) {
    return true;
  }

  // Standard, Integrated, and 256-bit Integrated addresses
  // https://monero.stackexchange.com/a/10627
  const moneroAddr =
    /^4(?:[0-9AB]|[1-9A-HJ-NP-Za-km-z]{12}(?:[1-9A-HJ-NP-Za-km-z]{30})?)[1-9A-HJ-NP-Za-km-z]{93}$/;
  if (moneroAddr.test(s)) {
    return true;
  }

  return false;
}

export class CryptoSafetyParent extends JSWindowActorParent {
  async receiveMessage(aMessage) {
    if (
@@ -33,7 +71,24 @@ export class CryptoSafetyParent extends JSWindowActorParent {
      return;
    }

    let address = aMessage.data.selection;
    // Read the global clipboard. We assume the contents come from the HTTP
    // page specified in `aMessage.data.host`.
    const trans = Cc["@mozilla.org/widget/transferable;1"].createInstance(
      Ci.nsITransferable
    );
    trans.init(null);
    trans.addDataFlavor("text/plain");
    Services.clipboard.getData(trans, Ci.nsIClipboard.kGlobalClipboard);
    let data = {};
    trans.getTransferData("text/plain", data);
    data = data?.value.QueryInterface(Ci.nsISupportsString).data;

    let address = data?.replace(/\s+/g, "");

    if (!address || !looksLikeCryptoAddress(address)) {
      return;
    }

    if (address.length > 32) {
      address = `${address.substring(0, 32)}…`;
    }