• metamask源码学习-contentscript.js


     

    When a new site is visited, the WebExtension creates a new ContentScript in that page's context, which can be seen at app/scripts/contentscript.js. This script represents a per-page setup process, which creates the per-page web3api, connects it to the background script via the Port API (wrapped in a stream abstraction), and injected into the DOM before anything loads.

    当访问一个新站点时,WebExtension会在该页面的上下文中创建一个新的ContentScript,可以在app/scripts/ ContentScript .js中看到其的代码。这个脚本表示每个页面的设置过程,它创建每个页面的web3api,通过端口API(封装在流抽象中)将其连接到后台脚本,并在加载之前注入DOM。

    它其实就是在页面与metamask之间进行交互前先通过contentscript来对页面的内容进行查看并判断是否提供web3给页面

    metamask-extension/app/scripts/contentscript.js

    它的作用就是将inpage.js这个脚本写到浏览器<script>上,使得浏览器能够调用这个脚本处理json rpc

    const fs = require('fs')
    const path = require('path')
    const pump = require('pump')
    const LocalMessageDuplexStream = require('post-message-stream')
    const PongStream = require('ping-pong-stream/pong')
    const ObjectMultiplex = require('obj-multiplex')
    const extension = require('extensionizer')
    const PortStream = require('./lib/port-stream.js')
    
    const inpageContent = fs.readFileSync(path.join(__dirname, '..', '..', 'dist', 'chrome', 'inpage.js')).toString()
    const inpageSuffix = '//# sourceURL=' + extension.extension.getURL('inpage.js') + '
    '
    const inpageBundle = inpageContent + inpageSuffix
    
    // Eventually this streaming injection could be replaced with:
    // https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Language_Bindings/Components.utils.exportFunction
    //
    // But for now that is only Firefox
    // If we create a FireFox-only code path using that API,
    // MetaMask will be much faster loading and performant on Firefox.
    
    if (shouldInjectWeb3()) {//判断传过来的访问页面如果判断满足能够InjectWeb3就将web3 inject并且建立从contentscript到inpage的双向流
      setupInjection() //然后这样传给inpage后,其web3才能使用,然后再传给页面使用
      setupStreams()
    }
    
    /**
     * Creates a script tag that injects inpage.js
     */
    function setupInjection () {//将inpage.js脚本嵌入页面<script>中
      try {
        // inject in-page script
        var scriptTag = document.createElement('script')
        scriptTag.textContent = inpageBundle
        scriptTag.onload = function () { this.parentNode.removeChild(this) }
        var container = document.head || document.documentElement
        // append as first child
        container.insertBefore(scriptTag, container.children[0])
      } catch (e) {
        console.error('Metamask injection failed.', e)
      }
    }
    
    /**
     * Sets up two-way communication streams between the
     * browser extension and local per-page browser context
     */
    function setupStreams () { //建立contentscriptinpage的双向流,inpage.js是创建inpagecontentscript的双向流
      // setup communication to page and plugin
      const pageStream = new LocalMessageDuplexStream({
        name: 'contentscript',
        target: 'inpage',
      })
      const pluginPort = extension.runtime.connect({ name: 'contentscript' })
      const pluginStream = new PortStream(pluginPort)
    
      // forward communication plugin->inpage
      pump(
        pageStream,
        pluginStream,
        pageStream,
        (err) => logStreamDisconnectWarning('MetaMask Contentscript Forwarding', err)
      )
    
      // setup local multistream channels
      const mux = new ObjectMultiplex()
      mux.setMaxListeners(25)
    
      pump(
        mux,
        pageStream,
        mux,
        (err) => logStreamDisconnectWarning('MetaMask Inpage', err)
      )
      pump(
        mux,
        pluginStream,
        mux,
        (err) => logStreamDisconnectWarning('MetaMask Background', err)
      )
    
      // connect ping stream
      const pongStream = new PongStream({ objectMode: true })
      pump(
        mux,
        pongStream,
        mux,
        (err) => logStreamDisconnectWarning('MetaMask PingPongStream', err)
      )
    
      // connect phishing warning stream
      const phishingStream = mux.createStream('phishing')
      phishingStream.once('data', redirectToPhishingWarning)
    
      // ignore unused channels (handled by background, inpage)
      mux.ignoreStream('provider')
      mux.ignoreStream('publicConfig')
    }
    
    
    /**
     * Error handler for page to plugin stream disconnections
     *
     * @param {string} remoteLabel Remote stream name
     * @param {Error} err Stream connection error
     */
    function logStreamDisconnectWarning (remoteLabel, err) {
      let warningMsg = `MetamaskContentscript - lost connection to ${remoteLabel}`
      if (err) warningMsg += '
    ' + err.stack
      console.warn(warningMsg)
    }
    
    /**
     * Determines if Web3 should be injected
     *
     * @returns {boolean} {@code true} if Web3 should be injected
     */
    function shouldInjectWeb3 () {决定是否应该插入web3
      return doctypeCheck() && suffixCheck() && 
        documentElementCheck() && !blacklistedDomainCheck() //
    }
    
    /**
     * Checks the doctype of the current document if it exists
     *
     * @returns {boolean} {@code true} if the doctype is html or if none exists
     */
    function doctypeCheck () {//查看页面的类型
      const doctype = window.document.doctype //指定文档类型节点是否为html或不存在
      if (doctype) {
        return doctype.name === 'html'
      } else {
        return true
      }
    }
    
    /**
     * Checks the current document extension
     *
     * @returns {boolean} {@code true} if the current extension is not prohibited
     */
    function suffixCheck () {//检查当前文档扩展名(不为'xml', 'pdf')
      var prohibitedTypes = ['xml', 'pdf']
      var currentUrl = window.location.href
      var currentRegex
      for (let i = 0; i < prohibitedTypes.length; i++) {
        currentRegex = new RegExp(`\.${prohibitedTypes[i]}$`)
        if (currentRegex.test(currentUrl)) {
          return false
        }
      }
      return true
    }
    
    /**
     * Checks the documentElement of the current document
     *
     * @returns {boolean} {@code true} if the documentElement is an html node or if none exists
     */
    function documentElementCheck () {
      var documentElement = document.documentElement.nodeName //返回文档的根节点是否为html或不存在
      if (documentElement) {
        return documentElement.toLowerCase() === 'html'
      }
      return true
    }
    
    /**
     * Checks if the current domain is blacklisted
     *
     * @returns {boolean} {@code true} if the current domain is blacklisted
     */
    function blacklistedDomainCheck () {//黑名单
      var blacklistedDomains = [
        'uscourts.gov',
        'dropbox.com',
        'webbyawards.com',
        'cdn.shopify.com/s/javascripts/tricorder/xtld-read-only-frame.html',
        'adyen.com',
        'gravityforms.com',
        'harbourair.com',
        'ani.gamer.com.tw',
        'blueskybooking.com',
      ]
      var currentUrl = window.location.href
      var currentRegex
      for (let i = 0; i < blacklistedDomains.length; i++) {
        const blacklistedDomain = blacklistedDomains[i].replace('.', '\.')
        currentRegex = new RegExp(`(?:https?:\/\/)(?:(?!${blacklistedDomain}).)*$`)
        if (!currentRegex.test(currentUrl)) {
          return true
        }
      }
      return false
    }
    
    /**
     * Redirects the current page to a phishing information page
     */
    function redirectToPhishingWarning () {
      console.log('MetaMask - routing to Phishing Warning component')
      const extensionURL = extension.runtime.getURL('phishing.html')
      window.location.href = extensionURL
    }
  • 相关阅读:
    Pentaho
    sympy 解四元一次方程
    install R language on ubuntu
    pyside
    浙江省医院网上挂号
    mtu值相关
    Python 中除法运算需要注意的几点
    idea
    kilim
    good blog
  • 原文地址:https://www.cnblogs.com/wanghui-garcia/p/9713754.html
Copyright © 2020-2023  润新知