Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ let config = {
country: 'fr'
}

let connect = client.getAisConnect(null, config)
let connect = await client.getAisConnect(null, config)
window.href.location = connect.url;
```

Expand Down
2 changes: 1 addition & 1 deletion fintecture-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ export class FintectureClient {
return this.connect.getPisConnect(accessToken, connectConfig);
}

public getAisConnect(accessToken: string, connectConfig: any): IAisConnect {
public async getAisConnect(accessToken: string, connectConfig: any): Promise<IAisConnect> {
return this.connect.getAisConnect(accessToken, connectConfig);
}

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "fintecture-client",
"version": "1.0.27",
"version": "2.0.0",
"description": "Fintecture Open Banking API Gateway enabling secure bank connections and payments",
"main": "lib/fintecture-client.js",
"types": "lib/fintecture-client.d.ts",
Expand Down
8 changes: 2 additions & 6 deletions spec/connect.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { FintectureClient } from '../fintecture-client';
import { BaseUrls } from './../src/utils/URLBuilders/BaseUrls';
import { IPisSetup, IAisSetup } from './../src/interfaces/connect/ConnectInterface';
import { TestConfig } from './constants/config';

Expand Down Expand Up @@ -34,20 +33,17 @@ const client = new FintectureClient({ app_id: TestConfig.appIdMerchant, app_secr

describe('Connect', () => {
it('#PIS getPisConnect', async (done) => {
const mockConnectUrl = BaseUrls.FINTECTURECONNECTURL_SBX + '/pis?config=';
const tokens: any = await client.getAccessToken();
const connectMin = await client.getPisConnect(tokens.access_token, connectPisConfigMin);
expect(connectMin.url).toContain(mockConnectUrl);
expect(!!connectMin.session_id).toBe(true);
const connectFull = await client.getPisConnect(tokens.access_token, connectPisConfigFull);
expect(connectFull.url).toContain(mockConnectUrl);
expect(!!connectFull.session_id).toBe(true);
expect(connectFull.url.length).toBeGreaterThan(connectMin.url.length)
done();
});

it('#AIS getAisConnectUrl', (done) => {
const connect = client.getAisConnect(null, connectAisMin);
it('#AIS getAisConnectUrl', async (done) => {
const connect = await client.getAisConnect(null, connectAisMin);
expect(!!connect.url).toBe(true);
done();
});
Expand Down
143 changes: 41 additions & 102 deletions src/Connect.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,22 @@
import * as UtilsCrypto from './utils/Crypto.js';
import { BaseUrls } from './utils/URLBuilders/BaseUrls';
import * as connectService from './services/ConnectService';
import { IPisSetup, IPisConnectConfig, IAisConnectConfig, IPaymentPayload, IData, IAttributes, IMeta } from './interfaces/connect/ConnectInterface';
import { ISessionPayload } from './interfaces/pis/PisInterface';
import qs from 'qs';

import { Endpoints } from './utils/URLBuilders/Endpoints';
import { IPisSetup, IPaymentPayload, IData, IAttributes, IMeta } from './interfaces/connect/ConnectInterface';
import { IFintectureConfig } from './interfaces/ConfigInterface';
import { Constants } from './utils/Constants.js';
import { PIS } from './Pis';
import * as apiService from './services/ApiService';

export class Connect {
public pis: PIS;
public axios: any;
public axiosInstance: any;
public config: IFintectureConfig;
public connectConfig: IPisSetup;

private signatureType: string;

constructor(config: IFintectureConfig) {
this.pis = new PIS(config);
this.axios = connectService;
this.axiosInstance = apiService.getInstance(config.env);
this.config = config;
this.signatureType = 'rsa-sha256';
}

/**
Expand All @@ -29,44 +25,30 @@ export class Connect {
* @param {string} accessTOken
* @param {payment} State
*/
public getAisConnect(accessToken: string, connectConfig: any) {
public async getAisConnect(accessToken: string, connectConfig: any) {
this.config = this._validateConfigIntegrity(this.config);

const headers: any = this._buildHeaders(accessToken, 'get', null, this.config.private_key, this.signatureType);

const config: IAisConnectConfig = {
app_id: this.config.app_id,
signature_type: this.signatureType,
signature: headers['Signature'],
const queryParameters = qs.stringify({
redirect_uri: connectConfig.redirect_uri,
origin_uri: connectConfig.origin_uri,
state: connectConfig.state,
psu_type: connectConfig.psu_type,
country: connectConfig.country,
date: headers['Date'],
request_id: headers['X-Request-ID'],
provider: connectConfig.provider
state: connectConfig.state
});
const url = `${Endpoints.AISCONNECT}?${queryParameters}`;

// Extend the headers with Connect specific headers if they are defined
const extraHeaders = {
'x-provider': connectConfig.provider,
'x-psu-type': connectConfig.psu_type,
'x-country': connectConfig.country,
'x-language': connectConfig.language,
};

if (accessToken) {
config.access_token = accessToken;
}

const psuType = connectConfig.psu_type ? connectConfig.psu_type : 'retail';
const country = connectConfig.country ? connectConfig.country : 'fr';

const url = `${
this.config.env === Constants.SANDBOXENVIRONMENT
? BaseUrls.FINTECTURECONNECTURL_SBX
: BaseUrls.FINTECTURECONNECTURL_PRD
}/ais/${psuType}/${country}`;
const headers = apiService.getHeaders('get', url, null, this.config, null, extraHeaders);

const connect = {
url: `${url}?config=${Buffer.from(JSON.stringify(config)).toString('base64')}`,
}

return connect;
const { data } = await this.axiosInstance.get(url, { headers });

return {
url: data.meta.url
};
}

/**
Expand All @@ -81,40 +63,29 @@ export class Connect {

const paymentPayload: IPaymentPayload = this._buildPaymentPayload(connectConfig);

const prepare: any = await this.pis.prepare(accessToken, paymentPayload);

const sessionPayload: ISessionPayload = this._buildSessionPayload(prepare);

const headers: any = this._buildHeaders(accessToken, 'post', sessionPayload, this.config.private_key, this.signatureType);

const config: IPisConnectConfig = {
app_id: this.config.app_id,
access_token: accessToken,
signature_type: this.signatureType,
signature: headers['Signature'],
redirect_uri: connectConfig.redirect_uri,
const queryParameters = qs.stringify({
origin_uri: connectConfig.origin_uri,
state: connectConfig.state,
payload: sessionPayload,
psu_type: connectConfig.psu_type,
country: connectConfig.country,
date: headers['Date'],
request_id: headers['X-Request-ID'],
provider: connectConfig.provider
redirect_uri: connectConfig.redirect_uri,
state: connectConfig.state
});
const url = `${Endpoints.PISCONNECT}?${queryParameters}`;

// Extend the headers with Connect specific headers if they are defined
const extraHeaders = {
'x-provider': connectConfig.provider,
'x-psu-type': connectConfig.psu_type,
'x-country': connectConfig.country,
'x-language': connectConfig.language,
};

const url = `${
this.config.env === Constants.SANDBOXENVIRONMENT
? BaseUrls.FINTECTURECONNECTURL_SBX
: BaseUrls.FINTECTURECONNECTURL_PRD
}/pis`;
const headers = apiService.getHeaders('post', url, accessToken, this.config, paymentPayload, extraHeaders);

const connect = {
url: `${url}?config=${Buffer.from(JSON.stringify(config)).toString('base64')}`,
session_id: prepare.meta.session_id
}
const { data } = await this.axiosInstance.post(url, paymentPayload, { headers });

return connect;
return {
session_id: data.meta.session_id,
url: data.meta.url,
};
}

private _validatePisConnectConfigIntegrity(connectConfig: any) {
Expand Down Expand Up @@ -143,14 +114,6 @@ export class Connect {
return connectConfig as IPisSetup;
}


private _buildHeaders(accessToken: string, method: string, payload: any, privateKey: string, algorithm: string): any {
const headers = apiService.getHeaders(method, '', accessToken, this.config, payload);
const signingString = UtilsCrypto.buildSigningString(headers, Constants.CONNECTHEADERPARAMETERLIST)
headers["Signature"] = UtilsCrypto.signPayload(signingString, this.config.private_key);
return headers;
}

private _buildPaymentPayload(payment: any) {
const attributes: IAttributes = {
amount: payment.amount,
Expand Down Expand Up @@ -184,30 +147,6 @@ export class Connect {
return payload;
}

private _buildSessionPayload(payment) {
const payload = {
meta: {
session_id: payment.meta.session_id,
},
data: {
attributes: {
amount: payment.data.attributes.amount,
currency: payment.data.attributes.currency
}
}
} as ISessionPayload;

if (payment.data.attributes.beneficiary) {
payload.data.attributes.beneficiary = {name: payment.data.attributes.beneficiary.name};
}

if (payment.data.attributes.execution_date) {
payload.data.attributes.execution_date = payment.data.attributes.execution_date;
}

return payload;
}

private _validateConfigIntegrity(config) {
if (!config.private_key) {
throw Error('private_key must be set to use this function');
Expand Down
8 changes: 7 additions & 1 deletion src/services/ApiService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,14 @@ export const getHeaders = (method: string, url: string, accessToken: string, con
headers['Signature'] = Crypto.createSignatureHeader(headers, config, Constants.SIGNEDHEADERPARAMETERLIST);
delete headers['(request-target)'];

// Extend with extra headers in case they are not undefined. `undefined` as value of a header
// is not allowed by Node.js
if (extraHeaders) {
Object.assign(headers, extraHeaders);
Object.entries(extraHeaders).forEach(([headerName, headerValue]) => {
if (headerValue !== undefined) {
headers[headerName] = headerValue;
}
})
}

return headers;
Expand Down
10 changes: 0 additions & 10 deletions src/services/ConnectService.ts

This file was deleted.

4 changes: 0 additions & 4 deletions src/utils/URLBuilders/BaseUrls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,8 @@ export class BaseUrls {
process.env.FINTECTUREOAUTHURL_DEV || 'https://oauth-sandbox.fintecture.com';
public static readonly FINTECTUREAPIURL_SBX: string =
process.env.FINTECTUREAPIURL_DEV || 'https://api-sandbox.fintecture.com';
public static readonly FINTECTURECONNECTURL_SBX: string =
process.env.FINTECTURECONNECTURL_DEV || 'https://connect-sandbox.fintecture.com';
public static readonly FINTECTUREOAUTHURL_PRD: string =
process.env.FINTECTUREOAUTHURL_DEV || 'https://oauth.fintecture.com';
public static readonly FINTECTUREAPIURL_PRD: string =
process.env.FINTECTUREAPIURL_DEV || 'https://api.fintecture.com';
public static readonly FINTECTURECONNECTURL_PRD: string =
process.env.FINTECTURECONNECTURL_DEV || 'https://connect.fintecture.com';
}
2 changes: 2 additions & 0 deletions src/utils/URLBuilders/Endpoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,6 @@ export class Endpoints {
public static readonly PIS: string = '/pis/v1';
public static readonly AISPROVIDER: string = '/ais/v1/provider';
public static readonly AISCUSTOMER: string = '/ais/v1/customer';
public static readonly AISCONNECT: string = '/ais/v2/connect';
public static readonly PISCONNECT: string = '/pis/v2/connect';
}