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

Commit

Permalink
Merge pull request #4396 from brave/ledger-redesign
Browse files Browse the repository at this point in the history
ledger backup and recovery
  • Loading branch information
bridiver authored Oct 11, 2016
2 parents c1fffde + b0ffd72 commit 43c0100
Show file tree
Hide file tree
Showing 24 changed files with 626 additions and 16 deletions.
106 changes: 106 additions & 0 deletions app/browser/tabs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
const {app, BrowserWindow, session, webContents} = require('electron')
const extensions = process.atomBinding('extension')
const { getIndexHTML } = require('../../js/lib/appUrlUtil')

let currentWebContents = {}
let activeTab = null

const cleanupWebContents = (tabId) => {
delete currentWebContents[tabId]
}

const tabs = {
init: () => {
app.on('web-contents-created', function (event, tab) {
// TODO(bridiver) - also exclude extension action windows??
if (extensions.isBackgroundPage(tab) || tab.getURL() === getIndexHTML()) {
return
}
let tabId = tab.getId()
tab.on('destroyed', cleanupWebContents.bind(null, tabId))
tab.on('crashed', cleanupWebContents.bind(null, tabId))
tab.on('close', cleanupWebContents.bind(null, tabId))
tab.on('set-active', function (evt, active) {
if (active) {
activeTab = tab
}
})
currentWebContents[tabId] = tab
})
},

getWebContents: (tabId) => {
return currentWebContents[tabId]
},

create: (createProperties) => {
return new Promise((resolve, reject) => {
// TODO(bridiver) - make this available from electron
var payload = {}
process.emit('ELECTRON_GUEST_VIEW_MANAGER_NEXT_INSTANCE_ID', payload)
var guestInstanceId = payload.returnValue

let win = BrowserWindow.getFocusedWindow()
let windowId = createProperties.windowId
if (windowId && windowId !== -2) {
win = BrowserWindow.fromId(windowId) || win
}
if (!win) {
reject('Could not find a window for new tab')
return
}
let opener = null
let newSession = session.defaultSession
let openerTabId = createProperties.openerTabId
if (openerTabId) {
opener = tabs.getWebContents(openerTabId)
if (!opener) {
reject('Opener does not exist')
return
}
// only use the opener if it is in the same window
if (opener.webContents.hostWebContents !== win.webContents) {
reject('Opener must be in the same window as new tab')
return
}
}

opener = opener || activeTab
if (opener) {
newSession = opener.session
} else {
reject('Could not find an opener for new tab')
return
}

let webPreferences = {
isGuest: true,
embedder: win.webContents,
session: newSession,
guestInstanceId,
delayedLoadUrl: createProperties.url || 'about:newtab'
}
webPreferences = Object.assign({}, opener.getWebPreferences(), webPreferences)
let guest = webContents.create(webPreferences)
process.emit('ELECTRON_GUEST_VIEW_MANAGER_REGISTER_GUEST', { sender: opener }, guest, guestInstanceId)

guest.once('did-finish-load', () => {
resolve(guest)
})
let active = createProperties.active !== false
if (!active) {
active = createProperties.selected !== false
}
let disposition = active ? 'foreground-tab' : 'background-tab'

process.emit('ELECTRON_GUEST_VIEW_MANAGER_TAB_OPEN',
{ sender: opener }, // event
'about:blank',
'',
disposition,
{ webPreferences: guest.getWebPreferences() })
})
}
}

module.exports = tabs
2 changes: 1 addition & 1 deletion app/extensions/brave/locales/en-US/app.properties
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ flashInstalled=Flash is already installed and can be enabled in Preferences > Se
goToPrefs=Open Preferences
goToAdobe=Reinstall Flash
allowFlashPlayer=Allow {{origin}} to run Flash Player?

