parent
2d4ff1dd82
commit
c76c9ca2c8
@ -0,0 +1,84 @@ |
||||
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, 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 }) => { |
||||
action && action === 'init-provider-request' && this.handleProviderRequest(origin) |
||||
}) |
||||
} |
||||
|
||||
/** |
||||
* 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.approvedOrigins[origin]) { |
||||
this.approveProviderRequest(origin) |
||||
return |
||||
} |
||||
this.openPopup && this.openPopup() |
||||
} |
||||
|
||||
/** |
||||
* 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) { |
||||
return this.approvedOrigins[origin] |
||||
} |
||||
} |
||||
|
||||
module.exports = ProviderApprovalController |
@ -0,0 +1,64 @@ |
||||
import PropTypes from 'prop-types' |
||||
import React, { Component } from 'react' |
||||
import { approveProviderRequest, rejectProviderRequest } from '../../ui/app/actions' |
||||
import { connect } from 'react-redux' |
||||
class ProviderApproval extends Component { |
||||
render () { |
||||
const { approveProviderRequest, origin, rejectProviderRequest } = this.props |
||||
return ( |
||||
<div className="flex-column flex-grow"> |
||||
<style dangerouslySetInnerHTML={{__html: ` |
||||
.provider_approval_actions { |
||||
display: flex; |
||||
justify-content: flex-end; |
||||
margin: 14px 25px; |
||||
} |
||||
.provider_approval_actions button { |
||||
margin-left: 10px; |
||||
text-transform: uppercase; |
||||
} |
||||
.provider_approval_content { |
||||
padding: 0 25px; |
||||
} |
||||
.provider_approval_origin { |
||||
font-weight: bold; |
||||
margin: 14px 0; |
||||
} |
||||
`}} />
|
||||
<div className="section-title flex-row flex-center"> |
||||
<i |
||||
className="fa fa-arrow-left fa-lg cursor-pointer" |
||||
onClick={() => { rejectProviderRequest(origin) }} /> |
||||
<h2 className="page-subtitle">Web3 API Request</h2> |
||||
</div> |
||||
<div className="provider_approval_content"> |
||||
{"The domain listed below is requesting access to the Ethereum blockchain and to view your current account. Always double check that you're on the correct site before approving access."} |
||||
<div className="provider_approval_origin">{origin}</div> |
||||
</div> |
||||
<div className="provider_approval_actions"> |
||||
<button |
||||
className="btn-green" |
||||
onClick={() => { approveProviderRequest(origin) }}>APPROVE</button> |
||||
<button |
||||
className="cancel btn-red" |
||||
onClick={() => { rejectProviderRequest(origin) }}>REJECT</button> |
||||
</div> |
||||
</div> |
||||
) |
||||
} |
||||
} |
||||
|
||||
ProviderApproval.propTypes = { |
||||
approveProviderRequest: PropTypes.func, |
||||
origin: PropTypes.string, |
||||
rejectProviderRequest: PropTypes.func, |
||||
} |
||||
|
||||
function mapDispatchToProps (dispatch) { |
||||
return { |
||||
approveProviderRequest: origin => dispatch(approveProviderRequest(origin)), |
||||
rejectProviderRequest: origin => dispatch(rejectProviderRequest(origin)), |
||||
} |
||||
} |
||||
|
||||
module.exports = connect(null, mapDispatchToProps)(ProviderApproval) |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,39 @@ |
||||
import React, { PureComponent } from 'react' |
||||
import PropTypes from 'prop-types' |
||||
import Modal, { ModalContent } from '../../modal' |
||||
|
||||
export default class ClearApprovedOrigins extends PureComponent { |
||||
static propTypes = { |
||||
hideModal: PropTypes.func.isRequired, |
||||
clearApprovedOrigins: PropTypes.func.isRequired, |
||||
} |
||||
|
||||
static contextTypes = { |
||||
t: PropTypes.func, |
||||
} |
||||
|
||||
handleClear = () => { |
||||
const { clearApprovedOrigins, hideModal } = this.props |
||||
clearApprovedOrigins() |
||||
hideModal() |
||||
} |
||||
|
||||
render () { |
||||
const { t } = this.context |
||||
|
||||
return ( |
||||
<Modal |
||||
onSubmit={this.handleClear} |
||||
onCancel={() => this.props.hideModal()} |
||||
submitText={t('ok')} |
||||
cancelText={t('nevermind')} |
||||
submitType="secondary" |
||||
> |
||||
<ModalContent |
||||
title={t('clearApprovalData')} |
||||
description={t('confirmClear')} |
||||
/> |
||||
</Modal> |
||||
) |
||||
} |
||||
} |
@ -0,0 +1,16 @@ |
||||
import { connect } from 'react-redux' |
||||
import { compose } from 'recompose' |
||||
import withModalProps from '../../../higher-order-components/with-modal-props' |
||||
import ClearApprovedOriginsComponent from './clear-approved-origins.component' |
||||
import { clearApprovedOrigins } from '../../../actions' |
||||
|
||||
const mapDispatchToProps = dispatch => { |
||||
return { |
||||
clearApprovedOrigins: () => dispatch(clearApprovedOrigins()), |
||||
} |
||||
} |
||||
|
||||
export default compose( |
||||
withModalProps, |
||||
connect(null, mapDispatchToProps) |
||||
)(ClearApprovedOriginsComponent) |
@ -0,0 +1 @@ |
||||
export { default } from './clear-approved-origins.container' |
@ -0,0 +1 @@ |
||||
export { default } from './provider-approval.container' |
@ -0,0 +1,35 @@ |
||||
import PageContainerContent from '../../page-container' |
||||
import PropTypes from 'prop-types' |
||||
import React, { Component } from 'react' |
||||
|
||||
export default class ProviderApproval extends Component { |
||||
static propTypes = { |
||||
approveProviderRequest: PropTypes.func, |
||||
origin: PropTypes.string, |
||||
rejectProviderRequest: PropTypes.func, |
||||
}; |
||||
|
||||
static contextTypes = { |
||||
t: PropTypes.func, |
||||
}; |
||||
|
||||
render () { |
||||
const { approveProviderRequest, origin, rejectProviderRequest } = this.props |
||||
return ( |
||||
<PageContainerContent |
||||
title={this.context.t('providerAPIRequest')} |
||||
subtitle={this.context.t('reviewProviderRequest')} |
||||
contentComponent={( |
||||
<div className="provider_approval_content"> |
||||
{this.context.t('providerRequestInfo')} |
||||
<div className="provider_approval_origin">{origin}</div> |
||||
</div> |
||||
)} |
||||
submitText={this.context.t('approve')} |
||||
cancelText={this.context.t('reject')} |
||||
onSubmit={() => { approveProviderRequest(origin) }} |
||||
onCancel={() => { rejectProviderRequest(origin) }} |
||||
onClose={() => { rejectProviderRequest(origin) }} /> |
||||
) |
||||
} |
||||
} |
@ -0,0 +1,12 @@ |
||||
import { connect } from 'react-redux' |
||||
import ProviderApproval from './provider-approval.component' |
||||
import { approveProviderRequest, rejectProviderRequest } from '../../../actions' |
||||
|
||||
function mapDispatchToProps (dispatch) { |
||||
return { |
||||
approveProviderRequest: origin => dispatch(approveProviderRequest(origin)), |
||||
rejectProviderRequest: origin => dispatch(rejectProviderRequest(origin)), |
||||
} |
||||
} |
||||
|
||||
export default connect(null, mapDispatchToProps)(ProviderApproval) |
@ -1 +1,3 @@ |
||||
@import './reveal-seed.scss'; |
||||
|
||||
@import './provider-approval.scss'; |
||||
|
@ -0,0 +1,11 @@ |
||||
.provider_approval_content { |
||||
height: auto; |
||||
overflow: auto; |
||||
padding: 16px; |
||||
} |
||||
|
||||
.provider_approval_origin { |
||||
font-weight: 999; |
||||
margin-top: 16px; |
||||
word-wrap: break-word; |
||||
} |
Loading…
Reference in new issue