2018-09-27 20:19:09 +02:00
|
|
|
const ObservableStore = require('obs-store')
|
2018-10-02 02:52:31 +02:00
|
|
|
const extension = require('extensionizer')
|
2018-09-27 20:19:09 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* A controller that services user-approved requests for a full Ethereum provider API
|
|
|
|
*/
|
|
|
|
class ProviderApprovalController {
|
|
|
|
/**
|
|
|
|
* Creates a ProviderApprovalController
|
|
|
|
*
|
|
|
|
* @param {Object} [config] - Options to configure controller
|
|
|
|
*/
|
|
|
|
constructor ({ closePopup, openPopup, platform, publicConfigStore } = {}) {
|
|
|
|
this.store = new ObservableStore()
|
|
|
|
this.closePopup = closePopup
|
|
|
|
this.openPopup = openPopup
|
|
|
|
this.platform = platform
|
|
|
|
this.publicConfigStore = publicConfigStore
|
|
|
|
this.approvedOrigins = {}
|
|
|
|
platform && platform.addMessageListener && platform.addMessageListener(({ action, origin }) => {
|
2018-10-04 17:05:32 +02:00
|
|
|
if (!action) { return }
|
|
|
|
switch (action) {
|
|
|
|
case 'init-provider-request':
|
|
|
|
this.handleProviderRequest(origin)
|
|
|
|
break
|
|
|
|
case 'provider-status-request':
|
|
|
|
this.handleProviderStatusRequest(origin)
|
|
|
|
break
|
|
|
|
}
|
2018-09-27 20:19:09 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Called when a tab requests access to a full Ethereum provider API
|
|
|
|
*
|
|
|
|
* @param {string} origin - Origin of the window requesting full provider access
|
|
|
|
*/
|
2018-10-02 02:52:31 +02:00
|
|
|
async handleProviderRequest (origin) {
|
2018-09-27 20:19:09 +02:00
|
|
|
this.store.updateState({ providerRequests: [{ origin }] })
|
2018-10-02 02:52:31 +02:00
|
|
|
if (await this.isApproved(origin)) {
|
2018-09-27 20:19:09 +02:00
|
|
|
this.approveProviderRequest(origin)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
this.openPopup && this.openPopup()
|
|
|
|
}
|
|
|
|
|
2018-10-04 17:05:32 +02:00
|
|
|
/**
|
|
|
|
* Called by a tab to detemrine if a full Ethereum provider API is exposed
|
|
|
|
*
|
|
|
|
* @param {string} origin - Origin of the window requesting provider status
|
|
|
|
*/
|
|
|
|
async handleProviderStatusRequest (origin) {
|
|
|
|
const isEnabled = await this.isApproved(origin)
|
|
|
|
this.platform && this.platform.sendMessage({ action: 'provider-status', isEnabled }, { active: true })
|
|
|
|
}
|
|
|
|
|
2018-09-27 20:19:09 +02:00
|
|
|
/**
|
|
|
|
* Called when a user approves access to a full Ethereum provider API
|
|
|
|
*
|
|
|
|
* @param {string} origin - Origin of the target window to approve provider access
|
|
|
|
*/
|
|
|
|
approveProviderRequest (origin) {
|
|
|
|
this.closePopup && this.closePopup()
|
|
|
|
const requests = this.store.getState().providerRequests || []
|
|
|
|
this.platform && this.platform.sendMessage({ action: 'approve-provider-request' }, { active: true })
|
|
|
|
this.publicConfigStore.emit('update', this.publicConfigStore.getState())
|
|
|
|
const providerRequests = requests.filter(request => request.origin !== origin)
|
|
|
|
this.store.updateState({ providerRequests })
|
|
|
|
this.approvedOrigins[origin] = true
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Called when a tab rejects access to a full Ethereum provider API
|
|
|
|
*
|
|
|
|
* @param {string} origin - Origin of the target window to reject provider access
|
|
|
|
*/
|
|
|
|
rejectProviderRequest (origin) {
|
|
|
|
this.closePopup && this.closePopup()
|
|
|
|
const requests = this.store.getState().providerRequests || []
|
|
|
|
this.platform && this.platform.sendMessage({ action: 'reject-provider-request' }, { active: true })
|
|
|
|
const providerRequests = requests.filter(request => request.origin !== origin)
|
|
|
|
this.store.updateState({ providerRequests })
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Clears any cached approvals for user-approved origins
|
|
|
|
*/
|
|
|
|
clearApprovedOrigins () {
|
|
|
|
this.approvedOrigins = {}
|
2018-10-02 02:52:31 +02:00
|
|
|
extension.storage.local.set({ forcedOrigins: [] })
|
2018-09-27 20:19:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Determines if a given origin has been approved
|
|
|
|
*
|
|
|
|
* @param {string} origin - Domain origin to check for approval status
|
|
|
|
* @returns {boolean} - True if the origin has been approved
|
|
|
|
*/
|
|
|
|
isApproved (origin) {
|
2018-10-02 02:52:31 +02:00
|
|
|
return new Promise(resolve => {
|
|
|
|
extension.storage.local.get(['forcedOrigins'], ({ forcedOrigins = [] }) => {
|
|
|
|
resolve(this.approvedOrigins[origin] || forcedOrigins.indexOf(origin) > -1)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Called when a user forces the exposure of a full Ethereum provider API
|
|
|
|
*/
|
|
|
|
forceInjection () {
|
|
|
|
this.platform.sendMessage({ action: 'force-injection' }, { active: true })
|
2018-09-27 20:19:09 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = ProviderApprovalController
|