mirror of https://codeberg.org/pzp/pzp-db.git
rename identity to account
This commit is contained in:
parent
557ea2252c
commit
af4325ef94
212
lib/index.js
212
lib/index.js
|
@ -11,8 +11,8 @@ const Obz = require('obz')
|
|||
const Keypair = require('ppppp-keypair')
|
||||
const MsgV3 = require('./msg-v3')
|
||||
const {
|
||||
SIGNATURE_TAG_IDENTITY_ADD,
|
||||
IDENTITY_SELF,
|
||||
SIGNATURE_TAG_ACCOUNT_ADD,
|
||||
ACCOUNT_SELF,
|
||||
} = require('./msg-v3/constants')
|
||||
const { ReadyGate } = require('./utils')
|
||||
const { decrypt } = require('./encryption')
|
||||
|
@ -22,8 +22,8 @@ const { decrypt } = require('./encryption')
|
|||
* @typedef {import('ppppp-keypair').KeypairPublicSlice} KeypairPublicSlice
|
||||
* @typedef {import('ppppp-keypair').KeypairPrivateSlice} KeypairPrivateSlice
|
||||
* @typedef {import('./msg-v3').Msg} Msg
|
||||
* @typedef {import('./msg-v3').IdentityData} IdentityData
|
||||
* @typedef {import('./msg-v3').IdentityPower} IdentityPower
|
||||
* @typedef {import('./msg-v3').AccountData} AccountData
|
||||
* @typedef {import('./msg-v3').AccountPower} AccountPower
|
||||
* @typedef {import('./encryption').EncryptionFormat} EncryptionFormat
|
||||
*
|
||||
* @typedef {Buffer | Uint8Array} B4A
|
||||
|
@ -281,21 +281,21 @@ function initDB(peer, config) {
|
|||
// row, because it creates a new Map() each time. Perhaps with QuickLRU
|
||||
const tangle = new DBTangle(tangleRootHash, records())
|
||||
|
||||
// Find which pubkeys are authorized to sign this msg given the identity:
|
||||
// Find which pubkeys are authorized to sign this msg given the account:
|
||||
const pubkeys = new Set()
|
||||
const identity = getIdentityId(rec)
|
||||
let identityTangle = /** @type {DBTangle | null} */ (null)
|
||||
if (identity && !MsgV3.isRoot(msg)) {
|
||||
identityTangle = new DBTangle(identity, records())
|
||||
if (!identityTangle.has(identity)) {
|
||||
const accountID = getAccountID(rec)
|
||||
let accountTangle = /** @type {DBTangle | null} */ (null)
|
||||
if (accountID && !MsgV3.isRoot(msg)) {
|
||||
accountTangle = new DBTangle(accountID, records())
|
||||
if (!accountTangle.has(accountID)) {
|
||||
// prettier-ignore
|
||||
return cb(new Error('add() failed because the identity tangle is unknown'))
|
||||
return cb(new Error('add() failed because the account tangle is unknown'))
|
||||
}
|
||||
// TODO: prune the identityTangle beyond msg.metadata.identityTips
|
||||
for (const msgHash of identityTangle.topoSort()) {
|
||||
// TODO: prune the accountTangle beyond msg.metadata.accountTips
|
||||
for (const msgHash of accountTangle.topoSort()) {
|
||||
const msg = get(msgHash)
|
||||
if (!msg?.data) continue
|
||||
/** @type {IdentityData} */
|
||||
/** @type {AccountData} */
|
||||
const data = msg.data
|
||||
if (data.action !== 'add') continue
|
||||
if (data.add.key.purpose !== 'sig') continue
|
||||
|
@ -309,14 +309,14 @@ function initDB(peer, config) {
|
|||
return cb(new Error('add() failed msg validation', { cause: err }))
|
||||
}
|
||||
|
||||
// Identity tangle related validations
|
||||
if (msg.metadata.identity === IDENTITY_SELF && identityTangle) {
|
||||
/** @type {IdentityData} */
|
||||
// Account tangle related validations
|
||||
if (msg.metadata.account === ACCOUNT_SELF && accountTangle) {
|
||||
/** @type {AccountData} */
|
||||
const data = msg.data
|
||||
if (data.action === 'add') {
|
||||
// Does this msg.pubkey have the "add" power?
|
||||
const keypair = { curve: 'ed25519', public: msg.pubkey }
|
||||
const powers = getIdentityPowers(identityTangle, keypair)
|
||||
const powers = getAccountPowers(accountTangle, keypair)
|
||||
if (!powers.has('add')) {
|
||||
// prettier-ignore
|
||||
return cb(new Error('add() failed because this msg.pubkey does not have "add" power'))
|
||||
|
@ -333,17 +333,17 @@ function initDB(peer, config) {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param {{ keypair?: Keypair; identity: string; domain: string; }} opts
|
||||
* @param {{ keypair?: Keypair; account: string; domain: string; }} opts
|
||||
* @param {CB<string>} cb
|
||||
*/
|
||||
function initializeFeed(opts, cb) {
|
||||
const keypair = opts.keypair ?? config.keypair
|
||||
const { identity, domain } = opts
|
||||
const { account, domain } = opts
|
||||
|
||||
const feedRootHash = getFeedId(identity, domain)
|
||||
const feedRootHash = getFeedId(account, domain)
|
||||
if (feedRootHash) return cb(null, feedRootHash)
|
||||
|
||||
const feedRoot = MsgV3.createRoot(identity, domain, keypair)
|
||||
const feedRoot = MsgV3.createRoot(account, domain, keypair)
|
||||
add(feedRoot, MsgV3.getMsgHash(feedRoot), (err, rec) => {
|
||||
// prettier-ignore
|
||||
if (err) return cb(new Error('initializeFeed() failed to add root', { cause: err }));
|
||||
|
@ -353,27 +353,27 @@ function initDB(peer, config) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Public the identity ID from the given record.
|
||||
* Public the account ID from the given record.
|
||||
*
|
||||
* @param {Pick<RecPresent, 'msg' | 'hash'>} rec
|
||||
* @returns {string | null}
|
||||
*/
|
||||
function getIdentityId(rec) {
|
||||
function getAccountID(rec) {
|
||||
if (!rec.msg) return null
|
||||
if (rec.msg.metadata.identity === IDENTITY_SELF) {
|
||||
if (rec.msg.metadata.account === ACCOUNT_SELF) {
|
||||
for (const tangleId in rec.msg.metadata.tangles) {
|
||||
return tangleId
|
||||
}
|
||||
return rec.hash
|
||||
} else if (rec.msg.metadata.identity) {
|
||||
return rec.msg.metadata.identity
|
||||
} else if (rec.msg.metadata.account) {
|
||||
return rec.msg.metadata.account
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the identity that contains this `keypair` (or the implicit
|
||||
* Find the account that contains this `keypair` (or the implicit
|
||||
* config.keypair) under the given `domain`.
|
||||
*
|
||||
* @public
|
||||
|
@ -383,9 +383,9 @@ function initDB(peer, config) {
|
|||
* }} opts
|
||||
* @param {CB<string>} cb
|
||||
*/
|
||||
function findIdentity(opts, cb) {
|
||||
function findAccount(opts, cb) {
|
||||
// prettier-ignore
|
||||
if (!opts.domain) return cb(new Error('identity.find() requires a `domain`'))
|
||||
if (!opts.domain) return cb(new Error('account.find() requires a `domain`'))
|
||||
const keypair = opts?.keypair ?? config.keypair
|
||||
const domain = opts.domain
|
||||
|
||||
|
@ -394,43 +394,43 @@ function initDB(peer, config) {
|
|||
if (!rec) continue
|
||||
if (!rec.msg) continue
|
||||
if (!rec.msg.data) continue
|
||||
if (rec.msg.metadata.identity !== IDENTITY_SELF) continue
|
||||
if (rec.msg.metadata.account !== ACCOUNT_SELF) continue
|
||||
if (rec.msg.metadata.domain !== domain) continue
|
||||
const data = /** @type {IdentityData} */ (rec.msg.data)
|
||||
const data = /** @type {AccountData} */ (rec.msg.data)
|
||||
if (data.action === 'add' && data.add.key.bytes === keypair.public) {
|
||||
const identityId = getIdentityId(rec)
|
||||
if (identityId) {
|
||||
cb(null, identityId)
|
||||
const accountId = getAccountID(rec)
|
||||
if (accountId) {
|
||||
cb(null, accountId)
|
||||
} else {
|
||||
// prettier-ignore
|
||||
cb(new Error(`identity.find() failed to find ID in ${JSON.stringify(rec.msg)}`))
|
||||
cb(new Error(`account.find() failed to find ID in ${JSON.stringify(rec.msg)}`))
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
// prettier-ignore
|
||||
const err = new Error(`identity.find() failed for pubkey=${keypair.public} domain=${domain}`, { cause: 'ENOENT' });
|
||||
const err = new Error(`account.find() failed for pubkey=${keypair.public} domain=${domain}`, { cause: 'ENOENT' });
|
||||
cb(err)
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this `identity` have this `keypair` (or the implicit config.keypair)?
|
||||
* Does this `account` have this `keypair` (or the implicit config.keypair)?
|
||||
*
|
||||
* @public
|
||||
* @param {{
|
||||
* keypair?: KeypairPublicSlice;
|
||||
* identity: string;
|
||||
* account: string;
|
||||
* }} opts
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function identityHas(opts) {
|
||||
function accountHas(opts) {
|
||||
const keypair = opts?.keypair ?? config.keypair
|
||||
|
||||
const identityTangle = new DBTangle(opts.identity, records())
|
||||
for (const msgHash of identityTangle.topoSort()) {
|
||||
const accountTangle = new DBTangle(opts.account, records())
|
||||
for (const msgHash of accountTangle.topoSort()) {
|
||||
const msg = get(msgHash)
|
||||
if (!msg?.data) continue
|
||||
/** @type {IdentityData} */
|
||||
/** @type {AccountData} */
|
||||
const data = msg.data
|
||||
if (data.action !== 'add') continue
|
||||
if (data.add.key.algorithm !== keypair.curve) continue
|
||||
|
@ -442,7 +442,7 @@ function initDB(peer, config) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Create an identity (root msg) for the given `keypair` (or the implicit
|
||||
* Create an account (root msg) for the given `keypair` (or the implicit
|
||||
* config.keypair) under this `domain`.
|
||||
*
|
||||
* @public
|
||||
|
@ -453,23 +453,23 @@ function initDB(peer, config) {
|
|||
* }} opts
|
||||
* @param {CB<string>} cb
|
||||
*/
|
||||
function createIdentity(opts, cb) {
|
||||
function createAccount(opts, cb) {
|
||||
// prettier-ignore
|
||||
if (!opts.domain) return cb(new Error('identity.create() requires a `domain`'))
|
||||
if (!opts.domain) return cb(new Error('account.create() requires a `domain`'))
|
||||
const keypair = opts?.keypair ?? config.keypair
|
||||
const domain = opts.domain
|
||||
|
||||
let msg
|
||||
try {
|
||||
msg = MsgV3.createIdentity(keypair, domain, opts?._nonce)
|
||||
msg = MsgV3.createAccount(keypair, domain, opts?._nonce)
|
||||
} catch (err) {
|
||||
return cb(new Error('identity.create() failed', { cause: err }))
|
||||
return cb(new Error('account.create() failed', { cause: err }))
|
||||
}
|
||||
const msgHash = MsgV3.getMsgHash(msg)
|
||||
|
||||
logAppend(msgHash, msg, (err, rec) => {
|
||||
// prettier-ignore
|
||||
if (err) return cb(new Error('identity.create() failed in the log', { cause: err }))
|
||||
if (err) return cb(new Error('account.create() failed in the log', { cause: err }))
|
||||
onRecordAdded.set(rec)
|
||||
const recHash = /** @type {string} */ (rec.hash)
|
||||
cb(null, recHash)
|
||||
|
@ -477,7 +477,7 @@ function initDB(peer, config) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Find or create an identity (root msg) for the given `keypair` (or the
|
||||
* Find or create an account (root msg) for the given `keypair` (or the
|
||||
* implicit config.keypair) under this `domain`.
|
||||
*
|
||||
* @public
|
||||
|
@ -488,29 +488,29 @@ function initDB(peer, config) {
|
|||
* }} opts
|
||||
* @param {CB<string>} cb
|
||||
*/
|
||||
function findOrCreateIdentity(opts, cb) {
|
||||
findIdentity(opts, (err, identityId) => {
|
||||
function findOrCreateAccount(opts, cb) {
|
||||
findAccount(opts, (err, accountID) => {
|
||||
if (err?.cause === 'ENOENT') {
|
||||
createIdentity(opts, cb)
|
||||
createAccount(opts, cb)
|
||||
} else if (err) {
|
||||
cb(err)
|
||||
} else {
|
||||
cb(null, identityId)
|
||||
cb(null, accountID)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {DBTangle} identityTangle
|
||||
* @param {DBTangle} accountTangle
|
||||
* @param {KeypairPublicSlice} keypair
|
||||
* @returns {Set<IdentityPower>}
|
||||
* @returns {Set<AccountPower>}
|
||||
*/
|
||||
function getIdentityPowers(identityTangle, keypair) {
|
||||
function getAccountPowers(accountTangle, keypair) {
|
||||
const powers = new Set()
|
||||
for (const msgHash of identityTangle.topoSort()) {
|
||||
for (const msgHash of accountTangle.topoSort()) {
|
||||
const msg = get(msgHash)
|
||||
if (!msg?.data) continue
|
||||
/** @type {IdentityData} */
|
||||
/** @type {AccountData} */
|
||||
const data = msg.data
|
||||
if (data.action !== 'add') continue
|
||||
if (data.add.key.algorithm !== keypair.curve) continue
|
||||
|
@ -526,22 +526,22 @@ function initDB(peer, config) {
|
|||
|
||||
/**
|
||||
* Create a consent signature for the given `keypair` (or the implicit
|
||||
* config.keypair) to be added to the given `identity`.
|
||||
* config.keypair) to be added to the given `account`.
|
||||
*
|
||||
* @public
|
||||
* @param {{
|
||||
* keypair?: KeypairPrivateSlice;
|
||||
* identity: string;
|
||||
* account: string;
|
||||
* }} opts
|
||||
* @returns {string}
|
||||
*/
|
||||
function consentToIdentity(opts) {
|
||||
function consentToAccount(opts) {
|
||||
// prettier-ignore
|
||||
if (!opts.identity) throw new Error('identity.consent() requires an `identity`')
|
||||
if (!opts.account) throw new Error('account.consent() requires an `account`')
|
||||
const keypair = opts?.keypair ?? config.keypair
|
||||
|
||||
const signableBuf = b4a.from(
|
||||
SIGNATURE_TAG_IDENTITY_ADD + base58.decode(opts.identity),
|
||||
SIGNATURE_TAG_ACCOUNT_ADD + base58.decode(opts.account),
|
||||
'utf8'
|
||||
)
|
||||
return Keypair.sign(keypair, signableBuf)
|
||||
|
@ -549,13 +549,13 @@ function initDB(peer, config) {
|
|||
|
||||
/**
|
||||
* Add the given `keypair` (or the implicit config.keypair) to the given
|
||||
* `identity`, authorized by the given `consent` (or implicitly created on the
|
||||
* `account`, authorized by the given `consent` (or implicitly created on the
|
||||
* fly if the `keypair` contains the private key) with the following `powers`
|
||||
* (defaulting to no powers).
|
||||
*
|
||||
* @param {{
|
||||
* identity: string;
|
||||
* powers?: Array<IdentityPower>;
|
||||
* account: string;
|
||||
* powers?: Array<AccountPower>;
|
||||
* _disobey?: true;
|
||||
* } & ({
|
||||
* keypair: KeypairPublicSlice & {private?: never};
|
||||
|
@ -566,20 +566,20 @@ function initDB(peer, config) {
|
|||
* })} opts
|
||||
* @param {CB<Rec>} cb
|
||||
*/
|
||||
function addToIdentity(opts, cb) {
|
||||
if (!opts) return cb(new Error('identity.add() requires an `opts`'))
|
||||
function addToAccount(opts, cb) {
|
||||
if (!opts) return cb(new Error('account.add() requires an `opts`'))
|
||||
// prettier-ignore
|
||||
if (!opts.identity) return cb(new Error('identity.add() requires a `identity`'))
|
||||
if (!opts.account) return cb(new Error('account.add() requires a `account`'))
|
||||
// prettier-ignore
|
||||
if (!opts.keypair) return cb(new Error('identity.add() requires a `keypair`'))
|
||||
if (!opts.keypair) return cb(new Error('account.add() requires a `keypair`'))
|
||||
// prettier-ignore
|
||||
if (!opts.keypair.public) return cb(new Error('identity.add() requires a `keypair` with `public`'))
|
||||
if (!opts.keypair.public) return cb(new Error('account.add() requires a `keypair` with `public`'))
|
||||
let consent = /** @type {string} */ (opts.consent)
|
||||
if (typeof opts.consent === 'undefined') {
|
||||
if (opts.keypair.private) {
|
||||
consent = consentToIdentity(opts)
|
||||
consent = consentToAccount(opts)
|
||||
} else {
|
||||
return cb(new Error('identity.add() requires a `consent`'))
|
||||
return cb(new Error('account.add() requires a `consent`'))
|
||||
}
|
||||
}
|
||||
const obeying = !opts._disobey
|
||||
|
@ -588,20 +588,20 @@ function initDB(peer, config) {
|
|||
|
||||
// Verify consent:
|
||||
const signableBuf = b4a.from(
|
||||
SIGNATURE_TAG_IDENTITY_ADD + base58.decode(opts.identity)
|
||||
SIGNATURE_TAG_ACCOUNT_ADD + base58.decode(opts.account)
|
||||
)
|
||||
if (obeying && !Keypair.verify(addedKeypair, signableBuf, consent)) {
|
||||
// prettier-ignore
|
||||
return cb(new Error('identity.add() failed because the consent is invalid'))
|
||||
return cb(new Error('account.add() failed because the consent is invalid'))
|
||||
}
|
||||
|
||||
// Verify powers of the signingKeypair:
|
||||
const identityTangle = new DBTangle(opts.identity, records())
|
||||
const accountTangle = new DBTangle(opts.account, records())
|
||||
if (obeying) {
|
||||
const signingPowers = getIdentityPowers(identityTangle, signingKeypair)
|
||||
const signingPowers = getAccountPowers(accountTangle, signingKeypair)
|
||||
if (!signingPowers.has('add')) {
|
||||
// prettier-ignore
|
||||
return cb(new Error('identity.add() failed because the signing keypair does not have the "add" power'))
|
||||
return cb(new Error('account.add() failed because the signing keypair does not have the "add" power'))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -609,24 +609,24 @@ function initDB(peer, config) {
|
|||
if (obeying && opts.powers) {
|
||||
if (!Array.isArray(opts.powers)) {
|
||||
// prettier-ignore
|
||||
return cb(new Error('identity.add() failed because opts.powers is not an array'))
|
||||
return cb(new Error('account.add() failed because opts.powers is not an array'))
|
||||
}
|
||||
for (const power of opts.powers) {
|
||||
if (power !== 'add' && power !== 'del' && power !== 'box') {
|
||||
// prettier-ignore
|
||||
return cb(new Error(`identity.add() failed because opts.powers contains an unknown power "${power}"`))
|
||||
return cb(new Error(`account.add() failed because opts.powers contains an unknown power "${power}"`))
|
||||
}
|
||||
// TODO check against duplicates
|
||||
}
|
||||
}
|
||||
|
||||
const identityRoot = get(opts.identity)
|
||||
if (!identityRoot) {
|
||||
const accountRoot = get(opts.account)
|
||||
if (!accountRoot) {
|
||||
// prettier-ignore
|
||||
return cb(new Error(`identity.add() failed because the identity root "${opts.identity}" is unknown`))
|
||||
return cb(new Error(`account.add() failed because the account root "${opts.account}" is unknown`))
|
||||
}
|
||||
|
||||
/** @type {IdentityData} */
|
||||
/** @type {AccountData} */
|
||||
const data = {
|
||||
action: 'add',
|
||||
add: {
|
||||
|
@ -642,14 +642,14 @@ function initDB(peer, config) {
|
|||
|
||||
// Fill-in tangle opts:
|
||||
const fullOpts = {
|
||||
identity: IDENTITY_SELF,
|
||||
identityTips: null,
|
||||
account: ACCOUNT_SELF,
|
||||
accountTips: null,
|
||||
tangles: {
|
||||
[opts.identity]: identityTangle,
|
||||
[opts.account]: accountTangle,
|
||||
},
|
||||
keypair: signingKeypair,
|
||||
data,
|
||||
domain: identityRoot.metadata.domain,
|
||||
domain: accountRoot.metadata.domain,
|
||||
}
|
||||
|
||||
// Create the actual message:
|
||||
|
@ -657,13 +657,13 @@ function initDB(peer, config) {
|
|||
try {
|
||||
msg = MsgV3.create(fullOpts)
|
||||
} catch (err) {
|
||||
return cb(new Error('identity.add() failed', { cause: err }))
|
||||
return cb(new Error('account.add() failed', { cause: err }))
|
||||
}
|
||||
const msgHash = MsgV3.getMsgHash(msg)
|
||||
|
||||
logAppend(msgHash, msg, (err, rec) => {
|
||||
// prettier-ignore
|
||||
if (err) return cb(new Error('identity.add() failed to append the log', { cause: err }))
|
||||
if (err) return cb(new Error('account.add() failed to append the log', { cause: err }))
|
||||
onRecordAdded.set(rec)
|
||||
cb(null, rec)
|
||||
})
|
||||
|
@ -675,7 +675,7 @@ function initDB(peer, config) {
|
|||
* encryptionFormat?: string;
|
||||
* data: any;
|
||||
* domain: string;
|
||||
* identity: string;
|
||||
* account: string;
|
||||
* tangles?: Array<string>;
|
||||
* }} opts
|
||||
* @param {CB<Rec>} cb
|
||||
|
@ -692,8 +692,8 @@ function initDB(peer, config) {
|
|||
}
|
||||
if (!opts.data) return cb(new Error('feed.publish() requires a `data`'))
|
||||
if (!opts.domain) return cb(new Error('feed.publish() requires a `domain`'))
|
||||
if (!opts.identity)
|
||||
return cb(new Error('feed.publish() requires a `identity`'))
|
||||
if (!opts.account)
|
||||
return cb(new Error('feed.publish() requires a `account`'))
|
||||
|
||||
initializeFeed(opts, (err, feedRootHash) => {
|
||||
// prettier-ignore
|
||||
|
@ -703,9 +703,9 @@ function initDB(peer, config) {
|
|||
const tangleTemplates = opts.tangles ?? []
|
||||
tangleTemplates.push(feedRootHash)
|
||||
const tangles = populateTangles(tangleTemplates)
|
||||
const identityTangle = new DBTangle(opts.identity, records())
|
||||
const identityTips = [...identityTangle.getTips()]
|
||||
const fullOpts = { ...opts, tangles, identityTips, keypair }
|
||||
const accountTangle = new DBTangle(opts.account, records())
|
||||
const accountTips = [...accountTangle.getTips()]
|
||||
const fullOpts = { ...opts, tangles, accountTips, keypair }
|
||||
|
||||
// If opts ask for encryption, encrypt and put ciphertext in opts.data
|
||||
const recps = fullOpts.data.recps
|
||||
|
@ -763,9 +763,9 @@ function initDB(peer, config) {
|
|||
* @param {string} findDomain
|
||||
*/
|
||||
function getFeedId(id, findDomain) {
|
||||
const findIdentity = MsgV3.stripIdentity(id)
|
||||
const findAccount = MsgV3.stripAccount(id)
|
||||
for (const rec of records()) {
|
||||
if (rec.msg && MsgV3.isFeedRoot(rec.msg, findIdentity, findDomain)) {
|
||||
if (rec.msg && MsgV3.isFeedRoot(rec.msg, findAccount, findDomain)) {
|
||||
return rec.hash
|
||||
}
|
||||
}
|
||||
|
@ -851,13 +851,13 @@ function initDB(peer, config) {
|
|||
installEncryptionFormat,
|
||||
loaded,
|
||||
add,
|
||||
identity: {
|
||||
find: findIdentity,
|
||||
create: createIdentity,
|
||||
findOrCreate: findOrCreateIdentity,
|
||||
add: addToIdentity,
|
||||
consent: consentToIdentity,
|
||||
has: identityHas,
|
||||
account: {
|
||||
find: findAccount,
|
||||
create: createAccount,
|
||||
findOrCreate: findOrCreateAccount,
|
||||
add: addToAccount,
|
||||
consent: consentToAccount,
|
||||
has: accountHas,
|
||||
},
|
||||
feed: {
|
||||
publish: publishToFeed,
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
module.exports = {
|
||||
/** @type {'self'} */
|
||||
IDENTITY_SELF: 'self',
|
||||
ACCOUNT_SELF: 'self',
|
||||
|
||||
/** @type {'any'} */
|
||||
IDENTITY_ANY: 'any',
|
||||
ACCOUNT_ANY: 'any',
|
||||
|
||||
SIGNATURE_TAG_MSG_V3: ':msg-v3:',
|
||||
SIGNATURE_TAG_IDENTITY_ADD: ':identity-add:',
|
||||
SIGNATURE_TAG_ACCOUNT_ADD: ':account-add:',
|
||||
}
|
||||
|
|
|
@ -45,12 +45,12 @@ function getMsgHash(x) {
|
|||
* @returns {string}
|
||||
*/
|
||||
function getMsgId(msg) {
|
||||
const { identity, domain } = msg.metadata
|
||||
const { account, domain } = msg.metadata
|
||||
const msgHash = getMsgHash(msg)
|
||||
if (domain) {
|
||||
return `ppppp:message/v3/${identity}/${domain}/${msgHash}`
|
||||
return `ppppp:message/v3/${account}/${domain}/${msgHash}`
|
||||
} else {
|
||||
return `ppppp:message/v3/${identity}/${msgHash}`
|
||||
return `ppppp:message/v3/${account}/${msgHash}`
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ const stringify = require('json-canon')
|
|||
const Keypair = require('ppppp-keypair')
|
||||
// @ts-ignore
|
||||
const union = require('set.prototype.union')
|
||||
const { stripIdentity } = require('./strip')
|
||||
const { stripAccount } = require('./strip')
|
||||
const isFeedRoot = require('./is-feed-root')
|
||||
const { getMsgId, getMsgHash } = require('./get-msg-id')
|
||||
const representData = require('./represent-data')
|
||||
|
@ -18,8 +18,8 @@ const {
|
|||
} = require('./validation')
|
||||
const Tangle = require('./tangle')
|
||||
const {
|
||||
IDENTITY_SELF,
|
||||
IDENTITY_ANY,
|
||||
ACCOUNT_SELF,
|
||||
ACCOUNT_ANY,
|
||||
SIGNATURE_TAG_MSG_V3,
|
||||
} = require('./constants')
|
||||
const { isEmptyObject } = require('./util')
|
||||
|
@ -43,8 +43,8 @@ const { isEmptyObject } = require('./util')
|
|||
* metadata: {
|
||||
* dataHash: string | null;
|
||||
* dataSize: number;
|
||||
* identity: string | (typeof IDENTITY_SELF) | (typeof IDENTITY_ANY);
|
||||
* identityTips: Array<string> | null;
|
||||
* account: string | (typeof ACCOUNT_SELF) | (typeof ACCOUNT_ANY);
|
||||
* accountTips: Array<string> | null;
|
||||
* tangles: Record<string, TangleMetadata>;
|
||||
* domain: string;
|
||||
* v: 3;
|
||||
|
@ -54,23 +54,12 @@ const { isEmptyObject } = require('./util')
|
|||
* }} Msg
|
||||
*
|
||||
* @typedef {{
|
||||
* action: 'add', add: IdentityAdd
|
||||
* action: 'add', add: AccountAdd
|
||||
* } | {
|
||||
* action: 'del', del: IdentityDel
|
||||
* }} IdentityData
|
||||
* action: 'del', del: AccountDel
|
||||
* }} AccountData
|
||||
*
|
||||
* @typedef {'add' | 'del' | 'box'} IdentityPower
|
||||
*
|
||||
* @typedef {{
|
||||
* key: IdentityKey;
|
||||
* nonce?: string;
|
||||
* consent?: string;
|
||||
* powers?: Array<IdentityPower>;
|
||||
* }} IdentityAdd
|
||||
*
|
||||
* @typedef {{
|
||||
* key: IdentityKey;
|
||||
* }} IdentityDel
|
||||
* @typedef {'add' | 'del' | 'box'} AccountPower
|
||||
*
|
||||
* @typedef {{
|
||||
* purpose: 'sig';
|
||||
|
@ -84,14 +73,25 @@ const { isEmptyObject } = require('./util')
|
|||
* bytes: string;
|
||||
* }} BoxKey;
|
||||
*
|
||||
* @typedef {SigKey | BoxKey} IdentityKey
|
||||
* @typedef {SigKey | BoxKey} AccountKey
|
||||
*
|
||||
* @typedef {{
|
||||
* key: AccountKey;
|
||||
* nonce?: string;
|
||||
* consent?: string;
|
||||
* powers?: Array<AccountPower>;
|
||||
* }} AccountAdd
|
||||
*
|
||||
* @typedef {{
|
||||
* key: AccountKey;
|
||||
* }} AccountDel
|
||||
*
|
||||
* @typedef {{
|
||||
* data: any;
|
||||
* domain: string;
|
||||
* keypair: Keypair;
|
||||
* identity: string | (typeof IDENTITY_SELF) | (typeof IDENTITY_ANY);
|
||||
* identityTips: Array<string> | null;
|
||||
* account: string | (typeof ACCOUNT_SELF) | (typeof ACCOUNT_ANY);
|
||||
* accountTips: Array<string> | null;
|
||||
* tangles: Record<string, Tangle>;
|
||||
* }} CreateOpts
|
||||
*/
|
||||
|
@ -108,8 +108,8 @@ function getFeedRootHash(id, domain) {
|
|||
metadata: {
|
||||
dataHash: null,
|
||||
dataSize: 0,
|
||||
identity: stripIdentity(id),
|
||||
identityTips: null,
|
||||
account: stripAccount(id),
|
||||
accountTips: null,
|
||||
tangles: {},
|
||||
domain,
|
||||
v: 3,
|
||||
|
@ -139,8 +139,8 @@ function create(opts) {
|
|||
if (!opts.tangles) throw new Error('opts.tangles is required')
|
||||
|
||||
const [dataHash, dataSize] = representData(opts.data)
|
||||
const identity = opts.identity
|
||||
const identityTips = opts.identityTips ? opts.identityTips.sort() : null
|
||||
const account = opts.account
|
||||
const accountTips = opts.accountTips ? opts.accountTips.sort() : null
|
||||
|
||||
const tangles = /** @type {Msg['metadata']['tangles']} */ ({})
|
||||
if (opts.tangles) {
|
||||
|
@ -164,8 +164,8 @@ function create(opts) {
|
|||
metadata: {
|
||||
dataHash,
|
||||
dataSize,
|
||||
identity,
|
||||
identityTips,
|
||||
account,
|
||||
accountTips,
|
||||
tangles,
|
||||
domain: opts.domain,
|
||||
v: 3,
|
||||
|
@ -200,8 +200,8 @@ function createRoot(id, domain, keypair) {
|
|||
metadata: {
|
||||
dataHash: null,
|
||||
dataSize: 0,
|
||||
identity: id,
|
||||
identityTips: null,
|
||||
account: id,
|
||||
accountTips: null,
|
||||
tangles: {},
|
||||
domain,
|
||||
v: 3,
|
||||
|
@ -229,8 +229,8 @@ function getRandomNonce() {
|
|||
* @param {string | (() => string)} nonce
|
||||
* @returns {Msg}
|
||||
*/
|
||||
function createIdentity(keypair, domain, nonce = getRandomNonce) {
|
||||
/** @type {IdentityData} */
|
||||
function createAccount(keypair, domain, nonce = getRandomNonce) {
|
||||
/** @type {AccountData} */
|
||||
const data = {
|
||||
action: 'add',
|
||||
add: {
|
||||
|
@ -246,8 +246,8 @@ function createIdentity(keypair, domain, nonce = getRandomNonce) {
|
|||
|
||||
return create({
|
||||
data,
|
||||
identity: IDENTITY_SELF,
|
||||
identityTips: null,
|
||||
account: ACCOUNT_SELF,
|
||||
accountTips: null,
|
||||
keypair,
|
||||
tangles: {},
|
||||
domain,
|
||||
|
@ -285,9 +285,9 @@ module.exports = {
|
|||
getFeedRootHash,
|
||||
create,
|
||||
createRoot,
|
||||
createIdentity,
|
||||
createAccount,
|
||||
erase,
|
||||
stripIdentity,
|
||||
stripAccount,
|
||||
toPlaintextBuffer,
|
||||
fromPlaintextBuffer,
|
||||
isRoot,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const { stripIdentity } = require('./strip')
|
||||
const { stripAccount } = require('./strip')
|
||||
const { isEmptyObject } = require('./util')
|
||||
|
||||
/**
|
||||
|
@ -11,13 +11,13 @@ const { isEmptyObject } = require('./util')
|
|||
* @param {string | 0} findDomain
|
||||
*/
|
||||
function isFeedRoot(msg, id = 0, findDomain = 0) {
|
||||
const { dataHash, dataSize, identity, identityTips, tangles, domain } =
|
||||
const { dataHash, dataSize, account, accountTips, tangles, domain } =
|
||||
msg.metadata
|
||||
if (dataHash !== null) return false
|
||||
if (dataSize !== 0) return false
|
||||
if (id === 0 && !identity) return false
|
||||
if (id !== 0 && identity !== stripIdentity(id)) return false
|
||||
if (identityTips !== null) return false
|
||||
if (id === 0 && !account) return false
|
||||
if (id !== 0 && account !== stripAccount(id)) return false
|
||||
if (accountTips !== null) return false
|
||||
if (!isEmptyObject(tangles)) return false
|
||||
if (findDomain !== 0 && domain !== findDomain) return false
|
||||
return true
|
||||
|
|
|
@ -24,13 +24,13 @@ function stripMsgKey(msgKey) {
|
|||
* @param {string} id
|
||||
* @returns {string}
|
||||
*/
|
||||
function stripIdentity(id) {
|
||||
if (id.startsWith('ppppp:identity/v3/') === false) return id
|
||||
const withoutPrefix = id.replace('ppppp:identity/v3/', '')
|
||||
function stripAccount(id) {
|
||||
if (id.startsWith('ppppp:account/v3/') === false) return id
|
||||
const withoutPrefix = id.replace('ppppp:account/v3/', '')
|
||||
return withoutPrefix.split('/')[0]
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
stripMsgKey,
|
||||
stripIdentity,
|
||||
stripAccount,
|
||||
}
|
||||
|
|
|
@ -195,7 +195,7 @@ class Tangle {
|
|||
const metadata = this.#rootMsg.metadata
|
||||
if (metadata.dataSize > 0) return false
|
||||
if (metadata.dataHash !== null) return false
|
||||
if (metadata.identityTips !== null) return false
|
||||
if (metadata.accountTips !== null) return false
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -205,8 +205,8 @@ class Tangle {
|
|||
console.trace('Tangle is missing root message')
|
||||
return null
|
||||
}
|
||||
const { identity, domain } = this.#rootMsg.metadata
|
||||
return { identity, domain }
|
||||
const { account, domain } = this.#rootMsg.metadata
|
||||
return { account, domain }
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -6,7 +6,7 @@ const stringify = require('json-canon')
|
|||
const Tangle = require('./tangle')
|
||||
const representData = require('./represent-data')
|
||||
const isFeedRoot = require('./is-feed-root')
|
||||
const { SIGNATURE_TAG_MSG_V3, IDENTITY_SELF } = require('./constants')
|
||||
const { SIGNATURE_TAG_MSG_V3, ACCOUNT_SELF } = require('./constants')
|
||||
|
||||
/**
|
||||
* @typedef {import('.').Msg} Msg
|
||||
|
@ -34,14 +34,14 @@ function validateShape(msg) {
|
|||
// prettier-ignore
|
||||
return 'invalid message: must have metadata.dataSize\n' + JSON.stringify(msg)
|
||||
}
|
||||
if (!('identity' in msg.metadata)) {
|
||||
if (!('account' in msg.metadata)) {
|
||||
return (
|
||||
'invalid message: must have metadata.identity\n' + JSON.stringify(msg)
|
||||
'invalid message: must have metadata.account\n' + JSON.stringify(msg)
|
||||
)
|
||||
}
|
||||
if (!('identityTips' in msg.metadata)) {
|
||||
if (!('accountTips' in msg.metadata)) {
|
||||
// prettier-ignore
|
||||
return 'invalid message: must have metadata.identityTips\n' + JSON.stringify(msg)
|
||||
return 'invalid message: must have metadata.accountTips\n' + JSON.stringify(msg)
|
||||
}
|
||||
if (!('tangles' in msg.metadata)) {
|
||||
return 'invalid message: must have metadata.tangles\n' + JSON.stringify(msg)
|
||||
|
@ -85,17 +85,17 @@ function validatePubkey(msg) {
|
|||
* @param {Set<string>} pubkeys
|
||||
* @returns {string | undefined}
|
||||
*/
|
||||
function validateIdentityPubkey(msg, pubkeys) {
|
||||
// Unusual case: if the msg is a feed root, ignore the identity and pubkey
|
||||
function validateAccountPubkey(msg, pubkeys) {
|
||||
// Unusual case: if the msg is a feed root, ignore the account and pubkey
|
||||
if (isFeedRoot(msg)) return
|
||||
|
||||
if (
|
||||
msg.metadata.identity &&
|
||||
msg.metadata.identity !== IDENTITY_SELF &&
|
||||
msg.metadata.account &&
|
||||
msg.metadata.account !== ACCOUNT_SELF &&
|
||||
!pubkeys.has(msg.pubkey)
|
||||
) {
|
||||
// prettier-ignore
|
||||
return `invalid message: pubkey "${msg.pubkey}" should have been one of "${[...pubkeys]}" from the identity "${msg.metadata.identity}"\n` + JSON.stringify(msg)
|
||||
return `invalid message: pubkey "${msg.pubkey}" should have been one of "${[...pubkeys]}" from the account "${msg.metadata.account}"\n` + JSON.stringify(msg)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -187,14 +187,14 @@ function validateTangle(msg, tangle, tangleId) {
|
|||
return `invalid message: depth "${depth}" should have been a positive integer\n` + JSON.stringify(msg)
|
||||
}
|
||||
if (tangle.isFeed()) {
|
||||
const { identity, domain } = /** @type {FeedDetails} */ (tangle.getFeed())
|
||||
const { account, domain } = /** @type {FeedDetails} */ (tangle.getFeed())
|
||||
if (domain !== msg.metadata.domain) {
|
||||
// prettier-ignore
|
||||
return `invalid message: domain "${msg.metadata.domain}" should have been feed domain "${domain}"\n` + JSON.stringify(msg)
|
||||
}
|
||||
if (identity !== msg.metadata.identity) {
|
||||
if (account !== msg.metadata.account) {
|
||||
// prettier-ignore
|
||||
return `invalid message: identity "${msg.metadata.identity}" should have been feed identity "${identity}"\n` + JSON.stringify(msg)
|
||||
return `invalid message: account "${msg.metadata.account}" should have been feed account "${account}"\n` + JSON.stringify(msg)
|
||||
}
|
||||
}
|
||||
let lastPrev = null
|
||||
|
@ -329,7 +329,7 @@ function validate(msg, tangle, pubkeys, msgHash, rootHash) {
|
|||
if ((err = validateDataSize(msg))) return err
|
||||
if ((err = validateData(msg))) return err
|
||||
if ((err = validateDomain(msg.metadata.domain))) return err
|
||||
if ((err = validateIdentityPubkey(msg, pubkeys))) return err
|
||||
if ((err = validateAccountPubkey(msg, pubkeys))) return err
|
||||
if (tangle.size() === 0) {
|
||||
if ((err = validateTangleRoot(msg, msgHash, rootHash))) return err
|
||||
} else {
|
||||
|
|
65
protospec.md
65
protospec.md
|
@ -10,9 +10,9 @@ Background: https://github.com/ssbc/ssb2-discussion-forum/issues/24
|
|||
- **Tangle Root** = the origin msg of a tangle
|
||||
- **Tangle Tips** = tangle msgs that are not yet referenced by any other msg in the tangle
|
||||
- **Tangle ID** = Msg hash of the tangle's root msg
|
||||
- **Identity tangle** = tangle with msgs that add (or remove?) asymmetric-crypto public keys
|
||||
- **ID** = tangle ID of the identity tangle, refers to the "identity" of a person or a group
|
||||
- **Feed** = tangle with msgs authored by (any pubkey in) an identity
|
||||
- **Account tangle** = tangle with msgs that add (or remove?) asymmetric-crypto public keys
|
||||
- **Account ID** = tangle ID of the account tangle
|
||||
- **Feed** = tangle with msgs authored by (any pubkey in) an account
|
||||
- **Feed root** = a msg that is deterministically predictable and empty, so to allow others to pre-know its hash
|
||||
- **Feed ID** = ID of a feed (Msg ID of the feed's root msg)
|
||||
|
||||
|
@ -24,8 +24,8 @@ interface Msg {
|
|||
metadata: {
|
||||
dataHash: ContentHash | null // blake3 hash of the `content` object serialized
|
||||
dataSize: number // byte size (unsigned integer) of the `content` object serialized
|
||||
identity: string | 'self' | 'any' // blake3 hash of an identity tangle root msg, or the string 'self', or 'any'
|
||||
identityTips: Array<string> | null // list of blake3 hashes of identity tangle tips, or null
|
||||
account: string | 'self' | 'any' // blake3 hash of an account tangle root msg, or the string 'self', or 'any'
|
||||
accountTips: Array<string> | null // list of blake3 hashes of account tangle tips, or null
|
||||
tangles: {
|
||||
// for each tangle this msg belongs to, identified by the tangle's root
|
||||
[rootMsgHash: string]: {
|
||||
|
@ -41,20 +41,20 @@ interface Msg {
|
|||
}
|
||||
```
|
||||
|
||||
## Identity tangle msgs
|
||||
## Account tangle msgs
|
||||
|
||||
Msgs in an identity tangle are special because they have empty `identity` and `identityTips` fields.
|
||||
Msgs in an account tangle are special because they have empty `account` and `accountTips` fields.
|
||||
|
||||
```typescript
|
||||
interface Msg {
|
||||
data: IdentityData
|
||||
data: AccountData
|
||||
metadata: {
|
||||
dataHash: ContentHash
|
||||
dataSize: number
|
||||
identity: 'self' // MUST be the string 'self'
|
||||
identityTips: null // MUST be null
|
||||
account: 'self' // MUST be the string 'self'
|
||||
accountTips: null // MUST be null
|
||||
tangles: {
|
||||
[identityTangleId: string]: {
|
||||
[accountTangleId: string]: {
|
||||
depth: number // maximum distance (positive integer) from this msg to the root
|
||||
prev: Array<MsgHash> // list of msg hashes of existing msgs, unique set and ordered alphabetically
|
||||
}
|
||||
|
@ -66,23 +66,23 @@ interface Msg {
|
|||
sig: Signature
|
||||
}
|
||||
|
||||
type IdentityData =
|
||||
| { action: 'add', add: IdentityAdd }
|
||||
| { action: 'del', del: IdentityDel }
|
||||
type AccountData =
|
||||
| { action: 'add', add: AccountAdd }
|
||||
| { action: 'del', del: AccountDel }
|
||||
|
||||
// "add" means this keypair can validly add more keypairs to the identity tangle
|
||||
// "del" means this keypair can validly revoke other keypairs from the identity
|
||||
// "add" means this keypair can validly add more keypairs to the account tangle
|
||||
// "del" means this keypair can validly revoke other keypairs from the account
|
||||
// "box" means the peer with this keypair should get access to the box keypair
|
||||
type IdentityPower = 'add' | 'del' | 'box'
|
||||
type AccountPower = 'add' | 'del' | 'box'
|
||||
|
||||
type IdentityAdd = {
|
||||
type AccountAdd = {
|
||||
key: Key
|
||||
nonce?: string // nonce required only on the identity tangle's root
|
||||
consent?: string // base58 encoded signature of the string `:identity-add:<ID>` where `<ID>` is the identity's ID, required only on non-root msgs
|
||||
identityPowers?: Array<IdentityPower> // list of powers granted to this key, defaults to []
|
||||
nonce?: string // nonce required only on the account tangle's root
|
||||
consent?: string // base58 encoded signature of the string `:account-add:<ID>` where `<ID>` is the account's ID, required only on non-root msgs
|
||||
accountPowers?: Array<AccountPower> // list of powers granted to this key, defaults to []
|
||||
}
|
||||
|
||||
type IdentityDel = {
|
||||
type AccountDel = {
|
||||
key: Key
|
||||
}
|
||||
|
||||
|
@ -99,7 +99,7 @@ type Key =
|
|||
}
|
||||
```
|
||||
|
||||
Examples of `IdentityData`:
|
||||
Examples of `AccountData`:
|
||||
|
||||
- Registering the first signing pubkey:
|
||||
```json
|
||||
|
@ -115,19 +115,6 @@ Examples of `IdentityData`:
|
|||
}
|
||||
}
|
||||
```
|
||||
- Registering a subidentity:
|
||||
```json
|
||||
{
|
||||
"action": "add",
|
||||
"add": {
|
||||
"key": {
|
||||
"purpose": "subidentity",
|
||||
"algorithm": "tangle",
|
||||
"bytes": "6yqq7iwyJEKdofJ3xpRLEq"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
- Revoking a signing pubkey:
|
||||
```json
|
||||
{
|
||||
|
@ -152,8 +139,8 @@ interface Msg {
|
|||
metadata: {
|
||||
dataHash: null // MUST be null
|
||||
dataSize: 0 // MUST be 0
|
||||
identity: string // MUST be an ID
|
||||
identityTips: null // MUST be null
|
||||
account: string // MUST be an ID
|
||||
accountTips: null // MUST be null
|
||||
tangles: {} // MUST be empty object
|
||||
domain: string
|
||||
v: 2
|
||||
|
@ -163,7 +150,7 @@ interface Msg {
|
|||
}
|
||||
```
|
||||
|
||||
Thus, given a `identity` and a `domain`, any peer can construct the `metadata` part of the feed root msg, and thus can derive the "msg ID" for the root based on that `metadata`.
|
||||
Thus, given a `account` and a `domain`, any peer can construct the `metadata` part of the feed root msg, and thus can derive the "msg ID" for the root based on that `metadata`.
|
||||
|
||||
Given the root msg ID, any peer can thus refer to the feed tangle, because the root msg ID is the tangle ID for the feed tangle.
|
||||
|
||||
|
|
|
@ -21,10 +21,10 @@ test('add()', async (t) => {
|
|||
|
||||
await peer.db.loaded()
|
||||
|
||||
const identityMsg0 = MsgV3.createIdentity(keypair, 'person')
|
||||
const id = MsgV3.getMsgHash(identityMsg0)
|
||||
const accountMsg0 = MsgV3.createAccount(keypair, 'person')
|
||||
const id = MsgV3.getMsgHash(accountMsg0)
|
||||
|
||||
await p(peer.db.add)(identityMsg0, id)
|
||||
await p(peer.db.add)(accountMsg0, id)
|
||||
|
||||
const rootMsg = MsgV3.createRoot(id, 'post', keypair)
|
||||
const rootHash = MsgV3.getMsgHash(rootMsg)
|
||||
|
@ -38,8 +38,8 @@ test('add()', async (t) => {
|
|||
keypair,
|
||||
domain: 'post',
|
||||
data: { text: 'This is the first post!' },
|
||||
identity: id,
|
||||
identityTips: [id],
|
||||
account: id,
|
||||
accountTips: [id],
|
||||
tangles: {
|
||||
[rootHash]: tangle,
|
||||
},
|
||||
|
|
|
@ -21,12 +21,12 @@ test('del', async (t) => {
|
|||
|
||||
await peer.db.loaded()
|
||||
|
||||
const id = await p(peer.db.identity.create)({ domain: 'person' })
|
||||
const id = await p(peer.db.account.create)({ domain: 'person' })
|
||||
|
||||
const msgHashes = []
|
||||
for (let i = 0; i < 5; i++) {
|
||||
const rec = await p(peer.db.feed.publish)({
|
||||
identity: id,
|
||||
account: id,
|
||||
domain: 'post',
|
||||
data: { text: 'm' + i },
|
||||
})
|
||||
|
@ -35,7 +35,7 @@ test('del', async (t) => {
|
|||
|
||||
const before = []
|
||||
for (const msg of peer.db.msgs()) {
|
||||
if (msg.data && msg.metadata.identity?.length > 4) {
|
||||
if (msg.data && msg.metadata.account?.length > 4) {
|
||||
before.push(msg.data.text)
|
||||
}
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ test('del', async (t) => {
|
|||
|
||||
const after = []
|
||||
for (const msg of peer.db.msgs()) {
|
||||
if (msg.data && msg.metadata.identity?.length > 4) {
|
||||
if (msg.data && msg.metadata.account?.length > 4) {
|
||||
after.push(msg.data.text)
|
||||
}
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ test('del', async (t) => {
|
|||
|
||||
assert.deepEqual(
|
||||
persistedMsgs
|
||||
.filter((msg) => msg.data && msg.metadata.identity?.length > 4)
|
||||
.filter((msg) => msg.data && msg.metadata.account?.length > 4)
|
||||
.map((msg) => msg.data.text),
|
||||
['m0', 'm1', 'm3', 'm4'],
|
||||
'msgs in disk after the delete'
|
||||
|
|
|
@ -21,12 +21,12 @@ test('erase', async (t) => {
|
|||
|
||||
await peer.db.loaded()
|
||||
|
||||
const id = await p(peer.db.identity.create)({ domain: 'person' })
|
||||
const id = await p(peer.db.account.create)({ domain: 'person' })
|
||||
|
||||
const msgHashes = []
|
||||
for (let i = 0; i < 5; i++) {
|
||||
const rec = await p(peer.db.feed.publish)({
|
||||
identity: id,
|
||||
account: id,
|
||||
domain: 'post',
|
||||
data: { text: 'm' + i },
|
||||
})
|
||||
|
@ -35,7 +35,7 @@ test('erase', async (t) => {
|
|||
|
||||
const before = []
|
||||
for (const msg of peer.db.msgs()) {
|
||||
if (msg.data && msg.metadata.identity?.length > 4) {
|
||||
if (msg.data && msg.metadata.account?.length > 4) {
|
||||
before.push(msg.data.text)
|
||||
}
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ test('erase', async (t) => {
|
|||
|
||||
const after = []
|
||||
for (const msg of peer.db.msgs()) {
|
||||
if (msg.data && msg.metadata.identity?.length > 4) {
|
||||
if (msg.data && msg.metadata.account?.length > 4) {
|
||||
after.push(msg.data.text)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ test('setup', async (t) => {
|
|||
|
||||
await peer.db.loaded()
|
||||
|
||||
id = (await p(peer.db.identity.create)({domain: 'person'}))
|
||||
id = (await p(peer.db.account.create)({domain: 'person'}))
|
||||
rootMsg = MsgV3.createRoot(id, 'post', keypair)
|
||||
rootHash = MsgV3.getMsgHash(rootMsg)
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ test('setup', async (t) => {
|
|||
|
||||
await peer.db.loaded()
|
||||
|
||||
id = (await p(peer.db.identity.create)({domain: 'person'}))
|
||||
id = (await p(peer.db.account.create)({domain: 'person'}))
|
||||
rootMsg = MsgV3.createRoot(id, 'post', keypair)
|
||||
rootHash = MsgV3.getMsgHash(rootMsg)
|
||||
})
|
||||
|
@ -36,7 +36,7 @@ let rec1
|
|||
let msgHash2
|
||||
test('feed.publish()', async (t) => {
|
||||
rec1 = await p(peer.db.feed.publish)({
|
||||
identity: id,
|
||||
account: id,
|
||||
domain: 'post',
|
||||
data: { text: 'I am 1st post' },
|
||||
})
|
||||
|
@ -55,7 +55,7 @@ test('feed.publish()', async (t) => {
|
|||
msgHash1 = MsgV3.getMsgHash(rec1.msg)
|
||||
|
||||
const rec2 = await p(peer.db.feed.publish)({
|
||||
identity: id,
|
||||
account: id,
|
||||
domain: 'post',
|
||||
data: { text: 'I am 2nd post' },
|
||||
})
|
||||
|
@ -80,8 +80,8 @@ test('add() forked then feed.publish() merged', async (t) => {
|
|||
|
||||
const msg3 = MsgV3.create({
|
||||
keypair,
|
||||
identity: id,
|
||||
identityTips: [id],
|
||||
account: id,
|
||||
accountTips: [id],
|
||||
domain: 'post',
|
||||
data: { text: '3rd post forked from 1st' },
|
||||
tangles: {
|
||||
|
@ -93,7 +93,7 @@ test('add() forked then feed.publish() merged', async (t) => {
|
|||
const msgHash3 = MsgV3.getMsgHash(rec3.msg)
|
||||
|
||||
const rec4 = await p(peer.db.feed.publish)({
|
||||
identity: id,
|
||||
account: id,
|
||||
domain: 'post',
|
||||
data: { text: 'I am 4th post' },
|
||||
})
|
||||
|
@ -119,7 +119,7 @@ test('add() forked then feed.publish() merged', async (t) => {
|
|||
|
||||
test('feed.publish() encrypted with box', async (t) => {
|
||||
const recEncrypted = await p(peer.db.feed.publish)({
|
||||
identity: id,
|
||||
account: id,
|
||||
domain: 'post',
|
||||
data: { text: 'I am chewing food', recps: [keypair.public] },
|
||||
encryptionFormat: 'box',
|
||||
|
@ -133,14 +133,14 @@ test('feed.publish() encrypted with box', async (t) => {
|
|||
|
||||
test('feed.publish() with tangles', async (t) => {
|
||||
const recA = await p(peer.db.feed.publish)({
|
||||
identity: id,
|
||||
account: id,
|
||||
domain: 'comment',
|
||||
data: { text: 'I am root' },
|
||||
})
|
||||
assert.equal(recA.msg.data.text, 'I am root', 'root text correct')
|
||||
|
||||
const recB = await p(peer.db.feed.publish)({
|
||||
identity: id,
|
||||
account: id,
|
||||
domain: 'comment',
|
||||
data: { text: 'I am comment 1' },
|
||||
tangles: [recA.hash],
|
||||
|
|
|
@ -25,10 +25,10 @@ test('setup', async (t) => {
|
|||
|
||||
await peer.db.loaded()
|
||||
|
||||
id = (await p(peer.db.identity.create)({domain: 'person'}))
|
||||
id = (await p(peer.db.account.create)({domain: 'person'}))
|
||||
|
||||
const rec1 = await p(peer.db.feed.publish)({
|
||||
identity: id,
|
||||
account: id,
|
||||
domain: 'post',
|
||||
data: { text: 'I am 1st post' },
|
||||
})
|
||||
|
|
|
@ -26,7 +26,7 @@ test('setup', async (t) => {
|
|||
|
||||
await peer.db.loaded()
|
||||
|
||||
const id = (await p(peer.db.identity.create)({domain: 'person'}))
|
||||
const id = (await p(peer.db.account.create)({domain: 'person'}))
|
||||
|
||||
// Slow down append so that we can trigger msg creation in parallel
|
||||
const originalAppend = peer.db._getLog().append
|
||||
|
@ -36,7 +36,7 @@ test('setup', async (t) => {
|
|||
|
||||
rootPost = (
|
||||
await p(peer.db.feed.publish)({
|
||||
identity: id,
|
||||
account: id,
|
||||
keypair: keypairA,
|
||||
domain: 'comment',
|
||||
data: { text: 'root' },
|
||||
|
@ -45,14 +45,14 @@ test('setup', async (t) => {
|
|||
|
||||
const [{ hash: reply1B }, { hash: reply1C }] = await Promise.all([
|
||||
p(peer.db.feed.publish)({
|
||||
identity: id,
|
||||
account: id,
|
||||
keypair: keypairB,
|
||||
domain: 'comment',
|
||||
data: { text: 'reply 1B' },
|
||||
tangles: [rootPost],
|
||||
}),
|
||||
p(peer.db.feed.publish)({
|
||||
identity: id,
|
||||
account: id,
|
||||
keypair: keypairC,
|
||||
domain: 'comment',
|
||||
data: { text: 'reply 1C' },
|
||||
|
@ -64,7 +64,7 @@ test('setup', async (t) => {
|
|||
|
||||
reply2A = (
|
||||
await p(peer.db.feed.publish)({
|
||||
identity: id,
|
||||
account: id,
|
||||
keypair: keypairA,
|
||||
domain: 'comment',
|
||||
data: { text: 'reply 2' },
|
||||
|
@ -74,14 +74,14 @@ test('setup', async (t) => {
|
|||
|
||||
const [{ hash: reply3B }, { hash: reply3C }] = await Promise.all([
|
||||
p(peer.db.feed.publish)({
|
||||
identity: id,
|
||||
account: id,
|
||||
keypair: keypairB,
|
||||
domain: 'comment',
|
||||
data: { text: 'reply 3B' },
|
||||
tangles: [rootPost],
|
||||
}),
|
||||
p(peer.db.feed.publish)({
|
||||
identity: id,
|
||||
account: id,
|
||||
keypair: keypairC,
|
||||
domain: 'comment',
|
||||
data: { text: 'reply 3C' },
|
||||
|
|
|
@ -8,10 +8,10 @@ const SecretStack = require('secret-stack')
|
|||
const caps = require('ppppp-caps')
|
||||
const Keypair = require('ppppp-keypair')
|
||||
|
||||
const DIR = path.join(os.tmpdir(), 'ppppp-db-identity-add')
|
||||
const DIR = path.join(os.tmpdir(), 'ppppp-db-account-add')
|
||||
rimraf.sync(DIR)
|
||||
|
||||
test('identity.add()', async (t) => {
|
||||
test('account.add()', async (t) => {
|
||||
const keypair1 = Keypair.generate('ed25519', 'alice')
|
||||
const keypair2 = Keypair.generate('ed25519', 'bob')
|
||||
|
||||
|
@ -21,23 +21,23 @@ test('identity.add()', async (t) => {
|
|||
.call(null, { keypair: keypair1, path: DIR })
|
||||
|
||||
await peer.db.loaded()
|
||||
const id = await p(peer.db.identity.create)({
|
||||
const id = await p(peer.db.account.create)({
|
||||
keypair: keypair1,
|
||||
domain: 'person',
|
||||
})
|
||||
|
||||
assert.equal(peer.db.identity.has({ identity: id, keypair: keypair2 }), false)
|
||||
assert.equal(peer.db.account.has({ account: id, keypair: keypair2 }), false)
|
||||
|
||||
const consent = peer.db.identity.consent({ identity: id, keypair: keypair2 })
|
||||
const consent = peer.db.account.consent({ account: id, keypair: keypair2 })
|
||||
|
||||
const identityRec1 = await p(peer.db.identity.add)({
|
||||
identity: id,
|
||||
const accountRec1 = await p(peer.db.account.add)({
|
||||
account: id,
|
||||
keypair: keypair2,
|
||||
consent,
|
||||
powers: ['box'],
|
||||
})
|
||||
assert.ok(identityRec1, 'identityRec1 exists')
|
||||
const { hash, msg } = identityRec1
|
||||
assert.ok(accountRec1, 'accountRec1 exists')
|
||||
const { hash, msg } = accountRec1
|
||||
assert.ok(hash, 'hash exists')
|
||||
assert.deepEqual(
|
||||
msg.data,
|
||||
|
@ -55,8 +55,8 @@ test('identity.add()', async (t) => {
|
|||
},
|
||||
'msg.data.add NEW KEY'
|
||||
)
|
||||
assert.equal(msg.metadata.identity, 'self', 'msg.metadata.identity')
|
||||
assert.equal(msg.metadata.identityTips, null, 'msg.metadata.identityTips')
|
||||
assert.equal(msg.metadata.account, 'self', 'msg.metadata.account')
|
||||
assert.equal(msg.metadata.accountTips, null, 'msg.metadata.accountTips')
|
||||
assert.equal(msg.metadata.domain, 'person', 'msg.metadata.domain')
|
||||
assert.deepEqual(
|
||||
msg.metadata.tangles,
|
||||
|
@ -65,12 +65,12 @@ test('identity.add()', async (t) => {
|
|||
)
|
||||
assert.equal(msg.pubkey, keypair1.public, 'msg.pubkey OLD KEY')
|
||||
|
||||
assert.equal(peer.db.identity.has({ identity: id, keypair: keypair2 }), true)
|
||||
assert.equal(peer.db.account.has({ account: id, keypair: keypair2 }), true)
|
||||
|
||||
await p(peer.close)()
|
||||
})
|
||||
|
||||
test('keypair with no "add" powers cannot identity.add()', async (t) => {
|
||||
test('keypair with no "add" powers cannot account.add()', async (t) => {
|
||||
rimraf.sync(DIR)
|
||||
const keypair1 = Keypair.generate('ed25519', 'alice')
|
||||
const keypair2 = Keypair.generate('ed25519', 'bob')
|
||||
|
@ -82,20 +82,20 @@ test('keypair with no "add" powers cannot identity.add()', async (t) => {
|
|||
.call(null, { keypair: keypair1, path: DIR })
|
||||
|
||||
await peer1.db.loaded()
|
||||
const id = await p(peer1.db.identity.create)({
|
||||
const id = await p(peer1.db.account.create)({
|
||||
keypair: keypair1,
|
||||
domain: 'account',
|
||||
})
|
||||
const msg1 = peer1.db.get(id)
|
||||
|
||||
const { msg: msg2 } = await p(peer1.db.identity.add)({
|
||||
identity: id,
|
||||
const { msg: msg2 } = await p(peer1.db.account.add)({
|
||||
account: id,
|
||||
keypair: keypair2,
|
||||
powers: [],
|
||||
})
|
||||
assert.equal(msg2.data.add.key.bytes, keypair2.public)
|
||||
|
||||
assert.equal(peer1.db.identity.has({ identity: id, keypair: keypair2 }), true)
|
||||
assert.equal(peer1.db.account.has({ account: id, keypair: keypair2 }), true)
|
||||
|
||||
await p(peer1.close)()
|
||||
rimraf.sync(DIR)
|
||||
|
@ -111,8 +111,8 @@ test('keypair with no "add" powers cannot identity.add()', async (t) => {
|
|||
|
||||
// Test author-side power validation
|
||||
assert.rejects(
|
||||
p(peer2.db.identity.add)({
|
||||
identity: id,
|
||||
p(peer2.db.account.add)({
|
||||
account: id,
|
||||
keypair: keypair3,
|
||||
powers: [],
|
||||
}),
|
||||
|
@ -120,8 +120,8 @@ test('keypair with no "add" powers cannot identity.add()', async (t) => {
|
|||
)
|
||||
|
||||
// Make the author disobey power validation
|
||||
const { msg: msg3 } = await p(peer2.db.identity.add)({
|
||||
identity: id,
|
||||
const { msg: msg3 } = await p(peer2.db.account.add)({
|
||||
account: id,
|
||||
keypair: keypair3,
|
||||
powers: [],
|
||||
_disobey: true,
|
||||
|
@ -150,7 +150,7 @@ test('keypair with no "add" powers cannot identity.add()', async (t) => {
|
|||
await p(peer1again.close)()
|
||||
})
|
||||
|
||||
test('publish with a key in the identity', async (t) => {
|
||||
test('publish with a key in the account', async (t) => {
|
||||
rimraf.sync(DIR)
|
||||
|
||||
const keypair1 = Keypair.generate('ed25519', 'alice')
|
||||
|
@ -163,40 +163,40 @@ test('publish with a key in the identity', async (t) => {
|
|||
|
||||
await peer.db.loaded()
|
||||
|
||||
const identity = await p(peer.db.identity.create)({
|
||||
const account = await p(peer.db.account.create)({
|
||||
keypair: keypair1,
|
||||
domain: 'person',
|
||||
})
|
||||
const identityMsg0 = peer.db.get(identity)
|
||||
const accountMsg0 = peer.db.get(account)
|
||||
|
||||
// Consent is implicitly created because keypair2 has .private
|
||||
const identityRec1 = await p(peer.db.identity.add)({
|
||||
identity,
|
||||
const accountRec1 = await p(peer.db.account.add)({
|
||||
account,
|
||||
keypair: keypair2,
|
||||
})
|
||||
|
||||
const postRec = await p(peer.db.feed.publish)({
|
||||
identity,
|
||||
account,
|
||||
domain: 'post',
|
||||
data: { text: 'hello' },
|
||||
keypair: keypair2,
|
||||
})
|
||||
assert.equal(postRec.msg.data.text, 'hello', 'post text correct')
|
||||
const postsId = peer.db.feed.getId(identity, 'post')
|
||||
const postsId = peer.db.feed.getId(account, 'post')
|
||||
assert.ok(postsId, 'postsId exists')
|
||||
|
||||
const recs = [...peer.db.records()]
|
||||
assert.equal(recs.length, 4, '4 records')
|
||||
const [_identityRec0, _identityRec1, postsRoot, _post] = recs
|
||||
assert.deepEqual(_identityRec0.msg, identityMsg0, 'identityMsg0')
|
||||
assert.deepEqual(_identityRec1.msg, identityRec1.msg, 'identityMsg1')
|
||||
const [_accountRec0, _accountRec1, postsRoot, _post] = recs
|
||||
assert.deepEqual(_accountRec0.msg, accountMsg0, 'accountMsg0')
|
||||
assert.deepEqual(_accountRec1.msg, accountRec1.msg, 'accountMsg1')
|
||||
assert.deepEqual(
|
||||
postsRoot.msg.metadata,
|
||||
{
|
||||
dataHash: null,
|
||||
dataSize: 0,
|
||||
identity,
|
||||
identityTips: null,
|
||||
account,
|
||||
accountTips: null,
|
||||
tangles: {},
|
||||
domain: 'post',
|
||||
v: 3,
|
||||
|
@ -218,8 +218,8 @@ test('publish with a key in the identity', async (t) => {
|
|||
|
||||
await carol.db.loaded()
|
||||
|
||||
await p(carol.db.add)(identityMsg0, identity)
|
||||
await p(carol.db.add)(identityRec1.msg, identity)
|
||||
await p(carol.db.add)(accountMsg0, account)
|
||||
await p(carol.db.add)(accountRec1.msg, account)
|
||||
await p(carol.db.add)(postsRoot.msg, postsId)
|
||||
await p(carol.db.add)(postRec.msg, postsId)
|
||||
// t.pass('carol added all messages successfully')
|
||||
|
|
|
@ -8,10 +8,10 @@ const SecretStack = require('secret-stack')
|
|||
const caps = require('ppppp-caps')
|
||||
const Keypair = require('ppppp-keypair')
|
||||
|
||||
const DIR = path.join(os.tmpdir(), 'ppppp-db-identity-create')
|
||||
const DIR = path.join(os.tmpdir(), 'ppppp-db-account-create')
|
||||
rimraf.sync(DIR)
|
||||
|
||||
test('identity.create() with just "domain"', async (t) => {
|
||||
test('account.create() with just "domain"', async (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
const peer = SecretStack({ appKey: caps.shse })
|
||||
.use(require('../lib'))
|
||||
|
@ -19,12 +19,12 @@ test('identity.create() with just "domain"', async (t) => {
|
|||
.call(null, { keypair, path: DIR })
|
||||
|
||||
await peer.db.loaded()
|
||||
const identity = await p(peer.db.identity.create)({
|
||||
const account = await p(peer.db.account.create)({
|
||||
domain: 'person',
|
||||
_nonce: 'MYNONCE',
|
||||
})
|
||||
assert.ok(identity, 'identityRec0 exists')
|
||||
const msg = peer.db.get(identity)
|
||||
assert.ok(account, 'accountRec0 exists')
|
||||
const msg = peer.db.get(account)
|
||||
assert.deepEqual(
|
||||
msg.data,
|
||||
{
|
||||
|
@ -41,8 +41,8 @@ test('identity.create() with just "domain"', async (t) => {
|
|||
},
|
||||
'msg.data.add'
|
||||
)
|
||||
assert.equal(msg.metadata.identity, 'self', 'msg.metadata.identity')
|
||||
assert.equal(msg.metadata.identityTips, null, 'msg.metadata.identityTips')
|
||||
assert.equal(msg.metadata.account, 'self', 'msg.metadata.account')
|
||||
assert.equal(msg.metadata.accountTips, null, 'msg.metadata.accountTips')
|
||||
assert.deepEqual(
|
||||
Object.keys(msg.metadata.tangles),
|
||||
[],
|
||||
|
@ -53,7 +53,7 @@ test('identity.create() with just "domain"', async (t) => {
|
|||
await p(peer.close)()
|
||||
})
|
||||
|
||||
test('identity.create() with "keypair" and "domain"', async (t) => {
|
||||
test('account.create() with "keypair" and "domain"', async (t) => {
|
||||
rimraf.sync(DIR)
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
|
||||
|
@ -63,15 +63,15 @@ test('identity.create() with "keypair" and "domain"', async (t) => {
|
|||
.call(null, { keypair, path: DIR })
|
||||
|
||||
await peer.db.loaded()
|
||||
const identity = await p(peer.db.identity.create)({
|
||||
const account = await p(peer.db.account.create)({
|
||||
keypair,
|
||||
domain: 'person',
|
||||
})
|
||||
assert.ok(identity, 'identity created')
|
||||
const msg = peer.db.get(identity)
|
||||
assert.ok(account, 'account created')
|
||||
const msg = peer.db.get(account)
|
||||
assert.equal(msg.data.add.key.bytes, keypair.public, 'msg.data.add')
|
||||
assert.equal(msg.metadata.identity, 'self', 'msg.metadata.identity')
|
||||
assert.equal(msg.metadata.identityTips, null, 'msg.metadata.identityTips')
|
||||
assert.equal(msg.metadata.account, 'self', 'msg.metadata.account')
|
||||
assert.equal(msg.metadata.accountTips, null, 'msg.metadata.accountTips')
|
||||
assert.deepEqual(
|
||||
Object.keys(msg.metadata.tangles),
|
||||
[],
|
||||
|
@ -82,7 +82,7 @@ test('identity.create() with "keypair" and "domain"', async (t) => {
|
|||
await p(peer.close)()
|
||||
})
|
||||
|
||||
test('identity.find() can find', async (t) => {
|
||||
test('account.find() can find', async (t) => {
|
||||
rimraf.sync(DIR)
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
const domain = 'person'
|
||||
|
@ -93,16 +93,16 @@ test('identity.find() can find', async (t) => {
|
|||
.call(null, { keypair, path: DIR })
|
||||
|
||||
await peer.db.loaded()
|
||||
const identity = await p(peer.db.identity.create)({ keypair, domain })
|
||||
assert.ok(identity, 'identity created')
|
||||
const account = await p(peer.db.account.create)({ keypair, domain })
|
||||
assert.ok(account, 'account created')
|
||||
|
||||
const found = await p(peer.db.identity.find)({ keypair, domain })
|
||||
assert.equal(found, identity, 'found')
|
||||
const found = await p(peer.db.account.find)({ keypair, domain })
|
||||
assert.equal(found, account, 'found')
|
||||
|
||||
await p(peer.close)()
|
||||
})
|
||||
|
||||
test('identity.findOrCreate() can find', async (t) => {
|
||||
test('account.findOrCreate() can find', async (t) => {
|
||||
rimraf.sync(DIR)
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
const domain = 'person'
|
||||
|
@ -113,16 +113,16 @@ test('identity.findOrCreate() can find', async (t) => {
|
|||
.call(null, { keypair, path: DIR })
|
||||
|
||||
await peer.db.loaded()
|
||||
const identity = await p(peer.db.identity.create)({ keypair, domain })
|
||||
assert.ok(identity, 'identity created')
|
||||
const account = await p(peer.db.account.create)({ keypair, domain })
|
||||
assert.ok(account, 'account created')
|
||||
|
||||
const found = await p(peer.db.identity.findOrCreate)({ keypair, domain })
|
||||
assert.equal(found, identity, 'found')
|
||||
const found = await p(peer.db.account.findOrCreate)({ keypair, domain })
|
||||
assert.equal(found, account, 'found')
|
||||
|
||||
await p(peer.close)()
|
||||
})
|
||||
|
||||
test('identity.findOrCreate() can create', async (t) => {
|
||||
test('account.findOrCreate() can create', async (t) => {
|
||||
rimraf.sync(DIR)
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
const domain = 'person'
|
||||
|
@ -135,18 +135,18 @@ test('identity.findOrCreate() can create', async (t) => {
|
|||
await peer.db.loaded()
|
||||
|
||||
let gotError = false
|
||||
await p(peer.db.identity.find)({ keypair, domain }).catch((err) => {
|
||||
await p(peer.db.account.find)({ keypair, domain }).catch((err) => {
|
||||
assert.equal(err.cause, 'ENOENT')
|
||||
gotError = true
|
||||
})
|
||||
assert.ok(gotError, 'identity not found')
|
||||
assert.ok(gotError, 'account not found')
|
||||
|
||||
const identity = await p(peer.db.identity.findOrCreate)({ keypair, domain })
|
||||
assert.ok(identity, 'identity created')
|
||||
const msg = peer.db.get(identity)
|
||||
const account = await p(peer.db.account.findOrCreate)({ keypair, domain })
|
||||
assert.ok(account, 'account created')
|
||||
const msg = peer.db.get(account)
|
||||
assert.equal(msg.data.add.key.bytes, keypair.public, 'msg.data.add')
|
||||
assert.equal(msg.metadata.identity, 'self', 'msg.metadata.identity')
|
||||
assert.equal(msg.metadata.identityTips, null, 'msg.metadata.identityTips')
|
||||
assert.equal(msg.metadata.account, 'self', 'msg.metadata.account')
|
||||
assert.equal(msg.metadata.accountTips, null, 'msg.metadata.accountTips')
|
||||
assert.deepEqual(
|
||||
Object.keys(msg.metadata.tangles),
|
||||
[],
|
||||
|
|
|
@ -3,15 +3,15 @@ const assert = require('node:assert')
|
|||
const Keypair = require('ppppp-keypair')
|
||||
const MsgV3 = require('../../lib/msg-v3')
|
||||
|
||||
let identity
|
||||
test('MsgV3.createIdentity()', (t) => {
|
||||
let account
|
||||
test('MsgV3.createAccount()', (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
|
||||
const identityMsg0 = MsgV3.createIdentity(keypair, 'person', 'MYNONCE')
|
||||
console.log(JSON.stringify(identityMsg0, null, 2))
|
||||
const accountMsg0 = MsgV3.createAccount(keypair, 'person', 'MYNONCE')
|
||||
console.log(JSON.stringify(accountMsg0, null, 2))
|
||||
|
||||
assert.deepEqual(
|
||||
identityMsg0.data,
|
||||
accountMsg0.data,
|
||||
{
|
||||
action: 'add',
|
||||
add: {
|
||||
|
@ -26,17 +26,17 @@ test('MsgV3.createIdentity()', (t) => {
|
|||
},
|
||||
'data'
|
||||
)
|
||||
assert.equal(identityMsg0.metadata.dataHash, 'R5az9nC1CB3Afd5Q57HYRQ', 'hash')
|
||||
assert.equal(identityMsg0.metadata.dataSize, 172, 'size')
|
||||
assert.equal(identityMsg0.metadata.identity, 'self', 'identity')
|
||||
assert.equal(identityMsg0.metadata.identityTips, null, 'identityTips')
|
||||
assert.deepEqual(identityMsg0.metadata.tangles, {}, 'tangles')
|
||||
assert.equal(identityMsg0.metadata.domain, 'person', 'domain')
|
||||
assert.equal(identityMsg0.metadata.v, 3, 'v')
|
||||
assert.equal(identityMsg0.pubkey, keypair.public, 'pubkey')
|
||||
assert.equal(accountMsg0.metadata.dataHash, 'R5az9nC1CB3Afd5Q57HYRQ', 'hash')
|
||||
assert.equal(accountMsg0.metadata.dataSize, 172, 'size')
|
||||
assert.equal(accountMsg0.metadata.account, 'self', 'account')
|
||||
assert.equal(accountMsg0.metadata.accountTips, null, 'accountTips')
|
||||
assert.deepEqual(accountMsg0.metadata.tangles, {}, 'tangles')
|
||||
assert.equal(accountMsg0.metadata.domain, 'person', 'domain')
|
||||
assert.equal(accountMsg0.metadata.v, 3, 'v')
|
||||
assert.equal(accountMsg0.pubkey, keypair.public, 'pubkey')
|
||||
|
||||
identity = MsgV3.getMsgHash(identityMsg0)
|
||||
assert.equal(identity, 'GZJ1T864pFVHKJ2mRS2c5q', 'identity ID')
|
||||
account = MsgV3.getMsgHash(accountMsg0)
|
||||
assert.equal(account, 'J2SUr6XtJuFuTusNbagEW5', 'account ID')
|
||||
})
|
||||
|
||||
let rootMsg = null
|
||||
|
@ -44,21 +44,21 @@ let rootHash = null
|
|||
test('MsgV3.createRoot()', (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
|
||||
rootMsg = MsgV3.createRoot(identity, 'post', keypair)
|
||||
rootMsg = MsgV3.createRoot(account, 'post', keypair)
|
||||
console.log(JSON.stringify(rootMsg, null, 2))
|
||||
|
||||
assert.equal(rootMsg.data, null, 'data')
|
||||
assert.equal(rootMsg.metadata.dataHash, null, 'hash')
|
||||
assert.equal(rootMsg.metadata.dataSize, 0, 'size')
|
||||
assert.equal(rootMsg.metadata.identity, identity, 'identity')
|
||||
assert.equal(rootMsg.metadata.identityTips, null, 'identityTips')
|
||||
assert.equal(rootMsg.metadata.account, account, 'account')
|
||||
assert.equal(rootMsg.metadata.accountTips, null, 'accountTips')
|
||||
assert.deepEqual(rootMsg.metadata.tangles, {}, 'tangles')
|
||||
assert.equal(rootMsg.metadata.domain, 'post', 'domain')
|
||||
assert.equal(rootMsg.metadata.v, 3, 'v')
|
||||
assert.equal(rootMsg.pubkey, keypair.public, 'pubkey')
|
||||
|
||||
rootHash = MsgV3.getMsgHash(rootMsg)
|
||||
assert.equal(rootHash, '4VfVj9DQArX5Vk6PVz5s5J', 'root hash')
|
||||
assert.equal(rootHash, 'VsBFptgidvAspk4xTKZx6c', 'root hash')
|
||||
})
|
||||
|
||||
test('MsgV3.create()', (t) => {
|
||||
|
@ -71,8 +71,8 @@ test('MsgV3.create()', (t) => {
|
|||
const msg1 = MsgV3.create({
|
||||
keypair,
|
||||
data,
|
||||
identity,
|
||||
identityTips: [identity],
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[rootHash]: tangle1,
|
||||
|
@ -86,8 +86,8 @@ test('MsgV3.create()', (t) => {
|
|||
[
|
||||
'dataHash',
|
||||
'dataSize',
|
||||
'identity',
|
||||
'identityTips',
|
||||
'account',
|
||||
'accountTips',
|
||||
'tangles',
|
||||
'domain',
|
||||
'v',
|
||||
|
@ -100,11 +100,11 @@ test('MsgV3.create()', (t) => {
|
|||
'metadata.dataHash'
|
||||
)
|
||||
assert.deepEqual(msg1.metadata.dataSize, 23, 'metadata.dataSize')
|
||||
assert.equal(msg1.metadata.identity, identity, 'metadata.identity')
|
||||
assert.equal(msg1.metadata.account, account, 'metadata.account')
|
||||
assert.deepEqual(
|
||||
msg1.metadata.identityTips,
|
||||
[identity],
|
||||
'metadata.identityTips'
|
||||
msg1.metadata.accountTips,
|
||||
[account],
|
||||
'metadata.accountTips'
|
||||
)
|
||||
assert.deepEqual(
|
||||
Object.keys(msg1.metadata.tangles),
|
||||
|
@ -126,15 +126,15 @@ test('MsgV3.create()', (t) => {
|
|||
)
|
||||
assert.equal(
|
||||
msg1.sig,
|
||||
'23CPZzKBAeRa6gb2ijwUJAd4VrYmokLSbQTmWEFMCiSogjViwqvms6ShyPq1UCzNWKAggmmJP4qETnVrY4iEMQ5J',
|
||||
'46CjqZzC8RAanRHnUKs147PMNFvrQcc9Y7a8tMP3s4qQubCtgYsypgzNA7XkSxM6vqRCe2ZBSKM2WR9AoHN3VoDz',
|
||||
'sig'
|
||||
)
|
||||
|
||||
const msgHash1 = 'kF6XHyi1LtJdttRDp54VM'
|
||||
const msgHash1 = 'R5G9WtDAQrco4FABRdvrUH'
|
||||
|
||||
assert.equal(
|
||||
MsgV3.getMsgId(msg1),
|
||||
`ppppp:message/v3/${identity}/post/${msgHash1}`,
|
||||
`ppppp:message/v3/${account}/post/${msgHash1}`,
|
||||
'getMsgId'
|
||||
)
|
||||
|
||||
|
@ -147,8 +147,8 @@ test('MsgV3.create()', (t) => {
|
|||
const msg2 = MsgV3.create({
|
||||
keypair,
|
||||
data: data2,
|
||||
identity,
|
||||
identityTips: [identity],
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[rootHash]: tangle2,
|
||||
|
@ -162,8 +162,8 @@ test('MsgV3.create()', (t) => {
|
|||
[
|
||||
'dataHash',
|
||||
'dataSize',
|
||||
'identity',
|
||||
'identityTips',
|
||||
'account',
|
||||
'accountTips',
|
||||
'tangles',
|
||||
'domain',
|
||||
'v',
|
||||
|
@ -176,11 +176,11 @@ test('MsgV3.create()', (t) => {
|
|||
'metadata.dataHash'
|
||||
)
|
||||
assert.deepEqual(msg2.metadata.dataSize, 21, 'metadata.dataSize')
|
||||
assert.equal(msg2.metadata.identity, identity, 'metadata.identity')
|
||||
assert.equal(msg2.metadata.account, account, 'metadata.account')
|
||||
assert.deepEqual(
|
||||
msg2.metadata.identityTips,
|
||||
[identity],
|
||||
'metadata.identityTips'
|
||||
msg2.metadata.accountTips,
|
||||
[account],
|
||||
'metadata.accountTips'
|
||||
)
|
||||
assert.deepEqual(
|
||||
Object.keys(msg2.metadata.tangles),
|
||||
|
@ -202,13 +202,13 @@ test('MsgV3.create()', (t) => {
|
|||
)
|
||||
assert.equal(
|
||||
msg2.sig,
|
||||
'tpMaMqV7t4hhYtLPZu7nFmUZej3pXVAYWf3pwXChThsQ8qT9Zxxym2TDDTUrT9VF7CNXRnLNoLMgYuZKAQrZ5bR',
|
||||
'31StEDDnoDoDtRi49L94XPTGXxNtDJa9QXSJTd4o3wBtFAJvfQA1RsHvunU4CxdY9iC69WnxnkaW6QryrztJZkiA',
|
||||
'sig'
|
||||
)
|
||||
|
||||
assert.deepEqual(
|
||||
MsgV3.getMsgId(msg2),
|
||||
`ppppp:message/v3/${identity}/post/7W2nJCdpMeco7D8BYvRq7A`,
|
||||
`ppppp:message/v3/${account}/post/LxWgRRr4wXd29sLDNGNTkr`,
|
||||
'getMsgId'
|
||||
)
|
||||
})
|
||||
|
@ -221,8 +221,8 @@ test('create() handles DAG tips correctly', (t) => {
|
|||
const msg1 = MsgV3.create({
|
||||
keypair,
|
||||
data: { text: '1' },
|
||||
identity,
|
||||
identityTips: [identity],
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[rootHash]: tangle,
|
||||
|
@ -231,7 +231,7 @@ test('create() handles DAG tips correctly', (t) => {
|
|||
const msgHash1 = MsgV3.getMsgHash(msg1)
|
||||
assert.deepEqual(
|
||||
msg1.metadata.tangles[rootHash].prev,
|
||||
[MsgV3.getFeedRootHash(identity, 'post')],
|
||||
[MsgV3.getFeedRootHash(account, 'post')],
|
||||
'msg1.prev is root'
|
||||
)
|
||||
|
||||
|
@ -240,8 +240,8 @@ test('create() handles DAG tips correctly', (t) => {
|
|||
const msg2A = MsgV3.create({
|
||||
keypair,
|
||||
data: { text: '2A' },
|
||||
identity,
|
||||
identityTips: [identity],
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[rootHash]: tangle,
|
||||
|
@ -256,8 +256,8 @@ test('create() handles DAG tips correctly', (t) => {
|
|||
const msg2B = MsgV3.create({
|
||||
keypair,
|
||||
data: { text: '2B' },
|
||||
identity,
|
||||
identityTips: [identity],
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[rootHash]: tangle,
|
||||
|
@ -275,8 +275,8 @@ test('create() handles DAG tips correctly', (t) => {
|
|||
const msg3 = MsgV3.create({
|
||||
keypair,
|
||||
data: { text: '3' },
|
||||
identity,
|
||||
identityTips: [identity],
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[rootHash]: tangle,
|
||||
|
@ -297,8 +297,8 @@ test('create() handles DAG tips correctly', (t) => {
|
|||
const msg4 = MsgV3.create({
|
||||
keypair,
|
||||
data: { text: '4' },
|
||||
identity,
|
||||
identityTips: [identity],
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[rootHash]: tangle,
|
||||
|
|
|
@ -5,15 +5,15 @@ const Keypair = require('ppppp-keypair')
|
|||
const MsgV3 = require('../../lib/msg-v3')
|
||||
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
const identity = MsgV3.getMsgHash(
|
||||
MsgV3.createIdentity(keypair, 'person', 'MYNONCE')
|
||||
const account = MsgV3.getMsgHash(
|
||||
MsgV3.createAccount(keypair, 'person', 'MYNONCE')
|
||||
)
|
||||
const pubkeys = new Set([keypair.public])
|
||||
|
||||
test('invalid msg with non-array prev', (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
|
||||
const rootMsg = MsgV3.createRoot(identity, 'post', keypair)
|
||||
const rootMsg = MsgV3.createRoot(account, 'post', keypair)
|
||||
const rootHash = MsgV3.getMsgHash(rootMsg)
|
||||
|
||||
const tangle = new MsgV3.Tangle(rootHash)
|
||||
|
@ -22,8 +22,8 @@ test('invalid msg with non-array prev', (t) => {
|
|||
const msg = MsgV3.create({
|
||||
keypair,
|
||||
data: { text: 'Hello world!' },
|
||||
identity,
|
||||
identityTips: [identity],
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[rootHash]: tangle,
|
||||
|
@ -44,7 +44,7 @@ test('invalid msg with non-array prev', (t) => {
|
|||
test('invalid msg with bad prev', (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
|
||||
const rootMsg = MsgV3.createRoot(identity, 'post', keypair)
|
||||
const rootMsg = MsgV3.createRoot(account, 'post', keypair)
|
||||
const rootHash = MsgV3.getMsgHash(rootMsg)
|
||||
|
||||
const tangle = new MsgV3.Tangle(rootHash)
|
||||
|
@ -53,8 +53,8 @@ test('invalid msg with bad prev', (t) => {
|
|||
const msg1 = MsgV3.create({
|
||||
keypair,
|
||||
data: { text: 'Hello world!' },
|
||||
identity,
|
||||
identityTips: [identity],
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[rootHash]: tangle,
|
||||
|
@ -66,8 +66,8 @@ test('invalid msg with bad prev', (t) => {
|
|||
const msg2 = MsgV3.create({
|
||||
keypair,
|
||||
data: { text: 'Hello world!' },
|
||||
identity,
|
||||
identityTips: [identity],
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[rootHash]: tangle,
|
||||
|
@ -89,7 +89,7 @@ test('invalid msg with bad prev', (t) => {
|
|||
test('invalid msg with URI in prev', (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
|
||||
const rootMsg = MsgV3.createRoot(identity, 'post', keypair)
|
||||
const rootMsg = MsgV3.createRoot(account, 'post', keypair)
|
||||
const rootHash = MsgV3.getMsgHash(rootMsg)
|
||||
|
||||
const tangle = new MsgV3.Tangle(rootHash)
|
||||
|
@ -98,8 +98,8 @@ test('invalid msg with URI in prev', (t) => {
|
|||
const msg1 = MsgV3.create({
|
||||
keypair,
|
||||
data: { text: 'Hello world!' },
|
||||
identity,
|
||||
identityTips: [identity],
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[rootHash]: tangle,
|
||||
|
@ -111,8 +111,8 @@ test('invalid msg with URI in prev', (t) => {
|
|||
const msg2 = MsgV3.create({
|
||||
keypair,
|
||||
data: { text: 'Hello world!' },
|
||||
identity,
|
||||
identityTips: [identity],
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[rootHash]: tangle,
|
||||
|
@ -132,7 +132,7 @@ test('invalid msg with URI in prev', (t) => {
|
|||
test('invalid msg with unknown prev', (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
|
||||
const rootMsg = MsgV3.createRoot(identity, 'post', keypair)
|
||||
const rootMsg = MsgV3.createRoot(account, 'post', keypair)
|
||||
const rootHash = MsgV3.getMsgHash(rootMsg)
|
||||
|
||||
const tangle = new MsgV3.Tangle(rootHash)
|
||||
|
@ -141,8 +141,8 @@ test('invalid msg with unknown prev', (t) => {
|
|||
const msg1 = MsgV3.create({
|
||||
keypair,
|
||||
data: { text: 'Hello world!' },
|
||||
identity,
|
||||
identityTips: [identity],
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[rootHash]: tangle,
|
||||
|
@ -154,8 +154,8 @@ test('invalid msg with unknown prev', (t) => {
|
|||
const unknownMsg = MsgV3.create({
|
||||
keypair,
|
||||
data: { text: 'Alien' },
|
||||
identity,
|
||||
identityTips: [identity],
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[rootHash]: tangle,
|
||||
|
@ -171,8 +171,8 @@ test('invalid msg with unknown prev', (t) => {
|
|||
const msg2 = MsgV3.create({
|
||||
keypair,
|
||||
data: { text: 'Hello world!' },
|
||||
identity,
|
||||
identityTips: [identity],
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[rootHash]: tangle2,
|
||||
|
@ -193,11 +193,11 @@ test('invalid feed msg with a different pubkey', (t) => {
|
|||
const keypairA = Keypair.generate('ed25519', 'alice')
|
||||
const keypairB = Keypair.generate('ed25519', 'bob')
|
||||
|
||||
const identityB = MsgV3.getMsgHash(
|
||||
MsgV3.createIdentity(keypairB, 'person', 'MYNONCE')
|
||||
const accountB = MsgV3.getMsgHash(
|
||||
MsgV3.createAccount(keypairB, 'person', 'MYNONCE')
|
||||
)
|
||||
|
||||
const rootMsg = MsgV3.createRoot(identity, 'post', keypair)
|
||||
const rootMsg = MsgV3.createRoot(account, 'post', keypair)
|
||||
const rootHash = MsgV3.getMsgHash(rootMsg)
|
||||
const feedTangle = new MsgV3.Tangle(rootHash)
|
||||
feedTangle.add(rootHash, rootMsg)
|
||||
|
@ -205,8 +205,8 @@ test('invalid feed msg with a different pubkey', (t) => {
|
|||
const msg = MsgV3.create({
|
||||
keypair: keypairB,
|
||||
data: { text: 'Hello world!' },
|
||||
identity: identityB,
|
||||
identityTips: [identityB],
|
||||
account: accountB,
|
||||
accountTips: [accountB],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[rootHash]: feedTangle,
|
||||
|
@ -218,7 +218,7 @@ test('invalid feed msg with a different pubkey', (t) => {
|
|||
assert.ok(err, 'invalid msg throws')
|
||||
assert.match(
|
||||
err,
|
||||
/pubkey ".*" should have been one of ".*" from the identity ".*"/,
|
||||
/pubkey ".*" should have been one of ".*" from the account ".*"/,
|
||||
'invalid msg'
|
||||
)
|
||||
})
|
||||
|
@ -226,7 +226,7 @@ test('invalid feed msg with a different pubkey', (t) => {
|
|||
test('invalid feed msg with a different domain', (t) => {
|
||||
const keypairA = Keypair.generate('ed25519', 'alice')
|
||||
|
||||
const rootMsg = MsgV3.createRoot(identity, 'post', keypair)
|
||||
const rootMsg = MsgV3.createRoot(account, 'post', keypair)
|
||||
const rootHash = MsgV3.getMsgHash(rootMsg)
|
||||
const feedTangle = new MsgV3.Tangle(rootHash)
|
||||
feedTangle.add(rootHash, rootMsg)
|
||||
|
@ -234,8 +234,8 @@ test('invalid feed msg with a different domain', (t) => {
|
|||
const msg = MsgV3.create({
|
||||
keypair: keypairA,
|
||||
data: { text: 'Hello world!' },
|
||||
identity,
|
||||
identityTips: [identity],
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'comment',
|
||||
tangles: {
|
||||
[rootHash]: feedTangle,
|
||||
|
@ -255,7 +255,7 @@ test('invalid feed msg with a different domain', (t) => {
|
|||
test('invalid feed msg with non-alphabetical prev', (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
|
||||
const rootMsg = MsgV3.createRoot(identity, 'post', keypair)
|
||||
const rootMsg = MsgV3.createRoot(account, 'post', keypair)
|
||||
const rootHash = MsgV3.getMsgHash(rootMsg)
|
||||
|
||||
const tangle = new MsgV3.Tangle(rootHash)
|
||||
|
@ -264,8 +264,8 @@ test('invalid feed msg with non-alphabetical prev', (t) => {
|
|||
const msg1 = MsgV3.create({
|
||||
keypair,
|
||||
data: { text: '1' },
|
||||
identity,
|
||||
identityTips: [identity],
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[rootHash]: tangle,
|
||||
|
@ -276,8 +276,8 @@ test('invalid feed msg with non-alphabetical prev', (t) => {
|
|||
const msg2 = MsgV3.create({
|
||||
keypair,
|
||||
data: { text: '2' },
|
||||
identity,
|
||||
identityTips: [identity],
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[rootHash]: tangle,
|
||||
|
@ -291,8 +291,8 @@ test('invalid feed msg with non-alphabetical prev', (t) => {
|
|||
const msg3 = MsgV3.create({
|
||||
keypair,
|
||||
data: { text: '3' },
|
||||
identity,
|
||||
identityTips: [identity],
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[rootHash]: tangle,
|
||||
|
@ -320,7 +320,7 @@ test('invalid feed msg with non-alphabetical prev', (t) => {
|
|||
test('invalid feed msg with duplicate prev', (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
|
||||
const rootMsg = MsgV3.createRoot(identity, 'post', keypair)
|
||||
const rootMsg = MsgV3.createRoot(account, 'post', keypair)
|
||||
const rootHash = MsgV3.getMsgHash(rootMsg)
|
||||
|
||||
const tangle = new MsgV3.Tangle(rootHash)
|
||||
|
@ -329,8 +329,8 @@ test('invalid feed msg with duplicate prev', (t) => {
|
|||
const msg1 = MsgV3.create({
|
||||
keypair,
|
||||
data: { text: '1' },
|
||||
identity,
|
||||
identityTips: [identity],
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
tangles: {
|
||||
[rootHash]: tangle,
|
||||
|
|
|
@ -5,19 +5,19 @@ const MsgV3 = require('../../lib/msg-v3')
|
|||
|
||||
test('lipmaa prevs', (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
const identity = MsgV3.getMsgHash(
|
||||
MsgV3.createIdentity(keypair, 'person', 'MYNONCE')
|
||||
const account = MsgV3.getMsgHash(
|
||||
MsgV3.createAccount(keypair, 'person', 'MYNONCE')
|
||||
)
|
||||
const data = { text: 'Hello world!' }
|
||||
|
||||
const rootMsg = MsgV3.createRoot(identity, 'post', keypair)
|
||||
const rootMsg = MsgV3.createRoot(account, 'post', keypair)
|
||||
const rootHash = MsgV3.getMsgHash(rootMsg)
|
||||
const tangle = new MsgV3.Tangle(rootHash)
|
||||
tangle.add(rootHash, rootMsg)
|
||||
|
||||
const msg1 = MsgV3.create({
|
||||
identity,
|
||||
identityTips: [identity],
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
data,
|
||||
tangles: {
|
||||
|
@ -35,8 +35,8 @@ test('lipmaa prevs', (t) => {
|
|||
)
|
||||
|
||||
const msg2 = MsgV3.create({
|
||||
identity,
|
||||
identityTips: [identity],
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
data,
|
||||
tangles: {
|
||||
|
@ -54,8 +54,8 @@ test('lipmaa prevs', (t) => {
|
|||
)
|
||||
|
||||
const msg3 = MsgV3.create({
|
||||
identity,
|
||||
identityTips: [identity],
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
data,
|
||||
tangles: {
|
||||
|
@ -73,8 +73,8 @@ test('lipmaa prevs', (t) => {
|
|||
)
|
||||
|
||||
const msg4 = MsgV3.create({
|
||||
identity,
|
||||
identityTips: [identity],
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
keypair,
|
||||
tangles: {
|
||||
|
@ -92,8 +92,8 @@ test('lipmaa prevs', (t) => {
|
|||
)
|
||||
|
||||
const msg5 = MsgV3.create({
|
||||
identity,
|
||||
identityTips: [identity],
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
data,
|
||||
tangles: {
|
||||
|
@ -111,8 +111,8 @@ test('lipmaa prevs', (t) => {
|
|||
)
|
||||
|
||||
const msg6 = MsgV3.create({
|
||||
identity,
|
||||
identityTips: [identity],
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
data,
|
||||
tangles: {
|
||||
|
@ -130,8 +130,8 @@ test('lipmaa prevs', (t) => {
|
|||
)
|
||||
|
||||
const msg7 = MsgV3.create({
|
||||
identity,
|
||||
identityTips: [identity],
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
data,
|
||||
tangles: {
|
||||
|
|
|
@ -6,26 +6,26 @@ const MsgV3 = require('../../lib/msg-v3')
|
|||
test('simple multi-author tangle', (t) => {
|
||||
const keypairA = Keypair.generate('ed25519', 'alice')
|
||||
const keypairB = Keypair.generate('ed25519', 'bob')
|
||||
const identityA = MsgV3.getMsgHash(
|
||||
MsgV3.createIdentity(keypairA, 'person', 'alice')
|
||||
const accountA = MsgV3.getMsgHash(
|
||||
MsgV3.createAccount(keypairA, 'person', 'alice')
|
||||
)
|
||||
const identityB = MsgV3.getMsgHash(
|
||||
MsgV3.createIdentity(keypairB, 'person', 'bob')
|
||||
const accountB = MsgV3.getMsgHash(
|
||||
MsgV3.createAccount(keypairB, 'person', 'bob')
|
||||
)
|
||||
|
||||
const rootMsgA = MsgV3.createRoot(identityA, 'post', keypairA)
|
||||
const rootMsgA = MsgV3.createRoot(accountA, 'post', keypairA)
|
||||
const rootHashA = MsgV3.getMsgHash(rootMsgA)
|
||||
const tangleA = new MsgV3.Tangle(rootHashA)
|
||||
tangleA.add(rootHashA, rootMsgA)
|
||||
|
||||
const rootMsgB = MsgV3.createRoot(identityB, 'post', keypairB)
|
||||
const rootMsgB = MsgV3.createRoot(accountB, 'post', keypairB)
|
||||
const rootHashB = MsgV3.getMsgHash(rootMsgB)
|
||||
const tangleB = new MsgV3.Tangle(rootHashB)
|
||||
tangleB.add(rootHashB, rootMsgB)
|
||||
|
||||
const msg1 = MsgV3.create({
|
||||
identity: identityA,
|
||||
identityTips: [identityA],
|
||||
account: accountA,
|
||||
accountTips: [accountA],
|
||||
domain: 'post',
|
||||
data: { text: 'Hello world!' },
|
||||
tangles: {
|
||||
|
@ -44,8 +44,8 @@ test('simple multi-author tangle', (t) => {
|
|||
tangleX.add(msgHash1, msg1)
|
||||
|
||||
const msg2 = MsgV3.create({
|
||||
identity: identityB,
|
||||
identityTips: [identityB],
|
||||
account: accountB,
|
||||
accountTips: [accountB],
|
||||
domain: 'post',
|
||||
data: { text: 'Hello world!' },
|
||||
tangles: {
|
||||
|
@ -86,28 +86,28 @@ test('simple multi-author tangle', (t) => {
|
|||
test('lipmaa in multi-author tangle', (t) => {
|
||||
const keypairA = Keypair.generate('ed25519', 'alice')
|
||||
const keypairB = Keypair.generate('ed25519', 'bob')
|
||||
const identityA = MsgV3.getMsgHash(
|
||||
MsgV3.createIdentity(keypairA, 'person', 'alice')
|
||||
const accountA = MsgV3.getMsgHash(
|
||||
MsgV3.createAccount(keypairA, 'person', 'alice')
|
||||
)
|
||||
const identityB = MsgV3.getMsgHash(
|
||||
MsgV3.createIdentity(keypairB, 'person', 'bob')
|
||||
const accountB = MsgV3.getMsgHash(
|
||||
MsgV3.createAccount(keypairB, 'person', 'bob')
|
||||
)
|
||||
|
||||
const data = { text: 'Hello world!' }
|
||||
|
||||
const rootMsgA = MsgV3.createRoot(identityA, 'post', keypairA)
|
||||
const rootMsgA = MsgV3.createRoot(accountA, 'post', keypairA)
|
||||
const rootHashA = MsgV3.getMsgHash(rootMsgA)
|
||||
const tangleA = new MsgV3.Tangle(rootHashA)
|
||||
tangleA.add(rootHashA, rootMsgA)
|
||||
|
||||
const rootMsgB = MsgV3.createRoot(identityB, 'post', keypairB)
|
||||
const rootMsgB = MsgV3.createRoot(accountB, 'post', keypairB)
|
||||
const rootHashB = MsgV3.getMsgHash(rootMsgB)
|
||||
const tangleB = new MsgV3.Tangle(rootHashB)
|
||||
tangleB.add(rootHashB, rootMsgB)
|
||||
|
||||
const msg1 = MsgV3.create({
|
||||
identity: identityA,
|
||||
identityTips: [identityA],
|
||||
account: accountA,
|
||||
accountTips: [accountA],
|
||||
domain: 'post',
|
||||
data,
|
||||
tangles: {
|
||||
|
@ -127,8 +127,8 @@ test('lipmaa in multi-author tangle', (t) => {
|
|||
)
|
||||
|
||||
const msg2 = MsgV3.create({
|
||||
identity: identityB,
|
||||
identityTips: [identityB],
|
||||
account: accountB,
|
||||
accountTips: [accountB],
|
||||
domain: 'post',
|
||||
data,
|
||||
tangles: {
|
||||
|
@ -148,8 +148,8 @@ test('lipmaa in multi-author tangle', (t) => {
|
|||
)
|
||||
|
||||
const msg3 = MsgV3.create({
|
||||
identity: identityB,
|
||||
identityTips: [identityB],
|
||||
account: accountB,
|
||||
accountTips: [accountB],
|
||||
domain: 'post',
|
||||
data,
|
||||
tangles: {
|
||||
|
@ -169,8 +169,8 @@ test('lipmaa in multi-author tangle', (t) => {
|
|||
)
|
||||
|
||||
const msg4 = MsgV3.create({
|
||||
identity: identityA,
|
||||
identityTips: [identityA],
|
||||
account: accountA,
|
||||
accountTips: [accountA],
|
||||
domain: 'post',
|
||||
data,
|
||||
tangles: {
|
||||
|
|
|
@ -5,12 +5,12 @@ const MsgV3 = require('../../lib/msg-v3')
|
|||
|
||||
test('validate root msg', (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
const identity = MsgV3.getMsgHash(
|
||||
MsgV3.createIdentity(keypair, 'person', 'alice')
|
||||
const account = MsgV3.getMsgHash(
|
||||
MsgV3.createAccount(keypair, 'person', 'alice')
|
||||
)
|
||||
const pubkeys = new Set([keypair.public])
|
||||
|
||||
const rootMsg = MsgV3.createRoot(identity, 'post', keypair)
|
||||
const rootMsg = MsgV3.createRoot(account, 'post', keypair)
|
||||
const rootHash = MsgV3.getMsgHash(rootMsg)
|
||||
const tangle = new MsgV3.Tangle(rootHash)
|
||||
|
||||
|
@ -18,67 +18,67 @@ test('validate root msg', (t) => {
|
|||
assert.ifError(err, 'valid root msg')
|
||||
})
|
||||
|
||||
test('validate identity tangle', (t) => {
|
||||
test('validate account tangle', (t) => {
|
||||
const pubkeys = new Set()
|
||||
const keypair1 = Keypair.generate('ed25519', 'alice')
|
||||
pubkeys.add(keypair1.public)
|
||||
|
||||
const identityMsg0 = MsgV3.createIdentity(keypair1, 'person', 'alice')
|
||||
const identity = MsgV3.getMsgHash(identityMsg0)
|
||||
const identityMsg0Hash = identity
|
||||
const accountMsg0 = MsgV3.createAccount(keypair1, 'person', 'alice')
|
||||
const account = MsgV3.getMsgHash(accountMsg0)
|
||||
const accountMsg0Hash = account
|
||||
|
||||
const tangle = new MsgV3.Tangle(identity)
|
||||
const tangle = new MsgV3.Tangle(account)
|
||||
|
||||
let err = MsgV3.validate(
|
||||
identityMsg0,
|
||||
accountMsg0,
|
||||
tangle,
|
||||
pubkeys,
|
||||
identityMsg0Hash,
|
||||
identity
|
||||
accountMsg0Hash,
|
||||
account
|
||||
)
|
||||
assert.ifError(err, 'valid identity root msg')
|
||||
assert.ifError(err, 'valid account root msg')
|
||||
|
||||
tangle.add(identity, identityMsg0)
|
||||
tangle.add(account, accountMsg0)
|
||||
|
||||
const keypair2 = Keypair.generate('ed25519', 'bob')
|
||||
|
||||
const identityMsg1 = MsgV3.create({
|
||||
identity: 'self',
|
||||
identityTips: null,
|
||||
domain: 'identity',
|
||||
const accountMsg1 = MsgV3.create({
|
||||
account: 'self',
|
||||
accountTips: null,
|
||||
domain: 'account',
|
||||
data: { add: keypair2.public },
|
||||
tangles: {
|
||||
[identity]: tangle,
|
||||
[account]: tangle,
|
||||
},
|
||||
keypair: keypair1, // announcing keypair2 but signing with keypair1
|
||||
})
|
||||
const identityMsg1Hash = MsgV3.getMsgHash(identityMsg1)
|
||||
const accountMsg1Hash = MsgV3.getMsgHash(accountMsg1)
|
||||
|
||||
err = MsgV3.validate(
|
||||
identityMsg1,
|
||||
accountMsg1,
|
||||
tangle,
|
||||
pubkeys,
|
||||
identityMsg1Hash,
|
||||
identity
|
||||
accountMsg1Hash,
|
||||
account
|
||||
)
|
||||
assert.ifError(err, 'valid identity msg')
|
||||
assert.ifError(err, 'valid account msg')
|
||||
})
|
||||
|
||||
test('validate 2nd msg with existing root', (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
const identity = MsgV3.getMsgHash(
|
||||
MsgV3.createIdentity(keypair, 'person', 'alice')
|
||||
const account = MsgV3.getMsgHash(
|
||||
MsgV3.createAccount(keypair, 'person', 'alice')
|
||||
)
|
||||
const pubkeys = new Set([keypair.public])
|
||||
|
||||
const rootMsg = MsgV3.createRoot(identity, 'post', keypair)
|
||||
const rootMsg = MsgV3.createRoot(account, 'post', keypair)
|
||||
const rootHash = MsgV3.getMsgHash(rootMsg)
|
||||
const tangle = new MsgV3.Tangle(rootHash)
|
||||
tangle.add(rootHash, rootMsg)
|
||||
|
||||
const msg1 = MsgV3.create({
|
||||
identity,
|
||||
identityTips: [identity],
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
data: { text: 'Hello world!' },
|
||||
tangles: {
|
||||
|
@ -95,19 +95,19 @@ test('validate 2nd msg with existing root', (t) => {
|
|||
|
||||
test('validate 2nd forked msg', (t) => {
|
||||
const keypair = Keypair.generate('ed25519', 'alice')
|
||||
const identity = MsgV3.getMsgHash(
|
||||
MsgV3.createIdentity(keypair, 'person', 'alice')
|
||||
const account = MsgV3.getMsgHash(
|
||||
MsgV3.createAccount(keypair, 'person', 'alice')
|
||||
)
|
||||
const pubkeys = new Set([keypair.public])
|
||||
|
||||
const rootMsg = MsgV3.createRoot(identity, 'post', keypair)
|
||||
const rootMsg = MsgV3.createRoot(account, 'post', keypair)
|
||||
const rootHash = MsgV3.getMsgHash(rootMsg)
|
||||
const tangle = new MsgV3.Tangle(rootHash)
|
||||
tangle.add(rootHash, rootMsg)
|
||||
|
||||
const msg1A = MsgV3.create({
|
||||
identity,
|
||||
identityTips: [identity],
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
data: { text: 'Hello world!' },
|
||||
tangles: {
|
||||
|
@ -118,8 +118,8 @@ test('validate 2nd forked msg', (t) => {
|
|||
const msgHash1A = MsgV3.getMsgHash(msg1A)
|
||||
|
||||
const msg1B = MsgV3.create({
|
||||
identity,
|
||||
identityTips: [identity],
|
||||
account,
|
||||
accountTips: [account],
|
||||
domain: 'post',
|
||||
data: { text: 'Hello world!' },
|
||||
tangles: {
|
||||
|
|
|
@ -19,11 +19,11 @@ test('msgs() iterator', async (t) => {
|
|||
|
||||
await peer.db.loaded()
|
||||
|
||||
const identity = (await p(peer.db.identity.create)({domain: 'person'}))
|
||||
const account = (await p(peer.db.account.create)({domain: 'person'}))
|
||||
|
||||
for (let i = 0; i < 6; i++) {
|
||||
await p(peer.db.feed.publish)({
|
||||
identity,
|
||||
account,
|
||||
domain: i % 2 === 0 ? 'post' : 'about',
|
||||
data:
|
||||
i % 2 === 0
|
||||
|
|
|
@ -19,7 +19,7 @@ test('onRecordAdded', async (t) => {
|
|||
|
||||
await peer.db.loaded()
|
||||
|
||||
const identity = (await p(peer.db.identity.create)({domain: 'person'}))
|
||||
const account = (await p(peer.db.account.create)({domain: 'person'}))
|
||||
|
||||
const listened = []
|
||||
var remove = peer.db.onRecordAdded((ev) => {
|
||||
|
@ -27,7 +27,7 @@ test('onRecordAdded', async (t) => {
|
|||
})
|
||||
|
||||
const rec1 = await p(peer.db.feed.publish)({
|
||||
identity,
|
||||
account,
|
||||
domain: 'post',
|
||||
data: { text: 'I am hungry' },
|
||||
})
|
||||
|
@ -36,7 +36,7 @@ test('onRecordAdded', async (t) => {
|
|||
await p(setTimeout)(500)
|
||||
|
||||
assert.equal(listened.length, 3)
|
||||
assert.equal(listened[0].msg.metadata.identity, 'self', 'identity root')
|
||||
assert.equal(listened[0].msg.metadata.account, 'self', 'account root')
|
||||
assert.equal(listened[1].msg.data, null, 'root')
|
||||
assert.equal(listened[1].msg.metadata.dataSize, 0, 'root')
|
||||
assert.deepEqual(listened[2], rec1, 'actual record')
|
||||
|
|
|
@ -19,13 +19,13 @@ test('publish some msgs, close, re-open', async (t) => {
|
|||
.call(null, { keypair, path: DIR })
|
||||
|
||||
await peer.db.loaded()
|
||||
const identity = await p(peer.db.identity.create)({ domain: 'person' })
|
||||
const account = await p(peer.db.account.create)({ domain: 'person' })
|
||||
// t.pass('opened db')
|
||||
|
||||
const msgHashes = []
|
||||
for (let i = 0; i < 6; i++) {
|
||||
const rec = await p(peer.db.feed.publish)({
|
||||
identity,
|
||||
account,
|
||||
domain: 'post',
|
||||
data: { text: 'hello ' + i },
|
||||
})
|
||||
|
@ -49,7 +49,7 @@ test('publish some msgs, close, re-open', async (t) => {
|
|||
|
||||
const texts = []
|
||||
for (const msg of peer2.db.msgs()) {
|
||||
if (!msg.data || !(msg.metadata.identity?.length > 4)) continue
|
||||
if (!msg.data || !(msg.metadata.account?.length > 4)) continue
|
||||
texts.push(msg.data.text)
|
||||
}
|
||||
|
||||
|
|
|
@ -18,11 +18,11 @@ test('records() iterator', async (t) => {
|
|||
.call(null, { keypair, path: DIR })
|
||||
|
||||
await peer.db.loaded()
|
||||
const identity = (await p(peer.db.identity.create)({ domain: 'person' }))
|
||||
const account = (await p(peer.db.account.create)({ domain: 'person' }))
|
||||
|
||||
for (let i = 0; i < 6; i++) {
|
||||
await p(peer.db.feed.publish)({
|
||||
identity,
|
||||
account,
|
||||
domain: i % 2 === 0 ? 'post' : 'about',
|
||||
data:
|
||||
i % 2 === 0
|
||||
|
@ -34,7 +34,7 @@ test('records() iterator', async (t) => {
|
|||
let count = 0
|
||||
for (const rec of peer.db.records()) {
|
||||
if (!rec.msg.data) continue
|
||||
if (rec.msg.metadata.identity === 'self') continue
|
||||
if (rec.msg.metadata.account === 'self') continue
|
||||
assert.ok(rec.misc.size > rec.msg.metadata.dataSize, 'size > dataSize')
|
||||
count++
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue