Skip to content

Commit

Permalink
v0.0.7 (#101)
Browse files Browse the repository at this point in the history
* Add input block to new connection requests
* Fix for origin spoofing due to overflowing text not wrapped
* Expand origin filter regex
* Update hot signer instructions
* Some dapps expect lowercase address
* Context isolation bridge (#100)
* Add interceptFileProtocol, disable nodeIntegration
* Improve text overflow
* Update dependencies
* Improve Ledger reliability
* Update interceptFile check for windows (#99)
* Better cross-platform Ledger detection
* Update dependencies
* Standard
  • Loading branch information
floating authored Sep 21, 2018
1 parent 58b64ab commit f5ef328
Show file tree
Hide file tree
Showing 40 changed files with 3,803 additions and 2,325 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ Frame is an OS-level Ethereum interface that lets you use standalone signers, su
"accounts": ["privateKey1", "privateKey2"]
}
```
- Run `npm run alpha` as normal
- Run `npm run dev` (hot signers will only be added in dev mode)

### Build Apps
```bash
Expand Down
42 changes: 17 additions & 25 deletions app/App/Panel/Local/index.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,17 @@
import React from 'react'
import Restore from 'react-restore'
import { ipcRenderer, remote } from 'electron'
import PersistStore from 'electron-store'
import svg from '../../../svg'
import link from '../../../link'

const resetAllSettings = () => {
const persist = new PersistStore()
persist.clear()
remote.app.relaunch()
remote.app.exit(0)
}

const networks = {1: 'Mainnet', 3: 'Ropsten', 4: 'Rinkeby', 42: 'Kovan'}
const networks = { 1: 'Mainnet', 3: 'Ropsten', 4: 'Rinkeby', 42: 'Kovan' }

class Settings extends React.Component {
constructor (props, context) {
super(props, context)
let network = context.store('local.connection.network')
let customTarget = context.store('local.connection.secondary.settings', network, 'options.custom')
this.customMessage = 'Custom Endpoint'
this.state = {localShake: {}, secondaryCustom: customTarget || this.customMessage, resetConfirm: false}
this.state = { localShake: {}, secondaryCustom: customTarget || this.customMessage, resetConfirm: false }
}
appInfo () {
return (
Expand All @@ -28,10 +20,10 @@ class Settings extends React.Component {
<div className='appInfoLine appInfoLineReset'>
{this.state.resetConfirm ? (
<span className='appInfoLineResetConfirm'>
{'Are you sure?'} <span onClick={() => resetAllSettings()}>{'Yes'}</span> <span>{'/'}</span> <span onClick={() => this.setState({resetConfirm: false})}>{'No'}</span>
{'Are you sure?'} <span onClick={() => link.send('tray:resetAllSettings')}>{'Yes'}</span> <span>{'/'}</span> <span onClick={() => this.setState({ resetConfirm: false })}>{'No'}</span>
</span>
) : (
<span onClick={() => this.setState({resetConfirm: true})}>{'Reset All Settings & Data'}</span>
<span onClick={() => this.setState({ resetConfirm: true })}>{'Reset All Settings & Data'}</span>
)}
</div>
<div className='appInfoLine appInfoLineVersion'>{'v' + require('../../../../package.json').version}</div>
Expand All @@ -46,34 +38,34 @@ class Settings extends React.Component {
return false
}
customFocus () {
if (this.state.secondaryCustom === this.customMessage) this.setState({secondaryCustom: ''})
if (this.state.secondaryCustom === this.customMessage) this.setState({ secondaryCustom: '' })
}
customBlur () {
if (this.state.secondaryCustom === '') this.setState({secondaryCustom: this.customMessage})
if (this.state.secondaryCustom === '') this.setState({ secondaryCustom: this.customMessage })
}
inputCustom (e) {
e.preventDefault()
clearTimeout(this.customInputTimeout)
let value = e.target.value
if (value.toLowerCase() === 'i understand the risks, unlock mainnet') {
this.setState({secondaryCustom: ''})
this.setState({ secondaryCustom: '' })
this.store.setSecondaryCustom('')
this.store.enableMainnet()
let target = e.target
setTimeout(() => target.blur(), 0)
return
}
this.setState({secondaryCustom: value})
this.setState({ secondaryCustom: value })
this.customInputTimeout = setTimeout(() => this.store.setSecondaryCustom(this.state.secondaryCustom), 1000)
}
localShake (key) {
let localShake = Object.assign({}, this.state.localShake)
localShake[key] = true
this.setState({localShake})
this.setState({ localShake })
setTimeout(() => {
let localShake = Object.assign({}, this.state.localShake)
localShake[key] = false
this.setState({localShake})
this.setState({ localShake })
}, 1010)
}
status (connection) {
Expand All @@ -92,7 +84,7 @@ class Settings extends React.Component {
quit () {
return (
<div className='quitFrame'>
<div onClick={() => ipcRenderer.send('tray:quit')} className='quitFrameButton'>{'Quit'}</div>
<div onClick={() => link.send('tray:quit')} className='quitFrameButton'>{'Quit'}</div>
</div>
)
}
Expand All @@ -108,7 +100,7 @@ class Settings extends React.Component {
selectNetwork (direction) {
this.store.selectNetwork(direction)
let target = this.store('local.connection.secondary.settings', this.store('local.connection.network'), 'options.custom')
this.setState({secondaryCustom: target || this.customMessage})
this.setState({ secondaryCustom: target || this.customMessage })
}
render () {
let network = this.store('local.connection.network')
Expand All @@ -119,11 +111,11 @@ class Settings extends React.Component {
{this.store('local.enableMainnet') ? (
<div className='connectionTitleSet'>
<div className='connectionTitleSetButton' onClick={() => this.selectNetwork('<-')}>
{svg.octicon('chevron-left', {height: 17})}
{svg.octicon('chevron-left', { height: 17 })}
</div>
<div className='connectionTitleSetText'>{networks[this.store('local.connection.network')] || 'Unknown, ID: ' + this.store('local.connection.network')}</div>
<div className='connectionTitleSetButton' onClick={() => this.selectNetwork('->')}>
{svg.octicon('chevron-right', {height: 17})}
{svg.octicon('chevron-right', { height: 17 })}
</div>
</div>
) : (
Expand Down Expand Up @@ -174,9 +166,9 @@ class Settings extends React.Component {
<div className='connectionOptionDetailsInset'>
{this.status(this.store('local.connection.secondary'))}
<div className='signerOptionSet'>
<div className='signerOptionSetButton' onClick={() => this.store.selectSecondary('<-')}>{svg.octicon('chevron-left', {height: 14})}</div>
<div className='signerOptionSetButton' onClick={() => this.store.selectSecondary('<-')}>{svg.octicon('chevron-left', { height: 14 })}</div>
<div className='signerOptionSetText'>{this.store('local.connection.secondary.settings', network, 'current')}</div>
<div className='signerOptionSetButton' onClick={() => this.store.selectSecondary('<-')}>{svg.octicon('chevron-right', {height: 14})}</div>
<div className='signerOptionSetButton' onClick={() => this.store.selectSecondary('<-')}>{svg.octicon('chevron-right', { height: 14 })}</div>
</div>
</div>
</div>
Expand Down
16 changes: 8 additions & 8 deletions app/App/Panel/Main/Signer/Requests/ProviderRequest/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import svg from '../../../../../../svg'
class ProviderRequest extends React.Component {
constructor (...args) {
super(...args)
this.state = {allowInput: false}
this.state = { allowInput: false }
setTimeout(() => {
this.setState({allowInput: true})
this.setState({ allowInput: true })
}, 2000)
}
render () {
Expand All @@ -23,7 +23,7 @@ class ProviderRequest extends React.Component {
if (origin.length > 28) originClass = 'requestProviderOrigin requestProviderOrigin18'
if (origin.length > 36) originClass = 'requestProviderOrigin requestProviderOrigin12'
return (
<div key={this.props.req.id || this.props.req.handlerId} className={requestClass} style={{top: (this.props.top * 10) + 'px'}}>
<div key={this.props.req.id || this.props.req.handlerId} className={requestClass} style={{ top: (this.props.top * 10) + 'px' }}>
<div className='approveTransaction'>
{notice ? (
<div className='requestNotice'>
Expand All @@ -35,16 +35,16 @@ class ProviderRequest extends React.Component {
</div>
)
} else if (status === 'success') {
return <div className='requestNoticeInner bounceIn'>{svg.octicon('check', {height: 80})}</div>
return <div className='requestNoticeInner bounceIn'>{svg.octicon('check', { height: 80 })}</div>
} else if (status === 'error' || status === 'declined') {
return <div className='requestNoticeInner bounceIn'>{svg.octicon('circle-slash', {height: 80})}</div>
return <div className='requestNoticeInner bounceIn'>{svg.octicon('circle-slash', { height: 80 })}</div>
}
})()}
</div>
) : (
<div className='approveTransactionPayload'>
<div className='approveRequestHeader approveTransactionHeader'>
<div className='approveRequestHeaderIcon'> {svg.octicon('shield', {height: 20})}</div>
<div className='approveRequestHeaderIcon'> {svg.octicon('shield', { height: 20 })}</div>
<div className='approveRequestHeaderLabel'> {'Connection'}</div>
</div>
<div className='requestProvider bounceIn'>
Expand All @@ -55,10 +55,10 @@ class ProviderRequest extends React.Component {
)}
</div>
<div className='requestApprove'>
<div className='requestDecline' onClick={() => this.store.giveAccess(this.props.req, false)}>
<div className='requestDecline' onClick={() => { if (this.state.allowInput) this.store.giveAccess(this.props.req, false) }}>
<div className='requestDeclineButton'>{'Decline'}</div>
</div>
<div className='requestSign' onClick={() => this.store.giveAccess(this.props.req, true)}>
<div className='requestSign' onClick={() => { if (this.state.allowInput) this.store.giveAccess(this.props.req, true) }}>
<div className='requestSignButton'>{'Approve'}</div>
</div>
</div>
Expand Down
33 changes: 17 additions & 16 deletions app/App/Panel/Main/Signer/Requests/TransactionRequest/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,31 @@ import React from 'react'
import Restore from 'react-restore'
import utils from 'web3-utils'
import svg from '../../../../../../svg'
import link from '../../../../../../link'

class TransactionRequest extends React.Component {
constructor (...args) {
super(...args)
this.state = {allowInput: false, dataView: false}
this.state = { allowInput: false, dataView: false }
setTimeout(() => {
this.setState({allowInput: true})
this.setState({ allowInput: true })
}, 2000)
}
copyAddress (e) {
e.preventDefault()
e.target.select()
document.execCommand('Copy')
this.setState({copied: true})
setTimeout(_ => this.setState({copied: false}), 1000)
this.setState({ copied: true })
setTimeout(_ => this.setState({ copied: false }), 1000)
}
approve (reqId, req) {
this.store.events.emit('approveRequest', reqId, req)
link.send('tray:approveRequest', reqId, req)
}
decline (reqId, req) {
this.store.events.emit('declineRequest', reqId, req)
link.send('tray:declineRequest', reqId, req)
}
toggleDataView (id) {
this.setState({dataView: !this.state.dataView})
this.setState({ dataView: !this.state.dataView })
}
hexToDisplayValue (hex) {
return (Math.round(parseFloat(utils.fromWei(hex, 'ether')) * 1000000) / 1000000).toFixed(6)
Expand All @@ -43,7 +44,7 @@ class TransactionRequest extends React.Component {
let value = this.hexToDisplayValue(this.props.req.data.value || '0x')
let fee = this.hexToDisplayValue(utils.numberToHex(parseInt(this.props.req.data.gas, 16) * parseInt(this.props.req.data.gasPrice, 16)))
return (
<div key={this.props.req.id || this.props.req.handlerId} className={requestClass} style={{top: (this.props.top * 10) + 'px'}}>
<div key={this.props.req.id || this.props.req.handlerId} className={requestClass} style={{ top: (this.props.top * 10) + 'px' }}>
<div className='requestOverlay'><div className='requestOverlayInset' /></div>
{this.props.req.type === 'approveTransaction' ? (
<div className='approveTransaction'>
Expand All @@ -54,21 +55,21 @@ class TransactionRequest extends React.Component {
if (status === 'pending') {
return (
<div key={status} className='requestNoticeInner bounceIn'>
<div style={{paddingBottom: 20}}><div className='loader' /></div>
<div style={{ paddingBottom: 20 }}><div className='loader' /></div>
<div className='requestNoticeInnerText'>{'See Signer'}</div>
</div>
)
} else if (status === 'success') {
return (
<div key={status} className='requestNoticeInner bounceIn'>
<div>{svg.octicon('check', {height: 80})}</div>
<div>{svg.octicon('check', { height: 80 })}</div>
<div className='requestNoticeInnerText'>{notice}</div>
</div>
)
} else if (status === 'error' || status === 'declined') {
return (
<div key={status} className='requestNoticeInner bounceIn'>
<div>{svg.octicon('circle-slash', {height: 80})}</div>
<div>{svg.octicon('circle-slash', { height: 80 })}</div>
<div className='requestNoticeInnerText'>{notice}</div>
</div>
)
Expand All @@ -80,7 +81,7 @@ class TransactionRequest extends React.Component {
) : (
<React.Fragment>
<div className='approveRequestHeader approveTransactionHeader'>
<div className='approveRequestHeaderIcon'> {svg.octicon('radio-tower', {height: 22})}</div>
<div className='approveRequestHeaderIcon'> {svg.octicon('radio-tower', { height: 22 })}</div>
<div className='approveRequestHeaderLabel'> {'Transaction'}</div>
</div>
<div className='transactionValue'>
Expand All @@ -100,9 +101,9 @@ class TransactionRequest extends React.Component {
{utils.toAscii(this.props.req.data.data || '0x') ? (
<div className={this.state.dataView ? 'transactionData transactionDataSelected' : 'transactionData'}>
<div className='transactionDataHeader' onClick={() => this.toggleDataView()}>
<div className='transactionDataNotice'>{svg.octicon('issue-opened', {height: 22})}</div>
<div className='transactionDataNotice'>{svg.octicon('issue-opened', { height: 22 })}</div>
<div className='transactionDataLabel'>{'View Data'}</div>
<div className='transactionDataIndicator'>{svg.octicon('chevron-down', {height: 22})}</div>
<div className='transactionDataIndicator'>{svg.octicon('chevron-down', { height: 22 })}</div>
</div>
<div className='transactionDataBody'>
<div className='transactionDataBodyInner'>
Expand All @@ -116,9 +117,9 @@ class TransactionRequest extends React.Component {
{this.props.req.data.to ? (
<div className='transactionTo'>
<div className='transactionToAddress'>
<div className='transactionToAddressLarge'>{this.props.req.data.to.substring(0, 11)} {svg.octicon('kebab-horizontal', {height: 20})} {this.props.req.data.to.substr(this.props.req.data.to.length - 11)}</div>
<div className='transactionToAddressLarge'>{this.props.req.data.to.substring(0, 11)} {svg.octicon('kebab-horizontal', { height: 20 })} {this.props.req.data.to.substr(this.props.req.data.to.length - 11)}</div>
<div className='transactionToAddressFull'>
{this.state.copied ? <span>{'Copied'}{svg.octicon('clippy', {height: 10})}</span> : this.props.req.data.to}
{this.state.copied ? <span>{'Copied'}{svg.octicon('clippy', { height: 10 })}</span> : this.props.req.data.to}
<input onClick={e => this.copyAddress(e)} value={this.props.req.data.to} readOnly />
</div>
</div>
Expand Down
18 changes: 9 additions & 9 deletions app/App/Panel/Main/Signer/Requests/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,33 @@ import React from 'react'
import Restore from 'react-restore'
import { CSSTransitionGroup } from 'react-transition-group'

import rpc from '../../../../../rpc'

import ProviderRequest from './ProviderRequest'
import TransactionRequest from './TransactionRequest'

import link from '../../../../../link'

class Requests extends React.Component {
constructor (...args) {
super(...args)
this.state = {minimized: false}
this.state = { minimized: false }
}
trezorPin (num) {
this.tPin = this.tPin ? this.tPin + num.toString() : num.toString()
if (this.tPin.length === 4) {
rpc('trezorPin', this.props.id, this.tPin, (err, status) => {
link.rpc('trezorPin', this.props.id, this.tPin, (err, status) => {
if (err) throw new Error(err)
})
this.tPin = ''
}
}
minimize () {
this.setState({minimized: true})
this.setState({ minimized: true })
}
setSigner () {
this.setState({minimized: false})
this.setState({ minimized: false })
let current = this.store('signer.current') === this.props.id
if (!current) {
rpc('setSigner', this.props.id, (err, status) => {
link.rpc('setSigner', this.props.id, (err, status) => {
if (err) throw new Error(err)
})
}
Expand All @@ -46,8 +46,8 @@ class Requests extends React.Component {
<div className='requestCount'>{requests.length}</div>
</div>
<div className='requestContainerWrap'>
<CSSTransitionGroup className='requestContainer' style={{height: (350 + (requests.length * 10)) + 'px'}} transitionName='slideUp' transitionEnterTimeout={960} transitionLeaveTimeout={640}>
<div key={'noReq'} style={requests.length !== 0 ? {opacity: 0} : {transitionDelay: '0.32s'}} className='noRequests'>{'No Pending Requests'}</div>
<CSSTransitionGroup className='requestContainer' style={{ height: (350 + (requests.length * 10)) + 'px' }} transitionName='slideUp' transitionEnterTimeout={960} transitionLeaveTimeout={640}>
<div key={'noReq'} style={requests.length !== 0 ? { opacity: 0 } : { transitionDelay: '0.32s' }} className='noRequests'>{'No Pending Requests'}</div>
{requests.sort((a, b) => {
if (a.type === 'approveTransaction' && b.type !== 'approveTransaction') return 1
if (a.type !== 'approveTransaction' && b.type === 'approveTransaction') return -1
Expand Down
4 changes: 4 additions & 0 deletions app/App/Panel/Main/Signer/Requests/style/index.styl
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,10 @@
width 300px
text-align center
transform translateZ(0px)
direction rtl
text-overflow ellipsis
white-space nowrap
overflow hidden

.requestProviderOrigin18
font-size 17
Expand Down
2 changes: 0 additions & 2 deletions app/App/Panel/Main/Signer/Settings/index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import React from 'react'
import Restore from 'react-restore'

// import provider from '../../../../../provider'

class Settings extends React.Component {
clearPermissions () {
return (
Expand Down
7 changes: 7 additions & 0 deletions app/App/Panel/Main/Signer/Settings/style/index.styl
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@

.signerPermissionOrigin
background transparent
width 250px
direction rtl
text-overflow ellipsis
overflow hidden
text-align left
white-space nowrap

.signerPermissionToggle
position relative
Expand All @@ -84,6 +90,7 @@
border-radius 10px
transition standard
transform translateZ(0)
margin-top 2px

.signerPermissionToggleSwitch
position absolute
Expand Down
Loading

0 comments on commit f5ef328

Please sign in to comment.