Ryan X. Charles
11 years ago
13 changed files with 4543 additions and 230 deletions
@ -0,0 +1,198 @@ |
|||||
|
#!/usr/bin/env node |
||||
|
|
||||
|
/** |
||||
|
* Modules |
||||
|
*/ |
||||
|
|
||||
|
var fs = require('fs'); |
||||
|
var url = require('url'); |
||||
|
var http = require('http'); |
||||
|
var path = require('path'); |
||||
|
var Stream = require('stream').Stream; |
||||
|
var StringDecoder = require('string_decoder').StringDecoder; |
||||
|
|
||||
|
/** |
||||
|
* Mozilla Root Cert URL |
||||
|
*/ |
||||
|
|
||||
|
var certUrl = 'https://raw.githubusercontent.com/joyent/node/master/src/node_root_certs.h'; |
||||
|
|
||||
|
/** |
||||
|
* Get Root Certs |
||||
|
*/ |
||||
|
|
||||
|
function getRootCerts(callback) { |
||||
|
return request(certUrl, function(err, res, body) { |
||||
|
if (err) return callback(err); |
||||
|
body = body.replace(/,$/, ''); |
||||
|
body = 'var RootCerts = [\n' + body + '\n];\n'; |
||||
|
body = body.replace(/^"/gm, '+ "'); |
||||
|
body = body.replace(/^\+ "-----B/gm, '"-----B'); |
||||
|
body += '' |
||||
|
+ '\n' |
||||
|
+ '// Use hash table for efficiency:\n' |
||||
|
+ 'RootCerts = RootCerts.reduce(function(trusted, cert) {\n' |
||||
|
+ ' cert = cert.replace(/\\s+/g, "");\n' |
||||
|
+ ' trusted[cert] = true;\n' |
||||
|
+ ' return trusted;\n' |
||||
|
+ '}, {});\n' |
||||
|
+ '\n' |
||||
|
+ 'function isTrusted(pem) {\n' |
||||
|
+ ' pem = pem + "";\n' |
||||
|
+ ' pem = pem.replace(/\\s+/g, "");\n' |
||||
|
+ ' return !!RootCerts[pem];\n' |
||||
|
+ '}\n' |
||||
|
+ '\n' |
||||
|
+ 'exports = RootCerts;\n' |
||||
|
+ 'exports.isTrusted = isTrusted;\n' |
||||
|
+ 'module.exports = exports;\n'; |
||||
|
return callback(null, body); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Helpers |
||||
|
*/ |
||||
|
|
||||
|
function request(options, callback) { |
||||
|
if (typeof options === 'string' || options.hostname) { |
||||
|
options = { uri: options }; |
||||
|
} |
||||
|
|
||||
|
var uri = options.uri || options.url |
||||
|
, body = options.json |
||||
|
? JSON.stringify(options.json) |
||||
|
: options.body || ''; |
||||
|
|
||||
|
if (typeof uri !== 'object') { |
||||
|
uri = url.parse(uri); |
||||
|
} |
||||
|
|
||||
|
if (options.qs) { |
||||
|
var query = uri.query ? qs.parse(uri.query) : {}; |
||||
|
Object.keys(options.qs).forEach(function(key) { |
||||
|
query[key] = options.qs[key]; |
||||
|
}); |
||||
|
uri.path = uri.pathname + '?' + qs.stringify(query); |
||||
|
} |
||||
|
|
||||
|
var protocol = uri.protocol === 'https:' |
||||
|
? require('https') |
||||
|
: http; |
||||
|
|
||||
|
options.method = options.method || (body ? 'POST' : 'GET'); |
||||
|
options.method = options.method.toUpperCase(); |
||||
|
options.headers = options.headers || {}; |
||||
|
|
||||
|
options.headers['Accept'] = options.headers['Accept'] || 'text/plain; charset=utf-8'; |
||||
|
|
||||
|
if (options.json) { |
||||
|
options.headers['Content-Type'] = 'application/json; charset=utf-8'; |
||||
|
options.headers['Accept'] = 'application/json'; |
||||
|
} |
||||
|
|
||||
|
if (options.method !== 'GET' && options.method !== 'HEAD') { |
||||
|
options.headers['Content-Length'] = Buffer.byteLength(body); |
||||
|
} |
||||
|
|
||||
|
var opt = { |
||||
|
auth: uri.auth, |
||||
|
host: uri.hostname, |
||||
|
port: uri.port || (protocol === http ? 80 : 443), |
||||
|
path: uri.path, |
||||
|
method: options.method, |
||||
|
headers: options.headers |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
var req = protocol.request(opt) |
||||
|
, response = new Stream; |
||||
|
|
||||
|
req.on('error', function(err) { |
||||
|
if (callback) { |
||||
|
callback(err); |
||||
|
} else { |
||||
|
response.emit('error', err); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
req.on('response', function(res) { |
||||
|
var decoder = new StringDecoder('utf8') |
||||
|
, done = false |
||||
|
, body = ''; |
||||
|
|
||||
|
function end() { |
||||
|
if (done) return; |
||||
|
done = true; |
||||
|
if (callback) { |
||||
|
res.body = body; |
||||
|
if (options.json) { |
||||
|
try { |
||||
|
body = JSON.parse(body); |
||||
|
} catch (e) { |
||||
|
; |
||||
|
} |
||||
|
} |
||||
|
callback(null, res, body); |
||||
|
} else { |
||||
|
response.emit('end'); |
||||
|
} |
||||
|
res.socket.removeListener('error', error); |
||||
|
res.socket.removeListener('end', end); |
||||
|
} |
||||
|
|
||||
|
function error(err) { |
||||
|
res.destroy(); |
||||
|
if (callback) { |
||||
|
callback(err); |
||||
|
} else { |
||||
|
response.emit('error', err); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
res.on('data', function(data) { |
||||
|
if (callback) { |
||||
|
body += decoder.write(data); |
||||
|
} else { |
||||
|
response.emit('data', data); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
res.on('error', error); |
||||
|
res.socket.on('error', error); |
||||
|
|
||||
|
res.on('end', end); |
||||
|
// An agent socket's `end` sometimes |
||||
|
// wont be emitted on the response. |
||||
|
res.socket.on('end', end); |
||||
|
}); |
||||
|
|
||||
|
req.end(body); |
||||
|
|
||||
|
return response; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Execute |
||||
|
*/ |
||||
|
|
||||
|
function main(argv, callback) { |
||||
|
if (!callback) { |
||||
|
callback = argv; |
||||
|
argv = null; |
||||
|
} |
||||
|
return getRootCerts(function(err, certs) { |
||||
|
var file = path.resolve(__dirname, '..', 'lib', 'common', 'RootCerts.js'); |
||||
|
return fs.writeFile(file, certs, callback); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
if (!module.parent) { |
||||
|
process.title = 'root-certs'; |
||||
|
main(process.argv.slice(), function(err, code) { |
||||
|
if (err) throw err; |
||||
|
return process.exit(code || 0); |
||||
|
}); |
||||
|
} else { |
||||
|
module.exports = main; |
||||
|
} |
@ -1,245 +1,61 @@ |
|||||
'use strict'; |
'use strict'; |
||||
var protobufjs = protobufjs || require('protobufjs/dist/ProtoBuf'); |
|
||||
var Message = Message || require('./Message'); |
|
||||
|
|
||||
// BIP 70 - payment protocol
|
|
||||
function PayPro() { |
|
||||
this.messageType = null; |
|
||||
this.message = null; |
|
||||
} |
|
||||
|
|
||||
PayPro.PAYMENT_REQUEST_MAX_SIZE = 50000; |
|
||||
PayPro.PAYMENT_MAX_SIZE = 50000; |
|
||||
PayPro.PAYMENT_ACK_MAX_SIZE = 60000; |
|
||||
PayPro.PAYMENT_REQUEST_CONTENT_TYPE = "application/bitcoin-paymentrequest"; |
|
||||
PayPro.PAYMENT_CONTENT_TYPE = "application/bitcoin-payment"; |
|
||||
PayPro.PAYMENT_ACK_CONTENT_TYPE = "application/bitcoin-paymentack"; |
|
||||
|
|
||||
PayPro.proto = {}; |
|
||||
|
|
||||
PayPro.proto.Output = "message Output {\ |
|
||||
optional uint64 amount = 1 [default = 0];\ |
|
||||
optional bytes script = 2;\ |
|
||||
}\n"; |
|
||||
|
|
||||
PayPro.proto.PaymentDetails = "message PaymentDetails {\ |
|
||||
optional string network = 1 [default = \"main\"];\ |
|
||||
repeated Output outputs = 2;\ |
|
||||
required uint64 time = 3;\ |
|
||||
optional uint64 expires = 4;\ |
|
||||
optional string memo = 5;\ |
|
||||
optional string payment_url = 6;\ |
|
||||
optional bytes merchant_data = 7;\ |
|
||||
}\n"; |
|
||||
|
|
||||
PayPro.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"; |
|
||||
|
|
||||
PayPro.proto.Payment = "message Payment {\ |
|
||||
optional bytes merchant_data = 1;\ |
|
||||
repeated bytes transactions = 2;\ |
|
||||
repeated Output refund_to = 3;\ |
|
||||
optional string memo = 4;\ |
|
||||
}\n"; |
|
||||
|
|
||||
PayPro.proto.PaymentACK = "message PaymentACK {\ |
var Message = Message || require('./Message'); |
||||
required Payment payment = 1;\ |
|
||||
optional string memo = 2;\ |
|
||||
}\n"; |
|
||||
|
|
||||
PayPro.proto.X509Certificates = "message X509Certificates {\ |
|
||||
repeated bytes certificate = 1;\ |
|
||||
}\n"; |
|
||||
|
|
||||
PayPro.proto.all = ""; |
|
||||
PayPro.proto.all = PayPro.proto.all + PayPro.proto.Output; |
|
||||
PayPro.proto.all = PayPro.proto.all + PayPro.proto.PaymentDetails; |
|
||||
PayPro.proto.all = PayPro.proto.all + PayPro.proto.PaymentRequest; |
|
||||
PayPro.proto.all = PayPro.proto.all + PayPro.proto.Payment; |
|
||||
PayPro.proto.all = PayPro.proto.all + PayPro.proto.PaymentACK; |
|
||||
PayPro.proto.all = PayPro.proto.all + PayPro.proto.X509Certificates; |
|
||||
|
|
||||
PayPro.builder = protobufjs.loadProto(PayPro.proto.all); |
|
||||
|
|
||||
PayPro.Output = PayPro.builder.build("Output"); |
|
||||
PayPro.PaymentDetails = PayPro.builder.build("PaymentDetails"); |
|
||||
PayPro.PaymentRequest = PayPro.builder.build("PaymentRequest"); |
|
||||
PayPro.Payment = PayPro.builder.build("Payment"); |
|
||||
PayPro.PaymentACK = PayPro.builder.build("PaymentACK"); |
|
||||
PayPro.X509Certificates = PayPro.builder.build("X509Certificates"); |
|
||||
|
|
||||
PayPro.prototype.makeOutput = function(obj) { |
|
||||
this.messageType = 'Output'; |
|
||||
this.message = new PayPro.Output(); |
|
||||
this.setObj(obj); |
|
||||
return this; |
|
||||
}; |
|
||||
|
|
||||
PayPro.prototype.makePaymentDetails = function(obj) { |
|
||||
this.messageType = 'PaymentDetails'; |
|
||||
this.message = new PayPro.PaymentDetails(); |
|
||||
this.setObj(obj); |
|
||||
return this; |
|
||||
}; |
|
||||
|
|
||||
PayPro.prototype.makePaymentRequest = function(obj) { |
|
||||
this.messageType = 'PaymentRequest'; |
|
||||
this.message = new PayPro.PaymentRequest(); |
|
||||
this.setObj(obj); |
|
||||
return this; |
|
||||
}; |
|
||||
|
|
||||
PayPro.prototype.makePayment = function(obj) { |
|
||||
this.messageType = 'Payment'; |
|
||||
this.message = new PayPro.Payment(); |
|
||||
this.setObj(obj); |
|
||||
return this; |
|
||||
}; |
|
||||
|
|
||||
PayPro.prototype.makePaymentACK = function(obj) { |
|
||||
this.messageType = 'Payment'; |
|
||||
this.message = new PayPro.PaymentACK(); |
|
||||
this.setObj(obj); |
|
||||
return this; |
|
||||
}; |
|
||||
|
|
||||
PayPro.prototype.makeX509Certificates = function(obj) { |
|
||||
this.messageType = 'X509Certificates'; |
|
||||
this.message = new PayPro.X509Certificates(); |
|
||||
this.setObj(obj); |
|
||||
return this; |
|
||||
}; |
|
||||
|
|
||||
PayPro.prototype.isValidSize = function() { |
|
||||
var s = this.serialize(); |
|
||||
if (this.messageType == 'PaymentRequest') |
|
||||
return s.length < PayPro.PAYMENT_REQUEST_MAX_SIZE; |
|
||||
if (this.messageType == 'Payment') |
|
||||
return s.length < PayPro.PAYMENT_MAX_SIZE; |
|
||||
if (this.messageType == 'PaymentACK') |
|
||||
return s.length < PayPro.PAYMENT_ACK_MAX_SIZE; |
|
||||
return true; |
|
||||
}; |
|
||||
|
|
||||
PayPro.prototype.getContentType = function() { |
|
||||
if (this.messageType == 'PaymentRequest') |
|
||||
return PayPro.PAYMENT_REQUEST_CONTENT_TYPE; |
|
||||
|
|
||||
if (this.messageType == 'Payment') |
|
||||
return PayPro.PAYMENT_CONTENT_TYPE; |
|
||||
|
|
||||
if (this.messageType == 'PaymentACK') |
|
||||
return PayPro.PAYMENT_ACK_CONTENT_TYPE; |
|
||||
|
|
||||
throw new Error('No known content type for this message type'); |
|
||||
}; |
|
||||
|
|
||||
PayPro.prototype.set = function(key, val) { |
|
||||
this.message.set(key, val); |
|
||||
return this; |
|
||||
}; |
|
||||
|
|
||||
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 RootCerts = require('./common/RootCerts'); |
||||
var maybebuf = v.toBuffer(); |
|
||||
return Buffer.isBuffer(maybebuf) ? maybebuf : new Buffer(new Uint8Array(maybebuf)); |
|
||||
} |
|
||||
|
|
||||
return v; |
var PayPro = require('./common/PayPro'); |
||||
}; |
|
||||
|
|
||||
PayPro.prototype.setObj = function(obj) { |
PayPro.prototype.x509Sign = function(key) { |
||||
for (var key in obj) { |
var self = this; |
||||
if (obj.hasOwnProperty(key)) { |
var crypto = require('crypto'); |
||||
var val = obj[key]; |
var pki_type = this.get('pki_type'); |
||||
this.message.set(key, val); |
var pki_data = this.get('pki_data'); // contains one or more x509 certs
|
||||
} |
var details = this.get('serialized_payment_details'); |
||||
|
var type = pki_type.split('+')[1].toUpperCase(); |
||||
|
|
||||
|
var trusted = [].concat(pki_data).every(function(cert) { |
||||
|
var der = cert.toString('hex'); |
||||
|
var pem = self._DERtoPEM(der, 'CERTIFICATE'); |
||||
|
return RootCerts.isTrusted(pem); |
||||
|
}); |
||||
|
|
||||
|
if (!trusted) { |
||||
|
// XXX Figure out what to do here
|
||||
|
// throw new Error('Unstrusted certificate.');
|
||||
} |
} |
||||
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)
|
|
||||
var maybebuf = this.message.toBuffer(); |
|
||||
var buf = (Buffer.isBuffer(maybebuf)) ? maybebuf : new Buffer(new Uint8Array(maybebuf)); |
|
||||
return buf; |
|
||||
}; |
|
||||
|
|
||||
PayPro.prototype.deserialize = function(buf, messageType) { |
var signature = crypto.createSign('RSA-' + type); |
||||
this.messageType = messageType || this.messageType; |
var buf = this.serializeForSig(); |
||||
if (!this.messageType) |
signature.update(buf); |
||||
throw new Error('Must specify messageType'); |
var sig = signature.sign(key); |
||||
this.message = PayPro[this.messageType].decode(buf); |
return sig; |
||||
return this; |
|
||||
}; |
}; |
||||
|
|
||||
PayPro.prototype.sign = function(key) { |
PayPro.prototype.x509Verify = function() { |
||||
if (this.messageType !== 'PaymentRequest') |
var self = this; |
||||
throw new Error('Signing can only be performed on a PaymentRequest'); |
var crypto = require('crypto'); |
||||
|
|
||||
var pki_type = this.get('pki_type'); |
var pki_type = this.get('pki_type'); |
||||
|
var sig = this.get('signature'); |
||||
|
var pki_data = this.get('pki_data'); |
||||
|
var details = this.get('serialized_payment_details'); |
||||
|
var buf = this.serializeForSig(); |
||||
|
var type = pki_type.split('+')[1].toUpperCase(); |
||||
|
|
||||
if (pki_type === 'SIN') |
var verifier = crypto.createVerify('RSA-' + type); |
||||
var sig = this.sinSign(key); |
verifier.update(buf); |
||||
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'); |
return [].concat(pki_data).every(function(cert) { |
||||
|
var der = cert.toString('hex'); |
||||
|
var pem = self._DERtoPEM(der, 'CERTIFICATE'); |
||||
|
|
||||
if (pki_type === 'SIN') |
if (!RootCerts.isTrusted(pem)) { |
||||
return this.sinVerify(); |
// XXX Figure out what to do here
|
||||
else |
// throw new Error('Unstrusted certificate.');
|
||||
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
|
return verifier.verify(pem, sig); |
||||
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 = PayPro; |
module.exports = PayPro; |
||||
|
@ -0,0 +1,79 @@ |
|||||
|
"use strict"; |
||||
|
|
||||
|
var Key = require('./Key'); |
||||
|
var KJUR = require('jsrsasign'); |
||||
|
var assert = require('assert'); |
||||
|
var PayPro = require('../common/PayPro'); |
||||
|
var RootCerts = require('../common/RootCerts'); |
||||
|
|
||||
|
// Documentation:
|
||||
|
// http://kjur.github.io/jsrsasign/api/symbols/KJUR.crypto.Signature.html#.sign
|
||||
|
// http://kjur.github.io/jsrsasign/api/symbols/RSAKey.html
|
||||
|
|
||||
|
PayPro.prototype.x509Sign = function(key) { |
||||
|
var pki_type = this.get('pki_type'); |
||||
|
var pki_data = this.get('pki_data'); // contains one or more x509 certs
|
||||
|
var type = pki_type.split('+')[1].toUpperCase(); |
||||
|
var buf = this.serializeForSig(); |
||||
|
|
||||
|
var trusted = [].concat(pki_data).every(function(cert) { |
||||
|
var der = cert.toString('hex'); |
||||
|
var pem = KJUR.asn1.ASN1Util.getPEMStringFromHex(der, 'CERTIFICATE'); |
||||
|
return RootCerts.isTrusted(pem); |
||||
|
}); |
||||
|
|
||||
|
if (!trusted) { |
||||
|
// XXX Figure out what to do here
|
||||
|
// throw new Error('Unstrusted certificate.');
|
||||
|
} |
||||
|
|
||||
|
var rsa = new KJUR.RSAKey(); |
||||
|
rsa.readPrivateKeyFromPEMString(key.toString()); |
||||
|
key = rsa; |
||||
|
|
||||
|
var jsrsaSig = new KJUR.crypto.Signature({ |
||||
|
alg: type.toUpperCase() + 'withRSA', |
||||
|
prov: 'cryptojs/jsrsa' |
||||
|
}); |
||||
|
|
||||
|
// XXX Could use this?
|
||||
|
//jsrsaSig.initSign(key);
|
||||
|
|
||||
|
jsrsaSig.init(key); |
||||
|
|
||||
|
jsrsaSig.updateHex(buf.toString('hex')); |
||||
|
|
||||
|
var sig = new Buffer(jsrsaSig.sign(), 'hex'); |
||||
|
return sig; |
||||
|
}; |
||||
|
|
||||
|
PayPro.prototype.x509Verify = function(key) { |
||||
|
var sig = this.get('signature'); |
||||
|
var pki_type = this.get('pki_type'); |
||||
|
var pki_data = this.get('pki_data'); |
||||
|
var buf = this.serializeForSig(); |
||||
|
var type = pki_type.split('+')[1].toUpperCase(); |
||||
|
|
||||
|
var jsrsaSig = new KJUR.crypto.Signature({ |
||||
|
alg: type.toUpperCase() + 'withRSA', |
||||
|
prov: 'cryptojs/jsrsa' |
||||
|
}); |
||||
|
|
||||
|
return [].concat(pki_data).every(function(cert) { |
||||
|
var der = cert.toString('hex'); |
||||
|
var pem = KJUR.asn1.ASN1Util.getPEMStringFromHex(der, 'CERTIFICATE'); |
||||
|
|
||||
|
if (!RootCerts.isTrusted(pem)) { |
||||
|
// XXX Figure out what to do here
|
||||
|
// throw new Error('Unstrusted certificate.');
|
||||
|
} |
||||
|
|
||||
|
jsrsaSig.initVerifyByCertificatePEM(pem); |
||||
|
|
||||
|
jsrsaSig.updateHex(buf.toString('hex')); |
||||
|
|
||||
|
return jsrsaSig.verify(sig.toString('hex')); |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
module.exports = PayPro; |
@ -0,0 +1,296 @@ |
|||||
|
'use strict'; |
||||
|
|
||||
|
var protobufjs = require('protobufjs/dist/ProtoBuf'); |
||||
|
var Message = require('../Message'); |
||||
|
|
||||
|
var RootCerts = require('../common/RootCerts'); |
||||
|
|
||||
|
// BIP 70 - payment protocol
|
||||
|
function PayPro() { |
||||
|
this.messageType = null; |
||||
|
this.message = null; |
||||
|
} |
||||
|
|
||||
|
PayPro.PAYMENT_REQUEST_MAX_SIZE = 50000; |
||||
|
PayPro.PAYMENT_MAX_SIZE = 50000; |
||||
|
PayPro.PAYMENT_ACK_MAX_SIZE = 60000; |
||||
|
PayPro.PAYMENT_REQUEST_CONTENT_TYPE = "application/bitcoin-paymentrequest"; |
||||
|
PayPro.PAYMENT_CONTENT_TYPE = "application/bitcoin-payment"; |
||||
|
PayPro.PAYMENT_ACK_CONTENT_TYPE = "application/bitcoin-paymentack"; |
||||
|
|
||||
|
PayPro.proto = {}; |
||||
|
|
||||
|
PayPro.proto.Output = "message Output {\ |
||||
|
optional uint64 amount = 1 [default = 0];\ |
||||
|
optional bytes script = 2;\ |
||||
|
}\n"; |
||||
|
|
||||
|
PayPro.proto.PaymentDetails = "message PaymentDetails {\ |
||||
|
optional string network = 1 [default = \"main\"];\ |
||||
|
repeated Output outputs = 2;\ |
||||
|
required uint64 time = 3;\ |
||||
|
optional uint64 expires = 4;\ |
||||
|
optional string memo = 5;\ |
||||
|
optional string payment_url = 6;\ |
||||
|
optional bytes merchant_data = 7;\ |
||||
|
}\n"; |
||||
|
|
||||
|
PayPro.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"; |
||||
|
|
||||
|
PayPro.proto.Payment = "message Payment {\ |
||||
|
optional bytes merchant_data = 1;\ |
||||
|
repeated bytes transactions = 2;\ |
||||
|
repeated Output refund_to = 3;\ |
||||
|
optional string memo = 4;\ |
||||
|
}\n"; |
||||
|
|
||||
|
PayPro.proto.PaymentACK = "message PaymentACK {\ |
||||
|
required Payment payment = 1;\ |
||||
|
optional string memo = 2;\ |
||||
|
}\n"; |
||||
|
|
||||
|
PayPro.proto.X509Certificates = "message X509Certificates {\ |
||||
|
repeated bytes certificate = 1;\ |
||||
|
}\n"; |
||||
|
|
||||
|
PayPro.proto.all = ""; |
||||
|
PayPro.proto.all = PayPro.proto.all + PayPro.proto.Output; |
||||
|
PayPro.proto.all = PayPro.proto.all + PayPro.proto.PaymentDetails; |
||||
|
PayPro.proto.all = PayPro.proto.all + PayPro.proto.PaymentRequest; |
||||
|
PayPro.proto.all = PayPro.proto.all + PayPro.proto.Payment; |
||||
|
PayPro.proto.all = PayPro.proto.all + PayPro.proto.PaymentACK; |
||||
|
PayPro.proto.all = PayPro.proto.all + PayPro.proto.X509Certificates; |
||||
|
|
||||
|
PayPro.builder = protobufjs.loadProto(PayPro.proto.all); |
||||
|
|
||||
|
PayPro.Output = PayPro.builder.build("Output"); |
||||
|
PayPro.PaymentDetails = PayPro.builder.build("PaymentDetails"); |
||||
|
PayPro.PaymentRequest = PayPro.builder.build("PaymentRequest"); |
||||
|
PayPro.Payment = PayPro.builder.build("Payment"); |
||||
|
PayPro.PaymentACK = PayPro.builder.build("PaymentACK"); |
||||
|
PayPro.X509Certificates = PayPro.builder.build("X509Certificates"); |
||||
|
|
||||
|
PayPro.prototype.makeOutput = function(obj) { |
||||
|
this.messageType = 'Output'; |
||||
|
this.message = new PayPro.Output(); |
||||
|
this.setObj(obj); |
||||
|
return this; |
||||
|
}; |
||||
|
|
||||
|
PayPro.prototype.makePaymentDetails = function(obj) { |
||||
|
this.messageType = 'PaymentDetails'; |
||||
|
this.message = new PayPro.PaymentDetails(); |
||||
|
this.setObj(obj); |
||||
|
return this; |
||||
|
}; |
||||
|
|
||||
|
PayPro.prototype.makePaymentRequest = function(obj) { |
||||
|
this.messageType = 'PaymentRequest'; |
||||
|
this.message = new PayPro.PaymentRequest(); |
||||
|
this.setObj(obj); |
||||
|
return this; |
||||
|
}; |
||||
|
|
||||
|
PayPro.prototype.makePayment = function(obj) { |
||||
|
this.messageType = 'Payment'; |
||||
|
this.message = new PayPro.Payment(); |
||||
|
this.setObj(obj); |
||||
|
return this; |
||||
|
}; |
||||
|
|
||||
|
PayPro.prototype.makePaymentACK = function(obj) { |
||||
|
this.messageType = 'Payment'; |
||||
|
this.message = new PayPro.PaymentACK(); |
||||
|
this.setObj(obj); |
||||
|
return this; |
||||
|
}; |
||||
|
|
||||
|
PayPro.prototype.makeX509Certificates = function(obj) { |
||||
|
this.messageType = 'X509Certificates'; |
||||
|
this.message = new PayPro.X509Certificates(); |
||||
|
this.setObj(obj); |
||||
|
return this; |
||||
|
}; |
||||
|
|
||||
|
PayPro.prototype.isValidSize = function() { |
||||
|
var s = this.serialize(); |
||||
|
if (this.messageType == 'PaymentRequest') |
||||
|
return s.length < PayPro.PAYMENT_REQUEST_MAX_SIZE; |
||||
|
if (this.messageType == 'Payment') |
||||
|
return s.length < PayPro.PAYMENT_MAX_SIZE; |
||||
|
if (this.messageType == 'PaymentACK') |
||||
|
return s.length < PayPro.PAYMENT_ACK_MAX_SIZE; |
||||
|
return true; |
||||
|
}; |
||||
|
|
||||
|
PayPro.prototype.getContentType = function() { |
||||
|
if (this.messageType == 'PaymentRequest') |
||||
|
return PayPro.PAYMENT_REQUEST_CONTENT_TYPE; |
||||
|
|
||||
|
if (this.messageType == 'Payment') |
||||
|
return PayPro.PAYMENT_CONTENT_TYPE; |
||||
|
|
||||
|
if (this.messageType == 'PaymentACK') |
||||
|
return PayPro.PAYMENT_ACK_CONTENT_TYPE; |
||||
|
|
||||
|
throw new Error('No known content type for this message type'); |
||||
|
}; |
||||
|
|
||||
|
PayPro.prototype.set = function(key, val) { |
||||
|
this.message.set(key, val); |
||||
|
return this; |
||||
|
}; |
||||
|
|
||||
|
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; |
||||
|
}; |
||||
|
|
||||
|
PayPro.prototype.setObj = function(obj) { |
||||
|
for (var key in obj) { |
||||
|
if (obj.hasOwnProperty(key)) { |
||||
|
var val = obj[key]; |
||||
|
this.message.set(key, val); |
||||
|
} |
||||
|
} |
||||
|
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)
|
||||
|
var maybebuf = this.message.toBuffer(); |
||||
|
var buf = (Buffer.isBuffer(maybebuf)) ? maybebuf : new Buffer(new Uint8Array(maybebuf)); |
||||
|
return buf; |
||||
|
}; |
||||
|
|
||||
|
PayPro.prototype.deserialize = function(buf, messageType) { |
||||
|
this.messageType = messageType || this.messageType; |
||||
|
if (!this.messageType) |
||||
|
throw new Error('Must specify messageType'); |
||||
|
this.message = PayPro[this.messageType].decode(buf); |
||||
|
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 if (pki_type === 'x509+sha1' || pki_type === 'x509+sha256') { |
||||
|
var sig = this.x509Sign(key); |
||||
|
} else if (pki_type === 'none') { |
||||
|
return this; |
||||
|
} 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 if (pki_type === 'x509+sha1' || pki_type === 'x509+sha256') { |
||||
|
return this.x509Verify(); |
||||
|
} else if (pki_type === 'none') { |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
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); |
||||
|
}; |
||||
|
|
||||
|
// Helpers
|
||||
|
|
||||
|
PayPro.prototype._PEMtoDER = function(pem) { |
||||
|
return this._PEMtoDERParam(pem); |
||||
|
}; |
||||
|
|
||||
|
PayPro.prototype._PEMtoDERParam = function(pem, param) { |
||||
|
if (Buffer.isBuffer(pem)) { |
||||
|
pem = pem.toString(); |
||||
|
} |
||||
|
var start = new RegExp('(?=-----BEGIN ' + (param || '[^-]+') + '-----)', 'i'); |
||||
|
var end = new RegExp('^-----END ' + (param || '[^-]+') + '-----$', 'gmi'); |
||||
|
pem = pem.replace(end, ''); |
||||
|
var parts = pem.split(start); |
||||
|
return parts.map(function(part) { |
||||
|
var type = /-----BEGIN ([^-]+)-----/.exec(part)[1]; |
||||
|
part = part.replace(/-----BEGIN ([^-]+)-----/g, ''); |
||||
|
part = part.replace(/\s+/g, ''); |
||||
|
if (!param || type !== param) return; |
||||
|
return new Buffer(part, 'base64'); |
||||
|
}).filter(Boolean); |
||||
|
}; |
||||
|
|
||||
|
PayPro.prototype._DERtoPEM = function(der, type) { |
||||
|
if (typeof der === 'string') { |
||||
|
der = new Buffer(der, 'hex'); |
||||
|
} |
||||
|
var type = type || 'UNKNOWN'; |
||||
|
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'; |
||||
|
}; |
||||
|
|
||||
|
module.exports = PayPro; |
File diff suppressed because it is too large
@ -0,0 +1,19 @@ |
|||||
|
-----BEGIN CERTIFICATE----- |
||||
|
MIIDBjCCAe4CCQDI2qWdA3/VpDANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJB |
||||
|
VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 |
||||
|
cyBQdHkgTHRkMB4XDTE0MDcxNjAxMzM1MVoXDTE1MDcxNjAxMzM1MVowRTELMAkG |
||||
|
A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 |
||||
|
IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB |
||||
|
AMUybitmhi59XVySg4eDMDy1JJdxyOaRpxuWnOJf9IoZqvHMAvhVT4GTEufWspIr |
||||
|
Afswu77b5CZP27/gUjl+6MXSLLi93SkBabl11X63W/ecGJ+DPv54xIVzJYVTB/zg |
||||
|
ogIPSSoUyli+hkVmQAIQO5QUYYEjQ04kwudQm4iu8QOqTePrUB8aJiT162UZGwdp |
||||
|
JTn1sG7/d2NydShQ/otDzEBy8O64RLpsQvd/hx1FWFR+x9Uz2R9W3VCSdNoEHspS |
||||
|
bLGAicnWT8zU/87rbPyiVnUb+ZccBvbvbTDTIISW5gGjJDBovqOzzRMj96hxa2KW |
||||
|
IbOaaixzETQe/EDPSHjYyxcCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAL6AMMfC3 |
||||
|
TlRcmsIgHxjVD4XYtISlldnrn2X9zvFbJKCpNy8XQQosQxrhyfzPHQKjlS2L/KCG |
||||
|
Mnjx9QkYD2Hlp1MJ1uVv9888th/gcZOv3Or3hQyi5K1Sh5xCG+69lUOqUEGu9B4i |
||||
|
rsqoFomQVbQolSy+t4apdJi7kuEDwFDk4gZiVEfsuX+naN5a6pCnWnhX1Vf4fKwf |
||||
|
kLobKKXm2zQVsjxlwBAqOEmJGDLoRMXH56qJnEZ/dqsczaJOHQSi9mFEHL0r5rsE |
||||
|
DTT5AVxdnBfNnyGaCH7/zANEko+FGBj1JdJaJgFTXdbxDoyoPTPD+LJqSK5XYToo |
||||
|
46y/T0u9CLveNA== |
||||
|
-----END CERTIFICATE----- |
@ -0,0 +1,16 @@ |
|||||
|
-----BEGIN CERTIFICATE REQUEST----- |
||||
|
MIICijCCAXICAQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx |
||||
|
ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcN |
||||
|
AQEBBQADggEPADCCAQoCggEBAMUybitmhi59XVySg4eDMDy1JJdxyOaRpxuWnOJf |
||||
|
9IoZqvHMAvhVT4GTEufWspIrAfswu77b5CZP27/gUjl+6MXSLLi93SkBabl11X63 |
||||
|
W/ecGJ+DPv54xIVzJYVTB/zgogIPSSoUyli+hkVmQAIQO5QUYYEjQ04kwudQm4iu |
||||
|
8QOqTePrUB8aJiT162UZGwdpJTn1sG7/d2NydShQ/otDzEBy8O64RLpsQvd/hx1F |
||||
|
WFR+x9Uz2R9W3VCSdNoEHspSbLGAicnWT8zU/87rbPyiVnUb+ZccBvbvbTDTIISW |
||||
|
5gGjJDBovqOzzRMj96hxa2KWIbOaaixzETQe/EDPSHjYyxcCAwEAAaAAMA0GCSqG |
||||
|
SIb3DQEBCwUAA4IBAQCu1Pdo1bKywBtzBXkqGudI5Nab6ixthjtlByTXdRd/7iy9 |
||||
|
zPMqoM6DBB9VtS6mnco7G1R8VaJu83N/uRoWCM80lb47isXRoMLe1DOrkjWmzjdU |
||||
|
/rvwjhEzq2v42OVASgTD/sRziDOJ2DTG5W4VMEDzIEHFCXdbCc2HodA5/iSM9m5i |
||||
|
FhhYC9HAHdHXgh1SVulxSGj6zOanOoNs68UBRnyGhS+c4lEDqlWw+WMioxmGgKic |
||||
|
XnFvGu5u6g7lzjKUV5H/oHnLhkY3llA67dyz3EK6Nij9+CLfNHfTz4c6DO2J9FQp |
||||
|
ME9S6EZSnvyDIKT6pgVk3nDiLzyYpQJ44cDlH2Db |
||||
|
-----END CERTIFICATE REQUEST----- |
Binary file not shown.
@ -0,0 +1,27 @@ |
|||||
|
-----BEGIN RSA PRIVATE KEY----- |
||||
|
MIIEpAIBAAKCAQEAxTJuK2aGLn1dXJKDh4MwPLUkl3HI5pGnG5ac4l/0ihmq8cwC |
||||
|
+FVPgZMS59aykisB+zC7vtvkJk/bv+BSOX7oxdIsuL3dKQFpuXXVfrdb95wYn4M+ |
||||
|
/njEhXMlhVMH/OCiAg9JKhTKWL6GRWZAAhA7lBRhgSNDTiTC51CbiK7xA6pN4+tQ |
||||
|
HxomJPXrZRkbB2klOfWwbv93Y3J1KFD+i0PMQHLw7rhEumxC93+HHUVYVH7H1TPZ |
||||
|
H1bdUJJ02gQeylJssYCJydZPzNT/zuts/KJWdRv5lxwG9u9tMNMghJbmAaMkMGi+ |
||||
|
o7PNEyP3qHFrYpYhs5pqLHMRNB78QM9IeNjLFwIDAQABAoIBAQDERrjPbAGcnl1h |
||||
|
+db+9734fthIARJVJJ5u4E+RJq8REhFLEKPYJ5m2P/xuVA1zXWlgaxZEFzwUQiJY |
||||
|
7l8JKV9pHxQyYZCS8vwXg8iXksvwPidoBcuan/wDVCQBey6VLcUzRaGuR/lLsX+V |
||||
|
7ftB0oRqlIqkbcPdMMvqTxowRuhPmuCrVTjO4pbNqnSONPLOiJ/FAXb2pfzFfpBR |
||||
|
Gx+EMmzwe+HFnJBGDhHZ99nn/TBfaJzNVCqDY/3bwz5X7HQNY7T+JyTUFseQ94xs |
||||
|
zrkibtdfTcTjpu+UhZo4sZzCr+fHGZoE9GDPqtd4gCprk4EKJsmqBESxBXSDhYgN |
||||
|
9pUD38sZAoGBAOrfDjt6Z/FCjanU8WzNFif+9T1A2xoMwD5VSlMuRrYmGlfr0C9M |
||||
|
f1EogivuTkbp7rkgdTaYTSbwfNqZBKxctyc7BhdpZxDEWJkfyq8qVx/zmBzMI+Vs |
||||
|
2Kb/apvWrbeosDOCryH5c8JsUT9xTX3XbxEjyOJQBSYGDMjPyJ6E9s6LAoGBANbv |
||||
|
wgtKckkKKl2a5vshdvDCg6qK/QgOm/6KTJUJESjhz2tR+fPVR70TH9RhhTRlpDWB |
||||
|
Bwz2ScBsTQ42/Lk1Fy20T/rMvKufHL5TMA4fz5dq1LHnczz6Uk5gXKAOOkR9UuXi |
||||
|
Tty3hDG2BC86MKMRxJ51EbqjoxwER100SanMPfMlAoGAIHKcZr8saPpG0/WlPODA |
||||
|
dNoWS1YQbvLgBDyIPiGghz2QWiEr67znwfCUuzj6+3UKE+1WBCraTczfktuc96r/ |
||||
|
ap4O42EeagSWMOFhgP2ad8GRfDj/pIx7CeczdUAdU8gsP5GIXGs4AN4yA0/F4uLG |
||||
|
Z1nIQOvJKk2fqoZ6MtwvtK0CgYEAgJ7FLeCE93Rf2dgCdTGXbYfZJss5lAK6Et5L |
||||
|
6budSyul5gEOZH2zClBRcdRR1AMm+uWVhIo1pDKrAeCh52r/zdfjLKAsHz9+Ad7i |
||||
|
GPGsVl4Vnch1S344lrJPe3BIKggc/Xgp3SbssprLcj+OL2dIk9JWo6ucxf1Bf2L0 |
||||
|
2elhAQkCgYBXsyzVV/ZJqXNpWCg55L3UFoTLyKSqlVKM3WiG5BKn4AazVCHL+GQU |
||||
|
xwxSgR9fQ4Inu+rPrN3Imyk0lKPGF9SzCRRTiJFR72sNqlO6l0V8CWRAPTPJcgqV |
||||
|
1U8NHK8b3ZiIoGJ+msNzpdxrj62H3A6+Y+AsNY4SmUTXH9yjg+nukg== |
||||
|
-----END RSA PRIVATE KEY----- |
@ -0,0 +1,46 @@ |
|||||
|
-----BEGIN CERTIFICATE----- |
||||
|
MIIDBjCCAe4CCQDI2qWdA3/VpDANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJB |
||||
|
VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 |
||||
|
cyBQdHkgTHRkMB4XDTE0MDcxNjAxMzM1MVoXDTE1MDcxNjAxMzM1MVowRTELMAkG |
||||
|
A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 |
||||
|
IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB |
||||
|
AMUybitmhi59XVySg4eDMDy1JJdxyOaRpxuWnOJf9IoZqvHMAvhVT4GTEufWspIr |
||||
|
Afswu77b5CZP27/gUjl+6MXSLLi93SkBabl11X63W/ecGJ+DPv54xIVzJYVTB/zg |
||||
|
ogIPSSoUyli+hkVmQAIQO5QUYYEjQ04kwudQm4iu8QOqTePrUB8aJiT162UZGwdp |
||||
|
JTn1sG7/d2NydShQ/otDzEBy8O64RLpsQvd/hx1FWFR+x9Uz2R9W3VCSdNoEHspS |
||||
|
bLGAicnWT8zU/87rbPyiVnUb+ZccBvbvbTDTIISW5gGjJDBovqOzzRMj96hxa2KW |
||||
|
IbOaaixzETQe/EDPSHjYyxcCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAL6AMMfC3 |
||||
|
TlRcmsIgHxjVD4XYtISlldnrn2X9zvFbJKCpNy8XQQosQxrhyfzPHQKjlS2L/KCG |
||||
|
Mnjx9QkYD2Hlp1MJ1uVv9888th/gcZOv3Or3hQyi5K1Sh5xCG+69lUOqUEGu9B4i |
||||
|
rsqoFomQVbQolSy+t4apdJi7kuEDwFDk4gZiVEfsuX+naN5a6pCnWnhX1Vf4fKwf |
||||
|
kLobKKXm2zQVsjxlwBAqOEmJGDLoRMXH56qJnEZ/dqsczaJOHQSi9mFEHL0r5rsE |
||||
|
DTT5AVxdnBfNnyGaCH7/zANEko+FGBj1JdJaJgFTXdbxDoyoPTPD+LJqSK5XYToo |
||||
|
46y/T0u9CLveNA== |
||||
|
-----END CERTIFICATE----- |
||||
|
-----BEGIN RSA PRIVATE KEY----- |
||||
|
MIIEpAIBAAKCAQEAxTJuK2aGLn1dXJKDh4MwPLUkl3HI5pGnG5ac4l/0ihmq8cwC |
||||
|
+FVPgZMS59aykisB+zC7vtvkJk/bv+BSOX7oxdIsuL3dKQFpuXXVfrdb95wYn4M+ |
||||
|
/njEhXMlhVMH/OCiAg9JKhTKWL6GRWZAAhA7lBRhgSNDTiTC51CbiK7xA6pN4+tQ |
||||
|
HxomJPXrZRkbB2klOfWwbv93Y3J1KFD+i0PMQHLw7rhEumxC93+HHUVYVH7H1TPZ |
||||
|
H1bdUJJ02gQeylJssYCJydZPzNT/zuts/KJWdRv5lxwG9u9tMNMghJbmAaMkMGi+ |
||||
|
o7PNEyP3qHFrYpYhs5pqLHMRNB78QM9IeNjLFwIDAQABAoIBAQDERrjPbAGcnl1h |
||||
|
+db+9734fthIARJVJJ5u4E+RJq8REhFLEKPYJ5m2P/xuVA1zXWlgaxZEFzwUQiJY |
||||
|
7l8JKV9pHxQyYZCS8vwXg8iXksvwPidoBcuan/wDVCQBey6VLcUzRaGuR/lLsX+V |
||||
|
7ftB0oRqlIqkbcPdMMvqTxowRuhPmuCrVTjO4pbNqnSONPLOiJ/FAXb2pfzFfpBR |
||||
|
Gx+EMmzwe+HFnJBGDhHZ99nn/TBfaJzNVCqDY/3bwz5X7HQNY7T+JyTUFseQ94xs |
||||
|
zrkibtdfTcTjpu+UhZo4sZzCr+fHGZoE9GDPqtd4gCprk4EKJsmqBESxBXSDhYgN |
||||
|
9pUD38sZAoGBAOrfDjt6Z/FCjanU8WzNFif+9T1A2xoMwD5VSlMuRrYmGlfr0C9M |
||||
|
f1EogivuTkbp7rkgdTaYTSbwfNqZBKxctyc7BhdpZxDEWJkfyq8qVx/zmBzMI+Vs |
||||
|
2Kb/apvWrbeosDOCryH5c8JsUT9xTX3XbxEjyOJQBSYGDMjPyJ6E9s6LAoGBANbv |
||||
|
wgtKckkKKl2a5vshdvDCg6qK/QgOm/6KTJUJESjhz2tR+fPVR70TH9RhhTRlpDWB |
||||
|
Bwz2ScBsTQ42/Lk1Fy20T/rMvKufHL5TMA4fz5dq1LHnczz6Uk5gXKAOOkR9UuXi |
||||
|
Tty3hDG2BC86MKMRxJ51EbqjoxwER100SanMPfMlAoGAIHKcZr8saPpG0/WlPODA |
||||
|
dNoWS1YQbvLgBDyIPiGghz2QWiEr67znwfCUuzj6+3UKE+1WBCraTczfktuc96r/ |
||||
|
ap4O42EeagSWMOFhgP2ad8GRfDj/pIx7CeczdUAdU8gsP5GIXGs4AN4yA0/F4uLG |
||||
|
Z1nIQOvJKk2fqoZ6MtwvtK0CgYEAgJ7FLeCE93Rf2dgCdTGXbYfZJss5lAK6Et5L |
||||
|
6budSyul5gEOZH2zClBRcdRR1AMm+uWVhIo1pDKrAeCh52r/zdfjLKAsHz9+Ad7i |
||||
|
GPGsVl4Vnch1S344lrJPe3BIKggc/Xgp3SbssprLcj+OL2dIk9JWo6ucxf1Bf2L0 |
||||
|
2elhAQkCgYBXsyzVV/ZJqXNpWCg55L3UFoTLyKSqlVKM3WiG5BKn4AazVCHL+GQU |
||||
|
xwxSgR9fQ4Inu+rPrN3Imyk0lKPGF9SzCRRTiJFR72sNqlO6l0V8CWRAPTPJcgqV |
||||
|
1U8NHK8b3ZiIoGJ+msNzpdxrj62H3A6+Y+AsNY4SmUTXH9yjg+nukg== |
||||
|
-----END RSA PRIVATE KEY----- |
@ -0,0 +1,9 @@ |
|||||
|
-----BEGIN PUBLIC KEY----- |
||||
|
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxTJuK2aGLn1dXJKDh4Mw |
||||
|
PLUkl3HI5pGnG5ac4l/0ihmq8cwC+FVPgZMS59aykisB+zC7vtvkJk/bv+BSOX7o |
||||
|
xdIsuL3dKQFpuXXVfrdb95wYn4M+/njEhXMlhVMH/OCiAg9JKhTKWL6GRWZAAhA7 |
||||
|
lBRhgSNDTiTC51CbiK7xA6pN4+tQHxomJPXrZRkbB2klOfWwbv93Y3J1KFD+i0PM |
||||
|
QHLw7rhEumxC93+HHUVYVH7H1TPZH1bdUJJ02gQeylJssYCJydZPzNT/zuts/KJW |
||||
|
dRv5lxwG9u9tMNMghJbmAaMkMGi+o7PNEyP3qHFrYpYhs5pqLHMRNB78QM9IeNjL |
||||
|
FwIDAQAB |
||||
|
-----END PUBLIC KEY----- |
Loading…
Reference in new issue