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 readKeys when excluding #32

Merged
merged 3 commits into from
May 2, 2023
Merged
Show file tree
Hide file tree
Changes from all 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 @@ -72,7 +72,7 @@ on the `sbot.box2` namespace:
- `key` must be a buffer. The key can then be used for decrypting messages from the group, and if picked with `pickGroupWriteKey`, as a "recp" to encrypt messages to the group. Note that the keys are not persisted in this module.
- `scheme` _String_ - scheme of that encryption key (optional, there is only one option at the moment which we default to)
- `root` _MessageId_ the id of the `group/init` message
- `excludeGroupInfo(groupId, cb)`: Removes group info from a groupId, for instance if you or someone else has excluded you from one. Getting info about it will only return `{ excluded: true }`. Returns a promise if cb isn't provided.
- `excludeGroupInfo(groupId, cb)`: Removes the writeKey from a groupId and marks the group as excluded. Useful for instance if you or someone else has excluded you from the group. Getting info about the group will return the old group info minus the `writeKey` and plus an `excluded` field set to `true`. Returns a promise if cb isn't provided.
- `listGroupIds({ live, excluded }) => PullStream<groupIds>`: Returns a pull stream of all groupIds whose messages you're able to decrypt. If `live` is true then it returns a pull stream with all previous but also all future group ids. If `excluded` is true then it returns only excluded groups (groups you've been excluded from) instead of only non-excluded groups.
- `pickGroupWriteKey(groupId, pickedKey, cb)`: Picks one of the group's current read keys to be the group's write key. The picked key needs to exactly match one of the read keys. Returns a promise if cb isn't provided.
- `groupId`: cloaked message id or uri encoded group id.
Expand Down
5 changes: 3 additions & 2 deletions format.js
Original file line number Diff line number Diff line change
Expand Up @@ -291,8 +291,9 @@ function makeEncryptionFormat() {
const authorBFE = BFE.encode(authorId)
const previousBFE = BFE.encode(opts.previous)

const groupKeys = keyring.group
.listSync()
const groups = keyring.group.listSync()
const excludedGroups = keyring.group.listSync({ excluded: true })
const groupKeys = [...groups, ...excludedGroups]
.map(keyring.group.get)
.map((groupInfo) => groupInfo.readKeys)
.flat()
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"pull-defer": "^0.2.3",
"pull-stream": "^3.6.14",
"ssb-bfe": "^3.7.0",
"ssb-keyring": "^5.3.0",
"ssb-keyring": "^5.3.2",
"ssb-private-group-keys": "^1.1.1",
"ssb-ref": "^2.16.0",
"ssb-uri2": "^2.4.1"
Expand Down
39 changes: 39 additions & 0 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,45 @@ test('decrypt as group recipient', (t) => {
})
})

test('decrypt as group recipient, still works after exclusion', (t) => {
const box2 = Box2()
const keys = ssbKeys.generate(null, 'alice', 'buttwoo-v1')

box2.setup({ keys }, () => {
const groupId = '%Lihvp+fMdt5CihjbOY6eZc0qCe0eKsrN2wfgXV2E3PM=.cloaked'
box2.addGroupInfo(groupId, {
key: Buffer.from(
'30720d8f9cbf37f6d7062826f6decac93e308060a8aaaa77e6a4747f40ee1a76',
'hex'
),
})

const opts = {
keys,
content: { type: 'post', text: 'super secret' },
previous: null,
timestamp: 12345678900,
tag: buttwoo.tags.SSB_FEED,
hmacKey: null,
recps: [groupId, ssbKeys.generate(null, '2').id],
}

const plaintext = buttwoo.toPlaintextBuffer(opts)
t.true(Buffer.isBuffer(plaintext), 'plaintext is a buffer')

const ciphertext = box2.encrypt(plaintext, opts)

box2.excludeGroupInfo(groupId, (err) => {
if (err) t.fail(err)

const decrypted = box2.decrypt(ciphertext, { ...opts, author: keys.id })
t.deepEqual(decrypted, plaintext, 'decrypted plaintext is the same')

t.end()
})
})
})

test('cannot decrypt own DM after we changed our own DM keys', (t) => {
const box2 = Box2()
const keys = ssbKeys.generate(null, 'alice', 'buttwoo-v1')
Expand Down
9 changes: 7 additions & 2 deletions test/tribes.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const SecretStack = require('secret-stack')
const caps = require('ssb-caps')
const ref = require('ssb-ref')
const pull = require('pull-stream')
const { keySchemes } = require('private-group-spec')

function readyDir(dir) {
rimraf.sync(dir)
Expand Down Expand Up @@ -369,8 +370,12 @@ test('You can exclude info from a group', async (t) => {

t.deepEquals(
groupInfo,
{ excluded: true },
'excluding group info just leaves excluded: true'
{
readKeys: [{ key: testkey, scheme: keySchemes.private_group }],
root: testRoot,
excluded: true,
},
'excluding group info removes writeKey and adds excluded: true'
)

const listNotExcluded = await pull(
Expand Down