diff --git a/chrome/extension/background.js b/chrome/extension/background.js index cab73c4efb..0eaf873b95 100644 --- a/chrome/extension/background.js +++ b/chrome/extension/background.js @@ -10,3 +10,18 @@ const onYoroiIconClicked = () => { }; chrome.browserAction.onClicked.addListener(debounce(onYoroiIconClicked, 500, { leading: true })); + +function connectHandler(message, sender, sendResponse) { + if (sender.id == "egflibcdkfhnhdpbdlbgopagfdbkghbo") { + console.log("REAL(background.js)-yoroi received: " + JSON.stringify(message)) + if (message.type == "yoroi_connect_request") { + chrome.tabs.create({ url: 'main_window.html', active: true }); + sendResponse(true); + } + } else { + console.log("received message \"" + message + "\" from other sender: " + sender.id); + } +} + +chrome.runtime.onMessageExternal.addListener(connectHandler); + diff --git a/chrome/extension/index.js b/chrome/extension/index.js index 3700908b8e..c13eb63c0e 100644 --- a/chrome/extension/index.js +++ b/chrome/extension/index.js @@ -22,6 +22,20 @@ configure({ enforceActions: 'always' }); // Since Yoroi handles money, it's better to error our than proceed if an error occurs BigNumber.DEBUG = true; +function getMethods(obj) { +var result = []; + for (var id in obj) { + try { + if (typeof(obj[id]) == "function") { + result.push(id + ": " + obj[id].toString()); + } + } catch (err) { + result.push(id + ": inaccessible"); + } + } + return result; + } + // Entry point into our application const initializeYoroi: void => Promise = async () => { const api = await setupApi(); @@ -40,6 +54,7 @@ const initializeYoroi: void => Promise = async () => { createStores(api, actions, router); }) }; + //alert("yoroi.api = " + JSON.stringify(window.yoroi.stores.wallets)); const root = document.querySelector('#root'); if (root == null) { @@ -49,8 +64,70 @@ const initializeYoroi: void => Promise = async () => { , root ); + + chrome.runtime.sendMessage( + "egflibcdkfhnhdpbdlbgopagfdbkghbo", + {type: "yoroi_connected"}, + ); }; addCloseListener(); window.addEventListener('load', initializeYoroi); + +function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +async function rpcHandler(message, sender, sendResponse) { + alert(`received ${JSON.stringify(message)} from rpcHandler`); + if (sender.id == "egflibcdkfhnhdpbdlbgopagfdbkghbo") { + console.log("REAL(index.js)-yoroi received: " + JSON.stringify(message)) + if (message.type == "connector_rpc_request") { + switch (message.function) { + case "get_balance": + if (message.params[0] == "ERG") { + //sleep(5000).then(() => { + //window.yoroi.api.?. + const wallets = window.yoroi.stores.wallets; + console.log("wallets: " + wallets.publicDerivers); + const publicDeriver = wallets.first; + //alert(); + //const getBalance = asGetBalance(publicDeriver); + publicDeriver.getBalance().then(x => { + sendResponse({ + //ok: publicDeriver.getBalance() + ok: x + }); + }); + //}); + } else { + sendResponse({ + ok: 5 + }); + } + break; + case "sign_tx": + sendResponse({ + err: { + code: 2, + info: "User rejected", + } + }); + case "ping": + sendResponse({ + ok: true, + }); + default: + sendResponse({ + err: "unknown RPC: " + message.function + "(" + message.params + ")" + }) + break; + } + } + } else { + alert("received message \"" + message + "\" from other sender: " + sender.id); + } +} + +chrome.runtime.onMessageExternal.addListener(rpcHandler); diff --git a/yoroi-ergo-connector/background.js b/yoroi-ergo-connector/background.js index 3b089afc81..210056d8bf 100644 --- a/yoroi-ergo-connector/background.js +++ b/yoroi-ergo-connector/background.js @@ -1,5 +1,8 @@ +// TODO: put this somewhere common? +const yoroiExtensionId = "bgihpbbhciffmelcfbccneidnnmkcdhl"; + chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) { - //alert("received from page: " + JSON.stringify(sender)); + //alert("background message: " + JSON.stringify(sender)); if (request.type == "init_page_action") { chrome.pageAction.setPopup({ tabId: sender.tab.id, @@ -7,4 +10,15 @@ chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) { }); chrome.pageAction.show(sender.tab.id); } +}); + +chrome.runtime.onMessageExternal.addListener(function(message, sender, sendResponse) { + //alert("background external message: " + JSON.stringify(message)); + if (sender.id == yoroiExtensionId) { + if (message.type == "yoroi_connected") { + chrome.tabs.query({active: true}, function(tabs) { + chrome.tabs.sendMessage(tabs[0].id, {type: "yoroi_connected"}); + }); + } + } }); \ No newline at end of file diff --git a/yoroi-ergo-connector/inject.js b/yoroi-ergo-connector/inject.js index 7b5e0ac71d..8d2d9f8e23 100644 --- a/yoroi-ergo-connector/inject.js +++ b/yoroi-ergo-connector/inject.js @@ -1,28 +1,61 @@ +// replace "*" with location.origin before committing on all postMessage calls + +//const yoroiExtensionId = "eegbdfmlofnpgiiilnlboaamccblbobe"; +const yoroiExtensionId = "bgihpbbhciffmelcfbccneidnnmkcdhl"; + // sets up RPC communication with the connector + access check/request functions const initialInject = ` - -var rpcUid = 0; -var rpcResolver = new Map(); var timeout = 0; -function _ergo_rpc_call(func, params) { +var connectRequests = []; + +window.addEventListener("message", function(event) { + if (event.data.type == "connector_connected") { + if (event.data.err !== undefined) { + connectRequests.forEach(promise => promise.reject(event.data.err)); + } else { + connectRequests.forEach(promise => promise.resolve(event.data.success)); + } + } +}); + +function ergo_request_read_access() { return new Promise(function(resolve, reject) { window.postMessage({ - type: "connector_rpc_request", - uid: rpcUid, - function: func, - params: params - }, location.origin); - rpcResolver.set(rpcUid, { resolve: resolve, reject: reject }); - rpcUid += 1; + type: "connector_connect_request", + }, "*"); + connectRequests.push({ resolve: resolve, reject: reject }); }); } -function ergo_request_read_access() { - return _ergo_rpc_call("ergo_request_read_access", []); -} +// TODO: fix or change back how RPCs work +// // disconnect detector +// setInterval(function() { +// if (timeout == 20) { +// window.dispatchEvent(new Event("ergo_wallet_disconnected")); +// } +// if (timeout == 25) { +// rpcResolver.forEach(function(rpc) { +// rpc.reject("timed out"); +// }); +// } +// timeout += 1; +// }, 1000); + +// // ping sender +// setInterval(function() { +// _ergo_rpc_call("ping", []).then(function() { +// timeout = 0; +// }); +// }, 10000); +` +// client-facing ergo object API +const apiInject = ` // RPC set-up +var rpcUid = 0; +var rpcResolver = new Map(); + window.addEventListener("message", function(event) { if (event.data.type == "connector_rpc_response") { console.log("page received from connector: " + JSON.stringify(event.data) + " with source = " + event.source + " and origin = " + event.origin); @@ -38,36 +71,26 @@ window.addEventListener("message", function(event) { } }); -// disconnect detector -setInterval(function() { - if (timeout == 20) { - window.dispatchEvent(new Event("ergo_wallet_disconnected")); - } - if (timeout == 25) { - rpcResolver.forEach(function(rpc) { - rpc.reject("timed out"); - }); - } - timeout += 1; -}, 1000); - -// ping sender -setInterval(function() { - _ergo_rpc_call("ping", []).then(function() { - timeout = 0; - }); -}, 10000); -` - -// client-facing ergo object API -const apiInject = ` class ErgoAPI { get_balance(token_id = 'ERG') { - return _ergo_rpc_call("get_balance", [token_id]); + return this._ergo_rpc_call("get_balance", [token_id]); } sign_tx(tx) { - return _ergo_rpc_call("sign_tx", [tx]); + return this._ergo_rpc_call("sign_tx", [tx]); + } + + _ergo_rpc_call(func, params) { + return new Promise(function(resolve, reject) { + window.postMessage({ + type: "connector_rpc_request", + uid: rpcUid, + function: func, + params: params + }, "*"); + rpcResolver.set(rpcUid, { resolve: resolve, reject: reject }); + rpcUid += 1; + }); } } @@ -92,63 +115,59 @@ function injectIntoPage(code) { injectIntoPage(initialInject); +chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) { + //alert("content script message: " + JSON.stringify(request)); + if (request.type == "yoroi_connected") { + // inject full API here + if (injectIntoPage(apiInject)) { + chrome.runtime.sendMessage({type: "init_page_action"}); + } else { + alert("failed to inject Ergo API"); + // TODO: return an error instead here if injection fails? + } + window.postMessage({ + type: "connector_connected", + success: true + }, "*"); + } +}); + window.addEventListener("message", function(event) { - function sendRpcToYoroi(injectApiOnSuccess) { + if (event.data.type == "connector_rpc_request") { + console.log("connector received from page: " + JSON.stringify(event.data) + " with source = " + event.source + " and origin = " + event.origin); chrome.runtime.sendMessage( - "eegbdfmlofnpgiiilnlboaamccblbobe", + yoroiExtensionId, event.data, {}, function(response) { - if (injectApiOnSuccess) { - // inject full API here - if (response.ok === true) { - if (injectIntoPage(apiInject)) { - chrome.runtime.sendMessage( - {type:"init_page_action"}); - } else { - alert("failed to inject Ergo API"); - // TODO: return an error instead here if injection fails? - } - } else { - // ??? - } - } window.postMessage({ type: "connector_rpc_response", uid: event.data.uid, return: response - }, location.origin); + }, "*"); }); - } - - if (event.data.type == "connector_rpc_request") { - console.log("connector received from page: " + JSON.stringify(event.data) + " with source = " + event.source + " and origin = " + event.origin); - if (event.data.function == "ergo_request_read_access") { - chrome.storage.local.get("whitelist", function(result) { - alert(JSON.stringify(result)); - let whitelist = Object.keys(result).length === 0 ? [] : result.whitelist; - if (!whitelist.includes(location.hostname)) { - if (confirm(`Allow access of ${location.hostname} to Ergo-Yoroi connector?`)) { - if (confirm(`Save ${location.hostname} to whitelist?`)) { - whitelist.push(location.hostname); - chrome.storage.local.set({whitelist:whitelist}); - } - sendRpcToYoroi(true); - } else { - // user refused - skip communication with Yoroi - window.postMessage({ - type: "connector_rpc_response", - uid: event.data.uid, - return: {ok: false} - }, location.origin); + } else if (event.data.type == "connector_connect_request") { + // TODO: add timeout somehow? + chrome.storage.local.get("whitelist", function(result) { + let whitelist = Object.keys(result).length === 0 ? [] : result.whitelist; + if (!whitelist.includes(location.hostname)) { + if (confirm(`Allow access of ${location.hostname} to Ergo-Yoroi connector?`)) { + if (confirm(`Save ${location.hostname} to whitelist?`)) { + whitelist.push(location.hostname); + chrome.storage.local.set({whitelist: whitelist}); } + chrome.runtime.sendMessage(yoroiExtensionId, {type: "yoroi_connect_request"}); } else { - // already in whitelist - sendRpcToYoroi(true); + // user refused - skip communication with Yoroi + window.postMessage({ + type: "connector_connected", + success: false + }, "*"); } - }); - } else { - sendRpcToYoroi(false); - } + } else { + // already in whitelist + chrome.runtime.sendMessage(yoroiExtensionId, {type: "yoroi_connect_request"}); + } + }); } }); \ No newline at end of file diff --git a/yoroi-ergo-connector/test.html b/yoroi-ergo-connector/test.html index 67de186c9f..e2f514b446 100644 --- a/yoroi-ergo-connector/test.html +++ b/yoroi-ergo-connector/test.html @@ -12,14 +12,14 @@ window.addEventListener("ergo_wallet_disconnected", function(event) { alert("wallet disconnected"); }); - _ergo_rpc_call("test", [1, 2, 3]).catch(function(result) { + ergo._ergo_rpc_call("test", [1, 2, 3]).catch(function(result) { console.log("_ergo_rpc_call(\"test\"(1, 2, 3)) = " + JSON.stringify(result)); }); ergo.get_balance().then(function(result) { - console.log("ergo.get_balance() = " + result); + alert("ergo.get_balance() = " + result); }); ergo.get_balance("ADA").then(function(result) { - console.log("ergo.get_balance(ADA) = " + result); + alert("ergo.get_balance(ADA) = " + result); }); ergo.sign_tx({}).then(function(result) { console.log("ergo.sign_tx() = " + result); @@ -30,4 +30,4 @@ }); } - \ No newline at end of file +