/** * Create a payment message with one standard pay to address output. * * @param transactions one or more transactions that satisfy the requested outputs. * @param refundAmount amount of coins to request as a refund, or null if no refund. * @param refundAddress address to refund coins to * @param memo arbitrary, user readable memo, or null if none * @param merchantData arbitrary merchant data, or null if none * @return created payment message */ public static Protos.Payment createPaymentMessage(List<Transaction> transactions, @Nullable Coin refundAmount, @Nullable Address refundAddress, @Nullable String memo, @Nullable byte[] merchantData) { if (refundAddress != null) { if (refundAmount == null) throw new IllegalArgumentException("Specify refund amount if refund address is specified."); return createPaymentMessage(transactions, ImmutableList.of(createPayToAddressOutput(refundAmount, refundAddress)), memo, merchantData); } else { return createPaymentMessage(transactions, null, memo, merchantData); } }
/** * Create a payment request with one standard pay to address output. You may want to sign the request using * {@link #signPaymentRequest}. Use {@link org.bitcoin.protocols.payments.Protos.PaymentRequest.Builder#build} to get the actual payment * request. * * @param params network parameters * @param amount amount of coins to request, or null * @param toAddress address to request coins to * @param memo arbitrary, user readable memo, or null if none * @param paymentUrl URL to send payment message to, or null if none * @param merchantData arbitrary merchant data, or null if none * @return created payment request, in its builder form */ public static Protos.PaymentRequest.Builder createPaymentRequest(NetworkParameters params, @Nullable Coin amount, Address toAddress, @Nullable String memo, @Nullable String paymentUrl, @Nullable byte[] merchantData) { return createPaymentRequest(params, ImmutableList.of(createPayToAddressOutput(amount, toAddress)), memo, paymentUrl, merchantData); }
@Override public PaymentProtocol.Ack call() throws Exception { HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("POST"); connection.setRequestProperty("Content-Type", PaymentProtocol.MIMETYPE_PAYMENT); connection.setRequestProperty("Accept", PaymentProtocol.MIMETYPE_PAYMENTACK); connection.setRequestProperty("Content-Length", Integer.toString(payment.getSerializedSize())); connection.setUseCaches(false); connection.setDoInput(true); connection.setDoOutput(true); // Send request. DataOutputStream outStream = new DataOutputStream(connection.getOutputStream()); payment.writeTo(outStream); outStream.flush(); outStream.close(); // Get response. Protos.PaymentACK paymentAck = Protos.PaymentACK.parseFrom(connection.getInputStream()); return PaymentProtocol.parsePaymentAck(paymentAck); } });
/** * Creates a PaymentSession from the provided {@link Protos.PaymentRequest}. * If verifyPki is true, also validates the signature and throws an exception if it fails. * If trustStoreLoader is null, the system default trust store is used. */ public PaymentSession(Protos.PaymentRequest request, boolean verifyPki, @Nullable final TrustStoreLoader trustStoreLoader) throws PaymentProtocolException { TrustStoreLoader nonNullTrustStoreLoader = trustStoreLoader != null ? trustStoreLoader : new TrustStoreLoader.DefaultTrustStoreLoader(); parsePaymentRequest(request); if (verifyPki) { try { pkiVerificationData = PaymentProtocol.verifyPaymentRequestPki(request, nonNullTrustStoreLoader.getKeyStore()); } catch (IOException x) { throw new PaymentProtocolException(x); } catch (KeyStoreException x) { throw new PaymentProtocolException(x); } } else { pkiVerificationData = null; } }
/** * @param merchantData The merchant data bytes (from the PaymentRequest) to reference * @param transactions The transactions that paid the payment request * @param refundAmount The amount to refund * @param refundAddress The refund address * @param paymentMemo The memo for the payment * @return a new BIP70 payment */ public Optional<Protos.Payment> newPayment(byte[] merchantData, List<Transaction> transactions, Coin refundAmount, Address refundAddress, String paymentMemo) { return Optional.of(PaymentProtocol.createPaymentMessage(transactions, refundAmount, refundAddress, paymentMemo, merchantData)); }
@Test(expected = PkiVerificationException.class) public void testSignAndVerifyExpired() throws Exception { Protos.PaymentRequest.Builder paymentRequest = minimalPaymentRequest().toBuilder(); // Sign KeyStore keyStore = X509Utils.loadKeyStore("JKS", "password", getClass().getResourceAsStream("test-expired-cert")); PrivateKey privateKey = (PrivateKey) keyStore.getKey("test-expired", "password".toCharArray()); X509Certificate clientCert = (X509Certificate) keyStore.getCertificate("test-expired"); PaymentProtocol.signPaymentRequest(paymentRequest, new X509Certificate[]{clientCert}, privateKey); // Verify PaymentProtocol.verifyPaymentRequestPki(paymentRequest.build(), caStore); }
paymentRequest = PaymentProtocol.createPaymentRequest( networkParameters, signedPaymentRequestSummary.getAmount(), PaymentProtocol.signPaymentRequest( paymentRequest, x509CertificateChain,
@Test public void testPaymentMessage() throws Exception { // Create List<Transaction> transactions = new LinkedList<>(); transactions.add(FakeTxBuilder.createFakeTx(NETWORK_PARAMS, AMOUNT, TO_ADDRESS)); Coin refundAmount = Coin.SATOSHI; Address refundAddress = new ECKey().toAddress(NETWORK_PARAMS); Payment payment = PaymentProtocol.createPaymentMessage(transactions, refundAmount, refundAddress, MEMO, MERCHANT_DATA); byte[] paymentBytes = payment.toByteArray(); // Parse Payment parsedPayment = Payment.parseFrom(paymentBytes); List<Transaction> parsedTransactions = PaymentProtocol.parseTransactionsFromPaymentMessage(NETWORK_PARAMS, parsedPayment); assertEquals(transactions, parsedTransactions); assertEquals(1, parsedPayment.getRefundToCount()); assertEquals(MEMO, parsedPayment.getMemo()); assertArrayEquals(MERCHANT_DATA, parsedPayment.getMerchantData().toByteArray()); }
@Test public void testPaymentRequest() throws Exception { // Create PaymentRequest paymentRequest = PaymentProtocol.createPaymentRequest(TestNet3Params.get(), AMOUNT, TO_ADDRESS, MEMO, PAYMENT_URL, MERCHANT_DATA).build(); byte[] paymentRequestBytes = paymentRequest.toByteArray(); // Parse PaymentSession parsedPaymentRequest = PaymentProtocol.parsePaymentRequest(PaymentRequest .parseFrom(paymentRequestBytes)); final List<Output> parsedOutputs = parsedPaymentRequest.getOutputs(); assertEquals(1, parsedOutputs.size()); assertEquals(AMOUNT, parsedOutputs.get(0).amount); assertArrayEquals(ScriptBuilder.createOutputScript(TO_ADDRESS).getProgram(), parsedOutputs.get(0).scriptData); assertEquals(MEMO, parsedPaymentRequest.getMemo()); assertEquals(PAYMENT_URL, parsedPaymentRequest.getPaymentUrl()); assertArrayEquals(MERCHANT_DATA, parsedPaymentRequest.getMerchantData()); }
/** * @param payment The BIP70 payment to reference * @param paymentACKMemo The memo for the paymentACK * @return a new BIP70 payment */ public Optional<Protos.PaymentACK> newPaymentACK(Protos.Payment payment, String paymentACKMemo) { return Optional.of(PaymentProtocol.createPaymentAck(payment, paymentACKMemo)); } }
StringBuilder output = new StringBuilder( format("Bitcoin payment request, version %d%nDate: %s%n", version, session.getDate())); PaymentProtocol.PkiVerificationData pki = PaymentProtocol.verifyPaymentRequestPki( session.getPaymentRequest(), new TrustStoreLoader.DefaultTrustStoreLoader().getKeyStore()); if (pki != null) {
/** * Generates a Payment message based on the information in the PaymentRequest. * Provide transactions built by the wallet. * If the PaymentRequest did not specify a payment_url, returns null. * @param txns list of transactions to be included with the Payment message. * @param refundAddr will be used by the merchant to send money back if there was a problem. * @param memo is a message to include in the payment message sent to the merchant. */ @Nullable public Protos.Payment getPayment(List<Transaction> txns, @Nullable Address refundAddr, @Nullable String memo) throws IOException, PaymentProtocolException.InvalidNetwork { if (paymentDetails.hasPaymentUrl()) { for (Transaction tx : txns) if (!tx.getParams().equals(params)) throw new PaymentProtocolException.InvalidNetwork(params.getPaymentProtocolId()); return PaymentProtocol.createPaymentMessage(txns, totalValue, refundAddr, memo, getMerchantData()); } else { return null; } }
@Test public void testSignAndVerifyValid() throws Exception { Protos.PaymentRequest.Builder paymentRequest = minimalPaymentRequest().toBuilder(); // Sign KeyStore keyStore = X509Utils .loadKeyStore("JKS", "password", getClass().getResourceAsStream("test-valid-cert")); PrivateKey privateKey = (PrivateKey) keyStore.getKey("test-valid", "password".toCharArray()); X509Certificate clientCert = (X509Certificate) keyStore.getCertificate("test-valid"); PaymentProtocol.signPaymentRequest(paymentRequest, new X509Certificate[]{clientCert}, privateKey); // Verify PkiVerificationData verificationData = PaymentProtocol.verifyPaymentRequestPki(paymentRequest.build(), caStore); assertNotNull(verificationData); assertEquals(caCert, verificationData.rootAuthority.getTrustedCert()); }
@Test public void testPaymentAck() throws Exception { // Create Payment paymentMessage = Protos.Payment.newBuilder().build(); PaymentACK paymentAck = PaymentProtocol.createPaymentAck(paymentMessage, MEMO); byte[] paymentAckBytes = paymentAck.toByteArray(); // Parse PaymentACK parsedPaymentAck = PaymentACK.parseFrom(paymentAckBytes); assertEquals(paymentMessage, parsedPaymentAck.getPayment()); assertEquals(MEMO, parsedPaymentAck.getMemo()); } }
/** * Create a payment request with one standard pay to address output. You may want to sign the request using * {@link #signPaymentRequest}. Use {@link Protos.PaymentRequest.Builder#build} to get the actual payment * request. * * @param params network parameters * @param amount amount of coins to request, or null * @param toAddress address to request coins to * @param memo arbitrary, user readable memo, or null if none * @param paymentUrl URL to send payment message to, or null if none * @param merchantData arbitrary merchant data, or null if none * @return created payment request, in its builder form */ public static Protos.PaymentRequest.Builder createPaymentRequest(NetworkParameters params, @Nullable Coin amount, Address toAddress, @Nullable String memo, @Nullable String paymentUrl, @Nullable byte[] merchantData) { return createPaymentRequest(params, ImmutableList.of(createPayToAddressOutput(amount, toAddress)), memo, paymentUrl, merchantData); }
/** * Create a payment message with one standard pay to address output. * * @param transactions one or more transactions that satisfy the requested outputs. * @param refundAmount amount of coins to request as a refund, or null if no refund. * @param refundAddress address to refund coins to * @param memo arbitrary, user readable memo, or null if none * @param merchantData arbitrary merchant data, or null if none * @return created payment message */ public static Protos.Payment createPaymentMessage(List<Transaction> transactions, @Nullable Coin refundAmount, @Nullable Address refundAddress, @Nullable String memo, @Nullable byte[] merchantData) { if (refundAddress != null) { if (refundAmount == null) throw new IllegalArgumentException("Specify refund amount if refund address is specified."); return createPaymentMessage(transactions, ImmutableList.of(createPayToAddressOutput(refundAmount, refundAddress)), memo, merchantData); } else { return createPaymentMessage(transactions, null, memo, merchantData); } }
/** * Creates a PaymentSession from the provided {@link org.bitcoin.protocols.payments.Protos.PaymentRequest}. * If verifyPki is true, also validates the signature and throws an exception if it fails. * If trustStoreLoader is null, the system default trust store is used. */ public PaymentSession(Protos.PaymentRequest request, boolean verifyPki, @Nullable final TrustStoreLoader trustStoreLoader) throws PaymentProtocolException { TrustStoreLoader nonNullTrustStoreLoader = trustStoreLoader != null ? trustStoreLoader : new TrustStoreLoader.DefaultTrustStoreLoader(); parsePaymentRequest(request); if (verifyPki) { try { pkiVerificationData = PaymentProtocol.verifyPaymentRequestPki(request, nonNullTrustStoreLoader.getKeyStore()); } catch (IOException x) { throw new PaymentProtocolException(x); } catch (KeyStoreException x) { throw new PaymentProtocolException(x); } } else { pkiVerificationData = null; } }
/** * Generates a Payment message based on the information in the PaymentRequest. * Provide transactions built by the wallet. * If the PaymentRequest did not specify a payment_url, returns null. * @param txns list of transactions to be included with the Payment message. * @param refundAddr will be used by the merchant to send money back if there was a problem. * @param memo is a message to include in the payment message sent to the merchant. */ @Nullable public Protos.Payment getPayment(List<Transaction> txns, @Nullable Address refundAddr, @Nullable String memo) throws IOException, PaymentProtocolException.InvalidNetwork { if (paymentDetails.hasPaymentUrl()) { for (Transaction tx : txns) if (!tx.getParams().equals(params)) throw new PaymentProtocolException.InvalidNetwork(params.getPaymentProtocolId()); return PaymentProtocol.createPaymentMessage(txns, totalValue, refundAddr, memo, getMerchantData()); } else { return null; } }
@Override public PaymentProtocol.Ack call() throws Exception { HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("POST"); connection.setRequestProperty("Content-Type", PaymentProtocol.MIMETYPE_PAYMENT); connection.setRequestProperty("Accept", PaymentProtocol.MIMETYPE_PAYMENTACK); connection.setRequestProperty("Content-Length", Integer.toString(payment.getSerializedSize())); connection.setUseCaches(false); connection.setDoInput(true); connection.setDoOutput(true); // Send request. DataOutputStream outStream = new DataOutputStream(connection.getOutputStream()); payment.writeTo(outStream); outStream.flush(); outStream.close(); // Get response. Protos.PaymentACK paymentAck = Protos.PaymentACK.parseFrom(connection.getInputStream()); return PaymentProtocol.parsePaymentAck(paymentAck); } });
/** * Create a payment request with one standard pay to address output. You may want to sign the request using * {@link #signPaymentRequest}. Use {@link Protos.PaymentRequest.Builder#build} to get the actual payment * request. * * @param params network parameters * @param amount amount of coins to request, or null * @param toAddress address to request coins to * @param memo arbitrary, user readable memo, or null if none * @param paymentUrl URL to send payment message to, or null if none * @param merchantData arbitrary merchant data, or null if none * @return created payment request, in its builder form */ public static Protos.PaymentRequest.Builder createPaymentRequest(NetworkParameters params, @Nullable Coin amount, Address toAddress, @Nullable String memo, @Nullable String paymentUrl, @Nullable byte[] merchantData) { return createPaymentRequest(params, ImmutableList.of(createPayToAddressOutput(amount, toAddress)), memo, paymentUrl, merchantData); }