From ebcfe66638abd1a229c3adad9d8b56dde4ca8831 Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Tue, 16 Aug 2016 20:14:58 -0700 Subject: [PATCH] walletdb: allow utf8 wallet and account names. --- lib/bcoin/keyring.js | 8 ++++---- lib/bcoin/rbt.js | 14 +++++++------- lib/bcoin/utils.js | 12 ++++++------ lib/bcoin/wallet.js | 12 ++++++------ lib/bcoin/walletdb.js | 19 +++++++++++-------- 5 files changed, 34 insertions(+), 31 deletions(-) diff --git a/lib/bcoin/keyring.js b/lib/bcoin/keyring.js index 7321d280..c7008209 100644 --- a/lib/bcoin/keyring.js +++ b/lib/bcoin/keyring.js @@ -132,12 +132,12 @@ KeyRing.prototype.fromOptions = function fromOptions(options) { } if (options.id) { - assert(utils.isAlpha(options.id)); + assert(utils.isName(options.id)); this.id = options.id; } if (options.name) { - assert(utils.isAlpha(options.name)); + assert(utils.isName(options.name)); this.name = options.name; } @@ -782,8 +782,8 @@ KeyRing.prototype.fromJSON = function fromJSON(json) { assert(utils.isNumber(json.n)); assert(typeof json.witness === 'boolean'); assert(!json.wid || utils.isNumber(json.wid)); - assert(!json.id || utils.isAlpha(json.id)); - assert(!json.name || utils.isAlpha(json.name)); + assert(!json.id || utils.isName(json.id)); + assert(!json.name || utils.isName(json.name)); assert(utils.isNumber(json.account)); assert(utils.isNumber(json.change)); assert(utils.isNumber(json.index)); diff --git a/lib/bcoin/rbt.js b/lib/bcoin/rbt.js index cb2100fd..d63709f1 100644 --- a/lib/bcoin/rbt.js +++ b/lib/bcoin/rbt.js @@ -56,7 +56,7 @@ RBT.prototype.search = function search(key) { var cmp; if (typeof key === 'string') - key = new Buffer(key, 'ascii'); + key = new Buffer(key, 'utf8'); while (!current.isNull()) { cmp = this.compare(key, current.key); @@ -83,7 +83,7 @@ RBT.prototype.insert = function insert(key, value) { var parent, cmp, node; if (typeof key === 'string') - key = new Buffer(key, 'ascii'); + key = new Buffer(key, 'utf8'); if (typeof value === 'string') value = new Buffer(value, 'utf8'); @@ -186,7 +186,7 @@ RBT.prototype.remove = function remove(key) { var cmp; if (typeof key === 'string') - key = new Buffer(key, 'ascii'); + key = new Buffer(key, 'utf8'); while (!current.isNull()) { cmp = this.compare(key, current.key); @@ -526,10 +526,10 @@ RBT.prototype.range = function range(gte, lte) { var cmp; if (typeof gte === 'string') - gte = new Buffer(gte, 'ascii'); + gte = new Buffer(gte, 'utf8'); if (typeof lte === 'string') - lte = new Buffer(lte, 'ascii'); + lte = new Buffer(lte, 'utf8'); if (gte) { // Find the node closest to our gte key. @@ -1078,7 +1078,7 @@ Iterator.prototype.seek = function seek(key) { assert(!this.ended, 'Already ended.'); if (typeof key === 'string') - key = new Buffer(key, 'ascii'); + key = new Buffer(key, 'utf8'); this.index = utils.binarySearch(this.snapshot, key, function(a, b) { return self.tree.compare(a.key, b); @@ -1122,7 +1122,7 @@ SENTINEL = new RBTSentinel(); function stringify(value) { if (Buffer.isBuffer(value)) - return value.toString('ascii'); + return value.toString('utf8'); return value; } diff --git a/lib/bcoin/utils.js b/lib/bcoin/utils.js index ef5691ba..90f23938 100644 --- a/lib/bcoin/utils.js +++ b/lib/bcoin/utils.js @@ -2401,18 +2401,18 @@ utils.mkdir = function mkdir(path, dirname) { utils._paths = {}; /** - * Test whether a string is alphanumeric - * enough to use as a leveldb key. + * Test whether a string is eligible + * to be used as a name or ID. * @param {String} key * @returns {Boolean} */ -utils.isAlpha = function isAlpha(key) { +utils.isName = function isName(key) { if (typeof key !== 'string') return false; - return key.length >= 1 - && key.length <= 40 - && /^[\u0020-\u007e]+$/.test(key); + + // Maximum worst case size: 80 bytes + return key.length >= 1 && key.length <= 40; }; /** diff --git a/lib/bcoin/wallet.js b/lib/bcoin/wallet.js index 3178b2d3..13e6e332 100644 --- a/lib/bcoin/wallet.js +++ b/lib/bcoin/wallet.js @@ -114,7 +114,7 @@ Wallet.prototype.fromOptions = function fromOptions(options) { } if (options.id) { - assert(utils.isAlpha(options.id), 'Wallet ID must be alphanumeric.'); + assert(utils.isName(options.id), 'Bad wallet ID.'); id = options.id; } @@ -1933,7 +1933,7 @@ Wallet.prototype.toJSON = function toJSON() { Wallet.prototype.fromJSON = function fromJSON(json) { assert(utils.isNumber(json.wid)); assert(typeof json.initialized === 'boolean'); - assert(utils.isAlpha(json.id), 'Wallet ID must be alphanumeric.'); + assert(utils.isName(json.id), 'Bad wallet ID.'); assert(utils.isNumber(json.accountDepth)); assert(typeof json.token === 'string'); assert(json.token.length === 64); @@ -2095,7 +2095,7 @@ Account.prototype.fromOptions = function fromOptions(options) { assert(options, 'Options are required.'); assert(utils.isNumber(options.wid)); - assert(utils.isAlpha(options.id), 'Wallet ID must be alphanumeric.'); + assert(utils.isName(options.id), 'Bad Wallet ID.'); assert(bcoin.hd.isHD(options.accountKey), 'Account key is required.'); assert(utils.isNumber(options.accountIndex), 'Account index is required.'); @@ -2103,7 +2103,7 @@ Account.prototype.fromOptions = function fromOptions(options) { this.id = options.id; if (options.name != null) { - assert(utils.isAlpha(options.name), 'Account name must be alphanumeric.'); + assert(utils.isName(options.name), 'Bad account name.'); this.name = options.name; } @@ -2659,8 +2659,8 @@ Account.prototype.fromJSON = function fromJSON(json) { assert.equal(json.network, this.network.type); assert(utils.isNumber(json.wid)); - assert(utils.isAlpha(json.id), 'Account name must be alphanumeric.'); - assert(utils.isAlpha(json.name), 'Account name must be alphanumeric.'); + assert(utils.isName(json.id), 'Bad wallet ID.'); + assert(utils.isName(json.name), 'Bad account name.'); assert(typeof json.initialized === 'boolean'); assert(typeof json.type === 'string'); assert(utils.isNumber(json.m)); diff --git a/lib/bcoin/walletdb.js b/lib/bcoin/walletdb.js index 31214dd6..45542830 100644 --- a/lib/bcoin/walletdb.js +++ b/lib/bcoin/walletdb.js @@ -15,6 +15,7 @@ var constants = bcoin.protocol.constants; var BufferReader = require('./reader'); var BufferWriter = require('./writer'); var TXDB = require('./txdb'); +var MAX_POINT = String.fromCharCode(0xdbff, 0xdfff); // U+10FFFF /* * Database Layout: @@ -88,13 +89,14 @@ var layout = { return key.readUInt32BE(1, true); }, l: function(id) { - var key = new Buffer(1 + id.length); + var len = Buffer.byteLength(id, 'utf8'); + var key = new Buffer(1 + len); key[0] = 0x6c; - key.write(id, 1, 'ascii'); + key.write(id, 1, 'utf8'); return key; }, ll: function(key) { - return key.toString('ascii', 1); + return key.toString('utf8', 1); }, a: function a(wid, index) { var key = new Buffer(9); @@ -104,14 +106,15 @@ var layout = { return key; }, i: function i(wid, name) { - var key = new Buffer(5 + name.length); + var len = Buffer.byteLength(name, 'utf8'); + var key = new Buffer(5 + len); key[0] = 0x69; key.writeUInt32BE(wid, 1, true); - key.write(name, 5, 'ascii'); + key.write(name, 5, 'utf8'); return key; }, ii: function ii(key) { - return [key.readUInt32BE(1, true), key.toString('ascii', 5)]; + return [key.readUInt32BE(1, true), key.toString('utf8', 5)]; }, R: new Buffer([0x52]), b: function b(hash) { @@ -759,7 +762,7 @@ WalletDB.prototype.getAccounts = function getAccounts(wid, callback) { this.db.iterate({ gte: layout.i(wid, ''), - lte: layout.i(wid, '\xff'), + lte: layout.i(wid, MAX_POINT), values: true, parse: function(value, key) { var name = layout.ii(key)[1]; @@ -1041,7 +1044,7 @@ WalletDB.prototype.getAddresses = function getAddresses(wid, callback) { WalletDB.prototype.getWallets = function getWallets(callback) { this.db.iterate({ gte: layout.l(''), - lte: layout.l('\xff'), + lte: layout.l(MAX_POINT), transform: function(key) { return layout.ll(key); }