Skip to content

Commit

Permalink
Allow unencrypted wallets (kyokan#462)
Browse files Browse the repository at this point in the history
While creating new wallet, encrypt unencrypted wallets (like `primary`) if they are not yet encrypted.
  • Loading branch information
rithvikvibhu authored and Falci committed Jun 22, 2022
1 parent 2c31c9b commit f2e4017
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 62 deletions.
1 change: 1 addition & 0 deletions app/background/wallet/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export const clientStub = ipcRendererInjector => makeClient(ipcRendererInjector,
'estimateMaxSend',
'removeWalletById',
'updateAccountDepth',
'encryptWallet',
'backup',
'rescan',
'deepClean',
Expand Down
61 changes: 40 additions & 21 deletions app/background/wallet/service.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ class WalletService {
type: SET_WALLET_NETWORK,
payload: this.networkName,
});
const wallets = await this.listWallets(false, true);
const wallets = await this.listWallets();
dispatchToMainWindow({
type: SET_WALLETS,
payload: createPayloadForSetWallets(wallets),
Expand Down Expand Up @@ -113,7 +113,7 @@ class WalletService {
timeout: 10000,
});

const wallets = await this.listWallets(false, true);
const wallets = await this.listWallets();
dispatchToMainWindow({
type: SET_WALLETS,
payload: createPayloadForSetWallets(wallets),
Expand All @@ -133,7 +133,7 @@ class WalletService {
type: SET_API_KEY,
payload: this.walletApiKey,
});
const wallets = await this.listWallets(false, true);
const wallets = await this.listWallets();
dispatchToMainWindow({
type: SET_WALLETS,
payload: createPayloadForSetWallets(wallets),
Expand Down Expand Up @@ -219,7 +219,7 @@ class WalletService {
timeout: 10000,
});

const wallets = await this.listWallets(false, true);
const wallets = await this.listWallets();
dispatchToMainWindow({
type: SET_WALLETS,
payload: createPayloadForSetWallets(wallets),
Expand Down Expand Up @@ -351,7 +351,7 @@ class WalletService {
await this.node.wdb.remove(wid);
this.setWallet(this.name === wid ? null : this.name);

const wallets = await this.listWallets(false, true);
const wallets = await this.listWallets();

dispatchToMainWindow({
type: SET_WALLETS,
Expand Down Expand Up @@ -380,7 +380,7 @@ class WalletService {
});
}

const wallets = await this.listWallets(false, true);
const wallets = await this.listWallets();
dispatchToMainWindow({
type: SET_WALLETS,
payload: createPayloadForSetWallets(wallets, name),
Expand All @@ -389,6 +389,20 @@ class WalletService {
return res.getJSON();
};

encryptWallet = async (name, passphrase) => {
this.setWallet(name);

const res = await this._executeRPC('encryptwallet', [passphrase]);

const wallets = await this.listWallets();
dispatchToMainWindow({
type: SET_WALLETS,
payload: createPayloadForSetWallets(wallets, name),
});

return res;
};

backup = async (path) => {
if (!path) throw new Error('Path is required.');
return this.node.wdb.backup(path);
Expand Down Expand Up @@ -419,7 +433,7 @@ class WalletService {
};

const res = await this.node.wdb.create({id: name, ...options});
const wallets = await this.listWallets(false, true);
const wallets = await this.listWallets();

dispatchToMainWindow({
type: SET_WALLETS,
Expand Down Expand Up @@ -965,24 +979,18 @@ class WalletService {
};

/**
* List Wallet IDs (exclude unencrypted wallets)
* @return {Promise<[string]>}
* List Wallets
* @return {Promise<[object]>}
*/
listWallets = async (includeUnencrypted = false, returnObjects = false) => {
listWallets = async () => {
const wdb = this.node.wdb;
const wallets = await wdb.getWallets();
const ret = [];

for (const wid of wallets) {
const info = await wdb.get(wid);
const {master: {encrypted}, watchOnly} = info;
if (includeUnencrypted === true || encrypted || watchOnly) {
if (returnObjects) {
ret.push({ wid, encrypted, watchOnly });
} else {
ret.push(wid);
}
}
ret.push({ wid, encrypted, watchOnly });
}

return ret;
Expand Down Expand Up @@ -1453,16 +1461,26 @@ function enforce(value, msg) {

function createPayloadForSetWallets(wallets, addName = null) {
let wids = wallets.map((wallet) => wallet.wid);

// array of objects to an object with wid as key
const walletsDetails = wallets.reduce((obj, wallet) => {
obj[wallet.wid] = wallet;
return obj;
}, {});

// Remove unencrypted wids from state.wallet.wallets,
// but not objects from state.wallet.walletsDetails
wids = wids.filter(
(wid) => walletsDetails[wid].encrypted || walletsDetails[wid].watchOnly
);

if (addName !== null) {
wids = uniq([...wids, addName]);
}

return {
wallets: wids,
walletsDetails: wallets.reduce((obj, wallet) => {
obj[wallet.wid] = wallet;
return obj;
}, {}), // array of objects to a single object with wid as key
walletsDetails,
};
}

Expand Down Expand Up @@ -1504,6 +1522,7 @@ const methods = {
estimateMaxSend: service.estimateMaxSend,
removeWalletById: service.removeWalletById,
updateAccountDepth: service.updateAccountDepth,
encryptWallet: service.encryptWallet,
backup: service.backup,
rescan: service.rescan,
deepClean: service.deepClean,
Expand Down
21 changes: 15 additions & 6 deletions app/pages/Onboarding/CreateNewAccount/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class CreateNewAccount extends Component {
completeInitialization: PropTypes.func.isRequired,
network: PropTypes.string.isRequired,
loc: PropTypes.string,
walletsDetails: PropTypes.object.isRequired,
};

static contextType = I18nContext;
Expand Down Expand Up @@ -134,12 +135,19 @@ class CreateNewAccount extends Component {
}
onNext={async () => {
this.setState({ isLoading: true });
await walletClient.createNewWallet(
this.state.name,
this.state.passphrase,
false, // isLedger
null // xpub (Ledger only)
);
const existingWallet = this.props.walletsDetails[this.state.name];
if (existingWallet) {
// Encrypt existing wallet
await walletClient.encryptWallet(this.state.name, this.state.passphrase);
} else {
// Create new wallet
await walletClient.createNewWallet(
this.state.name,
this.state.passphrase,
false, // isLedger
null // xpub (Ledger only)
);
}
const phrase = await walletClient.revealSeed(this.state.passphrase);
this.setState({
currentStep: COPY_SEEDPHRASE,
Expand Down Expand Up @@ -189,6 +197,7 @@ export default withRouter(
connect(
(state) => ({
network: state.wallet.network,
walletsDetails: state.wallet.walletsDetails,
}),
(dispatch) => ({
completeInitialization: (name, passphrase) =>
Expand Down
10 changes: 10 additions & 0 deletions app/pages/Onboarding/SetName/create.scss
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,16 @@
}
}

&__info {
color: $manatee-gray;
font-size: 0.75rem;
margin: -6px 0.375rem 12px 0.375rem;

&:empty {
margin: 0;
}
}

&__footer {
padding: 1.25rem 1.875rem 1rem 1.875rem;

Expand Down
27 changes: 16 additions & 11 deletions app/pages/Onboarding/SetName/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,20 @@ import c from 'classnames';
import './create.scss';
import Submittable from '../../../components/Submittable';
import WizardHeader from '../../../components/WizardHeader';
import walletClient from "../../../utils/walletClient";
import {I18nContext} from "../../../utils/i18n";

@connect(
(state) => ({
wallets: state.wallet.wallets,
walletsDetails: state.wallet.walletsDetails,
})
)
export default class CreatePassword extends Component {
static propTypes = {
currentStep: PropTypes.number.isRequired,
totalSteps: PropTypes.number.isRequired,
wallets: PropTypes.arrayOf(PropTypes.string).isRequired,
walletsDetails: PropTypes.object.isRequired,
onBack: PropTypes.func.isRequired,
onNext: PropTypes.func.isRequired,
onCancel: PropTypes.func.isRequired,
Expand All @@ -29,6 +30,7 @@ export default class CreatePassword extends Component {
super(props);
this.state = {
name: '',
infoMessage: '',
errorMessage: '',
};
}
Expand All @@ -37,15 +39,12 @@ export default class CreatePassword extends Component {
const {t} = this.context;

if (this.isValidName()) {
const allWallets = await walletClient.listWallets(true);
const {wallets} = this.props;
const {name} = this.state;
let errorMessage = '';

if (wallets.includes(name)) {
errorMessage = t('obSetNameAlreadyExistError', name);
} else if (allWallets.includes(name)) {
errorMessage = t('obSetNameCannotUseError', name);
}

if (errorMessage) {
Expand All @@ -61,31 +60,34 @@ export default class CreatePassword extends Component {

isValidName = () => {
const {errorMessage, name} = this.state;
return !errorMessage && name.match(/^[a-z0-9]+$/) && name !== 'primary';
return !errorMessage && name.match(/^[a-z0-9]+$/);
};

onChange = (name) => async (e) => {
const {wallets} = this.props;
const {wallets, walletsDetails} = this.props;
const inputValue = e.target.value;
const {t} = this.context;

let errorMessage = '';

if (inputValue === 'primary') {
errorMessage = t('obSetNameCannotUseError', inputValue);
} else if (wallets.includes(inputValue)) {
if (wallets.includes(inputValue)) {
errorMessage = t('obSetNameAlreadyExistError', inputValue);
}

let infoMessage = '';
if (walletsDetails[inputValue] && !walletsDetails[inputValue].encrypted) {
infoMessage = t('obSetNameUnencryptedExistError', inputValue);
}

this.setState({
[name]: inputValue,
errorMessage: errorMessage,
infoMessage: infoMessage,
});
};

render() {
const {currentStep, totalSteps, onBack} = this.props;
const {errorMessage} = this.state;
const {errorMessage, infoMessage} = this.state;
const {t} = this.context;

return (
Expand Down Expand Up @@ -120,6 +122,9 @@ export default class CreatePassword extends Component {
<div className="create-password__error">
{errorMessage}
</div>
<div className="create-password__info">
{infoMessage}
</div>
</Submittable>
</div>
<div className="create-password__footer">
Expand Down
Loading

0 comments on commit f2e4017

Please sign in to comment.