-
Notifications
You must be signed in to change notification settings - Fork 14
Rough version of web3 support and embeddable ParityBar #16
Changes from all commits
a70aeb8
f991c0f
759954a
c0b7ccb
4248797
dcf98cf
7da5386
09671b3
dc95e4e
15aa796
a464ae4
d86e14a
54cebbd
420636d
72bc298
523d9c2
d9e8376
cd78125
1895576
3723d7d
5f6cfd0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,13 +17,180 @@ | |
/* global chrome */ | ||
|
||
import Processor from './processor'; | ||
import Ws from './ws'; | ||
|
||
const processor = new Processor(); | ||
import { UI, TRANSPORT_UNINITIALIZED, getRetryTimeout } from '../shared'; | ||
|
||
chrome.runtime.onConnect.addListener((port) => { | ||
console.assert(port.name === 'id'); | ||
if (port.name === 'secureApi') { | ||
port.onMessage.addListener(web3Message(port)); | ||
return; | ||
} | ||
|
||
if (port.name === 'barScripts') { | ||
port.onMessage.addListener(loadScripts(port)); | ||
return; | ||
} | ||
|
||
// TODO [ToDr] Use connection without elevated privileges here! | ||
if (port.name === 'web3') { | ||
port.onMessage.addListener(web3Message(port)); | ||
return; | ||
} | ||
|
||
if (port.name === 'id') { | ||
port.onMessage.addListener(processId(port)); | ||
return; | ||
} | ||
|
||
throw new Error(`Unrecognized port: ${port.name}`); | ||
}); | ||
|
||
let openedTabId = null; | ||
let transport = null; | ||
// Attempt to extract token on start if not available. | ||
extractToken(); | ||
|
||
chrome.runtime.onMessage.addListener((request, sender, callback) => { | ||
if (!(transport && transport.isConnected) && request.token) { | ||
if (transport) { | ||
// TODO [ToDr] kill old transport! | ||
} | ||
|
||
if (openedTabId) { | ||
chrome.tabs.remove(openedTabId); | ||
openedTabId = null; | ||
} | ||
|
||
console.log('Extracted a token: ', request.token); | ||
console.log('Extracted backgroundSeed: ', request.backgroundSeed); | ||
chrome.storage.local.set({ | ||
'authToken': request.token, | ||
'backgroundSeed': request.backgroundSeed | ||
}, () => {}); | ||
transport = new Ws(`ws://${UI}`, request.token, true); | ||
return; | ||
} | ||
}); | ||
|
||
let codeCache = null; | ||
function loadScripts (port) { | ||
function retry (msg) { | ||
if (msg.type !== 'parity.bar.code') { | ||
return; | ||
} | ||
|
||
if (!codeCache) { | ||
const vendor = fetch(`http://${UI}/vendor.js`) | ||
.then(x => x.blob()); | ||
const embed = fetch(`http://${UI}/embed.html`) | ||
.then(x => x.text()) | ||
.then(page => ({ | ||
styles: /styles\/embed\.([a-z0-9]{10})\.css/.exec(page), | ||
scripts: /embed\.([a-z0-9]{10})\.js/.exec(page) | ||
})) | ||
.then(res => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We might want to use a ServiceWorker here. It's its job to fetch and cache requests, and it's work pretty good. Also it might be good to have a way to export which files are required by the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. AFAICT you cannot use ServiceWorker in background script of chrome extension (cause actually background scripts are more powerful then service workers). Also we cannot use service worker in the iframe, because of Mixed Content limitations. So the way it works is: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah ok, didn't know... So the API is not available either ? |
||
return Promise.all([ | ||
fetch(`http://${UI}/${res.styles[0]}`), | ||
fetch(`http://${UI}/${res.scripts[0]}`) | ||
]); | ||
}) | ||
.then(x => Promise.all(x.map(x => x.blob()))); | ||
|
||
codeCache = Promise.all([vendor, embed]) | ||
.then(scripts => { | ||
const vendor = scripts[0]; | ||
const styles = scripts[1][0]; | ||
const embed = scripts[1][1]; | ||
// Concat blobs | ||
const blob = new Blob([vendor, embed], { type: 'application/javascript' }); | ||
return { | ||
styles: URL.createObjectURL(styles), | ||
scripts: URL.createObjectURL(blob) | ||
}; | ||
}); | ||
} | ||
|
||
codeCache | ||
.then(code => { | ||
retry.retries = 0; | ||
port.postMessage(code); | ||
}) | ||
.catch(err => { | ||
codeCache = null; | ||
retry.retries += 1; | ||
|
||
console.error('Could not load ParityBar scripts. Retrying in a while..', err); | ||
setTimeout(() => retry(msg), getRetryTimeout(retry.retries)); | ||
}); | ||
} | ||
|
||
retry.retries = 0; | ||
return retry; | ||
} | ||
|
||
function extractToken () { | ||
chrome.storage.local.get('authToken', (token) => { | ||
if (!token.authToken) { | ||
fetch(`http://${UI}`) | ||
.then(() => { | ||
// Open a UI to extract the token from it | ||
chrome.tabs.create({ | ||
url: `http://${UI}`, | ||
active: false | ||
}, (tab) => { | ||
openedTabId = tab.id; | ||
}); | ||
extractToken.retries = 0; | ||
}) | ||
.catch(err => { | ||
console.error('Node seems down, will re-try', err); | ||
extractToken.retries += 1; | ||
setTimeout(() => extractToken(), getRetryTimeout(extractToken.retries)); | ||
}); | ||
return; | ||
} | ||
|
||
transport = new Ws(`ws://${UI}`, token.authToken, true); | ||
}); | ||
} | ||
extractToken.retries = 0; | ||
|
||
function web3Message (port) { | ||
return (msg) => { | ||
const { id, payload } = msg; | ||
if (!transport || !transport.isConnected) { | ||
console.error('Transport uninitialized!'); | ||
port.postMessage({ | ||
id, err: TRANSPORT_UNINITIALIZED, | ||
payload: null, | ||
connected: false | ||
}); | ||
return; | ||
} | ||
|
||
transport.executeRaw(payload) | ||
.then((response) => { | ||
port.postMessage({ | ||
id, | ||
err: null, | ||
payload: response, | ||
connected: true | ||
}); | ||
}) | ||
.catch((err) => { | ||
port.postMessage({ | ||
id, | ||
err, | ||
payload: null | ||
}); | ||
}); | ||
}; | ||
} | ||
|
||
port.onMessage.addListener((message = {}) => { | ||
const processor = new Processor(); | ||
function processId (port) { | ||
return (message = {}) => { | ||
const { id, data } = message; | ||
|
||
processor | ||
|
@@ -40,5 +207,5 @@ chrome.runtime.onConnect.addListener((port) => { | |
|
||
throw error; | ||
}); | ||
}); | ||
}); | ||
}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't it looks a bit sketchy to randomly open and close the tab when the Extension installs ? The user won't have the time to understand what happens ; I know I would be surprised. Might be better to have a settings/options/status window where it says that it needs the auth token, and on a button click it could open the right tab and gather the right data. However this might be included in a future issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That tab is opened in the background (and it always opens only once), we also check if the node is up before opening it.
I think it might be better to just display a welcome page (that's actually quite a common thing for extensions) loaded from
http://127.0.0.1:8180/#/welcome
- it could list extension features, and the token would be extracted automatically :)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed with the welcome message, as per other extensions. Would log it in another issue though.
Because even if the tab is open in background, you can still see it open and close, right?