1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
const ObservableStore = require('obs-store')
/**
* 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, preferencesController, publicConfigStore } = {}) {
this.store = new ObservableStore()
this.closePopup = closePopup
this.openPopup = openPopup
this.platform = platform
this.publicConfigStore = publicConfigStore
this.approvedOrigins = {}
this.preferencesController = preferencesController
platform && platform.addMessageListener && platform.addMessageListener(({ action, origin }) => {
if (!action) { return }
switch (action) {
case 'init-provider-request':
this.handleProviderRequest(origin)
break
case 'init-status-request':
this.handleProviderStatusRequest(origin)
break
case 'init-privacy-request':
this.handlePrivacyStatusRequest()
}
})
}
/**
* Called when a tab requests access to a full Ethereum provider API
*
* @param {string} origin - Origin of the window requesting full provider access
*/
handleProviderRequest (origin) {
this.store.updateState({ providerRequests: [{ origin }] })
if (this.isApproved(origin)) {
this.approveProviderRequest(origin)
return
}
this.openPopup && this.openPopup()
}
/**
* Called by a tab to determine if a full Ethereum provider API is exposed
*
* @param {string} origin - Origin of the window requesting provider status
*/
async handleProviderStatusRequest (origin) {
const isEnabled = this.isApproved(origin)
this.platform && this.platform.sendMessage({ action: 'answer-status-request', isEnabled }, { active: true })
}
handlePrivacyStatusRequest () {
const privacyMode = this.preferencesController.getFeatureFlags().privacyMode
if (!privacyMode) {
this.platform && this.platform.sendMessage({ action: 'approve-provider-request' }, { active: true })
this.publicConfigStore.emit('update', this.publicConfigStore.getState())
}
}
/**
* 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 = {}
}
/**
* 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) {
const privacyMode = this.preferencesController.getFeatureFlags().privacyMode
return !privacyMode || this.approvedOrigins[origin]
}
}
module.exports = ProviderApprovalController
|