ts-midtrans-client
Version:
This library is an UNOFFICIAL TypeScript version of the Midtrans Client - Node.js.
316 lines (315 loc) • 13 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const crypto = __importStar(require("crypto"));
const snapBiApiRequestor_1 = __importDefault(require("./snapBiApiRequestor"));
const snapBiConfig_1 = __importDefault(require("./snapBiConfig"));
class SnapBi {
constructor(paymentMethod) {
this.paymentMethod = paymentMethod;
this.apiPath = '';
this.accessTokenHeader = {};
this.transactionHeader = {};
this.body = {};
this.accessToken = '';
this.deviceId = '';
this.debugId = '';
this.timeStamp = new Date().toISOString();
this.timeout = null;
this.signature = '';
this.notificationUrlPath = '';
this.notificationPayload = {};
}
static directDebit() {
return new SnapBi('directDebit');
}
static va() {
return new SnapBi('va');
}
static qris() {
return new SnapBi('qris');
}
static notification() {
return new SnapBi('');
}
withAccessTokenHeader(headers) {
this.accessTokenHeader = Object.assign(Object.assign({}, this.accessTokenHeader), headers);
return this;
}
withTransactionHeader(headers) {
this.transactionHeader = Object.assign(Object.assign({}, this.transactionHeader), headers);
return this;
}
withAccessToken(accessToken) {
this.accessToken = accessToken;
return this;
}
withBody(body) {
this.body = body;
return this;
}
withSignature(signature) {
this.signature = signature;
return this;
}
withTimeStamp(timeStamp) {
this.timeStamp = timeStamp;
return this;
}
withNotificationPayload(notificationPayload) {
this.notificationPayload = notificationPayload;
return this;
}
withNotificationUrlPath(notificationUrlPath) {
this.notificationUrlPath = notificationUrlPath;
return this;
}
withPrivateKey(privateKey) {
snapBiConfig_1.default.snapBiPrivateKey = privateKey;
return this;
}
withClientId(clientId) {
snapBiConfig_1.default.snapBiClientId = clientId;
return this;
}
withClientSecret(clientSecret) {
snapBiConfig_1.default.snapBiClientSecret = clientSecret;
return this;
}
withPartnerId(partnerId) {
snapBiConfig_1.default.snapBiPartnerId = partnerId;
return this;
}
withChannelId(channelId) {
snapBiConfig_1.default.snapBiChannelId = channelId;
return this;
}
withDeviceId(deviceId) {
this.deviceId = deviceId;
return this;
}
withDebugId(debugId) {
this.debugId = debugId;
return this;
}
withTimeout(timeout) {
this.timeout = timeout;
return this;
}
createPayment(externalId) {
return __awaiter(this, void 0, void 0, function* () {
this.apiPath = this.setupCreatePaymentApiPath(this.paymentMethod);
return yield this.createConnection(externalId);
});
}
cancel(externalId) {
return __awaiter(this, void 0, void 0, function* () {
this.apiPath = this.setupCancelApiPath(this.paymentMethod);
return yield this.createConnection(externalId);
});
}
refund(externalId) {
return __awaiter(this, void 0, void 0, function* () {
this.apiPath = this.setupRefundApiPath(this.paymentMethod);
return yield this.createConnection(externalId);
});
}
getStatus(externalId) {
return __awaiter(this, void 0, void 0, function* () {
this.apiPath = this.setupGetStatusApiPath(this.paymentMethod);
return yield this.createConnection(externalId);
});
}
isWebhookNotificationVerified() {
if (snapBiConfig_1.default.snapBiPublicKey == null) {
throw new Error("The public key is null, You need to set the public key from SnapBiConfig.'\n" +
"For more details, contact support at support@midtrans.com if you have any questions.");
}
const notificationHttpMethod = "POST";
const minifiedNotificationBodyJsonString = JSON.stringify(this.notificationPayload);
const hashedNotificationBodyJsonString = crypto
.createHash("sha256")
.update(minifiedNotificationBodyJsonString)
.digest("hex")
.toLowerCase();
const rawStringDataToVerifyAgainstSignature = notificationHttpMethod +
":" +
this.notificationUrlPath +
":" +
hashedNotificationBodyJsonString +
":" +
this.timeStamp;
const verifier = crypto.createVerify("SHA256");
verifier.update(rawStringDataToVerifyAgainstSignature, "utf8");
const isSignatureVerified = verifier.verify(snapBiConfig_1.default.snapBiPublicKey, this.signature, "base64");
return isSignatureVerified;
}
getAccessToken() {
return __awaiter(this, void 0, void 0, function* () {
const snapBiAccessTokenHeader = this.buildAccessTokenHeader(this.timeStamp);
const openApiPayload = {
grant_type: 'client_credentials',
};
return yield snapBiApiRequestor_1.default.remoteCall(snapBiConfig_1.default.getBaseUrl() + SnapBi.ACCESS_TOKEN, snapBiAccessTokenHeader, openApiPayload, this.timeout);
});
}
createConnection() {
return __awaiter(this, arguments, void 0, function* (externalId = null) {
if (!this.accessToken) {
const accessTokenResponse = yield this.getAccessToken();
if (!accessTokenResponse.accessToken) {
return accessTokenResponse;
}
this.accessToken = accessTokenResponse.accessToken;
}
const snapBiTransactionHeader = this.buildSnapBiTransactionHeader(externalId, this.timeStamp);
return yield snapBiApiRequestor_1.default.remoteCall(snapBiConfig_1.default.getBaseUrl() + this.apiPath, snapBiTransactionHeader, this.body, this.timeout);
});
}
static getSymmetricSignatureHmacSh512(accessToken, requestBody, method, path, clientSecret, timeStamp) {
const minifiedBody = JSON.stringify(requestBody);
const hashedBody = crypto.createHash('sha256').update(minifiedBody).digest('hex').toLowerCase();
const payload = `${method.toUpperCase()}:${path}:${accessToken}:${hashedBody}:${timeStamp}`;
const hmac = crypto.createHmac('sha512', clientSecret).update(payload).digest('base64');
return hmac;
}
static getAsymmetricSignatureSha256WithRsa(clientId, xTimeStamp, privateKey) {
const stringToSign = clientId + "|" + xTimeStamp;
return crypto.sign('RSA-SHA256', Buffer.from(stringToSign), privateKey).toString("base64");
}
buildSnapBiTransactionHeader(externalId, timeStamp) {
let snapBiTransactionHeader = {
'Content-Type': 'application/json',
'Accept': 'application/json',
'X-PARTNER-ID': snapBiConfig_1.default.snapBiPartnerId,
'X-EXTERNAL-ID': externalId !== null && externalId !== void 0 ? externalId : '',
'X-DEVICE-ID': this.deviceId,
'CHANNEL-ID': snapBiConfig_1.default.snapBiChannelId,
'debug-id': this.debugId,
'Authorization': `Bearer ${this.accessToken}`,
'X-TIMESTAMP': timeStamp,
'X-SIGNATURE': SnapBi.getSymmetricSignatureHmacSh512(this.accessToken, this.body, 'post', this.apiPath, snapBiConfig_1.default.snapBiClientSecret, timeStamp),
};
if (this.transactionHeader) {
snapBiTransactionHeader = Object.assign(Object.assign({}, snapBiTransactionHeader), this.transactionHeader);
}
return snapBiTransactionHeader;
}
buildAccessTokenHeader(timeStamp) {
let snapBiAccessTokenHeader = {
'Content-Type': 'application/json',
'Accept': 'application/json',
'X-CLIENT-KEY': snapBiConfig_1.default.snapBiClientId,
'X-SIGNATURE': SnapBi.getAsymmetricSignatureSha256WithRsa(snapBiConfig_1.default.snapBiClientId, timeStamp, snapBiConfig_1.default.snapBiPrivateKey),
'X-TIMESTAMP': timeStamp,
'debug-id': this.debugId,
};
if (this.accessTokenHeader) {
snapBiAccessTokenHeader = Object.assign(Object.assign({}, snapBiAccessTokenHeader), this.accessTokenHeader);
}
return snapBiAccessTokenHeader;
}
setupCreatePaymentApiPath(paymentMethod) {
switch (paymentMethod) {
case 'va':
return SnapBi.CREATE_VA;
case 'qris':
return SnapBi.QRIS_PAYMENT;
case 'directDebit':
return SnapBi.PAYMENT_HOST_TO_HOST;
default:
throw new Error(`Payment method not implemented: ${paymentMethod}`);
}
}
setupRefundApiPath(paymentMethod) {
switch (paymentMethod) {
case 'qris':
return SnapBi.QRIS_REFUND;
case 'directDebit':
return SnapBi.DEBIT_REFUND;
default:
throw new Error(`Payment method not implemented: ${paymentMethod}`);
}
}
setupCancelApiPath(paymentMethod) {
switch (paymentMethod) {
case 'va':
return SnapBi.VA_CANCEL;
case 'qris':
return SnapBi.QRIS_CANCEL;
case 'directDebit':
return SnapBi.DEBIT_CANCEL;
default:
throw new Error(`Payment method not implemented: ${paymentMethod}`);
}
}
setupGetStatusApiPath(paymentMethod) {
switch (paymentMethod) {
case 'va':
return SnapBi.VA_STATUS;
case 'qris':
return SnapBi.QRIS_STATUS;
case 'directDebit':
return SnapBi.DEBIT_STATUS;
default:
throw new Error(`Payment method not implemented: ${paymentMethod}`);
}
}
}
SnapBi.ACCESS_TOKEN = '/v1.0/access-token/b2b';
SnapBi.PAYMENT_HOST_TO_HOST = '/v1.0/debit/payment-host-to-host';
SnapBi.CREATE_VA = '/v1.0/transfer-va/create-va';
SnapBi.DEBIT_STATUS = '/v1.0/debit/status';
SnapBi.DEBIT_REFUND = '/v1.0/debit/refund';
SnapBi.DEBIT_CANCEL = '/v1.0/debit/cancel';
SnapBi.VA_STATUS = '/v1.0/transfer-va/status';
SnapBi.VA_CANCEL = '/v1.0/transfer-va/delete-va';
SnapBi.QRIS_PAYMENT = '/v1.0/qr/qr-mpm-generate';
SnapBi.QRIS_STATUS = '/v1.0/qr/qr-mpm-query';
SnapBi.QRIS_REFUND = '/v1.0/qr/qr-mpm-refund';
SnapBi.QRIS_CANCEL = '/v1.0/qr/qr-mpm-cancel';
exports.default = SnapBi;