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