Skip to content

Commit

Permalink
Merge pull request #19 from netkicorp/bip75_endpoints
Browse files Browse the repository at this point in the history
Bip75 endpoints
  • Loading branch information
alan10fm authored Feb 25, 2021
2 parents c9a07b5 + ffd9139 commit fea196d
Show file tree
Hide file tree
Showing 3 changed files with 187 additions and 34 deletions.
28 changes: 25 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,29 @@ Also you can implement your own clients to connect to the API.

## General Usage

## Synchronous flow
## Bip75

### Synchronous flow

Endpoint: `/addresses/{address_id}/messages`
Description: `Send protocol message binary to this endpoint and receive the correspondent protocol message response synchronous.`
Verb: `POST`
Params:
- protocolMessage: `Binary containing protocolMessage`
Response: `Binary containing protocolMessage`

### Async flow

Endpoint: `/addresses/{address_id}/messages?async=true`
Description: `This endpoint receives a protocolMessage binary and gives a 202 in return. Asynchronously you will receive the correspondent protocolMessage binary in the URL defined in the protocolMessage`
Verb: `POST`
Params:
- invoiceRequest: `Binary containing protocolMessage`
Response: `HttpStatus 202 or error code`

## Testing messages independently

### Synchronous flow

### Initial invoice request

Expand Down Expand Up @@ -101,7 +123,7 @@ Params:
- payment: `Binary containing payment`
Response: `Binary containing paymentAck`

## Asynchronous flow
### Asynchronous flow

### Initial invoice request

Expand Down Expand Up @@ -157,7 +179,7 @@ Response: `Binary containing paymentAck`
### Encryption
You can generate EncryptedMessages to test this functionality. Once you start the service you can fetch a set of ECDSA keys to use in your ProtocolMessages.

Endpoint: `/encryption/keys`
Endpoint: `/utils/encryption/keys`
Description: `Send a GET request to this to receive a set of sender/recipient keys to test encrypted messages`
Verb: `GET`
Response: `Set of keys to do encryption`
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package com.netki.transactidlibraryjavademo.controller

import com.netki.transactidlibraryjavademo.service.TransactIdService
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.Parameter
import io.swagger.v3.oas.annotations.media.Content
import io.swagger.v3.oas.annotations.media.Schema
import io.swagger.v3.oas.annotations.responses.ApiResponse
import io.swagger.v3.oas.annotations.responses.ApiResponses
import io.swagger.v3.oas.annotations.tags.Tag
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*

