Created
January 8, 2021 07:22
-
-
Save vladutilie/49eac3391b10eb71b6dae501507314fa to your computer and use it in GitHub Desktop.
BT API | 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 { map } from 'rxjs/operators'; | |
import { User } from '../user/user.entity'; | |
import { BTTokenDTO, ExchangingDataDTO, MakePaymentDTO, PaymentInfoDTO, RegisterBTClientDTO } from './payment.dto'; | |
import { v4 as uuidv4 } from 'uuid'; | |
import sha256 from 'crypto-js/sha256'; | |
import Base64 from 'crypto-js/enc-base64'; | |
import qs from 'querystring'; | |
import { PaymentRepository } from './payment.repository'; | |
import { PaymentCredentials } from './payment-credentials.entity'; | |
import { plainToClass } from 'class-transformer'; | |
/* eslint-disable camelcase */ | |
@Injectable() | |
export class BTPaymentService { | |
constructor(private httpService: HttpService, private paymentRepository: PaymentRepository) {} | |
async registerBToAuthClient(currentUser: User): Promise<RegisterBTClientDTO> { | |
const payload = { | |
redirect_uris: [process.env.BT_REDIRECT_URI], | |
company_name: 'TPP Corp.', | |
client_name: currentUser.name, | |
company_url: 'https://google.com', | |
contact_person: currentUser.name, | |
email_address: currentUser.email, | |
phone_number: currentUser.phone, | |
}; | |
const options = { | |
headers: { | |
Accept: 'application/json', | |
'Content-Type': 'application/json', | |
}, | |
}; | |
return await this.httpService | |
.post(`${process.env.BT_PAYMENT_ENDPOINT}/oauth/register/TppOauthBT`, payload, options) | |
.pipe(map((response) => response.data)) | |
.toPromise(); | |
} | |
async create(user: User, register: RegisterBTClientDTO): Promise<PaymentCredentials> { | |
const credentials = await this.paymentRepository.findOne({ where: { user, bank: 'BT' } }); | |
if (!credentials) { | |
const newCredentials = new PaymentCredentials(); | |
newCredentials.user = user; | |
newCredentials.bank = 'BT'; | |
newCredentials.clientId = register.client_id; | |
newCredentials.clientSecret = register.client_secret; | |
return await this.paymentRepository.save(newCredentials); | |
} | |
const newCredentials = plainToClass(PaymentCredentials, { | |
id: credentials.id, | |
clientId: register.client_id, | |
clientSecret: register.client_secret, | |
}); | |
return await this.paymentRepository.save(newCredentials); | |
} | |
async makePayment(paymentInfo: PaymentInfoDTO): Promise<MakePaymentDTO> { | |
const payload = { | |
instructedAmount: { | |
currency: paymentInfo.currency, | |
amount: `${paymentInfo.amount}`, | |
}, | |
// TODO: handle the below details. | |
creditorAccount: { | |
iban: 'RO98BTRLEURCRT0ABCDEFGHI', | |
}, | |
creditorName: 'Creditor Name', | |
debtorId: 'J123456', | |
endToEndIdentification: 'TPP Reference', | |
remittanceInformationUnstructured: 'Merchant reference', | |
}; | |
const options = { | |
headers: { | |
Accept: 'application/json', | |
'Content-Type': 'application/json', | |
// TODO: Location and IP address should be handled. | |
'PSU-Geo-Location': 'Romania', | |
'PSU-IP-Address': '22.33.44.55', | |
'X-Request-ID': uuidv4(), | |
}, | |
}; | |
return await this.httpService | |
.post(`${process.env.BT_PAYMENT_ENDPOINT}/bt-psd2/v2/payments/ron-payment`, payload, options) | |
.pipe(map((response) => response.data)) | |
.toPromise(); | |
} | |
async buildAuthUri(register: RegisterBTClientDTO, payment: MakePaymentDTO, codeVerifier: string): Promise<string> { | |
/* | |
https://apistorebt.ro/mga/sps/oauth/oauth20/authorize? | |
?response_type=code | |
&client_id=<OOKFE3nE54aW7GtCra1b> | |
&redirect_uri=<https://google.com> | |
&scope=PIS:<paymentId> | |
&state=<statetest> | |
&code_challenge=<Q8aVElfXiBwpn14GYiNZI_j2kee8OSHCt5DWTxbyBVs> | |
&code_challenge_method=S256 | |
*/ | |
const params = { | |
response_type: 'code', | |
client_id: register.client_id, | |
redirect_uri: process.env.BT_REDIRECT_URI, | |
scope: `PIS:${payment.paymentId}`, | |
state: 'statetest', // TODO: State code should be generated and verified after BT redirects back. | |
code_challenge: await this.computeCodeChallange(codeVerifier), | |
code_challenge_method: 'S256', | |
}; | |
const authUri = Object.keys(params) | |
.map((key) => key + '=' + params[key]) | |
.join('&'); | |
return authUri; | |
} | |
async getToken(user: User, exchangingData: ExchangingDataDTO): Promise<BTTokenDTO> { | |
const credentials = await this.paymentRepository.findOne({ where: { user, bank: 'BT' } }); | |
const payload = qs.stringify({ | |
code: exchangingData.code, | |
grant_type: 'authorization_code', | |
redirect_uri: process.env.BT_REDIRECT_URI, | |
client_id: credentials.clientId, | |
client_secret: credentials.clientSecret, | |
code_verifier: process.env.BT_CODE_VERIFIER, | |
}); | |
const options = { | |
headers: { | |
Accept: 'application/json', | |
'Content-Type': 'application/x-www-form-urlencoded', | |
}, | |
}; | |
return await this.httpService | |
.post(`${process.env.BT_PAYMENT_ENDPOINT}/oauth/token`, payload, options) | |
.pipe(map((response) => response.data)) | |
.toPromise(); | |
} | |
async updateToken(user: User, tokenData: BTTokenDTO): Promise<PaymentCredentials> { | |
const credentials = await this.paymentRepository.findOne({ where: { user, bank: 'BT' } }); | |
credentials.accessToken = tokenData.access_token; | |
credentials.refreshToken = tokenData.refresh_token; | |
const expiresAt = new Date(); | |
expiresAt.setSeconds(parseInt(expiresAt.getSeconds() + tokenData.expires_in)); | |
credentials.expiresAt = expiresAt; | |
return await this.paymentRepository.save(credentials); | |
} | |
async computeCodeChallange(codeVerifier: string): Promise<string> { | |
return await sha256(codeVerifier).toString(Base64).replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_'); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment