Skip to content
This repository has been archived by the owner on Mar 28, 2023. It is now read-only.

Backup wallet seed #690

Merged
merged 5 commits into from
Aug 23, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
22 changes: 19 additions & 3 deletions js/languages/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -409,15 +409,28 @@
"purge": "Purge Shared Files",
"purgeHelper": "Delete cached files you are sharing with others",
"purgeBtn": "Purge Files",
"purgeToolTip": "OpenBazaar shares cached content you have viewed with other users. If you have viewed text or images you don't want to share this button will delete them. This will not affect any files that belong to you.",
"purgeToolTip": "OpenBazaar shares cached content you have viewed with other users. If you have viewed text or images you don't want to share, this button will delete them. This will not affect any files that belong to you.",
"purgeError": "There was an error, your cached files may not have been deleted.",
"purgeComplete": "Your cached files have been deleted.",
"blockData": "Block Data",
"blockDataHelper": "Show data useful for debugging.",
"blockDataBtn": "Show Block Data",
"blockDataError": "There was an error, your block data could not be retrieved.",
"blockDataTitle": "Your Block Data",
"blockDataCopy": "Copy to your Clipboard"
"blockDataCopy": "Copy to your Clipboard",
"backupWalletLbl": "Backup Wallet Seed",
"backupWalletHelper": "This seed will allow you to recover your wallet in case of computer failure.",
"unableToFetchSeedTitle": "There was an error fetching your wallet seed",
"walletSeed": {
"btnShowSeed": "Show Seed",
"introLine": "Your wallet generation seed is:",
"directionLine": "Write the following words on paper and keep them somewhere safe. They must be in this exact order.",
"warningHeading": "Warning:",
"warning1": "Never share your seed. Anyone with this seed can steal your funds.",
"warning2": "Never type it on a website.",
"warning3": "Do not store it electronically.",
"warning4": "Do not lose your seed, or your funds will be permanently lost if your data is erased."
}
},
"transaction": {
"sectionName": "Transactions",
Expand Down Expand Up @@ -690,7 +703,10 @@
"feeBumpOf": "Fee bump of %{address}"
},
"noTransactionsPlaceholder": "You have no transactions.",
"newTransactionsPopin": "%{smart_count} new transaction %{refreshLink} |||| %{smart_count} new transactions %{refreshLink}"
"newTransactionsPopin": "%{smart_count} new transaction %{refreshLink} |||| %{smart_count} new transactions %{refreshLink}",
"backupWalletWarningTitle": "Backup Wallet Recovery Seed",
"recoverySeedLink": "backup your wallet recovery seed",
"backupWalletWarningBody": "Looks like you have a transaction or two. This would be a good time to %{link}."
}
},
"formats": {
Expand Down
1 change: 1 addition & 0 deletions js/models/ServerConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export default class extends BaseModel {
dontShowTorExternalLinkWarning: false,
dismissedDiscoverCallout: false,
dismissedStoreWelcome: false,
backupWalletWarned: false,
};
}

Expand Down
12 changes: 12 additions & 0 deletions js/templates/modals/settings/advanced.html
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,18 @@ <h2 class="h4 clrT"><%= ob.polyT('settings.advancedTab.server.sectionName') %></
</div>
</div>
</div>
<div class="flexRow gutterH js-backupWalletSection">
<div class="col3">
<label>
<%= ob.polyT('settings.advancedTab.server.backupWalletLbl') %>
</label>
<div class="clrT2 txSm">
<%= ob.polyT('settings.advancedTab.server.backupWalletHelper') %>
</div>
</div>
<div class="col9 js-walletSeedContainer">
</div>
</div>
</form>
</div>
</div>
Expand Down
17 changes: 17 additions & 0 deletions js/templates/modals/settings/walletSeed.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<% if (!ob.seed) { %>
<%= ob.processingButton({
className: `btn clrP clrBr clrSh2 js-showSeed ${ob.isFetching ? 'processing' : ''}`,
btnText: ob.polyT('settings.advancedTab.server.walletSeed.btnShowSeed'),
}) %>
<% } else { %>
<p><%= ob.polyT('settings.advancedTab.server.walletSeed.introLine') %></p>
<p class="pad border clrBr clrP"><%= ob.seed %></p>
<p><%= ob.polyT('settings.advancedTab.server.walletSeed.directionLine') %></p>
<p class="txB row"><%= ob.polyT('settings.advancedTab.server.walletSeed.warningHeading') %></p>
<ul class="seedWarnings">
<li><%= ob.polyT('settings.advancedTab.server.walletSeed.warning1') %></li>
<li><%= ob.polyT('settings.advancedTab.server.walletSeed.warning2') %></li>
<li><%= ob.polyT('settings.advancedTab.server.walletSeed.warning3') %></li>
<li><%= ob.polyT('settings.advancedTab.server.walletSeed.warning4') %></li>
</ul>
<% } %>
25 changes: 25 additions & 0 deletions js/views/baseVw.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,31 @@ export default class baseVw extends View {
return data;
}

