diff --git a/app/lib/blockchain/DuniterBlockchain.ts b/app/lib/blockchain/DuniterBlockchain.ts index 93e8e963966f86035d3933b187e7ca2f04b2775d..220ef7440fa19165effe224223b8f123a3bd775c 100644 --- a/app/lib/blockchain/DuniterBlockchain.ts +++ b/app/lib/blockchain/DuniterBlockchain.ts @@ -305,21 +305,21 @@ export class DuniterBlockchain extends MiscIndexedBlockchain { } } - async updateMembers(block:BlockDTO, dal:any) { + async updateMembers(block:BlockDTO, dal:FileDAL) { // Joiners (come back) for (const inlineMS of block.joiners) { let ms = MembershipDTO.fromInline(inlineMS) - const idty = await dal.getWrittenIdtyByPubkey(ms.issuer); + const idty = await dal.getWrittenIdtyByPubkeyForWotbID(ms.issuer); dal.wotb.setEnabled(true, idty.wotb_id); } // Revoked for (const inlineRevocation of block.revoked) { let revocation = RevocationDTO.fromInline(inlineRevocation) - await dal.revokeIdentity(revocation.pubkey, block.number); + await dal.revokeIdentity(revocation.pubkey) } // Excluded for (const excluded of block.excluded) { - const idty = await dal.getWrittenIdtyByPubkey(excluded); + const idty = await dal.getWrittenIdtyByPubkeyForWotbID(excluded); dal.wotb.setEnabled(false, idty.wotb_id); } } @@ -349,8 +349,8 @@ export class DuniterBlockchain extends MiscIndexedBlockchain { // Revert links const writtenOn = await dal.cindexDAL.getWrittenOn(blockstamp); for (const entry of writtenOn) { - const from = await dal.getWrittenIdtyByPubkey(entry.issuer); - const to = await dal.getWrittenIdtyByPubkey(entry.receiver); + const from = await dal.getWrittenIdtyByPubkeyForWotbID(entry.issuer); + const to = await dal.getWrittenIdtyByPubkeyForWotbID(entry.receiver); if (entry.op == CommonConstants.IDX_CREATE) { // We remove the created link dal.wotb.removeLink(from.wotb_id, to.wotb_id, true); @@ -394,7 +394,7 @@ export class DuniterBlockchain extends MiscIndexedBlockchain { // Undo 'join' which can be either newcomers or comebackers // => equivalent to i_index.member = true AND i_index.op = 'UPDATE' if (entry.member === true && entry.op === CommonConstants.IDX_UPDATE) { - const idty = await dal.getWrittenIdtyByPubkey(entry.pub); + const idty = await dal.getWrittenIdtyByPubkeyForWotbID(entry.pub); dal.wotb.setEnabled(false, idty.wotb_id); } } @@ -412,7 +412,7 @@ export class DuniterBlockchain extends MiscIndexedBlockchain { // Undo excluded (make them become members again in wotb) // => equivalent to m_index.member = false if (entry.member === false && entry.op === CommonConstants.IDX_UPDATE) { - const idty = await dal.getWrittenIdtyByPubkey(entry.pub); + const idty = await dal.getWrittenIdtyByPubkeyForWotbID(entry.pub); dal.wotb.setEnabled(true, idty.wotb_id); } } @@ -435,7 +435,7 @@ export class DuniterBlockchain extends MiscIndexedBlockchain { static async removeCertificationsFromSandbox(block:BlockDTO, dal:FileDAL) { for (let inlineCert of block.certifications) { let cert = CertificationDTO.fromInline(inlineCert) - let idty = await dal.getWrittenIdtyByPubkey(cert.to); + let idty = await dal.getWrittenIdtyByPubkeyForHashing(cert.to); await dal.deleteCert({ from: cert.from, target: IdentityDTO.getTargetHash(idty), diff --git a/app/lib/common-libs/errors.ts b/app/lib/common-libs/errors.ts new file mode 100644 index 0000000000000000000000000000000000000000..6286123f9cb4918ba9c1233001d4763d45ce4372 --- /dev/null +++ b/app/lib/common-libs/errors.ts @@ -0,0 +1,4 @@ + +export enum DataErrors { + MEMBER_NOT_FOUND +} diff --git a/app/lib/common-libs/rawer.ts b/app/lib/common-libs/rawer.ts index 568199c92a3a68b1db6c3666b8d0f2dd7ea2a576..9ed172071cad9d086bc01db5d13e3df19440d02b 100644 --- a/app/lib/common-libs/rawer.ts +++ b/app/lib/common-libs/rawer.ts @@ -31,7 +31,17 @@ export const getOfficialIdentity = (json:any, withSig = true) => { } } -export const getOfficialCertification = (json:any) => { +export const getOfficialCertification = (json:{ + version?:number + currency:string + issuer:string + idty_issuer:string + idty_uid:string + idty_buid:string + idty_sig:string + buid:string + sig?:string +}) => { let raw = getNormalHeader('Certification', json); raw += "IdtyIssuer: " + json.idty_issuer + '\n'; raw += "IdtyUniqueID: " + json.idty_uid + '\n'; @@ -91,7 +101,11 @@ export const getTransaction = (json:any) => { return TransactionDTO.toRAW(json) } -function getNormalHeader(doctype:string, json:any) { +function getNormalHeader(doctype:string, json:{ + version?:number + currency:string + issuer:string +}) { let raw = ""; raw += "Version: " + (json.version || DOCUMENTS_VERSION) + "\n"; raw += "Type: " + doctype + "\n"; diff --git a/app/lib/dal/fileDAL.ts b/app/lib/dal/fileDAL.ts index 04ba4af7b0ff5ffb18d7d5f7a1c1ba1ba21de1d2..e544a79e24efab4b694f00f72de2b4ebf351386b 100644 --- a/app/lib/dal/fileDAL.ts +++ b/app/lib/dal/fileDAL.ts @@ -18,7 +18,7 @@ import {ConfDTO} from "../dto/ConfDTO" import {BlockDTO} from "../dto/BlockDTO" import {DBHead} from "../db/DBHead" import {DBIdentity, IdentityDAL} from "./sqliteDAL/IdentityDAL" -import {CindexEntry, IindexEntry, IndexEntry, SindexEntry} from "../indexer" +import {CindexEntry, FullMindexEntry, IindexEntry, IndexEntry, SindexEntry} from "../indexer" import {DBPeer} from "./sqliteDAL/PeerDAL" import {TransactionDTO} from "../dto/TransactionDTO" import {CertDAL, DBCert} from "./sqliteDAL/CertDAL" @@ -35,6 +35,9 @@ import {BIndexDAL} from "./sqliteDAL/index/BIndexDAL" import {MIndexDAL} from "./sqliteDAL/index/MIndexDAL" import {CIndexDAL} from "./sqliteDAL/index/CIndexDAL" import {SIndexDAL} from "./sqliteDAL/index/SIndexDAL" +import {IIndexDAL} from "./sqliteDAL/index/IIndexDAL" +import {DataErrors} from "../common-libs/errors" +import {BasicRevocableIdentity, IdentityDTO} from "../dto/IdentityDTO" const fs = require('fs') const path = require('path') @@ -72,7 +75,7 @@ export class FileDAL { walletDAL:WalletDAL bindexDAL:BIndexDAL mindexDAL:MIndexDAL - iindexDAL:any + iindexDAL:IIndexDAL sindexDAL:SIndexDAL cindexDAL:CIndexDAL newDals:{ [k:string]: Initiable } @@ -297,36 +300,231 @@ export class FileDAL { return this.sindexDAL.getAvailableForPubkey(pubkey) } - async getIdentityByHashOrNull(hash:string): Promise<DBIdentity|null> { - const pending = await this.idtyDAL.getByHash(hash); + async getGlobalIdentityByHashForExistence(hash:string): Promise<boolean> { + const pending = await this.idtyDAL.getByHash(hash) if (!pending) { - return this.iindexDAL.getFromHash(hash); + const idty = await this.iindexDAL.getFullFromHash(hash) + if (!idty) { + return false + } + } + return true + } + + async getGlobalIdentityByHashForHashingAndSig(hash:string): Promise<{ pubkey:string, uid:string, buid:string, sig:string }|null> { + const pending = await this.idtyDAL.getByHash(hash) + if (!pending) { + const idty = await this.iindexDAL.getFullFromHash(hash) + if (!idty) { + return null + } + return { + pubkey: idty.pub, + uid: idty.uid, + buid: idty.created_on, + sig: idty.sig + } + } + return pending + } + + async getGlobalIdentityByHashForLookup(hash:string): Promise<{ pubkey:string, uid:string, buid:string, sig:string, member:boolean, wasMember:boolean }|null> { + const pending = await this.idtyDAL.getByHash(hash) + if (!pending) { + const idty = await this.iindexDAL.getFullFromHash(hash) + if (!idty) { + return null + } + return { + pubkey: idty.pub, + uid: idty.uid, + buid: idty.created_on, + sig: idty.sig, + member: idty.member, + wasMember: idty.wasMember + } + } + return pending + } + + async getGlobalIdentityByHashForJoining(hash:string): Promise<{ pubkey:string, uid:string, buid:string, sig:string, member:boolean, wasMember:boolean, revoked:boolean }|null> { + const pending = await this.idtyDAL.getByHash(hash) + if (!pending) { + const idty = await this.iindexDAL.getFullFromHash(hash) + if (!idty) { + return null + } + const membership = await this.mindexDAL.getReducedMS(idty.pub) as FullMindexEntry + return { + pubkey: idty.pub, + uid: idty.uid, + buid: idty.created_on, + sig: idty.sig, + member: idty.member, + wasMember: idty.wasMember, + revoked: !!(membership.revoked_on) + } + } + return pending + } + + async getGlobalIdentityByHashForIsMember(hash:string): Promise<{ pub:string, member:boolean }|null> { + const pending = await this.idtyDAL.getByHash(hash) + if (!pending) { + const idty = await this.iindexDAL.getFullFromHash(hash) + if (!idty) { + return null + } + return { + pub: idty.pub, + member: idty.member + } + } + return { + pub: pending.pubkey, + member: pending.member + } + } + + async getGlobalIdentityByHashForRevocation(hash:string): Promise<{ pub:string, uid:string, created_on:string, sig:string, member:boolean, wasMember:boolean, revoked:boolean, revocation_sig:string|null, expires_on:number }|null> { + const pending = await this.idtyDAL.getByHash(hash) + if (!pending) { + const idty = await this.iindexDAL.getFullFromHash(hash) + if (!idty) { + return null + } + const membership = await this.mindexDAL.getReducedMS(idty.pub) as FullMindexEntry + return { + pub: idty.pub, + uid: idty.uid, + sig: idty.sig, + member: idty.member, + wasMember: idty.wasMember, + expires_on: membership.expires_on, + created_on: idty.created_on, + revoked: !!(membership.revoked_on), + revocation_sig: membership.revocation + } + } + return { + pub: pending.pubkey, + uid: pending.uid, + sig: pending.sig, + expires_on: pending.expires_on, + created_on: pending.buid, + member: pending.member, + wasMember: pending.wasMember, + revoked: pending.revoked, + revocation_sig: pending.revocation_sig } - return pending; } getMembers() { return this.iindexDAL.getMembers() } - async getWrittenIdtyByPubkey(pubkey:string) { + async getWrittenIdtyByPubkeyForHash(pubkey:string): Promise<{ hash:string }> { + return this.getWrittenForSureIdtyByPubkey(pubkey) + } + + async getWrittenIdtyByPubkeyForHashing(pubkey:string): Promise<{ uid:string, created_on:string, pub:string }> { + return this.getWrittenForSureIdtyByPubkey(pubkey) + } + + async getWrittenIdtyByPubkeyForWotbID(pubkey:string): Promise<{ wotb_id:number }> { + return this.getWrittenForSureIdtyByPubkey(pubkey) + } + + async getWrittenIdtyByPubkeyForUidAndPubkey(pubkey:string): Promise<{ pub:string, uid:string }> { + return this.getWrittenForSureIdtyByPubkey(pubkey) + } + + async getWrittenIdtyByPubkeyForIsMember(pubkey:string): Promise<{ member:boolean }|null> { + return this.iindexDAL.getFromPubkey(pubkey) + } + + async getWrittenIdtyByPubkeyForUidAndIsMemberAndWasMember(pubkey:string): Promise<{ uid:string, member:boolean, wasMember:boolean }|null> { + return this.iindexDAL.getFromPubkey(pubkey) + } + + async getWrittenIdtyByPubkeyOrUidForIsMemberAndPubkey(search:string): Promise<{ pub:string, member:boolean }|null> { + return this.iindexDAL.getFromPubkeyOrUid(search) + } + + async getWrittenIdtyByPubkeyOrUIdForHashingAndIsMember(search:string): Promise<{ uid:string, created_on:string, pub:string, member:boolean }|null> { + return await this.iindexDAL.getFromPubkeyOrUid(search) + } + + async getWrittenIdtyByPubkeyForRevocationCheck(pubkey:string): Promise<{ pub:string, uid:string, created_on:string, sig:string, revoked_on:number|null }|null> { const idty = await this.iindexDAL.getFromPubkey(pubkey) if (!idty) { - return null; + return null + } + const membership = await this.mindexDAL.getReducedMS(pubkey) as FullMindexEntry + return { + pub: idty.pub, + uid: idty.uid, + sig: idty.sig, + created_on: idty.created_on, + revoked_on: membership.revoked_on } - const membership = await this.mindexDAL.getReducedMS(pubkey) - idty.revoked_on = membership.revoked_on - return idty; } - async getWrittenIdtyByUID(uid:string) { - const idty = await this.iindexDAL.getFromUID(uid) + async getWrittenIdtyByPubkeyForCertificationCheck(pubkey:string): Promise<{ pub:string, uid:string, created_on:string, sig:string }|null> { + const idty = await this.iindexDAL.getFromPubkey(pubkey) if (!idty) { - return null; + return null } - const membership = await this.mindexDAL.getReducedMS(idty.pub) - idty.revoked_on = membership.revoked_on - return idty; + return { + pub: idty.pub, + uid: idty.uid, + sig: idty.sig, + created_on: idty.created_on, + } + } + + async getWrittenIdtyByPubkeyForUidAndMemberAndCreatedOn(pubkey:string): Promise<{ uid:string, member:boolean, created_on:string }|null> { + const idty = await this.iindexDAL.getFromPubkey(pubkey) + if (!idty) { + return null + } + return { + uid: idty.uid, + member: idty.member, + created_on: idty.created_on, + } + } + + private async getWrittenForSureIdtyByPubkey(pubkey:string) { + const idty = await this.iindexDAL.getFromPubkey(pubkey) + if (!idty) { + throw Error(DataErrors[DataErrors.MEMBER_NOT_FOUND]) + } + return idty + } + + private async getWrittenForSureIdtyByUid(pubkey:string) { + const idty = (await this.iindexDAL.getFullFromUID(pubkey)) + if (!idty) { + throw Error(DataErrors[DataErrors.MEMBER_NOT_FOUND]) + } + return idty + } + + async getWrittenIdtyByPubkeyForExistence(uid:string) { + return !!(await this.iindexDAL.getFromPubkey(uid)) + } + + async getWrittenIdtyByUIDForExistence(uid:string) { + return !!(await this.iindexDAL.getFromUID(uid)) + } + + async getWrittenIdtyByUidForHashing(uid:string): Promise<{ uid:string, created_on:string, pub:string }> { + return this.getWrittenForSureIdtyByUid(uid) + } + + async getWrittenIdtyByUIDForWotbId(uid:string): Promise<{ wotb_id:number }> { + return this.getWrittenForSureIdtyByUid(uid) } async findPeersWhoseHashIsIn(hashes:string[]) { @@ -355,8 +553,8 @@ export class FileDAL { const revoking = await this.idtyDAL.getToRevoke(); const toRevoke = []; for (const pending of revoking) { - const idty = await this.getWrittenIdtyByPubkey(pending.pubkey); - if (!idty.revoked_on) { + const idty = await this.getWrittenIdtyByPubkeyForRevocationCheck(pending.pubkey) + if (idty && !idty.revoked_on) { toRevoke.push(pending); } } @@ -385,7 +583,7 @@ export class FileDAL { return await Promise.all(found.map(async (f:any) => { const ms = await this.mindexDAL.getReducedMS(f.pub); if (ms) { - f.revoked_on = ms.revoked_on ? parseInt(ms.revoked_on) : null; + f.revoked_on = ms.revoked_on ? ms.revoked_on : null; f.revoked = !!f.revoked_on; f.revocation_sig = ms.revocation || null; } @@ -420,7 +618,7 @@ export class FileDAL { const links = await this.cindexDAL.getValidLinksFrom(pubkey); let matching = certs; await Promise.all(links.map(async (entry:any) => { - const idty = await this.getWrittenIdtyByPubkey(entry.receiver); + const idty = await this.getWrittenIdtyByPubkeyForHash(entry.receiver) entry.from = entry.issuer; entry.to = entry.receiver; const cbt = entry.created_on.split('-'); @@ -558,15 +756,17 @@ export class FileDAL { } async setRevoked(pubkey:string) { - const idty = await this.getWrittenIdtyByPubkey(pubkey); - idty.revoked = true; - return await this.idtyDAL.saveIdentity(idty); + return await this.idtyDAL.setRevoked(pubkey) } - setRevocating = (existing:DBIdentity, revocation_sig:string) => { - existing.revocation_sig = revocation_sig; - existing.revoked = false; - return this.idtyDAL.saveIdentity(existing); + setRevocating = (idty:BasicRevocableIdentity, revocation_sig:string) => { + const dbIdentity = IdentityDTO.fromBasicIdentity(idty) + dbIdentity.member = idty.member + dbIdentity.wasMember = idty.wasMember + dbIdentity.expires_on = idty.expires_on + dbIdentity.revocation_sig = revocation_sig + dbIdentity.revoked = false + return this.idtyDAL.saveIdentity(dbIdentity) } async getPeerOrNull(pubkey:string) { @@ -682,8 +882,8 @@ export class FileDAL { async updateWotbLinks(cindex:CindexEntry[]) { for (const entry of cindex) { - const from = await this.getWrittenIdtyByPubkey(entry.issuer); - const to = await this.getWrittenIdtyByPubkey(entry.receiver); + const from = await this.getWrittenIdtyByPubkeyForWotbID(entry.issuer); + const to = await this.getWrittenIdtyByPubkeyForWotbID(entry.receiver); if (entry.op == CommonConstants.IDX_CREATE) { this.wotb.addLink(from.wotb_id, to.wotb_id); } else { diff --git a/app/lib/dal/sqliteDAL/IdentityDAL.ts b/app/lib/dal/sqliteDAL/IdentityDAL.ts index fa34f13e831086446377e865d404f60f26a3236f..af22cf43e9588faa108ab29d184cb6eb52e7c56e 100644 --- a/app/lib/dal/sqliteDAL/IdentityDAL.ts +++ b/app/lib/dal/sqliteDAL/IdentityDAL.ts @@ -27,7 +27,19 @@ export abstract class DBIdentity implements Cloneable { } certs:any[] = [] - signed:any[] = [] + signed: { + idty: { + pubkey: string + uid: string + buid: string + sig: string + member: string + wasMember: string + } + block_number: number + block_hash: string + sig: string + }[] = [] revoked: boolean currentMSN: null @@ -48,7 +60,11 @@ export abstract class DBIdentity implements Cloneable { expires_on: number getTargetHash() { - return IdentityDTO.getTargetHash(this) + return IdentityDTO.getTargetHash({ + pub: this.pubkey, + created_on: this.buid, + uid: this.uid + }) } json() { @@ -72,7 +88,7 @@ export abstract class DBIdentity implements Cloneable { "timestamp": this.buid }, "revoked": this.revoked, - "revoked_on": this.revoked_on, + "revoked_on": parseInt(String(this.revoked_on)), "revocation_sig": this.revocation_sig, "self": this.sig, "others": others @@ -255,6 +271,10 @@ export class IdentityDAL extends AbstractSQLite<DBIdentity> { }) } + setRevoked(pubkey: string) { + return this.query('UPDATE ' + this.table + ' SET revoked = ? WHERE pubkey = ?', [true, pubkey]) + } + getByHash(hash:string) { return this.sqlFindOne({ hash: hash diff --git a/app/lib/dal/sqliteDAL/index/IIndexDAL.ts b/app/lib/dal/sqliteDAL/index/IIndexDAL.ts index c945ea994bc11b7c84a497fb51459111d58e79e3..050f21e55da9060d595929350f2c6e783b1fa328 100644 --- a/app/lib/dal/sqliteDAL/index/IIndexDAL.ts +++ b/app/lib/dal/sqliteDAL/index/IIndexDAL.ts @@ -13,7 +13,7 @@ import {SQLiteDriver} from "../../drivers/SQLiteDriver"; import {AbstractIndex} from "../AbstractIndex"; -import {IindexEntry, Indexer} from "../../../indexer"; +import {FullIindexEntry, IindexEntry, Indexer} from "../../../indexer"; const _ = require('underscore'); @@ -126,15 +126,19 @@ export class IIndexDAL extends AbstractIndex<IindexEntry> { } getFromPubkey(pubkey:string) { - return this.entityOrNull('pub', pubkey) + return this.entityOrNull('pub', pubkey) as Promise<FullIindexEntry|null> } - getFromUID(uid:string) { - return this.entityOrNull('uid', uid) + getFromUID(uid:string, retrieveOnPubkey = false) { + return this.entityOrNull('uid', uid, retrieveOnPubkey) } - getFromHash(hash:string) { - return this.entityOrNull('hash', hash, true) + getFullFromUID(uid:string): Promise<FullIindexEntry|null> { + return this.entityOrNull('uid', uid, true) as Promise<FullIindexEntry|null> + } + + getFullFromHash(hash:string): Promise<FullIindexEntry|null> { + return this.entityOrNull('hash', hash, true) as Promise<FullIindexEntry|null> } reducable(pub:string) { @@ -179,4 +183,12 @@ export class IIndexDAL extends AbstractIndex<IindexEntry> { written_on: row.written_on } } + + async getFromPubkeyOrUid(search: string) { + const idty = await this.getFromPubkey(search) + if (idty) { + return idty + } + return this.getFromUID(search, true) as Promise<FullIindexEntry|null> + } } diff --git a/app/lib/dal/sqliteDAL/index/MIndexDAL.ts b/app/lib/dal/sqliteDAL/index/MIndexDAL.ts index 2ff64db3b98dccf02f17ba0c788be2a6ca628fe0..29ab2c215e6c051fbdc1e8035aff7d064b42f148 100644 --- a/app/lib/dal/sqliteDAL/index/MIndexDAL.ts +++ b/app/lib/dal/sqliteDAL/index/MIndexDAL.ts @@ -13,7 +13,7 @@ import {SQLiteDriver} from "../../drivers/SQLiteDriver"; import {AbstractIndex} from "../AbstractIndex"; -import {Indexer, MindexEntry} from "../../../indexer"; +import {FullMindexEntry, Indexer, MindexEntry} from "../../../indexer"; export class MIndexDAL extends AbstractIndex<MindexEntry> { @@ -68,12 +68,12 @@ export class MIndexDAL extends AbstractIndex<MindexEntry> { 'COMMIT;') } - async getReducedMS(pub:string) { + async getReducedMS(pub:string): Promise<FullMindexEntry|null> { const reducables = await this.reducable(pub); if (reducables.length) { - return Indexer.DUP_HELPERS.reduce(reducables); + return Indexer.DUP_HELPERS.reduce(reducables) as FullMindexEntry } - return null; + return null } reducable(pub:string) { diff --git a/app/lib/dto/CertificationDTO.ts b/app/lib/dto/CertificationDTO.ts index 45c2d2d403635dfd673e3ea25d1c9a5a66d6d788..66b76c92d9df315a8267dfece93d8cf622e3f7c5 100644 --- a/app/lib/dto/CertificationDTO.ts +++ b/app/lib/dto/CertificationDTO.ts @@ -63,8 +63,8 @@ export class CertificationDTO extends ShortCertificationDTO implements Cloneable getTargetHash() { return IdentityDTO.getTargetHash({ uid: this.idty_uid, - buid: this.idty_buid, - pubkey: this.idty_issuer + created_on: this.idty_buid, + pub: this.idty_issuer }) } diff --git a/app/lib/dto/IdentityDTO.ts b/app/lib/dto/IdentityDTO.ts index b1ed24d2ee40b3d646ee10bd176c4b4c9591b7d8..5671987b0c2801dd1f820cae2d821a408ec48048 100644 --- a/app/lib/dto/IdentityDTO.ts +++ b/app/lib/dto/IdentityDTO.ts @@ -18,16 +18,26 @@ import {DBIdentity, NewDBIdentity} from "../dal/sqliteDAL/IdentityDAL" const DEFAULT_DOCUMENT_VERSION = 10 export interface HashableIdentity { + created_on: string + uid: string + pub: string +} + +export interface BasicIdentity { buid: string uid: string pubkey: string + sig: string } -export interface BasicIdentity { +export interface BasicRevocableIdentity { buid: string uid: string pubkey: string sig: string + member: boolean + wasMember: boolean + expires_on: number } export class IdentityDTO { @@ -85,7 +95,7 @@ export class IdentityDTO { } static getTargetHash(idty:HashableIdentity) { - return hashf(idty.uid + idty.buid + idty.pubkey) + return hashf(idty.uid + idty.created_on + idty.pub) } static fromJSONObject(obj:any) { @@ -106,8 +116,8 @@ export class IdentityDTO { basic.buid, basic.uid, IdentityDTO.getTargetHash({ - pubkey: basic.pubkey, - buid: basic.buid, + pub: basic.pubkey, + created_on: basic.buid, uid: basic.uid }) ) @@ -120,8 +130,8 @@ export class IdentityDTO { revoc.idty_buid, revoc.idty_uid, IdentityDTO.getTargetHash({ - pubkey: revoc.pubkey, - buid: revoc.idty_buid, + pub: revoc.pubkey, + created_on: revoc.idty_buid, uid: revoc.idty_uid }) ) diff --git a/app/lib/dto/MembershipDTO.ts b/app/lib/dto/MembershipDTO.ts index a3a564c03e34068acaf756d5ec2637a9ff41b94d..6d8ada8844142bb0f4c4467bd015b9a8b416c906 100644 --- a/app/lib/dto/MembershipDTO.ts +++ b/app/lib/dto/MembershipDTO.ts @@ -78,9 +78,9 @@ export class MembershipDTO implements Cloneable { getIdtyHash() { return IdentityDTO.getTargetHash({ - buid: this.certts, + created_on: this.certts, uid: this.userid, - pubkey: this.issuer + pub: this.issuer }) } diff --git a/app/lib/indexer.ts b/app/lib/indexer.ts index 42b8cea8882caa6a8623f4fe8070a519b4cde1ca..5cfa75f8be50ecbb074ca69fcfb07c4b66550efa 100644 --- a/app/lib/indexer.ts +++ b/app/lib/indexer.ts @@ -23,6 +23,7 @@ import {rawer, txunlock} from "./common-libs/index" import {CommonConstants} from "./common-libs/constants" import {MembershipDTO} from "./dto/MembershipDTO" import {UnlockMetadata} from "./common-libs/txunlock" +import {FileDAL} from "./dal/fileDAL" const _ = require('underscore'); @@ -61,6 +62,21 @@ export interface MindexEntry extends IndexEntry { revocationSigOK?: boolean, } +export interface FullMindexEntry { + op: string + pub: string + created_on: string + written_on: string + expires_on: number + expired_on: null|number + revokes_on: number + revoked_on: null|number + leaving: boolean + revocation: null|string + chainable_on: number + writtenOn: number +} + export interface IindexEntry extends IndexEntry { uid: string | null, pub: string, @@ -79,6 +95,21 @@ export interface IindexEntry extends IndexEntry { hasToBeExcluded?: boolean, } +export interface FullIindexEntry { + op: string + uid: string + pub: string + hash: string + sig: string + created_on: string + written_on: string + writtenOn: number + member: boolean + wasMember: boolean + kick: boolean + wotb_id: number +} + export interface CindexEntry extends IndexEntry { issuer: string, receiver: string, @@ -855,12 +886,21 @@ export class Indexer { // BR_G45 await Promise.all(cindex.map(async (ENTRY: CindexEntry) => { - ENTRY.sigOK = await checkCertificationIsValid(block, ENTRY, async (block:BlockDTO,pub:string,dal:any) => { + ENTRY.sigOK = await checkCertificationIsValid(block, ENTRY, async (block:BlockDTO,pub:string,dal:FileDAL) => { let localInlineIdty = block.getInlineIdentity(pub); if (localInlineIdty) { return IdentityDTO.fromInline(localInlineIdty) } - return dal.getWrittenIdtyByPubkey(pub) + const idty = await dal.getWrittenIdtyByPubkeyForCertificationCheck(pub) + if (!idty) { + return null + } + return { + pubkey: idty.pub, + uid: idty.uid, + sig: idty.sig, + buid: idty.created_on + } }, conf, dal); })) @@ -1903,28 +1943,28 @@ async function getNodeIDfromPubkey(nodesCache: any, pubkey: string, dal: any) { let toNode = nodesCache[pubkey]; // Eventually cache the target nodeID if (toNode === null || toNode === undefined) { - let idty = await dal.getWrittenIdtyByPubkey(pubkey); + let idty = await dal.getWrittenIdtyByPubkeyForWotbID(pubkey) toNode = idty.wotb_id; nodesCache[pubkey] = toNode; } return toNode; } -async function sigCheckRevoke(entry: MindexEntry, dal: any, currency: string) { +async function sigCheckRevoke(entry: MindexEntry, dal: FileDAL, currency: string) { try { let pubkey = entry.pub, sig = entry.revocation || ""; - let idty = await dal.getWrittenIdtyByPubkey(pubkey); + let idty = await dal.getWrittenIdtyByPubkeyForRevocationCheck(pubkey); if (!idty) { throw Error("A pubkey who was never a member cannot be revoked"); } - if (idty.revoked) { + if (idty.revoked_on) { throw Error("A revoked identity cannot be revoked again"); } let rawRevocation = rawer.getOfficialRevocation({ currency: currency, - issuer: idty.pubkey, + issuer: idty.pub, uid: idty.uid, - buid: idty.buid, + buid: idty.created_on, sig: idty.sig, revocation: '' }); @@ -1940,7 +1980,12 @@ async function sigCheckRevoke(entry: MindexEntry, dal: any, currency: string) { -async function checkCertificationIsValid (block: BlockDTO, cert: CindexEntry, findIdtyFunc: (b:BlockDTO,to:string,dal:any)=>Promise<IdentityDTO>, conf: ConfDTO, dal: any) { +async function checkCertificationIsValid (block: BlockDTO, cert: CindexEntry, findIdtyFunc: (b:BlockDTO,to:string,dal:FileDAL)=>Promise<{ + pubkey:string + uid:string + buid:string + sig:string +}|null>, conf: ConfDTO, dal: any) { if (block.number == 0 && cert.created_on != 0) { throw Error('Number must be 0 for root block\'s certifications'); } else { @@ -1955,7 +2000,7 @@ async function checkCertificationIsValid (block: BlockDTO, cert: CindexEntry, fi throw Error('Certification based on an unexisting block'); } } - let idty = await findIdtyFunc(block, cert.receiver, dal) + const idty = await findIdtyFunc(block, cert.receiver, dal) let current = block.number == 0 ? null : await dal.getCurrentBlockOrNull(); if (!idty) { throw Error('Identity does not exist for certified'); @@ -1967,8 +2012,8 @@ async function checkCertificationIsValid (block: BlockDTO, cert: CindexEntry, fi throw Error('Rejected certification: certifying its own self-certification has no meaning'); else { const buid = [cert.created_on, basedBlock.hash].join('-'); - idty.currency = conf.currency; - const raw = rawer.getOfficialCertification(_.extend(idty, { + const raw = rawer.getOfficialCertification({ + currency: conf.currency, idty_issuer: idty.pubkey, idty_uid: idty.uid, idty_buid: idty.buid, @@ -1976,7 +2021,7 @@ async function checkCertificationIsValid (block: BlockDTO, cert: CindexEntry, fi issuer: cert.issuer, buid: buid, sig: '' - })); + }) const verified = verify(raw, cert.sig, cert.issuer); if (!verified) { throw constants.ERRORS.WRONG_SIGNATURE_FOR_CERT diff --git a/app/lib/rules/global_rules.ts b/app/lib/rules/global_rules.ts index 3bc3d5417591fea6df8b84d6e1ff7290786e6669..f4dcf07e8f618b7b16b6b7d5bdb7b3a33a9c6497 100644 --- a/app/lib/rules/global_rules.ts +++ b/app/lib/rules/global_rules.ts @@ -76,7 +76,7 @@ export const GLOBAL_RULES_FUNCTIONS = { let current = await dal.getCurrentBlockOrNull(); for (const obj of block.identities) { let idty = IdentityDTO.fromInline(obj); - let found = await dal.getWrittenIdtyByUID(idty.uid); + let found = await dal.getWrittenIdtyByUIDForExistence(idty.uid) if (found) { throw Error('Identity already used'); } @@ -184,12 +184,16 @@ export const GLOBAL_RULES_HELPERS = { // Functions used in an external context too checkMembershipBlock: (ms:any, current:DBBlock, conf:ConfDTO, dal:FileDAL) => checkMSTarget(ms, current ? { number: current.number + 1} : { number: 0 }, conf, dal), - checkCertificationIsValid: (cert:any, current:BlockDTO, findIdtyFunc:any, conf:ConfDTO, dal:FileDAL) => { - return checkCertificationIsValid(current ? current : { number: 0, currency: '' }, cert, findIdtyFunc, conf, dal) + checkCertificationIsValidInSandbox: (cert:any, current:BlockDTO, findIdtyFunc:any, conf:ConfDTO, dal:FileDAL) => { + return checkCertificationShouldBeValid(current ? current : { number: 0, currency: '' }, cert, findIdtyFunc, conf, dal) }, - checkCertificationIsValidForBlock: (cert:any, block:{ number:number, currency:string }, findIdtyFunc:(b:{ number:number, currency:string }, pubkey:string, dal:FileDAL) => Promise<any>, conf:ConfDTO, dal:FileDAL) => { - return checkCertificationIsValid(block, cert, findIdtyFunc, conf, dal) + checkCertificationIsValidForBlock: (cert:any, block:{ number:number, currency:string }, findIdtyFunc:(b:{ number:number, currency:string }, pubkey:string, dal:FileDAL) => Promise<{ + pubkey:string + uid:string + buid:string + sig:string}|null>, conf:ConfDTO, dal:FileDAL) => { + return checkCertificationShouldBeValid(block, cert, findIdtyFunc, conf, dal) }, isOver3Hops: async (member:any, newLinks:any, newcomers:string[], current:DBBlock, conf:ConfDTO, dal:FileDAL) => { @@ -203,9 +207,9 @@ export const GLOBAL_RULES_HELPERS = { } }, - checkExistsUserID: (uid:string, dal:FileDAL) => dal.getWrittenIdtyByUID(uid), + checkExistsUserID: (uid:string, dal:FileDAL) => dal.getWrittenIdtyByUIDForExistence(uid), - checkExistsPubkey: (pub:string, dal:FileDAL) => dal.getWrittenIdtyByPubkey(pub), + checkExistsPubkey: (pub:string, dal:FileDAL) => dal.getWrittenIdtyByPubkeyForExistence(pub), checkSingleTransaction: ( tx:TransactionDTO, @@ -263,7 +267,12 @@ async function checkMSTarget (ms:any, block:any, conf:ConfDTO, dal:FileDAL) { } } -async function checkCertificationIsValid (block:{ number:number, currency:string }, cert:any, findIdtyFunc:(b:{ number:number, currency:string }, pubkey:string, dal:FileDAL) => Promise<any>, conf:ConfDTO, dal:FileDAL) { +async function checkCertificationShouldBeValid (block:{ number:number, currency:string }, cert:any, findIdtyFunc:(b:{ number:number, currency:string }, pubkey:string, dal:FileDAL) => Promise<{ + pubkey:string + uid:string + buid:string + sig:string +}|null>, conf:ConfDTO, dal:FileDAL) { if (block.number == 0 && cert.block_number != 0) { throw Error('Number must be 0 for root block\'s certifications'); } else { @@ -277,7 +286,7 @@ async function checkCertificationIsValid (block:{ number:number, currency:string throw Error('Certification based on an unexisting block'); } try { - const issuer = await dal.getWrittenIdtyByPubkey(cert.from) + const issuer = await dal.getWrittenIdtyByPubkeyForIsMember(cert.from) if (!issuer || !issuer.member) { throw Error('Issuer is not a member') } @@ -299,8 +308,8 @@ async function checkCertificationIsValid (block:{ number:number, currency:string const buid = [cert.block_number, basedBlock.hash].join('-'); if (cert.block_hash && buid != [cert.block_number, cert.block_hash].join('-')) throw Error('Certification based on an unexisting block buid. from ' + cert.from.substring(0,8) + ' to ' + idty.pubkey.substring(0,8)); - idty.currency = conf.currency; - const raw = rawer.getOfficialCertification(_.extend(idty, { + const raw = rawer.getOfficialCertification({ + currency: conf.currency, idty_issuer: idty.pubkey, idty_uid: idty.uid, idty_buid: idty.buid, @@ -308,7 +317,7 @@ async function checkCertificationIsValid (block:{ number:number, currency:string issuer: cert.from, buid: buid, sig: '' - })); + }) const verified = verify(raw, cert.sig, cert.from); if (!verified) { throw constants.ERRORS.WRONG_SIGNATURE_FOR_CERT diff --git a/app/modules/bma/lib/controllers/blockchain.ts b/app/modules/bma/lib/controllers/blockchain.ts index 7062a768afc2f1787c20fcafdc6ff4dbc2e8dc88..d38b561442a1b8df386b19117c3873209a68acf8 100644 --- a/app/modules/bma/lib/controllers/blockchain.ts +++ b/app/modules/bma/lib/controllers/blockchain.ts @@ -132,7 +132,7 @@ export class BlockchainBinding extends AbstractController { async hardship(req:any): Promise<HttpHardship> { let nextBlockNumber = 0; const search = await ParametersService.getSearchP(req); - const idty = await this.IdentityService.findMemberWithoutMemberships(search); + const idty = await this.server.dal.getWrittenIdtyByPubkeyOrUidForIsMemberAndPubkey(search); if (!idty) { throw BMAConstants.ERRORS.NO_MATCHING_IDENTITY; } @@ -143,7 +143,7 @@ export class BlockchainBinding extends AbstractController { if (current) { nextBlockNumber = current ? current.number + 1 : 0; } - const difficulty = await this.server.getBcContext().getIssuerPersonalizedDifficulty(idty.pubkey); + const difficulty = await this.server.getBcContext().getIssuerPersonalizedDifficulty(idty.pub); return { "block": nextBlockNumber, "level": difficulty @@ -156,8 +156,8 @@ export class BlockchainBinding extends AbstractController { const issuers = await this.server.dal.getUniqueIssuersBetween(number - 1 - current.issuersFrame, number - 1); const difficulties = []; for (const issuer of issuers) { - const member = await this.server.dal.getWrittenIdtyByPubkey(issuer); - const difficulty = await this.server.getBcContext().getIssuerPersonalizedDifficulty(member.pubkey); + const member = await this.server.dal.getWrittenIdtyByPubkeyForUidAndPubkey(issuer); + const difficulty = await this.server.getBcContext().getIssuerPersonalizedDifficulty(member.pub); difficulties.push({ uid: member.uid, level: difficulty diff --git a/app/modules/bma/lib/controllers/wot.ts b/app/modules/bma/lib/controllers/wot.ts index c9c7d6048cccdc3c3c1404f219c859e802965c93..f88c06a52e92c4d17849e7dba19fe2c7fd0b5a81 100644 --- a/app/modules/bma/lib/controllers/wot.ts +++ b/app/modules/bma/lib/controllers/wot.ts @@ -30,9 +30,12 @@ import { HttpResult, HttpSimpleIdentity } from "../dtos"; +import {IdentityDTO} from "../../../../lib/dto/IdentityDTO" +import {FullIindexEntry} from "../../../../lib/indexer" const _ = require('underscore'); const http2raw = require('../http2raw'); +const constants = require('../../../../lib/constants'); const ParametersService = require('../parameters').ParametersService @@ -50,7 +53,7 @@ export class WOTBinding extends AbstractController { const certs: any[] = await this.server.dal.certsToTarget(idty.pubkey, idty.getTargetHash()); const validCerts = []; for (const cert of certs) { - const member = await this.IdentityService.getWrittenByPubkey(cert.from); + const member = await this.server.dal.getWrittenIdtyByPubkeyForUidAndIsMemberAndWasMember(cert.from); if (member) { cert.uids = [member.uid]; cert.isMember = member.member; @@ -68,7 +71,7 @@ export class WOTBinding extends AbstractController { const validSigned = []; for (let j = 0; j < signed.length; j++) { const cert = _.clone(signed[j]); - cert.idty = await this.server.dal.getIdentityByHashOrNull(cert.target); + cert.idty = await this.server.dal.getGlobalIdentityByHashForLookup(cert.target) if (cert.idty) { validSigned.push(cert); } else { @@ -112,11 +115,11 @@ export class WOTBinding extends AbstractController { async certifiersOf(req:any): Promise<HttpCertifications> { const search = await ParametersService.getSearchP(req); - const idty = await this.IdentityService.findMemberWithoutMemberships(search); - const certs = await this.server.dal.certsToTarget(idty.pubkey, idty.getTargetHash()); + const idty = (await this.server.dal.getWrittenIdtyByPubkeyOrUIdForHashingAndIsMember(search)) as FullIindexEntry + const certs = await this.server.dal.certsToTarget(idty.pub, IdentityDTO.getTargetHash(idty)) const theCerts:HttpCertification[] = []; for (const cert of certs) { - const certifier = await this.server.dal.getWrittenIdtyByPubkey(cert.from); + const certifier = await this.server.dal.getWrittenIdtyByPubkeyForUidAndMemberAndCreatedOn(cert.from); if (certifier) { let certBlock = await this.server.dal.getBlock(cert.block_number) theCerts.push({ @@ -128,7 +131,7 @@ export class WOTBinding extends AbstractController { block: certBlock.number, medianTime: certBlock.medianTime }, - sigDate: certifier.buid, + sigDate: certifier.created_on, written: (cert.written_block !== null && cert.written_hash) ? { number: cert.written_block, hash: cert.written_hash @@ -138,9 +141,9 @@ export class WOTBinding extends AbstractController { } } return { - pubkey: idty.pubkey, + pubkey: idty.pub, uid: idty.uid, - sigDate: idty.buid, + sigDate: idty.created_on, isMember: idty.member, certifications: theCerts } @@ -206,11 +209,11 @@ export class WOTBinding extends AbstractController { async certifiedBy(req:any): Promise<HttpCertifications> { const search = await ParametersService.getSearchP(req); - const idty = await this.IdentityService.findMemberWithoutMemberships(search); - const certs = await this.server.dal.certsFrom(idty.pubkey); + const idty = (await this.server.dal.getWrittenIdtyByPubkeyOrUIdForHashingAndIsMember(search)) as FullIindexEntry + const certs = await this.server.dal.certsFrom(idty.pub); const theCerts:HttpCertification[] = []; for (const cert of certs) { - const certified = await this.server.dal.getWrittenIdtyByPubkey(cert.to); + const certified = await this.server.dal.getWrittenIdtyByPubkeyForUidAndMemberAndCreatedOn(cert.to); if (certified) { let certBlock = await this.server.dal.getBlock(cert.block_number) theCerts.push({ @@ -222,7 +225,7 @@ export class WOTBinding extends AbstractController { block: certBlock.number, medianTime: certBlock.medianTime }, - sigDate: certified.buid, + sigDate: certified.created_on, written: (cert.written_block !== null && cert.written_hash) ? { number: cert.written_block, hash: cert.written_hash @@ -232,9 +235,9 @@ export class WOTBinding extends AbstractController { } } return { - pubkey: idty.pubkey, + pubkey: idty.pub, uid: idty.uid, - sigDate: idty.buid, + sigDate: idty.created_on, isMember: idty.member, certifications: theCerts } @@ -242,17 +245,17 @@ export class WOTBinding extends AbstractController { async identityOf(req:any): Promise<HttpSimpleIdentity> { let search = await ParametersService.getSearchP(req); - let idty = await this.IdentityService.findMemberWithoutMemberships(search); + const idty = await this.server.dal.getWrittenIdtyByPubkeyOrUIdForHashingAndIsMember(search) if (!idty) { - throw 'Identity not found'; + throw constants.ERRORS.NO_MEMBER_MATCHING_PUB_OR_UID; } if (!idty.member) { throw 'Not a member'; } return { - pubkey: idty.pubkey, + pubkey: idty.pub, uid: idty.uid, - sigDate: idty.buid + sigDate: idty.created_on }; } diff --git a/app/modules/crawler/lib/sync.ts b/app/modules/crawler/lib/sync.ts index fea2026986e7394185b003a818840e40d48a8a27..2a2d6aeba0e428712165a967e3d0f1699a0188d0 100644 --- a/app/modules/crawler/lib/sync.ts +++ b/app/modules/crawler/lib/sync.ts @@ -283,7 +283,7 @@ export class Synchroniser extends stream.Duplex { } // Tells wether given peer is a member peer async isMemberPeer(thePeer: PeerDTO): Promise<boolean> { - let idty = await this.dal.getWrittenIdtyByPubkey(thePeer.pubkey); + let idty = await this.dal.getWrittenIdtyByPubkeyForIsMember(thePeer.pubkey); return (idty && idty.member) || false; } downloadBlocks(thePeer: PeerDTO, fromNumber: number, count?: number | undefined): Promise<BlockDTO[]> { diff --git a/app/modules/prover/lib/blockGenerator.ts b/app/modules/prover/lib/blockGenerator.ts index 20096a8d958e49e0a6e557186f9458f4ed28ea9e..3c6d67921060590fc4906325cb86d369955a2f4f 100644 --- a/app/modules/prover/lib/blockGenerator.ts +++ b/app/modules/prover/lib/blockGenerator.ts @@ -27,7 +27,6 @@ import {IdentityDTO} from "../../../lib/dto/IdentityDTO" import {CertificationDTO} from "../../../lib/dto/CertificationDTO" import {MembershipDTO} from "../../../lib/dto/MembershipDTO" import {BlockDTO} from "../../../lib/dto/BlockDTO" -import {DBIdentity} from "../../../lib/dal/sqliteDAL/IdentityDAL" import {ConfDTO} from "../../../lib/dto/ConfDTO" import {FileDAL} from "../../../lib/dal/fileDAL" @@ -37,6 +36,31 @@ const inquirer = require('inquirer'); const constants = CommonConstants +interface PreJoin { + identity: { + pubkey: string + uid: string + buid: string + sig: string + member: boolean + wasMember: boolean + revoked: boolean + } + key: null + idHash: string + certs: any[] + ms: any +} + +interface LeaveData { + identity: { + member: boolean + } | null + ms: any + key: any + idHash: string +} + export class BlockGenerator { mainContext:BlockchainContext @@ -82,13 +106,11 @@ export class BlockGenerator { const exclusions = await this.dal.getToBeKickedPubkeys(); const wereExcludeds = await this.dal.getRevokedPubkeys(); const newCertsFromWoT = await generator.findNewCertsFromWoT(current); - const newcomersLeavers = await this.findNewcomersAndLeavers(current, (joinersData:any) => generator.filterJoiners(joinersData)); + const newcomers = await this.findNewcomers(current, (joinersData:any) => generator.filterJoiners(joinersData)) + const leavers = await this.findLeavers(current) const transactions = await this.findTransactions(current, manualValues); - const joinData = newcomersLeavers[2]; - const leaveData = newcomersLeavers[3]; - const newCertsFromNewcomers = newcomersLeavers[4]; - const certifiersOfNewcomers = _.uniq(_.keys(joinData).reduce((theCertifiers:any, newcomer:string) => { - return theCertifiers.concat(_.pluck(joinData[newcomer].certs, 'from')); + const certifiersOfNewcomers = _.uniq(_.keys(newcomers).reduce((theCertifiers:any, newcomer:string) => { + return theCertifiers.concat(_.pluck(newcomers[newcomer].certs, 'from')); }, [])); const certifiers:string[] = [].concat(certifiersOfNewcomers); // Merges updates @@ -102,24 +124,8 @@ export class BlockGenerator { return !isCertifier; }); }); - _(newCertsFromNewcomers).keys().forEach((certified:string) => { - newCertsFromWoT[certified] = (newCertsFromWoT[certified] || []).concat(newCertsFromNewcomers[certified]); - }); - // Revocations // Create the block - return this.createBlock(current, joinData, leaveData, newCertsFromWoT, revocations, exclusions, wereExcludeds, transactions, manualValues); - } - - private async findNewcomersAndLeavers(current:DBBlock, filteringFunc: (joinData: { [pub:string]: any }) => Promise<{ [pub:string]: any }>) { - const newcomers = await this.findNewcomers(current, filteringFunc); - const leavers = await this.findLeavers(current); - - const cur = newcomers.current; - const newWoTMembers = newcomers.newWotMembers; - const finalJoinData = newcomers.finalJoinData; - const updates = newcomers.updates; - - return [cur, newWoTMembers, finalJoinData, leavers, updates]; + return this.createBlock(current, newcomers, leavers, newCertsFromWoT, revocations, exclusions, wereExcludeds, transactions, manualValues); } private async findTransactions(current:DBBlock, options:{ dontCareAboutChaining?:boolean }) { @@ -155,12 +161,12 @@ export class BlockGenerator { } private async findLeavers(current:DBBlock) { - const leaveData: { [pub:string]: any } = {}; + const leaveData: { [pub:string]: { identity: { member:boolean }|null, ms: any, key: any, idHash: string } } = {}; const memberships = await this.dal.findLeavers(current && current.medianTime); const leavers:string[] = []; memberships.forEach((ms:any) => leavers.push(ms.issuer)); for (const ms of memberships) { - const leave: { identity: DBIdentity|null, ms: any, key: any, idHash: string } = { identity: null, ms: ms, key: null, idHash: '' }; + const leave: { identity: { member:boolean }|null, ms: any, key: any, idHash: string } = { identity: null, ms: ms, key: null, idHash: '' }; leave.idHash = (hashf(ms.userid + ms.certts + ms.issuer) + "").toUpperCase(); let block; if (current) { @@ -169,20 +175,19 @@ export class BlockGenerator { else { block = {}; } - const identity = await this.dal.getIdentityByHashOrNull(leave.idHash); + const identity = await this.dal.getGlobalIdentityByHashForIsMember(leave.idHash) const currentMembership = await this.dal.mindexDAL.getReducedMS(ms.issuer); const currentMSN = currentMembership ? parseInt(currentMembership.created_on) : -1; if (identity && block && currentMSN < leave.ms.number && identity.member) { // MS + matching cert are found leave.identity = identity; - leaveData[identity.pubkey] = leave; + leaveData[identity.pub] = leave; } } return leaveData; } private async findNewcomers(current:DBBlock, filteringFunc: (joinData: { [pub:string]: any }) => Promise<{ [pub:string]: any }>) { - const updates = {}; const preJoinData = await this.getPreJoinData(current); const joinData = await filteringFunc(preJoinData); const members = await this.dal.getMembers(); @@ -198,12 +203,12 @@ export class BlockGenerator { joiners: someNewcomers, identities: _.filter(newcomers.map((pub:string) => joinData[pub].identity), { wasMember: false }).map((idty:any) => idty.pubkey) }; - const theNewLinks = await this.computeNewLinks(nextBlockNumber, someNewcomers, joinData, updates) + const theNewLinks = await this.computeNewLinks(nextBlockNumber, someNewcomers, joinData) await this.checkWoTConstraints(nextBlock, theNewLinks, current); }) - const newLinks = await this.computeNewLinks(nextBlockNumber, realNewcomers, joinData, updates); + const newLinks = await this.computeNewLinks(nextBlockNumber, realNewcomers, joinData) const newWoT = wotMembers.concat(realNewcomers); - const finalJoinData: { [pub:string]: any } = {}; + const finalJoinData: { [pub:string]: PreJoin } = {}; realNewcomers.forEach((newcomer:string) => { // Only keep membership of selected newcomers finalJoinData[newcomer] = joinData[newcomer]; @@ -217,12 +222,7 @@ export class BlockGenerator { }); joinData[newcomer].certs = keptCerts; }); - return { - current: current, - newWotMembers: wotMembers.concat(realNewcomers), - finalJoinData: finalJoinData, - updates: updates - } + return finalJoinData } catch(err) { this.logger.error(err); throw err; @@ -272,7 +272,7 @@ export class BlockGenerator { } private async getPreJoinData(current:DBBlock) { - const preJoinData:any = {}; + const preJoinData:{ [k:string]: PreJoin } = {} const memberships = await this.dal.findNewcomers(current && current.medianTime) const joiners:string[] = []; memberships.forEach((ms:any) => joiners.push(ms.issuer)); @@ -289,7 +289,7 @@ export class BlockGenerator { } } const idtyHash = (hashf(ms.userid + ms.certts + ms.issuer) + "").toUpperCase(); - const join:any = await this.getSinglePreJoinData(current, idtyHash, joiners); + const join = await this.getSinglePreJoinData(current, idtyHash, joiners); join.ms = ms; const currentMembership = await this.dal.mindexDAL.getReducedMS(ms.issuer); const currentMSN = currentMembership ? parseInt(currentMembership.created_on) : -1; @@ -307,19 +307,16 @@ export class BlockGenerator { return preJoinData; } - private async computeNewLinks(forBlock:number, theNewcomers:any, joinData:any, updates:any) { + private async computeNewLinks(forBlock:number, theNewcomers:any, joinData:any) { let newCerts = await this.computeNewCerts(forBlock, theNewcomers, joinData); - return this.newCertsToLinks(newCerts, updates); + return this.newCertsToLinks(newCerts); } - newCertsToLinks(newCerts:any, updates:any) { + newCertsToLinks(newCerts:any) { let newLinks:any = {}; _.mapObject(newCerts, function(certs:any, pubkey:string) { newLinks[pubkey] = _.pluck(certs, 'from'); }); - _.mapObject(updates, function(certs:any, pubkey:string) { - newLinks[pubkey] = (newLinks[pubkey] || []).concat(_.pluck(certs, 'pubkey')); - }); return newLinks; } @@ -352,7 +349,7 @@ export class BlockGenerator { } async getSinglePreJoinData(current:DBBlock, idHash:string, joiners:string[]) { - const identity = await this.dal.getIdentityByHashOrNull(idHash); + const identity = await this.dal.getGlobalIdentityByHashForJoining(idHash) let foundCerts = []; const vHEAD_1 = await this.mainContext.getvHEAD_1(); if (!identity) { @@ -413,10 +410,12 @@ export class BlockGenerator { const isMember = await this.dal.isMember(cert.from); const doubleSignature = !!(~certifiers.indexOf(cert.from)) if (isMember && !doubleSignature) { - const isValid = await GLOBAL_RULES_HELPERS.checkCertificationIsValidForBlock(cert, { number: current.number + 1, currency: current.currency }, async () => { - const idty = await this.dal.getIdentityByHashOrNull(idHash) - return idty - }, this.conf, this.dal); + const isValid = await GLOBAL_RULES_HELPERS.checkCertificationIsValidForBlock( + cert, + { number: current.number + 1, currency: current.currency }, + async () => this.dal.getGlobalIdentityByHashForHashingAndSig(idHash), + this.conf, + this.dal) if (isValid) { certifiers.push(cert.from); foundCerts.push(cert); @@ -429,15 +428,26 @@ export class BlockGenerator { } } } + const ms:any = null // TODO: refactor return { identity: identity, key: null, idHash: idHash, - certs: foundCerts + certs: foundCerts, + ms }; } - private async createBlock(current:DBBlock, joinData:any, leaveData:any, updates:any, revocations:any, exclusions:any, wereExcluded:any, transactions:any, manualValues:any) { + private async createBlock( + current:DBBlock, + joinData:{ [pub:string]: PreJoin }, + leaveData:{ [pub:string]: LeaveData }, + updates:any, + revocations:any, + exclusions:any, + wereExcluded:any, + transactions:any, + manualValues:any) { if (manualValues && manualValues.excluded) { exclusions = manualValues.excluded; @@ -547,7 +557,7 @@ export class BlockGenerator { leavers.forEach((leaver:any) => { const data = leaveData[leaver]; // Join only for non-members - if (data.identity.member) { + if (data.identity && data.identity.member) { if (blockLen < maxLenOfBlock) { block.leavers.push(MembershipDTO.fromJSONObject(data.ms).inline()); blockLen++; @@ -709,7 +719,7 @@ class NextBlockGenerator implements BlockGeneratorInterface { const certs = await this.dal.certsFindNew(); const vHEAD_1 = await this.mainContext.getvHEAD_1(); for (const cert of certs) { - const targetIdty = await this.dal.getIdentityByHashOrNull(cert.target); + const targetIdty = await this.dal.getGlobalIdentityByHashForHashingAndSig(cert.target) // The identity must be known if (targetIdty) { const certSig = cert.sig; diff --git a/app/service/IdentityService.ts b/app/service/IdentityService.ts index 9bccc12bc93793063c77c89d852e3419eedda733..167e3291d838baf94d5ace097ecaa6b634cf7a01 100644 --- a/app/service/IdentityService.ts +++ b/app/service/IdentityService.ts @@ -14,7 +14,7 @@ import {GlobalFifoPromise} from "./GlobalFifoPromise" import {FileDAL} from "../lib/dal/fileDAL" import {ConfDTO} from "../lib/dto/ConfDTO" -import {DBIdentity, ExistingDBIdentity} from "../lib/dal/sqliteDAL/IdentityDAL" +import {DBIdentity} from "../lib/dal/sqliteDAL/IdentityDAL" import {GLOBAL_RULES_FUNCTIONS, GLOBAL_RULES_HELPERS} from "../lib/rules/global_rules" import {BlockDTO} from "../lib/dto/BlockDTO" import {RevocationDTO} from "../lib/dto/RevocationDTO" @@ -50,18 +50,17 @@ export class IdentityService extends FIFOService { return this.dal.searchJustIdentities(search) } - async findMember(search:string): Promise<{ idty: ExistingDBIdentity; memberships: { blockstamp: string; membership: string; number: number; fpr: string; written_number: number | null }[] }> { + async findMember(search:string) { let idty = null; if (search.match(constants.PUBLIC_KEY)) { - idty = await this.dal.getWrittenIdtyByPubkey(search); + idty = await this.dal.getWrittenIdtyByPubkeyForHashing(search); } else { - idty = await this.dal.getWrittenIdtyByUID(search); + idty = await this.dal.getWrittenIdtyByUidForHashing(search); } if (!idty) { throw constants.ERRORS.NO_MEMBER_MATCHING_PUB_OR_UID; } - const obj = DBIdentity.copyFromExisting(idty) let memberships: { blockstamp:string @@ -71,9 +70,9 @@ export class IdentityService extends FIFOService { written_number:number|null }[] = [] - if (obj) { - const mss = await this.dal.msDAL.getMembershipsOfIssuer(obj.pubkey); - const mssFromMindex = await this.dal.mindexDAL.reducable(obj.pubkey); + if (idty) { + const mss = await this.dal.msDAL.getMembershipsOfIssuer(idty.pub); + const mssFromMindex = await this.dal.mindexDAL.reducable(idty.pub); memberships = mss.map(m => { return { blockstamp: [m.blockNumber, m.blockHash].join('-'), @@ -95,25 +94,14 @@ export class IdentityService extends FIFOService { })) } - return { idty: obj, memberships } - } - - async findMemberWithoutMemberships(search:string) { - let idty = null; - if (search.match(constants.PUBLIC_KEY)) { - idty = await this.dal.getWrittenIdtyByPubkey(search) - } - else { - idty = await this.dal.getWrittenIdtyByUID(search) + return { + idty: { + pubkey: idty.pub, + uid: idty.uid, + buid: idty.created_on + }, + memberships } - if (!idty) { - throw constants.ERRORS.NO_MEMBER_MATCHING_PUB_OR_UID; - } - return DBIdentity.copyFromExisting(idty) - } - - getWrittenByPubkey(pubkey:string) { - return this.dal.getWrittenIdtyByPubkey(pubkey) } getPendingFromPubkey(pubkey:string) { @@ -134,17 +122,17 @@ export class IdentityService extends FIFOService { if (!verified) { throw constants.ERRORS.SIGNATURE_DOES_NOT_MATCH; } - let existing = await this.dal.getIdentityByHashOrNull(toSave.hash); + let existing = await this.dal.getGlobalIdentityByHashForExistence(toSave.hash); if (existing) { throw constants.ERRORS.ALREADY_UP_TO_DATE; } else { // Create if not already written uid/pubkey - let used = await this.dal.getWrittenIdtyByPubkey(idty.pubkey); + let used = await GLOBAL_RULES_HELPERS.checkExistsPubkey(idty.pubkey, this.dal) if (used) { throw constants.ERRORS.PUBKEY_ALREADY_USED; } - used = await this.dal.getWrittenIdtyByUID(idty.uid); + used = await GLOBAL_RULES_HELPERS.checkExistsUserID(idty.uid, this.dal) if (used) { throw constants.ERRORS.UID_ALREADY_USED; } @@ -183,9 +171,14 @@ export class IdentityService extends FIFOService { obj.currency = this.conf.currency || obj.currency; const cert = CertificationDTO.fromJSONObject(obj) const targetHash = cert.getTargetHash(); - let possiblyNullIdty = await this.dal.getIdentityByHashOrNull(targetHash); + let possiblyNullIdty = await this.dal.getGlobalIdentityByHashForHashingAndSig(targetHash); let idtyAbsorbed = false - const idty: DBIdentity = possiblyNullIdty !== null ? possiblyNullIdty : await this.submitIdentity({ + const idty:{ + pubkey:string + uid:string + buid:string + sig:string + } = possiblyNullIdty !== null ? possiblyNullIdty : await this.submitIdentity({ pubkey: cert.idty_issuer, uid: cert.idty_uid, buid: cert.idty_buid, @@ -199,7 +192,7 @@ export class IdentityService extends FIFOService { return this.pushFIFO<CertificationDTO>(hash, async () => { this.logger.info('⬇ CERT %s block#%s -> %s', cert.from, cert.block_number, idty.uid); try { - await GLOBAL_RULES_HELPERS.checkCertificationIsValid(cert, potentialNext, () => Promise.resolve(idty), this.conf, this.dal); + await GLOBAL_RULES_HELPERS.checkCertificationIsValidInSandbox(cert, potentialNext, () => Promise.resolve(idty), this.conf, this.dal); } catch (e) { anErr = e; } @@ -268,7 +261,7 @@ export class IdentityService extends FIFOService { if (!verified) { throw 'Wrong signature for revocation'; } - const existing = await this.dal.getIdentityByHashOrNull(obj.hash); + const existing = await this.dal.getGlobalIdentityByHashForRevocation(obj.hash) if (existing) { // Modify if (existing.revoked) { @@ -277,7 +270,15 @@ export class IdentityService extends FIFOService { else if (existing.revocation_sig) { throw 'Revocation already registered'; } else { - await this.dal.setRevocating(existing, revoc.revocation); + await this.dal.setRevocating({ + pubkey: existing.pub, + buid: existing.created_on, + sig: existing.sig, + uid: existing.uid, + expires_on: existing.expires_on, + member: existing.member, + wasMember: existing.wasMember, + }, revoc.revocation); this.logger.info('✔ REVOCATION %s %s', revoc.pubkey, revoc.idty_uid); return revoc } diff --git a/test/integration/branches_revert_memberships.js b/test/integration/branches_revert_memberships.js index b40919e7d0fd6555bd9121fa0fe1b80cbb0ded14..33446bee4f554b005d67518aa2b328834c612f86 100644 --- a/test/integration/branches_revert_memberships.js +++ b/test/integration/branches_revert_memberships.js @@ -15,9 +15,7 @@ const co = require('co'); const should = require('should'); -const bma = require('../../app/modules/bma').BmaDependency.duniter.methods.bma; const TestUser = require('./tools/TestUser').TestUser -const commit = require('./tools/commit'); const toolbox = require('./tools/toolbox'); let s1, i1, i2, i3 diff --git a/test/integration/wotb.js b/test/integration/wotb.js index 6c180b4a83ee20048172b8f584ff725b84a11bc0..029cc4b0b06a08d59695eb8c6985418bbad09bc1 100644 --- a/test/integration/wotb.js +++ b/test/integration/wotb.js @@ -132,8 +132,8 @@ describe("WOTB module", function() { it('the wotb_id should be affected to new members', function() { return co(function *() { - let icat = yield s1.dal.getWrittenIdtyByUID("cat"); - let itoc = yield s1.dal.getWrittenIdtyByUID("toc"); + let icat = yield s1.dal.getWrittenIdtyByUIDForWotbId("cat"); + let itoc = yield s1.dal.getWrittenIdtyByUIDForWotbId("toc"); icat.should.have.property('wotb_id').equal(0); itoc.should.have.property('wotb_id').equal(1); wotb.isEnabled(0).should.equal(true); @@ -157,7 +157,7 @@ describe("WOTB module", function() { yield toc.cert(tic); yield tic.join(); yield commit(s1)(); - let itic = yield s1.dal.getWrittenIdtyByUID("tic"); + let itic = yield s1.dal.getWrittenIdtyByUIDForWotbId("tic"); itic.should.have.property('wotb_id').equal(2); wotb.isEnabled(2).should.equal(true); wotb.existsLink(1, 2).should.equal(true);