node-payments
Version:
node-payments is a express based facade to multiple payment services.
161 lines (133 loc) • 4.51 kB
text/coffeescript
config = require( "../../lib/config" )
request = require( "request" )
crypto = require( "crypto" )
_ = require( "lodash" )
async = require( "async" )
xml2js = require( "xml2js" )
xmlParser = new xml2js.Parser()
class ClickAndBuyMMS extends require( "../_base/main" )
initialize: =>
@cbConfig = config.get( "clickandbuy" )
@initialized = false
@_currencies = config.get( "defaultcurrency" )
#@initIPN()
return
init: ( @main )=>
if not @initialized
@initialized = true
server = @main.getExpress()
server.post @config.receiverPath, @verify, @input
return
answer200: ( req, res, next )=>
@debug "IPN Input", req.body
res.send( "OK" )
next()
return
checkSignature: ( xml, sig, secret )=>
_cleanXML = ( xml.replace( "<signature>#{sig}</signature>", "<signature />" ) )
_hs = "#{secret}#{_cleanXML}"
_hash = crypto.createHash('sha1').update( _hs ).digest('hex')
#console.log _hash, sig, _cleanXML
if sig is _hash
return true
else
return false
verify: ( req, res, next )=>
@debug "REQUEST INCOME", req.body
if not req.body.xml?
# if no payload exists is't just a ping to verify the availibility of this endpoint.
res.send( "OK" )
return
xmlParser.parseString req.body.xml, ( err, bodyObj )=>
if err
@error( "parse xml", err )
res.send( "FAILED", 500 )
return
signature = bodyObj?.eventlist?.signature?[ 0 ]
req._mmsevents = bodyObj?.eventlist?.payEvent
if @checkSignature( req.body.xml, signature, @config.cryptokey )
next()
else
@_handleError( null, "ECBMMSINVALIDSIGNATURE" )
res.send( "FAILED", 500 )
return
return
input: ( req, res )=>
afns = []
for _event in req._mmsevents
afns.push( @processEvent( _event ) )
async.series afns, ( err )=>
@info "processed #{afns.length} mms events"
if err?
@error( err )
res.send( "FAILED", 500 )
return
res.send( "OK" )
return
return
processEvent: ( data )=>
return ( cb )=>
try
_pid = data.externalID[ 0 ]
_rawstate = data.newState[ 0 ]
_transaction = data.transactionID[ 0 ]
_merchantID = data.merchantID[ 0 ]
_dataAmout = data.merchantAmount[ 0 ]
_currency = _dataAmout.currency[ 0 ]
_payer = data.crn?[ 0 ]
_atype = @_currencies[ _currency ]
if _atype is "int"
_amount = parseInt( _dataAmout.amount[ 0 ], 10 )
else
_amount = parseFloat( _dataAmout.amount[ 0 ], 10 )
if @cbConfig.merchantid? and _merchantID isnt @cbConfig.merchantid
@_handleError( cb, "ECBMMSINVALIDMERCHANT", { got: _merchantID, needed: @cbConfig.merchantid } )
return
@main.getPayment _pid, ( err, payment )=>
if err
if not config.get( "productionmode" ) and err?.name is "EPAYMENTNOTFOUND"
@warning( "Payment not found in system so return a 200 to IPN" )
cb( null )
return
cb( err )
return
@debug "MMS returned", _pid, payment.valueOf()
if _currency isnt payment.currency
@_handleError( cb, "ECBMMSINVALIDCURRENCY", { got: _currency, needed: payment.currency } )
return
if Math.abs( _amount ) isnt payment.amount
@_handleError( cb, "ECBMMSINVALIDAMOUNT", { got: _amount, needed: payment.amount } )
return
try
_state = payment._translateState( _rawstate )
payment.set( "rawProviderState", _rawstate )
payment.set( "payer_id", _payer ) if _payer?.length
payment.set( "state", _state )
payment.set( "transaction", _transaction )
payment.set( "verified", true )
catch _err
@error( _err )
cb( _err )
return
payment.persist ( err )=>
if err
cb( err )
return
@main.emit( "payment", "verfied", payment )
@main.emit( "payment:#{payment.id}", "verfied", payment )
@main.emit( "verfied", payment )
cb( null )
return
return
catch _err
@error( _err )
cb( _err )
return
return
ERRORS: =>
@extend super,
"ECBMMSINVALIDMERCHANT": "The click and buy MMS sends a completed message for a wrong receiver. Has to be `<%= needed %>` bot got `<%= got %>`."
"ECBMMSINVALIDCURRENCY": "The click and buy MMS sends a currency unlike the expected. Has to be `<%= needed %>` bot got `<%= got %>`."
"ECBMMSINVALIDAMOUNT": "The click and buy MMS sends a amount unlike the expected. Has to be `<%= needed %>` bot got `<%= got %>`."
"ECBMMSINVALIDSIGNATURE": "The signature check failed."
module.exports = new ClickAndBuyMMS()