/**
* Will scroll to the given element. The element must be within this view.
* @param {string|object} selector - A CSS selector or a DOM element or a jQuery object.
*/
scrollTo(selector) {
if (!selector) {
throw new Error('Please provide a selector');
}

if (!(typeof selector === 'string' ||
_.isElement(selector) || selector instanceof $)) {
throw new Error('The selector must be a string, DOM element or jQuery object.');
}

let $el;

if (typeof selector === 'string') {
$el = this.getCachedEl(selector);
} else if (!(selector instanceof $)) {
$el = $(selector);
}

$el[0].scrollIntoView();
}

/**
* If you are creating child views within your view, call this method
* to register them. This will ensure that they will have their remove
Expand Down
40 changes: 38 additions & 2 deletions js/views/modals/Settings/Advanced.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import $ from 'jquery';
import app from '../../../app';
import loadTemplate from '../../../utils/loadTemplate';
import baseVw from '../../baseVw';
import { openSimpleMessage } from '../SimpleMessage';
import Dialog from '../../modals/Dialog';
import { clipboard } from 'electron';
import loadTemplate from '../../../utils/loadTemplate';
import baseVw from '../../baseVw';
import WalletSeed from './WalletSeed';

export default class extends baseVw {
constructor(options = {}) {
Expand Down Expand Up @@ -38,6 +39,31 @@ export default class extends baseVw {
};
}

onClickShowSeed() {
if (this.walletSeedFetch && this.walletSeedFetch.state() === 'pending') {
return this.walletSeedFetch;
}

if (this.walletSeed) this.walletSeed.setState({ isFetching: true });

this.walletSeedFetch = $.get(app.getServerUrl('wallet/mnemonic')).done((data) => {
this.mnemonic = data.mnemonic;
if (this.walletSeed) {
this.walletSeed.setState({ seed: data.mnemonic });
}
}).always(() => {
if (this.walletSeed) this.walletSeed.setState({ isFetching: false });
})
.fail(xhr => {
openSimpleMessage(
app.polyglot.t('settings.advancedTab.server.unableToFetchSeedTitle'),
xhr.responseJSON && xhr.responseJSON.reason || ''
);
});

return this.walletSeedFetch;
}

resetSMTPFields() {
this.settings.set('smtpSettings',
this.settings.get('smtpSettings').defaults(), { validate: true });
Expand Down Expand Up @@ -230,6 +256,16 @@ export default class extends baseVw {
this.$formFields = this.$('select[name], input[name], textarea[name]').
not('[data-persistence-location="local"]');
this.$localFields = this.$('[data-persistence-location="local"]');

if (this.walletSeed) this.walletSeed.remove();
this.walletSeed = this.createChild(WalletSeed, {
initialState: {
seed: this.mnemonic || '',
isFetching: this.walletSeedFetch && this.walletSeedFetch.state() === 'pending',
},
});
this.listenTo(this.walletSeed, 'clickShowSeed', this.onClickShowSeed);
this.getCachedEl('.js-walletSeedContainer').append(this.walletSeed.render().el);
});

return this;
Expand Down
14 changes: 10 additions & 4 deletions js/views/modals/Settings/Settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ export default class extends BaseModal {
const opts = {
removeOnClose: true,
removeOnRoute: false,
initialTab: 'General',
scrollTo: '',
...options,
};

Expand All @@ -30,8 +32,6 @@ export default class extends BaseModal {
Moderation,
};

this.initTab = this.tabViews.hasOwnProperty(opts.initTab) ? opts.initTab : 'General';

this.listenTo(app.router, 'will-route', () => {
this.close(true);
this.remove();
Expand All @@ -55,7 +55,7 @@ export default class extends BaseModal {
this.selectTab(targ);
}

selectTab(targ) {
selectTab(targ, options = {}) {
const tabViewName = targ.data('tab');
let tabView = this.tabViewCache[tabViewName];

Expand All @@ -72,6 +72,10 @@ export default class extends BaseModal {

this.$tabContent.append(tabView.$el);
this.currentTabView = tabView;

if (options.scrollTo && typeof tabView.scrollTo === 'function') {
setTimeout(() => tabView.scrollTo(options.scrollTo));
}
}
}

Expand All @@ -82,7 +86,9 @@ export default class extends BaseModal {

this.$tabContent = this.$('.js-tabContent');

this.selectTab(this.$(`.js-tab[data-tab="${this.initTab}"]`));
this.selectTab(this.$(`.js-tab[data-tab="${this.options.initialTab}"]`), {
scrollTo: this.options.scrollTo,
});
});

return this;
Expand Down
45 changes: 45 additions & 0 deletions js/views/modals/Settings/WalletSeed.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import loadTemplate from '../../../utils/loadTemplate';
import BaseVw from '../../baseVw';

export default class extends BaseVw {
constructor(options = {}) {
const opts = {
initialState: {
seed: '',
isFetching: false,
...options.initialState || {},
},
...options,
};

super(opts);
this.options = opts;
this.listenTo(this.model, 'change', () => this.render());
}

className() {
return 'walletSeed gutterH';
}

events() {
return {
'click .js-showSeed': 'onClickShowSeed',
};
}

onClickShowSeed() {
this.trigger('clickShowSeed');
}

render() {
super.render();

loadTemplate('modals/settings/walletSeed.html', (t) => {
this.$el.html(t({
...this.getState(),
}));
});

return this;
}
}
10 changes: 6 additions & 4 deletions js/views/modals/SimpleMessage.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,13 @@ export function openSimpleMessage(title = '', message = '', options = {}) {
throw new Error('Please provide a title and / or message.');
}

new SimpleMessage({
const dialog = new SimpleMessage({
title,
message,
...options,
})
.render()
.open();
});

dialog.render().open();

return dialog;
}
2 changes: 1 addition & 1 deletion js/views/modals/purchase/Purchase.js
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ export default class extends BaseModal {
}

clickNewAddress() {
launchSettingsModal({ initTab: 'Addresses' });
launchSettingsModal({ initialTab: 'Addresses' });
}

applyCoupon() {
Expand Down
28 changes: 27 additions & 1 deletion js/views/modals/wallet/Transactions.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import $ from 'jquery';
import _ from 'underscore';
import app from '../../../app';
import { isScrolledIntoView } from '../../../utils/dom';
import { getSocket } from '../../../utils/serverConnect';
import { getSocket, getCurrentConnection } from '../../../utils/serverConnect';
import { openSimpleMessage } from '../SimpleMessage';
import { launchSettingsModal } from '../../../utils/modalManager';
import TransactionMd from '../../../models/wallet/Transaction';
import loadTemplate from '../../../utils/loadTemplate';
import baseVw from '../../baseVw';
Expand Down Expand Up @@ -226,6 +228,30 @@ export default class extends baseVw {
if (typeof this.countAtFirstFetch === 'undefined') {
this.countAtFirstFetch = data.count;
}

if (this.collection.length) {
const curConn = getCurrentConnection();

if (curConn && curConn.server && !curConn.server.get('backupWalletWarned')) {
const warning = openSimpleMessage(
app.polyglot.t('wallet.transactions.backupWalletWarningTitle'),
app.polyglot.t('wallet.transactions.backupWalletWarningBody', {
link: '<a class="js-recoverWalletSeed">' +
`${app.polyglot.t('wallet.transactions.recoverySeedLink')}</a>`,
})
);

warning.$el.on('click', '.js-recoverWalletSeed', () => {
launchSettingsModal({
initialTab: 'Advanced',
scrollTo: '.js-backupWalletSection',
});
warning.remove();
});

curConn.server.save({ backupWalletWarned: true });
}
}
});

if (this.transactionFetchState) {
Expand Down
2 changes: 1 addition & 1 deletion js/views/userPage/Store.js
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ export default class extends BaseVw {
}

onClickActivateStore() {
launchSettingsModal({ initTab: 'Store' });
launchSettingsModal({ initialTab: 'Store' });
}

get listingsViewType() {
Expand Down
2 changes: 1 addition & 1 deletion js/views/userPage/UserPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export default class extends baseVw {
}

clickCustomize() {
launchSettingsModal({ initTab: 'Page' });
launchSettingsModal({ initialTab: 'Page' });
}

clickCreateListing() {
Expand Down
8 changes: 8 additions & 0 deletions styles/modules/modals/_settings.scss
Original file line number Diff line number Diff line change
Expand Up @@ -184,4 +184,12 @@
}
}
}

.settingsAdvanced {
.walletSeed {
.seedWarnings {
padding-left: 18px;
}
}
}
}