Skip to content
This repository has been archived by the owner on Dec 11, 2019. It is now read-only.

Add geth + Ethereum Wallet integration into Brave #13177

Closed
wants to merge 47 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
e26429a
[WIP] eth wallet support
diracdeltas Feb 17, 2018
99fa452
geth runs when wallet is enabled
jumde Feb 17, 2018
7c46a0b
lint errors
jumde Feb 17, 2018
00cdfdd
move UI into a browserAction
diracdeltas Feb 17, 2018
aebc91e
fixed args for spawn
jumde Feb 17, 2018
566444c
Merge remote-tracking branch 'origin/feature/ethwallet' into feature/…
diracdeltas Feb 17, 2018
9e09bb3
Add tooling for upgrading geth, bundling
evq Feb 17, 2018
166cc16
style fixes
diracdeltas Feb 17, 2018
e94bb0f
exit issue
jumde Feb 17, 2018
84628d1
lint issue
jumde Feb 17, 2018
821fcde
lint issue
jumde Feb 17, 2018
b66ce0e
lint issue
jumde Feb 17, 2018
d54b113
add ETHEREUM_NETWORK env var to launch geth with --testnet
evq Feb 17, 2018
f4edf64
update package-lock.json
diracdeltas Feb 17, 2018
61a91a8
add buttons to browserAction
diracdeltas Feb 17, 2018
9a8da0c
fix about:ethwallet paths with more than one slash
diracdeltas Feb 17, 2018
994baaa
separate geth download from tools/downloadEthwallet
diracdeltas Feb 17, 2018
d3729f4
update meteor-dapp-wallet-prebuilt
diracdeltas Feb 17, 2018
daab0dd
remove ethwallet about: url mapping
diracdeltas Feb 17, 2018
a960129
remove unused fs require
diracdeltas Feb 17, 2018
b4a5bcd
Fix ethereum wallet title display in titleMode
diracdeltas Feb 17, 2018
28386ec
WIP: adding BAT balance display
diracdeltas Feb 18, 2018
d403826
fixup geth downloader, only dl once plus updates, change bin path
evq Feb 18, 2018
3a2c479
missing lint
evq Feb 18, 2018
f1d0d12
add hacky way to load transfer funds URL
diracdeltas Feb 18, 2018
8d77930
resized ethereum logo
jumde Feb 18, 2018
08713f3
resized ethereum logo
jumde Feb 18, 2018
72ea6a7
make transfer funds button slightly less hacky
diracdeltas Feb 18, 2018
0eb9686
fix geth download on macos
diracdeltas Feb 18, 2018
fd18cc7
fix launching geth for packaged builds
evq Feb 18, 2018
4560cbf
store geth data in user data dir
evq Feb 18, 2018
fb55f53
remove BAT balance for now
diracdeltas Feb 18, 2018
352dcca
resolving conflicts
jumde Feb 18, 2018
d4cb3b7
lint
jumde Feb 18, 2018
1fd6668
add bat contract on first load
evq Feb 18, 2018
771b53c
style
jumde Feb 18, 2018
964537a
invert colors
evq Feb 18, 2018
4bedfca
More style fixes, simplify create-wallet IPC
diracdeltas Feb 18, 2018
0c2229a
use new geth binary, WIP read geth pw from stdin
diracdeltas Feb 18, 2018
3c5a6d3
end geth stdin
diracdeltas Feb 18, 2018
851ae67
open ethwallet tab when wallet creation is done
diracdeltas Feb 18, 2018
e56e25f
switch to using ipc directly vs shelling out to get for account creation
evq Feb 18, 2018
f146f5f
pass ipcath explicitly
evq Feb 18, 2018
df3e5fe
UI tweaks
diracdeltas Feb 18, 2018
65820f2
remove unneccessary console.log
diracdeltas Feb 18, 2018
b0e9d2e
update Geth to 1.8.1
evq Feb 21, 2018
bfdab47
update Geth to 1.8.12
evq Jul 11, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ Brave.tar.bz2
app/extensions/gen
app/extensions/brave/gen
app/extensions/torrent/gen
app/extensions/ethwallet
*.pfx
js/constants/buildConfig.js

Expand All @@ -80,3 +81,6 @@ app/extensions/brave/content/scripts/sync.js

# script used for signing for widevine
signature_generator.py

