From 8840d45cab7d052a8dd69f26edb5f44e1068e80a Mon Sep 17 00:00:00 2001 From: cgeek <cem.moreau@gmail.com> Date: Wed, 18 Jan 2017 11:33:28 +0100 Subject: [PATCH] [enh] #739 BMA is now an external module --- app/cli.js | 7 - app/controllers/abstract.js | 22 - app/controllers/blockchain.js | 148 -- app/controllers/network.js | 71 - app/controllers/node.js | 38 - app/controllers/transactions.js | 110 - app/controllers/uds.js | 63 - app/controllers/wot.js | 242 --- app/lib/constants.js | 32 - app/lib/contacter.js | 4 +- app/lib/entity/configuration.js | 7 - app/lib/helpers/http2raw.js | 38 - app/lib/helpers/http400.js | 9 - app/lib/helpers/parameters.js | 101 - app/lib/streams/bma.js | 31 - app/lib/streams/dtos.js | 449 ---- app/lib/streams/jsoner.js | 21 - app/lib/streams/routes.js | 125 -- app/lib/streams/sanitize.js | 118 -- app/lib/system/limiter.js | 114 -- app/lib/system/network.js | 255 +-- app/lib/system/upnp.js | 66 - app/modules/bmapi.js | 564 ----- doc/HTTP_API.md | 1812 ----------------- index.js | 16 +- package.json | 13 +- server.js | 22 +- test/dal/triming.js | 2 - test/fast/ddos-test.js | 39 - test/fast/limiter-test.js | 60 - test/integration/branches.js | 2 +- test/integration/branches2.js | 2 +- test/integration/branches_pending_data.js | 2 +- test/integration/branches_revert.js | 2 +- test/integration/branches_revert2.js | 2 +- .../branches_revert_memberships.js | 5 +- test/integration/branches_switch.js | 2 +- .../integration/certification_chainability.js | 2 +- test/integration/collapse.js | 2 +- test/integration/crosschain-test.js | 2 +- test/integration/forwarding.js | 5 +- test/integration/http_api.js | 2 +- test/integration/identity-absorption.js | 2 +- test/integration/identity-clean-test.js | 2 +- test/integration/identity-expiry.js | 2 +- test/integration/identity-kicking.js | 2 +- test/integration/identity-same-pubkey.js | 2 +- test/integration/identity-test.js | 5 +- test/integration/lookup.js | 2 +- test/integration/network.js | 1 + test/integration/peer-outdated.js | 2 +- test/integration/peerings.js | 2 +- test/integration/peers-same-pubkey.js | 2 +- test/integration/revocation-test.js | 5 +- test/integration/server-import-export.js | 2 +- test/integration/server-sandbox.js | 5 +- test/integration/start_generate_blocks.js | 2 +- test/integration/tests.js | 5 +- test/integration/tools/node.js | 9 +- test/integration/tools/toolbox.js | 9 +- test/integration/transactions-chaining.js | 5 +- test/integration/transactions-test.js | 4 +- test/integration/v0.4-dividend.js | 2 +- test/integration/v0.4-times.js | 2 +- test/integration/v0.5-identity-blockstamp.js | 4 +- test/integration/v0.5-transactions.js | 4 +- test/integration/v0.6-difficulties.js | 4 +- test/integration/v1.0-source-garbaging.js | 4 +- test/integration/wotb.js | 2 +- 69 files changed, 66 insertions(+), 4655 deletions(-) delete mode 100644 app/controllers/abstract.js delete mode 100644 app/controllers/blockchain.js delete mode 100644 app/controllers/network.js delete mode 100644 app/controllers/node.js delete mode 100644 app/controllers/transactions.js delete mode 100644 app/controllers/uds.js delete mode 100644 app/controllers/wot.js delete mode 100644 app/lib/helpers/http2raw.js delete mode 100644 app/lib/helpers/http400.js delete mode 100644 app/lib/helpers/parameters.js delete mode 100644 app/lib/streams/bma.js delete mode 100644 app/lib/streams/dtos.js delete mode 100644 app/lib/streams/jsoner.js delete mode 100644 app/lib/streams/routes.js delete mode 100644 app/lib/streams/sanitize.js delete mode 100644 app/lib/system/limiter.js delete mode 100644 app/lib/system/upnp.js delete mode 100644 app/modules/bmapi.js delete mode 100644 doc/HTTP_API.md delete mode 100644 test/fast/ddos-test.js delete mode 100644 test/fast/limiter-test.js diff --git a/app/cli.js b/app/cli.js index a4f04d0f7..16702d1fe 100644 --- a/app/cli.js +++ b/app/cli.js @@ -41,13 +41,6 @@ module.exports = () => { .option('-d, --mdb <name>', 'Database name (defaults to "duniter_default").') .option('--autoconf', 'With `config` and `init` commands, will guess the best network and key options witout asking for confirmation') - .option('--ipv4 <address>', 'IPv4 interface to listen for requests') - .option('--ipv6 <address>', 'IPv6 interface to listen for requests') - .option('--remoteh <host>', 'Remote interface others may use to contact this node') - .option('--remote4 <host>', 'Remote interface for IPv4 access') - .option('--remote6 <host>', 'Remote interface for IPv6 access') - .option('-p, --port <port>', 'Port to listen for requests', parseInt) - .option('--remotep <port>', 'Remote port others may use to contact this node') .option('--addep <endpoint>', 'With `config` command, add given endpoint to the list of endpoints of this node') .option('--remep <endpoint>', 'With `config` command, remove given endpoint to the list of endpoints of this node') diff --git a/app/controllers/abstract.js b/app/controllers/abstract.js deleted file mode 100644 index 977232e29..000000000 --- a/app/controllers/abstract.js +++ /dev/null @@ -1,22 +0,0 @@ - -"use strict"; -const co = require('co'); -const dos2unix = require('../lib/system/dos2unix'); - -module.exports = function AbstractController (server) { - - const logger = require('../lib/logger')('abstractController'); - - this.pushEntity = (req, rawer, type) => co(function *() { - let rawDocument = rawer(req); - rawDocument = dos2unix(rawDocument); - const written = yield server.writeRaw(rawDocument, type); - try { - return written.json(); - } catch (e) { - logger.error('Written:', written); - logger.error(e); - throw e; - } - }); -}; diff --git a/app/controllers/blockchain.js b/app/controllers/blockchain.js deleted file mode 100644 index b920b8c5c..000000000 --- a/app/controllers/blockchain.js +++ /dev/null @@ -1,148 +0,0 @@ -"use strict"; - -const co = require('co'); -const _ = require('underscore'); -const constants = require('../lib/constants'); -const http2raw = require('../lib/helpers/http2raw'); -const Membership = require('../lib/entity/membership'); -const AbstractController = require('./abstract'); - -module.exports = function (server) { - return new BlockchainBinding(server); -}; - -function BlockchainBinding (server) { - - AbstractController.call(this, server); - - const conf = server.conf; - - // Services - const ParametersService = server.ParametersService; - const BlockchainService = server.BlockchainService; - const IdentityService = server.IdentityService; - - // Models - const Block = require('../lib/entity/block'); - const Stat = require('../lib/entity/stat'); - - this.parseMembership = (req) => this.pushEntity(req, http2raw.membership, constants.ENTITY_MEMBERSHIP); - - this.parseBlock = (req) => this.pushEntity(req, http2raw.block, constants.ENTITY_BLOCK); - - this.parameters = () => server.dal.getParameters(); - - this.with = { - - newcomers: getStat('newcomers'), - certs: getStat('certs'), - joiners: getStat('joiners'), - actives: getStat('actives'), - leavers: getStat('leavers'), - revoked: getStat('revoked'), - excluded: getStat('excluded'), - ud: getStat('ud'), - tx: getStat('tx') - }; - - function getStat (statName) { - return () => co(function *() { - let stat = yield server.dal.getStat(statName); - return { result: new Stat(stat).json() }; - }); - } - - this.promoted = (req) => co(function *() { - const number = yield ParametersService.getNumberP(req); - const promoted = yield BlockchainService.promoted(number); - return new Block(promoted).json(); - }); - - this.blocks = (req) => co(function *() { - const params = ParametersService.getCountAndFrom(req); - const count = parseInt(params.count); - const from = parseInt(params.from); - let blocks = yield BlockchainService.blocksBetween(from, count); - blocks = blocks.map((b) => (new Block(b).json())); - return blocks; - }); - - this.current = () => co(function *() { - const current = yield server.dal.getCurrentBlockOrNull(); - if (!current) throw constants.ERRORS.NO_CURRENT_BLOCK; - return new Block(current).json(); - }); - - this.hardship = (req) => co(function *() { - let nextBlockNumber = 0; - const search = yield ParametersService.getSearchP(req); - const idty = yield IdentityService.findMemberWithoutMemberships(search); - if (!idty) { - throw constants.ERRORS.NO_MATCHING_IDENTITY; - } - if (!idty.member) { - throw constants.ERRORS.NOT_A_MEMBER; - } - const current = yield BlockchainService.current(); - if (current) { - nextBlockNumber = current ? current.number + 1 : 0; - } - const difficulty = yield server.getBcContext().getIssuerPersonalizedDifficulty(idty.pubkey); - return { - "block": nextBlockNumber, - "level": difficulty - }; - }); - - this.difficulties = () => co(function *() { - const current = yield server.dal.getCurrentBlockOrNull(); - const number = (current && current.number) || 0; - const issuers = yield server.dal.getUniqueIssuersBetween(number - 1 - current.issuersFrame, number - 1); - const difficulties = []; - for (const issuer of issuers) { - const member = yield server.dal.getWrittenIdtyByPubkey(issuer); - const difficulty = yield server.getBcContext().getIssuerPersonalizedDifficulty(member.pubkey); - difficulties.push({ - uid: member.uid, - level: difficulty - }); - } - return { - "block": number + 1, - "levels": _.sortBy(difficulties, (diff) => diff.level) - }; - }); - - this.memberships = (req) => co(function *() { - const search = yield ParametersService.getSearchP(req); - const idty = yield IdentityService.findMember(search); - const json = { - pubkey: idty.pubkey, - uid: idty.uid, - sigDate: idty.buid, - memberships: [] - }; - json.memberships = idty.memberships.map((msObj) => { - const ms = new Membership(msObj); - return { - version: ms.version, - currency: conf.currency, - membership: ms.membership, - blockNumber: parseInt(ms.blockNumber), - blockHash: ms.blockHash, - written: (!ms.written_number && ms.written_number !== 0) ? null : ms.written_number - }; - }); - json.memberships = _.sortBy(json.memberships, 'blockNumber'); - json.memberships.reverse(); - return json; - }); - - this.branches = () => co(function *() { - const branches = yield BlockchainService.branches(); - const blocks = branches.map((b) => new Block(b).json()); - return { - blocks: blocks - }; - }); -} diff --git a/app/controllers/network.js b/app/controllers/network.js deleted file mode 100644 index 8aaf57fdf..000000000 --- a/app/controllers/network.js +++ /dev/null @@ -1,71 +0,0 @@ -"use strict"; -const _ = require('underscore'); -const co = require('co'); -const http2raw = require('../lib/helpers/http2raw'); -const constants = require('../lib/constants'); -const Peer = require('../lib/entity/peer'); -const AbstractController = require('./abstract'); - -module.exports = function (server) { - return new NetworkBinding(server); -}; - -function NetworkBinding (server) { - - AbstractController.call(this, server); - - // Services - const MerkleService = server.MerkleService; - const PeeringService = server.PeeringService; - - this.cert = PeeringService.cert; - - this.peer = () => co(function *() { - const p = yield PeeringService.peer(); - if (!p) { - throw constants.ERRORS.SELF_PEER_NOT_FOUND; - } - return p.json(); - }); - - this.peersGet = (req) => co(function *() { - let merkle = yield server.dal.merkleForPeers(); - return yield MerkleService.processForURL(req, merkle, (hashes) => { - return co(function *() { - try { - let peers = yield server.dal.findPeersWhoseHashIsIn(hashes); - const map = {}; - peers.forEach((peer) => { - map[peer.hash] = Peer.statics.peerize(peer).json(); - }); - if (peers.length == 0) { - throw constants.ERRORS.PEER_NOT_FOUND; - } - return map; - } catch (e) { - throw e; - } - }); - }); - }); - - this.peersPost = (req) => this.pushEntity(req, http2raw.peer, constants.ENTITY_PEER); - - this.peers = () => co(function *() { - let peers = yield server.dal.listAllPeers(); - return { - peers: peers.map((p) => { - return _.pick(p, - 'version', - 'currency', - 'status', - 'first_down', - 'last_try', - 'pubkey', - 'block', - 'signature', - 'endpoints'); - }) - }; - }); -} diff --git a/app/controllers/node.js b/app/controllers/node.js deleted file mode 100644 index 4ebc3aba4..000000000 --- a/app/controllers/node.js +++ /dev/null @@ -1,38 +0,0 @@ -"use strict"; - -const co = require('co'); - -module.exports = function (server) { - return new NodeBinding(server); -}; - -function NodeBinding (server) { - - this.summary = () => { - return { - "duniter": { - "software": "duniter", - "version": server.version, - "forkWindowSize": server.conf.forksize - } - }; - }; - - this.sandboxes = () => co(function*() { - return { - identities: yield sandboxIt(server.dal.idtyDAL.sandbox), - certifications: yield sandboxIt(server.dal.certDAL.sandbox), - memberships: yield sandboxIt(server.dal.msDAL.sandbox), - transactions: yield sandboxIt(server.dal.txsDAL.sandbox) - }; - }); -} - -function sandboxIt(sandbox) { - return co(function*() { - return { - size: sandbox.maxSize, - free: yield sandbox.getSandboxRoom() - }; - }); -} diff --git a/app/controllers/transactions.js b/app/controllers/transactions.js deleted file mode 100644 index b942455b6..000000000 --- a/app/controllers/transactions.js +++ /dev/null @@ -1,110 +0,0 @@ -"use strict"; -const co = require('co'); -const _ = require('underscore'); -const http2raw = require('../lib/helpers/http2raw'); -const Transaction = require('../lib/entity/transaction'); -const constants = require('../lib/constants'); -const AbstractController = require('./abstract'); - -module.exports = function (server) { - return new TransactionBinding(server); -}; - -function TransactionBinding(server) { - - AbstractController.call(this, server); - - const conf = server.conf; - - // Services - const ParametersService = server.ParametersService; - - // Models - const Source = require('../lib/entity/source'); - - this.parseTransaction = (req) => this.pushEntity(req, http2raw.transaction, constants.ENTITY_TRANSACTION); - - this.getSources = (req) => co(function *() { - const pubkey = yield ParametersService.getPubkeyP(req); - const sources = yield server.dal.getAvailableSourcesByPubkey(pubkey); - const result = { - "currency": conf.currency, - "pubkey": pubkey, - "sources": [] - }; - sources.forEach(function (src) { - result.sources.push(new Source(src).json()); - }); - return result; - }); - - this.getHistory = (req) => co(function *() { - const pubkey = yield ParametersService.getPubkeyP(req); - return getFilteredHistory(pubkey, (results) => results); - }); - - this.getHistoryBetweenBlocks = (req) => co(function *() { - const pubkey = yield ParametersService.getPubkeyP(req); - const from = yield ParametersService.getFromP(req); - const to = yield ParametersService.getToP(req); - return getFilteredHistory(pubkey, (res) => { - const histo = res.history; - histo.sent = _.filter(histo.sent, function(tx){ return tx && tx.block_number >= from && tx.block_number <= to; }); - histo.received = _.filter(histo.received, function(tx){ return tx && tx.block_number >= from && tx.block_number <= to; }); - _.extend(histo, { sending: [], receiving: [] }); - return res; - }); - }); - - this.getHistoryBetweenTimes = (req) => co(function *() { - const pubkey = yield ParametersService.getPubkeyP(req); - const from = yield ParametersService.getFromP(req); - const to = yield ParametersService.getToP(req); - return getFilteredHistory(pubkey, (res) => { - const histo = res.history; - histo.sent = _.filter(histo.sent, function(tx){ return tx && tx.time >= from && tx.time <= to; }); - histo.received = _.filter(histo.received, function(tx){ return tx && tx.time >= from && tx.time <= to; }); - _.extend(histo, { sending: [], receiving: [] }); - return res; - }); - }); - - this.getPendingForPubkey = (req) => co(function *() { - const pubkey = yield ParametersService.getPubkeyP(req); - return getFilteredHistory(pubkey, function(res) { - const histo = res.history; - _.extend(histo, { sent: [], received: [] }); - return res; - }); - }); - - this.getPending = () => co(function *() { - const pending = yield server.dal.getTransactionsPending(); - const res = { - "currency": conf.currency, - "pending": pending - }; - pending.map(function(tx, index) { - pending[index] = _.omit(new Transaction(tx).json(), 'currency', 'raw'); - }); - return res; - }); - - const getFilteredHistory = (pubkey, filter) => co(function*() { - let history = yield server.dal.getTransactionsHistory(pubkey); - let result = { - "currency": conf.currency, - "pubkey": pubkey, - "history": history - }; - _.keys(history).map((key) => { - history[key].map((tx, index) => { - history[key][index] = _.omit(new Transaction(tx).json(), 'currency', 'raw'); - _.extend(history[key][index], {block_number: tx && tx.block_number, time: tx && tx.time}); - }); - }); - return filter(result); - }); - - return this; -} diff --git a/app/controllers/uds.js b/app/controllers/uds.js deleted file mode 100644 index b8c4378ba..000000000 --- a/app/controllers/uds.js +++ /dev/null @@ -1,63 +0,0 @@ -"use strict"; -const co = require('co'); -const _ = require('underscore'); - -module.exports = function (server) { - return new UDBinding(server); -}; - -function UDBinding(server) { - - const conf = server.conf; - - // Services - const ParametersService = server.ParametersService; - - // Models - const Source = require('../lib/entity/source'); - - this.getHistory = (req) => co(function *() { - const pubkey = yield ParametersService.getPubkeyP(req); - return getUDSources(pubkey, (results) => results); - }); - - this.getHistoryBetweenBlocks = (req) => co(function *() { - const pubkey = yield ParametersService.getPubkeyP(req); - const from = yield ParametersService.getFromP(req); - const to = yield ParametersService.getToP(req); - return getUDSources(pubkey, (results) => { - results.history.history = _.filter(results.history.history, function(ud){ return ud.block_number >= from && ud.block_number <= to; }); - return results; - }); - }); - - this.getHistoryBetweenTimes = (req) => co(function *() { - const pubkey = yield ParametersService.getPubkeyP(req); - const from = yield ParametersService.getFromP(req); - const to = yield ParametersService.getToP(req); - return getUDSources(pubkey, (results) => { - results.history.history = _.filter(results.history.history, function(ud){ return ud.time >= from && ud.time <= to; }); - return results; - }); - }); - - function getUDSources(pubkey, filter) { - return co(function *() { - const history = yield server.dal.getUDHistory(pubkey); - const result = { - "currency": conf.currency, - "pubkey": pubkey, - "history": history - }; - _.keys(history).map((key) => { - history[key].map((src, index) => { - history[key][index] = _.omit(new Source(src).UDjson(), 'currency', 'raw'); - _.extend(history[key][index], { block_number: src && src.block_number, time: src && src.time }); - }); - }); - return filter(result); - }); - } - - return this; -} diff --git a/app/controllers/wot.js b/app/controllers/wot.js deleted file mode 100644 index f60b97df4..000000000 --- a/app/controllers/wot.js +++ /dev/null @@ -1,242 +0,0 @@ -"use strict"; -const co = require('co'); -const _ = require('underscore'); -const http2raw = require('../lib/helpers/http2raw'); -const constants = require('../lib/constants'); -const AbstractController = require('./abstract'); -const logger = require('../lib/logger')(); - -module.exports = function (server) { - return new WOTBinding(server); -}; - -function WOTBinding (server) { - - AbstractController.call(this, server); - - const ParametersService = server.ParametersService; - const IdentityService = server.IdentityService; - const BlockchainService = server.BlockchainService; - - const Identity = require('../lib/entity/identity'); - - this.lookup = (req) => co(function *() { - // Get the search parameter from HTTP query - const search = yield ParametersService.getSearchP(req); - // Make the research - const identities = yield IdentityService.searchIdentities(search); - // Entitify each result - identities.forEach((idty, index) => identities[index] = new Identity(idty)); - // Prepare some data to avoid displaying expired certifications - for (const idty of identities) { - const certs = yield server.dal.certsToTarget(idty.pubkey, idty.getTargetHash()); - const validCerts = []; - for (const cert of certs) { - const member = yield IdentityService.getWrittenByPubkey(cert.from); - if (member) { - cert.uids = [member.uid]; - cert.isMember = member.member; - cert.wasMember = member.wasMember; - } else { - const potentials = yield IdentityService.getPendingFromPubkey(cert.from); - cert.uids = _(potentials).pluck('uid'); - cert.isMember = false; - cert.wasMember = false; - } - validCerts.push(cert); - } - idty.certs = validCerts; - const signed = yield server.dal.certsFrom(idty.pubkey); - const validSigned = []; - for (let j = 0; j < signed.length; j++) { - const cert = _.clone(signed[j]); - cert.idty = yield server.dal.getIdentityByHashOrNull(cert.target); - if (cert.idty) { - validSigned.push(cert); - } else { - logger.debug('A certification to an unknown identity was found (%s => %s)', cert.from, cert.to); - } - } - idty.signed = validSigned; - } - if (identities.length == 0) { - throw constants.ERRORS.NO_MATCHING_IDENTITY; - } - const resultsByPubkey = {}; - identities.forEach((identity) => { - const jsoned = identity.json(); - if (!resultsByPubkey[jsoned.pubkey]) { - // Create the first matching identity with this pubkey in the map - resultsByPubkey[jsoned.pubkey] = jsoned; - } else { - // Merge the identity with the existing(s) - const existing = resultsByPubkey[jsoned.pubkey]; - // We add the UID of the identity to the list of already added UIDs - existing.uids = existing.uids.concat(jsoned.uids); - // We do not merge the `signed`: every identity with the same pubkey has the same `signed` because it the *pubkey* which signs, not the identity - } - }); - return { - partial: false, - results: Object.values(resultsByPubkey) - }; - }); - - this.members = () => co(function *() { - const identities = yield server.dal.getMembers(); - const json = { - results: [] - }; - identities.forEach((identity) => json.results.push({ pubkey: identity.pubkey, uid: identity.uid })); - return json; - }); - - this.certifiersOf = (req) => co(function *() { - const search = yield ParametersService.getSearchP(req); - const idty = yield IdentityService.findMemberWithoutMemberships(search); - const certs = yield server.dal.certsToTarget(idty.pubkey, idty.getTargetHash()); - idty.certs = []; - for (const cert of certs) { - const certifier = yield server.dal.getWrittenIdtyByPubkey(cert.from); - if (certifier) { - cert.uid = certifier.uid; - cert.isMember = certifier.member; - cert.sigDate = certifier.buid; - cert.wasMember = true; // As we checked if(certified) - if (!cert.cert_time) { - let certBlock = yield server.dal.getBlock(cert.block_number); - cert.cert_time = { - block: certBlock.number, - medianTime: certBlock.medianTime - }; - } - idty.certs.push(cert); - } - } - const json = { - pubkey: idty.pubkey, - uid: idty.uid, - sigDate: idty.buid, - isMember: idty.member, - certifications: [] - }; - idty.certs.forEach(function(cert){ - json.certifications.push({ - pubkey: cert.from, - uid: cert.uid, - isMember: cert.isMember, - wasMember: cert.wasMember, - cert_time: cert.cert_time, - sigDate: cert.sigDate, - written: cert.linked ? { - number: cert.written_block, - hash: cert.written_hash - } : null, - signature: cert.sig - }); - }); - return json; - }); - - this.requirements = (req) => co(function *() { - const search = yield ParametersService.getSearchP(req); - const identities = yield IdentityService.searchIdentities(search); - const all = yield BlockchainService.requirementsOfIdentities(identities); - if (!all || !all.length) { - throw constants.ERRORS.NO_IDTY_MATCHING_PUB_OR_UID; - } - return { - identities: all - }; - }); - - this.certifiedBy = (req) => co(function *() { - const search = yield ParametersService.getSearchP(req); - const idty = yield IdentityService.findMemberWithoutMemberships(search); - const certs = yield server.dal.certsFrom(idty.pubkey); - idty.certs = []; - for (const cert of certs) { - const certified = yield server.dal.getWrittenIdtyByPubkey(cert.to); - if (certified) { - cert.uid = certified.uid; - cert.isMember = certified.member; - cert.sigDate = certified.buid; - cert.wasMember = true; // As we checked if(certified) - if (!cert.cert_time) { - let certBlock = yield server.dal.getBlock(cert.block_number); - cert.cert_time = { - block: certBlock.number, - medianTime: certBlock.medianTime - }; - } - idty.certs.push(cert); - } - } - const json = { - pubkey: idty.pubkey, - uid: idty.uid, - sigDate: idty.buid, - isMember: idty.member, - certifications: [] - }; - idty.certs.forEach((cert) => json.certifications.push({ - pubkey: cert.to, - uid: cert.uid, - isMember: cert.isMember, - wasMember: cert.wasMember, - cert_time: cert.cert_time, - sigDate: cert.sigDate, - written: cert.linked ? { - number: cert.written_block, - hash: cert.written_hash - } : null, - signature: cert.sig - }) - ); - return json; - }); - - this.identityOf = (req) => co(function *() { - let search = yield ParametersService.getSearchP(req); - let idty = yield IdentityService.findMemberWithoutMemberships(search); - if (!idty) { - throw 'Identity not found'; - } - if (!idty.member) { - throw 'Not a member'; - } - return { - pubkey: idty.pubkey, - uid: idty.uid, - sigDate: idty.buid - }; - }); - - this.add = (req) => this.pushEntity(req, http2raw.identity, constants.ENTITY_IDENTITY); - - this.certify = (req) => this.pushEntity(req, http2raw.certification, constants.ENTITY_CERTIFICATION); - - this.revoke = (req) => this.pushEntity(req, http2raw.revocation, constants.ENTITY_REVOCATION); - - this.pendingMemberships = () => co(function*() { - const memberships = yield server.dal.findNewcomers(); - const json = { - memberships: [] - }; - json.memberships = memberships.map((ms) => { - return { - pubkey: ms.issuer, - uid: ms.userid, - version: ms.version, - currency: server.conf.currency, - membership: ms.membership, - blockNumber: parseInt(ms.blockNumber), - blockHash: ms.blockHash, - written: (!ms.written_number && ms.written_number !== 0) ? null : ms.written_number - }; - }); - json.memberships = _.sortBy(json.memberships, 'blockNumber'); - json.memberships.reverse(); - return json; - }); -} diff --git a/app/lib/constants.js b/app/lib/constants.js index 3b5c2fa71..091b6ef11 100644 --- a/app/lib/constants.js +++ b/app/lib/constants.js @@ -32,14 +32,6 @@ const MAXIMUM_LEN_OF_COMPACT_TX = 100; module.exports = { - ENTITY_TRANSACTION: 'transaction', - ENTITY_BLOCK: 'block', - ENTITY_MEMBERSHIP: 'membership', - ENTITY_PEER: 'peer', - ENTITY_IDENTITY: 'identity', - ENTITY_CERTIFICATION: 'certification', - ENTITY_REVOCATION: 'revocation', - ERROR: { PEER: { @@ -59,7 +51,6 @@ module.exports = { SIGNATURE_DOES_NOT_MATCH: { httpCode: 400, uerr: { ucode: 1003, message: "Signature does not match" }}, ALREADY_UP_TO_DATE: { httpCode: 400, uerr: { ucode: 1004, message: "Already up-to-date" }}, WRONG_DOCUMENT: { httpCode: 400, uerr: { ucode: 1005, message: "Document has unkown fields or wrong line ending format" }}, - HTTP_LIMITATION: { httpCode: 503, uerr: { ucode: 1006, message: "This URI has reached its maximum usage quota. Please retry later." }}, SANDBOX_FOR_IDENTITY_IS_FULL: { httpCode: 503, uerr: { ucode: 1007, message: "The identities' sandbox is full. Please retry with another document or retry later." }}, SANDBOX_FOR_CERT_IS_FULL: { httpCode: 503, uerr: { ucode: 1008, message: "The certifications' sandbox is full. Please retry with another document or retry later." }}, SANDBOX_FOR_MEMERSHIP_IS_FULL: { httpCode: 503, uerr: { ucode: 1009, message: "The memberships' sandbox is full. Please retry with another document or retry later." }}, @@ -69,31 +60,16 @@ module.exports = { CLI_CALLERR_RESET: { httpCode: 503, uerr: { ucode: 1013, message: "Bad command: usage is `reset config`, `reset data`, `reset peers`, `reset stats` or `reset all`" }}, CLI_CALLERR_CONFIG: { httpCode: 503, uerr: { ucode: 1014, message: "Bad command: usage is `config`." }}, - HTTP_PARAM_PUBKEY_REQUIRED: { httpCode: 400, uerr: { ucode: 1101, message: "Parameter `pubkey` is required" }}, - HTTP_PARAM_IDENTITY_REQUIRED: { httpCode: 400, uerr: { ucode: 1102, message: "Parameter `identity` is required" }}, - HTTP_PARAM_PEER_REQUIRED: { httpCode: 400, uerr: { ucode: 1103, message: "Requires a peer" }}, - HTTP_PARAM_BLOCK_REQUIRED: { httpCode: 400, uerr: { ucode: 1104, message: "Requires a block" }}, - HTTP_PARAM_MEMBERSHIP_REQUIRED: { httpCode: 400, uerr: { ucode: 1105, message: "Requires a membership" }}, - HTTP_PARAM_TX_REQUIRED: { httpCode: 400, uerr: { ucode: 1106, message: "Requires a transaction" }}, - HTTP_PARAM_SIG_REQUIRED: { httpCode: 400, uerr: { ucode: 1107, message: "Parameter `sig` is required" }}, - HTTP_PARAM_CERT_REQUIRED: { httpCode: 400, uerr: { ucode: 1108, message: "Parameter `cert` is required" }}, - HTTP_PARAM_REVOCATION_REQUIRED: { httpCode: 400, uerr: { ucode: 1109, message: "Parameter `revocation` is required" }}, - HTTP_PARAM_CONF_REQUIRED: { httpCode: 400, uerr: { ucode: 1110, message: "Parameter `conf` is required" }}, - HTTP_PARAM_CPU_REQUIRED: { httpCode: 400, uerr: { ucode: 1111, message: "Parameter `cpu` is required" }}, - // Business errors NO_MATCHING_IDENTITY: { httpCode: 404, uerr: { ucode: 2001, message: "No matching identity" }}, UID_ALREADY_USED: { httpCode: 400, uerr: { ucode: 2002, message: "UID already used in the blockchain" }}, PUBKEY_ALREADY_USED: { httpCode: 400, uerr: { ucode: 2003, message: "Pubkey already used in the blockchain" }}, NO_MEMBER_MATCHING_PUB_OR_UID: { httpCode: 404, uerr: { ucode: 2004, message: "No member matching this pubkey or uid" }}, - SELF_PEER_NOT_FOUND: { httpCode: 404, uerr: { ucode: 2005, message: "Self peering was not found" }}, WRONG_SIGNATURE_MEMBERSHIP: { httpCode: 400, uerr: { ucode: 2006, message: "wrong signature for membership" }}, ALREADY_RECEIVED_MEMBERSHIP: { httpCode: 400, uerr: { ucode: 2007, message: "Already received membership" }}, MEMBERSHIP_A_NON_MEMBER_CANNOT_LEAVE: { httpCode: 400, uerr: { ucode: 2008, message: "A non-member cannot leave" }}, NOT_A_MEMBER: { httpCode: 400, uerr: { ucode: 2009, message: "Not a member" }}, - NO_CURRENT_BLOCK: { httpCode: 404, uerr: { ucode: 2010, message: "No current block" }}, BLOCK_NOT_FOUND: { httpCode: 404, uerr: { ucode: 2011, message: "Block not found" }}, - PEER_NOT_FOUND: { httpCode: 404, uerr: { ucode: 2012, message: "Peer not found" }}, WRONG_UNLOCKER: { httpCode: 400, uerr: { ucode: 2013, message: "Wrong unlocker in transaction" }}, LOCKTIME_PREVENT: { httpCode: 400, uerr: { ucode: 2014, message: "Locktime not elapsed yet" }}, SOURCE_ALREADY_CONSUMED: { httpCode: 400, uerr: { ucode: 2015, message: "Source already consumed" }}, @@ -250,14 +226,6 @@ module.exports = { MAX_CONCURRENT_POST: 3, DEFAULT_TIMEOUT: 10 * 1000, // 10 seconds SYNC_LONG_TIMEOUT: 30 * 1000, // 30 seconds - DEFAULT_PORT: 8999, - PORT: { - START: 15000 - }, - UPNP: { - INTERVAL: 300, - TTL: 600 - }, SYNC: { MAX: 20 }, diff --git a/app/lib/contacter.js b/app/lib/contacter.js index 9187a4483..fcb34cfdd 100644 --- a/app/lib/contacter.js +++ b/app/lib/contacter.js @@ -3,8 +3,8 @@ const co = require('co'); const rp = require('request-promise'); const constants = require('./constants'); -const sanitize = require('./streams/sanitize'); -const dtos = require('./streams/dtos'); +const sanitize = require('duniter-bma').duniter.methods.sanitize; +const dtos = require('duniter-bma').duniter.methods.dtos; /** * Created by cgeek on 16/10/16. diff --git a/app/lib/entity/configuration.js b/app/lib/entity/configuration.js index acec9a379..5749d9377 100644 --- a/app/lib/entity/configuration.js +++ b/app/lib/entity/configuration.js @@ -5,13 +5,6 @@ const constants = require('../constants'); const defaultConf = function() { return { "currency": null, - "port": constants.NETWORK.DEFAULT_PORT, - "ipv4": "127.0.0.1", - "ipv6": null, - "remotehost": null, - "remoteipv4": null, - "remoteipv6": null, - "remoteport": constants.NETWORK.DEFAULT_PORT, "endpoints": [], "rmEndpoints": [], "cpu": constants.DEFAULT_CPU, diff --git a/app/lib/helpers/http2raw.js b/app/lib/helpers/http2raw.js deleted file mode 100644 index 76580f190..000000000 --- a/app/lib/helpers/http2raw.js +++ /dev/null @@ -1,38 +0,0 @@ -"use strict"; - -const constants = require('../constants'); - -module.exports = { - identity: requiresParameter('identity', constants.ERRORS.HTTP_PARAM_IDENTITY_REQUIRED), - certification: requiresParameter('cert', constants.ERRORS.HTTP_PARAM_CERT_REQUIRED), - revocation: requiresParameter('revocation', constants.ERRORS.HTTP_PARAM_REVOCATION_REQUIRED), - transaction: requiresParameter('transaction', constants.ERRORS.HTTP_PARAM_TX_REQUIRED), - peer: requiresParameter('peer', constants.ERRORS.HTTP_PARAM_PEER_REQUIRED), - membership: Http2RawMembership, - block: requiresParameter('block', constants.ERRORS.HTTP_PARAM_BLOCK_REQUIRED), - conf: requiresParameter('conf', constants.ERRORS.HTTP_PARAM_CONF_REQUIRED), - cpu: requiresParameter('cpu', constants.ERRORS.HTTP_PARAM_CPU_REQUIRED) -}; - -function requiresParameter(parameter, err) { - return (req) => { - if(!req.body || req.body[parameter] === undefined){ - throw err; - } - return req.body[parameter]; - }; -} - -function Http2RawMembership (req) { - if(!(req.body && req.body.membership)){ - throw constants.ERRORS.HTTP_PARAM_MEMBERSHIP_REQUIRED; - } - let ms = req.body.membership; - if(req.body && req.body.signature){ - ms = [ms, req.body.signature].join(''); - if (!ms.match(/\n$/)) { - ms += '\n'; - } - } - return ms; -} diff --git a/app/lib/helpers/http400.js b/app/lib/helpers/http400.js deleted file mode 100644 index 5029d40cc..000000000 --- a/app/lib/helpers/http400.js +++ /dev/null @@ -1,9 +0,0 @@ -"use strict"; -const logger = require('../logger')('http'); - -module.exports = function http400 (res) { - return function (err) { - logger.warn(err); - res.send(400, err); - }; -} diff --git a/app/lib/helpers/parameters.js b/app/lib/helpers/parameters.js deleted file mode 100644 index 2bb664b68..000000000 --- a/app/lib/helpers/parameters.js +++ /dev/null @@ -1,101 +0,0 @@ -"use strict"; -const Q = require('q'); -const constants = require('../constants'); - -module.exports = function () { - return new ParameterNamespace(); -}; - -function ParameterNamespace () { - - this.getSearch = function (req, callback) { - if(!req.params || !req.params.search){ - callback("No search criteria given"); - return; - } - callback(null, req.params.search); - }; - - this.getSearchP = (req) => Q.nbind(this.getSearch, this)(req); - - this.getCountAndFrom = function (req){ - if(!req.params.from){ - throw "From is required"; - } - if(!req.params.count){ - throw "Count is required"; - } - const matches = req.params.from.match(/^(\d+)$/); - if(!matches){ - throw "From format is incorrect, must be a positive integer"; - } - const matches2 = req.params.count.match(/^(\d+)$/); - if(!matches2){ - throw "Count format is incorrect, must be a positive integer"; - } - return { - count: matches2[1], - from: matches[1] - }; - }; - - this.getPubkey = function (req, callback){ - if(!req.params.pubkey){ - callback('Parameter `pubkey` is required'); - return; - } - const matches = req.params.pubkey.match(constants.PUBLIC_KEY); - if(!matches){ - callback("Pubkey format is incorrect, must be a Base58 string"); - return; - } - callback(null, matches[0]); - }; - - this.getPubkeyP = (req) => Q.nbind(this.getPubkey, this)(req); - - this.getFrom = function (req, callback){ - if(!req.params.from){ - callback('Parameter `from` is required'); - return; - } - const matches = req.params.from.match(/^(\d+)$/); - if(!matches){ - callback("From format is incorrect, must be a positive or zero integer"); - return; - } - callback(null, matches[0]); - }; - - this.getFromP = (req) => Q.nbind(this.getFrom, this)(req); - - this.getTo = function (req, callback){ - if(!req.params.to){ - callback('Parameter `to` is required'); - return; - } - const matches = req.params.to.match(/^(\d+)$/); - if(!matches){ - callback("To format is incorrect, must be a positive or zero integer"); - return; - } - callback(null, matches[0]); - }; - - this.getToP = (req) => Q.nbind(this.getTo, this)(req); - - this.getNumber = function (req, callback){ - if(!req.params.number){ - callback("Number is required"); - return; - } - const matches = req.params.number.match(/^(\d+)$/); - if(!matches){ - callback("Number format is incorrect, must be a positive integer"); - return; - } - callback(null, parseInt(matches[1])); - }; - - this.getNumberP = (req) => Q.nbind(this.getNumber, this)(req); -} diff --git a/app/lib/streams/bma.js b/app/lib/streams/bma.js deleted file mode 100644 index 7d1158749..000000000 --- a/app/lib/streams/bma.js +++ /dev/null @@ -1,31 +0,0 @@ -"use strict"; - -const network = require('../system/network'); -const routes = require('./routes'); - -module.exports = function(server, interfaces, httpLogs) { - - if (!interfaces) { - interfaces = []; - if (server.conf) { - if (server.conf.ipv4) { - interfaces = [{ - ip: server.conf.ipv4, - port: server.conf.port - }]; - } - if (server.conf.ipv6) { - interfaces.push({ - ip: server.conf.ipv6, - port: (server.conf.remoteport || server.conf.port) // We try to get the best one - }); - } - } - } - - return network.createServersAndListen('Duniter server', interfaces, httpLogs, null, (app, httpMethods) => { - - routes.bma(server, '', app, httpMethods); - - }, routes.bmaWS(server, '')); -}; diff --git a/app/lib/streams/dtos.js b/app/lib/streams/dtos.js deleted file mode 100644 index e39137068..000000000 --- a/app/lib/streams/dtos.js +++ /dev/null @@ -1,449 +0,0 @@ -"use strict"; - -let dtos; - -module.exports = dtos = {}; - -dtos.Summary = { - duniter: { - "software": String, - "version": String, - "forkWindowSize": Number - } -}; - -dtos.Parameters = { - currency: String, - c: Number, - dt: Number, - ud0: Number, - sigPeriod: Number, - sigStock: Number, - sigWindow: Number, - sigValidity: Number, - sigQty: Number, - idtyWindow: Number, - msWindow: Number, - xpercent: Number, - msValidity: Number, - stepMax: Number, - medianTimeBlocks: Number, - avgGenTime: Number, - dtDiffEval: Number, - percentRot: Number -}; - -dtos.Membership = { - "signature": String, - "membership": { - "version": Number, - "currency": String, - "issuer": String, - "membership": String, - "date": Number, - "sigDate": Number, - "raw": String - } -}; - -dtos.Memberships = { - "pubkey": String, - "uid": String, - "sigDate": String, - "memberships": [ - { - "version": Number, - "currency": String, - "membership": String, - "blockNumber": Number, - "blockHash": String, - "written": Number - } - ] -}; - -dtos.MembershipList = { - "memberships": [ - { - "pubkey": String, - "uid": String, - "version": Number, - "currency": String, - "membership": String, - "blockNumber": Number, - "blockHash": String, - "written": Number - } - ] -}; - -dtos.TransactionOfBlock = { - "version": Number, - "currency": String, - "comment": String, - "locktime": Number, - "signatures": [String], - "outputs": [String], - "inputs": [String], - "unlocks": [String], - "block_number": Number, - "blockstamp": String, - "blockstampTime": Number, - "time": Number, - "issuers": [String] -}; - -dtos.Block = { - "version": Number, - "currency": String, - "number": Number, - "issuer": String, - "issuersFrame": Number, - "issuersFrameVar": Number, - "issuersCount": Number, - "parameters": String, - "membersCount": Number, - "monetaryMass": Number, - "powMin": Number, - "time": Number, - "medianTime": Number, - "dividend": Number, - "unitbase": Number, - "hash": String, - "previousHash": String, - "previousIssuer": String, - "identities": [String], - "certifications": [String], - "joiners": [String], - "actives": [String], - "leavers": [String], - "revoked": [String], - "excluded": [String], - "transactions": [dtos.TransactionOfBlock], - "nonce": Number, - "inner_hash": String, - "signature": String, - "raw": String -}; - -dtos.Hardship = { - "block": Number, - "level": Number -}; - -dtos.Difficulty = { - "uid": String, - "level": Number -}; - -dtos.Difficulties = { - "block": Number, - "levels": [dtos.Difficulty] -}; - -dtos.Blocks = [dtos.Block]; - -dtos.Stat = { - "result": { - "blocks": [Number] - } -}; - -dtos.Branches = { - "blocks": [dtos.Block] -}; - -dtos.Peer = { - "version": Number, - "currency": String, - "pubkey": String, - "block": String, - "endpoints": [String], - "signature": String, - "raw": String -}; - -dtos.DBPeer = { - "version": Number, - "currency": String, - "pubkey": String, - "block": String, - "status": String, - "first_down": Number, - "last_try": Number, - "endpoints": [String], - "signature": String, - "raw": String -}; - -dtos.Peers = { - "peers": [dtos.DBPeer] -}; - -dtos.MerkleOfPeers = { - "depth": Number, - "nodesCount": Number, - "leavesCount": Number, - "root": String, - "leaves": [String], - "leaf": { - "hash": String, - "value": dtos.DBPeer - } -}; - -dtos.Other = { - "pubkey": String, - "meta": { - "block_number": Number, - "block_hash": String - }, - "uids": [String], - "isMember": Boolean, - "wasMember": Boolean, - "signature": String -}; - -dtos.UID = { - "uid": String, - "meta": { - "timestamp": String - }, - "self": String, - "revocation_sig": String, - "revoked": Boolean, - "revoked_on": Number, - "others": [dtos.Other] -}; - -dtos.Signed = { - "uid": String, - "pubkey": String, - "meta": { - "timestamp": String - }, - "cert_time": { - "block": Number, - "block_hash": String - }, - "isMember": Boolean, - "wasMember": Boolean, - "signature": String -}; - -dtos.CertIdentity = { - "issuer": String, - "uid": String, - "timestamp": String, - "sig": String -}; - -dtos.Cert = { - "issuer": String, - "timestamp": String, - "sig": String, - "target": dtos.CertIdentity -}; - -dtos.Identity = { - "pubkey": String, - "uids": [dtos.UID], - "signed": [dtos.Signed] -}; - -dtos.Result = { - "result": Boolean -}; - -dtos.Lookup = { - "partial": Boolean, - "results": [dtos.Identity] -}; - -dtos.Members = { - "results": [{ - pubkey: String, - uid: String - }] -}; - -dtos.RequirementsCert = { - from: String, - to: String, - expiresIn: Number -}; - -dtos.Requirements = { - "identities": [{ - pubkey: String, - uid: String, - meta: { - timestamp: String - }, - expired: Boolean, - outdistanced: Boolean, - certifications: [dtos.RequirementsCert], - membershipPendingExpiresIn: Number, - membershipExpiresIn: Number - }] -}; - -dtos.Certification = { - "pubkey": String, - "uid": String, - "isMember": Boolean, - "wasMember": Boolean, - "cert_time": { - "block": Number, - "medianTime": Number - }, - "sigDate": String, - "written": { - "number": Number, - "hash": String - }, - "signature": String -}; - -dtos.Certifications = { - "pubkey": String, - "uid": String, - "sigDate": String, - "isMember": Boolean, - "certifications": [dtos.Certification] -}; - -dtos.SimpleIdentity = { - "pubkey": String, - "uid": String, - "sigDate": String -}; - -dtos.Transaction = { - "version": Number, - "currency": String, - "issuers": [String], - "inputs": [String], - "unlocks": [String], - "outputs": [String], - "comment": String, - "locktime": Number, - "signatures": [String], - "raw": String, - "hash": String -}; - -dtos.Source = { - "type": String, - "noffset": Number, - "identifier": String, - "amount": Number, - "base": Number -}; - -dtos.Sources = { - "currency": String, - "pubkey": String, - "sources": [dtos.Source] -}; - -dtos.TxOfHistory = { - "version": Number, - "issuers": [String], - "inputs": [String], - "unlocks": [String], - "outputs": [String], - "comment": String, - "locktime": Number, - "received": Number, - "signatures": [String], - "hash": String, - "block_number": Number, - "time": Number, - "blockstamp": String, - "blockstampTime": Number -}; - -dtos.TxHistory = { - "currency": String, - "pubkey": String, - "history": { - "sent": [dtos.TxOfHistory], - "received": [dtos.TxOfHistory], - "sending": [dtos.TxOfHistory], - "receiving": [dtos.TxOfHistory], - "pending": [dtos.TxOfHistory] - } -}; - -dtos.TxPending = { - "currency": String, - "pending": [dtos.Transaction] -}; - -dtos.UD = { - "block_number": Number, - "consumed": Boolean, - "time": Number, - "amount": Number, - "base": Number -}; - -dtos.UDHistory = { - "currency": String, - "pubkey": String, - "history": { - "history": [dtos.UD] - } -}; - -dtos.Boolean = { - "success": Boolean -}; - -dtos.SummaryConf = { - "cpu": Number -}; - -dtos.AdminSummary = { - "version": String, - "host": String, - "current": dtos.Block, - "rootBlock": dtos.Block, - "pubkey": String, - "seckey": String, - "conf": dtos.SummaryConf, - "parameters": dtos.Parameters, - "lastUDBlock": dtos.Block -}; - -dtos.PoWSummary = { - "total": Number, - "mirror": Boolean, - "waiting": Boolean -}; - -dtos.PreviewPubkey = { - "pubkey": String -}; - -dtos.Sandbox = { - size: Number, - free: Number -}; - -dtos.IdentitySandbox = dtos.Sandbox; -dtos.CertificationSandbox = dtos.Sandbox; -dtos.MembershipSandbox = dtos.Sandbox; -dtos.TransactionSandbox = dtos.Sandbox; - -dtos.Sandboxes = { - identities: dtos.IdentitySandbox, - certifications: dtos.CertificationSandbox, - memberships: dtos.MembershipSandbox, - transactions: dtos.TransactionSandbox -}; - -dtos.LogLink = { - link: String -}; diff --git a/app/lib/streams/jsoner.js b/app/lib/streams/jsoner.js deleted file mode 100644 index e24820a3b..000000000 --- a/app/lib/streams/jsoner.js +++ /dev/null @@ -1,21 +0,0 @@ -"use strict"; -const util = require('util'); -const stream = require('stream'); - -module.exports = function () { - return new JSONer(); -}; - -function JSONer () { - - stream.Transform.call(this, { objectMode: true }); - - const that = this; - - this._write = function (entity, enc, done) { - that.push(entity.json()); - done(); - }; -} - -util.inherits(JSONer, stream.Transform); diff --git a/app/lib/streams/routes.js b/app/lib/streams/routes.js deleted file mode 100644 index 39b980d1b..000000000 --- a/app/lib/streams/routes.js +++ /dev/null @@ -1,125 +0,0 @@ -"use strict"; - -const co = require('co'); -const es = require('event-stream'); -const dtos = require('./dtos'); -const sanitize = require('./sanitize'); -const limiter = require('../system/limiter'); -const logger = require('../logger')('routes'); - -const WebSocketServer = require('ws').Server; - -module.exports = { - - bma: function(server, prefix, app, httpMethods) { - - const node = require('../../controllers/node')(server); - const blockchain = require('../../controllers/blockchain')(server); - const net = require('../../controllers/network')(server, server.conf); - const wot = require('../../controllers/wot')(server); - const transactions = require('../../controllers/transactions')(server); - const dividend = require('../../controllers/uds')(server); - httpMethods.httpGET( prefix + '/', node.summary, dtos.Summary, limiter.limitAsHighUsage()); - httpMethods.httpGET( prefix + '/node/summary', node.summary, dtos.Summary, limiter.limitAsHighUsage()); - httpMethods.httpGET( prefix + '/node/sandboxes', node.sandboxes, dtos.Sandboxes, limiter.limitAsHighUsage()); - httpMethods.httpGET( prefix + '/blockchain/parameters', blockchain.parameters, dtos.Parameters, limiter.limitAsHighUsage()); - httpMethods.httpPOST( prefix + '/blockchain/membership', blockchain.parseMembership, dtos.Membership, limiter.limitAsHighUsage()); - httpMethods.httpGET( prefix + '/blockchain/memberships/:search', blockchain.memberships, dtos.Memberships, limiter.limitAsHighUsage()); - httpMethods.httpPOST( prefix + '/blockchain/block', blockchain.parseBlock, dtos.Block, limiter.limitAsHighUsage()); - httpMethods.httpGET( prefix + '/blockchain/block/:number', blockchain.promoted, dtos.Block, limiter.limitAsHighUsage()); - httpMethods.httpGET( prefix + '/blockchain/blocks/:count/:from', blockchain.blocks, dtos.Blocks, limiter.limitAsHighUsage()); - httpMethods.httpGET( prefix + '/blockchain/current', blockchain.current, dtos.Block, limiter.limitAsHighUsage()); - httpMethods.httpGET( prefix + '/blockchain/hardship/:search', blockchain.hardship, dtos.Hardship, limiter.limitAsHighUsage()); - httpMethods.httpGET( prefix + '/blockchain/difficulties', blockchain.difficulties, dtos.Difficulties, limiter.limitAsHighUsage()); - httpMethods.httpGET( prefix + '/blockchain/with/newcomers', blockchain.with.newcomers, dtos.Stat, limiter.limitAsHighUsage()); - httpMethods.httpGET( prefix + '/blockchain/with/certs', blockchain.with.certs, dtos.Stat, limiter.limitAsHighUsage()); - httpMethods.httpGET( prefix + '/blockchain/with/joiners', blockchain.with.joiners, dtos.Stat, limiter.limitAsHighUsage()); - httpMethods.httpGET( prefix + '/blockchain/with/actives', blockchain.with.actives, dtos.Stat, limiter.limitAsHighUsage()); - httpMethods.httpGET( prefix + '/blockchain/with/leavers', blockchain.with.leavers, dtos.Stat, limiter.limitAsHighUsage()); - httpMethods.httpGET( prefix + '/blockchain/with/excluded', blockchain.with.excluded, dtos.Stat, limiter.limitAsHighUsage()); - httpMethods.httpGET( prefix + '/blockchain/with/revoked', blockchain.with.revoked, dtos.Stat, limiter.limitAsHighUsage()); - httpMethods.httpGET( prefix + '/blockchain/with/ud', blockchain.with.ud, dtos.Stat, limiter.limitAsHighUsage()); - httpMethods.httpGET( prefix + '/blockchain/with/tx', blockchain.with.tx, dtos.Stat, limiter.limitAsHighUsage()); - httpMethods.httpGET( prefix + '/blockchain/branches', blockchain.branches, dtos.Branches, limiter.limitAsHighUsage()); - httpMethods.httpGET( prefix + '/network/peering', net.peer, dtos.Peer, limiter.limitAsHighUsage()); - httpMethods.httpGET( prefix + '/network/peering/peers', net.peersGet, dtos.MerkleOfPeers, limiter.limitAsVeryHighUsage()); - httpMethods.httpPOST( prefix + '/network/peering/peers', net.peersPost, dtos.Peer, limiter.limitAsHighUsage()); - httpMethods.httpGET( prefix + '/network/peers', net.peers, dtos.Peers, limiter.limitAsHighUsage()); - httpMethods.httpPOST( prefix + '/wot/add', wot.add, dtos.Identity, limiter.limitAsHighUsage()); - httpMethods.httpPOST( prefix + '/wot/certify', wot.certify, dtos.Cert, limiter.limitAsHighUsage()); - httpMethods.httpPOST( prefix + '/wot/revoke', wot.revoke, dtos.Result, limiter.limitAsHighUsage()); - httpMethods.httpGET( prefix + '/wot/lookup/:search', wot.lookup, dtos.Lookup, limiter.limitAsHighUsage()); - httpMethods.httpGET( prefix + '/wot/members', wot.members, dtos.Members, limiter.limitAsHighUsage()); - httpMethods.httpGET( prefix + '/wot/pending', wot.pendingMemberships, dtos.MembershipList, limiter.limitAsHighUsage()); - httpMethods.httpGET( prefix + '/wot/requirements/:search', wot.requirements, dtos.Requirements, limiter.limitAsHighUsage()); - httpMethods.httpGET( prefix + '/wot/certifiers-of/:search', wot.certifiersOf, dtos.Certifications, limiter.limitAsHighUsage()); - httpMethods.httpGET( prefix + '/wot/certified-by/:search', wot.certifiedBy, dtos.Certifications, limiter.limitAsHighUsage()); - httpMethods.httpGET( prefix + '/wot/identity-of/:search', wot.identityOf, dtos.SimpleIdentity, limiter.limitAsHighUsage()); - httpMethods.httpPOST( prefix + '/tx/process', transactions.parseTransaction, dtos.Transaction, limiter.limitAsHighUsage()); - httpMethods.httpGET( prefix + '/tx/sources/:pubkey', transactions.getSources, dtos.Sources, limiter.limitAsHighUsage()); - httpMethods.httpGET( prefix + '/tx/history/:pubkey', transactions.getHistory, dtos.TxHistory, limiter.limitAsHighUsage()); - httpMethods.httpGET( prefix + '/tx/history/:pubkey/blocks/:from/:to', transactions.getHistoryBetweenBlocks, dtos.TxHistory, limiter.limitAsHighUsage()); - httpMethods.httpGET( prefix + '/tx/history/:pubkey/times/:from/:to', transactions.getHistoryBetweenTimes, dtos.TxHistory, limiter.limitAsHighUsage()); - httpMethods.httpGET( prefix + '/tx/history/:pubkey/pending', transactions.getPendingForPubkey, dtos.TxHistory, limiter.limitAsHighUsage()); - httpMethods.httpGET( prefix + '/tx/pending', transactions.getPending, dtos.TxPending, limiter.limitAsHighUsage()); - httpMethods.httpGET( prefix + '/ud/history/:pubkey', dividend.getHistory, dtos.UDHistory, limiter.limitAsHighUsage()); - httpMethods.httpGET( prefix + '/ud/history/:pubkey/blocks/:from/:to', dividend.getHistoryBetweenBlocks, dtos.UDHistory, limiter.limitAsHighUsage()); - httpMethods.httpGET( prefix + '/ud/history/:pubkey/times/:from/:to', dividend.getHistoryBetweenTimes, dtos.UDHistory, limiter.limitAsHighUsage()); - }, - - bmaWS: function(server, prefix) { - return (httpServer) => { - - let currentBlock = {}; - let wssBlock = new WebSocketServer({ - server: httpServer, - path: prefix + '/ws/block' - }); - let wssPeer = new WebSocketServer({ - server: httpServer, - path: prefix + '/ws/peer' - }); - - wssBlock.on('error', function (error) { - logger.error('Error on WS Server'); - logger.error(error); - }); - - wssBlock.on('connection', function connection(ws) { - co(function *() { - currentBlock = yield server.dal.getCurrentBlockOrNull(); - if (currentBlock) { - ws.send(JSON.stringify(sanitize(currentBlock, dtos.Block))); - } - }); - }); - - wssBlock.broadcast = (data) => wssBlock.clients.forEach((client) => { - try { - client.send(data); - } catch (e) { - logger.error('error on ws: %s', e); - } - }); - wssPeer.broadcast = (data) => wssPeer.clients.forEach((client) => client.send(data)); - - // Forward blocks & peers - server - .pipe(es.mapSync(function(data) { - try { - // Broadcast block - if (data.joiners) { - currentBlock = data; - wssBlock.broadcast(JSON.stringify(sanitize(currentBlock, dtos.Block))); - } - // Broadcast peer - if (data.endpoints) { - wssPeer.broadcast(JSON.stringify(sanitize(data, dtos.Peer))); - } - } catch (e) { - logger.error('error on ws mapSync:', e); - } - })); - }; - } -}; diff --git a/app/lib/streams/sanitize.js b/app/lib/streams/sanitize.js deleted file mode 100644 index c36b3bbc8..000000000 --- a/app/lib/streams/sanitize.js +++ /dev/null @@ -1,118 +0,0 @@ -"use strict"; - -let _ = require('underscore'); - -module.exports = function sanitize (json, contract) { - - // Tries to sanitize only if contract is given - if (contract) { - - if (Object.prototype.toString.call(contract) === "[object Array]") { - // Contract is an array - - if (Object.prototype.toString.call(json) !== "[object Array]") { - json = []; - } - - for (let i = 0, len = json.length; i < len; i++) { - json[i] = sanitize(json[i], contract[0]); - } - } else { - // Contract is an object or native type - - // Return type is either a string, a number or an object - if (typeof json != typeof contract) { - try { - // Cast value - json = contract(json); - } catch (e) { - // Cannot be casted: create empty value - json = contract(); - } - } - - let contractFields = _(contract).keys(); - let objectFields = _(json).keys(); - let toDeleteFromObj = _.difference(objectFields, contractFields); - - // Remove unwanted fields - for (let i = 0, len = toDeleteFromObj.length; i < len; i++) { - let field = toDeleteFromObj[i]; - delete json[field]; - } - - // Format wanted fields - for (let i = 0, len = contractFields.length; i < len; i++) { - let prop = contractFields[i]; - let propType = contract[prop]; - let t = ""; - if (propType.name) { - t = propType.name; - } else if (propType.length != undefined) { - t = 'Array'; - } else { - t = 'Object'; - } - // Test json member type - let tjson = typeof json[prop]; - if (~['Array', 'Object'].indexOf(t)) { - if (tjson == 'object' && json[prop] !== null) { - tjson = json[prop].length == undefined ? 'Object' : 'Array'; - } - } - // Check coherence & alter member if needed - if (!_(json[prop]).isNull() && t.toLowerCase() != tjson.toLowerCase()) { - try { - if (t == "String") { - let s = json[prop] == undefined ? '' : json[prop]; - json[prop] = String(s).valueOf(); - } - else if (t == "Number") { - let s = json[prop] == undefined ? '' : json[prop]; - json[prop] = Number(s).valueOf(); - } - else if (t == "Array") { - json[prop] = []; - } - else if (t == "Object") { - json[prop] = {}; - } - else { - json[prop] = Boolean(); - } - } catch (ex) { - if (t == "String") { - json[prop] = String(); - } - else if (t == "Number") { - json[prop] = Number(); - } - else if (t == "Array") { - json[prop] = []; - } - else if (t == "Object") { - json[prop] = {}; - } - else { - json[prop] = Boolean(); - } - } - } - // Arrays - if (t == 'Array') { - let subt = propType[0]; - for (let j = 0, len2 = json[prop].length; j < len2; j++) { - if (!(subt == "String" || subt == "Number")) { - json[prop][j] = sanitize(json[prop][j], subt); - } - } - } - // Recursivity - if (t == 'Object' && json[prop] !== null) { - json[prop] = sanitize(json[prop], contract[prop]); - } - } - } - } - return json; -}; diff --git a/app/lib/system/limiter.js b/app/lib/system/limiter.js deleted file mode 100644 index 6fe411e35..000000000 --- a/app/lib/system/limiter.js +++ /dev/null @@ -1,114 +0,0 @@ -"use strict"; - -const A_MINUTE = 60 * 1000; -const A_SECOND = 1000; - -const Limiter = { - - /** - * Tells wether the quota is reached at current time or not. - */ - canAnswerNow() { - // Rapid decision first. - // Note: we suppose limitPerSecond < limitPerMinute - if (this.reqsSecLen < this.limitPerSecond && this.reqsMinLen < this.limitPerMinute) { - return true; - } - this.updateRequests(); - return this.reqsSecLen < this.limitPerSecond && this.reqsMinLen < this.limitPerMinute; - }, - - /** - * Filter the current requests stock to remove the too old ones - */ - updateRequests() { - // Clean current requests stock and make the test again - const now = Date.now(); - let i = 0, reqs = this.reqsMin, len = this.reqsMinLen; - // Reinit specific indicators - this.reqsSec = []; - this.reqsMin = []; - while (i < len) { - const duration = now - reqs[i]; - if (duration < A_SECOND) { - this.reqsSec.push(reqs[i]); - } - if (duration < A_MINUTE) { - this.reqsMin.push(reqs[i]); - } - i++; - } - this.reqsSecLen = this.reqsSec.length; - this.reqsMinLen = this.reqsMin.length; - }, - - processRequest() { - const now = Date.now(); - this.reqsSec.push(now); - this.reqsSecLen++; - this.reqsMin.push(now); - this.reqsMinLen++; - } -}; - -let HIGH_USAGE_STRATEGY = Object.create(Limiter); -HIGH_USAGE_STRATEGY.limitPerSecond = 10; -HIGH_USAGE_STRATEGY.limitPerMinute = 300; - -let VERY_HIGH_USAGE_STRATEGY = Object.create(Limiter); -VERY_HIGH_USAGE_STRATEGY.limitPerSecond = 30; -VERY_HIGH_USAGE_STRATEGY.limitPerMinute = 30 * 60; // Limit is only per second - -let TEST_STRATEGY = Object.create(Limiter); -TEST_STRATEGY.limitPerSecond = 5; -TEST_STRATEGY.limitPerMinute = 6; - -let NO_LIMIT_STRATEGY = Object.create(Limiter); -NO_LIMIT_STRATEGY.limitPerSecond = 1000000; -NO_LIMIT_STRATEGY.limitPerMinute = 1000000 * 60; - -let disableLimits = false; - -module.exports = { - - limitAsHighUsage() { - return disableLimits ? createObject(NO_LIMIT_STRATEGY) : createObject(HIGH_USAGE_STRATEGY); - }, - - limitAsVeryHighUsage() { - return disableLimits ? createObject(NO_LIMIT_STRATEGY) : createObject(VERY_HIGH_USAGE_STRATEGY); - }, - - limitAsUnlimited() { - return createObject(NO_LIMIT_STRATEGY); - }, - - limitAsTest() { - return disableLimits ? createObject(NO_LIMIT_STRATEGY) : createObject(TEST_STRATEGY); - }, - - noLimit() { - disableLimits = true; - }, - - withLimit() { - disableLimits = false; - } -}; - -function createObject(strategy) { - - const obj = Object.create(strategy); - - // Stock of request times - obj.reqsSec = []; - - // The length of reqs. - // It is better to have it instead of calling reqs.length - obj.reqsSecLen = 0; - - // Minute specific - obj.reqsMin = []; - obj.reqsMinLen = 0; - return obj; -} diff --git a/app/lib/system/network.js b/app/lib/system/network.js index a11a911e7..b14be0f28 100644 --- a/app/lib/system/network.js +++ b/app/lib/system/network.js @@ -2,29 +2,16 @@ const co = require('co'); const os = require('os'); -const Q = require('q'); const _ = require('underscore'); -const ddos = require('ddos'); -const http = require('http'); -const express = require('express'); -const morgan = require('morgan'); -const errorhandler = require('errorhandler'); -const bodyParser = require('body-parser'); -const cors = require('cors'); -const fileUpload = require('express-fileupload'); -const constants = require('../constants'); -const sanitize = require('../streams/sanitize'); const logger = require('../logger')('network'); -const bmapiMethods = require('../../modules/bmapi').duniter.methods; +const bmapiMethods = require('duniter-bma').duniter.methods; module.exports = { getEndpoint: getEndpoint, getBestLocalIPv4: bmapiMethods.getBestLocalIPv4, getBestLocalIPv6: bmapiMethods.getBestLocalIPv6, - getLANIPv4: () => getLAN('IPv4'), - getLANIPv6: () => getLAN('IPv6'), listInterfaces: bmapiMethods.listInterfaces, @@ -32,225 +19,9 @@ module.exports = { getRandomPort: bmapiMethods.getRandomPort, - createServersAndListen: (name, interfaces, httpLogs, staticPath, routingCallback, listenWebSocket, enableFileUpload) => co(function *() { - - const app = express(); - - // all environments - if (httpLogs) { - app.use(morgan('\x1b[90m:remote-addr - :method :url HTTP/:http-version :status :res[content-length] - :response-time ms\x1b[0m', { - stream: { - write: function(message){ - message && logger.trace(message.replace(/\n$/,'')); - } - } - })); - } - - // DDOS protection - const whitelist = interfaces.map(i => i.ip); - if (whitelist.indexOf('127.0.0.1') === -1) { - whitelist.push('127.0.0.1'); - } - const ddosInstance = new ddos({ whitelist, silentStart: true }); - app.use(ddosInstance.express); - - // CORS for **any** HTTP request - app.use(cors()); - - if (enableFileUpload) { - // File upload for backup API - app.use(fileUpload()); - } - - app.use(bodyParser.urlencoded({ - extended: true - })); - app.use(bodyParser.json()); - - // development only - if (app.get('env') == 'development') { - app.use(errorhandler()); - } - - routingCallback(app, { - httpGET: (uri, promiseFunc, dtoContract, limiter) => handleRequest(app.get.bind(app), uri, promiseFunc, dtoContract, limiter), - httpPOST: (uri, promiseFunc, dtoContract, limiter) => handleRequest(app.post.bind(app), uri, promiseFunc, dtoContract, limiter), - httpGETFile: (uri, promiseFunc, dtoContract, limiter) => handleFileRequest(app.get.bind(app), uri, promiseFunc, limiter) - }); - - if (staticPath) { - app.use(express.static(staticPath)); - } - - const httpServers = interfaces.map(() => { - const httpServer = http.createServer(app); - const sockets = {}; - let nextSocketId = 0; - httpServer.on('connection', (socket) => { - const socketId = nextSocketId++; - sockets[socketId] = socket; - //logger.debug('socket %s opened', socketId); - - socket.on('close', () => { - //logger.debug('socket %s closed', socketId); - delete sockets[socketId]; - }); - }); - httpServer.on('error', (err) => { - httpServer.errorPropagates(err); - }); - listenWebSocket && listenWebSocket(httpServer); - return { - http: httpServer, - closeSockets: () => { - _.keys(sockets).map((socketId) => { - sockets[socketId].destroy(); - }); - } - }; - }); - - // May be removed when using Node 5.x where httpServer.listening boolean exists - const listenings = interfaces.map(() => false); - - if (httpServers.length == 0){ - throw 'Duniter does not have any interface to listen to.'; - } - - // Return API - return { - - getDDOS: () => ddosInstance, - - closeConnections: () => co(function *() { - for (let i = 0, len = httpServers.length; i < len; i++) { - const httpServer = httpServers[i].http; - const isListening = listenings[i]; - if (isListening) { - listenings[i] = false; - logger.info(name + ' stop listening'); - yield Q.Promise((resolve, reject) => { - httpServer.errorPropagates((err) => { - reject(err); - }); - httpServers[i].closeSockets(); - httpServer.close((err) => { - err && logger.error(err.stack || err); - resolve(); - }); - }); - } - } - return []; - }), - - openConnections: () => co(function *() { - for (let i = 0, len = httpServers.length; i < len; i++) { - const httpServer = httpServers[i].http; - const isListening = listenings[i]; - if (!isListening) { - const netInterface = interfaces[i].ip; - const port = interfaces[i].port; - try { - yield Q.Promise((resolve, reject) => { - // Weird the need of such a hack to catch an exception... - httpServer.errorPropagates = function(err) { - reject(err); - }; - //httpServer.on('listening', resolve.bind(this, httpServer)); - httpServer.listen(port, netInterface, (err) => { - if (err) return reject(err); - listenings[i] = true; - resolve(httpServer); - }); - }); - logger.info(name + ' listening on http://' + (netInterface.match(/:/) ? '[' + netInterface + ']' : netInterface) + ':' + port); - } catch (e) { - logger.warn('Could NOT listen to http://' + netInterface + ':' + port); - logger.warn(e); - } - } - } - return []; - }) - }; - }) -}; - -const handleRequest = (method, uri, promiseFunc, dtoContract, theLimiter) => { - const limiter = theLimiter || require('../system/limiter').limitAsUnlimited(); - method(uri, function(req, res) { - res.set('Access-Control-Allow-Origin', '*'); - res.type('application/json'); - co(function *() { - try { - if (!limiter.canAnswerNow()) { - throw constants.ERRORS.HTTP_LIMITATION; - } - limiter.processRequest(); - let result = yield promiseFunc(req); - // Ensure of the answer format - result = sanitize(result, dtoContract); - // HTTP answer - res.status(200).send(JSON.stringify(result, null, " ")); - } catch (e) { - let error = getResultingError(e); - // HTTP error - res.status(error.httpCode).send(JSON.stringify(error.uerr, null, " ")); - } - }); - }); -}; - -const handleFileRequest = (method, uri, promiseFunc, theLimiter) => { - const limiter = theLimiter || require('../system/limiter').limitAsUnlimited(); - method(uri, function(req, res) { - res.set('Access-Control-Allow-Origin', '*'); - co(function *() { - try { - if (!limiter.canAnswerNow()) { - throw constants.ERRORS.HTTP_LIMITATION; - } - limiter.processRequest(); - let fileStream = yield promiseFunc(req); - // HTTP answer - fileStream.pipe(res); - } catch (e) { - let error = getResultingError(e); - // HTTP error - res.status(error.httpCode).send(JSON.stringify(error.uerr, null, " ")); - throw e - } - }); - }); + createServersAndListen: require('duniter-bma').duniter.methods.createServersAndListen }; -function getResultingError(e) { - // Default is 500 unknown error - let error = constants.ERRORS.UNKNOWN; - if (e) { - // Print eventual stack trace - typeof e == 'string' && logger.error(e); - e.stack && logger.error(e.stack); - e.message && logger.warn(e.message); - // BusinessException - if (e.uerr) { - error = e; - } else { - const cp = constants.ERRORS.UNHANDLED; - error = { - httpCode: cp.httpCode, - uerr: { - ucode: cp.uerr.ucode, - message: e.message || e || error.uerr.message - } - }; - } - } - return error; -} - function getEndpoint(theConf) { let endpoint = 'BASIC_MERKLED_API'; if (theConf.remotehost) { @@ -267,25 +38,3 @@ function getEndpoint(theConf) { } return endpoint; } - -function getLAN(family) { - let netInterfaces = os.networkInterfaces(); - let keys = _.keys(netInterfaces); - let res = []; - for (const name of keys) { - let addresses = netInterfaces[name]; - for (const addr of addresses) { - if ((addr.family == "IPv4" && family == "IPv4" - && addr.address != "127.0.0.1" && addr.address != "lo" && addr.address != "localhost") - || (addr.family == "IPv6" && family == "IPv6" - && addr.address != "::1" && addr.address != "lo" && addr.address != "localhost")) - { - res.push({ - name: name, - value: addr.address - }); - } - } - } - return res; -} diff --git a/app/lib/system/upnp.js b/app/lib/system/upnp.js deleted file mode 100644 index fda7375ee..000000000 --- a/app/lib/system/upnp.js +++ /dev/null @@ -1,66 +0,0 @@ -const upnp = require('nnupnp'); -const async = require('async'); -const constants = require('../constants'); -const logger = require('../logger')('upnp'); -const co = require('co'); -const Q = require('q'); - -module.exports = function (localPort, remotePort) { - "use strict"; - return co(function *() { - logger.info('UPnP: configuring...'); - return co(function *() { - try { - yield openPort(localPort, remotePort); - } catch (e) { - const client = upnp.createClient(); - try { - yield Q.nbind(client.externalIp, client)(); - } catch (err) { - if (err && err.message == 'timeout') { - throw 'No UPnP gateway found: your node won\'t be reachable from the Internet. Use --noupnp option to avoid this message.' - } - throw err; - } finally { - client.close(); - } - } - let interval, upnpService = { - openPort: () => { - return openPort(localPort, remotePort); - }, - startRegular: () => { - upnpService.stopRegular(); - // Update UPnP IGD every INTERVAL seconds - interval = setInterval(async.apply(openPort, localPort, remotePort), 1000 * constants.NETWORK.UPNP.INTERVAL); - }, - stopRegular: () => { - if (interval) { - clearInterval(interval); - } - } - }; - return upnpService; - }); - }); -}; - -function openPort (localPort, remotePort) { - "use strict"; - return Q.Promise(function(resolve, reject){ - logger.trace('UPnP: mapping external port %s to local %s...', remotePort, localPort); - const client = upnp.createClient(); - client.portMapping({ - 'public': parseInt(remotePort), - 'private': parseInt(localPort), - 'ttl': constants.NETWORK.UPNP.TTL - }, function(err) { - client.close(); - if (err) { - logger.warn(err); - return reject(err); - } - resolve(); - }); - }); -} diff --git a/app/modules/bmapi.js b/app/modules/bmapi.js deleted file mode 100644 index f245b4e4e..000000000 --- a/app/modules/bmapi.js +++ /dev/null @@ -1,564 +0,0 @@ -"use strict"; - -const Q = require('q'); -const co = require('co'); -const os = require('os'); -const async = require('async'); -const _ = require('underscore'); -const util = require('util'); -const stream = require('stream'); -const constants = require('../lib/constants'); -const upnp = require('../lib/system/upnp'); -const inquirer = require('inquirer'); - -module.exports = { - duniter: { - - cliOptions: [ - { value: '--upnp', desc: 'Use UPnP to open remote port.' }, - { value: '--noupnp', desc: 'Do not use UPnP to open remote port.' } - ], - - wizard: { - - 'network': (conf, program, logger) => co(function*() { - yield Q.nbind(networkConfiguration, null, conf, logger)(); - }), - - 'network-reconfigure': (conf, program, logger) => co(function*() { - yield Q.nbind(networkReconfiguration, null, conf, logger, program.autoconf, program.noupnp)(); - }) - }, - - config: { - - onLoading: (conf, program, logger) => co(function*(){ - - // Network autoconf - const autoconfNet = program.autoconf - || !(conf.ipv4 || conf.ipv6) - || !(conf.remoteipv4 || conf.remoteipv6 || conf.remotehost) - || !(conf.port && conf.remoteport); - if (autoconfNet) { - yield Q.nbind(networkReconfiguration, null)(conf, autoconfNet, logger, program.noupnp); - } - - // Default value - if (conf.upnp === undefined || conf.upnp === null) { - conf.upnp = true; // Defaults to true - } - - // UPnP - if (program.noupnp === true) { - conf.upnp = false; - } - if (program.upnp === true) { - conf.upnp = true; - } - }) - }, - - service: { - input: (server, conf, logger) => new BMAPI(server, conf, logger) - }, - - methods: { - upnpConf, listInterfaces, getBestLocalIPv4, getBestLocalIPv6, getRandomPort - } - } -} - -function BMAPI(server, conf, logger) { - - // Public http interface - let bmapi; - // UPnP API - let upnpAPI; - - stream.Transform.call(this, { objectMode: true }); - - this.startService = () => co(function*() { - const bma = require('../lib/streams/bma'); - bmapi = yield bma(server, null, conf.httplogs); - yield bmapi.openConnections(); - - /*************** - * UPnP - **************/ - if (upnpAPI) { - upnpAPI.stopRegular(); - } - if (conf.upnp) { - try { - upnpAPI = yield upnp(conf.port, conf.remoteport); - upnpAPI.startRegular(); - } catch (e) { - logger.warn(e); - } - } - }); - - this.stopService = () => co(function*() { - if (bmapi) { - yield bmapi.closeConnections(); - } - if (upnpAPI) { - upnpAPI.stopRegular(); - } - }); -} - - - -function networkReconfiguration(conf, autoconf, logger, noupnp, done) { - async.waterfall([ - upnpResolve.bind(this, noupnp, logger), - function(upnpSuccess, upnpConf, next) { - - // Default values - conf.port = conf.port || constants.NETWORK.DEFAULT_PORT; - conf.remoteport = conf.remoteport || constants.NETWORK.DEFAULT_PORT; - - var localOperations = getLocalNetworkOperations(conf, autoconf); - var remoteOpertions = getRemoteNetworkOperations(conf, upnpConf.remoteipv4, upnpConf.remoteipv6, autoconf); - var dnsOperations = getHostnameOperations(conf, logger, autoconf); - var useUPnPOperations = getUseUPnPOperations(conf, logger, autoconf); - - if (upnpSuccess) { - _.extend(conf, upnpConf); - var local = [conf.ipv4, conf.port].join(':'); - var remote = [conf.remoteipv4, conf.remoteport].join(':'); - if (autoconf) { - conf.ipv6 = conf.remoteipv6 = getBestLocalIPv6(); - logger.info('IPv6: %s', conf.ipv6 || ""); - logger.info('Local IPv4: %s', local); - logger.info('Remote IPv4: %s', remote); - // Use proposed local + remote with UPnP binding - return async.waterfall(useUPnPOperations - .concat(dnsOperations), next); - } - choose("UPnP is available: duniter will be bound: \n from " + local + "\n to " + remote + "\nKeep this configuration?", true, - function () { - // Yes: not network changes - conf.ipv6 = conf.remoteipv6 = getBestLocalIPv6(); - async.waterfall(useUPnPOperations - .concat(dnsOperations), next); - }, - function () { - // No: want to change - async.waterfall( - localOperations - .concat(remoteOpertions) - .concat(useUPnPOperations) - .concat(dnsOperations), next); - }); - } else { - conf.upnp = false; - if (autoconf) { - // Yes: local configuration = remote configuration - return async.waterfall( - localOperations - .concat(getHostnameOperations(conf, logger, autoconf)) - .concat([function (confDone) { - conf.remoteipv4 = conf.ipv4; - conf.remoteipv6 = conf.ipv6; - conf.remoteport = conf.port; - logger.info('Local & Remote IPv4: %s', [conf.ipv4, conf.port].join(':')); - logger.info('Local & Remote IPv6: %s', [conf.ipv6, conf.port].join(':')); - confDone(); - }]), next); - } - choose("UPnP is *not* available: is this a public server (like a VPS)?", true, - function () { - // Yes: local configuration = remote configuration - async.waterfall( - localOperations - .concat(getHostnameOperations(conf, logger)) - .concat([function(confDone) { - conf.remoteipv4 = conf.ipv4; - conf.remoteipv6 = conf.ipv6; - conf.remoteport = conf.port; - confDone(); - }]), next); - }, - function () { - // No: must give all details - async.waterfall( - localOperations - .concat(remoteOpertions) - .concat(dnsOperations), next); - }); - } - } - ], done); -} - - -function upnpResolve(noupnp, logger, done) { - return co(function *() { - try { - let conf = yield upnpConf(noupnp, logger); - done(null, true, conf); - } catch (err) { - done(null, false, {}); - } - }); -} - -function networkConfiguration(conf, logger, done) { - async.waterfall([ - upnpResolve.bind(this, !conf.upnp, logger), - function(upnpSuccess, upnpConf, next) { - - var operations = getLocalNetworkOperations(conf) - .concat(getRemoteNetworkOperations(conf, upnpConf.remoteipv4, upnpConf.remoteipv6)); - - if (upnpSuccess) { - operations = operations.concat(getUseUPnPOperations(conf, logger)); - } - - async.waterfall(operations.concat(getHostnameOperations(conf, logger, false)), next); - } - ], done); -} - -function getLocalNetworkOperations(conf, autoconf) { - return [ - function (next){ - var osInterfaces = listInterfaces(); - var interfaces = [{ name: "None", value: null }]; - osInterfaces.forEach(function(netInterface){ - var addresses = netInterface.addresses; - var filtered = _(addresses).where({family: 'IPv4'}); - filtered.forEach(function(addr){ - interfaces.push({ - name: [netInterface.name, addr.address].join(' '), - value: addr.address - }); - }); - }); - if (autoconf) { - conf.ipv4 = getBestLocalIPv4(); - return next(); - } - inquirer.prompt([{ - type: "list", - name: "ipv4", - message: "IPv4 interface", - default: conf.ipv4, - choices: interfaces - }], function (answers) { - conf.ipv4 = answers.ipv4; - next(); - }); - }, - function (next){ - var osInterfaces = listInterfaces(); - var interfaces = [{ name: "None", value: null }]; - osInterfaces.forEach(function(netInterface){ - var addresses = netInterface.addresses; - var filtered = _(addresses).where({ family: 'IPv6' }); - filtered.forEach(function(addr){ - var address = addr.address - if (addr.scopeid) - address += "%" + netInterface.name - let nameSuffix = ""; - if (addr.scopeid == 0 && !addr.internal) { - nameSuffix = " (Global)"; - } - interfaces.push({ - name: [netInterface.name, address, nameSuffix].join(' '), - internal: addr.internal, - scopeid: addr.scopeid, - value: address - }); - }); - }); - interfaces.sort((addr1, addr2) => { - if (addr1.value === null) return -1; - if (addr1.internal && !addr2.internal) return 1; - if (addr1.scopeid && !addr2.scopeid) return 1; - return 0; - }); - if (autoconf || !conf.ipv6) { - conf.ipv6 = conf.remoteipv6 = getBestLocalIPv6(); - } - if (autoconf) { - return next(); - } - inquirer.prompt([{ - type: "list", - name: "ipv6", - message: "IPv6 interface", - default: conf.ipv6, - choices: interfaces - }], function (answers) { - conf.ipv6 = conf.remoteipv6 = answers.ipv6; - next(); - }); - }, - autoconf ? (done) => { - conf.port = getRandomPort(conf); - done(); - } : async.apply(simpleInteger, "Port", "port", conf) - ]; -} - -function getRemoteNetworkOperations(conf, remoteipv4) { - return [ - function (next){ - if (!conf.ipv4) { - conf.remoteipv4 = null; - return next(null, {}); - } - var choices = [{ name: "None", value: null }]; - // Local interfaces - var osInterfaces = listInterfaces(); - osInterfaces.forEach(function(netInterface){ - var addresses = netInterface.addresses; - var filtered = _(addresses).where({family: 'IPv4'}); - filtered.forEach(function(addr){ - choices.push({ - name: [netInterface.name, addr.address].join(' '), - value: addr.address - }); - }); - }); - if (conf.remoteipv4) { - choices.push({ name: conf.remoteipv4, value: conf.remoteipv4 }); - } - if (remoteipv4 && remoteipv4 != conf.remoteipv4) { - choices.push({ name: remoteipv4, value: remoteipv4 }); - } - choices.push({ name: "Enter new one", value: "new" }); - inquirer.prompt([{ - type: "list", - name: "remoteipv4", - message: "Remote IPv4", - default: conf.remoteipv4 || conf.ipv4 || null, - choices: choices, - validate: function (input) { - return input && input.toString().match(constants.IPV4_REGEXP) ? true : false; - } - }], function (answers) { - if (answers.remoteipv4 == "new") { - inquirer.prompt([{ - type: "input", - name: "remoteipv4", - message: "Remote IPv4", - default: conf.remoteipv4 || conf.ipv4, - validate: function (input) { - return input && input.toString().match(constants.IPV4_REGEXP) ? true : false; - } - }], async.apply(next, null)); - } else { - next(null, answers); - } - }); - }, - function (answers, next){ - conf.remoteipv4 = answers.remoteipv4; - return co(function*() { - try { - if (conf.remoteipv4 || conf.remotehost) { - yield new Promise((resolve, reject) => { - const getPort = async.apply(simpleInteger, "Remote port", "remoteport", conf); - getPort((err) => { - if (err) return reject(err); - resolve(); - }); - }); - } else if (conf.remoteipv6) { - conf.remoteport = conf.port; - } - next(); - } catch (e) { - next(e); - } - }); - } - ]; -} - -function getHostnameOperations(conf, logger, autoconf) { - return [function(next) { - if (!conf.ipv4) { - conf.remotehost = null; - return next(); - } - if (autoconf) { - logger.info('DNS: %s', conf.remotehost || 'No'); - return next(); - } - choose("Does this server has a DNS name?", !!conf.remotehost, - function() { - // Yes - simpleValue("DNS name:", "remotehost", "", conf, function(){ return true; }, next); - }, - function() { - conf.remotehost = null; - next(); - }); - }]; -} - -function getUseUPnPOperations(conf, logger, autoconf) { - return [function(next) { - if (!conf.ipv4) { - conf.upnp = false; - return next(); - } - if (autoconf) { - logger.info('UPnP: %s', 'Yes'); - conf.upnp = true; - return next(); - } - choose("UPnP is available: use automatic port mapping? (easier)", conf.upnp, - function() { - conf.upnp = true; - next(); - }, - function() { - conf.upnp = false; - next(); - }); - }]; -} - -function choose (question, defaultValue, ifOK, ifNotOK) { - inquirer.prompt([{ - type: "confirm", - name: "q", - message: question, - default: defaultValue - }], function (answer) { - answer.q ? ifOK() : ifNotOK(); - }); -} - -function upnpConf (noupnp, logger) { - return co(function *() { - const conf = {}; - const client = require('nnupnp').createClient(); - // Look for 2 random ports - const privatePort = getRandomPort(conf); - const publicPort = privatePort; - logger.info('Checking UPnP features...'); - if (noupnp) { - throw Error('No UPnP'); - } - const publicIP = yield Q.nbind(client.externalIp, client)(); - yield Q.nbind(client.portMapping, client)({ - public: publicPort, - private: privatePort, - ttl: 120 - }); - const privateIP = yield Q.Promise((resolve, reject) => { - client.findGateway((err, res, localIP) => { - if (err) return reject(err); - resolve(localIP); - }); - }); - conf.remoteipv4 = publicIP.match(constants.IPV4_REGEXP) ? publicIP : null; - conf.remoteport = publicPort; - conf.port = privatePort; - conf.ipv4 = privateIP.match(constants.IPV4_REGEXP) ? privateIP : null; - return conf; - }); -} - -function simpleValue (question, property, defaultValue, conf, validation, done) { - inquirer.prompt([{ - type: "input", - name: property, - message: question, - default: conf[property], - validate: validation - }], function (answers) { - conf[property] = answers[property]; - done(); - }); -} - -function simpleInteger (question, property, conf, done) { - simpleValue(question, property, conf[property], conf, function (input) { - return input && input.toString().match(/^[0-9]+$/) ? true : false; - }, done); -} - -function listInterfaces() { - const netInterfaces = os.networkInterfaces(); - const keys = _.keys(netInterfaces); - const res = []; - for (const name of keys) { - res.push({ - name: name, - addresses: netInterfaces[name] - }); - } - return res; -} - -function getBestLocalIPv4() { - return getBestLocal('IPv4'); -} - -function getBestLocalIPv6() { - const osInterfaces = listInterfaces(); - for (let netInterface of osInterfaces) { - const addresses = netInterface.addresses; - const filtered = _(addresses).where({family: 'IPv6', scopeid: 0, internal: false }); - const filtered2 = _(filtered).filter((address) => !address.address.match(/^fe80/) && !address.address.match(/^::1/)); - if (filtered2[0]) { - return filtered2[0].address; - } - } - return null; -} - -function getBestLocal(family) { - let netInterfaces = os.networkInterfaces(); - let keys = _.keys(netInterfaces); - let res = []; - for (const name of keys) { - let addresses = netInterfaces[name]; - for (const addr of addresses) { - if (!family || addr.family == family) { - res.push({ - name: name, - value: addr.address - }); - } - } - } - const interfacePriorityRegCatcher = [ - /^tun\d/, - /^enp\ds\d/, - /^enp\ds\df\d/, - /^eth\d/, - /^Ethernet/, - /^wlp\ds\d/, - /^wlan\d/, - /^Wi-Fi/, - /^lo/, - /^Loopback/, - /^None/ - ]; - const best = _.sortBy(res, function(entry) { - for(let priority in interfacePriorityRegCatcher){ - if (entry.name.match(interfacePriorityRegCatcher[priority])) return priority; - } - return interfacePriorityRegCatcher.length; - })[0]; - return (best && best.value) || ""; -} - -function getRandomPort(conf) { - if (conf && conf.remoteport) { - return conf.remoteport; - } else { - return ~~(Math.random() * (65536 - constants.NETWORK.PORT.START)) + constants.NETWORK.PORT.START; - } -} - -util.inherits(BMAPI, stream.Transform); diff --git a/doc/HTTP_API.md b/doc/HTTP_API.md deleted file mode 100644 index 6cd7f026c..000000000 --- a/doc/HTTP_API.md +++ /dev/null @@ -1,1812 +0,0 @@ -# Duniter HTTP API - -## Contents - -* [Contents](#contents) -* [Overview](#overview) -* [Merkle URLs](#merkle-urls) -* [API](#api) - * [node/](#node) - * [summary](#nodesummary) - * [wot/](#wot) - * [add](#wotadd) - * [certify](#wotcertify) - * [revoke](#wotrevoke) - * [lookup/[search]](#wotlookupsearch) - * [requirements/[PUBKEY]](#wotrequirementspubkey) - * [certifiers-of/[search]](#wotcertifiers-ofsearch) - * [certified-by/[search]](#wotcertified-bysearch) - * [blockchain/](#blockchain) - * [parameters](#blockchainparameters) - * [membership](#blockchainmembership) - * [memberships/[search]](#blockchainmembershipssearch) - * [block](#blockchainblock) - * [block/[number]](#blockchainblocknumber) - * [blocks/[count]/[from]](#blockchainblockscountfrom) - * [current](#blockchaincurrent) - * [hardship/[PUBKEY]](#blockchainhardshippubkey) - * [difficulties](#blockchaindifficulties) - * [with/](#blockchainwith) - * [newcomers](#blockchainwithnewcomers) - * [certs](#blockchainwithcerts) - * [actives](#blockchainwithactives) - * [leavers](#blockchainwithleavers) - * [excluded](#blockchainwithexcluded) - * [ud](#blockchainwithud) - * [tx](#blockchainwithtx) - * [branches](#blockchainbranches) - * [network/](#network) - * [peers](#networkpeers) - * [peering](#networkpeering) - * [peering/peers (GET)](#networkpeeringpeers-get) - * [peering/peers (POST)](#networkpeeringpeers-post) - * [tx/](#tx) - * [process](#txprocess) - * [sources/[pubkey]](#txsourcespubkey) - * [history/[pubkey]](#txhistorypubkey) - * [history/[pubkey]/blocks/[from]/[to]](#txhistorypubkeyblocksfromto) - * [history/[pubkey]/times/[from]/[to]](#txhistorypubkeytimesfromto) - * [ud/](#ud) - * [history/[pubkey]](#udhistorypubkey) - * [ws/](#ws) - * [block](#wsblock) - * [peer](#wspeer) - -## Overview - -Data is made accessible through an HTTP API mainly inspired from [OpenUDC_exchange_formats draft](https://github.com/Open-UDC/open-udc/blob/master/docs/OpenUDC_exchange_formats.draft.txt), and has been adapted to fit Duniter specificities. - - http[s]://Node[:port]/... - |-- wot/ - | |-- add - | |-- certify - | |-- revoke - | |-- requirements/[pubkey] - | |-- certifiers-of/[uid|pubkey] - | |-- certified-by/[uid|pubkey] - | |-- members - | `-- lookup - |-- blockchain/ - | |-- parameters - | |-- membership - | |-- with/ - | |-- newcomers - | |-- certs - | |-- joiners - | |-- actives - | |-- leavers - | |-- excluded - | |-- ud - | `-- tx - | |-- hardship - | | `-- [PUBKEY] - | |-- block - | | `-- [NUMBER] - | |-- difficulties - | `-- current - |-- network/ - | |-- peers - | `-- peering - | `-- peers - |-- tx/ - | |-- process - | |-- sources - | `-- history - |-- ud/ - | `-- history - `-- ws/ - |-- block - `-- peer - -## Merkle URLs - -Merkle URL is a special kind of URL applicable for resources: - -* `network/peering/peers (GET)` - -Such kind of URL returns Merkle tree hashes informations. In Duniter, Merkle trees are an easy way to detect unsynced data and where the differences come from. For example, `network/peering/peers` is a Merkle tree whose leaves are peers' key fingerprint sorted ascending way. Thus, if any new peer is added, a branch of the tree will see its hash modified and propagated to the root hash. Change is then easy to detect. - -For commodity issues, this URL uses query parameters to retrieve partial data of the tree, as most of the time all the data is not required. Duniter Merkle tree has a determined number of parent nodes (given a number of leaves), which allows to ask only for interval of them. - -Here is an example of members Merkle tree with 5 members (taken from [Tree Hash EXchange format (THEX)](http://web.archive.org/web/20080316033726/http://www.open-content.net/specs/draft-jchapweske-thex-02.html)): - - ROOT=H(H+E) - / \ - / \ - H=H(F+G) E - / \ \ - / \ \ - F=H(A+B) G=H(C+D) E - / \ / \ \ - / \ / \ \ - A B C D E - - - Note: H() is some hash function - -Where A,B,C,D,E are already hashed data. - -With such a tree structure, Duniter consider the tree has exactly 6 nodes: `[ROOT,H,E,F,G,E]`. Nodes are just an array, and for a Lambda Server LS1, it is easy to ask for the values of another server LS2 for level 1 (`H` and `E`, the second level): it requires nodes interval `[1;2]`. - -Hence it is quite easy for anyone who wants to check if a `Z` member joined the Duniter community as it would alter the `E` branch of the tree: - - ROOT'=H(H+E') - / \ - / \ - H=H(F+G) E' - / \ \ - / \ \ - F=H(A+B) G=H(C+D) E'=H(E+Z) - / \ / \ / \ - / \ / \ / \ - A B C D E Z - -`ROOT` changed to `ROOT'`, `E` to `E'`, but `H` did not. The whole `E'` branch should be updated with the proper new data. - -For that purpose, Merkle URL defines different parameters and results: - -**Parameters** - -Parameter | Description ---------- | ----------- -`leaves` | Defines wether or not leaves hashes should be returned too. Defaults to `false`. -`leaf` | Hash of a leaf whose content should be returned. Ignore `leaves` parameter. - -**Returns** - -Merkle URL result with `leaves=false`. -```json -{ - "depth": 3, - "nodesCount": 6, - "leavesCount": 5, - "root": "6513D6A1582DAE614D8A3B364BF3C64C513D236B" -} -``` - -Merkle URL result with `leaves=true`. -```json -{ - "depth": 3, - "nodesCount": 6, - "leavesCount": 5, - "root": "6513D6A1582DAE614D8A3B364BF3C64C513D236B", - "leaves": [ - "32096C2E0EFF33D844EE6D675407ACE18289357D", - "50C9E8D5FC98727B4BBC93CF5D64A68DB647F04F", - "6DCD4CE23D88E2EE9568BA546C007C63D9131C1B", - "AE4F281DF5A5D0FF3CAD6371F76D5C29B6D953EC", - "E0184ADEDF913B076626646D3F52C3B49C39AD6D" - ] -} -``` - -Merkle URL result with `leaf=AE4F281DF5A5D0FF3CAD6371F76D5C29B6D953EC`. -```json -{ - "depth": 3, - "nodesCount": 6, - "leavesCount": 5, - "root": "6513D6A1582DAE614D8A3B364BF3C64C513D236B", - "leaf": { - "hash": "AE4F281DF5A5D0FF3CAD6371F76D5C29B6D953EC", - "value": // JSON value (object, string, int, ...) - } -} -``` - -### Duniter Merkle trees leaves - -Each tree manages different data, and has a different goal. Hence, each tree has its own rules on how are generated and sorted tree leaves. -Here is a summup of such rules: - - -Merkle URL | Leaf | Sort ----------------------- | --------------------------| ------------- -`network/peers (GET)` | Hash of the peers' pubkey | By hash string sort, ascending. - -#### Unicity - -It has to be noted that **possible conflict exists** for leaves, as every leaf is hash, but is rather unlikely. - -## API - -### node/* - -#### `node/summary` -**Goal** - -GET technical informations about this peer. - -**Parameters** - -*None*. - -**Returns** - -Technical informations about the node. -```json -{ - "duniter": { - "software": "duniter", - "version": "0.10.3", - "forkWindowSize": 10 - } -} -``` - -### wot/* - -#### `wot/add` - - -**Goal** - -POST [Identity](./Protocol.md#identity) data. - -**Parameters** - -Name | Value | Method ----- | ----- | ------ -`identity` | The raw identity. | POST - -**Returns** - -The available validated data for this public key. -```json -{ - "pubkey": "HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY", - "uids": [ - { - "uid": "udid2;c;TOCQUEVILLE;FRANCOIS-XAVIER-ROBE;1989-07-14;e+48.84+002.30;0;", - "meta": { - "timestamp": "44-76522E321B3380B058DB6D9E66121705EEA63610869A7C5B3E701CF6AF2D55A8" - }, - "self": "J3G9oM5AKYZNLAB5Wx499w61NuUoS57JVccTShUbGpCMjCqj9yXXqNq7dyZpDWA6BxipsiaMZhujMeBfCznzyci", - "others": [ - { - "pubkey": "9WYHTavL1pmhunFCzUwiiq4pXwvgGG5ysjZnjz9H8yB", - "meta": { - "timestamp": "22-2E910FCCCEE008C4B978040CA68211C2395C84C3E6BFB432A267384ED8CD22E5" - }, - "signature": "42yQm4hGTJYWkPg39hQAUgP6S6EQ4vTfXdJuxKEHL1ih6YHiDL2hcwrFgBHjXLRgxRhj2VNVqqc6b4JayKqTE14r" - } - ] - } - ] -} -``` - -#### `wot/certify` - - -**Goal** - -POST [Certification](./Protocol.md#certification) data. - -**Parameters** - -Name | Value | Method ----- | ----- | ------ -`cert` | The raw certification. | POST - -**Returns** - -The available validated data for this public key. -```json -{ - "issuer": "HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY", - "timestamp": "44-76522E321B3380B058DB6D9E66121705EEA63610869A7C5B3E701CF6AF2D55A8", - "sig": "42yQm4hGTJYWkPg39hQAUgP6S6EQ4vTfXdJuxKEHL1ih6YHiDL2hcwrFgBHjXLRgxRhj2VNVqqc6b4JayKqTE14r", - "target": { - "issuer": "CqwuWfMsPqtUkWdUK6FxV6hPWeHaUfEcz7dFZZJA49BS", - "uid": "johnsnow", - "timestamp": "44-76522E321B3380B058DB6D9E66121705EEA63610869A7C5B3E701CF6AF2D55A8", - "sig": "42yQm4hGTJYWkPg39hQAUgP6S6EQ4vTfXdJuxKEHL1ih6YHiDL2hcwrFgBHjXLRgxRhj2VNVqqc6b4JayKqTE14r", - } -} -``` - -#### `wot/revoke` - - -**Goal** - -Remove an identity from Identity pool. - -> N.B.: An identity **written in the blockchain cannot be removed**. - -**Parameters** - -Name | Value | Method ----- | ----- | ------ -`revocation` | The raw revocation. | POST - -**Returns** - -True if operation went well. An HTTP error otherwise with body as error message. -```json -{ - "result": true -} -``` - -#### `wot/lookup/[search]` - - -**Goal** - -GET [Public key](./Protocol.md#publickey) data. - -**Parameters** - -Name | Value | Method ----- | ----- | ------ -`search` | A string of data to look for (public key, uid). | URL - -**Returns** - -A list of public key data matching search string (may not return all results, check `partial` flag which is set to `false` if all results are here, ` true` otherwise). -```json -{ - "partial": false, - "results": [ - { - "pubkey": "HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY", - "uids": [ - { - "uid": "udid2;c;TOCQUEVILLE;FRANCOIS-XAVIER-ROBE;1989-07-14;e+48.84+002.30;0;", - "meta": { - "timestamp": "56-97A56CCE04A1B7A03264ADE09545B262CBE65E62DDA481B7D7C89EB4669F5435" - }, - "self": "J3G9oM5AKYZNLAB5Wx499w61NuUoS57JVccTShUbGpCMjCqj9yXXqNq7dyZpDWA6BxipsiaMZhujMeBfCznzyci", - "revocation_sig": "CTmlh3tO4B8f8IbL8iDy5ZEr3jZDcxkPmDmRPQY74C39MRLXi0CKUP+oFzTZPYmyUC7fZrUXrb3LwRKWw1jEBQ==", - "revoked": false, - "others": [ - { - "pubkey": "9WYHTavL1pmhunFCzUwiiq4pXwvgGG5ysjZnjz9H8yB", - "meta": { - "timestamp": "32-DB30D958EE5CB75186972286ED3F4686B8A1C2CD" - }, - "signature": "42yQm4hGTJYWkPg39hQAUgP6S6EQ4vTfXdJuxKEHL1ih6YHiDL2hcwrFgBHjXLRgxRhj2VNVqqc6b4JayKqTE14r" - } - ] - } - ], - "signed": [ - { - "uid": "snow", - "pubkey": "2P7y2UDiCcvsgSSt8sgHF3BPKS4m9waqKw4yXHCuP6CN", - "meta": { - "timestamp": "33-AB30D958EE5CB75186972286ED3F4686B8A1C2CD" - }, - "revocation_sig": "CK6UDDJM3d0weE1RVtzFJnw/+J507lPAtspleHc59T4+N1tzQj1RRGWrzPiTknCjnCO6SxBSJX0B+MIUWrpNAw==", - "revoked": false, - "signature": "Xbr7qhyGNCmLoVuuKnKIbrdmtCvb9VBIEY19izUNwA5nufsjNm8iEsBTwKWOo0lq5O1+AAPMnht8cm2JjMq8AQ==" - }, - { - "uid": "snow", - "pubkey": "2P7y2UDiCcvsgSSt8sgHF3BPKS4m9waqKw4yXHCuP6CN", - "meta": { - "timestamp": "978-B38F54242807DFA1A12F17E012D355D8DB92CA6E947FC5D147F131B30C639163" - }, - "revocation_sig": "a7SFapoVaXq27NU+wZj4afmxp0SbwLGqLJih8pfX6TRKPvNp/V93fbKixbqg10cwa1CadNenztxq3ZgOivqADw==", - "revoked": false, - "signature": "HU9VPwC4EqPJwATPuyUJM7HLjfig5Ke1CKonL9Q78n5/uNSL2hkgE9Pxsor8CCJfkwCxh66NjGyqnGYqZnQMAg==" - }, - { - "uid": "snow", - "pubkey": "7xapQvvxQ6367bs8DsskEf3nvQAgJv97Yu11aPbkCLQj", - "meta": { - "timestamp": "76-0DC977717C49E69A78A67C6A1526EC17ED380BC68F0C38D290A954471A1349B7" - }, - "revocation_sig": "h8D/dx/z5K2dx06ktp7fnmLRdxkdV5wRkJgnmEvKy2k55mM2RyREpHfD7t/1CC5Ew+UD0V9N27PfaoLxZc1KCQ==", - "revoked": true, - "signature": "6S3x3NwiHB2QqYEY79x4wCUYHcDctbazfxIyxejs38V1uRAl4DuC8R3HJUfD6wMSiWKPqbO+td+8ZMuIn0L8AA==" - }, - { - "uid": "cat", - "pubkey": "CK2hBp25sYQhdBf9oFMGHyokkmYFfzSCmwio27jYWAN7", - "meta": { - "timestamp": "63-999677597FC04E6148860AE888A2E1942DF0E1E732C31500BA8EFF07F06FEC0C" - }, - "revocation_sig": "bJyoM2Tz4hltVXkLvYHOOmLP4qqh2fx7aMLkS5q0cMoEg5AFER3iETj13uoFyhz8yiAKESyAZSDjjQwp8A1QDw==", - "revoked": false, - "signature": "AhgblSOdxUkLwpUN9Ec46St3JGaw2jPyDn/mLcR4j3EjKxUOwHBYqqkxcQdRz/6K4Qo/xMa941MgUp6NjNbKBA==" - } - ] - } - ] -} -``` - -#### `wot/members` - - -**Goal** - -GET the list of current Web of Trust members. - -**Parameters** - -*None*. - -**Returns** - -A list of public key + uid. -```json -{ - "results": [ - { "pubkey": "HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY", "uid": "cat" }, - { "pubkey": "9kNEiyseUNoPn3pmNUhWpvCCwPRgavsLu7YFKZuzzd1L", "uid": "tac" }, - { "pubkey": "9HJ9VXa9wc6EKC6NkCi8b5TKWBot68VhYDg7kDk5T8Cz", "uid": "toc" } - ] -} -``` - -#### `wot/requirements/[pubkey]` - - -**Goal** - -GET requirements to be filled by pubkey to become a member. - -**Parameters** - -Name | Value | Method ----- | ----- | ------ -`pbkey` | Public key to check. | URL - -**Returns** - -A list of identities matching this pubkey and the requirements of each identities to become a member. - -> If the pubkey is matching a member, only one identity may be displayed: the one which is a member. - -```json -{ - "pubkey": "HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY", - "identities": [{ - "uid": "tobi", - "meta": { - "timestamp": "12-20504546F37853625C1E695B757D93CFCC6E494069D53F73748E428947933E45" - }, - "outdistanced": true, - "certifications": 2, - "membershipMissing": true - } - ... - ] -} -``` - -#### `wot/certifiers-of/[search]` - - -**Goal** - -GET [Certification](./Protocol.md#certification) data over a member. - -**Parameters** - -Name | Value | Method ----- | ----- | ------ -`search` | Public key or uid of a *member* (or someone who *was a member*) we want see the certifications. | URL - -**Returns** - -A list of certifications issued to the member by other members (or who used to be members), with `written` data indicating wether the certification is written in the blockchain or not. - -Each certification also has: - -* a `isMember` field to indicate wether the issuer of the certification is still a member or not. -* a `written` field to indicate the block where the certification was written (or null if not written yet). - -```json -{ - "pubkey": "HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY", - "uid": "user identifier", - "isMember": true, - sigDate: 1421787461, - "certifications": [ - { - "pubkey": "9WYHTavL1pmhunFCzUwiiq4pXwvgGG5ysjZnjz9H8yB", - "uid": "certifier uid", - "cert_time": { - "block": 88, - "medianTime": 1509991044 - }, - sigDate: 1421787461, - "written": { - "number": 872768, - "hash": "D30978C9D6C5A348A8188603F039423D90E50DC5" - }, - "isMember": true, - "signature": "42yQm4hGTJYWkPg39hQAUgP6S6EQ4vTfXdJuxKEHL1ih6YHiDL2hcwrFgBHjXLRgxRhj2VNVqqc6b4JayKqTE14r" - }, - ... - ] -} -``` - -#### `wot/certified-by/[search]` - - -**Goal** - -GET [Certification](./Protocol.md#certification) data over a member. - -**Parameters** - -Name | Value | Method ----- | ----- | ------ -`search` | Public key or uid of a *member* (or someone who *was a member*) we want see the certifications. | URL - -**Returns** - -A list of certifications issued by the member to other members (or who used to be members), with `written` data indicating wether the certification is written in the blockchain or not. - -Each certification also has: - -* a `isMember` field to indicate wether the issuer of the certification is still a member or not. -* a `written` field to indicate the block where the certification was written (or null if not written yet). -```json -{ - "pubkey": "HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY", - "uid": "user identifier", - "isMember": true, - sigDate: 1421787461, - "certifications": [ - { - "pubkey": "9WYHTavL1pmhunFCzUwiiq4pXwvgGG5ysjZnjz9H8yB", - "uid": "certifier uid", - "cert_time": { - "block": 88, - "medianTime": 1509991044 - }, - sigDate: 1421787461, - "written": { - "number": 872768, - "hash": "D30978C9D6C5A348A8188603F039423D90E50DC5" - }, - "isMember": true, - "signature": "42yQm4hGTJYWkPg39hQAUgP6S6EQ4vTfXdJuxKEHL1ih6YHiDL2hcwrFgBHjXLRgxRhj2VNVqqc6b4JayKqTE14r" - }, - ... - ] -} -``` - -#### `wot/identity-of/[search]` - - -**Goal** - -GET identity data written for a member. - -**Parameters** - -Name | Value | Method ----- | ----- | ------ -`search` | Public key or uid of a *member* we want see the attached identity. | URL - -**Returns** - -Identity data written in the blockchain. -```json -{ - "pubkey": "HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY", - "uid": "user identifier", - "sigDate": "21-EB18A8D89256EA80195990C91AD399B798F92EE8187F775DF7F4823C46E61F00" -} -``` - - -### blockchain/* - -#### `blockchain/parameters` - -**Goal** - -GET the blockchain parameters used by this node. - -**Parameters** - -*None*. - -**Returns** - -The synchronization parameters. -```json -{ - currency: "beta_brouzouf", - c: 0.01, - dt: 302400, - ud0: 100, - sigPeriod: 7200, - sigStock: 45, - sigWindow: 604800, - sigValidity: 2629800, - sigQty: 3, - idtyWindow: 604800, - msWindow: 604800, - xpercent: 5, - msValidity: 2629800, - stepMax: 3, - medianTimeBlocks: 11, - avgGenTime: 600, - dtDiffEval: 10, - percentRot: 0.67 -} -``` - -Parameters meaning is described under [Protocol parameters](./Protocol.md#protocol-parameters). - -#### `blockchain/membership` - - -**Goal** - -POST a [Membership](./Protocol.md#membership) document. - -**Parameters** - -Name | Value | Method ----- | ----- | ------ -`membership` | The membership document (with signature). | POST - -**Returns** - -The posted membership request. -```json -{ - "signature": "H41/8OGV2W4CLKbE35kk5t1HJQsb3jEM0/QGLUf80CwJvGZf3HvVCcNtHPUFoUBKEDQO9mPK3KJkqOoxHpqHCw==", - "membership": { - "version": "2", - "currency": "beta_brouzouf", - "issuer": "HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY", - "membership": "IN", - "sigDate": 1390739944, - "uid": "superman63" - } -} -``` - -#### `blockchain/memberships/[search]` - - -**Goal** - -GET [Membership](./Protocol.md#membership) data written for a member. - -**Parameters** - -Name | Value | Method ----- | ----- | ------ -`search` | Public key or uid of a *member* we want see the memberships. | URL - -**Returns** - -A list of memberships issued by the *member* and written in the blockchain. -```json -{ - "pubkey": "HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY", - "uid": "user identifier", - "sigDate": 1390739944, - "memberships": [ - { - "version": "2", - "currency": "beta_brouzouf", - "membership": "IN", - "blockNumber": 678, - "blockHash": "000007936DF3CC32BFCC1023D1258EC9E485D474", - "written_number": null - }, - ... - ] -} -``` - -#### `blockchain/block` - -**Goal** - -POST a new block to add to the blockchain. - -**Parameters** - -Name | Value | Method ------------------- | ------------------------------ | ------ -`block` | The raw block to be added | POST -`signature` | Signature of the raw block | POST - -**Returns** - -The promoted block if successfully added to the blockchain (see [block/[number]](#blockchainblocknumber) return object). - -#### `blockchain/block/[NUMBER]` - -**Goal** - -GET the promoted block whose number `NUMBER`. - -**Parameters** - -Name | Value | Method ------------------- | ------------------------------------------------------------- | ------ -`NUMBER` | The promoted block number (integer value) we want to see. | URL - -**Returns** - -The promoted block if it exists (otherwise return HTTP 404). -```json -{ - "version": 2, - "currency": "beta_brouzouf", - "nonce": 28, - "inner_hash": "FD09B0F7CEC5A575CA6E528DC4C854B612AE77B7283F48E0D28677F5C9C9D0DD", - "number": 1, - "time": 1408996317, - "medianTime": 1408992543, - "dividend": 254, - "monetaryMass": 18948, - "issuer": "HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY", - "previousHash": "0009A7A62703F976F683BBA500FC0CB832B8220D", - "previousIssuer": "CYYjHsNyg3HMRMpTHqCJAN9McjH5BwFLmDKGV3PmCuKp", - "membersCount": 4, - "hash": "0000F40BDC0399F2E84000468628F50A122B5F16", - "identities": [ - "9WYHTavL1pmhunFCzUwiiq4pXwvgGG5ysjZnjz9H8yB:2D96KZwNUvVtcapQPq2mm7J9isFcDCfykwJpVEZwBc7tCgL4qPyu17BT5ePozAE9HS6Yvj51f62Mp4n9d9dkzJoX:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:crowlin" - ], - "joiners": [ - "9WYHTavL1pmhunFCzUwiiq4pXwvgGG5ysjZnjz9H8yB:2XiBDpuUdu6zCPWGzHXXy8c4ATSscfFQG9DjmqMZUxDZVt1Dp4m2N5oHYVUfoPdrU9SLk4qxi65RNrfCVnvQtQJk:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:crowlin" - ], - "leavers": [ - "9WYHTavL1pmhunFCzUwiiq4pXwvgGG5ysjZnjz9H8yB:2XiBDpuUdu6zCPWGzHXXy8c4ATSscfFQG9DjmqMZUxDZVt1Dp4m2N5oHYVUfoPdrU9SLk4qxi65RNrfCVnvQtQJk:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855:crowlin" - ], - "revoked": [ - "9WYHTavL1pmhunFCzUwiiq4pXwvgGG5ysjZnjz9H8yB:2D96KZwNUvVtcapQPq2mm7J9isFcDCfykwJpVEZwBc7tCgL4qPyu17BT5ePozAE9HS6Yvj51f62Mp4n9d9dkzJoX" - ], - "excluded": [ - "9WYHTavL1pmhunFCzUwiiq4pXwvgGG5ysjZnjz9H8yB" - ], - "certifications": [ - "CYYjHsNyg3HMRMpTHqCJAN9McjH5BwFLmDKGV3PmCuKp:9WYHTavL1pmhunFCzUwiiq4pXwvgGG5ysjZnjz9H8yB:1505900000:2XiBDpuUdu6zCPWGzHXXy8c4ATSscfFQG9DjmqMZUxDZVt1Dp4m2N5oHYVUfoPdrU9SLk4qxi65RNrfCVnvQtQJk" - ], - "transactions": [ - { - "signatures": [ - "H41/8OGV2W4CLKbE35kk5t1HJQsb3jEM0/QGLUf80CwJvGZf3HvVCcNtHPUFoUBKEDQO9mPK3KJkqOoxHpqHCw==" - "2D96KZwNUvVtcapQPq2mm7J9isFcDCfykwJpVEZwBc7tCgL4qPyu17BT5ePozAE9HS6Yvj51f62Mp4n9d9dkzJoX", - "2XiBDpuUdu6zCPWGzHXXy8c4ATSscfFQG9DjmqMZUxDZVt1Dp4m2N5oHYVUfoPdrU9SLk4qxi65RNrfCVnvQtQJk" - ], - "version": 2, - "currency": "beta_brouzouf", - "issuers": [ - "HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY", - "CYYjHsNyg3HMRMpTHqCJAN9McjH5BwFLmDKGV3PmCuKp", - "9WYHTavL1pmhunFCzUwiiq4pXwvgGG5ysjZnjz9H8yB" - ], - "inputs": [ - "T:6991C993631BED4733972ED7538E41CCC33660F554E3C51963E2A0AC4D6453D3:0", - "T:3A09A20E9014110FD224889F13357BAB4EC78A72F95CA03394D8CCA2936A7435:0", - "D:4745EEBA84D4E3C2BDAE4768D4E0F5A671531EE1B0B9F5206744B4551C664FDF:243", - "T:3A09A20E9014110FD224889F13357BAB4EC78A72F95CA03394D8CCA2936A7435:1", - "T:67F2045B5318777CC52CD38B424F3E40DDA823FA0364625F124BABE0030E7B5B:0", - "D:521A760049DF4FAA602FEF86B7A8E306654502FA3A345F6169B8468B81E71AD3:187" - ], - "unlocks": [ - "0:SIG(0)", - "1:SIG(2)", - "2:SIG(1)", - "3:SIG(1)", - "4:SIG(0)", - "5:SIG(0)" - ], - "outputs": [ - "30:SIG(BYfWYFrsyjpvpFysgu19rGK3VHBkz4MqmQbNyEuVU64g)", - "156:SIG(DSz4rgncXCytsUMW2JU2yhLquZECD2XpEkpP9gG5HyAx)", - "49:SIG(6DyGr5LFtFmbaJYRvcs9WmBsr4cbJbJ1EV9zBbqG7A6i)" - ] - } - ], - "signature": "H41/8OGV2W4CLKbE35kk5t1HJQsb3jEM0/QGLUf80CwJvGZf3HvVCcNtHPUFoUBKEDQO9mPK3KJkqOoxHpqHCw==", -} -``` - -#### `blockchain/blocks/[COUNT]/[FROM]` - -**Goal** - -GET the `[COUNT]` promoted blocks from `[FROM]` number, inclusive. - -**Parameters** - -Name | Value | Method ------------------- | ------------------------------------------------------------- | ------ -`COUNT` | The number of blocks we want to see. | URL -`FROM` | The starting block. | URL - -**Returns** - -The promoted blocks if it exists block `[FROM]` (otherwise return HTTP 404). Result is an array whose values are the same structure as [/blockchain/block/[number]](#blockchainblocknumber). -```json -{ - "blocks": [ - { number: 2, ... }, - { number: 3, ... } - ] -} -``` - -#### `blockchain/current` - -Same as [block/[number]](#blockchainblocknumber), but return last accepted block. - -#### `blockchain/hardship/[PUBKEY]` - -**Goal** - -GET hardship level for given member's pubkey for writing next block. - -**Parameters** - -Name | Value | Method ----- | ----- | ------ -`PUBKEY` | Member's pubkey. | URL - -**Returns** - -The hardship value (`level`) + `block` number. -```json -{ - "block": 598, - "level": 3 -} - -``` - -#### `blockchain/difficulties` - -**Goal** - -GET hardship level for given member's pubkey for writing next block. - -**Parameters** - -None. - -**Returns** - -The respective difficulty of each member in the last `IssuersFrame` blocks for current block. -```json -{ - "block": 598, - "levels": [{ - "uid": "jack", - "level": 8 - },{ - "uid": "cat", - "level": 4 - }] -} - -``` - -#### `blockchain/with/newcomers` -**Goal** - -GET the block numbers containing newcomers (new identities). - -**Parameters** - -*None*. - -**Returns** - -Block numbers. -```json -{ - "result": { - "blocks": [223,813] - } -} -``` - -#### `blockchain/with/certs` -**Goal** - -GET the block numbers containing certifications. - -**Parameters** - -*None*. - -**Returns** - -Block numbers. -```json -{ - "result": { - "blocks": [223,813] - } -} -``` - -#### `blockchain/with/joiners` -**Goal** - -GET the block numbers containing joiners (newcomers or people coming back after exclusion). - -**Parameters** - -*None*. - -**Returns** - -Block numbers. -```json -{ - "result": { - "blocks": [223,813] - } -} -``` - -#### `blockchain/with/actives` -**Goal** - -GET the block numbers containing actives (members updating their membership). - -**Parameters** - -*None*. - -**Returns** - -Block numbers. -```json -{ - "result": { - "blocks": [223,813] - } -} -``` - -#### `blockchain/with/leavers` -**Goal** - -GET the block numbers containing leavers (members leaving definitely the currency). - -**Parameters** - -*None*. - -**Returns** - -Block numbers. -```json -{ - "result": { - "blocks": [223,813] - } -} -``` - -#### `blockchain/with/revoked` -**Goal** - -GET the block numbers containing revoked members. - -**Parameters** - -*None*. - -**Returns** - -Block numbers. -```json -{ - "result": { - "blocks": [223,813] - } -} -``` - -#### `blockchain/with/excluded` -**Goal** - -GET the block numbers containing excluded members. - -**Parameters** - -*None*. - -**Returns** - -Block numbers. -```json -{ - "result": { - "blocks": [223,813] - } -} -``` - -#### `blockchain/with/ud` -**Goal** - -GET the block numbers containing Universal Dividend. - -**Parameters** - -*None*. - -**Returns** - -Block numbers. -```json -{ - "result": { - "blocks": [223,813] - } -} -``` - -#### `blockchain/with/tx` -**Goal** - -GET the block numbers containing transactions. - -**Parameters** - -*None*. - -**Returns** - -Block numbers. -```json -{ - "result": { - "blocks": [223,813] - } -} -``` - -#### `blockchain/branches` - -**Goal** - -GET current branches of the node. - -**Parameters** - -*None*. - -**Returns** - -Top block of each branch, i.e. the last received block of each branch. An array of 4 blocks would mean the node has 4 branches, -3 would mean 3 branches, and so on. - -```json -{ - "blocks": [ - { number: 2, ... }, - { number: 3, ... } - ] -} -``` - -### network/* - -This URL is used for Duniter Gossip protocol (exchanging UCG messages). - -#### `network/peers` -**Goal** - -GET the exhaustive list of peers known by the node. - -**Parameters** - -*None*. - -**Returns** - -List of peering entries. -```json -{ - "peers": [ - { - "version": "2", - "currency": "meta_brouzouf", - "status": "UP", - "first_down": null, - "last_try": null, - "pubkey": "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk", - "block": "45180-00000E577DD4B308B98D0ED3E43926CE4D22E9A8", - "signature": "GKTrlUc4um9lQuj9UI8fyA/n/JKieYqBYcl9keIWfAVOnvHamLHaqGzijsdX1kNt64cadcle/zkd7xOgMTdQAQ==", - "endpoints": [ - "BASIC_MERKLED_API metab.ucoin.io 88.174.120.187 9201" - ] - }, - { - "version": "2", - "currency": "meta_brouzouf", - "status": "UP", - "first_down": null, - "last_try": null, - "pubkey": "2aeLmae5d466y8D42wLK5MknwUBCR6MWWeixRzdTQ4Hu", - "block": "45182-0000064EEF412C1CDD1B370CC45A3BC3B9743464", - "signature": "kbdTay1OirDqG/E3jyCaDlL7HVVHb9/BXvNHAg+xO9sSA+NgmBo/4mEqL9b7hH0UnbXHss6TfuvxAHZLmBqsCw==", - "endpoints": [ - "BASIC_MERKLED_API twiced.fr 88.174.120.187 9223" - ] - }, - ... - ] -} -``` - -#### `network/peering` -**Goal** - -GET the peering informations of this node. - -**Parameters** - -*None*. - -**Returns** - -Peering entry of the node. -```json -{ - "version": "2", - "currency": "beta_brouzouf", - "pubkey": "HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY", - "endpoints": [ - "BASIC_MERKLED_API some.dns.name 88.77.66.55 2001:0db8:0000:85a3:0000:0000:ac1f 9001", - "BASIC_MERKLED_API some.dns.name 88.77.66.55 2001:0db8:0000:85a3:0000:0000:ac1f 9002", - "OTHER_PROTOCOL 88.77.66.55 9001", - ], - "signature": "42yQm4hGTJYWkPg39hQAUgP6S6EQ4vTfXdJuxKEHL1ih6YHiDL2hcwrFgBHjXLRgxRhj2VNVqqc6b4JayKqTE14r" -} -``` - -#### `network/peering/peers (GET)` -**Goal** - -Merkle URL refering to peering entries of every node inside the currency network. - -**Parameters** - -*None*. - -**Returns** - -Merkle URL result. -```json -{ - "depth": 3, - "nodesCount": 6, - "leavesCount": 5, - "root": "114B6E61CB5BB93D862CA3C1DFA8B99E313E66E9" -} -``` - -Merkle URL leaf: peering entry -```json -{ - "hash": "2E69197FAB029D8669EF85E82457A1587CA0ED9C", - "value": { - "version": "2", - "currency": "beta_brouzouf", - "pubkey": "HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY", - "endpoints": [ - "BASIC_MERKLED_API some.dns.name 88.77.66.55 2001:0db8:0000:85a3:0000:0000:ac1f 9001", - "BASIC_MERKLED_API some.dns.name 88.77.66.55 2001:0db8:0000:85a3:0000:0000:ac1f 9002", - "OTHER_PROTOCOL 88.77.66.55 9001", - ], - "signature": "42yQm4hGTJYWkPg39hQAUgP6S6EQ4vTfXdJuxKEHL1ih6YHiDL2hcwrFgBHjXLRgxRhj2VNVqqc6b4JayKqTE14r" - } -} -``` - -#### `network/peering/peers (POST)` -**Goal** - -POST a peering entry document. - -**Parameters** - -Name | Value | Method ------------ | ----------------------------------- | ------ -`peer` | The peering entry document. | POST - -**Returns** - -The posted entry. -```json -{ - "version": "2", - "currency": "beta_brouzouf", - "pubkey": "HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY", - "endpoints": [ - "BASIC_MERKLED_API some.dns.name 88.77.66.55 2001:0db8:0000:85a3:0000:0000:ac1f 9001", - "BASIC_MERKLED_API some.dns.name 88.77.66.55 2001:0db8:0000:85a3:0000:0000:ac1f 9002", - "OTHER_PROTOCOL 88.77.66.55 9001", - ], - "signature": "42yQm4hGTJYWkPg39hQAUgP6S6EQ4vTfXdJuxKEHL1ih6YHiDL2hcwrFgBHjXLRgxRhj2VNVqqc6b4JayKqTE14r" -} -``` - -### tx/* - -#### `tx/process` -**Goal** - -POST a transaction. - -**Parameters** - -Name | Value | Method ------------------ | ------------------------------------------------------------- | ------ -`transaction` | The raw transaction. | POST - -**Returns** - -The recorded transaction. -```json -{ - "raw": "Version: 2\r\n...\r\n", - "transaction": - { - "signatures": [ - "H41/8OGV2W4CLKbE35kk5t1HJQsb3jEM0/QGLUf80CwJvGZf3HvVCcNtHPUFoUBKEDQO9mPK3KJkqOoxHpqHCw==" - "2D96KZwNUvVtcapQPq2mm7J9isFcDCfykwJpVEZwBc7tCgL4qPyu17BT5ePozAE9HS6Yvj51f62Mp4n9d9dkzJoX", - "2XiBDpuUdu6zCPWGzHXXy8c4ATSscfFQG9DjmqMZUxDZVt1Dp4m2N5oHYVUfoPdrU9SLk4qxi65RNrfCVnvQtQJk" - ], - "version": 2, - "currency": "beta_brouzouf", - "issuers": [ - "HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY", - "CYYjHsNyg3HMRMpTHqCJAN9McjH5BwFLmDKGV3PmCuKp", - "9WYHTavL1pmhunFCzUwiiq4pXwvgGG5ysjZnjz9H8yB" - ], - "inputs": [ - "T:6991C993631BED4733972ED7538E41CCC33660F554E3C51963E2A0AC4D6453D3:0", - "T:3A09A20E9014110FD224889F13357BAB4EC78A72F95CA03394D8CCA2936A7435:0", - "D:4745EEBA84D4E3C2BDAE4768D4E0F5A671531EE1B0B9F5206744B4551C664FDF:243", - "T:3A09A20E9014110FD224889F13357BAB4EC78A72F95CA03394D8CCA2936A7435:1", - "T:67F2045B5318777CC52CD38B424F3E40DDA823FA0364625F124BABE0030E7B5B:0", - "D:521A760049DF4FAA602FEF86B7A8E306654502FA3A345F6169B8468B81E71AD3:187" - ], - "unlocks": [ - "0:SIG(0)", - "1:SIG(2)", - "2:SIG(1)", - "3:SIG(1)", - "4:SIG(0)", - "5:SIG(0)" - ], - "outputs": [ - "30:SIG(BYfWYFrsyjpvpFysgu19rGK3VHBkz4MqmQbNyEuVU64g)", - "156:SIG(DSz4rgncXCytsUMW2JU2yhLquZECD2XpEkpP9gG5HyAx)", - "49:SIG(6DyGr5LFtFmbaJYRvcs9WmBsr4cbJbJ1EV9zBbqG7A6i)" - ] - } -} -``` - - -#### `tx/sources/[pubkey]` - -**Goal** - -GET a list of available sources. - -**Parameters** - -Name | Value | Method ----- | ----- | ------ -`pubkey` | Owner of the coins' pubkey. | URL - -**Returns** - -A list of available sources for the given `pubkey`. -```json -{ - "currency": "beta_brouzouf", - "pubkey": "HsLShAtzXTVxeUtQd7yi5Z5Zh4zNvbu8sTEZ53nfKcqY", - "sources": [ - { - "type: "D", - "noffset": 5, - "identifier": "6C20752F6AD06AEA8D0BB46BB8C4F68641A34C79", - "amount": 100 - }, - { - "type: "D", - "noffset": 18, - "identifier": "DB7D88E795E42CF8CFBFAAFC77379E97847F9B42", - "amount": 110 - }, - { - "type: "T", - "noffset": 55, - "identifier": "E614E814179F313B1113475E6319EF4A3D470AD0", - "amount": 30 - } - ] -} -``` - - -#### `tx/history/[pubkey]` - -**Goal** - -Get the wallet transaction history - -**parameters** - -Name | Value | Method ----- | ----- | ------ -`pubkey` | Wallet public key. | URL - -**Returns** - -The full transaction history for the given `pubkey` -```json -{ - "currency": "meta_brouzouf", - "pubkey": "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk", - "history": { - "sent": [ - { - "version": 2, - "received": null, - "issuers": [ - "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk" - ], - "inputs": [ - "D:000A8362AE0C1B8045569CE07735DE4C18E81586:125" - ], - "outputs": [ - "5:SIG(8Fi1VSTbjkXguwThF4v2ZxC5whK7pwG2vcGTkPUPjPGU)", - "95:SIG(HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk)" - ], - "comment": "Essai", - "signatures": [ - "8zzWSU+GNSNURnH1NKPT/TBoxngEc/0wcpPSbs7FqknGxud+94knvT+dpe99k6NwyB5RXvOVnKAr4p9/KEluCw==" - ], - "hash": "FC7BAC2D94AC9C16AFC5C0150C2C9E7FBB2E2A09", - "block_number": 173, - "time": 1421932545 - } - ], - "received": [ - { - "version": 2, - "received": null, - "issuers": [ - "8Fi1VSTbjkXguwThF4v2ZxC5whK7pwG2vcGTkPUPjPGU" - ], - "inputs": [ - "D:000A8362AE0C1B8045569CE07735DE4C18E81586:125" - ], - "outputs": [ - "7:SIG(HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk)", - "93:SIG(8Fi1VSTbjkXguwThF4v2ZxC5whK7pwG2vcGTkPUPjPGU)" - ], - "comment": "", - "signatures": [ - "1Mn8q3K7N+R4GZEpAUm+XSyty1Uu+BuOy5t7BIRqgZcKqiaxfhAUfDBOcuk2i4TJy1oA5Rntby8hDN+cUCpvDg==" - ], - "hash": "5FB3CB80A982E2BDFBB3EA94673A74763F58CB2A", - "block_number": 207, - "time": 1421955525 - }, - { - "version": 2, - "received": null, - "issuers": [ - "J78bPUvLjxmjaEkdjxWLeENQtcfXm7iobqB49uT1Bgp3" - ], - "inputs": [ - "T:6A50FF82410387B239489CE38B34E0FDDE1697FE:0" - ], - "outputs": [ - "42:SIG(HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk)", - "9958:SIG(J78bPUvLjxmjaEkdjxWLeENQtcfXm7iobqB49uT1Bgp3)" - ], - "comment": "", - "signatures": [ - "XhBcCPizPiWdKeXWg1DX/FTQst6DppEjsYEtoAZNA0P11reXtgc9IduiIxNWzNjt/KvTw8APkSI8/Uf31QQVDA==" - ], - "hash": "ADE7D1C4002D6BC10013C34CE22733A55173BAD4", - "block_number": 15778, - "time": 1432314584 - } - ], - "sending": [ - { - "version": 2, - "received": 1459691641, - "issuers": [ - "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk" - ], - "inputs": [ - "0:D:8196:000022AD426FE727C707D847EC2168A64C577706:5872" - ], - "outputs": [ - "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk:5871" - "2sq8bBDQGK74f1eD3mAPQVgHCmFdijZr9nbv16FwbokX:1", - ], - "comment": "some comment", - "signatures": [ - "kLOAAy7/UldQk7zz4I7Jhv9ICuGYRx7upl8wH8RYL43MMF6+7MbPh3QRN1qNFGpAfa3XMWIQmbUWtjZKP6OfDA==" - ], - "hash": "BA41013F2CD38EDFFA9D38A275F8532DD906A2DE" - } - ], - "receiving": [ - { - "version": 2, - "received": 1459691641, - "issuers": [ - "2sq8bBDQGK74f1eD3mAPQVgHCmFdijZr9nbv16FwbokX" - ], - "inputs": [ - "0:D:8196:000022AD426FE727C707D847EC2168A64C577706:4334" - ], - "outputs": [ - "2sq8bBDQGK74f1eD3mAPQVgHCmFdijZr9nbv16FwbokX:1", - "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk:4333" - ], - "comment": "some comment", - "signatures": [ - "DRiZinUEKrrLiJNogtydzwEbmETrvWiLNYXCiJsRekxTLyU5g4LjnwiLp/XlvmIekjJK5n/gullLWrHUBvFSAw== - ], - "hash": "A0A511131CD0E837204A9441B3354918AC4CE671" - } - ] - } -} -``` - -#### `tx/history/[PUBKEY]/blocks/[from]/[to]` - -**Goal** - -Get the wallet transaction history - -**parameters** - -Name | Value | Method ----- | ----- | ------ -`pubkey` | Wallet public key. | URL -`from` | The starting block. | URL -`to` | the ending block. | URL - -**Returns** - -The transaction history for the given `pubkey` and between the given `from` and `to` blocks. -```json -{ - "currency": "meta_brouzouf", - "pubkey": "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk", - "history": { - "sent": [ - { - "version": 2, - "issuers": [ - "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk" - ], - "inputs": [ - "0:D:125:000A8362AE0C1B8045569CE07735DE4C18E81586:100" - ], - "outputs": [ - "8Fi1VSTbjkXguwThF4v2ZxC5whK7pwG2vcGTkPUPjPGU:5", - "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk:95" - ], - "comment": "Essai", - "signatures": [ - "8zzWSU+GNSNURnH1NKPT/TBoxngEc/0wcpPSbs7FqknGxud+94knvT+dpe99k6NwyB5RXvOVnKAr4p9/KEluCw==" - ], - "hash": "FC7BAC2D94AC9C16AFC5C0150C2C9E7FBB2E2A09", - "block_number": 173, - "time": 1421932545 - } - ], - "received": [ - { - "version": 2, - "issuers": [ - "8Fi1VSTbjkXguwThF4v2ZxC5whK7pwG2vcGTkPUPjPGU" - ], - "inputs": [ - "0:D:125:000A8362AE0C1B8045569CE07735DE4C18E81586:100" - ], - "outputs": [ - "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk:7", - "8Fi1VSTbjkXguwThF4v2ZxC5whK7pwG2vcGTkPUPjPGU:93" - ], - "comment": "", - "signatures": [ - "1Mn8q3K7N+R4GZEpAUm+XSyty1Uu+BuOy5t7BIRqgZcKqiaxfhAUfDBOcuk2i4TJy1oA5Rntby8hDN+cUCpvDg==" - ], - "hash": "5FB3CB80A982E2BDFBB3EA94673A74763F58CB2A", - "block_number": 207, - "time": 1421955525 - }, - { - "version": 2, - "issuers": [ - "J78bPUvLjxmjaEkdjxWLeENQtcfXm7iobqB49uT1Bgp3" - ], - "inputs": [ - "0:T:15128:6A50FF82410387B239489CE38B34E0FDDE1697FE:10000" - ], - "outputs": [ - "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk:42", - "J78bPUvLjxmjaEkdjxWLeENQtcfXm7iobqB49uT1Bgp3:9958" - ], - "comment": "", - "signatures": [ - "XhBcCPizPiWdKeXWg1DX/FTQst6DppEjsYEtoAZNA0P11reXtgc9IduiIxNWzNjt/KvTw8APkSI8/Uf31QQVDA==" - ], - "hash": "ADE7D1C4002D6BC10013C34CE22733A55173BAD4", - "block_number": 15778, - "time": 1432314584 - } - ], - "sending": [ - { - "version": 2, - "issuers": [ - "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk" - ], - "inputs": [ - "0:D:8196:000022AD426FE727C707D847EC2168A64C577706:5872" - ], - "outputs": [ - "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk:5871" - "2sq8bBDQGK74f1eD3mAPQVgHCmFdijZr9nbv16FwbokX:1", - ], - "comment": "some comment", - "signatures": [ - "kLOAAy7/UldQk7zz4I7Jhv9ICuGYRx7upl8wH8RYL43MMF6+7MbPh3QRN1qNFGpAfa3XMWIQmbUWtjZKP6OfDA==" - ], - "hash": "BA41013F2CD38EDFFA9D38A275F8532DD906A2DE" - } - ], - "receiving": [ - { - "version": 2, - "issuers": [ - "2sq8bBDQGK74f1eD3mAPQVgHCmFdijZr9nbv16FwbokX" - ], - "inputs": [ - "0:D:8196:000022AD426FE727C707D847EC2168A64C577706:4334" - ], - "outputs": [ - "2sq8bBDQGK74f1eD3mAPQVgHCmFdijZr9nbv16FwbokX:1", - "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk:4333" - ], - "comment": "some comment", - "signatures": [ - "DRiZinUEKrrLiJNogtydzwEbmETrvWiLNYXCiJsRekxTLyU5g4LjnwiLp/XlvmIekjJK5n/gullLWrHUBvFSAw== - ], - "hash": "A0A511131CD0E837204A9441B3354918AC4CE671" - } - ] - } -} -``` - -#### `tx/history/[pubkey]/times/[from]/[to]` - -**Goal** - -Get the wallet transaction history - -**parameters** - -Name | Value | Method ----- | ----- | ------ -`pubkey` | Wallet public key. | URL -`from` | The starting timestamp limit. (optionnal) | URL -`to` | The ending timestamp. (optionnal) | URL - -**Returns** - -The transaction history for the given `pubkey` and between the given `from` and `to` dates. -```json -{ - "currency": "meta_brouzouf", - "pubkey": "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk", - "history": { - "sent": [ - { - "version": 2, - "issuers": [ - "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk" - ], - "inputs": [ - "0:D:125:000A8362AE0C1B8045569CE07735DE4C18E81586:100" - ], - "outputs": [ - "8Fi1VSTbjkXguwThF4v2ZxC5whK7pwG2vcGTkPUPjPGU:5", - "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk:95" - ], - "comment": "Essai", - "signatures": [ - "8zzWSU+GNSNURnH1NKPT/TBoxngEc/0wcpPSbs7FqknGxud+94knvT+dpe99k6NwyB5RXvOVnKAr4p9/KEluCw==" - ], - "hash": "FC7BAC2D94AC9C16AFC5C0150C2C9E7FBB2E2A09", - "block_number": 173, - "time": 1421932545 - } - ], - "received": [ - { - "version": 2, - "issuers": [ - "8Fi1VSTbjkXguwThF4v2ZxC5whK7pwG2vcGTkPUPjPGU" - ], - "inputs": [ - "0:D:125:000A8362AE0C1B8045569CE07735DE4C18E81586:100" - ], - "outputs": [ - "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk:7", - "8Fi1VSTbjkXguwThF4v2ZxC5whK7pwG2vcGTkPUPjPGU:93" - ], - "comment": "", - "signatures": [ - "1Mn8q3K7N+R4GZEpAUm+XSyty1Uu+BuOy5t7BIRqgZcKqiaxfhAUfDBOcuk2i4TJy1oA5Rntby8hDN+cUCpvDg==" - ], - "hash": "5FB3CB80A982E2BDFBB3EA94673A74763F58CB2A", - "block_number": 207, - "time": 1421955525 - }, - { - "version": 2, - "issuers": [ - "J78bPUvLjxmjaEkdjxWLeENQtcfXm7iobqB49uT1Bgp3" - ], - "inputs": [ - "0:T:15128:6A50FF82410387B239489CE38B34E0FDDE1697FE:10000" - ], - "outputs": [ - "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk:42", - "J78bPUvLjxmjaEkdjxWLeENQtcfXm7iobqB49uT1Bgp3:9958" - ], - "comment": "", - "signatures": [ - "XhBcCPizPiWdKeXWg1DX/FTQst6DppEjsYEtoAZNA0P11reXtgc9IduiIxNWzNjt/KvTw8APkSI8/Uf31QQVDA==" - ], - "hash": "ADE7D1C4002D6BC10013C34CE22733A55173BAD4", - "block_number": 15778, - "time": 1432314584 - } - ], - "sending": [ - { - "version": 2, - "issuers": [ - "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk" - ], - "inputs": [ - "0:D:8196:000022AD426FE727C707D847EC2168A64C577706:5872" - ], - "outputs": [ - "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk:5871" - "2sq8bBDQGK74f1eD3mAPQVgHCmFdijZr9nbv16FwbokX:1", - ], - "comment": "some comment", - "signatures": [ - "kLOAAy7/UldQk7zz4I7Jhv9ICuGYRx7upl8wH8RYL43MMF6+7MbPh3QRN1qNFGpAfa3XMWIQmbUWtjZKP6OfDA==" - ], - "hash": "BA41013F2CD38EDFFA9D38A275F8532DD906A2DE" - } - ], - "receiving": [ - { - "version": 2, - "issuers": [ - "2sq8bBDQGK74f1eD3mAPQVgHCmFdijZr9nbv16FwbokX" - ], - "inputs": [ - "0:D:8196:000022AD426FE727C707D847EC2168A64C577706:4334" - ], - "outputs": [ - "2sq8bBDQGK74f1eD3mAPQVgHCmFdijZr9nbv16FwbokX:1", - "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk:4333" - ], - "comment": "some comment", - "signatures": [ - "DRiZinUEKrrLiJNogtydzwEbmETrvWiLNYXCiJsRekxTLyU5g4LjnwiLp/XlvmIekjJK5n/gullLWrHUBvFSAw== - ], - "hash": "A0A511131CD0E837204A9441B3354918AC4CE671" - } - ] - } -} -``` -### ud/* - -#### `ud/history/[pubkey]` - -**Goal** - -Get the wallet universal dividend history - -**parameters** - -Name | Value | Method ----- | ----- | ------ -`pubkey` | Wallet public key. | URL - -**Returns** - -The universal dividend history for the given `pubkey`. -```json -{ - "currency": "meta_brouzouf", - "pubkey": "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk", - "history": { - "history": [ - { - "block_number": 125, - "consumed": true, - "time": 1421927007, - "amount": 100 - }, - { - "block_number": 410, - "consumed": false, - "time": 1422012828, - "amount": 100 - }, - { - "block_number": 585, - "consumed": true, - "time": 1422098800, - "amount": 100 - } - ] - } -} -``` - - -### ws/* - -#### `ws/block` - -**Goal** - -A websocket entry point for receiving blocks. - -**Parameters** - -*None*. - -**Returns** - -Websocket connection. - -#### `ws/peer` - -**Goal** - -A websocket entry point for receiving peers. - -**Parameters** - -*None*. - -**Returns** - -Websocket connection. diff --git a/index.js b/index.js index 512d77e1c..b6737e398 100644 --- a/index.js +++ b/index.js @@ -26,7 +26,7 @@ const daemonDependency = require('./app/modules/daemon'); const pSignalDependency = require('./app/modules/peersignal'); const crawlerDependency = require('./app/modules/crawler'); const proverDependency = require('./app/modules/prover'); -const bmapiDependency = require('./app/modules/bmapi'); +const bmapiDependency = require('duniter-bma'); const routerDependency = require('./app/modules/router'); const MINIMAL_DEPENDENCIES = [ @@ -326,14 +326,6 @@ function commandLineConf(program, conf) { cpu: program.cpu, server: { port: program.port, - ipv4address: program.ipv4, - ipv6address: program.ipv6, - remote: { - host: program.remoteh, - ipv4: program.remote4, - ipv6: program.remote6, - port: program.remotep - } }, db: { mport: program.mport, @@ -354,13 +346,7 @@ function commandLineConf(program, conf) { // Update conf if (cli.currency) conf.currency = cli.currency; - if (cli.server.ipv4address) conf.ipv4 = cli.server.ipv4address; - if (cli.server.ipv6address) conf.ipv6 = cli.server.ipv6address; if (cli.server.port) conf.port = cli.server.port; - if (cli.server.remote.host != undefined) conf.remotehost = cli.server.remote.host; - if (cli.server.remote.ipv4 != undefined) conf.remoteipv4 = cli.server.remote.ipv4; - if (cli.server.remote.ipv6 != undefined) conf.remoteipv6 = cli.server.remote.ipv6; - if (cli.server.remote.port != undefined) conf.remoteport = cli.server.remote.port; if (cli.cpu) conf.cpu = Math.max(0.01, Math.min(1.0, cli.cpu)); if (cli.logs.http) conf.httplogs = true; if (cli.logs.nohttp) conf.httplogs = false; diff --git a/package.json b/package.json index bb7af9947..fe9ee7dc9 100644 --- a/package.json +++ b/package.json @@ -38,27 +38,19 @@ "archiver": "1.0.1", "async": "1.5.2", "bindings": "1.2.1", - "body-parser": "1.15.2", "co": "4.6.0", "colors": "1.1.2", "commander": "2.9.0", - "cors": "2.8.1", "daemonize2": "0.4.2", - "ddos": "0.1.16", "duniter-keypair": "duniter/duniter-keypair", - "errorhandler": "1.4.3", + "duniter-bma": "duniter/duniter-bma", "event-stream": "3.3.4", - "express": "4.14.0", - "express-cors": "0.0.3", - "express-fileupload": "0.0.5", "inquirer": "0.8.5", "jison": "0.4.17", "merkle": "0.5.1", "moment": "2.15.1", - "morgan": "1.7.0", "multimeter": "0.1.1", "naclb": "1.3.7", - "nnupnp": "1.0.2", "node-pre-gyp": "0.6.32", "node-uuid": "1.4.7", "optimist": "0.6.1", @@ -75,8 +67,7 @@ "unzip": "0.1.11", "unzip2": "0.2.5", "winston": "2.2.0", - "wotb": "0.4.14", - "ws": "1.1.1" + "wotb": "0.4.14" }, "devDependencies": { "coveralls": "2.11.4", diff --git a/server.js b/server.js index 46289b304..f9566ccbf 100644 --- a/server.js +++ b/server.js @@ -35,17 +35,21 @@ function Server (home, memoryOnly, overrideConf) { that.lib = {}; that.lib.keyring = require('./app/lib/crypto/keyring'); that.lib.Identity = require('./app/lib/entity/identity'); + that.lib.Transaction = require('./app/lib/entity/transaction'); + that.lib.Peer = require('./app/lib/entity/peer'); + that.lib.Membership = require('./app/lib/entity/membership'); + that.lib.Block = require('./app/lib/entity/block'); + that.lib.Stat = require('./app/lib/entity/stat'); that.lib.rawer = require('./app/lib/ucp/rawer'); - that.lib.http2raw = require('./app/lib/helpers/http2raw'); + that.lib.http2raw = require('duniter-bma').duniter.methods.http2raw; that.lib.dos2unix = require('./app/lib/system/dos2unix'); that.lib.contacter = require('./app/lib/contacter'); - that.lib.bma = require('./app/lib/streams/bma'); + that.lib.bma = require('duniter-bma').duniter.methods.bma; that.lib.network = require('./app/lib/system/network'); that.lib.constants = require('./app/lib/constants'); that.lib.ucp = require('./app/lib/ucp/buid'); that.MerkleService = require("./app/lib/helpers/merkle"); - that.ParametersService = require("./app/lib/helpers/parameters")(); that.IdentityService = require('./app/service/IdentityService')(); that.MembershipService = require('./app/service/MembershipService')(); that.PeeringService = require('./app/service/PeeringService')(that); @@ -189,19 +193,9 @@ function Server (home, memoryOnly, overrideConf) { this.isServerMember = () => this.BlockchainService.isMember(); this.checkConfig = () => co(function*() { - const conf = that.conf; - if (!conf.pair) { + if (!that.conf.pair) { throw new Error('No keypair was given.'); } - if(!conf.ipv4 && !conf.ipv6){ - throw new Error("No interface to listen to."); - } - if(!conf.remoteipv4 && !conf.remoteipv6 && !conf.remotehost){ - throw new Error('No interface for remote contact.'); - } - if (!conf.remoteport) { - throw new Error('No port for remote contact.'); - } }); this.resetHome = () => co(function *() { diff --git a/test/dal/triming.js b/test/dal/triming.js index 50ed30d28..770a34401 100644 --- a/test/dal/triming.js +++ b/test/dal/triming.js @@ -5,7 +5,6 @@ const FileDAL = require('../../app/lib/dal/fileDAL'); const dir = require('../../app/lib/system/directory'); const indexer = require('../../app/lib/dup/indexer'); const toolbox = require('../integration/tools/toolbox'); -const limiter = require('../../app/lib/system/limiter'); let dal; @@ -14,7 +13,6 @@ describe("Triming", function(){ before(() => co(function *() { dal = FileDAL(yield dir.getHomeParams(true, 'db0')); yield dal.init(); - limiter.noLimit(); })); it('should be able to feed the bindex', () => co(function *() { diff --git a/test/fast/ddos-test.js b/test/fast/ddos-test.js deleted file mode 100644 index 73e3f8d90..000000000 --- a/test/fast/ddos-test.js +++ /dev/null @@ -1,39 +0,0 @@ -"use strict"; -const should = require('should'); -const co = require('co'); -const limiter = require('../../app/lib/system/limiter'); -const toolbox = require('../integration/tools/toolbox'); -const user = require('../integration/tools/user'); -const bma = require('../../app/lib/streams/bma'); - -limiter.noLimit(); - -const s1 = toolbox.server({ - pair: { - pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', - sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP' - } -}); - -describe('DDOS', () => { - - before(() => co(function*() { - limiter.noLimit(); - yield s1.initWithDAL().then(bma).then((bmapi) => { - s1.bma = bmapi; - bmapi.openConnections(); - }); - })); - - it('should not be able to send more than 4 reqs/s', () => co(function*() { - try { - s1.bma.getDDOS().params.limit = 3; - s1.bma.getDDOS().params.burst = 3; - s1.bma.getDDOS().params.whitelist = []; - yield Array.from({ length: 4 }).map(() => s1.get('/blockchain/current')); - throw 'Wrong error thrown'; - } catch (e) { - e.should.have.property('statusCode').equal(429); - } - })); -}); diff --git a/test/fast/limiter-test.js b/test/fast/limiter-test.js deleted file mode 100644 index efc1ca239..000000000 --- a/test/fast/limiter-test.js +++ /dev/null @@ -1,60 +0,0 @@ -"use strict"; -const should = require('should'); -const co = require('co'); -const limiter = require('../../app/lib/system/limiter'); -const toolbox = require('../integration/tools/toolbox'); -const user = require('../integration/tools/user'); -const bma = require('../../app/lib/streams/bma'); - -limiter.noLimit(); - -const s1 = toolbox.server({ - pair: { - pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', - sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP' - } -}); - -const cat = user('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 }); - -let theLimiter; - -describe('Limiter', () => { - - before(() => { - limiter.withLimit(); - theLimiter = limiter.limitAsTest(); - }); - - it('should not be able to send more than 10 reqs/s', () => { - theLimiter.canAnswerNow().should.equal(true); - for (let i = 1; i <= 4; i++) { - theLimiter.processRequest(); - } - theLimiter.canAnswerNow().should.equal(true); - theLimiter.processRequest(); // 5 in 1sec - theLimiter.canAnswerNow().should.equal(false); - }); - - it('should be able to send 1 more request (by minute constraint)', () => co(function*(){ - yield new Promise((resolve) => setTimeout(resolve, 1000)); - theLimiter.canAnswerNow().should.equal(true); - theLimiter.processRequest(); // 1 in 1sec, 6 in 1min - theLimiter.canAnswerNow().should.equal(false); - })); - - it('should work with BMA API', () => co(function*(){ - yield s1.initWithDAL().then(bma).then((bmapi) => bmapi.openConnections()); - yield cat.createIdentity(); - try { - for (let i = 0; i < 11; i++) { - yield s1.get('/wot/lookup/cat'); - } - throw 'Should have thrown a limiter error'; - } catch (e) { - e.should.have.property('error').property('ucode').equal(1006); - } - })); - - after(() => limiter.noLimit()); -}); diff --git a/test/integration/branches.js b/test/integration/branches.js index 480009199..0db977f6a 100644 --- a/test/integration/branches.js +++ b/test/integration/branches.js @@ -4,7 +4,7 @@ const _ = require('underscore'); const co = require('co'); const should = require('should'); const duniter = require('../../index'); -const bma = require('../../app/lib/streams/bma'); +const bma = require('duniter-bma').duniter.methods.bma; const rp = require('request-promise'); const httpTest = require('./tools/http'); diff --git a/test/integration/branches2.js b/test/integration/branches2.js index 5dcc3804f..e31619514 100644 --- a/test/integration/branches2.js +++ b/test/integration/branches2.js @@ -3,7 +3,7 @@ const co = require('co'); const _ = require('underscore'); const duniter = require('../../index'); -const bma = require('../../app/lib/streams/bma'); +const bma = require('duniter-bma').duniter.methods.bma; const user = require('./tools/user'); const constants = require('../../app/lib/constants'); const rp = require('request-promise'); diff --git a/test/integration/branches_pending_data.js b/test/integration/branches_pending_data.js index 83c87585b..9cf29a9b0 100644 --- a/test/integration/branches_pending_data.js +++ b/test/integration/branches_pending_data.js @@ -3,7 +3,7 @@ const co = require('co'); const _ = require('underscore'); const duniter = require('../../index'); -const bma = require('../../app/lib/streams/bma'); +const bma = require('duniter-bma').duniter.methods.bma; const user = require('./tools/user'); const rp = require('request-promise'); const httpTest = require('./tools/http'); diff --git a/test/integration/branches_revert.js b/test/integration/branches_revert.js index 7a174e8ba..ed00d5e76 100644 --- a/test/integration/branches_revert.js +++ b/test/integration/branches_revert.js @@ -2,7 +2,7 @@ const co = require('co'); const _ = require('underscore'); -const bma = require('../../app/lib/streams/bma'); +const bma = require('duniter-bma').duniter.methods.bma; const user = require('./tools/user'); const toolbox = require('./tools/toolbox'); const commit = require('./tools/commit'); diff --git a/test/integration/branches_revert2.js b/test/integration/branches_revert2.js index 89db2d780..8dddeff3e 100644 --- a/test/integration/branches_revert2.js +++ b/test/integration/branches_revert2.js @@ -3,7 +3,7 @@ const co = require('co'); const _ = require('underscore'); const duniter = require('../../index'); -const bma = require('../../app/lib/streams/bma'); +const bma = require('duniter-bma').duniter.methods.bma; const user = require('./tools/user'); const rp = require('request-promise'); const httpTest = require('./tools/http'); diff --git a/test/integration/branches_revert_memberships.js b/test/integration/branches_revert_memberships.js index 298afd8ac..4b12f96d8 100644 --- a/test/integration/branches_revert_memberships.js +++ b/test/integration/branches_revert_memberships.js @@ -2,11 +2,10 @@ const co = require('co'); const should = require('should'); -const bma = require('../../app/lib/streams/bma'); +const bma = require('duniter-bma').duniter.methods.bma; const user = require('./tools/user'); const commit = require('./tools/commit'); const toolbox = require('./tools/toolbox'); -const limiter = require('../../app/lib/system/limiter'); const s1 = toolbox.server({ memory: true, @@ -27,8 +26,6 @@ describe("Revert memberships", function() { before(() => co(function*() { - limiter.noLimit(); - yield s1.initWithDAL().then(bma).then((bmapi) => bmapi.openConnections()); yield i1.createIdentity(); diff --git a/test/integration/branches_switch.js b/test/integration/branches_switch.js index 0bcd556d6..d19a35aa6 100644 --- a/test/integration/branches_switch.js +++ b/test/integration/branches_switch.js @@ -3,7 +3,7 @@ const co = require('co'); const _ = require('underscore'); const duniter = require('../../index'); -const bma = require('../../app/lib/streams/bma'); +const bma = require('duniter-bma').duniter.methods.bma; const user = require('./tools/user'); const rp = require('request-promise'); const httpTest = require('./tools/http'); diff --git a/test/integration/certification_chainability.js b/test/integration/certification_chainability.js index 0b6e71f54..5731249fd 100644 --- a/test/integration/certification_chainability.js +++ b/test/integration/certification_chainability.js @@ -4,7 +4,7 @@ const _ = require('underscore'); const co = require('co'); const should = require('should'); const duniter = require('../../index'); -const bma = require('../../app/lib/streams/bma'); +const bma = require('duniter-bma').duniter.methods.bma; const user = require('./tools/user'); const constants = require('../../app/lib/constants'); const rp = require('request-promise'); diff --git a/test/integration/collapse.js b/test/integration/collapse.js index 56cfd9115..9b602e302 100644 --- a/test/integration/collapse.js +++ b/test/integration/collapse.js @@ -3,7 +3,7 @@ const co = require('co'); const _ = require('underscore'); const duniter = require('../../index'); -const bma = require('../../app/lib/streams/bma'); +const bma = require('duniter-bma').duniter.methods.bma; const user = require('./tools/user'); const commit = require('./tools/commit'); const httpTest = require('./tools/http'); diff --git a/test/integration/crosschain-test.js b/test/integration/crosschain-test.js index 0293a2079..2f0861781 100644 --- a/test/integration/crosschain-test.js +++ b/test/integration/crosschain-test.js @@ -5,7 +5,7 @@ const _ = require('underscore'); const assert = require('assert'); const should = require('should'); const rp = require('request-promise'); -const bma = require('../../app/lib/streams/bma'); +const bma = require('duniter-bma').duniter.methods.bma; const commit = require('./tools/commit'); const toolbox = require('./tools/toolbox'); const user = require('./tools/user'); diff --git a/test/integration/forwarding.js b/test/integration/forwarding.js index 605b43944..8ac1a4723 100644 --- a/test/integration/forwarding.js +++ b/test/integration/forwarding.js @@ -7,9 +7,6 @@ const co = require('co'); const node = require('./tools/node'); const user = require('./tools/user'); const jspckg = require('../../package'); -const limiter = require('../../app/lib/system/limiter'); - -limiter.noLimit(); const MEMORY_MODE = true; @@ -17,7 +14,7 @@ describe("Forwarding", function() { describe("Nodes", function() { - const common = { currency: 'bb', ipv4: '127.0.0.1', remoteipv4: '127.0.0.1', upnp: false, rootoffset: 0, sigQty: 1 }; + const common = { currency: 'bb', ipv4: '127.0.0.1', remoteipv4: '127.0.0.1', rootoffset: 0, sigQty: 1 }; const node1 = node({ name: 'db_1', memory: MEMORY_MODE }, _({ httplogs: false, port: 9600, remoteport: 9600, pair: { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'} }).extend(common)); const node2 = node({ name: 'db_2', memory: MEMORY_MODE }, _({ httplogs: false, port: 9601, remoteport: 9601, pair: { pub: 'G2CBgZBPLe6FSFUgpx2Jf1Aqsgta6iib3vmDRA1yLiqU', sec: '58LDg8QLmF5pv6Dn9h7X4yFKfMTdP8fdAiWVcyDoTRJu454fwRihCLULH4MW37zncsg4ruoTGJPZneWk22QmG1w4'} }).extend(common)); diff --git a/test/integration/http_api.js b/test/integration/http_api.js index 8a3e3d563..7ff64280d 100644 --- a/test/integration/http_api.js +++ b/test/integration/http_api.js @@ -5,7 +5,7 @@ const _ = require('underscore'); const should = require('should'); const assert = require('assert'); const duniter = require('../../index'); -const bma = require('../../app/lib/streams/bma'); +const bma = require('duniter-bma').duniter.methods.bma; const user = require('./tools/user'); const http = require('./tools/http'); const constants = require('../../app/lib/constants'); diff --git a/test/integration/identity-absorption.js b/test/integration/identity-absorption.js index 518c7249c..3150b9b70 100644 --- a/test/integration/identity-absorption.js +++ b/test/integration/identity-absorption.js @@ -3,7 +3,7 @@ const _ = require('underscore'); const co = require('co'); const duniter = require('../../index'); -const bma = require('../../app/lib/streams/bma'); +const bma = require('duniter-bma').duniter.methods.bma; const user = require('./tools/user'); const rp = require('request-promise'); const httpTest = require('./tools/http'); diff --git a/test/integration/identity-clean-test.js b/test/integration/identity-clean-test.js index a217197e9..2ee0fc136 100644 --- a/test/integration/identity-clean-test.js +++ b/test/integration/identity-clean-test.js @@ -3,7 +3,7 @@ const _ = require('underscore'); const co = require('co'); const duniter = require('../../index'); -const bma = require('../../app/lib/streams/bma'); +const bma = require('duniter-bma').duniter.methods.bma; const user = require('./tools/user'); const rp = require('request-promise'); const httpTest = require('./tools/http'); diff --git a/test/integration/identity-expiry.js b/test/integration/identity-expiry.js index 4875faf1a..c43753cdd 100644 --- a/test/integration/identity-expiry.js +++ b/test/integration/identity-expiry.js @@ -4,7 +4,7 @@ const _ = require('underscore'); const co = require('co'); const should = require('should'); const duniter = require('../../index'); -const bma = require('../../app/lib/streams/bma'); +const bma = require('duniter-bma').duniter.methods.bma; const user = require('./tools/user'); const constants = require('../../app/lib/constants'); const rp = require('request-promise'); diff --git a/test/integration/identity-kicking.js b/test/integration/identity-kicking.js index 96fb97c41..45f7f4b04 100644 --- a/test/integration/identity-kicking.js +++ b/test/integration/identity-kicking.js @@ -4,7 +4,7 @@ const _ = require('underscore'); const co = require('co'); const should = require('should'); const duniter = require('../../index'); -const bma = require('../../app/lib/streams/bma'); +const bma = require('duniter-bma').duniter.methods.bma; const user = require('./tools/user'); const constants = require('../../app/lib/constants'); const rp = require('request-promise'); diff --git a/test/integration/identity-same-pubkey.js b/test/integration/identity-same-pubkey.js index b2c014758..f64e9fc77 100644 --- a/test/integration/identity-same-pubkey.js +++ b/test/integration/identity-same-pubkey.js @@ -2,7 +2,7 @@ const co = require('co'); const should = require('should'); -const bma = require('../../app/lib/streams/bma'); +const bma = require('duniter-bma').duniter.methods.bma; const user = require('./tools/user'); const commit = require('./tools/commit'); const toolbox = require('./tools/toolbox'); diff --git a/test/integration/identity-test.js b/test/integration/identity-test.js index bf62d7955..72e8aa705 100644 --- a/test/integration/identity-test.js +++ b/test/integration/identity-test.js @@ -4,15 +4,12 @@ const _ = require('underscore'); const co = require('co'); const should = require('should'); const duniter = require('../../index'); -const bma = require('../../app/lib/streams/bma'); +const bma = require('duniter-bma').duniter.methods.bma; const user = require('./tools/user'); const constants = require('../../app/lib/constants'); const rp = require('request-promise'); const httpTest = require('./tools/http'); const commit = require('./tools/commit'); -const limiter = require('../../app/lib/system/limiter'); - -limiter.noLimit(); const expectAnswer = httpTest.expectAnswer; diff --git a/test/integration/lookup.js b/test/integration/lookup.js index c30dcc477..84fdf26c1 100644 --- a/test/integration/lookup.js +++ b/test/integration/lookup.js @@ -3,7 +3,7 @@ const _ = require('underscore'); const co = require('co'); const duniter = require('../../index'); -const bma = require('../../app/lib/streams/bma'); +const bma = require('duniter-bma').duniter.methods.bma; const user = require('./tools/user'); const rp = require('request-promise'); const httpTest = require('./tools/http'); diff --git a/test/integration/network.js b/test/integration/network.js index ecc54a25a..4e67e182c 100644 --- a/test/integration/network.js +++ b/test/integration/network.js @@ -23,6 +23,7 @@ const s1 = node({ memory: MEMORY_MODE, name: 'bb33' }, _.extend({ + ipv4: '127.0.0.1', port: '20501', remoteport: '20501', pair: { diff --git a/test/integration/peer-outdated.js b/test/integration/peer-outdated.js index 7c7e7112d..d0897a161 100644 --- a/test/integration/peer-outdated.js +++ b/test/integration/peer-outdated.js @@ -5,7 +5,7 @@ const Q = require('q'); const should = require('should'); const es = require('event-stream'); const _ = require('underscore'); -const bma = require('../../app/lib/streams/bma'); +const bma = require('duniter-bma').duniter.methods.bma; const user = require('./tools/user'); const commit = require('./tools/commit'); const until = require('./tools/until'); diff --git a/test/integration/peerings.js b/test/integration/peerings.js index e963b555f..b296c807d 100644 --- a/test/integration/peerings.js +++ b/test/integration/peerings.js @@ -5,7 +5,7 @@ const Q = require('q'); const _ = require('underscore'); const should = require('should'); const duniter = require('../../index'); -const bma = require('../../app/lib/streams/bma'); +const bma = require('duniter-bma').duniter.methods.bma; const user = require('./tools/user'); const constants = require('../../app/lib/constants'); const rp = require('request-promise'); diff --git a/test/integration/peers-same-pubkey.js b/test/integration/peers-same-pubkey.js index cd16aa371..1d9f0ad54 100644 --- a/test/integration/peers-same-pubkey.js +++ b/test/integration/peers-same-pubkey.js @@ -4,7 +4,7 @@ const co = require('co'); const Q = require('q'); const _ = require('underscore'); const should = require('should'); -const bma = require('../../app/lib/streams/bma'); +const bma = require('duniter-bma').duniter.methods.bma; const user = require('./tools/user'); const commit = require('./tools/commit'); const sync = require('./tools/sync'); diff --git a/test/integration/revocation-test.js b/test/integration/revocation-test.js index 7ed26cc63..61d39215c 100644 --- a/test/integration/revocation-test.js +++ b/test/integration/revocation-test.js @@ -4,14 +4,11 @@ const _ = require('underscore'); const co = require('co'); const should = require('should'); const duniter = require('../../index'); -const bma = require('../../app/lib/streams/bma'); +const bma = require('duniter-bma').duniter.methods.bma; const user = require('./tools/user'); const rp = require('request-promise'); const httpTest = require('./tools/http'); const commit = require('./tools/commit'); -const limiter = require('../../app/lib/system/limiter'); - -limiter.noLimit(); const expectAnswer = httpTest.expectAnswer; diff --git a/test/integration/server-import-export.js b/test/integration/server-import-export.js index c0372d89e..d00adeb6e 100644 --- a/test/integration/server-import-export.js +++ b/test/integration/server-import-export.js @@ -6,7 +6,7 @@ const co = require('co'); const unzip = require('unzip'); const toolbox = require('../integration/tools/toolbox'); const user = require('../integration/tools/user'); -const bma = require('../../app/lib/streams/bma'); +const bma = require('duniter-bma').duniter.methods.bma; const serverConfig = { memory: false, diff --git a/test/integration/server-sandbox.js b/test/integration/server-sandbox.js index 26c9f5338..e6dc5d9e1 100644 --- a/test/integration/server-sandbox.js +++ b/test/integration/server-sandbox.js @@ -2,14 +2,11 @@ const co = require('co'); const should = require('should'); -const bma = require('../../app/lib/streams/bma'); +const bma = require('duniter-bma').duniter.methods.bma; const user = require('./tools/user'); const commit = require('./tools/commit'); const toolbox = require('./tools/toolbox'); const constants = require('../../app/lib/constants'); -const limiter = require('../../app/lib/system/limiter'); - -limiter.noLimit(); const s1 = toolbox.server({ idtyWindow: 10, diff --git a/test/integration/start_generate_blocks.js b/test/integration/start_generate_blocks.js index 8aebbcdb7..ede15accc 100644 --- a/test/integration/start_generate_blocks.js +++ b/test/integration/start_generate_blocks.js @@ -3,7 +3,7 @@ const co = require('co'); const _ = require('underscore'); const duniter = require('../../index'); -const bma = require('../../app/lib/streams/bma'); +const bma = require('duniter-bma').duniter.methods.bma; const user = require('./tools/user'); const rp = require('request-promise'); const httpTest = require('./tools/http'); diff --git a/test/integration/tests.js b/test/integration/tests.js index d7f019a75..7e81633d6 100644 --- a/test/integration/tests.js +++ b/test/integration/tests.js @@ -4,7 +4,7 @@ const co = require('co'); const _ = require('underscore'); const should = require('should'); const assert = require('assert'); -const bma = require('../../app/lib/streams/bma'); +const bma = require('duniter-bma').duniter.methods.bma; const constants = require('../../app/lib/constants'); const node = require('./tools/node'); const duniter = require('../../index'); @@ -13,9 +13,6 @@ const jspckg = require('../../package'); const commit = require('./tools/commit'); const httpTest = require('./tools/http'); const rp = require('request-promise'); -const limiter = require('../../app/lib/system/limiter'); - -limiter.noLimit(); const expectAnswer = httpTest.expectAnswer; const MEMORY_MODE = true; diff --git a/test/integration/tools/node.js b/test/integration/tools/node.js index fc65b020f..63b2be1ad 100644 --- a/test/integration/tools/node.js +++ b/test/integration/tools/node.js @@ -13,7 +13,7 @@ var Configuration = require('../../../app/lib/entity/configuration'); var Peer = require('../../../app/lib/entity/peer'); var user = require('./user'); var http = require('./http'); -const bma = require('../../../app/lib/streams/bma'); +const bma = require('duniter-bma').duniter.methods.bma; module.exports = function (dbName, options) { return new Node(dbName, options); @@ -146,6 +146,13 @@ function Node (dbName, options) { duniter: { config: { onLoading: (conf, program) => co(function*() { + options.port = options.port || 8999; + options.ipv4 = options.ipv4 || "127.0.0.1"; + options.ipv6 = options.ipv6 || null; + options.remotehost = options.remotehost || null; + options.remoteipv4 = options.remoteipv4 || null; + options.remoteipv6 = options.remoteipv6 || null; + options.remoteport = options.remoteport || 8999; const overConf = Configuration.statics.complete(options); _.extend(conf, overConf); }) diff --git a/test/integration/tools/toolbox.js b/test/integration/tools/toolbox.js index 0a5365381..d899f12b3 100644 --- a/test/integration/tools/toolbox.js +++ b/test/integration/tools/toolbox.js @@ -12,11 +12,14 @@ const until = require('../tools/until'); const Peer = require('../../../app/lib/entity/peer'); const Identity = require('../../../app/lib/entity/identity'); const Block = require('../../../app/lib/entity/block'); -const bma = require('../../../app/lib/streams/bma'); +const bma = require('duniter-bma').duniter.methods.bma; const multicaster = require('../../../app/lib/streams/multicaster'); const network = require('../../../app/lib/system/network'); -const dtos = require('../../../app/lib/streams/dtos'); +const dtos = require('duniter-bma').duniter.methods.dtos; const duniter = require('../../../index'); +const logger = require('../../../app/lib/logger')('toolbox'); + +require('duniter-bma').duniter.methods.noLimit(); // Disables the HTTP limiter const MEMORY_MODE = true; const CURRENCY_NAME = 'duniter_unit_test_currency'; @@ -125,7 +128,7 @@ module.exports = { const fakeServer = yield network.createServersAndListen("Fake Duniter Server", [{ ip: host, port: port - }], NO_HTTP_LOGS, NO_STATIC_PATH, (app, httpMethods) => { + }], NO_HTTP_LOGS, logger, NO_STATIC_PATH, (app, httpMethods) => { // Mock BMA method for sync mocking httpMethods.httpGET('/network/peering', () => { diff --git a/test/integration/transactions-chaining.js b/test/integration/transactions-chaining.js index 6412fde9e..de951f884 100644 --- a/test/integration/transactions-chaining.js +++ b/test/integration/transactions-chaining.js @@ -5,15 +5,12 @@ const _ = require('underscore'); const should = require('should'); const assert = require('assert'); const constants = require('../../app/lib/constants'); -const bma = require('../../app/lib/streams/bma'); +const bma = require('duniter-bma').duniter.methods.bma; const toolbox = require('./tools/toolbox'); const node = require('./tools/node'); const user = require('./tools/user'); const unit = require('./tools/unit'); const http = require('./tools/http'); -const limiter = require('../../app/lib/system/limiter'); - -limiter.noLimit(); describe("Transaction chaining", function() { diff --git a/test/integration/transactions-test.js b/test/integration/transactions-test.js index 70d386a59..e435fbd12 100644 --- a/test/integration/transactions-test.js +++ b/test/integration/transactions-test.js @@ -5,15 +5,13 @@ const _ = require('underscore'); const should = require('should'); const assert = require('assert'); const constants = require('../../app/lib/constants'); -const bma = require('../../app/lib/streams/bma'); +const bma = require('duniter-bma').duniter.methods.bma; const toolbox = require('./tools/toolbox'); const node = require('./tools/node'); const user = require('./tools/user'); const unit = require('./tools/unit'); const http = require('./tools/http'); -const limiter = require('../../app/lib/system/limiter'); -limiter.noLimit(); describe("Testing transactions", function() { diff --git a/test/integration/v0.4-dividend.js b/test/integration/v0.4-dividend.js index fa2b22b89..4cd821459 100644 --- a/test/integration/v0.4-dividend.js +++ b/test/integration/v0.4-dividend.js @@ -2,7 +2,7 @@ const co = require('co'); const should = require('should'); -const bma = require('../../app/lib/streams/bma'); +const bma = require('duniter-bma').duniter.methods.bma; const user = require('./tools/user'); const commit = require('./tools/commit'); const toolbox = require('./tools/toolbox'); diff --git a/test/integration/v0.4-times.js b/test/integration/v0.4-times.js index b8f9a8969..c9f7cc61f 100644 --- a/test/integration/v0.4-times.js +++ b/test/integration/v0.4-times.js @@ -2,7 +2,7 @@ const co = require('co'); const should = require('should'); -const bma = require('../../app/lib/streams/bma'); +const bma = require('duniter-bma').duniter.methods.bma; const commit = require('./tools/commit'); const toolbox = require('./tools/toolbox'); diff --git a/test/integration/v0.5-identity-blockstamp.js b/test/integration/v0.5-identity-blockstamp.js index f861a8b81..3cda20910 100644 --- a/test/integration/v0.5-identity-blockstamp.js +++ b/test/integration/v0.5-identity-blockstamp.js @@ -2,9 +2,8 @@ const co = require('co'); const should = require('should'); -const bma = require('../../app/lib/streams/bma'); +const bma = require('duniter-bma').duniter.methods.bma; const constants = require('../../app/lib/constants'); -const limiter = require('../../app/lib/system/limiter'); const toolbox = require('./tools/toolbox'); const conf = { @@ -20,7 +19,6 @@ describe("Protocol 0.5 Identity blockstamp", function() { before(() => co(function*() { - limiter.noLimit(); const res1 = yield toolbox.simpleNodeWith2Users(conf); const res2 = yield toolbox.simpleNodeWith2otherUsers(conf); s1 = res1.s1; diff --git a/test/integration/v0.5-transactions.js b/test/integration/v0.5-transactions.js index edbf382af..9a3ac5916 100644 --- a/test/integration/v0.5-transactions.js +++ b/test/integration/v0.5-transactions.js @@ -2,9 +2,8 @@ const co = require('co'); const should = require('should'); -const bma = require('../../app/lib/streams/bma'); +const bma = require('duniter-bma').duniter.methods.bma; const constants = require('../../app/lib/constants'); -const limiter = require('../../app/lib/system/limiter'); const toolbox = require('./tools/toolbox'); const conf = { @@ -21,7 +20,6 @@ describe("Protocol 0.5 Transaction version", function() { before(() => co(function*() { - limiter.noLimit(); const res1 = yield toolbox.simpleNodeWith2Users(conf); s1 = res1.s1; const cat = res1.cat; diff --git a/test/integration/v0.6-difficulties.js b/test/integration/v0.6-difficulties.js index 6a217d9f9..64f98bef6 100644 --- a/test/integration/v0.6-difficulties.js +++ b/test/integration/v0.6-difficulties.js @@ -2,9 +2,8 @@ const co = require('co'); const should = require('should'); -const bma = require('../../app/lib/streams/bma'); +const bma = require('duniter-bma').duniter.methods.bma; const constants = require('../../app/lib/constants'); -const limiter = require('../../app/lib/system/limiter'); const toolbox = require('./tools/toolbox'); const conf = { @@ -20,7 +19,6 @@ describe("Protocol 0.6 Difficulties", function() { before(() => co(function*() { - limiter.noLimit(); const res = yield toolbox.simpleNetworkOf2NodesAnd2Users(conf); s1 = res.s1; s2 = res.s2; diff --git a/test/integration/v1.0-source-garbaging.js b/test/integration/v1.0-source-garbaging.js index 70cd2e98d..f38410e35 100644 --- a/test/integration/v1.0-source-garbaging.js +++ b/test/integration/v1.0-source-garbaging.js @@ -2,9 +2,8 @@ const co = require('co'); const should = require('should'); -const bma = require('../../app/lib/streams/bma'); +const bma = require('duniter-bma').duniter.methods.bma; const constants = require('../../app/lib/constants'); -const limiter = require('../../app/lib/system/limiter'); const toolbox = require('./tools/toolbox'); const conf = { @@ -36,7 +35,6 @@ describe("Protocol 1.0 Source Garbaging", function() { before(() => co(function*() { - limiter.noLimit(); const res1 = yield toolbox.simpleNodeWith2Users(conf); s1 = res1.s1; cat = res1.cat; // HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd diff --git a/test/integration/wotb.js b/test/integration/wotb.js index ce3e35e2e..98581d58d 100644 --- a/test/integration/wotb.js +++ b/test/integration/wotb.js @@ -4,7 +4,7 @@ const co = require('co'); const should = require('should'); const _ = require('underscore'); const duniter = require('../../index'); -const bma = require('../../app/lib/streams/bma'); +const bma = require('duniter-bma').duniter.methods.bma; const user = require('./tools/user'); const commit = require('./tools/commit'); -- GitLab