From f7490c821fd18a83aadab0f40168583ad1003ac1 Mon Sep 17 00:00:00 2001
From: cgeek <cem.moreau@gmail.com>
Date: Sun, 17 Aug 2014 13:58:41 +0200
Subject: [PATCH] Accepting FOUNDER keychanges (for root keyblock)

---
 app/lib/keyhelper.js           |  18 ++++++
 app/models/key.js              |   2 +-
 app/models/keyblock.js         |  31 +++++----
 app/models/trustedkey.js       |  29 +++++++++
 app/service/KeychainService.js | 112 ++++++++++++++++++---------------
 server.js                      |   3 +-
 wotserver.js                   |   2 +-
 7 files changed, 131 insertions(+), 66 deletions(-)
 create mode 100644 app/models/trustedkey.js

diff --git a/app/lib/keyhelper.js b/app/lib/keyhelper.js
index 45c7d832b..cac605134 100644
--- a/app/lib/keyhelper.js
+++ b/app/lib/keyhelper.js
@@ -4,10 +4,24 @@ var PacketList = openpgp.packet.List;
 
 module.exports = {
 
+  fromKey: function (key){
+    return new KeyHelper(key.toPacketlist());
+  },
+
   fromPackets: function (packetList){
     return new KeyHelper(packetList);
   },
 
+  fromEncodedPackets: function (encodedPackets){
+    return this.fromDecodedPackets(base64.decode(encodedPackets));
+  },
+
+  fromDecodedPackets: function (decodedPackets){
+    var list = new openpgp.packet.List();
+    list.read(decodedPackets);
+    return new KeyHelper(list);
+  },
+
   fromArmored: function (armored){
     var readKeys = openpgp.key.readArmored(armored).keys;
     var packets = new PacketList();
@@ -26,6 +40,10 @@ function KeyHelper (packetList) {
   var that = this;
   var key = new openpgp.key.Key(packetList);
 
+  this.getFingerprint = function (){
+    return key && key.primaryKey && key.primaryKey.getFingerprint().toUpperCase();
+  };
+
   this.getUserID = function (param, next){
     var primaryUser = key.getPrimaryUser();
     return primaryUser && primaryUser.user && primaryUser.user.userId && primaryUser.user.userId.userid;
diff --git a/app/models/key.js b/app/models/key.js
index 24a42e23e..d8cb81004 100644
--- a/app/models/key.js
+++ b/app/models/key.js
@@ -124,7 +124,7 @@ KeySchema.statics.setKicked = function(fingerprint, done){
   });
 };
 
-KeySchema.statics.removeKicked = function(fingerprint, done){
+KeySchema.statics.unsetKicked = function(fingerprint, done){
   var Key = this.model('Key');
   Key.update({ fingerprint: fingerprint }, { kick: false }, function (err) {
     done(err);
diff --git a/app/models/keyblock.js b/app/models/keyblock.js
index ce98f4278..60468f382 100644
--- a/app/models/keyblock.js
+++ b/app/models/keyblock.js
@@ -70,6 +70,16 @@ KeyBlockSchema.methods = {
     return json;
   },
 
+  getNewPubkeys: function() {
+    var pubkeys = [];
+    this.keysChanges.forEach(function(kc){
+      if (kc.type == 'F' || kc.type == 'N') {
+        pubkeys.push(kc.keypackets);
+      }
+    });
+    return pubkeys;
+  },
+
   getPublicKeysPackets: function() {
     var pubkeys = [];
     this.publicKeys.forEach(function(obj){
@@ -197,8 +207,15 @@ KeyBlockSchema.methods = {
   getMemberships: function() {
     var notFoundMembership = 0;
     var mss = {};
-    this.memberships.forEach(function(shortMS){
+    this.keysChanges.forEach(function(kc){
+      var shortSIG = kc.membership.signature;
+      var shortMS = kc.membership.membership;
+      // Membership content
       var sp = shortMS.split(':');
+      // Signature
+      var signature = '-----BEGIN PGP SIGNATURE-----\nVersion: GnuPG v1\n\n';
+      signature += shortSIG;
+      signature += '-----END PGP SIGNATURE-----\n';
       var ms = {
         version: sp[0],
         keyID: sp[1].substring(24),
@@ -206,20 +223,10 @@ KeyBlockSchema.methods = {
         membership: sp[2],
         date: new Date(parseInt(sp[3])*1000),
         userid: sp[4],
+        signature: signature
       };
       mss[ms.keyID] = ms;
     });
-    this.membershipsSigs.forEach(function(msSig){
-      var keyID = msSig.fingerprint.substring(24);
-      if (mss[keyID]) {
-        var signature = '-----BEGIN PGP SIGNATURE-----\nVersion: GnuPG v1\n\n';
-        signature += msSig.packets;
-        signature += '-----END PGP SIGNATURE-----\n';
-        mss[keyID].signature = signature;
-        mss[keyID].issuer = msSig.fingerprint;
-      }
-      else notFoundMembership++;
-    });
     return {
       'notFoundMembership': notFoundMembership,
       'mss': mss
diff --git a/app/models/trustedkey.js b/app/models/trustedkey.js
new file mode 100644
index 000000000..0771b03d3
--- /dev/null
+++ b/app/models/trustedkey.js
@@ -0,0 +1,29 @@
+var mongoose = require('mongoose');
+var Schema   = mongoose.Schema;
+
+var TrustedKeySchema = new Schema({
+  keyID: { type: String, unique: true },
+  fingerprint: String,
+  uid: String,
+  packets: String,
+  created: { type: Date, default: Date.now },
+  updated: { type: Date, default: Date.now }
+});
+
+TrustedKeySchema.pre('save', function (next) {
+  this.updated = Date.now();
+  next();
+});
+
+TrustedKeySchema.statics.getTheOne = function (keyID, done) {
+  this.find({ keyID: keyID }, function (err, keys) {
+    if(keys.length < 1){
+      done('Trusted Key 0x' + keyID + ' not found.');
+      return;
+    }
+    var pubkey = keys[0];
+    done(null, pubkey);
+  });
+};
+
+module.exports = TrustedKeySchema;
diff --git a/app/service/KeychainService.js b/app/service/KeychainService.js
index a9830f12f..9a6a6bcea 100644
--- a/app/service/KeychainService.js
+++ b/app/service/KeychainService.js
@@ -22,6 +22,7 @@ function KeyService (conn, conf, PublicKeyService) {
   var Membership = conn.model('Membership');
   var KeyBlock   = conn.model('KeyBlock');
   var PublicKey  = conn.model('PublicKey');
+  var TrustedKey = conn.model('TrustedKey');
   var Link       = conn.model('Link');
   var Key        = conn.model('Key');
 
@@ -136,13 +137,12 @@ function KeyService (conn, conf, PublicKeyService) {
       },
       function (next) {
         // Check document's coherence
-      //   checkCoherence(currentBlock, block, next);
-      // },
-      // function (next) {
+        checkCoherence(currentBlock, block, next);
+      },
+      function (next) {
         // Save block data + compute links obsolescence
-        console.log('OK');
-        next(null, block);
-        // saveBlockData(block, next);
+        // next(null, block);
+        saveBlockData(block, next);
       }
     ], done);
   };
@@ -154,12 +154,8 @@ function KeyService (conn, conf, PublicKeyService) {
         checkKicked(block, next);
       },
       function (next){
-        // Check memberships
-        checkMemberships(current, block, next);
-      },
-      function (next){
-        // Check certifications updates
-        checkCertificationsUpdates(block, next);
+        // Check key changes
+        checkKeychanges(current, block, next);
       },
       function (next){
         // Check members' changes (+ and -), root & count
@@ -170,6 +166,20 @@ function KeyService (conn, conf, PublicKeyService) {
     });
   }
 
+  function checkKeychanges (current, block, done) {
+    if (current) {
+      done('Post-root blocks are not managed yet');
+    } else {
+      checkRootBlockKeychanges(block, done);
+    }
+  }
+
+  function checkRootBlockKeychanges(block, done) {
+    async.forEach(block.keysChanges, function(kc, callback){
+      callback(kc.type != 'F' ? 'Root block must contain only FOUNDER keychanges' : null);
+    }, done);
+  }
+
   function checkMemberships (current, block, done) {
     // Test membership
     var basicPubkeys = block.getBasicPublicKeys();
@@ -432,15 +442,15 @@ function KeyService (conn, conf, PublicKeyService) {
   }
 
   function updateMembers (block, done) {
-    var mss = block.getMemberships().mss;
-    async.forEach(_(mss).values(), function(ms, callback){
-      var doMember = ms.membership == 'IN' ? Key.addMember : Key.removeMember;
+    async.forEach(block.membersChanges, function(mc, callback){
+      var isPlus = mc[0] == '+';
+      var fpr = mc.substring(1);
       async.waterfall([
         function (next){
-          doMember.call(Key, ms.fingerprint, next);
+          (isPlus ? Key.addMember : Key.removeMember).call(Key, fpr, next);
         },
         function (next) {
-          Key.removeKicked(ms.fingerprint, next);
+          Key.unsetKicked(fpr, next);
         }
       ], callback);
     }, done);
@@ -460,21 +470,19 @@ function KeyService (conn, conf, PublicKeyService) {
       },
       function (next){
         // Save new pubkeys
-        var pubkeys = block.getBasicPublicKeys();
-        async.forEach(pubkeys, function(key, callback){
-          var armored = unix2dos(key.armor());
-          var parser = parsers.parsePubkey(next);
-          async.waterfall([
-            function (next){
-              parser.asyncWrite(armored, next);
-            },
-            function (json, next) {
-              json.keychain = base64.encode(key.toPacketlist().write());
-              PublicKeyService.submitPubkey(json, function (err) {
-                next(err);
-              });
-            },
-          ], callback);
+        var pubkeys = block.getNewPubkeys();
+        async.forEach(pubkeys, function(encodedPackets, callback){
+          var key = keyhelper.fromEncodedPackets(encodedPackets);
+          var fpr = key.getFingerprint();
+          var kid = fpr.substring(24);
+          var trusted = new TrustedKey({
+            fingerprint: fpr,
+            keyID: kid,
+            packets: encodedPackets
+          });
+          trusted.save(function (err){
+            callback(err);
+          });
         }, next);
       },
       function (next){
@@ -483,24 +491,25 @@ function KeyService (conn, conf, PublicKeyService) {
       },
       function (next){
         // Save links
-        var certifs = block.getTierCertificationPackets();
-        async.forEach(certifs, function(certif, callback){
-          async.waterfall([
-            function (next){
-              PublicKey.getTheOne(certif.issuerKeyId.toHex().toUpperCase(), next);
-            },
-            function (pubk, next){
-              var link = new Link({
-                source: pubk.fingerprint,
-                target: certif.target,
-                timestamp: certif.created.timestamp()
-              });
-              link.save(function (err) {
-                next(err);
-              });
-            },
-          ], callback);
-        }, next);
+        next();
+        // var certifs = block.getTierCertificationPackets();
+        // async.forEach(certifs, function(certif, callback){
+        //   async.waterfall([
+        //     function (next){
+        //       PublicKey.getTheOne(certif.issuerKeyId.toHex().toUpperCase(), next);
+        //     },
+        //     function (pubk, next){
+        //       var link = new Link({
+        //         source: pubk.fingerprint,
+        //         target: certif.target,
+        //         timestamp: certif.created.timestamp()
+        //       });
+        //       link.save(function (err) {
+        //         next(err);
+        //       });
+        //     },
+        //   ], callback);
+        // }, next);
       },
       function (next){
         // Save memberships
@@ -511,7 +520,8 @@ function KeyService (conn, conf, PublicKeyService) {
       },
       function (next){
         // Compute obsolete links
-        computeObsoleteLinks(block, next);
+        next();
+        // computeObsoleteLinks(block, next);
       },
     ], function (err) {
       done(err, block);
diff --git a/server.js b/server.js
index 58c0edb1a..69b030dbf 100644
--- a/server.js
+++ b/server.js
@@ -10,7 +10,7 @@ var http       = require('http');
 var log4js     = require('log4js');
 var connectPgp = require('connect-pgp');
 
-var models = ['Amendment', 'Coin', 'Configuration', 'Forward', 'Key', 'Link', 'CKey', 'Merkle', 'Peer', 'PublicKey', 'Wallet', 'Transaction', 'TxMemory', 'Membership', 'KeyBlock'];
+var models = ['Amendment', 'Coin', 'Configuration', 'Forward', 'Key', 'Link', 'TrustedKey', 'Merkle', 'Peer', 'PublicKey', 'Wallet', 'Transaction', 'TxMemory', 'Membership', 'KeyBlock'];
 var INNER_WRITE = true;
 
 function Server (dbConf, overrideConf, interceptors, onInit) {
@@ -175,6 +175,7 @@ function Server (dbConf, overrideConf, interceptors, onInit) {
           'wallets',
           'transactions',
           'txmemories',
+          'trustedkeys',
           'memberships'];
         async.forEachSeries(deletableCollections, function(collection, next){
           if (that.conn.collections[collection]) {
diff --git a/wotserver.js b/wotserver.js
index f22380d8c..a7df37c8b 100644
--- a/wotserver.js
+++ b/wotserver.js
@@ -35,7 +35,7 @@ function WOTServer (dbConf, overrideConf, interceptors, onInit) {
             server.KeychainService.submitKeyBlock(obj, next);
           },
           function (tx, next){
-            server.emit('transaction', tx);
+            server.emit('keyblock', tx);
             next(null, tx);
           },
         ], next);
-- 
GitLab