mirror of https://codeberg.org/pzp/pzp-db.git
Prune the accountTangle in getSigkeysInAccount (#23)
This commit is contained in:
parent
d332308104
commit
e40c7cff09
26
lib/index.js
26
lib/index.js
|
@ -376,11 +376,11 @@ function initDB(peer, config) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Pick<RecPresent, 'id' | 'msg'>} rec
|
* @param {Pick<RecPresent, 'id' | 'msg'>} rec
|
||||||
* @returns {Tangle | null}
|
* @returns {DBTangle | null}
|
||||||
*/
|
*/
|
||||||
function getAccountTangle(rec) {
|
function getAccountTangle(rec) {
|
||||||
const accountID = getAccountID(rec)
|
const accountID = getAccountID(rec)
|
||||||
let accountTangle = /** @type {Tangle | null} */ (null)
|
let accountTangle = /** @type {DBTangle | null} */ (null)
|
||||||
if (accountID) {
|
if (accountID) {
|
||||||
accountTangle = new DBTangle(accountID, records(), get)
|
accountTangle = new DBTangle(accountID, records(), get)
|
||||||
if (rec.id === accountID) {
|
if (rec.id === accountID) {
|
||||||
|
@ -397,15 +397,20 @@ function initDB(peer, config) {
|
||||||
* Find which sigkeys are authorized to sign this msg given the account.
|
* Find which sigkeys are authorized to sign this msg given the account.
|
||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
* @param {Tangle | null} accountTangle
|
* @param {DBTangle | null} accountTangle
|
||||||
|
* @param {Msg['metadata']['accountTips']} accountTipsInMsg
|
||||||
* @returns {Set<string>}
|
* @returns {Set<string>}
|
||||||
*/
|
*/
|
||||||
function getSigkeysInAccount(accountTangle) {
|
function getSigkeysInAccount(accountTangle, accountTipsInMsg) {
|
||||||
const sigkeys = new Set()
|
const sigkeys = new Set()
|
||||||
if (!accountTangle) return sigkeys
|
if (!accountTangle) return sigkeys
|
||||||
// TODO: prune the accountTangle beyond msg.metadata.accountTips
|
|
||||||
for (const msgID of accountTangle.topoSort()) {
|
const prunedTangle = accountTangle.slice(
|
||||||
const msg = get(msgID)
|
undefined,
|
||||||
|
accountTipsInMsg ?? undefined
|
||||||
|
)
|
||||||
|
|
||||||
|
for (const msg of prunedTangle) {
|
||||||
if (!msg?.data) continue
|
if (!msg?.data) continue
|
||||||
/** @type {AccountData} */
|
/** @type {AccountData} */
|
||||||
const data = msg.data
|
const data = msg.data
|
||||||
|
@ -461,14 +466,17 @@ function initDB(peer, config) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Identify the account and its sigkeys:
|
// Identify the account and its sigkeys:
|
||||||
/** @type {Tangle | null} */
|
/** @type {DBTangle | null} */
|
||||||
let accountTangle
|
let accountTangle
|
||||||
try {
|
try {
|
||||||
accountTangle = getAccountTangle(rec)
|
accountTangle = getAccountTangle(rec)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return new Error('Unknown account tangle owning this msg', { cause: err })
|
return new Error('Unknown account tangle owning this msg', { cause: err })
|
||||||
}
|
}
|
||||||
const sigkeys = getSigkeysInAccount(accountTangle)
|
const sigkeys = getSigkeysInAccount(
|
||||||
|
accountTangle,
|
||||||
|
rec.msg.metadata.accountTips
|
||||||
|
)
|
||||||
|
|
||||||
// Don't accept ghosts to come back, unless they are trail msgs
|
// Don't accept ghosts to come back, unless they are trail msgs
|
||||||
if (!!rec.msg.data && ghosts.read(tangleID).has(rec.id)) {
|
if (!!rec.msg.data && ghosts.read(tangleID).has(rec.id)) {
|
||||||
|
|
|
@ -306,7 +306,7 @@ function isRoot(msg) {
|
||||||
* @returns {msg is FeedMsg<T>}
|
* @returns {msg is FeedMsg<T>}
|
||||||
*/
|
*/
|
||||||
function isFeedMsg(msg) {
|
function isFeedMsg(msg) {
|
||||||
const {account, accountTips} = msg.metadata
|
const { account, accountTips } = msg.metadata
|
||||||
return Array.isArray(accountTips) && account !== 'self' && account !== 'any'
|
return Array.isArray(accountTips) && account !== 'self' && account !== 'any'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -235,6 +235,6 @@ test('MsgV4.Tangle can add msgs in random order', (t) => {
|
||||||
tangle.add(msgID2, msg2)
|
tangle.add(msgID2, msg2)
|
||||||
tangle.add(msgID1, msg1)
|
tangle.add(msgID1, msg1)
|
||||||
|
|
||||||
assert.deepEqual(tangle.topoSort(), [mootAID, msgID1, msgID2]);
|
assert.deepEqual(tangle.topoSort(), [mootAID, msgID1, msgID2])
|
||||||
assert.deepEqual([...tangle.tips], [msgID2], 'tangle tips')
|
assert.deepEqual([...tangle.tips], [msgID2], 'tangle tips')
|
||||||
})
|
})
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
const test = require('node:test')
|
||||||
|
const assert = require('node:assert')
|
||||||
|
const path = require('node:path')
|
||||||
|
const p = require('node:util').promisify
|
||||||
|
const os = require('node:os')
|
||||||
|
const rimraf = require('rimraf')
|
||||||
|
const Keypair = require('ppppp-keypair')
|
||||||
|
const { createPeer } = require('./util')
|
||||||
|
const MsgV4 = require('../lib/msg-v4')
|
||||||
|
|
||||||
|
const DIR = path.join(os.tmpdir(), 'ppppp-db-sigkeys')
|
||||||
|
const DIR2 = path.join(os.tmpdir(), 'ppppp-db-sigkeys2')
|
||||||
|
rimraf.sync(DIR)
|
||||||
|
rimraf.sync(DIR2)
|
||||||
|
|
||||||
|
test('sigkeys', async (t) => {
|
||||||
|
await t.test(
|
||||||
|
"Can't add msg that is signed by key newer than what accountTips points to",
|
||||||
|
async () => {
|
||||||
|
const keypair1 = Keypair.generate('ed25519', 'alice')
|
||||||
|
const keypair2 = Keypair.generate('ed25519', 'alice2')
|
||||||
|
const keypairOther = Keypair.generate('ed25519', 'bob')
|
||||||
|
|
||||||
|
const peer = createPeer({ keypair: keypair1, path: DIR })
|
||||||
|
const peerOther = createPeer({ keypair: keypairOther, path: DIR2 })
|
||||||
|
|
||||||
|
await peer.db.loaded()
|
||||||
|
await peerOther.db.loaded()
|
||||||
|
|
||||||
|
const account = await p(peer.db.account.create)({
|
||||||
|
keypair: keypair1,
|
||||||
|
subdomain: 'person',
|
||||||
|
})
|
||||||
|
const accountMsg0 = peer.db.get(account)
|
||||||
|
|
||||||
|
const consent = peer.db.account.consent({ account, keypair: keypair2 })
|
||||||
|
|
||||||
|
const accountRec1 = await p(peer.db.account.add)({
|
||||||
|
account,
|
||||||
|
keypair: keypair2,
|
||||||
|
consent,
|
||||||
|
powers: ['external-encryption'],
|
||||||
|
})
|
||||||
|
|
||||||
|
const goodRec = await p(peer.db.feed.publish)({
|
||||||
|
account,
|
||||||
|
domain: 'post',
|
||||||
|
data: { text: 'potatoGood' },
|
||||||
|
keypair: keypair2,
|
||||||
|
})
|
||||||
|
|
||||||
|
const postMootId = peer.db.feed.getID(account, 'post')
|
||||||
|
const postMootMsg = peer.db.get(postMootId)
|
||||||
|
|
||||||
|
const tangle = new MsgV4.Tangle(postMootId)
|
||||||
|
tangle.add(postMootId, postMootMsg)
|
||||||
|
tangle.add(goodRec.id, goodRec.msg)
|
||||||
|
const badMsg = MsgV4.create({
|
||||||
|
account,
|
||||||
|
accountTips: [account], // intentionally excluding keypair2
|
||||||
|
domain: 'post',
|
||||||
|
keypair: keypair2, // intentionally using newer key than accountTips points to
|
||||||
|
tangles: {
|
||||||
|
[postMootId]: tangle,
|
||||||
|
},
|
||||||
|
data: { text: 'potato' },
|
||||||
|
})
|
||||||
|
await assert.rejects(
|
||||||
|
p(peer.db.add)(badMsg, postMootId),
|
||||||
|
/add\(\) failed to verify msg/,
|
||||||
|
"Shouldn't be able to add() own bad msg"
|
||||||
|
)
|
||||||
|
|
||||||
|
await p(peerOther.db.add)(accountMsg0, account)
|
||||||
|
await p(peerOther.db.add)(accountRec1.msg, account)
|
||||||
|
await p(peerOther.db.add)(postMootMsg, postMootId)
|
||||||
|
await p(peerOther.db.add)(goodRec.msg, postMootId)
|
||||||
|
await assert.rejects(
|
||||||
|
p(peerOther.db.add)(badMsg, postMootId),
|
||||||
|
/add\(\) failed to verify msg/,
|
||||||
|
"Shouldn't be able to add() someone else's bad msg"
|
||||||
|
)
|
||||||
|
|
||||||
|
await p(peer.close)()
|
||||||
|
await p(peerOther.close)()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
Loading…
Reference in New Issue