aboutsummaryrefslogtreecommitdiffstats
path: root/app/scripts/controllers/provider-approval.js
blob: 918fc8ad085cde0e70d3ca2051e79285bc0ac148 (plain) (blame)
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
115
const ObservableStore = require('obs-store')
const extension = require('extensionizer')

/**
 * 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 }) => {
      if (!action) { return }
      switch (action) {
        case 'init-provider-request':
          this.handleProviderRequest(origin)
          break
        case 'provider-status-request':
          this.handleProviderStatusRequest(origin)
          break
      }
    })
  }

  /**
   * Called when a tab requests access to a full Ethereum provider API
   *
   * @param {string} origin - Origin of the window requesting full provider access
   */
  async handleProviderRequest (origin) {
    this.store.updateState({ providerRequests: [{ origin }] })
    if (await this.isApproved(origin)) {
      this.approveProviderRequest(origin)
      return
    }
    this.openPopup && this.openPopup()
  }

  /**
   * 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 })
  }

  /**
   * 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 = {}
    extension.storage.local.set({ forcedOrigins: [] })
  }

  /**
   * 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) {
    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 })
  }
}

module.exports = ProviderApprovalController