Skip to content

Commit

Permalink
Merge pull request #9 from bloqhouse/feat/rework
Browse files Browse the repository at this point in the history
  • Loading branch information
JFGHT authored Sep 24, 2020
2 parents 4ab23a4 + 4fb7d4f commit a467398
Show file tree
Hide file tree
Showing 12 changed files with 2,350 additions and 819 deletions.
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
language: node_js
node_js:
- '8'
- '9'
- '10'
- '12'
- '14'
script:
- npm run test:ci
87 changes: 51 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,47 +1,62 @@
# node-idin [![Build Status](https://travis-ci.org/bloqhouse/node-idin.svg?branch=master)](https://travis-ci.org/bloqhouse/node-idin) [![Coverage Status](https://coveralls.io/repos/github/bloqhouse/node-idin/badge.svg?branch=master)](https://coveralls.io/github/bloqhouse/node-idin?branch=master)

# node-idin [![Build Status](https://travis-ci.com/bloqhouse/node-idin.svg?branch=master)](https://travis-ci.com/bloqhouse/node-idin) [![Coverage Status](https://coveralls.io/repos/github/bloqhouse/node-idin/badge.svg?branch=master)](https://coveralls.io/github/bloqhouse/node-idin?branch=master)

Node.js Library for [iDIN](https://www.idin.nl/)



Node-idin has 3 exportable methods. These methods accept two objects as parameters.
Node.js Library for [iDIN](https://www.idin.nl/). You can find all the protocol documentation [here](https://betaalvereniging.atlassian.net/wiki/spaces/IIDIFMD/pages/588284049/iDIN+Merchant+Implemention+Guide+EN).
Supporting Node 10+.



## How to use

Install the dep by:
```bash
yarn add node-idin
```

Create a `NodeIdin` instance:

1. `GeneralParameters` object which includes:
```ts
merchantId: string
merchantSubId: string
routingEndpoint: string // callback url
routingCert: string
publicKey: string
publicKeyFingerprint: string
privateKey: string
const config = {
merchantId: '35235',
merchantSubId: '0',
routingEndpoint: 'https://abnamro-test.bank-request.com/bvn-idx-bankid-rs/bankidGateway',
routingCert: '-----BEGIN CERTIFICATE-----...',
privateKey: '-----BEGIN RSA PRIVATE KEY-----...',
publicKey: '-----BEGIN PUBLIC KEY-----...',
publicKeyFingerprint: 'xekf2o3f...',
}

const idin = new NodeIdin(config);
```
2. Specific object per method, more info in the table below.

| Method | Specific object required | Description |
|--|--|--|
| getDirectoryResponse | Not required | Gets the different issuers (banks) available |
| getTransactionResponse | { loa: string, merchantReturnUrl: string, idPrefix: string, requestedService: number, defaultLanguage: string, expirationPeriod: string, issuerId: string, transactionId: string } | Initial step to get the user's data. |
| getStatusResponse | { transactionId: string } | Final data retrieval |
Use the method you need:

```ts
const directory = await idin.getDirectory();
```

Example:
```ts
const transaction = await idin.getTransaction({
loa: 'loa3',
merchantReturnUrl: 'https://...',
idPrefix: 'RND',
requestedService: '21968',
defaultLanguage: 'en',
expirationPeriod: 'PT5M',
issuerId: 'randomId',
transactionId: 'randomId#2',
});
```

```ts
try {
const gParams: GeneralParameters = {
merchantId: '35235',
merchantSubId: '0',
routingEndpoint: 'https://abnamro-test.bank-request.com/bvn-idx-bankid-rs/bankidGateway',
routingCert: '-----BEGIN CERTIFICATE-----...',
privateKey: '-----BEGIN RSA PRIVATE KEY-----...',
publicKey: '-----BEGIN PUBLIC KEY-----...',
publicKeyFingerprint: 'xekf2o3f...',
};
const specificParams: StatusParameters = {
transactionId: 'wefawef2',
};
const data = await getStatusResponse(gParams, specificParams);
console.log(data)
} catch (e) {
console.log(e);
}
const status = await idin.getStatus({ transactionId: '92fo2k3qdd' });
```

## Notes

- Read protocol documentation for a better understanding of the parameters.

- This library does not fully implement the protocol and has some issues that still need to be addressed. Use at your own risk.
3 changes: 2 additions & 1 deletion index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// tslint:disable-next-line:no-reference
/// <reference path="./index.d.ts" />

export * from './lib';
import NodeIdin from './lib';
export default NodeIdin;
22 changes: 5 additions & 17 deletions lib/directory-protocol.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,6 @@ describe('Directory Protocol', (): void => {
jest.resetModules();
});

test('no general object param', async () => {
const { getDirectoryResponse } = require('./index');
// @ts-ignore
expect(() => getDirectoryResponse()).toThrow('No general object parameter found.');
});

test('missing gen keys', async () => {
const { getDirectoryResponse } = require('./index');
// @ts-ignore
expect(() => getDirectoryResponse({})).toThrow('Parameters missing.');
});

test('response error', async () => {
jest.mock('xml-crypto', (): any => ({
xpath: (): string => '',
Expand All @@ -32,7 +20,7 @@ describe('Directory Protocol', (): void => {
this.getSignedXml = (): string => '';
},
}));
const { getDirectoryResponse } = require('./index');
const { default: NodeIdin } = require('./index');

const gParams: GeneralParameters = {
merchantId: '0',
Expand All @@ -48,7 +36,7 @@ describe('Directory Protocol', (): void => {
const fetch = require('node-fetch');
fetch.mockReturnValue(Promise.reject('error1'));

await expect(getDirectoryResponse(gParams)).rejects.toThrowError('error1');
await expect(new NodeIdin(gParams).getDirectory()).rejects.toThrowError('error1');
expect(fetch).toHaveBeenCalledTimes(1);
expect(fetch).toHaveBeenCalledWith('url', {
body: '',
Expand Down Expand Up @@ -125,7 +113,7 @@ describe('Directory Protocol', (): void => {
}],
},
};
const { getDirectoryResponse } = require('./index');
const { default: NodeIdin } = require('./index');

const gParams: GeneralParameters = {
merchantId: '0',
Expand All @@ -143,7 +131,7 @@ describe('Directory Protocol', (): void => {
const { Response } = jest.requireActual('node-fetch');
fetch.mockReturnValueOnce(Promise.resolve(new Response(mockIssuers(true))));

await expect(getDirectoryResponse(gParams)).resolves.toMatchObject(toReceive);
await expect(new NodeIdin(gParams).getDirectory()).resolves.toMatchObject(toReceive);
expect(fetch).toHaveBeenCalledTimes(1);
expect(fetch).toHaveBeenCalledWith('url', {
body: '',
Expand All @@ -152,7 +140,7 @@ describe('Directory Protocol', (): void => {

fetch.mockReturnValueOnce(Promise.resolve(new Response(mockIssuers(false))));

await expect(getDirectoryResponse(gParams)).resolves.toMatchObject(toReceive);
await expect(new NodeIdin(gParams).getDirectory()).resolves.toMatchObject(toReceive);
expect(fetch).toHaveBeenCalledTimes(2);
expect(fetch).toHaveBeenCalledWith('url', {
body: '',
Expand Down
2 changes: 1 addition & 1 deletion lib/idin-protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export async function verifySignature({ routingCert, signedXml }: VerifySignatur

const result = XML.checkSignature(signedXml.trim());
if (!result) {
console.error(new Error(XML.validationErrors));
console.log(new Error(XML.validationErrors));
}

return signedXml;
Expand Down
34 changes: 17 additions & 17 deletions lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
import { checkParams } from './utils';
import getDirectory from './directory-protocol';
import getTransaction, { TransactionParams } from './transaction-protocol';
import getStatus, { StatusParameters } from './status-protocol';
import getDirectoryResponse from './directory-protocol';
import getTransactionResponse, { TransactionParams } from './transaction-protocol';
import getStatusResponse, { StatusParameters } from './status-protocol';
import { GeneralParameters } from './idin-protocol';

export function getDirectoryResponse(arg1: GeneralParameters) {
checkParams('getDirectory', ...arguments);
return getDirectory(arg1);
}
export default class NodeIdin {
constructor(
private config: GeneralParameters,
) { }

export function getStatusResponse(arg1: GeneralParameters, arg2: StatusParameters) {
checkParams('getStatus', ...arguments);
return getStatus(arg1, arg2);
}
public getDirectory() {
return getDirectoryResponse(this.config);
}

export function getTransactionResponse(arg1: GeneralParameters, arg2: TransactionParams) {
checkParams('getTransaction', ...arguments);
return getTransaction(arg1, arg2);
}
public getTransaction(transactionConfig: TransactionParams) {
return getTransactionResponse(this.config, transactionConfig);
}

export { GeneralParameters, TransactionParams, StatusParameters };
public getStatus(statusConfig: StatusParameters) {
return getStatusResponse(this.config, statusConfig);
}
}
60 changes: 9 additions & 51 deletions lib/status-protocol.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,48 +10,6 @@ describe('Status Protocol', (): void => {
jest.resetModules();
});

test('no general object param', async () => {
const { getStatusResponse } = require('./index');
// @ts-ignore
expect(() => getStatusResponse()).toThrow('No general object parameter found.');
});

test('no specific object param', async () => {
const { getStatusResponse } = require('./index');
const gParams: GeneralParameters = {
merchantId: '0',
merchantSubId: '0',
privateKey: '',
publicKey: '',
publicKeyFingerprint: '',
routingCert: '',
routingEndpoint: 'url',
};
// @ts-ignore
expect(() => getStatusResponse(gParams)).toThrow('No specific object parameter found.');
});

test('missing gen keys', async () => {
const { getStatusResponse } = require('./index');
// @ts-ignore
expect(() => getStatusResponse({}, {})).toThrow('Parameters missing.');
});

test('missing specific keys', async () => {
const { getStatusResponse } = require('./index');
const gParams: GeneralParameters = {
merchantId: '0',
merchantSubId: '0',
privateKey: '',
publicKey: '',
publicKeyFingerprint: '',
routingCert: '',
routingEndpoint: 'url',
};
// @ts-ignore
expect(() => getStatusResponse(gParams, {})).toThrow('Parameters missing.');
});

test('response error', async () => {
jest.mock('xml-crypto', (): any => ({
xpath: (): string => '',
Expand All @@ -63,7 +21,7 @@ describe('Status Protocol', (): void => {
this.getSignedXml = (): string => '';
},
}));
const { getStatusResponse } = require('./index');
const { default: NodeIdin } = require('./index');

const gParams: GeneralParameters = {
merchantId: '0',
Expand All @@ -83,7 +41,7 @@ describe('Status Protocol', (): void => {
const fetch = require('node-fetch');
fetch.mockReturnValue(Promise.reject('error1'));

await expect(getStatusResponse(gParams, sParams)).rejects.toThrowError('error1');
await expect(new NodeIdin(gParams).getStatus(sParams)).rejects.toThrowError('error1');
expect(fetch).toHaveBeenCalledTimes(1);
expect(fetch).toHaveBeenCalledWith('url', {
body: '',
Expand Down Expand Up @@ -143,7 +101,7 @@ describe('Status Protocol', (): void => {
.mockReturnValueOnce(mockXpathMapReturn('')),
};
});
const { getStatusResponse } = require('./index');
const { default: NodeIdin } = require('./index');

const gParams: GeneralParameters = {
merchantId: '0',
Expand All @@ -164,7 +122,7 @@ describe('Status Protocol', (): void => {
const { Response } = jest.requireActual('node-fetch');
fetch.mockReturnValueOnce(Promise.resolve(new Response(mockStatus)));

await expect(getStatusResponse(gParams, sParams)).resolves.toMatchObject({
await expect(new NodeIdin(gParams).getStatus(sParams)).resolves.toMatchObject({
createDateTimestamp: { _text: '' },
Error: {},
});
Expand Down Expand Up @@ -273,7 +231,7 @@ describe('Status Protocol', (): void => {
.mockReturnValueOnce(mockXpathMapReturn('')),
};
});
const { getStatusResponse } = require('./index');
const { default: NodeIdin } = require('./index');

const gParams: GeneralParameters = {
merchantId: '0',
Expand All @@ -294,7 +252,7 @@ describe('Status Protocol', (): void => {
const { Response } = jest.requireActual('node-fetch');
fetch.mockReturnValueOnce(Promise.resolve(new Response(mockStatus(''))));

await expect(getStatusResponse(gParams, sParams)).rejects.toThrowError();
await expect(new NodeIdin(gParams).getStatus(sParams)).rejects.toThrowError();
expect(fetch).toHaveBeenCalledTimes(1);
expect(fetch).toHaveBeenCalledWith('url', {
body: '',
Expand Down Expand Up @@ -434,7 +392,7 @@ describe('Status Protocol', (): void => {
transactionID: mockTransactionId,
},
};
const { getStatusResponse } = require('./index');
const { default: NodeIdin } = require('./index');

const gParams: GeneralParameters = {
merchantId: '0',
Expand All @@ -455,7 +413,7 @@ describe('Status Protocol', (): void => {
const { Response } = jest.requireActual('node-fetch');
fetch.mockReturnValueOnce(Promise.resolve(new Response(mockStatus(''))));

await expect(getStatusResponse(gParams, sParams)).resolves.toMatchObject(toReceive1);
await expect(new NodeIdin(gParams).getStatus(sParams)).resolves.toMatchObject(toReceive1);
expect(fetch).toHaveBeenCalledTimes(1);
expect(fetch).toHaveBeenCalledWith('url', {
body: '',
Expand Down Expand Up @@ -485,7 +443,7 @@ describe('Status Protocol', (): void => {

fetch.mockReturnValueOnce(Promise.resolve(new Response(mockStatus('2'))));

await expect(getStatusResponse(gParams, sParams)).resolves.toMatchObject(toReceive2);
await expect(new NodeIdin(gParams).getStatus(sParams)).resolves.toMatchObject(toReceive2);
expect(fetch).toHaveBeenCalledTimes(2);
expect(fetch).toHaveBeenCalledWith('url', {
body: '',
Expand Down
Loading

0 comments on commit a467398

Please sign in to comment.