Skip to content
Open
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
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ For mutable content, the hash will be the hash of the public key, `opts.k`.
These options are available:

* `opts.k` - ed25519 public key buffer (32 bytes) (REQUIRED)
* `opts.sign(buf)` - function to generate an ed25519 signature buffer (64 bytes) corresponding to the `opts.k` public key (REQUIRED)
* `opts.sign(buf[, cb])` - function to generate an ed25519 signature buffer (64 bytes) corresponding to the `opts.k` public key (REQUIRED)
* `opts.seq` - optional sequence (integer), must monotonically increase (REQUIRED)
* `opts.cas` - optional previous sequence for compare-and-swap
* `opts.salt` - optional salt buffer to include (<= 64 bytes) when calculating
Expand All @@ -263,8 +263,8 @@ const opts = {
k: keypair.pk,
seq: 0,
v: value,
sign: function (buf) {
return ed.sign(buf, keypair.sk)
sign: function (buf, cb) {
cb(ed.sign(buf, keypair.sk))
}
}

Expand Down
23 changes: 19 additions & 4 deletions client.js
Original file line number Diff line number Diff line change
Expand Up @@ -309,18 +309,33 @@ class DHT extends EventEmitter {
if (opts.salt) message.a.salt = opts.salt
message.a.k = opts.k
message.a.seq = opts.seq
if (typeof opts.sign === 'function') message.a.sig = opts.sign(encodeSigData(message.a))
else if (Buffer.isBuffer(opts.sig)) message.a.sig = opts.sig
if (typeof opts.sign === 'function') {
if (opts.sign.length === 1) {
message.a.sig = opts.sign(encodeSigData(message.a))
this._putSigned(table, key, message, cb)
} else {
opts.sign(encodeSigData(message.a), (sig) => {
message.a.sig = sig
this._putSigned(table, key, message, cb)
})
}
} else if (Buffer.isBuffer(opts.sig)) {
message.a.sig = opts.sig
this._putSigned(table, key, message, cb)
}
} else {
this._values.set(key.toString('hex'), message.a)
this._putSigned(table, key, message, cb)
}

return key
}

_putSigned (table, key, message, cb) {
this._rpc.queryAll(table.closest(key), message, null, (err, n) => {
if (err) return cb(err, key, n)
cb(null, key, n)
})

return key
}

_preput (key, opts, cb) {
Expand Down
44 changes: 44 additions & 0 deletions test/dht_store_mutable.js
Original file line number Diff line number Diff line change
Expand Up @@ -612,3 +612,47 @@ test('valid sequence', t => {
}
})
})

test('asynchronous signing', t => {
t.plan(4)

const keypair = ed.keygen()

const dht = new DHT({ bootstrap: false, verify: ed.verify })
t.once('end', () => {
dht.destroy()
})
common.failOnWarningOrError(t, dht)

dht.listen(() => {
dht.addNode({ host: '127.0.0.1', port: dht.address().port })
dht.once('node', ready)
})

function ready () {
const value = common.fill(500, 'abc')
const opts = {
k: keypair.pk,
sign: (data, cb) => cb(common.sign(keypair)(data)),
seq: 0,
v: value
}

const expectedHash = crypto.createHash('sha1').update(opts.k).digest()

dht.put(opts, (_, hash) => {
t.equal(
hash.toString('hex'),
expectedHash.toString('hex'),
'hash of the public key'
)
dht.get(hash, (err, res) => {
t.ifError(err)
t.equal(res.v.toString('utf8'), opts.v.toString('utf8'),
'got back what we put in'
)
t.equal(res.seq, 0)
})
})
}
})