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 2 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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ Returns a pull stream source listing every known member of the group with id `gr

### `ssb.tribes2.listInvites() => source`

Returns a pull stream source listing invites (another user sent you one with `addMembers`) that you haven't accepted yet. The invites are on the same format as that of #create.
Returns a pull stream source listing groupIds of groups that you're invited to (another user sent you an invite with `addMembers`) that you haven't accepted yet. The invites are on the same format as that of #create.

### `ssb.tribes2.acceptInvite(groupId, cb)`

Expand Down
33 changes: 29 additions & 4 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const pull = require('pull-stream')
const paraMap = require('pull-paramap')
const pullMany = require('pull-many')
const lodashGet = require('lodash.get')
const uniqBy = require('lodash.uniqby')
const clarify = require('clarify-error')
const {
where,
Expand Down Expand Up @@ -362,7 +363,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 +394,32 @@ 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) => {
// TODO: which writeKey should be picked??
// or is that maybe not that important to decide here, maybe for acceptInvite?
Powersource marked this conversation as resolved.
Show resolved Hide resolved
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,6 +439,7 @@ module.exports = {
pull.drain(
(groupInfo) => {
foundInvite = true
// TODO: loop over all the readKeys we've found and add them all
Powersource marked this conversation as resolved.
Show resolved Hide resolved
ssb.box2.addGroupInfo(
groupInfo.id,
{
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"is-canonical-base64": "^1.1.1",
"lodash.get": "^4.4.2",
"lodash.set": "^4.3.2",
"lodash.uniqby": "^4.7.0",
"private-group-spec": "^6.0.0",
"pull-paramap": "^1.2.2",
"pull-stream": "^3.7.0",
Expand Down
102 changes: 102 additions & 0 deletions test/exclude-members.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -417,3 +417,105 @@ 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'
)

// TODO: bob use invite
Powersource marked this conversation as resolved.
Show resolved Hide resolved

// TODO: bob can read first and second alice post
Powersource marked this conversation as resolved.
Show resolved Hide resolved

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