@RestController
@Tag(name = "Bip75", description = "BIP75 API")
class Bip75Controller {

@Autowired
private lateinit var transactIdService: TransactIdService

@Operation(
summary = "Post protocol message binary",
description = "Post a protocol message binary, could be encrypted or not"
)
@ApiResponses(
value = [
ApiResponse(
responseCode = "202",
description = "Protocol message accepted and stored."
),
ApiResponse(
responseCode = "200",
description = "Returns the correspondent response for the protocol message.",
content = [
Content(
mediaType = MediaType.APPLICATION_OCTET_STREAM_VALUE,
schema = Schema(implementation = ByteArray::class)
)
]
)
]
)
@RequestMapping(
method = [RequestMethod.POST],
value = ["/addresses/{address_id}/messages"],
consumes = [MediaType.APPLICATION_OCTET_STREAM_VALUE],
produces = [MediaType.APPLICATION_OCTET_STREAM_VALUE]
)
fun sendProtocolMessage(
@Parameter(description = "Unique identifier for address.")
@PathVariable("address_id") addressId: String,
@Parameter(description = "Set to true if you want to do this flow async, false otherwise.")
@RequestParam async: Boolean = false,
@Parameter(description = "Binary containing the protocol message")
@RequestBody protocolMessage: ByteArray
): ResponseEntity<Any> {
val messageResponse = when (async) {
true -> transactIdService.sendProtocolMessageAsync(addressId, protocolMessage)
false -> transactIdService.sendProtocolMessage(addressId, protocolMessage)
}
return if (messageResponse != null) {
ResponseEntity.ok(messageResponse)
} else {
ResponseEntity(HttpStatus.ACCEPTED)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,40 @@ class TransactIdService {

fun getVaspCertificate() = Information(VASP_CERTIFICATE)

fun sendProtocolMessage(addressId: String, protocolMessage: ByteArray): ByteArray? {
val protocolMessageMetadata = transactId.getProtocolMessageMetadata(protocolMessage)
val isEncrypted = protocolMessageMetadata.encrypted
val messageType = protocolMessageMetadata.messageType
val identifier = protocolMessageMetadata.identifier
return when (messageType) {
MessageType.INVOICE_REQUEST -> createPaymentRequest(isEncrypted, identifier)
MessageType.PAYMENT_REQUEST -> createPayment(protocolMessage)
MessageType.PAYMENT -> createPaymentAck(isEncrypted, identifier)
MessageType.PAYMENT_ACK -> null
MessageType.UNKNOWN_MESSAGE_TYPE -> throw IllegalArgumentException("UNKNOWN_MESSAGE_TYPE")
}
}

fun sendProtocolMessageAsync(addressId: String, protocolMessage: ByteArray): ByteArray? {
val protocolMessageMetadata = transactId.getProtocolMessageMetadata(protocolMessage)
val isEncrypted = protocolMessageMetadata.encrypted
val messageType = protocolMessageMetadata.messageType
val identifier = protocolMessageMetadata.identifier
return when (messageType) {
MessageType.INVOICE_REQUEST -> {
postInvoiceRequestAsync(protocolMessage)
null
}
MessageType.PAYMENT_REQUEST -> {
postPaymentRequestAsync(protocolMessage)
null
}
MessageType.PAYMENT -> createPaymentAck(isEncrypted, identifier)
MessageType.PAYMENT_ACK -> null
MessageType.UNKNOWN_MESSAGE_TYPE -> throw IllegalArgumentException("UNKNOWN_MESSAGE_TYPE")
}
}

fun sendInitialInvoiceRequest(url: String) {
val invoiceRequest = getInitialInvoiceRequest()
transactIdRepository.sendRequestNoResponse(invoiceRequest, url)
Expand All @@ -90,7 +124,7 @@ class TransactIdService {
val sender = SENDER_PKI_X509SHA256
val invoiceRequestParameters = InvoiceRequestParameters(
amount = 1000,
memo = "memo",
memo = "InvoiceRequest Memo",
notificationUrl = NOTIFICATION_URL,
originatorsAddresses = OUTPUTS,
originatorParameters = originators,
Expand All @@ -115,7 +149,7 @@ class TransactIdService {
)
val invoiceRequestParameters = InvoiceRequestParameters(
amount = 1000,
memo = "memo",
memo = "InvoiceRequest Encrypted Memo",
notificationUrl = NOTIFICATION_URL,
originatorsAddresses = OUTPUTS,
originatorParameters = originators,
Expand All @@ -134,24 +168,31 @@ class TransactIdService {
fun postInvoiceRequest(invoiceRequest: ByteArray): ByteArray {
logger.info("InvoiceRequest received")
logger.info(
"InvoiceRequest valid? ${transactId.isInvoiceRequestValid(
invoiceRequest,
recipientParameters
)}"
"InvoiceRequest valid? ${
transactId.isInvoiceRequestValid(
invoiceRequest,
recipientParameters
)
}"
)
val invoiceRequestModel =
transactId.parseInvoiceRequest(invoiceRequest, recipientParameters)
logger.info("InvoiceRequest parsed: $invoiceRequestModel")
return createPaymentRequest(invoiceRequestModel.protocolMessageMetadata.encrypted, invoiceRequestModel.protocolMessageMetadata.identifier)
return createPaymentRequest(
invoiceRequestModel.protocolMessageMetadata.encrypted,
invoiceRequestModel.protocolMessageMetadata.identifier
)
}

fun postInvoiceRequestAsync(invoiceRequest: ByteArray) {
logger.info("InvoiceRequest received")
logger.info(
"InvoiceRequest valid? ${transactId.isInvoiceRequestValid(
invoiceRequest,
recipientParameters
)}"
"InvoiceRequest valid? ${
transactId.isInvoiceRequestValid(
invoiceRequest,
recipientParameters
)
}"
)
val invoiceRequestModel =
transactId.parseInvoiceRequest(invoiceRequest, recipientParameters)
Expand All @@ -162,7 +203,10 @@ class TransactIdService {
throw IllegalArgumentException("Missing notificationUrl to send the async response")
} else {
val paymentRequest =
createPaymentRequest(invoiceRequestModel.protocolMessageMetadata.encrypted, invoiceRequestModel.protocolMessageMetadata.identifier)
createPaymentRequest(
invoiceRequestModel.protocolMessageMetadata.encrypted,
invoiceRequestModel.protocolMessageMetadata.identifier
)
transactIdRepository.sendRequestNoResponse(paymentRequest, notificationUrl)
}
}
Expand All @@ -180,7 +224,7 @@ class TransactIdService {
beneficiariesAddresses = OUTPUTS,
time = Timestamp(System.currentTimeMillis()),
expires = Timestamp(System.currentTimeMillis()),
memo = "memo",
memo = "PaymentRequest Encrypted Memo",
paymentUrl = PAYMENT_URL,
merchantData = "merchant data",
beneficiaryParameters = beneficiaries,
Expand All @@ -203,7 +247,7 @@ class TransactIdService {
beneficiariesAddresses = OUTPUTS,
time = Timestamp(System.currentTimeMillis()),
expires = Timestamp(System.currentTimeMillis()),
memo = "memo",
memo = "PaymentRequest Memo",
paymentUrl = PAYMENT_URL,
merchantData = "merchant data",
beneficiaryParameters = beneficiaries,
Expand All @@ -217,21 +261,25 @@ class TransactIdService {
fun postPaymentRequest(paymentRequest: ByteArray): ByteArray {
logger.info("PaymentRequest received")
logger.info(
"PaymentRequest valid? ${transactId.isPaymentRequestValid(
paymentRequest,
recipientParameters
)}"
"PaymentRequest valid? ${
transactId.isPaymentRequestValid(
paymentRequest,
recipientParameters
)
}"
)
return createPayment(paymentRequest)
}

fun postPaymentRequestAsync(paymentRequest: ByteArray) {
logger.info("PaymentRequest received")
logger.info(
"PaymentRequest valid? ${transactId.isPaymentRequestValid(
paymentRequest,
recipientParameters
)}"
"PaymentRequest valid? ${
transactId.isPaymentRequestValid(
paymentRequest,
recipientParameters
)
}"
)
val paymentRequestModel =
transactId.parsePaymentRequest(paymentRequest, recipientParameters)
Expand Down Expand Up @@ -267,14 +315,17 @@ class TransactIdService {
"transaction2".toByteArray()
),
outputs = OUTPUTS,
memo = "memo",
memo = "Payment Encrypted Memo",
originatorParameters = originators,
beneficiaryParameters = beneficiaries,
messageInformation = messageInformationEncrypted,
senderParameters = senderParameters,
recipientParameters = recipientParameters
)
transactId.createPayment(paymentParameters, paymentRequestModel.protocolMessageMetadata.identifier)
transactId.createPayment(
paymentParameters,
paymentRequestModel.protocolMessageMetadata.identifier
)

} else {
logger.info("Creating Payment...")
Expand All @@ -293,11 +344,14 @@ class TransactIdService {
"transaction2".toByteArray()
),
outputs = OUTPUTS,
memo = "memo",
memo = "Payment Memo",
originatorParameters = originators,
beneficiaryParameters = beneficiaries
)
transactId.createPayment(paymentParameters, paymentRequestModel.protocolMessageMetadata.identifier)
transactId.createPayment(
paymentParameters,
paymentRequestModel.protocolMessageMetadata.identifier
)
}
}

Expand All @@ -307,25 +361,32 @@ class TransactIdService {
val paymentModel = transactId.parsePayment(payment, recipientParameters)
logger.info("Payment parsed: $paymentModel")

return if (paymentModel.protocolMessageMetadata!!.encrypted) {
return createPaymentAck(
paymentModel.protocolMessageMetadata!!.encrypted,
paymentModel.protocolMessageMetadata!!.identifier
)
}

private fun createPaymentAck(encrypted: Boolean, identifier: String): ByteArray {
return if (encrypted) {
logger.info("Creating PaymentAck Encrypted...")
logger.info("Returning PaymentAck Encrypted...")
val paymentAckParameters = PaymentAckParameters(
payment = PAYMENT,
memo = "memo ack",
memo = "PaymentAck Encrypted Memo",
messageInformation = messageInformationEncrypted,
senderParameters = senderParameters,
recipientParameters = recipientParameters
)
transactId.createPaymentAck(paymentAckParameters, paymentModel.protocolMessageMetadata!!.identifier)
transactId.createPaymentAck(paymentAckParameters, identifier)
} else {
logger.info("Creating PaymentAck...")
logger.info("Returning PaymentAck...")
val paymentAckParameters = PaymentAckParameters(
payment = PAYMENT,
memo = "memo ack"
memo = "PaymentAck Memo"
)
transactId.createPaymentAck(paymentAckParameters, paymentModel.protocolMessageMetadata!!.identifier)
transactId.createPaymentAck(paymentAckParameters, identifier)
}
}
}

0 comments on commit fea196d

Please sign in to comment.