Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expect full ILP packet & add disallowOverPayment #16

Merged
merged 3 commits into from
Aug 3, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 34 additions & 18 deletions src/lib/receiver.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const Client = require('ilp-core').Client
const cc = require('five-bells-condition')
const EventEmitter = require('eventemitter2')
const debug = require('debug')('ilp-itp:receiver')
const BigNumber = require('bignumber.js')

/**
* @module Receiver
Expand All @@ -23,6 +24,7 @@ const debug = require('debug')('ilp-itp:receiver')
* @param {ilp-core.Client} [opts.client] [ilp-core](https://github.com/interledger/js-ilp-core) Client, which can optionally be supplied instead of the previous options
* @param {Buffer} [opts.hmacKey=crypto.randomBytes(32)] 32-byte secret used for generating request conditions
* @param {Number} [opts.defaultRequestTimeout=30] Default time in seconds that requests will be valid for
* @param {Boolean} [opts.allowOverPayment=false] Allow transfers where the amount is greater than requested
* @return {Receiver}
*/
function createReceiver (opts) {
Expand All @@ -38,6 +40,7 @@ function createReceiver (opts) {
}
const hmacKey = opts.hmacKey || crypto.randomBytes(32)
const defaultRequestTimeout = opts.defaultRequestTimeout || 30
const allowOverPayment = !!opts.allowOverPayment

/**
* Create a payment request
Expand Down Expand Up @@ -97,27 +100,40 @@ function createReceiver (opts) {
return 'no-execution'
}

// TODO look for the request in transfer.data.ilp_header after https://github.com/interledger/five-bells-connector/pull/195 is merged
// if (!transfer.data || !transfer.data.ilp_header) {
// debug('got notification of transfer without ilp packet', transfer)
// return false
// }
const request = {
amount: String(transfer.amount),
ledger: client.getPlugin().id,
account: client.getPlugin().getAccount(),
data: {
expires_at: transfer.data.expires_at,
request_id: transfer.data.request_id
// The request is the ilp_header
let request = transfer.data && transfer.data.ilp_header
if (request && request.data && request.data.execution_condition) {
delete request.data.execution_condition
}

// For now support the old connector behavior that only passes on the ILP packet data field
if (!request && transfer.data.request_id) {
debug('using old behavior for when connector only passes on the ilp packet data field')
request = {
amount: (new BigNumber(transfer.amount)).toString(),
ledger: client.getPlugin().id,
account: client.getPlugin().getAccount(),
data: {
expires_at: transfer.data.expires_at,
request_id: transfer.data.request_id
}
}
}

// TODO re-enable this when we aren't using the transfer's amount
// TODO also allow receiver to disallow amounts greater than requested
// if ((new BigNumber(transfer.amount)).lessThan(request.amount)) {
// debug('got notification of transfer where amount is less than expected (' + request.amount + ')', transfer)
// return 'insufficient'
// }
if (!request) {
debug('got notification of transfer with no request attached')
return 'no-packet'
}

if ((new BigNumber(transfer.amount)).lessThan(request.amount)) {
debug('got notification of transfer where amount is less than expected (' + request.amount + ')', transfer)
return 'insufficient'
}

if (!allowOverPayment && (new BigNumber(transfer.amount)).greaterThan(request.amount)) {
debug('got notification of transfer where amount is greater than expected (' + request.amount + ')', transfer)
return 'overpayment-disallowed'
}

if (request.data.expires_at && moment().isAfter(request.data.expires_at)) {
debug('got notification of transfer with expired request packet', transfer)
Expand Down
2 changes: 1 addition & 1 deletion test/data/paymentParams.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@
"request_id": "22e315dc-3f99-4f89-9914-1987ceaa906d",
"expires_at": "1970-01-01T00:00:10Z"
},
"executionCondition": "cc:0:3:crwqC6igtxv1DsIFiKv91roUp7qQxToKutwGELGQZIE:32",
"executionCondition": "cc:0:3:4l2SBwP_i-oCEzaD2IGRpwdywCfaBmrxJcpJ_3PXv6o:32",
"expiresAt": "1970-01-01T00:00:10.000Z"
}
2 changes: 1 addition & 1 deletion test/data/paymentRequest.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
"data": {
"request_id": "22e315dc-3f99-4f89-9914-1987ceaa906d",
"expires_at": "1970-01-01T00:00:10Z",
"execution_condition": "cc:0:3:crwqC6igtxv1DsIFiKv91roUp7qQxToKutwGELGQZIE:32"
"execution_condition": "cc:0:3:4l2SBwP_i-oCEzaD2IGRpwdywCfaBmrxJcpJ_3PXv6o:32"
}
}
14 changes: 11 additions & 3 deletions test/data/transferIncoming.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,17 @@
"account": "https://blue.ilpdemo.org/ledger/accounts/connie",
"amount": "1.0000",
"data":{
"request_id": "22e315dc-3f99-4f89-9914-1987ceaa906d",
"expires_at": "1970-01-01T00:00:10Z"
"ilp_header": {
"ledger": "https://blue.ilpdemo.org/ledger",
"account": "https://blue.ilpdemo.org/ledger/accounts/bob",
"amount": "1",
"data": {
"request_id": "22e315dc-3f99-4f89-9914-1987ceaa906d",
"expires_at": "1970-01-01T00:00:10Z",
"execution_condition": "cc:0:3:4l2SBwP_i-oCEzaD2IGRpwdywCfaBmrxJcpJ_3PXv6o:32"
}
}
},
"executionCondition": "cc:0:3:crwqC6igtxv1DsIFiKv91roUp7qQxToKutwGELGQZIE:32",
"executionCondition": "cc:0:3:4l2SBwP_i-oCEzaD2IGRpwdywCfaBmrxJcpJ_3PXv6o:32",
"expiresAt": "1970-01-01T00:00:10.000Z"
}
56 changes: 47 additions & 9 deletions test/receiverSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -182,30 +182,39 @@ describe('Receiver Module', function () {
expect(results).to.deep.equal(['no-execution'])
})

it.skip('should ignore transfers without ilp packets in the data field', function * () {

it('should ignore transfers without ilp packets in the data field', function * () {
const results = yield this.client.emitAsync('receive', _.assign(this.transfer, {
data: { not: 'a packet' }
}))
expect(results).to.deep.equal(['no-packet'])
})

it('should ignore expired packets', function * () {
timekeeper.freeze(new Date(10000))
const results = yield this.client.emitAsync('receive', _.merge(this.transfer, {
data: {
expires_at: '1970-01-01T00:00:01Z'
ilp_header: {
data: {
expires_at: '1970-01-01T00:00:01Z'
}
}
}
}))
expect(results).to.deep.equal(['expired'])
})

// TODO re-enable this when we aren't using the transfer's amount
it.skip('should ignore transfers where the amount is less than specified in the packet', function * () {
it('should ignore transfers where the amount is less than specified in the packet', function * () {
const results = yield this.client.emitAsync('receive', _.merge(this.transfer, {
amount: '1.0000000000001'
amount: '0.999999999'
}))
expect(results).to.deep.equal(['insufficient'])
})

it.skip('should ignore transfers where the amount is more than requested if disallowOverPayment is set', function () {

it('should ignore transfers where the amount is more than requested', function * () {
const results = yield this.client.emitAsync('receive', _.merge(this.transfer, {
amount: '1.0000000001'
}))
expect(results).to.deep.equal(['overpayment-disallowed'])
})

it('should ignore transfers where the executionCondition does not match the generated condition', function * () {
Expand All @@ -216,7 +225,36 @@ describe('Receiver Module', function () {
})

it('should fulfill the conditions of transfers corresponding to requests generated by the receiver', function * () {
const results = yield this.client.emitAsync('receive', this.transfer)
const request = this.receiver.createRequest({
amount: 1
})
const results = yield this.client.emitAsync('receive', _.assign(this.transfer, {
data: {
ilp_header: request
},
executionCondition: request.data.execution_condition
}))
expect(results).to.deep.equal(['sent'])
})

it('should allow overpayment if allowOverPayment is set', function * () {
const receiver = createReceiver({
client: this.client,
hmacKey: Buffer.from('+Xd3hhabpygJD6cen+R/eon+acKWvFLzqp65XieY8W0=', 'base64'),
allowOverPayment: true
})
yield receiver.listen()
const results = yield this.client.emitAsync('receive', _.assign(this.transfer, {
amount: '10000000000000' // a bit excessive, i know
}))
// because we're instantiating an extra receiver there will actually be two events
expect(results).to.contain('sent')
})

it('should (temporarily) support the old behavior where the connector only passes on the ilp packet data field', function * () {
const results = yield this.client.emitAsync('receive', _.assign(this.transfer, {
data: this.transfer.data.ilp_header.data
}))
expect(results).to.deep.equal(['sent'])
})
})
Expand Down
2 changes: 1 addition & 1 deletion test/senderSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ describe('Sender Module', function () {
'request_id': '22e315dc-3f99-4f89-9914-1987ceaa906d',
'expires_at': '1970-01-01T00:00:10Z'
},
'executionCondition': 'cc:0:3:crwqC6igtxv1DsIFiKv91roUp7qQxToKutwGELGQZIE:32',
'executionCondition': 'cc:0:3:4l2SBwP_i-oCEzaD2IGRpwdywCfaBmrxJcpJ_3PXv6o:32',
'expiresAt': '1970-01-01T00:00:10.000Z'
})
})
Expand Down