Skip to content

Commit 827769d

Browse files
committed
Merge PR #932 from 'nodech/timeout-valid'
2 parents 85a1ada + d8e8857 commit 827769d

File tree

3 files changed

+99
-10
lines changed

3 files changed

+99
-10
lines changed

lib/wallet/http.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,9 +414,11 @@ class HTTP extends Server {
414414
this.post('/wallet/:id/unlock', async (req, res) => {
415415
const valid = Validator.fromRequest(req);
416416
const passphrase = valid.str('passphrase');
417-
const timeout = valid.u32('timeout');
417+
const timeout = valid.u32('timeout', 60);
418418

419419
enforce(passphrase, 'Passphrase is required.');
420+
// setTimeout maximum is 24.85 days, we round to 24 days.
421+
enforce(timeout <= 2073600, 'Timeout must be less than 24 days.');
420422

421423
await req.wallet.unlock(passphrase, timeout);
422424

lib/wallet/masterkey.js

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,8 @@ class MasterKey extends bio.Struct {
135135
/**
136136
* Decrypt the key and set a timeout to destroy decrypted data.
137137
* @param {Buffer|String} passphrase - Zero this yourself.
138-
* @param {Number} [timeout=60000] timeout in ms.
139-
* @returns {Promise} - Returns {@link HDPrivateKey}.
138+
* @param {Number} [timeout=60] timeout in seconds.
139+
* @returns {Promise<HDPrivateKey>}
140140
*/
141141

142142
async unlock(passphrase, timeout) {
@@ -152,8 +152,8 @@ class MasterKey extends bio.Struct {
152152
* Decrypt the key without a lock.
153153
* @private
154154
* @param {Buffer|String} passphrase - Zero this yourself.
155-
* @param {Number} [timeout=60000] timeout in ms.
156-
* @returns {Promise} - Returns {@link HDPrivateKey}.
155+
* @param {Number} [timeout=60] timeout in seconds.
156+
* @returns {Promise<HDPrivateKey>}
157157
*/
158158

159159
async _unlock(passphrase, timeout) {
@@ -219,7 +219,7 @@ class MasterKey extends bio.Struct {
219219
/**
220220
* Derive an aes key based on params.
221221
* @param {String|Buffer} passwd
222-
* @returns {Promise}
222+
* @returns {Promise<Buffer>}
223223
*/
224224

225225
async derive(passwd) {
@@ -324,7 +324,7 @@ class MasterKey extends bio.Struct {
324324
* Decrypt the key permanently.
325325
* @param {Buffer|String} passphrase - Zero this yourself.
326326
* @param {Boolean} [clean=false]
327-
* @returns {Promise}
327+
* @returns {Promise<Buffer|null>}
328328
*/
329329

330330
async decrypt(passphrase, clean) {
@@ -341,7 +341,7 @@ class MasterKey extends bio.Struct {
341341
* @private
342342
* @param {Buffer|String} passphrase - Zero this yourself.
343343
* @param {Boolean} [clean=false]
344-
* @returns {Promise}
344+
* @returns {Promise<Buffer|null>}
345345
*/
346346

347347
async _decrypt(passphrase, clean) {
@@ -373,7 +373,7 @@ class MasterKey extends bio.Struct {
373373
* Encrypt the key permanently.
374374
* @param {Buffer|String} passphrase - Zero this yourself.
375375
* @param {Boolean} [clean=false]
376-
* @returns {Promise}
376+
* @returns {Promise<Buffer|null>}
377377
*/
378378

379379
async encrypt(passphrase, clean) {
@@ -390,7 +390,7 @@ class MasterKey extends bio.Struct {
390390
* @private
391391
* @param {Buffer|String} passphrase - Zero this yourself.
392392
* @param {Boolean} [clean=false]
393-
* @returns {Promise}
393+
* @returns {Promise<Buffer|null>}
394394
*/
395395

396396
async _encrypt(passphrase, clean) {

test/wallet-http-test.js

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const secp256k1 = require('bcrypto/lib/secp256k1');
1414
const network = Network.get('regtest');
1515
const assert = require('bsert');
1616
const {BufferSet} = require('buffer-map');
17+
const util = require('../lib/utils/util');
1718
const common = require('./util/common');
1819
const Outpoint = require('../lib/primitives/outpoint');
1920
const consensus = require('../lib/protocol/consensus');
@@ -96,6 +97,92 @@ describe('Wallet HTTP', function() {
9697
});
9798
});
9899

100+
describe('Unlock wallet', function() {
101+
const WNAME = 'lockedWallet';
102+
const PASSPHRASE = 'test1234';
103+
let walletClient, wallet;
104+
105+
before(async () => {
106+
await beforeAll();
107+
108+
await wclient.createWallet(WNAME, {
109+
passphrase: PASSPHRASE
110+
});
111+
112+
walletClient = wclient.wallet(WNAME);
113+
wallet = await nodeCtx.wdb.get(WNAME);
114+
115+
await wallet.lock();
116+
});
117+
118+
after(afterAll);
119+
120+
afterEach(async () => {
121+
await walletClient.lock();
122+
});
123+
124+
it('unlock wallet', async () => {
125+
assert.strictEqual(wallet.master.encrypted, true);
126+
await walletClient.unlock(PASSPHRASE, 1);
127+
const until = util.now() + 1;
128+
129+
assert(wallet.master.until <= until);
130+
assert(wallet.master.key);
131+
132+
await sleep(1000);
133+
assert(!wallet.master.key);
134+
});
135+
136+
it('should fail to unlock with wrong passphrase', async () => {
137+
let err;
138+
try {
139+
await walletClient.unlock('wrong', 100);
140+
} catch (e) {
141+
err = e;
142+
}
143+
144+
assert(err);
145+
assert.strictEqual(err.message, 'Could not decrypt.');
146+
});
147+
148+
it('should unlock for an hour', async () => {
149+
// Unlock for an hour
150+
await walletClient.unlock(PASSPHRASE, 3600);
151+
const until = util.now() + 3600;
152+
153+
assert(wallet.master.until <= until);
154+
assert(wallet.master.key);
155+
});
156+
157+
it('should unlock for max duration', async () => {
158+
const MAX = 2073600;
159+
await walletClient.unlock(PASSPHRASE, MAX);
160+
});
161+
162+
it('should fail unlock for invalid durations', async () => {
163+
const MAX = 2073600;
164+
const invalid = [
165+
['text', 'timeout must be a int.'],
166+
[-1, 'timeout must be a uint.'],
167+
[-100, 'timeout must be a uint.'],
168+
[MAX + 1, 'Timeout must be less than 24 days.']
169+
];
170+
171+
for (const [duration, message] of invalid) {
172+
let err;
173+
174+
try {
175+
await walletClient.unlock(PASSPHRASE, duration);
176+
} catch (e) {
177+
err = e;
178+
}
179+
180+
assert(err, `Expected error for duration: ${duration}`);
181+
assert.strictEqual(err.message, message);
182+
}
183+
});
184+
});
185+
99186
describe('Lookahead', function() {
100187
before(beforeAll);
101188
after(afterAll);

0 commit comments

Comments
 (0)