From 99a7b8f69cb719309e440089244a130f592bc403 Mon Sep 17 00:00:00 2001
From: cgeek <cem.moreau@gmail.com>
Date: Tue, 5 Aug 2014 00:00:32 +0200
Subject: [PATCH] PublicKey: now parses pubkey and remember eligible packets

---
 app/lib/keyhelper.js    | 78 +++++++++++++++++++++++++++++++++++++++++
 app/lib/md5.js          |  7 ++++
 app/models/publickey.js | 25 +++++++++++++
 3 files changed, 110 insertions(+)
 create mode 100644 app/lib/keyhelper.js
 create mode 100644 app/lib/md5.js

diff --git a/app/lib/keyhelper.js b/app/lib/keyhelper.js
new file mode 100644
index 000000000..4920ecf8b
--- /dev/null
+++ b/app/lib/keyhelper.js
@@ -0,0 +1,78 @@
+var openpgp    = require('openpgp');
+var base64     = require('./base64');
+var PacketList = openpgp.packet.List;
+
+module.exports = {
+
+  fromPackets: function (packetList){
+    return new KeyHelper(packetList);
+  },
+
+  fromArmored: function (armored){
+    var readKeys = openpgp.key.readArmored(asciiArmored).keys;
+    var packets = new PacketList();
+    if(readKeys.length == 1){
+      packets = readKeys[0].toPacketList();
+    }
+    return new KeyHelper(packets);
+  }
+};
+
+var UDID2_FORMAT = /udid2;c;/;
+// var UDID2_FORMAT = /\(udid2;c;([A-Z-]*);([A-Z-]*);(\d{4}-\d{2}-\d{2});(e\+\d{2}\.\d{2}-\d{3}\.\d{2});(\d+)(;?)\)/;
+
+function KeyHelper (packetList) {
+
+  var that = this;
+  var key = new openpgp.key.Key(packetList);
+
+  this.getUserID = function (param, next){
+    var primaryUser = key.getPrimaryUser();
+    return primaryUser && primaryUser.user && primaryUser.user.userId && primaryUser.user.userId.userid;
+  };
+
+  this.hasValidUdid2 = function (param, next){
+    var userid = that.getUserID();
+    return userid != null && userid.match(UDID2_FORMAT);
+  };
+
+  this.getBase64publicKey = function (){
+    return key.getKeyPacket() && base64.encode(key.getKeyPacket().write());
+  };
+
+  this.getBase64primaryUser = function (){
+    var primaryUser = key.getPrimaryUser();
+    var packets = new PacketList();
+    if (primaryUser) {
+      packets.push(primaryUser.user.userId);
+      packets.push(primaryUser.selfCertificate);
+    }
+    return primaryUser && base64.encode(packets.write());
+  };
+
+  this.getBase64primaryUserOtherCertifications = function (){
+    var primaryUser = key.getPrimaryUser();
+    var certifs = [];
+    if (primaryUser) {
+      (primaryUser.user.otherCertifications || []).forEach(function(oCert){
+        certifs.push(base64.encode(oCert.write()));
+        // oCert.verify(key, { userid: primaryUser.user.userId, key: key }))) {
+      });
+    }
+    return certifs;
+  };
+
+  // Give base64 encoded signing subkey packets (subkey + binding)
+  this.getBase64subkeys = function (){
+    var bSubkeys = [];
+    (key.subKeys || []).forEach(function(subkeyWrapper){
+      if (subkeyWrapper.isValidSigningKey(key) || subkeyWrapper.isValidEncryptionKey(key)) {
+        var packets = new PacketList();
+        packets.push(subkeyWrapper.subKey);
+        packets.push(subkeyWrapper.bindingSignature);
+        bSubkeys.push(base64.encode(packets.write()));
+      }
+    });
+    return bSubkeys;
+  };
+}
diff --git a/app/lib/md5.js b/app/lib/md5.js
new file mode 100644
index 000000000..cba0ee329
--- /dev/null
+++ b/app/lib/md5.js
@@ -0,0 +1,7 @@
+
+module.exports = function (str){
+  return require("crypto")
+    .createHash("md5")
+    .update(str)
+    .digest("hex");
+};
diff --git a/app/models/publickey.js b/app/models/publickey.js
index bcc747b23..5e23d40a0 100644
--- a/app/models/publickey.js
+++ b/app/models/publickey.js
@@ -4,6 +4,10 @@ var async    = require('async');
 var sha1     = require('sha1');
 var _        = require('underscore');
 var Schema   = mongoose.Schema;
+var openpgp  = require('openpgp');
+var KHelper  = require('../lib/keyhelper');
+var base64   = require('../lib/base64');
+var md5      = require('../lib/md5');
 var unix2dos = require('../lib/unix2dos');
 var parsers  = require('../lib/streams/parsers/doc');
 var logger   = require('../lib/logger')('pubkey');
@@ -13,6 +17,8 @@ var PublicKeySchema = new Schema({
   fingerprint: { type: String, unique: true },
   subkeys: [String], // Array of keyId
   hashes: [String], // Array of ASCII armor representation fingerprints
+  registered: [String], // Array of md5 hashes of the known packets (base64 encoded)
+  eligible: [String], // Array of md5 hashes of the unknown packets (base64 encoded)
   name: String,
   email: String,
   comment: String,
@@ -209,6 +215,25 @@ PublicKeySchema.statics.persist = function (pubkey, done) {
           var storedKey = jpgp().certificate(foundKeys[0].raw).key;
           // Merges packets
           storedKey.update(comingKey);
+          var kh = KHelper.fromPackets(storedKey.toPacketlist());
+          var potentials = [];
+          if (kh.hasValidUdid2()) {
+            potentials.push(kh.getBase64publicKey());
+            potentials.push(kh.getBase64primaryUser());
+            kh.getBase64primaryUserOtherCertifications().forEach(function(base64SubKey){
+              potentials.push(base64SubKey);
+            });
+            kh.getBase64subkeys().forEach(function(base64SubKey){
+              potentials.push(base64SubKey);
+            });
+          }
+          potentials.forEach(function(encoded){
+            var md5ed = md5(encoded);
+            if (foundKeys[0].registered.indexOf(md5ed) == -1 && foundKeys[0].eligible.indexOf(md5ed) == -1)  {
+              foundKeys[0].eligible.push(md5ed);
+            }
+          });
+          // Check for unknown packets
           var mergedCert = jpgp().certificate(storedKey.armor());
           var raw = unix2dos(storedKey.armor());
           foundKeys[0].subkeys = mergedCert.subkeys;
-- 
GitLab