Skip to content

Commit

Permalink
feat(AEX_2): Connect to extension from iframe (#992)
Browse files Browse the repository at this point in the history
* feat(AEX_2): Add flag for allowing cross origin messages for WindowMessageConnection and Content script bridge
Adjust WalletDetector to properly resolve origin and create connnection

* feat(AEX_2): Remove check for available network in Wallet `connect` handler

* feat(AEX_2): Add auto target detection for BrowserWindowConnection

* feat(AEX_2): Adjust helper for multiple browser support

* feat(AEX_2): Fix RPC test's

* feat(AEX_2): Fix RPC test's
  • Loading branch information
nduchak authored May 20, 2020
1 parent 87b9ef9 commit 47179f7
Show file tree
Hide file tree
Showing 7 changed files with 50 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import stampit from '@stamp/it'
import WalletConnection from '.'
import { v4 as uuid } from 'uuid'
import { MESSAGE_DIRECTION } from '../schema'
import { isContentScript, isInIframe } from '../helpers'

/**
* Check if connected
Expand All @@ -52,11 +53,12 @@ function connect (onMessage) {
const origin = this.origin
const receiveDirection = this.receiveDirection
const debug = this.debug
const forceOrigin = this.forceOrigin
if (this.listener) throw new Error('You already connected')

this.listener = (msg, source) => {
if (!msg || typeof msg.data !== 'object') return
if (origin && origin !== msg.origin) return
if (!forceOrigin && origin && origin !== msg.origin) return
if (debug) console.log('Receive message: ', msg)
if (msg.data.type) {
if (msg.data.type !== receiveDirection) return
Expand Down Expand Up @@ -95,6 +97,16 @@ function sendMessage (msg) {
this.postFn(message)
}

const getTarget = () => {
const isCS = isContentScript()
if (isCS) {
return window
}
// When we is the main page we need to decide the target by our self
// Probably can be implemented some algo for checking DOM for Iframes and somehow decide which Iframe to talk
return isInIframe() ? window.parent : undefined
}

/**
* BrowserWindowMessageConnection
* @function
Expand All @@ -111,7 +123,7 @@ function sendMessage (msg) {
* @return {Object}
*/
export const BrowserWindowMessageConnection = stampit({
init ({ connectionInfo = {}, target = window.parent, self = window, origin, sendDirection, receiveDirection = MESSAGE_DIRECTION.to_aepp, debug = false } = {}) {
init ({ connectionInfo = {}, target = getTarget(), self = window, origin, sendDirection, receiveDirection = MESSAGE_DIRECTION.to_aepp, debug = false, forceOrigin = false } = {}) {
if (sendDirection && !Object.keys(MESSAGE_DIRECTION).includes(sendDirection)) throw new Error(`sendDirection must be one of [${Object.keys(MESSAGE_DIRECTION)}]`)
if (!Object.keys(MESSAGE_DIRECTION).includes(receiveDirection)) throw new Error(`receiveDirection must be one of [${Object.keys(MESSAGE_DIRECTION)}]`)
this.connectionInfo = { ...{ id: uuid() }, ...connectionInfo }
Expand All @@ -120,6 +132,7 @@ export const BrowserWindowMessageConnection = stampit({
const targetP = target
this.origin = origin
this.debug = debug
this.forceOrigin = forceOrigin
this.sendDirection = sendDirection
this.receiveDirection = receiveDirection
this.subscribeFn = (listener) => selfP.addEventListener('message', listener, false)
Expand Down
6 changes: 4 additions & 2 deletions es/utils/aepp-wallet-communication/content-script-bridge.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,14 @@ import stampit from '@stamp/it'
* @return {void}
*/
function run () {
const allowCrossOrigin = this.allowCrossOrigin
// Connect to extension using runtime
this.extConnection.connect((msg) => {
this.pageConnection.sendMessage(msg)
})
// Connect to page using window.postMessage
this.pageConnection.connect((msg, origin, source) => {
if (source !== window) return
if (!allowCrossOrigin && source !== window) return
this.extConnection.sendMessage(msg)
})
}
Expand Down Expand Up @@ -67,10 +68,11 @@ function stop () {
* @return {ContentScriptBridge}
*/
export const ContentScriptBridge = stampit({
init ({ pageConnection, extConnection }) {
init ({ pageConnection, extConnection, allowCrossOrigin = false }) {
if (!window) throw new Error('Window object not found, you can run bridge only in browser')
if (!pageConnection) throw new Error('pageConnection required')
if (!extConnection) throw new Error('extConnection required')
this.allowCrossOrigin = allowCrossOrigin
this.pageConnection = pageConnection
this.extConnection = extConnection
},
Expand Down
9 changes: 9 additions & 0 deletions es/utils/aepp-wallet-communication/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,22 @@
/* eslint-disable no-undef */
import { isMemoryAccount } from '../../account/selector'

const isWeb = () => location && location.protocol && location.protocol.startsWith('http')

export const getBrowserAPI = (force = false) => {
if (chrome === Object(chrome) && chrome.runtime) return chrome
if (browser === Object(browser) && browser.runtime) return browser
if (!force) throw new Error('Browser is not detected')
return {}
}

const isExtensionContext = () => {
const browser = getBrowserAPI()
return typeof browser === 'object' && browser && typeof browser.extension === 'object'
}

export const isContentScript = () => isExtensionContext() && isWeb()

export const isInIframe = () => window !== window.parent

export const getWindow = () => {
Expand Down
20 changes: 18 additions & 2 deletions es/utils/aepp-wallet-communication/wallet-detector.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,20 @@ import { isInIframe } from './helpers'

const wallets = {}

const getOrigin = ({ isExtension, origin }) => {
if (isExtension) {
return window.origin
}
return origin
}

const getTarget = ({ isExtension, source }) => {
if (isExtension) {
return source
}
return isInIframe() ? window.parent : source
}

const handleDetection = (onDetected) => ({ method, params }, origin, source) => {
if (!method || !params) return
const ifExist = Object.prototype.hasOwnProperty.call(wallets, params.id)
Expand All @@ -40,12 +54,14 @@ const handleDetection = (onDetected) => ({ method, params }, origin, source) =>
async getConnection () {
// if detect extension wallet or page wallet
const isExtension = this.type === 'extension'
const origin = getOrigin({ isExtension, origin: this.origin })
const target = getTarget({ isExtension, source })
return BrowserWindowMessageConnection({
connectionInfo: this,
origin: isExtension ? window.origin : this.origin,
sendDirection: isExtension ? MESSAGE_DIRECTION.to_waellet : undefined,
receiveDirection: isExtension ? MESSAGE_DIRECTION.to_aepp : undefined,
target: isInIframe() ? window.parent : source
target,
origin
})
}
}
Expand Down
3 changes: 2 additions & 1 deletion examples/browser/extension/src/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@
],
"js": [
"inject.bundle.js"
]
],
"all_frames": true
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@
async created () {
// Open iframe with Wallet if run in top window
window !== window.parent || await this.getReverseWindow()
//
this.client = await RpcAepp({
name: 'AEPP',
nodes: [{ name: 'test-net', instance: await Node({ url: NODE_URL, internalUrl: NODE_INTERNAL_URL }) }],
Expand Down
1 change: 1 addition & 0 deletions test/integration/rpc.js
Original file line number Diff line number Diff line change
Expand Up @@ -674,5 +674,6 @@ describe('Aepp<->Wallet', function () {
const getConnections = (direct) => {
global.chrome = { runtime: {} }
global.window = { location: { origin: '//test' } }
global.location = { protocol: 'http://test.com' }
return getFakeConnections(direct)
}

0 comments on commit 47179f7

Please sign in to comment.