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

Test being added to an old epoch #94

Merged
merged 16 commits into from
Apr 20, 2023
Merged
Show file tree
Hide file tree
Changes from 6 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
69 changes: 50 additions & 19 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ const { promisify } = require('util')
const pull = require('pull-stream')
const paraMap = require('pull-paramap')
const pullMany = require('pull-many')
const multicb = require('multicb')
const lodashGet = require('lodash.get')
const uniqBy = require('lodash.uniqby')
const clarify = require('clarify-error')
const {
where,
Expand Down Expand Up @@ -362,7 +364,8 @@ module.exports = {
// prettier-ignore
if (err) return cb(clarify(err, 'Failed to list group IDs when listing invites'))

const source = pull(
let acc = {}
pull(
ssb.db.query(
where(and(isDecrypted('box2'), type('group/add-member'))),
toPullStream()
Expand Down Expand Up @@ -392,10 +395,30 @@ module.exports = {
readKeys: [{ key, scheme }],
root: lodashGet(msg, 'value.content.root'),
}
})
)
}),
// aggregate multiple readKeys from invites to different epochs into one invite object
pull.drain(
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this won't be very streamy now, but maybe that's ok for now since we're just getting it to work at first?

(invite) => {
if (acc[invite.id]) {
// readKeys from both invites
acc[invite.id].readKeys.push(...invite.readKeys)
// but no duplicates
acc[invite.id].readKeys = uniqBy(
acc[invite.id].readKeys,
(readKey) => readKey.key.toString('base64')
)
} else {
acc[invite.id] = invite
}
},
(err) => {
if (err) return cb('todo')

return cb(null, source)
const inviteArray = Object.values(acc)
return cb(null, pull.values(inviteArray))
}
)
)
})
)
})
Expand All @@ -415,22 +438,31 @@ module.exports = {
pull.drain(
(groupInfo) => {
foundInvite = true
ssb.box2.addGroupInfo(
groupInfo.id,
{
key: groupInfo.writeKey.key,
root: groupInfo.root,
},
(err) => {

const done = multicb()

// TODO: which writeKey should be picked??
// this will essentially pick a random write key
groupInfo.readKeys.forEach((readKey) => {
ssb.box2.addGroupInfo(
groupInfo.id,
{
key: readKey.key,
root: groupInfo.root,
},
done()
)
})

done((err) => {
// prettier-ignore
if (err) return cb(clarify(err, 'Failed to add group info when accepting an invite'))
ssb.db.reindexEncrypted((err) => {
// prettier-ignore
if (err) return cb(clarify(err, 'Failed to add group info when accepting an invite'))
ssb.db.reindexEncrypted((err) => {
// prettier-ignore
if (err) cb(clarify(err, 'Failed to reindex encrypted messages when accepting an invite'))
if (err) cb(clarify(err, 'Failed to reindex encrypted messages when accepting an invite'))
else cb(null, groupInfo)
})
}
)
})
})
},
(err) => {
// prettier-ignore
Expand Down Expand Up @@ -482,7 +514,6 @@ module.exports = {
// look for new epochs that we're added to
pull(
ssb.db.query(
// TODO: does this output new stuff if we accept an invite to an old epoch and then find additions to newer epochs?
Powersource marked this conversation as resolved.
Show resolved Hide resolved
where(and(isDecrypted('box2'), type('group/add-member'))),
live({ old: true }),
toPullStream()
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
"is-canonical-base64": "^1.1.1",
"lodash.get": "^4.4.2",
"lodash.set": "^4.3.2",
"lodash.uniqby": "^4.7.0",
"multicb": "^1.2.2",
"private-group-spec": "^6.0.0",
"pull-paramap": "^1.2.2",
"pull-stream": "^3.7.0",
Expand Down
114 changes: 114 additions & 0 deletions test/exclude-members.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -417,3 +417,117 @@ test("If you're not the excluder nor the excludee then you should still be in th
await p(bob.close)(true)
await p(carol.close)(true)
})

test('Get added to an old epoch but still find newer epochs', async (t) => {
const alice = Testbot({
keys: ssbKeys.generate(null, 'alice'),
mfSeed: Buffer.from(
'000000000000000000000000000000000000000000000000000000000000a1ce',
'hex'
),
})
const bob = Testbot({
keys: ssbKeys.generate(null, 'bob'),
mfSeed: Buffer.from(
'0000000000000000000000000000000000000000000000000000000000000b0b',
'hex'
),
})
const carol = Testbot({
keys: ssbKeys.generate(null, 'carol'),
mfSeed: Buffer.from(
'00000000000000000000000000000000000000000000000000000000000ca201',
'hex'
),
})

await alice.tribes2.start()
await bob.tribes2.start()
await carol.tribes2.start()
t.pass('tribes2 started for everyone')

await p(alice.metafeeds.findOrCreate)()
const bobRoot = await p(bob.metafeeds.findOrCreate)()
const carolRoot = await p(carol.metafeeds.findOrCreate)()

await replicate(alice, bob)
await replicate(alice, carol)
await replicate(bob, carol)
t.pass('everyone replicates their trees')

const { id: groupId } = await alice.tribes2
.create()
.catch((err) => t.error(err, 'alice failed to create group'))

const { key: firstPostId } = await alice.tribes2
.publish({
type: 'test',
text: 'first post',
recps: [groupId],
})
.catch(t.fail)

// replicate the first group messages to bob when he can't decrypt them
await replicate(alice, bob).catch(t.error)

await alice.tribes2
.addMembers(groupId, [bobRoot.id, carolRoot.id])
.then(() => t.pass('added bob and carol'))
.catch((err) => t.error(err, 'add bob and carol fail'))

await alice.tribes2
.excludeMembers(groupId, [carolRoot.id])
.then(() => t.pass('alice excluded carol'))
.catch((err) => t.error(err, 'remove member fail'))

const { key: secondPostId } = await alice.tribes2
.publish({
type: 'test',
text: 'second post',
recps: [groupId],
})
.catch(t.fail)

// only replicate bob's invite to him once we're already on the new epoch
await replicate(alice, bob).catch(t.error)

const bobInvites = await pull(
bob.tribes2.listInvites(),
pull.collectAsPromise()
).catch(t.fail)
t.deepEquals(
bobInvites.map((invite) => invite.id),
[groupId],
'bob has an invite to the group'
)
t.equals(
bobInvites[0].readKeys.length,
2,
'there are 2 readKeys in the invite'
)
t.notEquals(
bobInvites[0].readKeys[0].key.toString('base64'),
bobInvites[0].readKeys[1].key.toString('base64'),
'the two readKeys are different'
)

await bob.tribes2.acceptInvite(groupId).catch(t.fail)

const bobGotFirstMsg = await p(bob.db.get)(firstPostId)
t.notEquals(
typeof bobGotFirstMsg.content,
'string',
"bob managed to decrypt alice's first message"
)

const bobGotSecondMsg = await p(bob.db.get)(secondPostId)
t.notEquals(
typeof bobGotSecondMsg.content,
'string',
"bob managed to decrypt alice's second message"
)

await p(alice.close)(true)
await p(bob.close)(true)
await p(carol.close)(true)
})