Created
January 8, 2021 07:24
-
-
Save vladutilie/715ea6809dd05947124447807f08b597 to your computer and use it in GitHub Desktop.
ING API | Get token and payment initiate @nestjs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { HttpService, Injectable } from '@nestjs/common'; | |
import { PaymentRepository } from './payment.repository'; | |
import { map } from 'rxjs/operators'; | |
import fs from 'fs'; | |
import crypto from 'crypto'; | |
import https from 'https'; | |
import { User } from '../user/user.entity'; | |
import { LessThan, MoreThan } from 'typeorm'; | |
import { INGTokenDTO } from './payment.dto'; | |
import { PaymentCredentials } from './payment-credentials.entity'; | |
import { v4 as uuidv4 } from 'uuid'; | |
@Injectable() | |
export class INGPaymentService { | |
constructor(private httpService: HttpService, private paymentRepository: PaymentRepository) {} | |
async initiatePayment(token: PaymentCredentials) { | |
const keyId = token.clientId; | |
const requestedId = uuidv4(); | |
const reqDate = new Date().toUTCString(); | |
const payload = JSON.stringify({ | |
instructedAmount: { amount: '1', currency: 'EUR' }, | |
creditorAccount: { iban: 'AT861921125678901234' }, | |
creditorName: 'Laura Musterfraus', | |
}); | |
const payloadDigest = crypto.createHash('sha256').update(payload).digest('base64'); | |
const digest = `SHA-256=${payloadDigest}`; | |
// KEEP signingString without indentation on the lines with "date" and "digest" values! | |
const signingString = `(request-target): post /v1/payments/sepa-credit-transfers | |
date: ${reqDate} | |
digest: ${digest} | |
x-request-id: ${requestedId}`; | |
const privateKey = fs.readFileSync('./storage/ing/eidas_client_signing.key', 'utf-8'); | |
const signatureHash = crypto.createSign('sha256').update(signingString).sign(privateKey).toString('base64'); | |
const signature = `keyId="${keyId}",algorithm="rsa-sha256",headers="(request-target) date digest x-request-id",signature="${signatureHash}"`; | |
const httpsAgent = new https.Agent({ | |
rejectUnauthorized: false, // This will disable client verification | |
cert: fs.readFileSync('./storage/ing/eidas_client_tls.cer'), | |
key: fs.readFileSync('./storage/ing/eidas_client_tls.key'), | |
}); | |
const options = { | |
headers: { | |
Accept: 'application/json', | |
'Content-Type': 'application/json', | |
Digest: digest, | |
Date: reqDate, | |
// TODO: Change TPP-Redirect-URI with process.env.ING_REDIRECT_URI when on production. | |
'TPP-Redirect-URI': 'https://example.com/redirect', | |
'PSU-IP-Address': '37.44.220.0', | |
'X-Request-ID': requestedId, | |
Authorization: `Bearer ${token.accessToken}`, | |
Signature: signature, | |
}, | |
httpsAgent, | |
}; | |
return await this.httpService | |
.post(`${process.env.ING_PAYMENT_ENDPOINT}/v1/payments/sepa-credit-transfers`, payload, options) | |
.pipe(map((response) => response.data)) | |
.toPromise(); | |
} | |
async getToken(user: User): Promise<PaymentCredentials> { | |
const now = new Date(); | |
const token = await this.paymentRepository.findOne({ | |
where: { user, bank: 'ING', expiresAt: MoreThan(now) }, | |
}); | |
if (!token) { | |
// Deletes expired access_token. | |
await this.paymentRepository.delete({ user, bank: 'ING', expiresAt: LessThan(now) }); | |
const newToken = await this.authRequest(); | |
const credentials = new PaymentCredentials(); | |
credentials.user = user; | |
credentials.bank = 'ING'; | |
credentials.clientId = newToken.client_id; | |
credentials.accessToken = newToken.access_token; | |
now.setSeconds(now.getSeconds() + newToken.expires_in); | |
credentials.expiresAt = now; | |
await this.paymentRepository.save(credentials); | |
return credentials; | |
} | |
return token; | |
} | |
async authRequest(): Promise<INGTokenDTO> { | |
const keyId = `SN=${process.env.ING_CERT_SN}`; | |
const payload = 'grant_type=client_credentials'; | |
const payloadDigest = crypto.createHash('sha256').update(payload).digest('base64'); | |
const digest = `SHA-256=${payloadDigest}`; | |
const reqDate = new Date().toUTCString(); | |
// KEEP signingString without indentation on the lines with "date" and "digest" values! | |
const signingString = `(request-target): post /oauth2/token | |
date: ${reqDate} | |
digest: ${digest}`; | |
const privateKey = fs.readFileSync('./storage/ing/eidas_client_signing.key', 'utf-8'); | |
const certificate = fs.readFileSync('./storage/ing/eidas_client_signing.cer', 'utf-8'); | |
const signature = crypto.createSign('sha256').update(signingString).sign(privateKey); | |
const signatureBase64 = signature.toString('base64'); | |
const authorization = `Signature keyId="${keyId}",algorithm="rsa-sha256",headers="(request-target) date digest",signature="${signatureBase64}"`; | |
const httpsAgent = new https.Agent({ | |
rejectUnauthorized: false, // This will disable client verification | |
cert: fs.readFileSync('./storage/ing/eidas_client_tls.cer'), | |
key: fs.readFileSync('./storage/ing/eidas_client_tls.key'), | |
}); | |
const options = { | |
headers: { | |
Accept: 'application/json', | |
'Content-Type': 'application/x-www-form-urlencoded', | |
Digest: digest, | |
Date: reqDate, | |
'TPP-Signature-Certificate': certificate.replace(/[\r\n]+/gm, ''), | |
authorization, | |
}, | |
httpsAgent, | |
}; | |
return await this.httpService | |
.post(`${process.env.ING_PAYMENT_ENDPOINT}/oauth2/token`, payload, options) | |
.pipe(map((response) => response.data)) | |
.toPromise(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment