From 9e84881f369feb5dc8df465818ede71457b8996c Mon Sep 17 00:00:00 2001 From: Vincent Weevers Date: Sat, 14 Sep 2019 13:16:05 +0200 Subject: [PATCH 1/4] Use reachdown package (Level/community#82) --- leveldown.js | 21 +++++---------------- matchdown.js | 8 ++++++++ package.json | 3 ++- 3 files changed, 15 insertions(+), 17 deletions(-) create mode 100644 matchdown.js diff --git a/leveldown.js b/leveldown.js index a07988e..cffa5c2 100644 --- a/leveldown.js +++ b/leveldown.js @@ -1,6 +1,8 @@ var inherits = require('inherits') var abstract = require('abstract-leveldown') var wrap = require('level-option-wrap') +var reachdown = require('reachdown') +var matchdown = require('./matchdown') var rangeOptions = 'start end gt gte lt lte'.split(' ') var defaultClear = abstract.AbstractLevelDOWN.prototype._clear @@ -83,13 +85,13 @@ SubDown.prototype._open = function (opts, cb) { this.db.open(function (err) { if (err) return cb(err) - var subdb = down(self.db, 'subleveldown') + var subdb = reachdown(self.db, 'subleveldown') if (subdb && subdb.prefix) { self.prefix = subdb.prefix + self.prefix - self.leveldown = down(subdb.db) + self.leveldown = reachdown(subdb.db, matchdown, false) } else { - self.leveldown = down(self.db) + self.leveldown = reachdown(self.db, matchdown, false) } if (self._beforeOpen) self._beforeOpen(cb) @@ -179,16 +181,3 @@ SubDown.prototype._iterator = function (opts) { } module.exports = SubDown - -function down (db, type) { - if (typeof db.down === 'function') return db.down(type) - if (type && db.type === type) return db - if (isLooseAbstract(db.db)) return down(db.db, type) - if (isLooseAbstract(db._db)) return down(db._db, type) - return type ? null : db -} - -function isLooseAbstract (db) { - if (!db || typeof db !== 'object') { return false } - return typeof db._batch === 'function' && typeof db._iterator === 'function' -} diff --git a/matchdown.js b/matchdown.js new file mode 100644 index 0000000..089ce39 --- /dev/null +++ b/matchdown.js @@ -0,0 +1,8 @@ +module.exports = function matchdown (db, type) { + // Skip layers that we handle ourselves + if (type === 'levelup') return false + if (type === 'encoding-down') return false + if (type === 'deferred-leveldown') return false + + return true +} diff --git a/package.json b/package.json index 4f18f5d..dffbb46 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,8 @@ "encoding-down": "^6.2.0", "inherits": "^2.0.3", "level-option-wrap": "^1.1.0", - "levelup": "^4.2.0" + "levelup": "^4.2.0", + "reachdown": "^1.0.0" }, "devDependencies": { "after": "^0.8.2", From 4302311f862d52bf8f060fe09524b7b7551e38eb Mon Sep 17 00:00:00 2001 From: Vincent Weevers Date: Sat, 14 Sep 2019 13:35:02 +0200 Subject: [PATCH 2/4] Test subleveldown on encrypt-down --- package.json | 1 + test/index.js | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/package.json b/package.json index dffbb46..1073f55 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "reachdown": "^1.0.0" }, "devDependencies": { + "@adorsys/encrypt-down": "^2.0.1", "after": "^0.8.2", "coveralls": "^3.0.2", "dependency-check": "^3.3.0", diff --git a/test/index.js b/test/index.js index a59feb1..1568c6b 100644 --- a/test/index.js +++ b/test/index.js @@ -7,6 +7,8 @@ var after = require('after') var subdown = require('../leveldown') var subdb = require('..') var levelup = require('levelup') +var reachdown = require('reachdown') +var encrypt = require('@adorsys/encrypt-down') // Test abstract-leveldown compliance suite({ @@ -359,6 +361,37 @@ test('SubDb main function', function (t) { } }) +// The reason we test encrypt-down is that subleveldown should in this case +// peel off the levelup, deferred-leveldown and encoding-down layers from db, +// but stop peeling at the encrypt-down layer. +test('subleveldown on encrypt-down', function (t) { + t.plan(5) + + var jwk = { + kty: 'oct', + alg: 'A256GCM', + use: 'enc', + k: '123456789abcdefghijklmnopqrstuvwxyz12345678' + } + + var db = levelup(encoding(encrypt(memdown(), { jwk }))) + var sub = subdb(db, 'test') + + sub.put('key', 'value', function (err) { + t.error(err, 'no err') + + db.get('!test!key', function (err, value) { + t.ifError(err, 'no levelup get error') + t.is(value, 'value') + }) + + reachdown(db).get('!test!key', { asBuffer: false }, function (err, value) { + t.ifError(err, 'no memdown get error') + t.isNot(value, 'value', 'value is encrypted') + }) + }) +}) + function getKey (entry) { return entry.key } From 5460a412bbb2cfc7516c2b5a7c6971e2054e1dad Mon Sep 17 00:00:00 2001 From: Vincent Weevers Date: Sun, 15 Sep 2019 08:23:01 +0200 Subject: [PATCH 3/4] Test against legacy memdb --- package.json | 1 + test/index.js | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/package.json b/package.json index 1073f55..93f5417 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "hallmark": "^2.0.0", "level-community": "^3.0.0", "level-concat-iterator": "^2.0.1", + "memdb": "^1.3.1", "memdown": "^5.0.0", "nyc": "^14.0.0", "standard": "^14.0.0", diff --git a/test/index.js b/test/index.js index 1568c6b..1f2e04f 100644 --- a/test/index.js +++ b/test/index.js @@ -8,6 +8,7 @@ var subdown = require('../leveldown') var subdb = require('..') var levelup = require('levelup') var reachdown = require('reachdown') +var memdb = require('memdb') var encrypt = require('@adorsys/encrypt-down') // Test abstract-leveldown compliance @@ -392,6 +393,37 @@ test('subleveldown on encrypt-down', function (t) { }) }) +test('legacy memdb (old levelup)', function (t) { + t.plan(7) + + // Should not result in double json encoding + var db = memdb({ valueEncoding: 'json' }) + var sub = subdb(db, 'test', { valueEncoding: 'json' }) + + // Integration with memdb still works because subleveldown waits to reachdown + // until the (old levelup) db is open. Reaching down then correctly lands on + // the memdown db. If subleveldown were to reachdown immediately it'd land on + // the old deferred-leveldown (which when unopened doesn't have a reference to + // the memdown db yet) so we'd be unable to persist anything. + t.is(Object.getPrototypeOf(reachdown(db)).constructor.name, 'DeferredLevelDOWN') + + sub.put('key', { a: 1 }, function (err) { + t.ifError(err, 'no put error') + + sub.get('key', function (err, value) { + t.ifError(err, 'no get error') + t.same(value, { a: 1 }) + }) + + t.is(Object.getPrototypeOf(reachdown(db)).constructor.name, 'MemDOWN') + + reachdown(db).get('!test!key', { asBuffer: false }, function (err, value) { + t.ifError(err, 'no get error') + t.is(value, '{"a":1}') + }) + }) +}) + function getKey (entry) { return entry.key } From e335d85f5b02ff8bd6f63180915b6e6678467390 Mon Sep 17 00:00:00 2001 From: Vincent Weevers Date: Sun, 15 Sep 2019 09:06:55 +0200 Subject: [PATCH 4/4] Replace encrypt-down with mock abstract-leveldown --- package.json | 1 - test/index.js | 41 ++++++++++++++++++++++++++--------------- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/package.json b/package.json index 93f5417..a00a235 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,6 @@ "reachdown": "^1.0.0" }, "devDependencies": { - "@adorsys/encrypt-down": "^2.0.1", "after": "^0.8.2", "coveralls": "^3.0.2", "dependency-check": "^3.3.0", diff --git a/test/index.js b/test/index.js index 1f2e04f..e3503e9 100644 --- a/test/index.js +++ b/test/index.js @@ -9,7 +9,8 @@ var subdb = require('..') var levelup = require('levelup') var reachdown = require('reachdown') var memdb = require('memdb') -var encrypt = require('@adorsys/encrypt-down') +var abstract = require('abstract-leveldown') +var inherits = require('util').inherits // Test abstract-leveldown compliance suite({ @@ -362,20 +363,30 @@ test('SubDb main function', function (t) { } }) -// The reason we test encrypt-down is that subleveldown should in this case -// peel off the levelup, deferred-leveldown and encoding-down layers from db, -// but stop peeling at the encrypt-down layer. -test('subleveldown on encrypt-down', function (t) { - t.plan(5) - - var jwk = { - kty: 'oct', - alg: 'A256GCM', - use: 'enc', - k: '123456789abcdefghijklmnopqrstuvwxyz12345678' +// Test that we peel off the levelup, deferred-leveldown and encoding-down +// layers from db, but stop at any other intermediate layer like encrypt-down, +// cachedown, etc. +test('subleveldown on intermediate layer', function (t) { + t.plan(7) + + function Intermediate (db) { + abstract.AbstractLevelDOWN.call(this) + this.db = db + } + + inherits(Intermediate, abstract.AbstractLevelDOWN) + + Intermediate.prototype._put = function (key, value, options, callback) { + t.pass('got _put call') + this.db._put('mitm' + key, value, options, callback) } - var db = levelup(encoding(encrypt(memdown(), { jwk }))) + Intermediate.prototype._get = function (key, options, callback) { + t.pass('got _get call') + this.db._get('mitm' + key, options, callback) + } + + var db = levelup(encoding(new Intermediate(memdown()))) var sub = subdb(db, 'test') sub.put('key', 'value', function (err) { @@ -386,9 +397,9 @@ test('subleveldown on encrypt-down', function (t) { t.is(value, 'value') }) - reachdown(db).get('!test!key', { asBuffer: false }, function (err, value) { + reachdown(db).get('mitm!test!key', { asBuffer: false }, function (err, value) { t.ifError(err, 'no memdown get error') - t.isNot(value, 'value', 'value is encrypted') + t.is(value, 'value') }) }) })