ssb-keyring
Version:
A persistence store for encryption keys for scuttlebutt. It's purpose is to make easy to answer box2 encryption/ decryption questions.
109 lines (93 loc) • 2.56 kB
JavaScript
const pull = require('pull-stream')
const { read } = require('pull-level')
const { directMessageKey } = require('ssb-private-group-keys')
const bfe = require('ssb-bfe')
const URI = require('ssb-uri2')
const { keySchemes } = require('private-group-spec')
function normalise (id) {
if (id.startsWith('@')) return URI.fromFeedSigil(id)
else return id
}
function getDbId (myId, theirId) {
return normalise(myId) + '<>' + normalise(theirId)
}
const DM_KEYS = 'dm'
module.exports = function DirectMessage (db) {
// This map contains two schemas:
// * `myLeafId<>theirLeafId` => directMessageKey
// * `xRootId<>yLeafId` => xLeafId
let cache = new Map()
const api = {
load (cb) {
readPersisted((err, pairs) => {
if (err) return cb(err)
cache = new Map(pairs)
cb(null)
})
},
add (myId, theirId, myDhKeys, theirDhKeys, cb) {
if (!cache) throw new Error('keyring not ready')
const dbId = getDbId(myId, theirId)
if (cache.has(dbId)) {
if (cb) cb()
return false
}
const x = {
dh: myDhKeys.toBFE(),
id: bfe.encode(myId)
}
const y = {
dh: theirDhKeys.toBFE(),
id: bfe.encode(theirId)
}
const dmKey = directMessageKey(
x.dh.secret, x.dh.public, x.id,
y.dh.public, y.id
)
dmKey.scheme = keySchemes.feed_id_metafeed_dm
cache.set(dbId, dmKey)
db.put([DM_KEYS, dbId], dmKey, cb)
return true
},
addTriangle (xRootId, xLeafId, yLeafId, cb) {
if (!cache) throw new Error('keyring not ready')
const dbId = getDbId(xRootId, yLeafId)
if (cache.has(dbId)) {
if (cb) cb()
return false
}
xLeafId = normalise(xLeafId)
cache.set(dbId, xLeafId)
db.put([DM_KEYS, dbId], xLeafId, cb)
return true
},
get (myId, theirId) {
const dbId = getDbId(myId, theirId)
return cache.get(dbId)
},
triangulate (xRootId, yLeafId) {
const dbId = getDbId(xRootId, yLeafId)
return cache.get(dbId)
},
has (myId, theirId) {
const dbId = getDbId(myId, theirId)
return cache.has(dbId)
}
}
return api
function readPersisted (cb) {
pull(
read(db, {
gt: [DM_KEYS, null],
lt: [DM_KEYS + '~', undefined]
}),
pull.map(({ key, value: info }) => {
return [normalise(key[1]), info]
}),
pull.collect((err, pairs) => {
if (err) return cb(err)
cb(null, pairs)
})
)
}
}