ssb-keyring
Version:
A persistence store for encryption keys for scuttlebutt. It's purpose is to make easy to answer box2 encryption/ decryption questions.
75 lines (65 loc) • 2.05 kB
JavaScript
const pull = require('pull-stream')
const { read } = require('pull-level')
const { toBuffer, isPOBoxId } = require('../util')
const POBOX = 'pobox'
module.exports = function POBox (db, dm) {
let cache // Map: groupId => group.info
const api = {
load (cb) {
readPersisted((err, map) => {
if (err) return cb(err)
cache = map
cb(null)
})
},
add (poBoxId, info, cb) {
if (!cache) throw new Error('keyring not ready')
if (cache.has(poBoxId)) {
if (cb) cb()
return false
}
if (!isPOBoxId(poBoxId)) return cb(new Error(`expected a poBoxId, got ${poBoxId}`))
if (!info.key) return cb(new Error('expected info.key'))
// TODO <<< store public/secret keys in BFE format, along with ID in BFE format ???
try {
// 32 bytes, where 32 === sodium-universal's crypto_scalarmult_SCALARBYTES
info.key = toBuffer(info.key, 32)
} catch (e) { return cb(e) }
cache.set(poBoxId, info)
db.put([POBOX, poBoxId, Date.now()], info, cb)
return true
// TODO store entity poBox is associated with too?
// - groupId (so only reindex the group lobby feed?
// - fusionId
},
has (poboxId) {
if (!cache) throw new Error('keyring not ready')
return cache.has(poboxId)
},
get (poboxId) {
if (!cache) throw new Error('keyring not ready')
return cache.get(poboxId)
},
list () {
if (!cache) throw new Error('keyring not ready')
return Array.from(cache.keys())
}
}
return api
function readPersisted (cb) {
pull(
read(db, {
lt: [POBOX + '~', undefined, undefined], // "group~" is just above "group" in charwise sort
gt: [POBOX, null, null]
}),
pull.map(({ key, value: info }) => {
const [_, poBoxId, createdAt] = key // eslint-disable-line
return [poBoxId, info]
}),
pull.collect((err, pairs) => {
if (err) return cb(err)
cb(null, new Map(pairs))
})
)
}
}