diff --git a/es/utils/aepp-wallet-communication/connection/browser-window-message.js b/es/utils/aepp-wallet-communication/connection/browser-window-message.js index 0db3993e8c..02731afa4e 100644 --- a/es/utils/aepp-wallet-communication/connection/browser-window-message.js +++ b/es/utils/aepp-wallet-communication/connection/browser-window-message.js @@ -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 @@ -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 @@ -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 @@ -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 } @@ -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) diff --git a/es/utils/aepp-wallet-communication/content-script-bridge.js b/es/utils/aepp-wallet-communication/content-script-bridge.js index 74c1252630..dc4343984d 100644 --- a/es/utils/aepp-wallet-communication/content-script-bridge.js +++ b/es/utils/aepp-wallet-communication/content-script-bridge.js @@ -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) }) } @@ -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 }, diff --git a/es/utils/aepp-wallet-communication/helpers.js b/es/utils/aepp-wallet-communication/helpers.js index ba0354f151..ade8070e57 100644 --- a/es/utils/aepp-wallet-communication/helpers.js +++ b/es/utils/aepp-wallet-communication/helpers.js @@ -4,6 +4,8 @@ /* 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 @@ -11,6 +13,13 @@ export const getBrowserAPI = (force = false) => { 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 = () => { diff --git a/es/utils/aepp-wallet-communication/wallet-detector.js b/es/utils/aepp-wallet-communication/wallet-detector.js index ede87d39e4..d6d43078a6 100644 --- a/es/utils/aepp-wallet-communication/wallet-detector.js +++ b/es/utils/aepp-wallet-communication/wallet-detector.js @@ -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) @@ -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 }) } } diff --git a/examples/browser/extension/src/manifest.json b/examples/browser/extension/src/manifest.json index e1bca564ce..089fd98bff 100644 --- a/examples/browser/extension/src/manifest.json +++ b/examples/browser/extension/src/manifest.json @@ -31,7 +31,8 @@ ], "js": [ "inject.bundle.js" - ] + ], + "all_frames": true } ] } diff --git a/examples/browser/vuejs/connect-two-ae/aepp/src/components/Home.vue b/examples/browser/vuejs/connect-two-ae/aepp/src/components/Home.vue index 938fedb325..6a9f179c2d 100644 --- a/examples/browser/vuejs/connect-two-ae/aepp/src/components/Home.vue +++ b/examples/browser/vuejs/connect-two-ae/aepp/src/components/Home.vue @@ -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 }) }], diff --git a/test/integration/rpc.js b/test/integration/rpc.js index 9cc6b21f7b..a163c1ee03 100644 --- a/test/integration/rpc.js +++ b/test/integration/rpc.js @@ -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) }