Dennis R
Dennis R

Reputation: 21

Node.js POST request with .p12 and pem certificates outputs "Error: read ECONNRESET"

I'm setting up a function using node on Firebase to test a Swish integration. Swish is a mobile application for money transfer between wallets (bank accounts). Currently Im testing their Merchant Swish Simulator test environment that is available for merchants to test their integration with the Swish Commerce API.

There is a available manual on their developer website: https://developer.getswish.se/merchants/

Example request that can be done through a unix terminal (to test one of their endpoints) which works perfectly for me (getting 201 respond) is:

curl -s -S -i --cert ./Swish_Merchant_TestCertificate_1231181189.p12:swish --cert-type p12 --cacert ./Swish_TLS_RootCA.pem --tlsv1.1 --header "Content-Type: application/json" https://mss.cpc.getswish.net/swish-cpcapi/api/v1/paymentrequests --data '{ "payeePaymentReference" : "0123456789", "callbackUrl" : "https://myfakehost.se/swishcallback.cfm", "payerAlias" : "46766268608", "payeeAlias" : "1231181189", "amount" : "100", "currency" : "SEK", "message" : "Kingston USB Flash Drive 8 GB" }'

The issue is im not sure of how to make a similar request with including the certs using firebase.

const functions = require('firebase-functions');
const express = require('express');
const app = express();
let fs = require('fs');
let request = require('request');

app.post('/request-payment', async (req, res) => {
    const url = 'https://mss.cpc.getswish.net/swish-cpcapi/api/v1/paymentrequests';

    let data = {
        payeePaymentReference : '0123456789',
        message: 'Kingston USB Flash Drive 8 GB',
        callbackUrl: 'https://myfakehost.se/swishcallback.cfm',
        amount: '100',
        currency: 'SEK',
        payeeAlias: '1231181189',
        payerAlias: '46766268608'
    };

    let options = {
        url: url,
        headers: {
            "content-type": "application/json",
        },
        agentOptions: {
            pfx: fs.readFileSync('certificates/Swish_Merchant_TestCertificate_1231181189.p12'),
            passphrase: 'swish',
        },
        ca: fs.readFileSync('certificates/Swish_TLS_RootCA.pem'),
        body: data,
        json: true
    };

    return await request.post(options, async (error, response, body) => {
        if (!error && response.statusCode === 201) {
            return res.status(200).json({
                url: response.body.url,
            })
        } else {
            console.log('error', error);
            return res.status(404).json({
                message: 'Error: ' + error,
            })
        }
    });
});

exports.swish = functions.https.onRequest(app);

I've been trying to pass the .p12 and .pem files when making a request to the endpoint above and im sending the exact same data as above. I still get this error:

error { Error: read ECONNRESET at TLSWrap.onread (net.js:622:25) errno: 'ECONNRESET', code: 'ECONNRESET', syscall: 'read' }

Can anyone see anything wrong I do?

I've also tried to set a "binary" option to the .pem file. I do then get a crash from node saying that the header is to long....

Upvotes: 2

Views: 2129

Answers (2)

user15157348
user15157348

Reputation: 1

Note that Swish has now released API v2. I got the payment initiation endpoint working like this:

import { readFileSync } from "fs"
import { Agent, AgentOptions } from "https"
import fetch from "node-fetch"

const url = `https://mss.cpc.getswish.net/swish-cpcapi/api/v2/paymentrequests/${randomUUID}`

const data = {
      callbackUrl: "https://myfakehost.se/swishcallback.cfm",
      amount: "100.00",
      currency: "SEK",
      payeeAlias: "1234679304",
      payeePaymentReference: "foo"
    }

const cert = {
      cert: readFileSync(`./Swish_Merchant_TestCertificate_1234679304.pem`, "utf-8"),
      key: readFileSync(`./Swish_Merchant_TestCertificate_1234679304.key`, "utf-8"),
      passphrase: "swish",
    }    

const options = {
      agent: new Agent({ ...cert, minVersion: "TLSv1.2", maxVersion: "TLSv1.2" }),
      method: "PUT",
      body: JSON.stringify(data),
      headers: { "Content-Type": "application/json" }
    }

fetch(url, options)
   .then(handleToken)
   .catch(handleError)

Upvotes: 0

Amid
Amid

Reputation: 22372

Here is the way I populate options for request to make it work:

const options = {
            url: "https://mss.cpc.getswish.net/swish-cpcapi/api/v1/paymentrequests",
            json: true,
            cert: fs.readFileSync("Swish_Merchant_TestCertificate_1231181189.pem", "ascii"),
            passphrase: "swish",
            body: data,
            ca: fs.readFileSync("Swish_TLS_RootCA.pem", "ascii"),
            key: fs.readFileSync("Swish_Merchant_TestCertificate_1231181189.key", "ascii")
        };

Note the important differences:

  • "ascii" encoding to read the files
  • usage of the "pem" certificate instead of "p12".

Upvotes: 1

Related Questions