Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Keep using keyring storage from older versions #108

Merged
merged 11 commits into from
Nov 17, 2023
7 changes: 7 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
const fs = require('fs')
const set = require('lodash.set')
const { isFeed, isCloakedMsg: isGroup } = require('ssb-ref')
const bfe = require('ssb-bfe')
@@ -8,6 +9,7 @@ const listen = require('./listen')
const { GetGroupTangle, tanglePrune, groupId: buildGroupId, poBoxKeys } = require('./lib')

const Method = require('./method')
const { join } = require('path')

module.exports = {
name: 'tribes',
@@ -50,6 +52,11 @@ module.exports = {
function init (ssb, config) {
if (!(config.box2 && config.box2.legacyMode)) throw Error('ssb-tribes error: config.box2.legacyMode needs to be `true`')

// where old versions of ssb-tribes used to store the keyring. now we use ssb-box2 (which uses keyring internally) which defaults to a different location. if we detect that there's something at the old path we need to prompt the user to config ssb-box2 differently
const oldKeyringPathExists = fs.existsSync(join(config.path, 'tribes/keystore'))
const box2PathPointsToOldLocation = (config.box2 && config.box2.path) === 'tribes/keystore'
if (oldKeyringPathExists && !box2PathPointsToOldLocation) throw Error('ssb-tribes found an old keystore at SSB_PATH/tribes/keystore but ssb-box2 is not configured to use it. Please set config.box2.path = "tribes/keystore"')

const state = {
keys: ssb.keys,
feedId: bfe.encode(ssb.id),
373 changes: 373 additions & 0 deletions package-lock.json
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -48,7 +48,11 @@
"ssb-replicate": "^1.3.3",
"standard": "^17.1.0",
"tap-arc": "^0.4.0",
"tape": "^5.7.0"
"tape": "^5.7.0",
"ssb-tribes-3-1-3": "npm:ssb-tribes@3.1.3",
"ssb-backlinks-2-1-1": "npm:ssb-backlinks@2.1.1",
"ssb-query-2-4-5": "npm:ssb-query@2.4.5",
"scuttle-testbot-1-11-0": "npm:scuttle-testbot@1.11.0"
},
"keywords": [
"scuttlebutt",
79 changes: 79 additions & 0 deletions test/from-old-versions.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
const test = require('tape')
const { promisify: p } = require('util')
const childProcess = require('node:child_process')

const OldTestBot = require('scuttle-testbot-1-11-0')
const NewBot = require('./helpers/test-bot')
const { join } = require('path')

const OldBot = (opts) => {
let stack = OldTestBot // eslint-disable-line
.use(require('ssb-backlinks-2-1-1'))
.use(require('ssb-query-2-4-5'))
.use(require('ssb-tribes-3-1-3'))

return stack(opts)
}

test('can continue from old keyring from ssb-tribes 3.1.3', async t => {
const oldAlice = OldBot({ name: 'alice' })

const oldGroup = await p(oldAlice.tribes.create)({})

t.equal(typeof oldGroup.groupId, 'string', 'got a group id when creating using old bot')

const oldList = await p(oldAlice.tribes.list)()
t.deepEqual(oldList, [oldGroup.groupId], 'group got listed by old bot')

const oldGet = await p(oldAlice.tribes.get)(oldGroup.groupId)

t.equal(oldGet.groupId, oldGroup.groupId, 'got correct groupId')
t.equal(oldGet.key, oldGroup.groupKey, 'got correct key')
t.equal(typeof oldGet.scheme, 'string', 'got scheme')
t.equal(typeof oldGet.root, 'string', 'got root')

await p(oldAlice.close)(true)

await p(setTimeout)(500)

// we have to do it this way because we have no normal way of killing a bot that's crashed and therefore releasing its DB locks.
const throwChild = childProcess.fork(join(__dirname, 'helpers/throw-bot.js'))

await new Promise((resolve) => {
throwChild.on('message', (msg) => {
t.match(msg, /found an old keystore/, "error when there's an old keystore but we don't use it")

throwChild.kill()

resolve()
})
})

await p(setTimeout)(1000)

const newOpts = {
name: 'alice',
startUnclean: true
}

const newAlice = NewBot({
...newOpts,
box2: {
path: 'tribes/keystore'
}
})

const newList = await p(newAlice.tribes.list)()
t.deepEqual(newList, oldList, 'new bot has same group list as old')

const newGet = await p(newAlice.tribes.get)(oldGroup.groupId)

t.deepEqual(newGet, {
groupId: oldGet.groupId,
writeKey: { key: oldGet.key, scheme: oldGet.scheme },
readKeys: [{ key: oldGet.key, scheme: oldGet.scheme }],
root: oldGet.root
}, 'get with new bot matches get with old bot')

await p(newAlice.close)()
})
12 changes: 4 additions & 8 deletions test/helpers/test-bot.js
Original file line number Diff line number Diff line change
@@ -12,30 +12,26 @@ module.exports = function TestBot (opts = {}) {
// }

let stack = Server // eslint-disable-line
// .use(require('ssb-backlinks'))
// .use(require('ssb-query'))
.use(require('ssb-db2/core'))
.use(require('ssb-classic'))
.use(require('ssb-db2/compat'))
.use(require('ssb-db2/compat/feedstate'))
.use(require("ssb-db2/compat/post"))
.use(require('ssb-db2/compat/post'))
.use(require('ssb-box2'))
.use(require('../..')) // ssb-tribes - NOTE load it after ssb-backlinks
.use(require('../..'))

if (opts.installReplicate === true) {
stack = stack.use(require('ssb-replicate'))
}

if (opts.name) opts.name = 'ssb-tribes/' + opts.name

const ssb = stack({
...opts,
box2: {
legacyMode: true,
...opts.box2
},
// we don't want testbot to import db1 or db2 for us, we want to control what db2 plugins get imported
noDefaultUse: true,
...opts
noDefaultUse: true
})

if (opts.debug) {
14 changes: 14 additions & 0 deletions test/helpers/throw-bot.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// this file is used in test/from-old-versions.test.js

const NewBot = require('./test-bot')

const newOpts = {
name: 'alice',
startUnclean: true
}

try {
NewBot(newOpts)
} catch (err) {
process.send(err.message)
}