Commit 946896bd authored by Cédric Moreau's avatar Cédric Moreau

Starting on better basis : as a PKS server

parent 39f2bf19
......@@ -23,21 +23,11 @@ function AmendmentBinding (hdcServer) {
// Services
var ParametersService = hdcServer.ParametersService;
var MerkleService = hdcServer.MerkleService;
var VoteService = hdcServer.VoteService;
var StrategyService = hdcServer.StrategyService;
var PeeringService = hdcServer.PeeringService;
var SyncService = hdcServer.SyncService;
var ContractService = hdcServer.ContractService;
// Models
var Amendment = hdcServer.conn.model('Amendment');
var Merkle = hdcServer.conn.model('Merkle');
this.promoted = function (req, res) {
showAmendment(res, ContractService.current());
};
this.promotedNumber = function (req, res) {
async.waterfall([
function (next){
......@@ -57,125 +47,6 @@ function AmendmentBinding (hdcServer) {
});
});
};
this.viewAM = {
signatures: function (req, res) {
amendmentMerkle(req, res, Merkle.signaturesOfAmendment.bind(Merkle), Merkle.mapForSignatures.bind(Merkle));
},
self: function (req, res) {
ParametersService.getAmendmentID(req, function (err, number, hash) {
if(err){
res.send(400, err);
return;
}
async.waterfall([
function (next){
ParametersService.getAmendmentID(req, next);
},
function (number, hash, next){
Amendment.findByNumberAndHash(number, hash, next);
},
], function (err, found) {
if(err){
res.send(404, err);
return;
}
res.setHeader("Content-Type", "text/plain");
res.send(JSON.stringify(found.json(), null, " "));
});
});
}
};
this.votes = {
sigs: function (req, res) {
async.waterfall([
function (next){
ParametersService.getAmendmentID(req, next);
},
function (number, hash, next){
Merkle.signaturesOfAmendment(number, hash, function (err, merkle) {
next(err, merkle, number);
});
},
function (merkle, number, next){
MerkleService.processForURL(req, merkle, async.apply(Merkle.mapForSignatures.bind(Merkle), number), next);
}
], function (err, json) {
if(err){
res.send(400, err);
return;
}
MerkleService.merkleDone(req, res, json);
});
},
get: function (req, res) {
VoteService.votesIndex(function (err, json) {
if(err){
res.send(500, err);
return;
}
if(req.query.nice){
res.setHeader("Content-Type", "text/plain");
res.end(JSON.stringify(json, null, " "));
}
else res.end(JSON.stringify(json));
});
},
post: function (req, res) {
var onError = http400(res);
http2raw.vote(req, onError)
.pipe(unix2dos())
.pipe(parsers.parseVote(onError))
.pipe(versionFilter(onError))
.pipe(currencyFilter(conf.currency, onError))
.pipe(extractSignature(onError))
.pipe(link2pubkey(hdcServer.PublicKeyService, onError))
.pipe(verifySignature(onError))
.pipe(hdcServer.singleWriteStream(onError))
.pipe(jsoner())
.pipe(es.stringify())
.pipe(res);
}
}
}
function amendmentMerkle (req, res, merkleSource, merkleMap) {
ParametersService.getAmendmentID(req, function (err, number, hash) {
if(err){
res.send(400, err);
return;
}
async.waterfall([
function (next){
Amendment.findByNumberAndHash(number, hash, next);
},
], function (err, am) {
if(err){
res.send(404, err);
return;
}
async.waterfall([
function (next){
merkleSource.call(merkleSource, am.number, am.hash, next);
},
function (merkle, next){
MerkleService.processForURL(req, merkle, merkleMap, next);
}
], function (err, json) {
if(err){
res.send(400, err);
return;
}
MerkleService.merkleDone(req, res, json);
});
});
});
}
function showAmendment (res, current) {
......
var jpgp = require('../lib/jpgp');
var async = require('async');
var vucoin = require('vucoin');
var _ = require('underscore');
var es = require('event-stream');
var unix2dos = require('../lib/unix2dos');
var versionFilter = require('../lib/streams/versionFilter');
var currencyFilter = require('../lib/streams/currencyFilter');
var http2raw = require('../lib/streams/parsers/http2raw');
var jsoner = require('../lib/streams/jsoner');
var http400 = require('../lib/http/http400');
var parsers = require('../lib/streams/parsers/doc');
var link2pubkey = require('../lib/streams/link2pubkey');
var extractSignature = require('../lib/streams/extractSignature');
var verifySignature = require('../lib/streams/verifySignature');
var logger = require('../lib/logger')();
var mlogger = require('../lib/logger')('membership');
module.exports = function (wotServer) {
return new KeychainBinding(wotServer);
}
function KeychainBinding (wotServer) {
var that = this;
// Services
var http = wotServer.HTTPService;
var MerkleService = wotServer.MerkleService;
var ParametersService = wotServer.ParametersService;
var PeeringService = wotServer.PeeringService;
var SyncService = wotServer.SyncService;
var ContractService = wotServer.ContractService;
// Models
var Peer = wotServer.conn.model('Peer');
var Forward = wotServer.conn.model('Forward');
var Membership = wotServer.conn.model('Membership');
var PublicKey = wotServer.conn.model('PublicKey');
var Merkle = wotServer.conn.model('Merkle');
var Key = wotServer.conn.model('Key');
this.parseMembership = function (req, res) {
var onError = http400(res);
http2raw.membership(req, onError)
.pipe(unix2dos())
.pipe(parsers.parseMembership(onError))
.pipe(versionFilter(onError))
.pipe(currencyFilter(conf.currency, onError))
.pipe(extractSignature(onError))
.pipe(link2pubkey(wotServer.PublicKeyService, onError))
.pipe(verifySignature(onError))
.pipe(wotServer.singleWriteStream(onError))
.pipe(jsoner())
.pipe(es.stringify())
.pipe(res);
};
this.parseKeyblock = function (req, res) {
res.end(503);
}
this.current = function (req, res) {
res.end(503);
}
}
var jpgp = require('../lib/jpgp');
var async = require('async');
var vucoin = require('vucoin');
var _ = require('underscore');
var es = require('event-stream');
var unix2dos = require('../lib/unix2dos');
var versionFilter = require('../lib/streams/versionFilter');
var currencyFilter = require('../lib/streams/currencyFilter');
var http2raw = require('../lib/streams/parsers/http2raw');
var jsoner = require('../lib/streams/jsoner');
var http400 = require('../lib/http/http400');
var parsers = require('../lib/streams/parsers/doc');
var link2pubkey = require('../lib/streams/link2pubkey');
var extractSignature = require('../lib/streams/extractSignature');
var verifySignature = require('../lib/streams/verifySignature');
var logger = require('../lib/logger')();
var mlogger = require('../lib/logger')('membership');
var vlogger = require('../lib/logger')('voting');
module.exports = function (registryServer, conf) {
return new RegistryBinding(registryServer, conf);
};
function RegistryBinding (registryServer, conf) {
var that = this;
// Services
var http = registryServer.HTTPService;
var MerkleService = registryServer.MerkleService;
var ParametersService = registryServer.ParametersService;
var PeeringService = registryServer.PeeringService;
var SyncService = registryServer.SyncService;
var ContractService = registryServer.ContractService;
// Models
var Peer = registryServer.conn.model('Peer');
var Forward = registryServer.conn.model('Forward');
var Amendment = registryServer.conn.model('Amendment');
var Membership = registryServer.conn.model('Membership');
var Voting = registryServer.conn.model('Voting');
var PublicKey = registryServer.conn.model('PublicKey');
var Merkle = registryServer.conn.model('Merkle');
var Key = registryServer.conn.model('Key');
this.parameters = function (req, res) {
res.end(JSON.stringify({
AMStart: conf.sync.AMStart,
AMFrequency: conf.sync.AMFreq,
UDFrequency: conf.sync.UDFreq,
UD0: conf.sync.UD0,
UDPercent: conf.sync.UDPercent,
UDMinCoin: conf.sync.UDMinCoin,
Consensus: conf.sync.Consensus
}, null, " "));
};
this.membershipPost = function (req, res) {
var onError = http400(res);
http2raw.membership(req, onError)
.pipe(unix2dos())
.pipe(parsers.parseMembership(onError))
.pipe(versionFilter(onError))
.pipe(currencyFilter(conf.currency, onError))
.pipe(extractSignature(onError))
.pipe(link2pubkey(registryServer.PublicKeyService, onError))
.pipe(verifySignature(onError))
.pipe(registryServer.singleWriteStream(onError))
.pipe(jsoner())
.pipe(es.stringify())
.pipe(res);
};
this.membershipCurrent = function (req, res) {
var that = this;
async.waterfall([
// Parameters
function(next){
ParametersService.getFingerprint(req, next);
},
function (fingerprint, next) {
Membership.getCurrent(fingerprint, next);
}
], function (err, ms) {
if (!ms) {
res.send(404, "Not found");
return;
}
http.answer(res, 400, err, function () {
res.end(JSON.stringify(ms.json(), null, " "));
});
});
};
this.membershipHistory = function (req, res) {
var that = this;
async.waterfall([
// Parameters
function(next){
ParametersService.getFingerprint(req, next);
},
function (fingerprint, next) {
Membership.getHistory(fingerprint, next);
}
], function (err, history) {
var list = [];
history.forEach(function(ms){
list.push(ms.json());
});
http.answer(res, 400, err, function () {
res.end(JSON.stringify(list, null, " "));
});
});
};
this.votingPost = function (req, res) {
var onError = http400(res);
http2raw.voting(req, onError)
.pipe(unix2dos())
.pipe(parsers.parseVoting(onError))
.pipe(versionFilter(onError))
.pipe(currencyFilter(conf.currency, onError))
.pipe(extractSignature(onError))
.pipe(link2pubkey(registryServer.PublicKeyService, onError))
.pipe(verifySignature(onError))
.pipe(registryServer.singleWriteStream(onError))
.pipe(jsoner())
.pipe(es.stringify())
.pipe(res);
};
this.votingCurrent = function (req, res) {
var that = this;
async.waterfall([
// Parameters
function(next){
ParametersService.getFingerprint(req, next);
},
function (fingerprint, next) {
Voting.getCurrent(fingerprint, next);
}
], function (err, voting) {
if (!voting) {
res.send(404, "Not found");
return;
}
http.answer(res, 400, err, function () {
res.end(JSON.stringify(voting.json(), null, " "));
});
});
};
this.votingHistory = function (req, res) {
var that = this;
async.waterfall([
// Parameters
function(next){
ParametersService.getFingerprint(req, next);
},
function (fingerprint, next) {
Voting.getHistory(fingerprint, next);
}
], function (err, history) {
var list = [];
history.forEach(function(voting){
list.push(voting.json());
});
http.answer(res, 400, err, function () {
res.end(JSON.stringify(list, null, " "));
});
});
};
this.membersIn = function (req, res) {
processMerkle(Merkle.membersIn.bind(Merkle), Merkle.mapForMemberships.bind(Merkle), req, res);
};
this.membersOut = function (req, res) {
processMerkle(Merkle.membersOut.bind(Merkle), Merkle.mapForMemberships.bind(Merkle), req, res);
};
this.votersIn = function (req, res) {
processMerkle(Merkle.votersIn.bind(Merkle), Merkle.mapForVotings.bind(Merkle), req, res);
};
this.votersOut = function (req, res) {
processMerkle(Merkle.votersOut.bind(Merkle), Merkle.mapForVotings.bind(Merkle), req, res);
};
this.statementPost = function (req, res) {
var onError = http400(res);
http2raw.communityFlow(req, onError)
.pipe(unix2dos())
.pipe(parsers.parseStatement(onError))
.pipe(versionFilter(onError))
.pipe(currencyFilter(conf.currency, onError))
.pipe(extractSignature(onError))
.pipe(link2pubkey(registryServer.PublicKeyService, onError))
.pipe(verifySignature(onError))
.pipe(registryServer.singleWriteStream(onError))
.pipe(jsoner())
.pipe(es.stringify())
.pipe(res);
};
function processMerkle (getMerkle, mapMerkle, req, res) {
var that = this;
async.waterfall([
function (next) {
ParametersService.getAmendmentNumberAndAlgo(req, next);
},
function (number, algo, next){
getMerkle(number, algo, next);
},
function (merkle, next){
MerkleService.processForURL(req, merkle, mapMerkle, next);
}
], function (err, json) {
if(err){
res.send(400, err);
return;
}
MerkleService.merkleDone(req, res, json);
});
}
this.askSelf = function (req, res) {
async.waterfall([
function (next){
ParametersService.getAmendmentNumberAndAlgo(req, next);
},
function (amNumber, algo, next){
Amendment.getTheOneToBeVoted(amNumber, algo, next);
},
], function (err, am) {
http.answer(res, 404, err, function () {
// Render the amendment
res.end(JSON.stringify(am.json(), null, " "));
});
});
};
this.askStatement = function (req, res) {
var that = this;
async.waterfall([
// Parameters
function(next){
ParametersService.getAmendmentNumberAndAlgo(req, next);
},
function (amNumber, algo, next) {
SyncService.getStatement(parseInt(amNumber), algo, next)
},
], function (err, cf, am) {
http.answer(res, 404, err, function () {
res.end(JSON.stringify({
"statement": cf.json()
}, null, " "));
});
});
};
this.askVote = function (req, res) {
var that = this;
async.waterfall([
// Parameters
function(next){
ParametersService.getAmendmentNumberAndAlgo(req, next);
},
function (amNumber, algo, next) {
SyncService.getVote(amNumber, algo, next);
},
function (vote, next){
vote.getAmendment(function (err, am) {
next(err, vote, am);
});
},
], function (err, vote, am) {
http.answer(res, 404, err, function () {
res.end(JSON.stringify({
"issuer": vote.issuer,
"amendment": am.json(),
"signature": vote.signature
}, null, " "));
});
});
};
}
var async = require('async');
var common = require('./common');
var hexstrdump = require('../../hexstrdump');
var jpgp = require('../../jpgp');
var parsers = require('../../streams/parsers/doc');
module.exports = function (isMemberFunc, getPubkeyFunc) {
return function (pkey, ctx, amNext, done) {
async.waterfall([
function (next){
parsers.parsePubkey(next).asyncWrite(pkey.raw, next);
},
function (betterPubkey, next) {
async.detect(betterPubkey.udid2s, function (udid2, cb) {
var nbMatching = 0;
async.forEach(udid2.signatures || [], function (certification, cb2) {
var issuer = hexstrdump(certification.issuerKeyId.bytes).toUpperCase();
async.waterfall([
function (next){
getPubkeyFunc(issuer, next);
},
function (issuerPubkey, next){
isMemberFunc(issuerPubkey.fingerprint, function (err, isOK) {
next(err || (!isOK && "Signatory is not a member"), issuerPubkey);
});
},
function (issuerPubkey, next) {
var certSignatory = jpgp().certificate(issuerPubkey.raw);
var certOwner = jpgp().certificate(pkey.raw);
var verified = certification.verify(certSignatory.key.primaryKey, { userid: udid2.user.userId, key: certOwner.key.primaryKey });
next((!verified && "Certification verification gives FALSE") || null, verified);
}
], function (err, verified) {
if (verified) nbMatching++;
cb2(err);
});
}, function (err) {
cb(nbMatching >= 1);
});
}, function (detected) {
if (detected != undefined)
next(null, { nbVerifiedSigs: 1 });
else
next(null, { nbVerifiedSigs: 0 });
});
},
function (virtualPubkey, next){
common.computeIndicators(virtualPubkey, ctx, amNext, context2AnalyticalMembership, context2AnalyticalVoting, next);
},
], done);
};
}
var VTExpires = 3600*24*14; // Every 14 days
/**
* Converts member context vars to analytical expression parameters (for computing functions' namespace)
*/
function context2AnalyticalMembership (pubkey, context, done) {
var ctx = context || { currentMembership: null, nextMembership: null };
var isMember = ctx.currentMembership && ctx.currentMembership.membership == 'IN';
var ms = [
isMember ? 1 : 0,
!isMember ? 1 : 0,
];
var hasInvalidKey = (pubkey.nbVerifiedSigs || 0) < 1;
var hasNextIn = ctx