aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app/scripts/metamask-controller.js1
-rw-r--r--library/controller.js172
-rw-r--r--library/controllers/index-db-controller.js87
-rw-r--r--library/index.js2
-rw-r--r--library/popup.js20
-rw-r--r--library/server.js6
-rw-r--r--library/sw-controller.js78
-rw-r--r--library/sw-core.js204
-rw-r--r--package.json3
-rw-r--r--ui/index.js1
10 files changed, 407 insertions, 167 deletions
diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js
index 92533e022..15bf9f436 100644
--- a/app/scripts/metamask-controller.js
+++ b/app/scripts/metamask-controller.js
@@ -208,7 +208,6 @@ module.exports = class MetamaskController extends EventEmitter {
//
getState () {
-
const wallet = this.configManager.getWallet()
const vault = this.keyringController.store.getState().vault
const isInitialized = (!!wallet || !!vault)
diff --git a/library/controller.js b/library/controller.js
index 5823287cc..f0aa7172c 100644
--- a/library/controller.js
+++ b/library/controller.js
@@ -1,159 +1,13 @@
-const urlUtil = require('url')
-const extend = require('xtend')
-const Dnode = require('dnode')
-const eos = require('end-of-stream')
-const ParentStream = require('iframe-stream').ParentStream
-const PortStream = require('../app/scripts/lib/port-stream.js')
-const notification = require('../app/scripts/lib/notifications.js')
-const messageManager = require('../app/scripts/lib/message-manager')
-const setupMultiplex = require('../app/scripts/lib/stream-utils.js').setupMultiplex
-const MetamaskController = require('../app/scripts/metamask-controller')
-const extension = require('../app/scripts/lib/extension')
-
-const STORAGE_KEY = 'metamask-config'
-
-
-initializeZeroClient()
-
-function initializeZeroClient() {
-
- const controller = new MetamaskController({
- // User confirmation callbacks:
- showUnconfirmedMessage,
- unlockAccountMessage,
- showUnapprovedTx,
- // Persistence Methods:
- setData,
- loadData,
- })
- const idStore = controller.idStore
-
- function unlockAccountMessage () {
- console.log('notif stub - unlockAccountMessage')
- }
-
- function showUnconfirmedMessage (msgParams, msgId) {
- console.log('notif stub - showUnconfirmedMessage')
- }
-
- function showUnapprovedTx (txParams, txData, onTxDoneCb) {
- console.log('notif stub - showUnapprovedTx')
- }
-
- //
- // connect to other contexts
- //
-
- var connectionStream = new ParentStream()
-
- connectRemote(connectionStream, getParentHref())
-
- function connectRemote (connectionStream, originDomain) {
- var isMetaMaskInternalProcess = (originDomain === '127.0.0.1:9001')
- if (isMetaMaskInternalProcess) {
- // communication with popup
- setupTrustedCommunication(connectionStream, 'MetaMask')
- } else {
- // communication with page
- setupUntrustedCommunication(connectionStream, originDomain)
- }
- }
-
- function setupUntrustedCommunication (connectionStream, originDomain) {
- // setup multiplexing
- var mx = setupMultiplex(connectionStream)
- // connect features
- controller.setupProviderConnection(mx.createStream('provider'), originDomain)
- controller.setupPublicConfig(mx.createStream('publicConfig'))
- }
-
- function setupTrustedCommunication (connectionStream, originDomain) {
- // setup multiplexing
- var mx = setupMultiplex(connectionStream)
- // connect features
- setupControllerConnection(mx.createStream('controller'))
- controller.setupProviderConnection(mx.createStream('provider'), originDomain)
- }
-
- //
- // remote features
- //
-
- function setupControllerConnection (stream) {
- controller.stream = stream
- var api = controller.getApi()
- var dnode = Dnode(api)
- stream.pipe(dnode).pipe(stream)
- dnode.on('remote', (remote) => {
- // push updates to popup
- controller.ethStore.on('update', controller.sendUpdate.bind(controller))
- controller.listeners.push(remote)
- idStore.on('update', controller.sendUpdate.bind(controller))
-
- // teardown on disconnect
- eos(stream, () => {
- controller.ethStore.removeListener('update', controller.sendUpdate.bind(controller))
- })
- })
- }
-
- function loadData () {
- var oldData = getOldStyleData()
- var newData
- try {
- newData = JSON.parse(window.localStorage[STORAGE_KEY])
- } catch (e) {}
-
- var data = extend({
- meta: {
- version: 0,
- },
- data: {
- config: {
- provider: {
- type: 'testnet',
- },
- },
- },
- }, oldData || null, newData || null)
- return data
- }
-
- function getOldStyleData () {
- var config, wallet, seedWords
-
- var result = {
- meta: { version: 0 },
- data: {},
- }
-
- try {
- config = JSON.parse(window.localStorage['config'])
- result.data.config = config
- } catch (e) {}
- try {
- wallet = JSON.parse(window.localStorage['lightwallet'])
- result.data.wallet = wallet
- } catch (e) {}
- try {
- seedWords = window.localStorage['seedWords']
- result.data.seedWords = seedWords
- } catch (e) {}
-
- return result
- }
-
- function setData (data) {
- window.localStorage[STORAGE_KEY] = JSON.stringify(data)
- }
-
- function getParentHref(){
- try {
- var parentLocation = window.parent.location
- return parentLocation.hostname + ':' + parentLocation.port
- } catch (err) {
- return 'unknown'
- }
- }
-
-}
+// const SWcontroller = require('./sw-controller')
+// const SwStream = require('sw-stream/lib/sw-stream.js')
+// const startPopup = require('../app/scripts/popup-core')
+
+// console.log('outside:open')
+// const background = new SWcontroller({
+// fileName: 'sw-build.js',
+// })
+// background.on('ready', (readSw) => {
+// startPopup(SwStream(background.controller))
+// })
+// background.startWorker()
+console.log('hello from controller')
diff --git a/library/controllers/index-db-controller.js b/library/controllers/index-db-controller.js
new file mode 100644
index 000000000..6bcae9845
--- /dev/null
+++ b/library/controllers/index-db-controller.js
@@ -0,0 +1,87 @@
+const EventEmitter = require('events')
+module.exports = class IndexDbController extends EventEmitter {
+
+ constructor (opts) {
+ super()
+ this.migrations = opts.migrations
+ this.key = opts.key
+ this.dbObject = global.indexedDB
+ this.IDBTransaction = global.IDBTransaction || global.webkitIDBTransaction || global.msIDBTransaction || {READ_WRITE: "readwrite"}; // This line should only be needed if it is needed to support the object's constants for older browsers
+ this.IDBKeyRange = global.IDBKeyRange || global.webkitIDBKeyRange || global.msIDBKeyRange;
+ this.version = opts.version
+ this.logging = opts.logging
+ this.initialState = opts.initialState
+ if (this.logging) this.on('log', logger)
+ }
+
+ // Opens the database connection and returns a promise
+ open (version = this.version) {
+ return new Promise((resolve, reject) => {
+ const dbOpenRequest = this.dbObject.open(this.key, version)
+ dbOpenRequest.onerror = (event) => {
+ return reject(event)
+ }
+ dbOpenRequest.onsuccess = (event) => {
+ this.db = dbOpenRequest.result
+ if (!this.db.objectStoreNames.length) {
+ Object.keys(this.initialState).forEach((key) => {
+ this._add(key, this.initialState[key])
+ })
+ }
+ this.emit('success')
+ resolve(this.db)
+ }
+ dbOpenRequest.onupgradeneeded = (event) => {
+ // if (this.migrators)
+ this.db = event.target.result
+ this.migrate()
+ }
+ })
+ }
+
+ requestObjectStore (key, type = 'readonly') {
+ return new Promise((resolve, reject) => {
+ const dbReadWrite = this.db.transaction(key, type)
+ const dataStore = dbReadWrite.objectStore(key)
+ resolve(dataStore)
+ })
+ }
+
+ get (key) {
+ return this.requestObjectStore(key)
+ .then((dataObject)=> {
+ return new Promise((resolve, reject) => {
+ const getRequest = dataObject.get(key)
+ getRequest.onsuccess = (event) => resolve(event.currentTarget.result)
+ getRequest.onerror = (event) => reject(event)
+ })
+ })
+ }
+
+ put (state) {
+ return this.requestObjectStore('dataStore', 'readwrite')
+ .then((dataObject)=> {
+ const putRequest = dataObject.put(state, 'dataStore')
+ putRequest.onsuccess = (event) => Promise.resolve(event.currentTarget.result)
+ putRequest.onerror = (event) => Promise.reject(event)
+ })
+ }
+
+ migrate () {
+ this.db.createObjectStore('dataStore')
+ }
+
+ _add (key, objStore, cb = logger) {
+ return this.requestObjectStore(key, 'readwrite')
+ .then((dataObject)=> {
+ const addRequest = dataObject.add(objStore, key)
+ addRequest.onsuccess = (event) => Promise.resolve(event.currentTarget.result)
+ addRequest.onerror = (event) => Promise.reject(event)
+ })
+ }
+
+}
+
+function logger (err, ress) {
+ err ? console.error(`Logger says: ${err}`) : console.dir(`Logger says: ${ress}`)
+}
diff --git a/library/index.js b/library/index.js
index b5f4f6637..af82c6546 100644
--- a/library/index.js
+++ b/library/index.js
@@ -26,7 +26,7 @@ var shouldPop = false
window.addEventListener('click', function(){
if (!shouldPop) return
shouldPop = false
- window.open('http://127.0.0.1:9001/popup/popup.html', '', 'width=360 height=500')
+ window.open('http://localhost:9001/popup/popup.html', '', 'width=360 height=500')
console.log('opening window...')
})
diff --git a/library/popup.js b/library/popup.js
index 667b13371..3825661cf 100644
--- a/library/popup.js
+++ b/library/popup.js
@@ -1,7 +1,10 @@
const injectCss = require('inject-css')
const MetaMaskUiCss = require('../ui/css')
-const startPopup = require('../app/scripts/popup-core')
const setupIframe = require('./lib/setup-iframe.js')
+const MetamaskInpageProvider = require('../app/scripts/lib/inpage-provider.js')
+const SWcontroller = require('./sw-controller')
+const SwStream = require('sw-stream/lib/sw-stream.js')
+const startPopup = require('../app/scripts/popup-core')
var css = MetaMaskUiCss()
@@ -11,9 +14,18 @@ var name = 'popup'
window.METAMASK_UI_TYPE = name
var iframeStream = setupIframe({
- zeroClientProvider: 'http://127.0.0.1:9001',
+ zeroClientProvider: 'http://localhost:9001',
sandboxAttributes: ['allow-scripts', 'allow-popups', 'allow-same-origin'],
container: document.body,
})
-
-startPopup(iframeStream)
+console.log('outside:open')
+const background = new SWcontroller({
+ fileName: '/popup/sw-build.js',
+})
+background.on('ready', (readSw) => {
+ // var inpageProvider = new MetamaskInpageProvider(SwStream(background.controller))
+ // startPopup(inpageProvider)
+ startPopup(SwStream(background.controller))
+})
+background.startWorker()
+console.log('hello from /library/popup.js')
diff --git a/library/server.js b/library/server.js
index 797ad8a77..a284d3e05 100644
--- a/library/server.js
+++ b/library/server.js
@@ -7,6 +7,7 @@ const zeroBundle = createBundle('./index.js')
const controllerBundle = createBundle('./controller.js')
const popupBundle = createBundle('./popup.js')
const appBundle = createBundle('./example/index.js')
+const swBuild = createBundle('./sw-core.js')
//
// Iframe Server
@@ -24,6 +25,11 @@ iframeServer.use('/popup', express.static('../dist/chrome'))
iframeServer.get('/controller.js', function(req, res){
res.send(controllerBundle.latest)
})
+iframeServer.get('/popup/sw-build.js', function(req, res){
+ console.log('/sw-build.js')
+ res.setHeader('Content-Type', 'application/javascript')
+ res.send(swBuild.latest)
+})
// serve background controller
iframeServer.use(express.static('./server'))
diff --git a/library/sw-controller.js b/library/sw-controller.js
new file mode 100644
index 000000000..23d67026e
--- /dev/null
+++ b/library/sw-controller.js
@@ -0,0 +1,78 @@
+const EventEmitter = require('events')
+
+module.exports = class ClientSideServiceWorker extends EventEmitter{
+ constructor (opts) {
+ super()
+ this.fileName = opts.fileName
+ this.startDelay = opts.startDelay
+
+ this.serviceWorkerApi = navigator.serviceWorker
+ this.serviceWorkerApi.onmessage = (event) => this.emit('message', event)
+ this.serviceWorkerApi.onerror = (event) => this.emit('error')
+
+ // temporary function
+ this.askForId = (message) => {
+ this.sendMessage('check-in')
+ .then((data) => console.log(`${message}----${data}`))
+ }
+
+ // if (!!this.serviceWorkerApi) this.askForId('before')
+
+ if (opts.initStart) this.startWorker()
+
+ this.on('ready', (sw) => {
+ this.askForId('ready')
+ })
+ }
+
+ get controller () {
+ return this.sw || this.serviceWorkerApi.controller
+ }
+
+
+ startWorker () {
+ return this.registerWorker()
+ .then((sw) => {
+ this.sw = sw
+ this.askForId('after register:')
+ this.sw.onerror = (err) => this.emit('error', err)
+ this.sw = sw
+ this.emit('ready', this.sw)
+ })
+ .catch((err) => this.emit('error', err))
+ }
+
+ registerWorker () {
+ return this.serviceWorkerApi.register(this.fileName)
+ .then((registerdWorker) => {
+ return new Promise((resolve, reject) => {
+ this.askForId('after')
+ let timeOutId = setTimeout(() => {
+ if (this.serviceWorkerApi.controller) return resolve(this.serviceWorkerApi.controller)
+ if (registerdWorker.active) return resolve(registerdWorker.active)
+ return reject(new Error('ClientSideServiceWorker: No controller found and onupdatefound timed out'))
+ }, this.startDelay || 1000 )
+
+ registerdWorker.onupdatefound = (event) => {
+ this.emit('updatefound')
+ registerdWorker.update()
+ }
+ })
+ })
+ }
+
+ sendMessage (message) {
+ const self = this
+ return new Promise((resolve, reject) => {
+ var messageChannel = new MessageChannel()
+ messageChannel.port1.onmessage = (event) => {
+ if (event.data.err) {
+ reject(event.data.error)
+ } else {
+ resolve(event.data.data)
+ }
+ }
+ this.controller.postMessage(message, [messageChannel.port2])
+ })
+ }
+}
diff --git a/library/sw-core.js b/library/sw-core.js
new file mode 100644
index 000000000..8c7de2c32
--- /dev/null
+++ b/library/sw-core.js
@@ -0,0 +1,204 @@
+global.window = global
+const SWGlobal = self
+const urlUtil = require('url')
+const endOfStream = require('end-of-stream')
+const asyncQ = require('async-q')
+const pipe = require('pump')
+
+const SwGlobalListener = require('sw-stream/lib/sw-global-listener.js')
+const connectionListener = new SwGlobalListener(self)
+const setupMultiplex = require('../app/scripts/lib/stream-utils.js').setupMultiplex
+const PortStream = require('../app/scripts/lib/port-stream.js')
+// const notification = require('../app/scripts/lib/notifications.js')
+
+const DbController = require('./controllers/index-db-controller')
+
+const MetamaskController = require('../app/scripts/metamask-controller')
+// const extension = require('../app/scripts/lib/extension')
+// const LocalStorageStore = require('obs-store/lib/localStorage')
+const storeTransform = require('obs-store/lib/transform')
+const Migrator = require('../app/scripts/lib/migrator/')
+const migrations = require('../app/scripts/migrations/')
+const firstTimeState = require('../app/scripts/first-time-state')
+
+const STORAGE_KEY = 'metamask-config'
+const METAMASK_DEBUG = 'GULP_METAMASK_DEBUG'
+let popupIsOpen = false
+
+const log = require('loglevel')
+global.log = log
+log.setDefaultLevel(METAMASK_DEBUG ? 'debug' : 'warn')
+
+self.addEventListener('install', function(event) {
+ event.waitUntil(self.skipWaiting())
+})
+self.addEventListener('activate', function(event) {
+ event.waitUntil(self.clients.claim())
+})
+
+self.onsync = function (syncEvent) {
+// What is done when a sync even is fired
+ console.log('inside:sync')
+ var focused
+ self.clients.matchAll()
+ .then(clients => {
+ clients.forEach(function(client) {
+
+ })
+ })
+}
+
+
+
+console.log('inside:open')
+
+
+// // state persistence
+let diskStore
+const dbController = new DbController({
+ key: STORAGE_KEY,
+ global: self,
+ version: 2,
+ initialState: {
+ dataStore: {
+ meta: 2,
+ data: firstTimeState,
+ },
+ },
+})
+asyncQ.waterfall([
+ () => loadStateFromPersistence(),
+ (initState) => setupController(initState),
+])
+.then(() => console.log('MetaMask initialization complete.'))
+.catch((err) => {
+ console.log('WHILE SETTING UP:')
+ console.error(err)
+})
+
+// initialization flow
+
+//
+// State and Persistence
+//
+function loadStateFromPersistence() {
+ // migrations
+ let migrator = new Migrator({ migrations })
+ const initialState = migrator.generateInitialState(firstTimeState)
+ dbController.initialState = initialState
+ return dbController.open()
+ .then((openRequest) => {
+ return dbController.get('dataStore')
+ })
+ .then((data) => {
+ if (!data) {
+ return dbController._add('dataStore', initialState)
+ .then(() => dbController.get('dataStore'))
+ .then((versionedData) => Promise.resolve(versionedData.data))
+ }
+
+ return Promise.resolve(data.data)
+ })
+ .catch((err) => console.error(err))
+ /*
+ need to get migrations working
+ */
+
+ // return asyncQ.waterfall([
+ // // read from disk
+ // () => Promise.resolve(diskStore || initialState),
+ // // migrate data
+ // (versionedData) => migrator.migrateData(versionedData),
+ // // write to disk
+ // (versionedData) => {
+ // diskStore.put(versionedData)
+ // return Promise.resolve(versionedData)
+ // },
+ // // resolve to just data
+ // (versionedData) => Promise.resolve(versionedData.data),
+ // ])
+}
+
+function setupController (initState, client) {
+
+ //
+ // MetaMask Controller
+ //
+
+ const controller = new MetamaskController({
+ // User confirmation callbacks:
+ showUnconfirmedMessage: triggerUi,
+ unlockAccountMessage: triggerUi,
+ showUnapprovedTx: triggerUi,
+ // initial state
+ initState,
+ })
+ global.metamaskController = controller
+
+ // setup state persistence
+ // pipe(
+ // controller.store,
+ // storeTransform(versionifyData),
+ // diskStore
+ // )
+ controller.store.subscribe((state) => {
+ dbController.put(versionifyData(state))
+ .catch((err) => {console.error(err)})
+ })
+ function versionifyData(state) {
+ // let versionedData = diskStore.getState()
+ // versionedData.data = state
+ let versionedData = {data: state}
+ return versionedData
+ }
+
+ //
+ // connect to other contexts
+ //
+ /*
+ need to write a service worker stream for this
+ */
+ connectionListener.on('remote', (portStream, messageEvent) => {
+ connectRemote(portStream, messageEvent.origin)
+ })
+
+ function connectRemote (connectionStream, originDomain) {
+ var isMetaMaskInternalProcess = (originDomain === 'http://localhost:9001')
+ if (isMetaMaskInternalProcess) {
+ // communication with popup
+ controller.setupTrustedCommunication(connectionStream, 'MetaMask')
+ } else {
+ // communication with page
+ setupUntrustedCommunication(connectionStream, originDomain)
+ }
+ }
+
+ function setupUntrustedCommunication (connectionStream, originDomain) {
+ // setup multiplexing
+ var mx = setupMultiplex(connectionStream)
+ // connect features
+ controller.setupProviderConnection(mx.createStream('provider'), originDomain)
+ controller.setupPublicConfig(mx.createStream('publicConfig'))
+ }
+
+ function setupTrustedCommunication (connectionStream, originDomain) {
+ // setup multiplexing
+ var mx = setupMultiplex(connectionStream)
+ // connect features
+ controller.setupProviderConnection(mx.createStream('provider'), originDomain)
+ }
+ //
+ // User Interface setup
+ //
+ return Promise.resolve()
+
+}
+
+// // //
+// // // Etc...
+// // //
+
+// // // popup trigger
+function triggerUi () {
+ if (!popupIsOpen) notification.show()
+}
diff --git a/package.json b/package.json
index 488e7e90d..c08d92339 100644
--- a/package.json
+++ b/package.json
@@ -103,13 +103,14 @@
"request-promise": "^4.1.1",
"sandwich-expando": "^1.0.5",
"semaphore": "^1.0.5",
+ "sw-stream": "^1.0.2",
"textarea-caret": "^3.0.1",
"three.js": "^0.73.2",
"through2": "^2.0.1",
"valid-url": "^1.0.9",
"vreme": "^3.0.2",
"web3": "0.18.2",
- "web3-provider-engine": "^10.0.1",
+ "web3-provider-engine": "^11.0.0",
"web3-stream-provider": "^2.0.6",
"xtend": "^4.0.1"
},
diff --git a/ui/index.js b/ui/index.js
index 1a65f813c..16875fce4 100644
--- a/ui/index.js
+++ b/ui/index.js
@@ -14,7 +14,6 @@ log.setLevel(debugMode ? 'debug' : 'warn')
function launchApp (opts) {
var accountManager = opts.accountManager
actions._setBackgroundConnection(accountManager)
-
// check if we are unlocked first
accountManager.getState(function (err, metamaskState) {
if (err) throw err