From d889410923866fdd55c4b7bef7e569bfd788c0f0 Mon Sep 17 00:00:00 2001 From: cgeek Date: Sun, 24 Aug 2014 11:23:04 +0200 Subject: [PATCH] Add gen-updates command --- app/models/key.js | 5 ++ app/models/publickey.js | 17 ++++++ app/service/KeychainService.js | 106 ++++++++++++++++++++++++++++----- bin/ucoind | 5 ++ 4 files changed, 117 insertions(+), 16 deletions(-) diff --git a/app/models/key.js b/app/models/key.js index 07b2ec98..8be32132 100644 --- a/app/models/key.js +++ b/app/models/key.js @@ -124,6 +124,11 @@ KeySchema.statics.findMembersWhereSignatory = function(signatory, done){ Key.find({ member: true, signatories: new RegExp(signatory.substring(24) + '$') }, done); }; +KeySchema.statics.findMembersWithUpdates = function(done){ + var Key = this.model('Key'); + Key.find({ member: true, $or: [ {signatories: { $not: { $size: 0 }}}, { subkeys: { $not: { $size: 0 }}}] }, done); +}; + KeySchema.statics.addMember = function(fingerprint, done){ var Key = this.model('Key'); Key.update({ fingerprint: fingerprint }, { member: true }, function (err) { diff --git a/app/models/publickey.js b/app/models/publickey.js index 1707c939..7f1e2e67 100644 --- a/app/models/publickey.js +++ b/app/models/publickey.js @@ -128,6 +128,23 @@ PublicKeySchema.methods = { if (hashedCertifs[md5hash]) { var decoded = base64.decode(hashedCertifs[md5hash]); var otherList = new openpgp.packet.List(); + // Should read a 1 packet list (signature) + otherList.read(decoded); + packets.concat(otherList); + } + }); + return packets; + }, + + getSubkeysFromMD5List: function (md5array){ + var packets = new openpgp.packet.List(); + var key = keyhelper.fromArmored(this.raw); + var hashedSubkeys = key.getHashedSubkeyPackets(); + md5array.forEach(function(md5hash){ + if (hashedSubkeys[md5hash]) { + var decoded = base64.decode(hashedSubkeys[md5hash]); + var otherList = new openpgp.packet.List(); + // Should read a 2 packets list (subkey + binding signature) otherList.read(decoded); packets.concat(otherList); } diff --git a/app/service/KeychainService.js b/app/service/KeychainService.js index c9f1ddaa..cc05f5b9 100644 --- a/app/service/KeychainService.js +++ b/app/service/KeychainService.js @@ -267,8 +267,8 @@ function KeyService (conn, conf, PublicKeyService) { async.parallel({ certifications: function(callback){ // Check certifications + kc.certifiers = []; async.forEach(keyhelper.toPacketlist(kc.certpackets), function(certif, callback2){ - kc.certifiers = []; async.waterfall([ function (next){ checkCertificationOfKey(certif, kc.fingerprint, newKeys, next); @@ -330,8 +330,8 @@ function KeyService (conn, conf, PublicKeyService) { // TODO: check subkeys? // Check certifications + kc.certifiers = []; async.forEach(keyhelper.toPacketlist(kc.certpackets), function(certif, callback){ - kc.certifiers = []; async.waterfall([ function (next){ checkCertificationOfKey(certif, kc.fingerprint, newKeys, next); @@ -725,6 +725,67 @@ function KeyService (conn, conf, PublicKeyService) { done(null, block); } + /** + * Generate a "newcomers" keyblock + */ + this.generateUpdates = function (done) { + var updates = {}; + var subupdates = {}; + async.waterfall([ + function (next){ + Key.findMembersWithUpdates(next); + }, + function (members, next){ + async.forEachSeries(members, function(member, callback){ + var fpr = member.fingerprint; + async.waterfall([ + function (next){ + PublicKey.getTheOne(fpr, next); + }, + function (pubkey, next){ + var key = pubkey.getKey(); + var finalPackets = new openpgp.packet.List(); + var certifs = pubkey.getCertificationsFromMD5List(member.certifs); + var subkeys = pubkey.getSubkeysFromMD5List(member.subkeys); + if (subkeys.length > 0) { + subupdates[fpr] = subkeys; + } + async.forEachSeries(certifs, function(certif, callback){ + var issuerKeyId = certif.issuerKeyId.toHex().toUpperCase(); + async.waterfall([ + function (next){ + TrustedKey.getTheOne(issuerKeyId, next); + }, + function (trusted, next){ + // Issuer is a member + finalPackets.push(certif); + next(); + }, + ], function (err) { + // Issuer is not a member + callback(); + }); + }, function(err){ + if (finalPackets.length > 0) { + updates[fpr] = finalPackets; + } + next(); + }); + }, + ], callback); + }, next); + }, + function (next){ + KeyBlock.current(function (err, current) { + next(null, current || null); + }); + }, + function (current, next){ + createNewcomerBlock(current, null, {}, updates, subupdates, next); + }, + ], done); + } + /** this.generateNewcomers = function (done) { * Generate a "newcomers" keyblock @@ -922,7 +983,7 @@ function KeyService (conn, conf, PublicKeyService) { updates[signedFPR] = keptCertifs; }); // Create the block - createNewcomerBlock(current, wotMembers.concat(realNewcomers), finalJoinData, updates, next); + createNewcomerBlock(current, wotMembers.concat(realNewcomers), finalJoinData, updates, {}, next); }, ], done); }; @@ -997,7 +1058,7 @@ function KeyService (conn, conf, PublicKeyService) { return matched; } - function createNewcomerBlock (current, members, joinData, updates, done) { + function createNewcomerBlock (current, members, joinData, updates, subupdates, done) { var block = new KeyBlock(); block.version = 1; block.currency = current ? current.currency : conf.currency; @@ -1005,14 +1066,24 @@ function KeyService (conn, conf, PublicKeyService) { block.previousHash = current ? current.hash : ""; block.previousIssuer = current ? current.issuer : ""; // Members merkle - members.sort(); - var tree = merkle(members, 'sha1').process(); - block.membersCount = members.length; - block.membersRoot = tree.root(); - block.membersChanges = []; - _(joinData).keys().forEach(function(fpr){ - block.membersChanges.push('+' + fpr); - }); + if (members) { + members.sort(); + var tree = merkle(members, 'sha1').process(); + block.membersCount = members.length; + block.membersRoot = tree.root(); + block.membersChanges = []; + _(joinData).keys().forEach(function(fpr){ + block.membersChanges.push('+' + fpr); + }); + } else if (!members && current) { + // No members changes + block.membersCount = current.membersCount; + block.membersRoot = current.membersRoot; + block.membersChanges = []; + } else { + done('Wrong new block: cannot make a root block without members'); + return; + } // Keychanges - newcomers block.keysChanges = []; _(joinData).values().forEach(function(join){ @@ -1029,13 +1100,16 @@ function KeyService (conn, conf, PublicKeyService) { }); }); // Keychanges - updates: signatures from newcomers - _(updates).keys().forEach(function(fpr){ - if (updates[fpr].length > 0) { + var updateKeys = _(updates).keys(); + var subkeyKeys = _(subupdates).keys(); + var allUpdates = _(updateKeys.concat(subkeyKeys)).uniq(); + allUpdates.forEach(function(fpr){ + if ((updates[fpr] && updates[fpr].length > 0) || (subupdates[fpr] && subupdates[fpr].length > 0)) { block.keysChanges.push({ type: 'U', fingerprint: fpr, - keypackets: '', - certpackets: base64.encode(updates[fpr].write()), + keypackets: subupdates[fpr] ? base64.encode(subupdates[fpr].write()) : '', + certpackets: updates[fpr] ? base64.encode(updates[fpr].write()) : '', membership: {} }); } diff --git a/bin/ucoind b/bin/ucoind index cc710765..bf896ee1 100755 --- a/bin/ucoind +++ b/bin/ucoind @@ -226,6 +226,11 @@ program .description('Tries to generate the next keyblock of the keychain without any changes') .action(service(DO_NOT_LISTEN_HTTP, ucoin.createWOTServer, generateAndSend("generateEmptyNext"))); +program + .command('gen-updates [host] [port] [difficulty]') + .description('Tries to generate an update (#2+) keyblock, containing only update changes') + .action(service(DO_NOT_LISTEN_HTTP, ucoin.createWOTServer, generateAndSend("generateUpdates"))); + program .command('gen-newcomers [host] [port] [difficulty]') .description('Tries to generate a newcomers (#2+) keyblock, containing only newcomers changes') -- 2.22.0