From abf824c70035e1f07cdc555f8aedaee36c19d173 Mon Sep 17 00:00:00 2001 From: Jacob Karlsson Date: Fri, 7 Apr 2023 13:30:30 +0200 Subject: [PATCH 01/12] Add failing test for being removed from a group --- test/exclude-members.test.js | 71 ++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/test/exclude-members.test.js b/test/exclude-members.test.js index 93ab60c..62c511a 100644 --- a/test/exclude-members.test.js +++ b/test/exclude-members.test.js @@ -174,3 +174,74 @@ test('add and remove a person, post on the new feed', async (t) => { await p(alice.close)(true) await p(bob.close)(true) }) + +test('Verify that you actually get removed from a group', 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' + ), + }) + + await alice.tribes2.start() + await bob.tribes2.start() + t.pass('tribes2 started for both alice and bob') + + const aliceRoot = await p(alice.metafeeds.findOrCreate)() + const bobRoot = await p(bob.metafeeds.findOrCreate)() + + await replicate(alice, bob) + t.pass('alice and bob replicate their trees') + + const { id: groupId } = await alice.tribes2 + .create() + .catch((err) => t.error(err, 'alice failed to create group')) + + await alice.tribes2 + .addMembers(groupId, [bobRoot.id]) + .catch((err) => t.error(err, 'add member fail')) + + await replicate(alice, bob) + + await bob.tribes2.acceptInvite(groupId).catch(t.error) + + await bob.tribes2 + .publish({ + type: 'test', + text: 'bob first post', + recps: [groupId], + }) + .then(() => t.pass("bob posts in the group while he's in it")) + .catch(t.error) + + await replicate(alice, bob) + + await alice.tribes2 + .excludeMembers(groupId, [bobRoot.id]) + .catch((err) => t.error(err, 'remove member fail')) + + await replicate(alice, bob) + + await bob.tribes2 + .publish({ + type: 'test', + text: 'bob second post', + recps: [groupId], + }) + .then(() => + t.fail("Bob posted again in the group even if he's removed from it") + ) + .catch(() => + t.pass("Bob can't post in the group anymore since he's removed from it") + ) + + // TODO: check bob's group list, it should still have an entry for the group but it should be marked that he's removed from it or something. or an opt for the function? +}) From 98e190fbd5d08105eb8f2d6c70eb5028df2baa2a Mon Sep 17 00:00:00 2001 From: Jacob Karlsson Date: Fri, 7 Apr 2023 20:15:33 +0200 Subject: [PATCH 02/12] Try to remove group info on exclusion --- index.js | 28 ++++++++++++++++++++++++++++ package.json | 2 +- test/exclude-members.test.js | 6 ++++++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 015328e..da3d4eb 100644 --- a/index.js +++ b/index.js @@ -407,6 +407,34 @@ module.exports = { if (err) return cb(clarify(err, 'Error finding or creating additions feed when starting ssb-tribes2')) return cb() }) + + ssb.metafeeds.findOrCreate((err, myRoot) => { + // prettier-ignore + if (err) return cb(clarify(err, 'todo')) + + pull( + ssb.db.query( + where(and(isDecrypted('box2'), type('group/exclude'))), + live({ old: true }), + toPullStream() + ), + pull.filter((msg) => + // it's an exclusion of us + msg.value?.content?.excludes?.includes(myRoot.id) + ), + pull.drain( + (msg) => { + const groupId = msg.value?.content?.recps?.[0] + console.log('removing for groupid', groupId) + ssb.box2.removeGroupInfo(groupId, null) + }, + (err) => { + // prettier-ignore + if (err) return cb(clarify(err, 'todo')) + } + ) + ) + }) } return { diff --git a/package.json b/package.json index 3436cae..058c859 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "pull-paramap": "^1.2.2", "pull-stream": "^3.7.0", "ssb-bfe": "^3.7.0", - "ssb-box2": "^6.0.0", + "ssb-box2": "github:ssbc/ssb-box2#remove-group-info", "ssb-crut": "^4.6.2", "ssb-db2": "^6.3.3", "ssb-meta-feeds": "^0.39.0", diff --git a/test/exclude-members.test.js b/test/exclude-members.test.js index 62c511a..3d1faf3 100644 --- a/test/exclude-members.test.js +++ b/test/exclude-members.test.js @@ -230,6 +230,9 @@ test('Verify that you actually get removed from a group', async (t) => { await replicate(alice, bob) + // TODO: lower + await p(setTimeout)(4000) + await bob.tribes2 .publish({ type: 'test', @@ -244,4 +247,7 @@ test('Verify that you actually get removed from a group', async (t) => { ) // TODO: check bob's group list, it should still have an entry for the group but it should be marked that he's removed from it or something. or an opt for the function? + + // TODO: try to check the messages encrypted to the new key/epoch, and fail + // checking the re-addition messages on alice's additions feed should do }) From 618e7bf2b6e21b5669b528589e826261a6cb8cc8 Mon Sep 17 00:00:00 2001 From: Jacob Karlsson Date: Mon, 10 Apr 2023 14:47:13 +0200 Subject: [PATCH 03/12] Bob can't post once he's removed --- index.js | 18 +++++++++++------- lib/tangles/get-tangle-data.js | 2 +- test/exclude-members.test.js | 10 +++++++--- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/index.js b/index.js index da3d4eb..cd3badb 100644 --- a/index.js +++ b/index.js @@ -259,18 +259,23 @@ module.exports = { } const groupId = recps[0] - addTangles(ssb, content, tangles, (err, content) => { + get(groupId, (err, { writeKey, removed }) => { // prettier-ignore - if (err) return cb(clarify(err, 'Failed to add group tangle when publishing to a group')) + if (err) return cb(clarify(err, 'Failed to get group details when publishing to a group')) - if (!isValid(content)) + if (removed) return cb( - new Error(isValid.errorsString ?? 'content failed validation') + new Error("Cannot publish to a group we've been removed from") ) - get(groupId, (err, { writeKey }) => { + addTangles(ssb, content, tangles, (err, content) => { // prettier-ignore - if (err) return cb(clarify(err, 'Failed to get group details when publishing to a group')) + if (err) return cb(clarify(err, 'Failed to add group tangle when publishing to a group')) + + if (!isValid(content)) + return cb( + new Error(isValid.errorsString ?? 'content failed validation') + ) const getFeed = opts?.feedKeys ? (_, cb) => cb(null, { keys: opts.feedKeys }) @@ -425,7 +430,6 @@ module.exports = { pull.drain( (msg) => { const groupId = msg.value?.content?.recps?.[0] - console.log('removing for groupid', groupId) ssb.box2.removeGroupInfo(groupId, null) }, (err) => { diff --git a/lib/tangles/get-tangle-data.js b/lib/tangles/get-tangle-data.js index 6bfec90..b033397 100644 --- a/lib/tangles/get-tangle-data.js +++ b/lib/tangles/get-tangle-data.js @@ -23,7 +23,7 @@ function getTangleRoot(server, groupId, tangle, cb) { // prettier-ignore if (err) return cb(clarify(err, 'Failed to get group info when getting a tangle')) - if (!info) { + if (!info || info.removed) { return cb(new Error(`get-tangle: unknown groupId ${groupId}`)) } diff --git a/test/exclude-members.test.js b/test/exclude-members.test.js index 3d1faf3..2ddf5d5 100644 --- a/test/exclude-members.test.js +++ b/test/exclude-members.test.js @@ -195,7 +195,7 @@ test('Verify that you actually get removed from a group', async (t) => { await bob.tribes2.start() t.pass('tribes2 started for both alice and bob') - const aliceRoot = await p(alice.metafeeds.findOrCreate)() + await p(alice.metafeeds.findOrCreate)() const bobRoot = await p(bob.metafeeds.findOrCreate)() await replicate(alice, bob) @@ -230,8 +230,9 @@ test('Verify that you actually get removed from a group', async (t) => { await replicate(alice, bob) - // TODO: lower - await p(setTimeout)(4000) + await p(setTimeout)(500) + + t.pass('replicated, about to publish') await bob.tribes2 .publish({ @@ -250,4 +251,7 @@ test('Verify that you actually get removed from a group', async (t) => { // TODO: try to check the messages encrypted to the new key/epoch, and fail // checking the re-addition messages on alice's additions feed should do + + await p(alice.close)(true) + await p(bob.close)(true) }) From abbec00212cb094dacd6c9b934371a28ee0494bf Mon Sep 17 00:00:00 2001 From: Jacob Karlsson Date: Tue, 11 Apr 2023 19:43:07 +0200 Subject: [PATCH 04/12] Adapt to remove->exclude rename --- index.js | 8 ++++---- lib/tangles/get-tangle-data.js | 14 +++++++++----- test/exclude-members.test.js | 16 ++++++++-------- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/index.js b/index.js index cd3badb..1d9cbc1 100644 --- a/index.js +++ b/index.js @@ -259,13 +259,13 @@ module.exports = { } const groupId = recps[0] - get(groupId, (err, { writeKey, removed }) => { + get(groupId, (err, { writeKey, excluded }) => { // prettier-ignore if (err) return cb(clarify(err, 'Failed to get group details when publishing to a group')) - if (removed) + if (excluded) return cb( - new Error("Cannot publish to a group we've been removed from") + new Error("Cannot publish to a group we've been excluded from") ) addTangles(ssb, content, tangles, (err, content) => { @@ -430,7 +430,7 @@ module.exports = { pull.drain( (msg) => { const groupId = msg.value?.content?.recps?.[0] - ssb.box2.removeGroupInfo(groupId, null) + ssb.box2.excludeGroupInfo(groupId, null) }, (err) => { // prettier-ignore diff --git a/lib/tangles/get-tangle-data.js b/lib/tangles/get-tangle-data.js index b033397..72137da 100644 --- a/lib/tangles/get-tangle-data.js +++ b/lib/tangles/get-tangle-data.js @@ -23,7 +23,7 @@ function getTangleRoot(server, groupId, tangle, cb) { // prettier-ignore if (err) return cb(clarify(err, 'Failed to get group info when getting a tangle')) - if (!info || info.removed) { + if (!info || info.excluded) { return cb(new Error(`get-tangle: unknown groupId ${groupId}`)) } @@ -78,10 +78,13 @@ module.exports = function getTangleData(server, tangle, groupId, cb) { // prettier-ignore if (err) return cb(clarify(err, 'Failed to read updates when getting tangle')) - const nodes = msgs.map((msg) => ({ - key: toUri(msg.key), - previous: msg.value.content.tangles[tangle].previous, - })) + const nodes = msgs.map((msg) => { + if (!msg.key) console.log('msg without key?', msg) + return { + key: toUri(msg.key), + previous: msg.value.content.tangles[tangle].previous, + } + }) // NOTE: getUpdates query does not get root node nodes.push({ key: root, previous: null }) @@ -91,6 +94,7 @@ module.exports = function getTangleData(server, tangle, groupId, cb) { // reducing the graph to find the tips // each node should be pruned down to e.g. { key: '%D', previous: ['%B', '%C'] } + console.log('nodes', nodes) const reduce = new Reduce(strategy, { nodes }) cb(null, { root, diff --git a/test/exclude-members.test.js b/test/exclude-members.test.js index 2ddf5d5..d2fac4c 100644 --- a/test/exclude-members.test.js +++ b/test/exclude-members.test.js @@ -11,7 +11,7 @@ const Testbot = require('./helpers/testbot') const replicate = require('./helpers/replicate') const countGroupFeeds = require('./helpers/count-group-feeds') -test('add and remove a person, post on the new feed', async (t) => { +test('add and exclude a person, post on the new feed', async (t) => { // Alice's feeds should look like // first: initGroup->excludeBob // second: initEpoch->post @@ -62,7 +62,7 @@ test('add and remove a person, post on the new feed', async (t) => { await alice.tribes2 .excludeMembers(groupId, [bobRoot.id]) - .catch((err) => t.error(err, 'remove member fail')) + .catch((err) => t.error(err, 'exclude member fail')) t.equals( await p(countGroupFeeds)(alice), @@ -175,7 +175,7 @@ test('add and remove a person, post on the new feed', async (t) => { await p(bob.close)(true) }) -test('Verify that you actually get removed from a group', async (t) => { +test('Verify that you actually get excluded from a group', async (t) => { const alice = Testbot({ keys: ssbKeys.generate(null, 'alice'), mfSeed: Buffer.from( @@ -226,11 +226,11 @@ test('Verify that you actually get removed from a group', async (t) => { await alice.tribes2 .excludeMembers(groupId, [bobRoot.id]) - .catch((err) => t.error(err, 'remove member fail')) + .catch((err) => t.error(err, 'exclude member fail')) await replicate(alice, bob) - await p(setTimeout)(500) + await p(setTimeout)(5000) t.pass('replicated, about to publish') @@ -241,13 +241,13 @@ test('Verify that you actually get removed from a group', async (t) => { recps: [groupId], }) .then(() => - t.fail("Bob posted again in the group even if he's removed from it") + t.fail("Bob posted again in the group even if he's excluded from it") ) .catch(() => - t.pass("Bob can't post in the group anymore since he's removed from it") + t.pass("Bob can't post in the group anymore since he's excluded from it") ) - // TODO: check bob's group list, it should still have an entry for the group but it should be marked that he's removed from it or something. or an opt for the function? + // TODO: check bob's group list, it should still have an entry for the group but it should be marked that he's excluded from it or something. or an opt for the function? // TODO: try to check the messages encrypted to the new key/epoch, and fail // checking the re-addition messages on alice's additions feed should do From 8b1a07cad3315478d98d14cc953357631c756b09 Mon Sep 17 00:00:00 2001 From: Jacob Karlsson Date: Tue, 11 Apr 2023 19:44:41 +0200 Subject: [PATCH 05/12] Remove logs --- lib/tangles/get-tangle-data.js | 12 ++++-------- test/exclude-members.test.js | 2 +- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/lib/tangles/get-tangle-data.js b/lib/tangles/get-tangle-data.js index 72137da..a8ad948 100644 --- a/lib/tangles/get-tangle-data.js +++ b/lib/tangles/get-tangle-data.js @@ -78,13 +78,10 @@ module.exports = function getTangleData(server, tangle, groupId, cb) { // prettier-ignore if (err) return cb(clarify(err, 'Failed to read updates when getting tangle')) - const nodes = msgs.map((msg) => { - if (!msg.key) console.log('msg without key?', msg) - return { - key: toUri(msg.key), - previous: msg.value.content.tangles[tangle].previous, - } - }) + const nodes = msgs.map((msg) => ({ + key: toUri(msg.key), + previous: msg.value.content.tangles[tangle].previous, + })) // NOTE: getUpdates query does not get root node nodes.push({ key: root, previous: null }) @@ -94,7 +91,6 @@ module.exports = function getTangleData(server, tangle, groupId, cb) { // reducing the graph to find the tips // each node should be pruned down to e.g. { key: '%D', previous: ['%B', '%C'] } - console.log('nodes', nodes) const reduce = new Reduce(strategy, { nodes }) cb(null, { root, diff --git a/test/exclude-members.test.js b/test/exclude-members.test.js index d2fac4c..4d6f5c2 100644 --- a/test/exclude-members.test.js +++ b/test/exclude-members.test.js @@ -230,7 +230,7 @@ test('Verify that you actually get excluded from a group', async (t) => { await replicate(alice, bob) - await p(setTimeout)(5000) + await p(setTimeout)(500) t.pass('replicated, about to publish') From 897d6aebb4a840ea941cfacc6245a93bf4e97fe3 Mon Sep 17 00:00:00 2001 From: Jacob Karlsson Date: Tue, 11 Apr 2023 19:56:26 +0200 Subject: [PATCH 06/12] Test list after exclusion --- test/exclude-members.test.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/exclude-members.test.js b/test/exclude-members.test.js index 4d6f5c2..f37f7e4 100644 --- a/test/exclude-members.test.js +++ b/test/exclude-members.test.js @@ -3,6 +3,7 @@ // SPDX-License-Identifier: CC0-1.0 const test = require('tape') +const pull = require('pull-stream') const { promisify: p } = require('util') const ssbKeys = require('ssb-keys') const { where, author, toPromise } = require('ssb-db2/operators') @@ -247,7 +248,12 @@ test('Verify that you actually get excluded from a group', async (t) => { t.pass("Bob can't post in the group anymore since he's excluded from it") ) - // TODO: check bob's group list, it should still have an entry for the group but it should be marked that he's excluded from it or something. or an opt for the function? + const bobGroups = await pull(bob.tribes2.list(), pull.collectAsPromise()) + t.deepEquals( + bobGroups, + [{ id: groupId, excluded: true }], + "bob is excluded from the only group he's been in. sad." + ) // TODO: try to check the messages encrypted to the new key/epoch, and fail // checking the re-addition messages on alice's additions feed should do From 950bef98d0c20d963ebc402512d7e4a143374d7e Mon Sep 17 00:00:00 2001 From: Jacob Karlsson Date: Tue, 11 Apr 2023 20:10:22 +0200 Subject: [PATCH 07/12] Test bob not decrypting new msgs --- test/exclude-members.test.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/test/exclude-members.test.js b/test/exclude-members.test.js index f37f7e4..076f778 100644 --- a/test/exclude-members.test.js +++ b/test/exclude-members.test.js @@ -229,6 +229,12 @@ test('Verify that you actually get excluded from a group', async (t) => { .excludeMembers(groupId, [bobRoot.id]) .catch((err) => t.error(err, 'exclude member fail')) + const { key: aliceNewEpochPostKey } = await alice.tribes2.publish({ + type: 'shitpost', + text: 'alicepost', + recps: [groupId], + }) + await replicate(alice, bob) await p(setTimeout)(500) @@ -255,8 +261,12 @@ test('Verify that you actually get excluded from a group', async (t) => { "bob is excluded from the only group he's been in. sad." ) - // TODO: try to check the messages encrypted to the new key/epoch, and fail - // checking the re-addition messages on alice's additions feed should do + const bobGotMsg = await p(bob.db.get)(aliceNewEpochPostKey) + t.equals( + typeof bobGotMsg.content, + 'string', + "bob didn't manage to decrypt alice's new message" + ) await p(alice.close)(true) await p(bob.close)(true) From eb43f010a8efe2d58e4eadead532fd594d0a8f70 Mon Sep 17 00:00:00 2001 From: Jacob Karlsson Date: Tue, 11 Apr 2023 20:33:49 +0200 Subject: [PATCH 08/12] Test listInvites --- test/exclude-members.test.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/exclude-members.test.js b/test/exclude-members.test.js index 076f778..7a7c308 100644 --- a/test/exclude-members.test.js +++ b/test/exclude-members.test.js @@ -268,6 +268,9 @@ test('Verify that you actually get excluded from a group', async (t) => { "bob didn't manage to decrypt alice's new message" ) + const invites = await pull(bob.tribes2.listInvites(), pull.collectAsPromise()) + t.deepEquals(invites, [], 'Bob has no invites') + await p(alice.close)(true) await p(bob.close)(true) }) From 51de8e6848b4018b66bc2dff0191a3a70b05ad97 Mon Sep 17 00:00:00 2001 From: Jacob Karlsson Date: Tue, 11 Apr 2023 20:52:57 +0200 Subject: [PATCH 09/12] Error listMembers when called on excluded group --- index.js | 40 +++++++++++++++++++++++++++--------- test/exclude-members.test.js | 12 +++++++++++ 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/index.js b/index.js index 1d9cbc1..e8722cd 100644 --- a/index.js +++ b/index.js @@ -297,16 +297,36 @@ module.exports = { function listMembers(groupId, opts = {}) { return pull( - ssb.db.query( - where(and(isDecrypted('box2'), type('group/add-member'))), - opts.live ? live({ old: true }) : null, - toPullStream() - ), - pull.map((msg) => lodashGet(msg, 'value.content.recps', [])), - pull.filter((recps) => recps.length > 1 && recps[0] === groupId), - pull.map((recps) => recps.slice(1)), - pull.flatten(), - pull.unique() + pull.values([0]), + pull.asyncMap((n, cb) => { + get(groupId, (err, group) => { + // prettier-ignore + if (err) return cb(clarify(err, 'Failed to get group info when listing members')) + + if (group.excluded) { + return cb( + new Error("We're excluded from this group, can't list members") + ) + } else { + const source = pull( + ssb.db.query( + where(and(isDecrypted('box2'), type('group/add-member'))), + opts.live ? live({ old: true }) : null, + toPullStream() + ), + pull.map((msg) => lodashGet(msg, 'value.content.recps', [])), + pull.filter( + (recps) => recps.length > 1 && recps[0] === groupId + ), + pull.map((recps) => recps.slice(1)), + pull.flatten(), + pull.unique() + ) + return cb(null, source) + } + }) + }), + pull.flatten() ) } diff --git a/test/exclude-members.test.js b/test/exclude-members.test.js index 7a7c308..853929b 100644 --- a/test/exclude-members.test.js +++ b/test/exclude-members.test.js @@ -271,6 +271,18 @@ test('Verify that you actually get excluded from a group', async (t) => { const invites = await pull(bob.tribes2.listInvites(), pull.collectAsPromise()) t.deepEquals(invites, [], 'Bob has no invites') + await pull(bob.tribes2.listMembers(groupId), pull.collectAsPromise()) + .then(() => + t.fail( + "Bob didn't get an error when trying to list members of the group he's excluded from" + ) + ) + .catch(() => + t.pass( + "Bob gets an error when trying to list members of the group he's excluded from" + ) + ) + await p(alice.close)(true) await p(bob.close)(true) }) From b0057c891b1a1ff87b07130cb02b7aae875cb4ad Mon Sep 17 00:00:00 2001 From: Jacob Karlsson Date: Thu, 13 Apr 2023 11:55:33 +0200 Subject: [PATCH 10/12] Verify exclude msg shape --- index.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index cc9c3dc..e294201 100644 --- a/index.js +++ b/index.js @@ -450,13 +450,14 @@ module.exports = { live({ old: true }), toPullStream() ), + pull.filter(isExclude), pull.filter((msg) => // it's an exclusion of us - msg.value?.content?.excludes?.includes(myRoot.id) + msg.value.content.excludes.includes(myRoot.id) ), pull.drain( (msg) => { - const groupId = msg.value?.content?.recps?.[0] + const groupId = msg.value.content.recps[0] ssb.box2.excludeGroupInfo(groupId, null) }, (err) => { From 765126e89eb4a1f0349db4fe5c298e1211e04cf7 Mon Sep 17 00:00:00 2001 From: Jacob Karlsson Date: Thu, 13 Apr 2023 11:58:05 +0200 Subject: [PATCH 11/12] Clarify err and refactor root getting --- index.js | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/index.js b/index.js index e294201..553d126 100644 --- a/index.js +++ b/index.js @@ -442,8 +442,9 @@ module.exports = { ssb.metafeeds.findOrCreate((err, myRoot) => { // prettier-ignore - if (err) return cb(clarify(err, 'todo')) + if (err) return cb(clarify(err, 'Error getting own root in start()')) + // check if we've been excluded pull( ssb.db.query( where(and(isDecrypted('box2'), type('group/exclude'))), @@ -462,17 +463,12 @@ module.exports = { }, (err) => { // prettier-ignore - if (err) return cb(clarify(err, 'todo')) + if (err) return cb(clarify(err, 'Error on looking for exclude messages excluding us')) } ) ) - }) - - // look for new epochs that we're added to - ssb.metafeeds.findOrCreate((err, myRoot) => { - // prettier-ignore - if (err) return cb(clarify(err, 'Error getting own root in start()')) + // 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? From b3dc7ceb6b7b91035ca1906a4cdb7f2733e53631 Mon Sep 17 00:00:00 2001 From: Jacob Karlsson Date: Thu, 13 Apr 2023 16:40:32 +0200 Subject: [PATCH 12/12] Adapt to list with exclude opt --- README.md | 4 ++-- index.js | 15 +++++++++++++-- package.json | 2 +- test/exclude-members.test.js | 5 ++++- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index da5f4b7..0ffbc1f 100644 --- a/README.md +++ b/README.md @@ -126,9 +126,9 @@ Gets information about a specific group. - `groupId` _GroupUri_ - the public-safe SSB URI which identifies the group - `cb` _Function_ - callback function of signature `(err, group)` where `group` is an object on the same format as the `group` object returned by #create -### `ssb.tribes2.list({ live }) => source` +### `ssb.tribes2.list({ live, excluded }) => source` -Creates a pull-stream source which emits `group` data of each private group you're a part of. If `live` is true then it also outputs all new groups you join. +Creates a pull-stream source which emits `group` data of each private group you're a part of. If `live` is true then it also outputs all new groups you join. If `excluded` is true then it only outputs groups that you've been excluded from, instead of just ones you haven't. (Same format as `group` object returned by #create) ### `ssb.tribes2.addMembers(groupId, feedIds, opts, cb)` diff --git a/index.js b/index.js index 553d126..8d28f45 100644 --- a/index.js +++ b/index.js @@ -5,6 +5,7 @@ const { promisify } = require('util') const pull = require('pull-stream') const paraMap = require('pull-paramap') +const pullMany = require('pull-many') const lodashGet = require('lodash.get') const clarify = require('clarify-error') const { @@ -117,7 +118,13 @@ module.exports = { } function list(opts = {}) { - return pull(ssb.box2.listGroupIds({ live: !!opts.live }), paraMap(get, 4)) + return pull( + ssb.box2.listGroupIds({ + live: !!opts.live, + excluded: !!opts.excluded, + }), + paraMap(get, 4) + ) } function addMembers(groupId, feedIds, opts = {}, cb) { @@ -346,7 +353,11 @@ module.exports = { if (err) return cb(clarify(err, 'Failed to get root metafeed when listing invites')) pull( - ssb.box2.listGroupIds(), + pullMany([ + ssb.box2.listGroupIds(), + ssb.box2.listGroupIds({ excluded: true }), + ]), + pull.flatten(), pull.collect((err, groupIds) => { // prettier-ignore if (err) return cb(clarify(err, 'Failed to list group IDs when listing invites')) diff --git a/package.json b/package.json index 7d60a28..f8944a2 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "pull-paramap": "^1.2.2", "pull-stream": "^3.7.0", "ssb-bfe": "^3.7.0", - "ssb-box2": "github:ssbc/ssb-box2#remove-group-info", + "ssb-box2": "^6.1.0", "ssb-crut": "^4.6.2", "ssb-db2": "^6.3.3", "ssb-meta-feeds": "^0.39.0", diff --git a/test/exclude-members.test.js b/test/exclude-members.test.js index e100f58..1fa020a 100644 --- a/test/exclude-members.test.js +++ b/test/exclude-members.test.js @@ -254,7 +254,10 @@ test('Verify that you actually get excluded from a group', async (t) => { t.pass("Bob can't post in the group anymore since he's excluded from it") ) - const bobGroups = await pull(bob.tribes2.list(), pull.collectAsPromise()) + const bobGroups = await pull( + bob.tribes2.list({ excluded: true }), + pull.collectAsPromise() + ) t.deepEquals( bobGroups, [{ id: groupId, excluded: true }],