|
|
@ -18,9 +18,9 @@ function PaymentProtocol() { |
|
|
|
PaymentProtocol.PAYMENT_REQUEST_MAX_SIZE = 50000; |
|
|
|
PaymentProtocol.PAYMENT_MAX_SIZE = 50000; |
|
|
|
PaymentProtocol.PAYMENT_ACK_MAX_SIZE = 60000; |
|
|
|
PaymentProtocol.PAYMENT_REQUEST_CONTENT_TYPE = "application/bitcoin-paymentrequest"; |
|
|
|
PaymentProtocol.PAYMENT_CONTENT_TYPE = "application/bitcoin-payment"; |
|
|
|
PaymentProtocol.PAYMENT_ACK_CONTENT_TYPE = "application/bitcoin-paymentack"; |
|
|
|
PaymentProtocol.PAYMENT_REQUEST_CONTENT_TYPE = 'application/bitcoin-paymentrequest'; |
|
|
|
PaymentProtocol.PAYMENT_CONTENT_TYPE = 'application/bitcoin-payment'; |
|
|
|
PaymentProtocol.PAYMENT_ACK_CONTENT_TYPE = 'application/bitcoin-paymentack'; |
|
|
|
|
|
|
|
// https://www.google.com/search?q=signatureAlgorithm+1.2.840.113549.1.1.1
|
|
|
|
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa379057(v=vs.85).aspx
|
|
|
@ -43,7 +43,7 @@ PaymentProtocol.getAlgorithm = function(value, index) { |
|
|
|
value = value.join('.'); |
|
|
|
} |
|
|
|
value = PaymentProtocol.X509_ALGORITHM[value]; |
|
|
|
if (index != null) { |
|
|
|
if (typeof(index) !== 'undefined') { |
|
|
|
value = value.split('_'); |
|
|
|
if (index === true) { |
|
|
|
return { |
|
|
@ -66,7 +66,7 @@ PaymentProtocol.getTBSCertificate = function(data) { |
|
|
|
// [ 48, 130, 5, 32, 48, 130, 4, 8, 160, 3 ]
|
|
|
|
var start = 0; |
|
|
|
var starts = 0; |
|
|
|
for (var start = 0; start < data.length; start++) { |
|
|
|
for (start = 0; start < data.length; start++) { |
|
|
|
if (starts === 1 && data[start] === 48) { |
|
|
|
break; |
|
|
|
} |
|
|
@ -84,7 +84,7 @@ PaymentProtocol.getTBSCertificate = function(data) { |
|
|
|
// SEQ of the TBSCertificate.
|
|
|
|
var end = 0; |
|
|
|
var ends = 0; |
|
|
|
for (var end = data.length - 1; end > 0; end--) { |
|
|
|
for (end = data.length - 1; end > 0; end--) { |
|
|
|
if (ends === 2 && data[end] === 48) { |
|
|
|
break; |
|
|
|
} |
|
|
@ -126,8 +126,7 @@ PaymentProtocol.validateCertIssuer = function(c, nc) { |
|
|
|
var issuerObjectValue = issuerObject.value.toString('hex'); |
|
|
|
var subjectObjectValue = subjectObject.value.toString('hex'); |
|
|
|
|
|
|
|
return issuerObjectType === subjectObjectType |
|
|
|
&& issuerObjectValue === subjectObjectValue; |
|
|
|
return issuerObjectType === subjectObjectType && issuerObjectValue === subjectObjectValue; |
|
|
|
}); |
|
|
|
}); |
|
|
|
return issuerVerified; |
|
|
@ -137,12 +136,12 @@ PaymentProtocol.RootCerts = RootCerts; |
|
|
|
|
|
|
|
PaymentProtocol.proto = {}; |
|
|
|
|
|
|
|
PaymentProtocol.proto.Output = "message Output {\ |
|
|
|
PaymentProtocol.proto.Output = 'message Output {\ |
|
|
|
optional uint64 amount = 1 [default = 0];\ |
|
|
|
optional bytes script = 2;\ |
|
|
|
}\n"; |
|
|
|
}\n'; |
|
|
|
|
|
|
|
PaymentProtocol.proto.PaymentDetails = "message PaymentDetails {\ |
|
|
|
PaymentProtocol.proto.PaymentDetails = 'message PaymentDetails {\ |
|
|
|
optional string network = 1 [default = \"main\"];\ |
|
|
|
repeated Output outputs = 2;\ |
|
|
|
required uint64 time = 3;\ |
|
|
@ -150,33 +149,33 @@ PaymentProtocol.proto.PaymentDetails = "message PaymentDetails {\ |
|
|
|
optional string memo = 5;\ |
|
|
|
optional string payment_url = 6;\ |
|
|
|
optional bytes merchant_data = 7;\ |
|
|
|
}\n"; |
|
|
|
}\n'; |
|
|
|
|
|
|
|
PaymentProtocol.proto.PaymentRequest = "message PaymentRequest {\ |
|
|
|
PaymentProtocol.proto.PaymentRequest = 'message PaymentRequest {\ |
|
|
|
optional uint32 payment_details_version = 1 [default = 1];\ |
|
|
|
optional string pki_type = 2 [default = \"none\"];\ |
|
|
|
optional bytes pki_data = 3;\ |
|
|
|
required bytes serialized_payment_details = 4;\ |
|
|
|
optional bytes signature = 5;\ |
|
|
|
}\n"; |
|
|
|
}\n'; |
|
|
|
|
|
|
|
PaymentProtocol.proto.Payment = "message Payment {\ |
|
|
|
PaymentProtocol.proto.Payment = 'message Payment {\ |
|
|
|
optional bytes merchant_data = 1;\ |
|
|
|
repeated bytes transactions = 2;\ |
|
|
|
repeated Output refund_to = 3;\ |
|
|
|
optional string memo = 4;\ |
|
|
|
}\n"; |
|
|
|
}\n'; |
|
|
|
|
|
|
|
PaymentProtocol.proto.PaymentACK = "message PaymentACK {\ |
|
|
|
PaymentProtocol.proto.PaymentACK = 'message PaymentACK {\ |
|
|
|
required Payment payment = 1;\ |
|
|
|
optional string memo = 2;\ |
|
|
|
}\n"; |
|
|
|
}\n'; |
|
|
|
|
|
|
|
PaymentProtocol.proto.X509Certificates = "message X509Certificates {\ |
|
|
|
PaymentProtocol.proto.X509Certificates = 'message X509Certificates {\ |
|
|
|
repeated bytes certificate = 1;\ |
|
|
|
}\n"; |
|
|
|
}\n'; |
|
|
|
|
|
|
|
PaymentProtocol.proto.all = ""; |
|
|
|
PaymentProtocol.proto.all = ''; |
|
|
|
PaymentProtocol.proto.all = PaymentProtocol.proto.all + PaymentProtocol.proto.Output; |
|
|
|
PaymentProtocol.proto.all = PaymentProtocol.proto.all + PaymentProtocol.proto.PaymentDetails; |
|
|
|
PaymentProtocol.proto.all = PaymentProtocol.proto.all + PaymentProtocol.proto.PaymentRequest; |
|
|
@ -186,12 +185,12 @@ PaymentProtocol.proto.all = PaymentProtocol.proto.all + PaymentProtocol.proto.X5 |
|
|
|
|
|
|
|
PaymentProtocol.builder = protobufjs.loadProto(PaymentProtocol.proto.all); |
|
|
|
|
|
|
|
PaymentProtocol.Output = PaymentProtocol.builder.build("Output"); |
|
|
|
PaymentProtocol.PaymentDetails = PaymentProtocol.builder.build("PaymentDetails"); |
|
|
|
PaymentProtocol.PaymentRequest = PaymentProtocol.builder.build("PaymentRequest"); |
|
|
|
PaymentProtocol.Payment = PaymentProtocol.builder.build("Payment"); |
|
|
|
PaymentProtocol.PaymentACK = PaymentProtocol.builder.build("PaymentACK"); |
|
|
|
PaymentProtocol.X509Certificates = PaymentProtocol.builder.build("X509Certificates"); |
|
|
|
PaymentProtocol.Output = PaymentProtocol.builder.build('Output'); |
|
|
|
PaymentProtocol.PaymentDetails = PaymentProtocol.builder.build('PaymentDetails'); |
|
|
|
PaymentProtocol.PaymentRequest = PaymentProtocol.builder.build('PaymentRequest'); |
|
|
|
PaymentProtocol.Payment = PaymentProtocol.builder.build('Payment'); |
|
|
|
PaymentProtocol.PaymentACK = PaymentProtocol.builder.build('PaymentACK'); |
|
|
|
PaymentProtocol.X509Certificates = PaymentProtocol.builder.build('X509Certificates'); |
|
|
|
|
|
|
|
PaymentProtocol.prototype.makeOutput = function(obj) { |
|
|
|
this.messageType = 'Output'; |
|
|
@ -237,24 +236,30 @@ PaymentProtocol.prototype.makeX509Certificates = function(obj) { |
|
|
|
|
|
|
|
PaymentProtocol.prototype.isValidSize = function() { |
|
|
|
var s = this.serialize(); |
|
|
|
if (this.messageType == 'PaymentRequest') |
|
|
|
if (this.messageType === 'PaymentRequest') { |
|
|
|
return s.length < PaymentProtocol.PAYMENT_REQUEST_MAX_SIZE; |
|
|
|
if (this.messageType == 'Payment') |
|
|
|
} |
|
|
|
if (this.messageType === 'Payment') { |
|
|
|
return s.length < PaymentProtocol.PAYMENT_MAX_SIZE; |
|
|
|
if (this.messageType == 'PaymentACK') |
|
|
|
} |
|
|
|
if (this.messageType === 'PaymentACK') { |
|
|
|
return s.length < PaymentProtocol.PAYMENT_ACK_MAX_SIZE; |
|
|
|
} |
|
|
|
return true; |
|
|
|
}; |
|
|
|
|
|
|
|
PaymentProtocol.prototype.getContentType = function() { |
|
|
|
if (this.messageType == 'PaymentRequest') |
|
|
|
if (this.messageType === 'PaymentRequest') { |
|
|
|
return PaymentProtocol.PAYMENT_REQUEST_CONTENT_TYPE; |
|
|
|
} |
|
|
|
|
|
|
|
if (this.messageType == 'Payment') |
|
|
|
if (this.messageType === 'Payment') { |
|
|
|
return PaymentProtocol.PAYMENT_CONTENT_TYPE; |
|
|
|
} |
|
|
|
|
|
|
|
if (this.messageType == 'PaymentACK') |
|
|
|
if (this.messageType === 'PaymentACK') { |
|
|
|
return PaymentProtocol.PAYMENT_ACK_CONTENT_TYPE; |
|
|
|
} |
|
|
|
|
|
|
|
throw new Error('No known content type for this message type'); |
|
|
|
}; |
|
|
@ -267,13 +272,15 @@ PaymentProtocol.prototype.set = function(key, val) { |
|
|
|
PaymentProtocol.prototype.get = function(key) { |
|
|
|
var v = this.message.get(key); |
|
|
|
|
|
|
|
if (v === null) |
|
|
|
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') |
|
|
|
if (typeof v.low !== 'undefined' && typeof v.high !== 'undefined') { |
|
|
|
return v.toInt(); |
|
|
|
} |
|
|
|
|
|
|
|
if (typeof v.toBuffer !== 'undefined') { |
|
|
|
var maybebuf = v.toBuffer(); |
|
|
@ -294,8 +301,9 @@ PaymentProtocol.prototype.setObj = function(obj) { |
|
|
|
}; |
|
|
|
|
|
|
|
PaymentProtocol.prototype.serializeForSig = function() { |
|
|
|
if (this.messageType !== 'PaymentRequest') |
|
|
|
if (this.messageType !== 'PaymentRequest') { |
|
|
|
throw new Error('serializeForSig is only for PaymentRequest'); |
|
|
|
} |
|
|
|
|
|
|
|
var save = this.message.get('signature'); |
|
|
|
this.message.set('signature', new Buffer([])); |
|
|
@ -314,22 +322,25 @@ PaymentProtocol.prototype.serialize = function() { |
|
|
|
|
|
|
|
PaymentProtocol.prototype.deserialize = function(buf, messageType) { |
|
|
|
this.messageType = messageType || this.messageType; |
|
|
|
if (!this.messageType) |
|
|
|
if (!this.messageType) { |
|
|
|
throw new Error('Must specify messageType'); |
|
|
|
} |
|
|
|
this.message = PaymentProtocol[this.messageType].decode(buf); |
|
|
|
return this; |
|
|
|
}; |
|
|
|
|
|
|
|
PaymentProtocol.prototype.sign = function(key, returnTrust) { |
|
|
|
if (this.messageType !== 'PaymentRequest') |
|
|
|
if (this.messageType !== 'PaymentRequest') { |
|
|
|
throw new Error('Signing can only be performed on a PaymentRequest'); |
|
|
|
} |
|
|
|
|
|
|
|
var pki_type = this.get('pki_type'); |
|
|
|
|
|
|
|
var sig; |
|
|
|
if (pki_type === 'SIN') { |
|
|
|
var sig = this.sinSign(key); |
|
|
|
sig = this.sinSign(key); |
|
|
|
} else if (pki_type === 'x509+sha1' || pki_type === 'x509+sha256') { |
|
|
|
var sig = this.x509Sign(key, returnTrust); |
|
|
|
sig = this.x509Sign(key, returnTrust); |
|
|
|
} else if (pki_type === 'none') { |
|
|
|
return this; |
|
|
|
} else { |
|
|
@ -342,8 +353,9 @@ PaymentProtocol.prototype.sign = function(key, returnTrust) { |
|
|
|
}; |
|
|
|
|
|
|
|
PaymentProtocol.prototype.verify = function(returnTrust) { |
|
|
|
if (this.messageType !== 'PaymentRequest') |
|
|
|
if (this.messageType !== 'PaymentRequest') { |
|
|
|
throw new Error('Verifying can only be performed on a PaymentRequest'); |
|
|
|
} |
|
|
|
|
|
|
|
var pki_type = this.get('pki_type'); |
|
|
|
|
|
|
@ -366,7 +378,7 @@ function magicHash(str) { |
|
|
|
var buf = Buffer.concat([prefix1, magicBytes, prefix2, message]); |
|
|
|
var hash = sha256sha256(buf); |
|
|
|
return hash; |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
//default signing function for prototype.sign
|
|
|
|
PaymentProtocol.prototype.sinSign = function(privateKey) { |
|
|
@ -413,7 +425,9 @@ PaymentProtocol.prototype._PEMtoDERParam = function(pem, param) { |
|
|
|
var type = /-----BEGIN ([^-]+)-----/.exec(part)[1]; |
|
|
|
part = part.replace(/-----BEGIN ([^-]+)-----/g, ''); |
|
|
|
part = part.replace(/\s+/g, ''); |
|
|
|
if (!param || type !== param) return; |
|
|
|
if (!param || type !== param) { |
|
|
|
return; |
|
|
|
} |
|
|
|
return new Buffer(part, 'base64'); |
|
|
|
}).filter(Boolean); |
|
|
|
}; |
|
|
@ -423,14 +437,14 @@ PaymentProtocol.prototype._DERtoPEM = function(der, type) { |
|
|
|
if (typeof der === 'string') { |
|
|
|
der = new Buffer(der, 'hex'); |
|
|
|
} |
|
|
|
var type = type || 'PRIVACY-ENHANCED MESSAGE'; |
|
|
|
type = type || 'PRIVACY-ENHANCED MESSAGE'; |
|
|
|
der = der.toString('base64'); |
|
|
|
der = der.replace(/(.{64})/g, '$1\r\n'); |
|
|
|
der = der.replace(/\r\n$/, ''); |
|
|
|
return '' |
|
|
|
+ '-----BEGIN ' + type + '-----\r\n' |
|
|
|
+ der |
|
|
|
+ '\r\n-----END ' + type + '-----\r\n'; |
|
|
|
return '' + |
|
|
|
'-----BEGIN ' + type + '-----\r\n' + |
|
|
|
der + |
|
|
|
'\r\n-----END ' + type + '-----\r\n'; |
|
|
|
}; |
|
|
|
|
|
|
|
// Expose RootCerts
|
|
|
|