mollie / mollie-api-node

Official Mollie API client for Node
http://www.mollie.com
BSD 3-Clause "New" or "Revised" License
237 stars 63 forks source link

fs.readFileSync is not a function #130

Closed Borisboky closed 4 years ago

Borisboky commented 4 years ago

I'm using gatsby (v 2.18.4) for my frontend. It worked fine but after I installed this package. Now I get error TypeError: fs__WEBPACK_IMPORTED_MODULE_1___default.a.readFileSync is not a function

I found that adding this to gatsby-config.js file will solve the problem

exports.onCreateWebpackConfig = ({ actions }) => {
    actions.setWebpackConfig({
        node: {
            fs: 'empty',
            net: 'empty'
        }
    })
};

But it doesn't work. The code in Mollie package for which I get an error is:

import fs from 'fs';

function createHttpClient(options) {
  const axiosOptions = cloneDeep(options);
  delete axiosOptions.apiKey;
  delete axiosOptions.versionStrings;
  axiosOptions.baseURL = 'https://api.mollie.com:443/v2/';

  if (undefined == axiosOptions.headers) {
    axiosOptions.headers = {};
  }

  axiosOptions.headers['Authorization'] = `Bearer ${options.apiKey}`;
  axiosOptions.headers['Accept-Encoding'] = 'gzip';
  axiosOptions.headers['Content-Type'] = 'application/json';
  var customVersionStrings = options.versionStrings;

  if (undefined == customVersionStrings) {
    customVersionStrings = [];
  } else if (false == Array.isArray(customVersionStrings)) {
    customVersionStrings = [customVersionStrings];
  }

  axiosOptions.headers['User-Agent'] = [`Node/${process.version}`, `Mollie/${version}`, ...customVersionStrings.map(versionString => {
    //                platform /version
    const matches = /^([^\/]+)\/([^\/\s]+)$/.exec(versionString);

    if (null === matches) {
      if (-1 == versionString.indexOf('/') || versionString.indexOf('/') != versionString.lastIndexOf('/')) {
        throw new Error('Invalid version string. It needs to consist of a name and version separated by a forward slash, e.g. RockenbergCommerce/3.1.12');
      } else {
        throw new Error('Invalid version string. The version may not contain any whitespace.');
      }
    } // Replace whitespace in platform name with camelCase (first char stays untouched).

    const platform = matches[1].replace(/([^^])(\b\w)/g, (match, boundary, character) => [boundary, character.toUpperCase()].join('')).replace(/\s+/g, '');
    const version = matches[2];
    return [platform, version].join('/');
  })].join(' ');
  axiosOptions.httpsAgent = new https.Agent({
    ///////////////////////////////////////////////
    //////////////// THIS LINE ///////////////////

    cert: fs.readFileSync(path.resolve(__dirname, './cacert.pem'), 'utf8') 
  });
  return axios.create(axiosOptions);
}

The error is in the next code:

axiosOptions.httpsAgent = new https.Agent({   
    cert: fs.readFileSync(path.resolve(__dirname, './cacert.pem'), 'utf8') 
  });

Any idea how to solve it?

Pimm commented 4 years ago

Hi Boris,

This library is meant to be run in Node.js. That is not a compatibility issue; it is by design.

Could you explain what you are hoping to achieve?

Borisboky commented 4 years ago

Hi,

I'm trying to add a possibillity to Pay from my frontend. I have a simple component as follows:

import React from 'react';
const { createMollieClient } = require('@mollie/api-client');

const mollieClient = createMollieClient({ apiKey: 'test_my_code' });

const Payment = ({data, reservationData, onBack}) => {   

    const onPay = () => {
        mollieClient.payments.create({
            amount: {
                value:    '10.00',
                currency: 'EUR'
            },
            description: 'My first API payment',
            redirectUrl: 'https://yourwebshop.example.org/order/123456',
            webhookUrl:  'https://yourwebshop.example.org/webhook'
        })
            .then(payment => {
                debugger;
                // Forward the customer to the payment.getCheckoutUrl()
            })
            .catch(error => {
                // Handle the error
            });
    };

    return (
        <div>
            <button onClick={() => onPay()}>PAY</button>
        </div>
    );
};

export default Payment;

But I'm getting this fs error.

Pimm commented 4 years ago

Unfortunately, the issue is in your setup. You are currently including the API key in your frontend. Thereby it ends up in the hands of your users.

With your API key, anyone can make requests to Mollie on your behalf. There is no way for Mollie to distinguish valid payments coming from your app from malicious requests coming from someone who extracted your API key. They could issue refunds, for instance. That's a major security issue.

To solve this, you will have to set up a Node.js server. This server will include this library, and will have access to the API key. From your Gatsby app, rather than calling mollieClient.payments.create directly, you'll make a request to your server and your server will in turn call mollieClient.payments.create.

This will clear up that error as well, since you won't be using this library in your Gatsby app.

Alternatively, you can set up a PHP, Ruby, or Python server instead of a Node.js one.

vernondegoede commented 4 years ago

@Borisboky If the frontend that you tried to implement this module into has been publicly accessible, please make sure you reset that API key from your Mollie Dashboard.