ledgerBackupText=Your ledger keys are {{paymentId}} and {{passphrase}}
error=Error
caseSensitivity=Match case
nameField=Title:
Expand Down
24 changes: 23 additions & 1 deletion app/extensions/brave/locales/en-US/preferences.properties
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,12 @@ bitcoinVisitAccount=Transfer BTC
bitcoinBalance=Please transfer: 
bitcoinWalletNotAvailable=Wallet information not available. :(
usd=$
cancel=Cancel
done=Done
off=off
on=on
notifications=notifications
ok=Ok
notifications=Show payment notifications
moneyAdd=Use your debit/credit card
moneyAddSubTitle=No Bitcoin needed!
outsideUSAPayment=Need to buy Bitcoin outside of the USA?
Expand All @@ -71,6 +73,11 @@ add=Fund with debit/credit
transferTime=Transfer may take up to 40 minutes
addFundsTitle=Add funds…
addFunds=Three ways to add funds to your Brave Wallet
copy=Copy
firstKey=Key 1
secondKey=Key 2
firstRecoveryKey=Recovery Key 1
secondRecoveryKey=Recovery Key 2
copyToClipboard=Copy to clipboard
smartphoneTitle=Use your smartphone app to transfer Bitcoin
displayQRCode=Display QR code
Expand Down Expand Up @@ -110,6 +117,21 @@ offerSearchSuggestions=Autocomplete search term as you type
doNotTrackTitle=Do Not Track
doNotTrack=Send a 'Do Not Track' header with browsing requests (requires browser restart)
blockCanvasFingerprinting=Fingerprinting Protection (may break some websites)
advancedSettings=Advanced Settings...
advancedSettingsTitle=Advanced Settings for Brave Payments
ledgerRecoveryTitle=Recover your Brave wallet
ledgerRecoverySubtitle=Enter your recovery keys below
ledgerRecoveryContent=The balance of the recovered wallet will be transferred to your new Brave wallet. The old wallet will still exist as an empty wallet.
ledgerBackupTitle=Backup your Brave wallet
ledgerBackupContent=Below, you will find the anonymized recovery keys that are required if you ever lose access to this computer.
minimumPageTimeSetting=Minimum page time before logging a visit
minimumVisitsSetting=Minimum visits for publisher relevancy
backupLedger=Backup your wallet
balanceRecovered={{balance}} BTC was recovered and transferred to your Brave wallet.
recoverLedger=Recover your wallet
recover=Recover
printKeys=Print keys
saveRecoveryFile=Save recovery file...
advancedPrivacySettings=Advanced Privacy Settings:
braveryDefaults=Bravery Defaults
blockAttackSites=Block reported attack sites (not available yet)
Expand Down
2 changes: 2 additions & 0 deletions app/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ const contentSettings = require('../js/state/contentSettings')
const privacy = require('../js/state/privacy')
const basicAuth = require('./browser/basicAuth')
const async = require('async')
const tabs = require('./browser/tabs')

// temporary fix for #4517, #4518 and #4472
app.commandLine.appendSwitch('enable-use-zoom-for-dsf', 'false')
Expand Down Expand Up @@ -415,6 +416,7 @@ app.on('ready', () => {
Menu.init(initialState, null)
return loadedPerWindowState
}).then((loadedPerWindowState) => {
tabs.init()
basicAuth.init()
contentSettings.init()
privacy.init()
Expand Down
86 changes: 84 additions & 2 deletions app/ledger.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ const appStore = require('../js/stores/appStore')
const eventStore = require('../js/stores/eventStore')
const rulesolver = require('./extensions/brave/content/scripts/pageInformation')
const ledgerUtil = require('./common/lib/ledgerUtil')
const Tabs = require('./browser/tabs')
const {fileUrl} = require('../js/lib/appUrlUtil')

// TBD: remove these post beta [MTR]
const logPath = 'ledger-log.json'
Expand Down Expand Up @@ -133,9 +135,25 @@ const doAction = (action) => {
case settings.PAYMENTS_ENABLED:
initialize(action.value)
break

case settings.PAYMENTS_CONTRIBUTION_AMOUNT:
setPaymentInfo(action.value)
break

case settings.MINIMUM_VISIT_TIME:
if (action.value <= 0) break

synopsis.options.minDuration = action.value
updatePublisherInfo()
break

case settings.MINIMUM_VISTS:
if (action.value <= 0) break

synopsis.options.minPublisherVisits = action.value
updatePublisherInfo()
break

default:
break
}
Expand Down Expand Up @@ -215,6 +233,51 @@ var boot = () => {
})
}

/*
* Print or Save Recovery Keys
*/

var backupKeys = (appState, action) => {
const paymentId = appState.getIn(['ledgerInfo', 'paymentId'])
const passphrase = appState.getIn(['ledgerInfo', 'passphrase'])
const message = locale.translation('ledgerBackupText', {paymentId, passphrase})
const filePath = path.join(app.getPath('userData'), '/brave_wallet_recovery.txt')

fs.writeFile(filePath, message, (err) => {
if (err) {
console.log(err)
} else {
Tabs.create({url: fileUrl(filePath)}).then((webContents) => {
if (action.backupAction === 'print') {
webContents.print({silent: false, printBackground: false})
} else {
webContents.downloadURL(fileUrl(filePath))
}
}).catch((err) => {
console.error(err)
})
}
})

return appState
}

/*
* Recover Ledger Keys
*/

var recoverKeys = (appState, action) => {
client.recoverWallet(action.firstRecoveryKey, action.secondRecoveryKey, (err, body) => {
if (err) {
setImmediate(() => appActions.ledgerRecoveryFailed())
} else {
setImmediate(() => appActions.ledgerRecoverySucceeded())
}
})

return appState
}

/*
* IPC entry point
*/
Expand Down Expand Up @@ -571,6 +634,8 @@ var enable = (paymentsEnabled) => {
*/

var publisherInfo = {
options: undefined,

synopsis: undefined,

_internal: {
Expand Down Expand Up @@ -601,13 +666,15 @@ var updatePublisherInfo = () => {
syncWriter(pathName(synopsisPath), synopsis, () => {})
publisherInfo.synopsis = synopsisNormalizer()

publisherInfo.synopsisOptions = synopsis.options

if (publisherInfo._internal.debugP) {
data = []
publisherInfo.synopsis.forEach((entry) => {
data.push(underscore.extend(underscore.omit(entry, [ 'faviconURL' ]), { faviconURL: entry.faviconURL && '...' }))
})

console.log('\nupdatePublisherInfo: ' + JSON.stringify(data, null, 2))
console.log('\nupdatePublisherInfo: ' + JSON.stringify({ options: publisherInfo.synopsisOptions, synopsis: data }, null, 2))
}

appActions.updatePublisherInfo(underscore.omit(publisherInfo, [ '_internal' ]))
Expand Down Expand Up @@ -871,6 +938,14 @@ var ledgerInfo = {
buyURL: undefined,
bravery: undefined,

// wallet credentials
paymentId: undefined,
passphrase: undefined,

// advanced ledger settings
minDuration: undefined,
minPublisherVisits: undefined,

hasBitcoinHandler: false,

// geoIP/exchange information
Expand Down Expand Up @@ -1109,6 +1184,12 @@ var getStateInfo = (state) => {
var info = state.paymentInfo
var then = underscore.now() - msecs.year

ledgerInfo.paymentId = state.properties.wallet.paymentId
ledgerInfo.passphrase = state.properties.wallet.keychains.passphrase

ledgerInfo.minDuration = synopsis.options.minDuration
ledgerInfo.minPublisherVisits = synopsis.options.minPublisherVisits

ledgerInfo.created = !!state.properties.wallet
ledgerInfo.creating = !ledgerInfo.created

Expand Down Expand Up @@ -1230,7 +1311,6 @@ var getPaymentInfo = () => {

info = underscore.extend(info, underscore.pick(body, [ 'buyURL', 'buyURLExpires', 'balance', 'unconfirmed', 'satoshis' ]))
info.address = client.getWalletAddress()
info.passphrase = client.getWalletPassphrase()
if ((amount) && (currency)) {
info = underscore.extend(info, { amount: amount, currency: currency })
if ((body.rates) && (body.rates[currency])) {
Expand Down Expand Up @@ -1452,6 +1532,8 @@ const showNotificationPaymentDone = (transactionContributionFiat) => {

module.exports = {
init: init,
recoverKeys: recoverKeys,
backupKeys: backupKeys,
quit: quit,
boot: boot
}
9 changes: 8 additions & 1 deletion app/locale.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ var rendererIdentifiers = function () {
'deleteHistoryEntry',
'deleteHistoryEntries',
'deleteLedgerEntry',
'ledgerBackupText',
'editFolder',
'editBookmark',
'unmuteTabs',
Expand Down Expand Up @@ -233,13 +234,19 @@ var ctx = null
var translations = {}
var lang = 'en-US'

// todo: FSI/PDI stripping can probably be replaced once
// https://github.com/l20n/l20n.js/commit/2fea50bf43c43a8e930a519a37f0f64f3626e885
// is released
const FSI = '\u2068'
const PDI = '\u2069'

// Return a translate token from cache or a placeholder
// indicating that no translation is available
exports.translation = function (token, replacements = {}) {
if (translations[token]) {
let returnVal = translations[token]
for (var key in replacements) {
returnVal = returnVal.replace(new RegExp('{{\\s*' + key + '\\s*}}'), replacements[key])
returnVal = returnVal.replace(new RegExp(FSI + '{{\\s*' + key + '\\s*}}' + PDI), replacements[key])
}
return returnVal
} else {
Expand Down
4 changes: 4 additions & 0 deletions app/sessionStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,10 @@ module.exports.cleanAppData = (data, isShutdown) => {
data.temporarySiteSettings = {}
// Delete Flash state since this is checked on startup
delete data.flashInitialized
// Delete Recovery status on shut down
try {
delete data.ui.about.preferences.recoverySucceeded
} catch (e) {}
// We used to store a huge list of IDs but we didn't use them.
// Get rid of them here.
delete data.windows
Expand Down
12 changes: 12 additions & 0 deletions docs/appActions.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,18 @@ Dispatches a message to clear all completed downloads



### ledgerRecoverySucceeded()

Dispatches a message to clear all completed downloads



### ledgerRecoveryFailed()

Dispatches a message to clear all completed downloads



### setDefaultWindowSize(size)

Sets the default window size
Expand Down
Loading

0 comments on commit 43c0100

Please sign in to comment.