# geth binary download
app/extensions/bin/geth*
5 changes: 4 additions & 1 deletion app/browser/tabs.js
Original file line number Diff line number Diff line change
Expand Up @@ -626,7 +626,7 @@ const api = {
// forget last active trail in window tab
// is detaching from
const oldTab = getTabValue(oldTabId)
const detachedFromWindowId = oldTab.get('windowId')
const detachedFromWindowId = oldTab ? oldTab.get('windowId') : undefined
if (detachedFromWindowId != null) {
activeTabHistory.clearTabFromWindow(detachedFromWindowId, oldTabId)
}
Expand Down Expand Up @@ -804,6 +804,9 @@ const api = {
},

loadURLInActiveTab: (state, windowId, url) => {
if (windowId == null) {
windowId = BrowserWindow.getActiveWindow().id
}
const tabValue = tabState.getActiveTab(state, windowId)
if (tabValue) {
api.loadURLInTab(state, tabValue.get('tabId'), url)
Expand Down
108 changes: 106 additions & 2 deletions app/extensions.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ const fs = require('fs')
const path = require('path')
const l10n = require('../js/l10n')
const {bravifyText} = require('./renderer/lib/extensionsUtil')
const {componentUpdater, session} = require('electron')
const {app, componentUpdater, session, ipcMain} = require('electron')
const {spawn} = require('child_process')
const ledgerState = require('./common/state/ledgerState')
const net = require('net')

// Takes Content Security Policy flags, for example { 'default-src': '*' }
// Returns a CSP string, for example 'default-src: *;'
Expand Down Expand Up @@ -267,6 +270,45 @@ let generateTorrentManifest = () => {
}
}

let generateEthwalletManifest = () => {
let cspDirectives = {
'default-src': '\'self\'',
'style-src': '\'self\' \'unsafe-inline\'',
'connect-src': 'blob: \'self\' http://localhost:* https://min-api.cryptocompare.com https://mini-api.cryptocompare.com',
'img-src': '\'self\' data:',
'script-src': '\'sha256-7B6rTuXUsu9shBeECmDFH4h7RDsfogQ3kIonJnIL40o=\' \'sha256-dHk4wOUZR8kQPod/eH4V2U8eAnISQFg5bqkG8wdrqiA=\' \'self\''
}

if (process.env.NODE_ENV === 'development') {
// allow access to webpack dev server resources
let devServer = 'localhost:' + process.env.npm_package_config_port
cspDirectives['default-src'] += ' http://' + devServer + ' ' + 'ws://' + devServer
}

return {
name: 'Ethereum Wallet',
description: l10n.translation('ethwalletDesc'),
manifest_version: 2,
version: '1.0',
content_security_policy: concatCSP(cspDirectives),
icons: {
128: 'ethereum-128.png',
48: 'ethereum-48.png',
16: 'ethereum-16.png'
},
browser_action: {
default_icon: {
38: 'ethereum-38.png',
19: 'ethereum-19.png'
},
default_popup: 'ethwallet-popup.html',
default_title: 'Ethereum Wallet'
},
incognito: 'split',
key: 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzrdMUtpj4PkN7uoeRC7pXsJyNC65iCWJObISzDQ/mCXerD3ATL54Y8TCkE1mS9O2tiZFY+og4g0GqLjT/M9GJ/Rjlj6cQqIaa9MnQ65H789V6rqPlTQyrd3udIylPJbr5aJ9RvuMcX8BKpT7SKcYvRSwZblKQ/OZ/a/5ylfM+QPyS5ZzooEq921I8eB4JF80aic/3cdU+Xmpyo/jdEe804/MemQ6kqlErXdNaFVU7fQ3lvCzWWcI+I3A1QbKSC2+G1HiToxllxU1gv+rAOsoHYwSkL2ZBTPkvnVBuV5vTS91GF3jGF9TMbw4m3TRNPJZkU32nfJy2JNaa1Ssnws+bQIDAQAB'
}
}

let generateSyncManifest = () => {
let cspDirectives = {
'default-src': '\'self\'',
Expand Down Expand Up @@ -480,7 +522,7 @@ module.exports.init = () => {
}
if (!extensionInfo.isLoaded(extensionId) && !extensionInfo.isLoading(extensionId)) {
extensionInfo.setState(extensionId, extensionStates.LOADING)
if (extensionId === config.braveExtensionId || extensionId === config.torrentExtensionId || extensionId === config.cryptoTokenExtensionId || extensionId === config.syncExtensionId) {
if (extensionId === config.braveExtensionId || extensionId === config.torrentExtensionId || extensionId === config.ethwalletExtensionId || extensionId === config.cryptoTokenExtensionId || extensionId === config.syncExtensionId) {
session.defaultSession.extensions.load(extensionPath, manifest, manifestLocation)
return
}
Expand Down Expand Up @@ -528,6 +570,68 @@ module.exports.init = () => {
extensionInfo.setState(config.syncExtensionId, extensionStates.REGISTERED)
loadExtension(config.syncExtensionId, getExtensionsPath('brave'), generateSyncManifest(), 'unpacked')

if (getSetting(settings.ETHWALLET_ENABLED)) {
var gethArgs = [
'--light',
'--rpc',
'--rpccorsdomain',
'chrome-extension://dakeiobolocmlkdebloniehpglcjkgcp',
'--datadir',
path.join(app.getPath('userData'), 'ethereum'),
'--ipcpath',
path.join(app.getPath('userData'), 'ethereum', 'geth.ipc')
]
if (process.env.ETHEREUM_NETWORK === 'ropsten') {
gethArgs.push('--testnet')
}
var geth
if (process.platform === 'win32') {
geth = spawn(path.join(getExtensionsPath('bin'), 'geth.exe'), gethArgs)
} else {
geth = spawn(path.join(getExtensionsPath('bin'), 'geth'), gethArgs)
}
geth.stdout.on('data', (data) => {
console.warn(data.toString())
})
geth.on('exit', function (code, signal) {
geth.stdout.destroy()
})
geth.on('close', function (code, signal) {
geth.stdout.destroy()
})
extensionInfo.setState(config.ethwalletExtensionId, extensionStates.REGISTERED)
loadExtension(config.ethwalletExtensionId, getExtensionsPath('ethwallet'), generateEthwalletManifest(), 'component')
let popupWebContents = null
ipcMain.on('get-popup-bat-balance', (e) => {
const appState = appStore.getState()
const ledgerInfo = ledgerState.getInfoProps(appState)
popupWebContents = e.sender
e.sender.send('popup-bat-balance',
ledgerInfo.get('balance'),
ledgerInfo.getIn(['addresses', 'BAT']))
})
// Forward index load messages to the popup
ipcMain.on('ethwallet-index-loaded', () => {
if (popupWebContents) {
popupWebContents.send('ethwallet-index-loaded')
}
})
ipcMain.on('create-wallet', (e, pwd) => {
var client = net.createConnection(path.join(app.getPath('userData'), 'ethereum', 'geth.ipc'))

client.on('connect', () => {
client.write(JSON.stringify({ 'method': 'personal_newAccount', 'params': [pwd], 'id': 1, 'jsonrpc': '2.0' }))
})

client.on('data', (data) => {
client.end()
})
})
} else {
extensionInfo.setState(config.ethwalletExtensionId, extensionStates.DISABLED)
extensionActions.extensionDisabled(config.ethwalletExtensionId)
}

if (getSetting(settings.TORRENT_VIEWER_ENABLED)) {
extensionInfo.setState(config.torrentExtensionId, extensionStates.REGISTERED)
loadExtension(config.torrentExtensionId, getExtensionsPath('torrent'), generateTorrentManifest(), 'component')
Expand Down
51 changes: 51 additions & 0 deletions app/extensions/brave/ethwallet-main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
'use strict'

const ipc = window.chrome.ipcRenderer

window.addEventListener('load', () => {
document.body.style.zoom = '120%'
ipc.send('ethwallet-index-loaded')
})

Meteor.startup(function() {
Tracker.autorun(function(){
// If on ropsten, add the testnet BAT token, only once.
if (!localStorage['dapp_hasBAT'] && Session.get('network') === 'ropsten'){
localStorage.setItem('dapp_hasBAT', true)

// wait 5s, to allow the tokens to be loaded from the localstorage first
Meteor.setTimeout(function(){
const batToken = '0x60b10c134088ebd63f80766874e2cade05fc987b'
const tokenId = Helpers.makeId('token', batToken)
Tokens.upsert(tokenId, {$set: {
address: batToken,
name: 'BAT Ropsten',
symbol: 'BATr',
balances: {},
decimals: 18
}})
}, 5000)

// If on main net, add the BAT token, only once.
} else if (!localStorage['dapp_hasBAT'] && Session.get('network') === 'main'){
localStorage.setItem('dapp_hasBAT', true)

// wait 5s, to allow the tokens to be loaded from the localstorage first
Meteor.setTimeout(function(){
const batToken = '0x0D8775F648430679A709E98d2b0Cb6250d2887EF'
const tokenId = Helpers.makeId('token', batToken)
Tokens.upsert(tokenId, {$set: {
address: batToken,
name: 'Basic Attention Token',
symbol: 'BAT',
balances: {},
decimals: 18
}})
}, 5000)
}
})
})


var sheet = document.styleSheets[0]
sheet.insertRule('body { filter: invert(100%) }', 1)
69 changes: 69 additions & 0 deletions app/extensions/brave/ethwallet-popup.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<!DOCTYPE html>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<html>
<head>
<style>
html, body {
background: #222;
}
button {
font-size: 14px;
font-weight: bold;
padding: 10px;
margin: 10px;
margin-left: 8px;
margin-top: 6px;
text-align: center;
width: 250px;
}
input {
font-size: 15px;
margin-left: 8px;
margin-bottom: 8px;
margin-top: 8px;
width: 240px;
}
#label {
font-size: 14px;
font-weight: bold;
margin-left: 8px;
color: white;
}
.hidden {
display: none;
}
.visible {
display: block;
}
</style>
<script src="ethwallet-popup.js" async></script>
</head>
<body>
<div id="appContainer" class="visible">
<div id='batBalance'></div>
<div>
<button id="openEthwallet">Open Ethereum Wallet</button>
</div>
<div>
<button id="transferFunds">Transfer Funds to Brave Wallet...</button>
</div>
<div>
<button id="createWallet">Create Ethereum Wallet...</button>
</div>
</div>
<div id="create" class="hidden">
<div id="label">Enter Wallet Password: </div>
<div>
<input type="password" id="pwd" />
</div>
<div>
<button id="createEthWallet">Create</button>
</div>
<div>
<button id="back">Back</button>
</div>
</div>
</body>
</html>
65 changes: 65 additions & 0 deletions app/extensions/brave/ethwallet-popup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
'use strict'

const ipc = window.chrome.ipcRenderer
let batAddress = null
const indexUrl = `${window.location.origin}/index.html`

ipc.send('get-popup-bat-balance')
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't have a good way to do state updates in extensions with redux so an ipc message is ok, but for sending messages to the browser process we should be using actions which do work in extensions

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the problem is sending the message back to the popup window, which is a browserAction popup and not in the redux appState. is there a way to get the correct webcontents in reducers using event.sender.getId() if the sender isn't a redux tab?

ipc.on('popup-bat-balance', (e, amount, walletAddress) => {
/*
if (amount) {
document.getElementById('batBalance').innerText = `Brave Wallet Balance: ${amount} BAT`
}
*/
batAddress = walletAddress
})

const doAction = (message, args) => {
args.actionType = message
ipc.send('dispatch-action', JSON.stringify([args]))
}

const onBack = () => {
document.getElementById('create').classList.remove('visible')
document.getElementById('create').classList.add('hidden')
document.getElementById('appContainer').classList.remove('hidden')
document.getElementById('appContainer').classList.add('visible')
}

document.getElementById('createEthWallet').onclick = () => {
var pwd = document.getElementById('pwd').value
ipc.send('create-wallet', pwd)
onBack()
}

document.getElementById('createWallet').onclick = () => {
document.getElementById('create').classList.add('visible')
document.getElementById('create').classList.remove('hidden')
document.getElementById('appContainer').classList.add('hidden')
document.getElementById('appContainer').classList.remove('visible')
}

document.getElementById('back').onclick = onBack

document.getElementById('openEthwallet').onclick = () => {
doAction('app-create-tab-requested', {
createProperties: {
url: indexUrl
}
})
}

document.getElementById('transferFunds').onclick = () => {
const sendUrl = `${window.location.origin}/#!send/${batAddress || ''}`
doAction('app-create-tab-requested', {
createProperties: {
url: indexUrl
}
})
// Meteor can't load sendUrl until indexUrl has already been loaded :(
ipc.once('ethwallet-index-loaded', () => {
doAction('app-load-url-in-active-tab-requested', {
url: sendUrl
})
})
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 3 additions & 1 deletion app/extensions/brave/locales/en-US/extensions.properties
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,7 @@ sync= Brave Sync
syncDesc=
torrent= Torrent Viewer
torrentDesc=Uses WebTorrent to display torrents directly in the browser. Supports torrent files and magnet links.
ethwallet=Ethereum Wallet
ethwalletDesc=Local Ethereum Wallet with hardware wallet support, based on https://wallet.ethereum.org.
vimium= Vimium
vimiumDesc=
vimiumDesc=
1 change: 1 addition & 0 deletions app/locale.js
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ var rendererIdentifiers = function () {
'downloadPaused',
'noDownloads',
'torrentDesc',
'ethwalletDesc',
'multiSelectionBookmarks',
// Caption buttons in titlebar (min/max/close - Windows only)
'windowCaptionButtonMinimize',
Expand Down
Loading