ssb-keyring
Version:
A persistence store for encryption keys for scuttlebutt. It's purpose is to make easy to answer box2 encryption/ decryption questions.
137 lines (115 loc) • 3.77 kB
JavaScript
const { keySchemes } = require('private-group-spec')
const { toBuffer, isObject, isString, isBuffer } = require('../util')
function isSSBKeys (obj) {
if (!obj || typeof obj !== 'object') return false
if (!obj.id || typeof obj.id !== 'string') return false
if (!obj.curve || typeof obj.curve !== 'string') return false
if (!obj.public || typeof obj.public !== 'string') return false
if (!obj.private || typeof obj.private !== 'string') return false
return true
}
const keyEncoding = {
encode (buf) {
if (typeof buf === 'string') return buf
if (isBuffer(buf)) return buf.toString('base64')
throw new Error(`expected type Buffer|String, got ${typeof buf}`)
},
decode: toBuffer
}
const schemeEncoding = {
encode (str) {
switch (str) {
case keySchemes.private_group: return 1
case keySchemes.feed_id_self: return 2
case keySchemes.po_box: return 3
case keySchemes.feed_id_dm: return 4
case keySchemes.feed_id_metafeed_dm: return 5
default: return str
}
},
decode (int) {
switch (int) {
case 1: return keySchemes.private_group
case 2: return keySchemes.feed_id_self
case 3: return keySchemes.po_box
case 4: return keySchemes.feed_id_dm
case 5: return keySchemes.feed_id_metafeed_dm
default: {
console.log('ssb-keyring info-encoding found unknown entry:', int, typeof int)
return int
}
}
}
}
module.exports = {
encode (info) {
if (isString(info)) return JSON.stringify(info)
if (isObject(info)) {
if (isSSBKeys(info)) return JSON.stringify(info)
const output = { root: info.root }
// encode keys
if (info.key) output.key = keyEncoding.encode(info.key)
if (info.public) output.public = keyEncoding.encode(info.public)
if (info.secret) output.secret = keyEncoding.encode(info.secret)
if (info.writeKey?.key) {
output.writeKey = {
key: keyEncoding.encode(info.writeKey.key),
scheme: schemeEncoding.encode(info.writeKey.scheme)
}
}
if (info.readKeys) {
output.readKeys = info.readKeys.map(readKey => ({
key: keyEncoding.encode(readKey.key),
scheme: schemeEncoding.encode(readKey.scheme)
}))
}
if (info.scheme) output.scheme = schemeEncoding.encode(info.scheme)
if (info.excluded) output.excluded = true
return JSON.stringify(output)
}
throw new Error('unable to encode info')
},
decode (str) {
const info = JSON.parse(str)
if (isSSBKeys(info)) return info
// decode keys
if (info.key) info.key = keyEncoding.decode(info.key)
if (info.public) info.public = keyEncoding.decode(info.public)
if (info.secret) info.secret = keyEncoding.decode(info.secret)
if (info.writeKey?.key) {
info.writeKey = {
key: keyEncoding.decode(info.writeKey.key),
scheme: schemeEncoding.decode(info.writeKey.scheme)
}
}
if (info.readKeys) {
info.readKeys = info.readKeys.map(readKey => ({
key: keyEncoding.decode(readKey.key),
scheme: schemeEncoding.decode(readKey.scheme)
}))
}
if (info.scheme) info.scheme = schemeEncoding.decode(info.scheme)
// migrate from old to new group storage format
if (info.key && info.scheme === keySchemes.private_group) {
if (!info.writeKey) {
info.writeKey = {
key: info.key,
scheme: info.scheme
}
}
if (!info.readKeys) {
info.readKeys = [
{
key: info.key,
scheme: info.scheme
}
]
}
delete info.key
delete info.scheme
}
return info
},
buffer: false,
type: 'keystore-info-encoding'
}