Merge branch 'feature/bip70-signing'

This commit is contained in:
Ryan X. Charles 2014-07-07 16:58:07 -07:00
commit 5cdc160dea
2 changed files with 172 additions and 2 deletions

View File

@ -1,6 +1,7 @@
'use strict';
var imports = require('soop').imports();
var protobufjs = protobufjs || require('protobufjs/dist/ProtoBuf');
var Message = Message || require('./Message');
// BIP 70 - payment protocol
function PayPro() {
@ -8,8 +9,6 @@ function PayPro() {
this.message = null;
}
PayPro.constants = {};
PayPro.PAYMENT_REQUEST_MAX_SIZE = 50000;
PayPro.PAYMENT_MAX_SIZE = 50000;
PayPro.PAYMENT_ACK_MAX_SIZE = 60000;
@ -149,11 +148,19 @@ PayPro.prototype.set = function(key, val) {
PayPro.prototype.get = function(key) {
var v = this.message.get(key);
if (v === null)
return v;
//protobuf supports longs, javascript naturally does not
//convert longs (see long.js, e.g. require('long')) to Numbers
if (typeof v.low !== 'undefined' && typeof v.high !== 'undefined')
return v.toInt();
if (typeof v.toBuffer !== 'undefined') {
var maybebuf = v.toBuffer();
return Buffer.isBuffer(maybebuf) ? maybebuf : new Buffer(new Uint8Array(maybebuf));
}
return v;
};
@ -167,6 +174,17 @@ PayPro.prototype.setObj = function(obj) {
return this;
};
PayPro.prototype.serializeForSig = function() {
if (this.messageType !== 'PaymentRequest')
throw new Error('serializeForSig is only for PaymentRequest');
var save = this.message.get('signature');
this.message.set('signature', new Buffer([]));
var buf = this.serialize();
this.message.set('signature', save);
return buf;
};
PayPro.prototype.serialize = function() {
//protobufjs returns either a Buffer or an ArrayBuffer
//but we always want a Buffer (which browserify understands, browser or no)
@ -183,4 +201,46 @@ PayPro.prototype.deserialize = function(buf, messageType) {
return this;
};
PayPro.prototype.sign = function(key) {
if (this.messageType !== 'PaymentRequest')
throw new Error('Signing can only be performed on a PaymentRequest');
var pki_type = this.get('pki_type');
if (pki_type === 'SIN')
var sig = this.sinSign(key);
else
throw new Error('Unsupported pki_type');
this.set('signature', sig);
return this;
};
PayPro.prototype.verify = function() {
if (this.messageType !== 'PaymentRequest')
throw new Error('Verifying can only be performed on a PaymentRequest');
var pki_type = this.get('pki_type');
if (pki_type === 'SIN')
return this.sinVerify();
else
throw new Error('Unsupported pki_type');
};
//default signing function for prototype.sign
PayPro.prototype.sinSign = function(key) {
this.set('pki_data', key.public)
var buf = this.serializeForSig();
return Message.sign(buf, key);
};
//default verify function
PayPro.prototype.sinVerify = function() {
var sig = this.get('signature');
var pubkey = this.get('pki_data');
var buf = this.serializeForSig();
return Message.verifyWithPubKey(pubkey, buf, sig);
};
module.exports = require('soop')(PayPro);

View File

@ -177,6 +177,37 @@ describe('PayPro', function() {
});
describe('#setObj', function() {
it('should set properties of paymentdetails', function() {
var pd = new PayPro.PaymentDetails();
var paypro = new PayPro();
paypro.messageType = "PaymentDetails";
paypro.message = pd;
paypro.setObj({
time: 0
});
paypro.get('time').should.equal(0);
});
});
describe('#serializeForSig', function() {
it('should serialize a PaymentRequest and not fail', function() {
var pd = new PayPro.PaymentDetails();
pd.set('time', 0);
var pdbuf = pd.toBuffer();
var paypro = new PayPro();
paypro.makePaymentRequest();
paypro.set('serialized_payment_details', pdbuf);
var buf = paypro.serializeForSig();
buf.length.should.be.greaterThan(0);
});
});
describe('#serialize', function() {
it('should serialize', function() {
@ -209,4 +240,83 @@ describe('PayPro', function() {
});
describe('#sign', function() {
it('should sign a payment request', function() {
var pd = new PayPro.PaymentDetails();
pd.set('time', 0);
var pdbuf = pd.toBuffer();
var paypro = new PayPro();
paypro.makePaymentRequest();
paypro.set('serialized_payment_details', pdbuf);
paypro.set('pki_type', 'SIN');
var key = new bitcore.Key();
key.private = bitcore.util.sha256('test key');
key.regenerateSync();
paypro.sign(key);
var sig = paypro.get('signature');
sig.length.should.be.greaterThan(0);
});
});
describe('#verify', function() {
it('should verify a signed payment request', function() {
var pd = new PayPro.PaymentDetails();
pd.set('time', 0);
var pdbuf = pd.toBuffer();
var paypro = new PayPro();
paypro.makePaymentRequest();
paypro.set('serialized_payment_details', pdbuf);
paypro.set('pki_type', 'SIN');
var key = new bitcore.Key();
key.private = bitcore.util.sha256('test key');
key.regenerateSync();
paypro.sign(key);
var verify = paypro.verify();
verify.should.equal(true);
});
});
describe('#sinSign', function() {
it('should sign assuming pki_type is SIN', function() {
var pd = new PayPro.PaymentDetails();
pd.set('time', 0);
var pdbuf = pd.toBuffer();
var paypro = new PayPro();
paypro.makePaymentRequest();
paypro.set('serialized_payment_details', pdbuf);
paypro.set('pki_type', 'SIN');
var key = new bitcore.Key();
key.private = bitcore.util.sha256('test key');
key.regenerateSync();
var sig = paypro.sinSign(key);
sig.length.should.be.greaterThan(0);
});
});
describe('#sinVerify', function() {
it('should verify assuming pki_type is SIN', function() {
var pd = new PayPro.PaymentDetails();
pd.set('time', 0);
var pdbuf = pd.toBuffer();
var paypro = new PayPro();
paypro.makePaymentRequest();
paypro.set('serialized_payment_details', pdbuf);
paypro.set('pki_type', 'SIN');
var key = new bitcore.Key();
key.private = bitcore.util.sha256('test key');
key.regenerateSync();
paypro.sign(key);
var verify = paypro.sinVerify();
verify.should.equal(true);
});
});
});