diff --git a/lib/PayPro.js b/lib/PayPro.js index f827cf6..1a1623e 100644 --- a/lib/PayPro.js +++ b/lib/PayPro.js @@ -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; }; @@ -171,8 +178,10 @@ 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; }; @@ -192,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); diff --git a/test/test.PayPro.js b/test/test.PayPro.js index ab1b710..d8dcf31 100644 --- a/test/test.PayPro.js +++ b/test/test.PayPro.js @@ -240,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); + }); + + }); + });